diff --git a/apps/reaktor/config/app.yml b/apps/reaktor/config/app.yml new file mode 100644 index 0000000..d5e820a --- /dev/null +++ b/apps/reaktor/config/app.yml @@ -0,0 +1,235 @@ +### Remember if you change anything in this file you need to clear the cache! ### + +all: + rss: + title: Reaktor + email: reaktor@deichman.no + authorname: Reaktor + url: #appended to site url + artwork_items: 10 + + reaktor_url: http://reaktor + image_path: images + logged_in_time: 1800 # The number of seconds that a user is counted since they logged in + main_title: Reaktor # This is fixed so can be used as a fallback if you don't want the automatic subreaktor + # and admin attachments (for example) + site_title: Reaktor # Make sure this one is the same as the one in view.yml for consistency - + # it is dynamically set - don't rely on it to always be this value! + title_seperator: " ~ " # In between the main site title defined in view.yml and the custom page title + admin_logo: "logoAdmin.gif" # Default is logoAdmin.gif + redaksjon_logo: "reaktor_red.gif" # Default is reaktor_red.gif + help_email: "help@minreaktor.no" + + fixed_articles: + terms_and_conditions: "Vilkaar_for_bruk" # The permalink to the article that contains the terms and conditions + login_help: "login_help" # The permalink to the article that is associated with the login help link + + files: + location_identifiers: # The list of possible identifiers, add to this if adding a new /content directory + image: image # Uses associative array so form helpers work correctly, assigning values to keys + pdf: pdf + audio: audio + video: video + flash_animation: flash_animation + text: text + + sf_google_analytics_plugin: + enabled: on + profile_id: UA-4885488-1 + tracker: google + + recaptcha: + publickey: 6Lf7mQIAAAAAAG0NGOQMemqzYMViFHl4Egu0qHH- + privatekey: 6Lf7mQIAAAAAAO26Xy8xoRmfqKvteF_v7oohruog + + admin: + commentlistmax: 10 + opt_in_email_blocks: 20 #set this to 0 to not use any blocks + pma_readonly_user: pma_user #PHPMyAdmin user + pma_password: R3ak+0rpmA + ga_tracker_number: UA-4885488-1 #The google analytics tracker number - currently reaktor.lab.linpro.no + +### Remember if you change anything in this file you need to clear the cache! ### + + upload: + upload_dir: content + image_dir: image + video_dir: video + audio_dir: audio + pdf_dir: pdf + text_dir: text + flash_animation_dir: flash_animation + attachment_dir: /%sf_upload_dir_name%/attachments + max_image_width: 700 + max_image_height: 700 + image_extensions: [jpg, png, gif] #Deprecated in favour of mime types from DB + pdf_extensions: [pdf] #Deprecated in favour of mime types from DB + audio_extensions: [mp3, wav] #Deprecated in favour of mime types from DB + video_extensions: [mpg, mpeg, avi, swf] #Deprecated in favour of mime types from DB + text_extensions: [txt] #Deprecated in favour of mime types from DB + max_thumb_height: 150 + max_thumb_width: 150 + fix_thumb_height: 160 + fix_thumb_width: 240 + fix_mini_height: 65 + fix_mini_width: 78 + pdf_thumb_width: 116 #Try to maintain A4/letter aspect ratio - NOT USED WITH FIXED HEIGHTS YET, THUMB STORY COMING SOON :) + pdf_thumb_height: 150 + thumb_allowed_mime: + audio: ['image/jpeg', 'image/jpg', 'image/pjpeg'] #Allowed mime types for audio thumbnails - other types will inherit from upload/validators/uploadInline.yml + crop_safe_mime: ['image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png'] # Mime types that do not need to be checked for animation frames when cropping + + sf_guard_plugin: + profile_class: sfGuardUserData + remember_key_expiration_age: # Default is 15 days (must be supplied in seconds) + remember_cookie_name: "ReaktorRemember" # Default is sfRemember + + subreaktors: + logo_path: %sf_web_dir%/images/ + subcategory_list_length: 7 + +### Remember if you change anything in this file you need to clear the cache! ### + + profile: + max_image_width: 48 + max_image_height: 48 + max_age: 105 #Birthyear before 1902 and after 2038 will cause an overflow + min_password_length: 6 + email_template: apps/reaktor/modules/profile/data/mail.ini + avatar_path: %sf_web_dir%/%sf_upload_dir_name%/profile_images/ + avatar_url: /%sf_upload_dir_name%/profile_images/ + portfolio_pagination: 21 + artwork: + content_path: ../content/ + max_score: 6 + pagination: 10 + sender: The reaktor team + sender_email: reaktor@deichman.no + valid_title_chars: "a-z0-9-_\søåæäöØÅÆÖÄ!?'\"" #Regular expression format + max_title_length: 100 # More than 255 will be cropped by the database + min_title_length: 3 + teaser_len: 22 + other_by_user: 6 # Number of artworks to show in the "other work by " section on artwork page + other_usrs_also_like: 6 # Number of artworks to show in the "Users who like this arwork also like" section on artwork show page + + additional_file_types: + text: ["pdf"] #Additional file types that these artwork types can contain + pdf: ["text"] + + show_navigation: ["text", "pdf", "video", "flash_animation"] # Artwork types that have next/previous links on display + + articles: + teaser_len: 100 + help_max_count: 5 + internal_max_count: 5 + footer_max_count: 5 + my_page_max_count: 5 + regular_max_count: 5 + + + tagging: + minimum_tags: 0 # Tags required by each uploaded file (set 0 for none required) + max_length: 35 # More than 255 will be cropped by the database + min_length: 2 + cloud_type: pretty # fugly = display numbers in tag cloud | pretty = do not display numbers + + category: + max_count_on_reaktors: 3 + + home: + list_length: 5 + max_tags: 40 # The maximum number of tags to show on the home page tag cloud + max_tag_length: 1000 # The maximum number of character space the tag cloud can occupy + + message: + max_length: 500 # The maximum number of chars to show in the inline message box + + +### Remember if you change anything in this file you need to clear the cache! ### + + sfPropelActAsCommentableBehaviorPlugin: + use_ajax: true + css: false + anonymous: + enabled: false + layout: + name: required + email: required + title: required + comment: required + name: Anonymous User + user: + enabled: true + layout: + title: required + comment: require + table: sf_guard_user + id: id + class: sfGuardUser + id_method: getId + toString: __toString + namespaces: + backend: administrator + count: + enabled: true + method: setSfCommentCount + namespace: frontend + + rating: + star_width: 20 + + + + userlist: + exclude: ["admin", "editorialboy1", "editorialboy2", "editorialboy3", "articleboy", "languageboy", ] + + .editorial_team_competitions_array: + editorial_team_competitions: + # Example competition assignment follows + competition1: # This can be anything, just give a unique meaningful title + start: 2008-04-04 # yyyy-mm-dd - the date these categories/subreaktors will be checked from + end: 2008-04-11 # yyyy-mm-dd - the date to stop checking + subreaktors: ["foto"] # List of subreaktors/formats that the artwork must be part of (will generally be one) + categories: [3] # List of category IDs that the artwork can be assigned to (will generally be one but can be a list) + team: "konkurranse_redaksjon" # The editorial team that the artwork will be assigned to + + editorial_team_assignment: + #example: [example_redaksjon, foto_redaksjon] + # Example_redaksjon would be set if they are enabled, if not it would fall to foto_redaksjon, and if that fails it would go to default (below) + groruddalen: ["groruddalen_redaksjon"] + foto: ["assign_by_residence"] + tegneserier: ["serieteket_redaksjon"] + tegning: ["assign_by_residence"] + film: ["assign_by_residence"] + lyd: ["musikk_redaksjon"] + tekst: ["assign_by_residence"] + # Who gets the ones that don't match? For example when lots of teams are on holiday. This group should never be on holiday, + # as it will always recieve the assignment regardless. This should be a single group, not a list. + + editorial_team_default: "deichman_redaksjon" + # If "assign_by_residence" is set as one of the options (above) the following lists will decide which team takes the assignment + # based on the where the user lives. Residence IDs can be seen next to the list of residences via the admin interface + # If IDs are duplicated, the first one found will be matched - so you can have a chain of backups if you feel like it + + .editorial_team_assign_by_residence_array: + editorial_team_assign_by_residence: + deichman_redaksjon: [1, 2, 3, 5, 10, 11, 12, 14, 16, 17, 18, 19, 21, 22, 23, 24] + trondheim_redaksjon: [4, 6, 7, 9, 8, 13, 25, 15, 26] + groruddalen_redaksjon: [20] + + # Backup teams can be assigned for individual teams in the case of assign_by_residence, if a team is unavailable this backup + # list will be checked before falling back to the absolute default defined above. + editorial_team_backup_teams: + deichman_redaksjon: ["trondheim_redaksjon"] + trondheim_redaksjon: ["deichman_redaksjon"] + + reports: + bookmarks_to_show: 5 + + sf_use_process_cache: apc + +test: + artwork: + content_path: content/ + +### Remember if you change anything in this file you need to clear the cache! ### diff --git a/apps/reaktor/config/cache.yml b/apps/reaktor/config/cache.yml new file mode 100644 index 0000000..a2fe36f --- /dev/null +++ b/apps/reaktor/config/cache.yml @@ -0,0 +1,7 @@ +default: + enabled: off + with_layout: false + lifetime: 86400 + +_menubar: + enabled: off diff --git a/apps/reaktor/config/config.php b/apps/reaktor/config/config.php new file mode 100644 index 0000000..0f92067 --- /dev/null +++ b/apps/reaktor/config/config.php @@ -0,0 +1,18 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +// include project configuration +require SF_ROOT_DIR.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'; + +// symfony bootstraping +require_once $sf_symfony_lib_dir.'/util/sfCore.class.php'; +sfCore::bootstrap($sf_symfony_lib_dir, $sf_symfony_data_dir); \ No newline at end of file diff --git a/apps/reaktor/config/factories.yml b/apps/reaktor/config/factories.yml new file mode 100644 index 0000000..f8e6b9e --- /dev/null +++ b/apps/reaktor/config/factories.yml @@ -0,0 +1,36 @@ +cli: + controller: + class: sfConsoleController + request: + class: sfConsoleRequest + response: + class: sfConsoleResponse + +test: + storage: + class: sfSessionTestStorage + +all: +# controller: +# class: sfFrontWebController +# +# request: +# class: sfWebRequest +# +# response: +# class: sfWebResponse +# + user: + class: myUser + + storage: + class: sfSessionStorage + param: + session_name: reaktor + +# +# view_cache: +# class: sfFileCache +# param: +# automaticCleaningFactor: 0 +# cacheDir: %SF_TEMPLATE_CACHE_DIR% diff --git a/apps/reaktor/config/filters.yml b/apps/reaktor/config/filters.yml new file mode 100644 index 0000000..b8eb508 --- /dev/null +++ b/apps/reaktor/config/filters.yml @@ -0,0 +1,26 @@ +rendering: ~ +web_debug: ~ +security: + class: sfGuardBasicSecurityFilter + +# generally, you will want to insert your own filters here + +sf_google_analytics_plugin: + class: sfGoogleAnalyticsFilter + +remember: + class: rememberMeFilter + +adminFilter: + class: adminFilter +userFilter: + class: userFilter + +cache: ~ +common: ~ +flash: ~ + +subreaktorFilter: + class: subreaktorFilter + +execution: ~ diff --git a/apps/reaktor/config/i18n.yml b/apps/reaktor/config/i18n.yml new file mode 100644 index 0000000..d0868b2 --- /dev/null +++ b/apps/reaktor/config/i18n.yml @@ -0,0 +1,17 @@ +prod: + default_culture: 'no' + source: MySQL + database: mysql://reaktor_user:cT0PHPCm@localhost/reaktor + debug: on + cache: off + untranslated_prefix: "" + untranslated_suffix: "" + +dev: + default_culture: 'no' + source: MySQL + database: mysql://reaktor_user:cT0PHPCm@localhost/reaktor + debug: on + cache: off + untranslated_prefix: "" + untranslated_suffix: "" diff --git a/apps/reaktor/config/logging.yml b/apps/reaktor/config/logging.yml new file mode 100644 index 0000000..beceea9 --- /dev/null +++ b/apps/reaktor/config/logging.yml @@ -0,0 +1,22 @@ +prod: + enabled: off + level: err + rotate: on + purge: on + +#all: +# enabled: on +# level: debug +# rotate: off +# period: 7 +# history: 10 +# purge: on +# loggers: +# sf_web_debug: +# class: sfWebDebugLogger +# param: +# condition: %SF_WEB_DEBUG% +# sf_file_debug: +# class: sfFileLogger +# param: +# file: %SF_LOG_DIR%/%SF_APP%_%SF_ENVIRONMENT%.log diff --git a/apps/reaktor/config/metaMap.yml b/apps/reaktor/config/metaMap.yml new file mode 100644 index 0000000..cebfcd3 --- /dev/null +++ b/apps/reaktor/config/metaMap.yml @@ -0,0 +1,95 @@ +image_list: + creator: + - MAKERNOTE.OwnerName + description.creation: # This becomes "Method of production" + - IFD0.Software + - IFD0.Model + type: + - FILE.MimeType + format.width: + - COMPUTED.Width + format.height: + - COMPUTED.Height + date.creation: + - EXIF.DateTimeOriginal + - IFD0.DateTime + format.size: + - FILE.FileSize + format.aperture: + - COMPUTED.ApertureFNumber + - EXIF.FNumber + format.shutter: + - EXIF.ExposureTime + format.focalLength: + - EXIF.FocalLength + description.camera: + - IFD0.Model + description.software: + - IFD0.Software + + +audio_list: + creator: + - tags.id3v2.artist.0 + - tags.id3v1.artist.0 + - tags.vorbiscomment.encoded-by.0 + - tags.ape.artist.0 + creator.publisher: + - tags.id3v2.publisher.0 + - tags.id3v1.publisher.0 + - tags.ape.publisher.0 + creator.composer: + - tags.id3v2.composer.0 + - tags.id3v1.composer.0 + - tags.vorbiscomment.composer.0 + - tags.ape.composer.0 + title: + - tags.id3v2.title.0 + - tags.id3v1.title.0 + - tags.vorbiscomment.title.0 + - tags.ape.title.0 + description.abstract: + - tags.id3v2.comment.0 + - tags.id3v1.comment.0 + - tags.vorbiscomment.description.0 + - tags.vorbiscomment.comment.0 + - tags.ape.description.0 + description.artist: + - tags.id3v2.artist.0 + - tags.id3v1.artist.0 + - tags.vorbiscomment.artist.0 + - tags.ape.artist.0 + description.album: + - tags.id3v2.album.0 + - tags.id3v1.album.0 + - tags.vorbiscomment.album.0 + - tags.ape.album.0 + description.genre: + - tags.id3v2.genre.0 + - tags.id3v1.genre.0 + - tags.vorbiscomment.genre.0 + - tags.ape.genre.0 + description.track: + - tags.id3v2.track.0 + - tags.id3v1.track.0 + - tags.vorbiscomment.tracknumber.0 + - tags.ape.track.0 + format.duration: + - playing_time + format.samplerate: + - sample_rate + format.bitratemode: + - bitrate_mode + format: + - format_name + date: + - tags.id3v2.year.0 + - tags.id3v1.year.0 + - tags.vorbiscomment.date.0 + - tags.ape.yaer.0 + license: + - tags.vorbiscomment.license.0 + +# Add new formats where applicable, the system will go down the list and stop when it finds a useable value +# For example, in the case of description.creation, the Software value will be checked and if not found +# Then the Model value will be checked. diff --git a/apps/reaktor/config/routing.yml b/apps/reaktor/config/routing.yml new file mode 100644 index 0000000..a1f016a --- /dev/null +++ b/apps/reaktor/config/routing.yml @@ -0,0 +1,1470 @@ +# Please always add a route for every possible URL combination - this will become crucial +# When we come to install i18n because we will likely be adding country codes to the URLs +# Which we can do via this file and will take effect globally, providing you have used routing rules. +# We also want to hide paths to plugins wherever possible - Symfony should be transparent to the user +# Adding routes also enforces rules and stops bogus values being sent to the action + +#Ajax requests with short URLS :) + +updateContentSidebar: + url: /updateContentSidebar/:user + param: { module: userContent, action: updateSidebar } + +updateFileList: + url: /updateFileList/:artworkId + param: { module: artwork, action: updateFileList } + +updateArtworkTagList: + url: /updateArtworkTagList/:fileId/:artworkId + param: { module: artwork, action: updateArtworkTagList } + +#articles +orderarticlesupdate: + url: /articles/order/update + param: { module: articles, action: orderArticlesUpdate } + +orderarticles: + url: /:sf_culture/admin/articles/order/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: orderArticles } + +relatearticle: + url: /article/relate/:id + param: { module: articles, action: relateArticle } + +unrelatearticle: + url: /article/unrelate/:article1/:article2 + param: { module: articles, action: unrelateArticle} + +setarticleexpirationdate: + url: /article/expire/:article_id/* + param: { module: articles, action: setExpirationDate} + +relateartworktoarticle: + url: /:sf_culture/admin/article/relatetoartwork/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: relateToArtwork} + +browsearticleartworks: + url: /:sf_culture/admin/article/edit/browse/artworks/:article_id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: listArtworksPopup} + +browsearticlefiles: + url: /:sf_culture/admin/article/edit/:article_id/browse/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: filelist, action: browseFiles} + +editarticle: + url: /:sf_culture/admin/article/edit/:article_id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: edit} + +listarticles: + url: /:sf_culture/admin/articles/list/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: list } + +showarticle_attachments: + url: /:sf_culture/article/attachments/:article_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: showArticleAttachments} + +showarticle_artworks: + url: /:sf_culture/article/artwork/:article_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: showArticleArtworkRelations} + +article_set_banner: + url: /:sf_culture/article/:article_id/banner/attach/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: attachBannerToArticle} + +article_attach: + url: /:sf_culture/article/:article_id/attach/:file_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: attachToArticle} + +nuke_article_attachment: + url: /:sf_culture/article/:article_id/nuke/attachment/:attachment_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: nukeAttachment} + +nuke_related_artwork_from_article: + url: /:sf_culture/article/:article_id/nuke/artwork/:artwork_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: nukeArtworkRelation} + +articlecalendar_type: + url: /:sf_culture/article/calendar/:article_type/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: calendar} + +createarticle: + url: /:sf_culture/admin/article/create/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: edit} + +article_admin: + url: /:sf_culture/admin/article/:permalink + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: view} + +article: + url: /:sf_culture/article/:permalink + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: view} + +latestarticlebytype: + url: /:sf_culture/article/:type/latest + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: view, latest: true } + +subreaktorarticle: + url: /:sf_culture/:subreaktor/article/:permalink + requirements: { sf_culture: (?:no|nn|en) } + param: { module: articles, action: view} + +article_editor: + url: /:sf_culture/article/tinymce + requirements: { sf_culture: (?:no|nn|en) } + param: { module: article, action: tinymceJs, sf_format: js } + +#messaging + +sendmessage: + url: /:sf_culture/message/send + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: sendMessageAction} + +markmessageread: + url: /:sf_culture/message/markRead/:id/ + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: markMessageRead} + +newMessages: + url: /:sf_culture/message/getNewMessages + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: getNewMessages} + +updateMessageCounter: + url: /:sf_culture/message/updateMessageCounter + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: updateMessageCounter} + +updateMessageContentAjax: + url: /:sf_culture/message/updateMessageContentAjax + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: messageContentAjax} + +ignoreuser: + url: /:sf_culture/message/ignoreUser/:id/:do/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: ignoreUser} + +deletemessage: + url: /:sf_culture/message/deleteMessage/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: deleteMessage} + +add_favourite: + url: /:sf_culture/favourite/add/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: favourite, action: add} + +remove_favourite: + url: /:sf_culture/favourite/remove/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: favourite, action: remove} + +restoremessage: + url: /:sf_culture/message/restoreMessage/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: restoreMessage} + +adminmessage: + url: /:sf_culture/admin/message + requirements: { sf_culture: (?:no|nn|en) } + param: { module: adminmessage, action: list } + +messageinbox: + url: /:sf_culture/message/inbox/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: messaging, action: messageInbox} + +#Profiles and user routes + +checkusername: + url: /checkusername/* + param: { module: profile, action: checkUsername} + +userlist: + url: /:sf_culture/list/users/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardUser, action: listUsers} + +subreaktoruserlist: + url: /:subreaktor/:sf_culture/list/users/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardUser, action: listUsers} + +updateprofile: + url: /:sf_culture/profile/update/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: update} + +subreaktorupdateprofile: + url: /:sf_culture/:subreaktor/profile/update/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: update} + +changepassword: + url: /:sf_culture/profile/changepassword/:username/:key/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: changePassword} + +subreaktorchangepassword: + url: /:sf_culture/:subreaktor/profile/changepassword/:username/:key/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: changePassword} + +subreaktormypage: + url: /:sf_culture/:subreaktor/mypage/:user + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: myPage} + +activate: + url: /:sf_culture/profile/activate/:key + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: activate} + +changeemail: + url: /:sf_culture/profile/changeemail/:key/:new_email_key + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: changeemail} + +mypage: + url: /:sf_culture/mypage/:user + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: myPage} + +portfolio: + url: /:sf_culture/portfolio/:user/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: portfolio} + +subreaktorportfolio: + url: /:sf_culture/:subreaktor/portfolio/:user/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: portfolio} + +subreaktoraddresource: + url: /:sf_culture/:subreaktor/addresource/:user + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: addResource } + +addresource: + url: /:sf_culture/addresource/:user + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: addResource } + +subreaktorremoveresource: + url: /:sf_culture/:subreaktor/removeresource/:user/:resourceid + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: removeResource } + +removeresource: + url: /:sf_culture/removeresource/:user/:resourceid + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: removeResource } + +subreaktorallusercomments: + url: /:sf_culture/:subreaktor/list/comments/user/:user_id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfComment, action: listComments } + +allusercomments: + url: /:sf_culture/list/comments/user/:user_id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfComment, action: listComments } + +subreaktormyusercomments: + url: /:sf_culture/:subreaktor/list/comments/username/:username/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfComment, action: listComments } + +myusercomments: + url: /:sf_culture/list/comments/username/:username/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfComment, action: listComments } + +subreaktorallusersmatchinginterests: + url: /:sf_culture/:subreaktor/list/matchingusers/:user_id/:all + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: listMatchingUsers } + +allusersmatchinginterests: + url: /:sf_culture/list/matchingusers/:user_id/:all + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: listMatchingUsers } + +lokalreaktor: + url: /:sf_culture/admin/lokalreaktor/edit/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: lokalreaktor, action: edit} + +listignoredusers: + url: /:sf_culture/admin/listIgnoredUsers/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listIgnoredUsers} + +listoptinusers: + url: /:sf_culture/admin/listPromotionalEmailRecipients + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listPromotionalEmailRecipients} + +listreportedcontent: + url: /:sf_culture/admin/list/file/reported + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: listReportedContent} + +listrejectedfiles: + url: /:sf_culture/admin/list/file/rejected + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listRejectedFiles} + +listmyteams: + url: /:sf_culture/admin/list/myteams/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: editorialTeams } + +unapproved_listmyteams: + url: /:sf_culture/admin/list/unapprovedmyteams/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: listUnapprovedMyTeams } + +unapproved_listotherteam: + url: /:sf_culture/admin/list/unapprovedotherteams/:team + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: listUnapprovedOtherTeams } + +unapproved_listotherteams: + url: /:sf_culture/admin/list/unapprovedotherteams/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: listUnapprovedOtherTeams } + +rejection_type_chosen: + url: /:sf_culture/admin/rejection_type/chosen + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: rejectionTypeChosen } + +rejectiontypeupdate: + url: /:sf_culture/admin/rejection_type/update + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: rejectionTypeUpdate } + +rejectiontypeshow: + url: /:sf_culture/admin/rejection_type/show/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: rejectionTypeShow } + +rejectiontypedelete: + url: /:sf_culture/admin/rejection_type/delete/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: rejectionTypeDelete } + +rejectiontypes: + url: /:sf_culture/admin/settings/rejection_types + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: rejectionType } + +rejectiontypecreate: + url: /:sf_culture/admin/rejection_type/create + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: rejectionTypeCreate } + +artworkstatusupdate: + url: /:sf_culture/admin/artwork_status/update + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: artworkStatusUpdate } + +artworkslistmodified: + url: /:sf_culture/admin/artwork/list_modified/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: listModified } + +artworkstatusshow: + url: /:sf_culture/admin/artwork_status/show/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: artworkStatusShow } + +artworkstatuses: + url: /:sf_culture/admin/settings/artwork_statuses + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: artworkStatus } + +historyactionupdate: + url: /:sf_culture/admin/history_action/update + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: historyActionUpdate } + +historyactions: + url: /:sf_culture/admin/settings/history_actions + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: historyActions } + +AJAX_browse_unrelated_artworks: + url: /:sf_culture/ajax/artwork/:id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: relatedFilter } + +subreaktornameupdate: + url: /:sf_culture/admin/translate/subreaktorname/update + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: subreaktorNameUpdate } + +subreaktornameedit: + url: /:sf_culture/admin/translate/subreaktorname/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: subreaktorNameEdit } + +subreaktornames: + url: /:sf_culture/admin/translate/subreaktorname + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: subreaktorNames } + +sfguardpermissiondescriptionupdate: + url: /:sf_culture/admin/translate/permissiondescription/update + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: permissionDescriptionUpdate } + +sfguardpermissiondescriptionedit: + url: /:sf_culture/admin/translate/permissiondescription/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: permissionDescriptionEdit } + +sfguardpermissiondescriptionlist: + url: /:sf_culture/admin/translate/permissiondescriptions + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: permissionDescriptionsList } + +listcategories: + url: /:sf_culture/admin/settings/categories + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: categoryList } + +subreaktorlistcategories: + url: /:sf_culture/:subreaktor/admin/settings/categories + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: categoryList } + +categoryupdate: + url: /:sf_culture/admin/category/update + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: categoryUpdate } + +subreaktorcategoryupdate: + url: /:sf_culture/:subreaktor/admin/category/update + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: categoryUpdate } + +editCategory: + url: /:sf_culture/admin/category/edit/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: categoryEdit } + +renameCategory: + url: /:sf_culture/admin/category/rename/:id/:basename + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: categoryRename } + +subreaktoreditCategory: + url: /:sf_culture/:subreaktor/admin/category/edit/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: categoryEdit } + +newCategory: + url: /:sf_culture/admin/category/new + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: newCategory } + +subreaktornewCategory: + url: /:sf_culture/:subreaktor/admin/category/new + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: newCategory } + +commentsbyuser: + url: /:sf_culture/admin/list/comments/user/:user_id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfComment, action: listComments } + +reportedcomments: + url: /:sf_culture/admin/list/comments/reported/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listReportedComments } + +unsuitablecomments: + url: /:sf_culture/admin/list/comments/unsuitable/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listUnsuitableComments } + +listreportedfiles: + url: /:sf_culture/admin/list/files/reported + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listReportedContent } + +listcommentsbydate: + url: /:sf_culture/admin/list/comments/* # Allow no date to be specified + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listComments } + +editadminmessage: + url: /:sf_culture/admin/message/edit/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: adminmessage, action: edit } + +listadminmessage: + url: /:sf_culture/admin/message/list/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: adminmessage, action: list } + +createadminmessage: + url: /:sf_culture/admin/message/create + requirements: { sf_culture: (?:no|nn|en) } + param: { module: adminmessage, action: create } + +listusers: + url: /:sf_culture/admin/list/users/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardUser, action: list } + +edituser: + url: /:sf_culture/admin/edit/user/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardUser, action: edit } + +createuser: + url: /:sf_culture/admin/user/create + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardUser, action: create } + +saveuser: + url: /:sf_culture/admin/save/user + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardUser, action: save } + +listgroups: + url: /:sf_culture/admin/list/groups/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardGroup, action: list } + +editgroup: + url: /:sf_culture/admin/edit/group/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardGroup, action: edit } + +savegroup: + url: /:sf_culture/admin/save/group + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardGroup, action: save } + +listpermissions: + url: /:sf_culture/admin/list/permissions/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardPermission, action: list } + +editpermissions: + url: /:sf_culture/admin/edit/permissions/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardPermission, action: edit } + +savepermissions: + url: /:sf_culture/admin/save/permissions + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardPermission, action: save } + +listrejected: + url: /:sf_culture/admin/list/rejected + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listRejected } + +listdiscussion: + url: /:sf_culture/admin/list/discussion + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: listDiscussion } + +commentscalendar: + url: /:sf_culture/admin/comments/* + requirements: { sf_culture: (?:no|nn|en) } + param: {module: admin, action: commentsCalendar } + +createcompositeartwork: + url: /:sf_culture/admin/artwork/createcomposite + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: createCompositeArtwork } + +admin: + url: /:sf_culture/admin + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: index } + +admin_functions: + url: /:sf_culture/admin/functions/:mode + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: adminFunctions } + +admin_home: + url: /:sf_culture/admin + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: index } + +taglist: + url: /:sf_culture/admin/tags/list/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: listTags } + +admin_addtag: + url: /:sf_culture/admin/tags/add/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: addTag } + +taglist_unapproved: + url: /:sf_culture/admin/tags/unapproved/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: listTags, unapproved: 1 } + +listsubreaktors: + url: /:sf_culture/admin/list/subreaktors + requirements: { sf_culture: (?:no|nn|en) } + param: { module: subreaktors, action: list } + +addsubreaktor: + url: /:sf_culture/admin/add/subreaktors + requirements: { sf_culture: (?:no|nn|en) } + param: { module: subreaktors, action: add } + +editsubreaktor: + url: /:sf_culture/admin/edit/subreaktors/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: subreaktors, action: edit } + +updatesubreaktor: + url: /:sf_culture/admin/update/subreaktors/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: subreaktors, action: update } + +deletesubreaktor: + url: /:sf_culture/admin/delete/subreaktors/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: subreaktors, action: delete } + +adminupdatesubreaktororder: + url: /:sf_culture/admin/updateorder/subreaktors/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: subreaktors, action: updateOrder } + +listrecommended: + url: /:sf_culture/admin/list/recommended + requirements: {sf_culture: (?:no|nn|en) } + param: {module: admin, action: listRecommended } + +approvedartwork: + url: /:sf_culture/admin/list/approved + requirements: {sf_culture: (?:no|nn|en) } + param: {module: admin, action: listApproved } + +listcompositeartwork: + url: /:sf_culture/admin/list/composite + requirements: {sf_culture: (?:no|nn|en) } + param: {module: admin, action: listComposite } + +approvedartwork_year: + url: /:sf_culture/admin/list/approved/:year + requirements: {sf_culture: (?:no|nn|en) } + param: {module: admin, action: listApproved } + +approvedartwork_month: + url: /:sf_culture/admin/list/approved/:year/:month/* + requirements: {sf_culture: (?:no|nn|en) } + param: {module: admin, action: listApproved } + +rejectedartwork: + url: /:sf_culture/admin/list/rejected + requirements: {sf_culture: (?:no|nn|en) } + param: {module: artwork, action: listRejected } + +rejectedartwork_year: + url: /:sf_culture/admin/list/rejected/:year + requirements: {sf_culture: (?:no|nn|en) } + param: {module: artwork, action: listRejected } + +rejectedartwork_month: + url: /:sf_culture/admin/list/rejected/:year/:month/* + requirements: {sf_culture: (?:no|nn|en) } + param: {module: artwork, action: listRejected } + +residences: + url: /:sf_culture/admin/list/residences/* + requirements: {sf_culture: (?:no|nn|en) } + param: {module: residence, action: list } + +residence_edit: + url: /:sf_culture/admin/edit/residence/:id + requirements: {sf_culture: (?:no|nn|en) } + param: {module: residence, action: edit } + +residence_delete: + url: /:sf_culture/admin/delete/residence/:id + requirements: {sf_culture: (?:no|nn|en) } + param: {module: residence, action: delete } + +pma: + url: /admin/pma + param: { module: admin, action: PMA} + +setLang: + url: /lang/:lang/* + param: {module: sfTransUnit, action: setCulture } + +# File upload & Management + +resolveuploadid: + url: /resolveUploadFileId/* + param: { module: upload, action: resolveUploadFileId } + +resolveartworkid: + url: /resolveArtworkId/* + param: { module: artwork, action: resolveArtworkId } + +updateartworkeditorialteam: + url: /:sf_culture/artwork/update/editorialteam/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: updateEditorialTeam } + +removefilefromartwork: + url: /:sf_culture/artwork/removefile/:artwork/:file + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: removeFileFromArtwork } + +artworkupdatefield: + url: /:sf_culture/artwork/update/:id/:field + requirements: { sf_culture: (?:no|nn|en), field: (?:title|description|files) } + param: { module: artwork, action: update } + +cropImage: + url: /:sf_culture/upload/thumbnailcrop/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: thumbnailCrop } + +subreaktorcropImage: + url: /:sf_culture/:subreaktor/upload/thumbnailcrop/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: thumbnailCrop } + +uploadcropimage: + url: /:sf_culture/upload/crop/:file + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: crop } + +subreaktoruploadcropimage: + url: /:sf_culture/:subreaktor/upload/crop/:file + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: crop } + +subreaktorupdate_content: + url: /:sf_culture/:subreaktor/update/:artwork_id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: upload} + +update_content: + url: /:sf_culture/update/:artwork_id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: upload} + +upload_attachment: + url: /:sf_culture/upload/attachment/:article_id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: uploadAttachment} + +new_text: + url: /:sf_culture/textsubmit + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: upload, mce_data: ' '} + +subreaktornew_text: + url: /:sf_culture/:subreaktor/textsubmit + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: upload, mce_data: ' '} + +subreaktoredit_upload: + url: /:sf_culture/:subreaktor/upload/edit/:fileId/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: edit} + +edit_upload: + url: /:sf_culture/upload/edit/:fileId/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: edit} + +subreaktorinline_upload: + url: /:sf_culture/:subreaktor/upload/inline + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: updateInline} + +inline_upload: + url: /:sf_culture/upload/inline + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: updateInline} + +subreaktormy_content: + url: /:sf_culture/:subreaktor/mypage/content/manage/:mode + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage } + +my_content: + url: /:sf_culture/mypage/content/manage/:mode + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage } + +user_content: + url: /:sf_culture/admin/content/manage/:user/:mode + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage } + +subreaktoruser_content: + url: /:sf_culture/admin/content/manage/:user/:mode + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage } + +subreaktormy_content_filtered: + url: /:sf_culture/content/manage/:mode/:year + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage } + +my_content_filtered: + url: /:sf_culture/content/manage/:mode/:year + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage } + +user_content_filtered: + url: /:sf_culture/admin/content/manage/:user/:mode/:year + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage } + +admin_link_existing_file: + url: /:sf_culture/admin/content/link/:user/:artworkId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage, mode: link } + +admin_link_existing_file_allusers: + url: /:sf_culture/admin/content/:user/linkall/:artworkId/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage, mode: link, allusers: true } + +subreaktorlink_existing_file: + url: /:sf_culture/:subreaktor/content/link/:artworkId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage, mode: link } + +link_existing_file: + url: /:sf_culture/content/link/:artworkId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: manage, mode: link } + +addToCollection: + url: /:sf_culture/content/executeLink/:artworkId/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: add } + +subreaktoraddToCollection: + url: /:sf_culture/:subreaktor/content/executeLink/:artworkId/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: add } + +adminaddToCollection: + url: /:sf_culture/admin/content/:user/executeLink/:artworkId/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: add } + +getartworklist: + url: /:sf_culture/content/getArtworkList/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: getArtworkList } + +removeFromCollection: + url: /:sf_culture/content/executeRemove/:artworkId/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: remove } + +adminremoveFromCollection: + url: /:sf_culture/admin/content/:user/executeRemove/:artworkId/:fileId/:allusers + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: remove } + +subreaktordelete_file: + url: /:sf_culture/:subreaktor/upload/delete/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: deleteFile } + +delete_file: + url: /:sf_culture/upload/delete/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: deleteFile } + +hide_file: + url: /:sf_culture/file/remove/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: userContent, action: hideFile } + +subreaktorremove_file_create: + url: /:sf_culture/:subreaktor/artwork/remove/:artworkId/:fileId/create + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: unlink, mode: create } + +remove_file_create: + url: /:sf_culture/artwork/remove/:artworkId/:fileId/create + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: unlink, mode: create } + +subreaktorremove_file_link: + url: /:sf_culture/:subreaktor/artwork/remove/:artworkId/:fileId/link + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: unlink, mode: link } + +remove_file_link: + url: /:sf_culture/artwork/remove/:artworkId/:fileId/link + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: unlink, mode: link } + +subreaktorcategory_action: + url: /:sf_culture/:subreaktor/artwork/categoryAction + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: categoryAction } + +category_action: + url: /:sf_culture/artwork/categoryAction + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: categoryAction } + +category_autocomplete: + url: /:sf_culture/category/autocomplete + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: categoryAutocomplete } + +subreaktorremove_artwork_file: + url: /:sf_culture/:subreaktor/artwork/remove/:artworkId/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: unlink, mode: remove } + +remove_artwork_file: + url: /:sf_culture/artwork/remove/:artworkId/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: unlink, mode: remove } + +subreaktorreport_file: + url: /:sf_culture/:subreaktor/artwork/:id/:title/reportfile/:file + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: reportfile } + +report_file: + url: /:sf_culture/artwork/:id/:title/reportfile/:file + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: reportfile } + +removefilemessage: + url: /:sf_culture/admin/artwork/removefilemessage/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: removeFileMessage} + +subreaktorupload_content: + url: /:sf_culture/:subreaktor/upload + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: upload} + +upload_content: + url: /:sf_culture/upload + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: upload} + + +# Content server + +content_server: + url: /content/:id/:filename + requirements: { sf_culture: (?:no|nn|en) } + param: { module: contentServer, action: contentServer} + +content_thumb: + url: /content/:id/thumb/:filename + requirements: { sf_culture: (?:no|nn|en) } + param: { module: contentServer, action: contentThumb} + +content_mini: + url: /content/:id/mini/:filename + requirements: { sf_culture: (?:no|nn|en) } + param: { module: contentServer, action: contentMini} + +content_original: + url: /content/:id/original/:filename + requirements: { sf_culture: (?:no|nn|en) } + param: { module: contentServer, action: contentOriginal} + +# Artwork display / management + +artwork_link: + url: /:sf_culture/upload/link/:link_artwork_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: upload} + +subreaktorartwork_link: + url: /:sf_culture/:subreaktor/upload/link/:link_artwork_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: upload, action: upload} + +subreaktorshow_artwork_file: + url: /:sf_culture/:subreaktor/artwork/show/:id/:file/:title + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: show } + +show_artwork_file: + url: /:sf_culture/artwork/show/:id/:file/:title + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: show } + +subreaktorshow_artwork: + url: /:sf_culture/:subreaktor/artwork/show/:id/:title + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: show } + +show_artwork: + url: /:sf_culture/artwork/show/:id/:title + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: show } + +show_artwork_titleless: + url: /:sf_culture/artwork/show/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: show } + +subreaktorshow_artwork_metadata: + url: /:sf_culture/:subreaktor/artwork/showmetadata/:id/:title + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: showMetadata } + +show_artwork_metadata: + url: /:sf_culture/artwork/showmetadata/:id/:title + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: showMetadata } + +remove_metadata: + url: /:sf_culture/artwork/removemetadata/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: removeMetadata } + +show_artwork_xml: + url: /:sf_culture/artwork/showxml/:id/:format + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: showXML } + +subreaktoredit_artwork: + url: /:sf_culture/:subreaktor/artwork/edit/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: edit} + +edit_artwork: + url: /:sf_culture/artwork/edit/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: edit} + +edit_nodecor_artwork: + url: /:sf_culture/artwork/edit_nodecor/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: edit} + +re_transcode_file: + url: /:sf_culture/artwork/edit/retranscode/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: reTranscode} + +transcoderlog: + url: /:sf_culture/artwork/transcoderlog/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: transcoderLog} + +show_discussion: + url: /:sf_culture/admin/discuss/:type/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: discuss } + +subreaktorshow_discussion: + url: /:sf_culture/:subreaktor/admin/discuss/:type/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: discuss } + +subreaktorrejectartwork: + url: /:sf_culture/:subreaktor/artwork/reject/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: rejectArtwork} + +rejectartwork: + url: /:sf_culture/artwork/reject/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: rejectArtwork} + +subreaktorartwork_status: + url: /:sf_culture/:subreaktor/artwork/changeartworkstatus/:status/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: changeArtworkStatus} + +artwork_mark_discussion: + url: /:sf_culture/admin/artwork_status/discussion/:id/:status + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: changeDiscussionStatus, type: artwork } + +file_mark_discussion: + url: /:sf_culture/admin/file_status/discussion/:id/:status + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: changeDiscussionStatus, type: file } + +artwork_status: + url: /:sf_culture/artwork/changeartworkstatus/:status/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: changeArtworkStatus } + +artwork_status_returndetails: + url: /:sf_culture/artwork/changeartworkstatus/returndetails/:status/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: changeArtworkStatus, returndetails: true} + +accept_artwork_modifications: + url: /:sf_culture/artwork/acceptartworkmodifications/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: acceptArtworkModifications } + +accept_file_modifications: + url: /:sf_culture/artwork/acceptfilemodifications/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: acceptFileModifications } + +subreaktorartworklist: + url: /:sf_culture/:subreaktor/artworklist/:user + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: list} + +artworklist: + url: /:sf_culture/artworklist/:user + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: list} + +subreaktorremovefile: + url: /:sf_culture/:subreaktor/artwork/removefile/:artworkId/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: removeFileMessage} + +removefile: + url: /:sf_culture/artwork/removefile/:artworkId/:fileId + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: removeFileMessage} + +subreaktorflag_ok_file: + url: /:sf_culture/:subreaktor/artwork/okfile/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: OkFile} + +flag_ok_file: + url: /:sf_culture/artwork/okfile/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: OkFile} + +subreaktorflag_suitable_file: + url: /:sf_culture/:subreaktor/artwork/suitablefile/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: suitableFile} + +flag_suitable_file: + url: /:sf_culture/artwork/suitablefile/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: suitableFile} + +subreaktorartworklastartworksfromuseraction: + url: /:sf_culture/:subreaktor/artwork/lastartworksfromuseraction/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: lastArtworksFromUserAction } + +artworklastartworksfromuseraction: + url: /:sf_culture/artwork/lastartworksfromuseraction/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: lastArtworksFromUserAction } + +relateartwork: + url: /:sf_culture/artwork/relate/:id/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: relateArtwork} + +crosslink_all_artworks: + url: /:sf_culture/artwork/crossrelate/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: crossRelateArtwork} + +removeartworkrelation: + url: /:sf_culture/artwork/removerelation/:viewartwork/:relatedartwork + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: removeArtworkRelation } + +addartworkrecommendation: + url: /:sf_culture/artwork/add/recommendation/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: addRecommendation } + +artworkupdate: + url: /:sf_culture/artwork/update + requirements: { sf_culture: (?:no|nn|en) } + param: { module: artwork, action: update } + +# Tags and tagging + +subreaktorfindtags: + url: /:sf_culture/:subreaktor/tags/find/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: find } + +subreaktorfindcategory: + url: /:sf_culture/:subreaktor/category/:category/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: findcategory } + +findtags: + url: /:sf_culture/tags/find/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: find } + +subreaktorfindsubreaktortags: + url: /:sf_culture/:subreaktor/tags/find/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: find } + +findsubreaktortags: + url: /:sf_culture/tags/find/:tag + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: find } + +tags: + url: /:sf_culture/tags/index/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: tags, action: index} + +# Login and user routes + +subreaktorsf_guard_signin: + url: /:sf_culture/:subreaktor/login + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardAuth, action: signin } + +sf_guard_signin: + url: /:sf_culture/login + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardAuth, action: signin } + +subreaktorsf_guard_signout: + url: /:sf_culture/:subreaktor/logout + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardAuth, action: signout } + +sf_guard_signout: + url: /:sf_culture/logout + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardAuth, action: signout } + +#deprecated - now ajax only profile/passRequest +#sf_guard_password: +# url: /:sf_culture/request_password +# requirements: { sf_culture: (?:no|nn|en) } +# param: { module: profile, action: password } + +#register_alternate: +# url: /:sf_culture/register_alternate +# param: { module: sfGuardUser, action: create } + +subreaktorregister: + url: /:sf_culture/:subreaktor/register + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: register} + +register: + url: /:sf_culture/register + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: register} + +subreaktorprofile: + url: /:sf_culture/:subreaktor/profile + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: edit} + +profile: + url: /:sf_culture/profile + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: edit} + +otherprofile: + url: /:sf_culture/profile/edit/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: edit} + +subreaktorotherprofile: + url: /:sf_culture/:subreaktor/profile/edit/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: profile, action: edit} + +viewotherprofile: + url: /:sf_culture/admin/edit/user/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfGuardUser, action: edit } + +#Translation + +trans_list: + url: /:sf_culture/admin/translation/list/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfTransUnit, action: list} + +trans_edit: + url: /:sf_culture/admin/translation/edit/:msg_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfTransUnit, action: edit} + +trans_edit2: + url: /:sf_culture/admin/translation/edit/msg_id/:msg_id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfTransUnit, action: edit} + +trans_unit_setculture: + url: /:sf_culture/trans_unit/setCulture/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfTransUnit, action: setCulture} + +translateFormAction: + url: /:sf_culture/translate/new + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfTransUnit, action: newTranslation} + +subreaktortranslateFormAction: + url: /:sf_culture/:subreaktor/translate/new + requirements: { sf_culture: (?:no|nn|en) } + param: { module: sfTransUnit, action: newTranslation} + +#RSS Feeds + +adminfeed: + url: /:sf_culture/feed/admin/:slug/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: adminFeed } + +subreaktoradminfeed: + url: /:sf_culture/:subreaktor/feed/admin/:slug/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: adminFeed } + +artworkfeed: + url: /:sf_culture/feed/:slug + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: artworkFeed } + +subreaktorartworkfeed: + url: /:sf_culture/:subreaktor/feed/:slug + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: artworkFeed } + +showfilefeed: + url: /:sf_culture/feed/:slug/:id/files + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: fileFeed } + +subreaktorshowfilefeed: + url: /:sf_culture/:subreaktor/feed/:slug/:id/files + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: fileFeed } + +userfeed: + url: /:sf_culture/feed/:slug/:username/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: userFeed } + +subreaktoruserfeed: + url: /:sf_culture/:subreaktor/feed/:slug/:username/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: userFeed } + +feedindex: + url: /:sf_culture/rssfeeds + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: list } + +subreaktorfeedindex: + url: /:sf_culture/:subreaktor/rssfeeds + requirements: { sf_culture: (?:no|nn|en) } + param: { module: feed, action: list } + +# Report rules + +deletereport: + url: /:sf_culture/admin/reports/delete/:id + requirements: { sf_culture: (?:no|nn|en) } + param: { module: reports, action: deleteReport } + +userreports: + url: /:sf_culture/admin/reports/user/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: reports, action: userReports } + +most_active: + url: /:sf_culture/admin/mostactiveusers + requirements: { sf_culture: (?:no|nn|en) } + param: { module: admin, action: getMostActiveUsers } + + +artworkreports: + url: /:sf_culture/admin/reports/artwork/* + requirements: { sf_culture: (?:no|nn|en) } + param: { module: reports, action: artworkReports } + +showReportBookmarks: + url: /:sf_culture/admin/reports/bookmarks + requirements: { sf_culture: (?:no|nn|en) } + param: { module: reports, action: showBookmarks } + +reportBookmarkSave: + url: /:sf_culture/admin/reports/bookmark/savenew + requirements: { sf_culture: (?:no|nn|en) } + param: { module: reports, action: saveNewBookmark } + +# default rules + +subreaktorhome: + url: /:sf_culture/:subreaktor + requirements: { sf_culture: (?:no|nn|en) } + param: { module: subreaktors, action: index } + +home: + url: / + param: { module: home, action: index } + +home_translated: + url: /:sf_culture + requirements: { sf_culture: (?:no|nn|en) } + param: { module: home, action: index } + +default_trick: + url: /:sf_culture/default/index + requirements: { sf_culture: (?:no|nn|en) } + param: { module: home, action: error404 } + +default_index: + url: /:sf_culture/:module + requirements: { sf_culture: (?:no|nn|en) } + param: { action: index } + +default: + url: /:sf_culture/:module/:action/* + requirements: { sf_culture: (?:no|nn|en) } + + diff --git a/apps/reaktor/config/security.yml b/apps/reaktor/config/security.yml new file mode 100644 index 0000000..25b4f0a --- /dev/null +++ b/apps/reaktor/config/security.yml @@ -0,0 +1,2 @@ +default: + is_secure: on diff --git a/apps/reaktor/config/settings.yml b/apps/reaktor/config/settings.yml new file mode 100644 index 0000000..0c0ef7e --- /dev/null +++ b/apps/reaktor/config/settings.yml @@ -0,0 +1,105 @@ +prod: + .settings: + no_script_name: on + error_reporting: 4095 + cache: on +dev: + .settings: + # E_ALL | E_STRICT = 4095 + error_reporting: 8191 + web_debug: on + cache: on + no_script_name: off + etag: off + +test: + .settings: + # E_ALL | E_STRICT & ~E_NOTICE = 2047 + error_reporting: 2047 + cache: off + web_debug: off + no_script_name: off + etag: off + +all: + .actions: + default_module: home # Default module and action to be called when + default_action: index # A routing rule doesn't set it +# + error_404_module: home # To be called when a 404 error is raised + error_404_action: error404 # Or when the requested URL doesn't match any route +# + login_module: sfGuardAuth # To be called when a non-authenticated user + login_action: signin # Tries to access a secure page + + secure_module: sfGuardAuth # To be called when a user doesn't have + secure_action: secure # The credentials required for an action +# +# module_disabled_module: default # To be called when a user requests +# module_disabled_action: disabled # A module disabled in the module.yml +# +# unavailable_module: default # To be called when a user requests a page +# unavailable_action: unavailable # From an application disabled via the available setting below +# + .settings: +# available: on # Enable the whole application. Switch to off to redirect all requests to the unavailable module and action. +# +# # Optional features. Deactivating unused features boots performance a bit. +# use_database: on # Enable database manager. Set to off if you don't use a database. +# use_security: on # Enable security features (login and credentials). Set to off for public applications. +# use_flash: on # Enable flash parameter feature. Set to off if you never use the set_flash() method in actions. + i18n: on # Enable interface translation. Set to off if your application should not be translated. +# check_symfony_version: off # Enable check of symfony version for every request. Set to on to have symfony clear the cache automatically when the framework is upgraded. Set to off if you always clear the cache after an upgrade. +# use_process_cache: on # Enable symfony optimizations based on PHP accelerators. Set to off for tests or when you have enabled a PHP accelerator in your server but don't want symfony to use it internally. +# compressed: off # Enable PHP response compression. Set to on to compress the outgoing HTML via the PHP handler. +# check_lock: off # Enable the application lock system triggered by the clear-cache task. Set to on to have all requests redirected to the $sf_symfony_data_dir/web/arrors/unavailable.php page during the clear-cache process. +# +# # Output escaping settings +# escaping_strategy: bc # Determines how variables are made available to templates. Accepted values: bc, both, on, off. The value off deactivates escaping completely and gives a slight boost. +# escaping_method: ESC_ENTITIES # Function or helper used for escaping. Accepted values: ESC_RAW, ESC_ENTITIES, ESC_JS, ESC_JS_NO_ENTITIES. +# +# # Routing settings +# relative_url_root: # Default URL prefix. Use this when your symfony project is installed in a sub directory of the apache document root. +# suffix: . # Default suffix for generated URLs. If set to a single dot (.), no suffix is added. Possible values: .html, .php, and so on. +# no_script_name: off # Enable the front controller name in generated URLs +# +# # Validation settings, used for error generation by the Validation helper +# validation_error_prefix: ' ↓ ' +# validation_error_suffix: '  ↓' +# validation_error_class: form_error +# validation_error_id_prefix: error_for_ +# +# # Cache settings +# cache: off # Enable the template cache +# etag: on # Enable etag handling +# +# # Logging and debugging settings +# web_debug: off # Enable the web debug toolbar +# error_reporting: 341 # Determines which events are logged. The default value is E_PARSE | E_COMPILE_ERROR | E_ERROR | E_CORE_ERROR | E_USER_ERROR = 341 +# +# # Assets paths +# rich_text_js_dir: js/tiny_mce + prototype_web_dir: +# admin_web_dir: /sf/sf_admin +# web_debug_web_dir: /sf/sf_web_debug +# +# # Helpers included in all templates by default +# standard_helpers: [Partial, Cache, Form] + standard_helpers: [I18N, Validation, Form, Tags, Partial, subreaktor, browserDetection] +# # Activated modules from plugins or from the symfony core + enabled_modules: [sfGuardGroup, sfGuardUser, sfGuardPermission, sfGuardAuth, sfMediaLibrary, sfThumbnail, sfPropelActAsTaggableBehavior, sfPropelActAsCommentableBehavior, sfComment, sfRating, getId3, sfI18nDbTranslation, sfTransUnit, recaptcha] +# +# # Charset used for the response + charset: utf-8 +# +# # Miscellaneous +# strip_comments: on # Remove comments in core framework classes as defined in the core_compile.yml +# autoloading_functions: ~ # Functions called when a class is requested and this it is not already loaded. Expects an array of callables. Used by the framework bridges. +# timeout: 1800 # Session timeout, in seconds +# max_forwards: 5 +# path_info_array: SERVER +# path_info_key: PATH_INFO +# url_format: PATH +# +# # ORM +# orm: propel diff --git a/apps/reaktor/config/view.yml b/apps/reaktor/config/view.yml new file mode 100644 index 0000000..16e5db9 --- /dev/null +++ b/apps/reaktor/config/view.yml @@ -0,0 +1,22 @@ +default: + http_metas: + content-type: text/html + content-style-type: text/css + content-script-type: text/javascript + + metas: + title: Reaktor # Make sure this is the same in app.yml + robots: index, follow + description: Reaktor er et nettsted for deg med interesse for film, foto, animasjon, musikk, tegneserier, tekst og tegning. Her kan du legge ut egne verk, kommentere andres og bli kjent med folk med samme interesse. Reaktor er gratis og aapen for alle! + keywords: reaktor, minreaktor, minreaktor.no, egenproduserte verk, verk, egenprodusert, egenproduserte, foto, bilder, tegning, grafikk, illustrasjon, film, animasjon, kortfilm, flash, tegneserier, tekst, dikt, fortellinger, lyd, musikk, deichman, deichmanske bibliotek + language: en + + stylesheets: [main: {media: all}, /css/print: {media: print}] + + javascripts: [dw_cookies.js, dw_sizerdx.js, prototype.js, scriptaculous.js, main.js, VM_FlashContent.js] + + has_layout: on + layout: layout + + components: + sidebar_articles: [sidebar, sidebarArticles] diff --git a/apps/reaktor/lib/adminFilter.class.php b/apps/reaktor/lib/adminFilter.class.php new file mode 100644 index 0000000..de0fb4f --- /dev/null +++ b/apps/reaktor/lib/adminFilter.class.php @@ -0,0 +1,41 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +class adminFilter extends sfFilter +{ + public function execute ($filterChain) + { + // execute this filter only once + if ($this->isFirstCall()) + { + if ((sfContext::getInstance()->getModuleName() == 'admin' || strpos(sfContext::getInstance()->getRequest()->getUri(), '/admin') !== false) + && (sfContext::getInstance()->getUser()->hasCredential("admin") || sfContext::getInstance()->getUser()->hasCredential("staff"))) + { + sfConfig::set("admin_mode", true); + if (sfContext::getInstance()->getUser()->hasCredential("admin")) + { + sfContext::getInstance()->getResponse()->setTitle(sfConfig::get("app_site_title")." ".sfContext::getInstance()->getI18N()->__("administrator")); + sfConfig::set("app_site_title", sfConfig::get("app_site_title")." ".sfContext::getInstance()->getI18N()->__("administrator")); + sfConfig::set("app_admin_logo", sfConfig::get("admin_logo", "logoAdmin.gif")); + } + elseif (sfContext::getInstance()->getUser()->hasCredential("staff")) + { + sfContext::getInstance()->getResponse()->setTitle(sfConfig::get("app_site_title")." ".sfContext::getInstance()->getI18N()->__("editorial centre")); + sfConfig::set("app_site_title", sfConfig::get("app_site_title")." ".sfContext::getInstance()->getI18N()->__("editorial centre")); + sfConfig::set("app_admin_logo", sfConfig::get("redaksjon_logo", "reaktor_red.gif")); + } + } + } + // execute next filter + $filterChain->execute(); + } +} \ No newline at end of file diff --git a/apps/reaktor/lib/artworkFile.class.php b/apps/reaktor/lib/artworkFile.class.php new file mode 100644 index 0000000..a3a2e46 --- /dev/null +++ b/apps/reaktor/lib/artworkFile.class.php @@ -0,0 +1,1586 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseReaktorFilePeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseFileMimetype.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseFileMetadata.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/ReaktorFile.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/FileMimetype.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/FileMetadata.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseReaktorFilePeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseFileMimetypePeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseFileMetadataPeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/ReaktorFilePeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/FileMimetypePeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/FileMetadataPeer.php'; + +/** + * Artwork file class. Builds upon the ReaktorFile class, but doesn't extend it + * + * @author Daniel Andre Eikeland + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class artworkFile +{ + /** + * @var ReaktorFile + */ + protected $_reaktorfile; + + /** + * Parent artwork + * + * @var genericArtwork + */ + protected $_parentartworks = array(); + + /** + * Backtrack which artwork requested this file + * + * @var mixed + */ + protected $_parentartworkid = null; + + /** + * Whether the file is saved or not + * + * @var boolean + */ + protected $_isunsaved = true; + + /** + * An array of formats allowed when passed to the mimetype functions + * + * @var array + */ + protected $_allowedFormatArray = array("converted", "thumbnail", "original"); + + + /** + * If the file has been rejected, this variable can be set to hold the latest rejected message. + * It is stored in the reaktor_history table, so it has to be set manually before retrieving it + * from the object in a template. + * + * @var string + */ + protected $_rejectedMessage = ""; + + /** + * The file title, use sparingly as this needs to be extracted from the metadata table + * + * @var string + */ + protected $_title = null; + + /** + * An array of all the file metadata, populated on the first request for any metadata + * + * @var array + */ + protected $_metadata = null; + + /** + * Whether or not this file has a static (non animated) thumbnail + * This variable is populated on first request + * + * @var boolean + */ + protected $_hasStaticThumbnail = null; + + /** + * Returns a database resultset that can be used to retrieve one or more files, base on an + * id, or an array of ids + * + * @param mixed $id An integer, or an array of integers + * + * @return Resultset + */ + static function getResultsetFromIDs($id) + { + $c = new Criteria(); + $c->add(ReaktorArtworkFilePeer::FILE_ID, $id, Criteria::IN); + //$c->addJoin(ReaktorFilePeer::USER_ID, sfGuardUserPeer::ID); + $res = ReaktorArtworkFilePeer::doSelectJoinAll($c); + + if (empty($res)) + { + $c = new Criteria(); + $c->add(ReaktorFilePeer::ID, $id, Criteria::IN); + $res = ReaktorFilePeer::doSelectJoinAll($c); + } + return $res; + } + + /** + * Constructor function + * + * @param integer $id Id of the file object to retrieve, or null to create a new file + * @param genericArtwork $parentArtwork Single Parent artwork object if passed + * @param array $resultset Results from a reaktorFile query + * + * @throws Exception + */ + function __construct($id = null, $parentArtwork = null, $resultset = null) + { + if ($id !== null) + { + if (!$id instanceof ReaktorFile) + { + sfContext::getInstance()->getLogger()->info("Id was not null"); + if ($resultset === null) + { + sfContext::getInstance()->getLogger()->info("Resultset was empty, asking database to retrieve files"); + sfContext::getInstance()->getLogger()->info(get_class($resultset)); + $resultset = self::getResultsetFromIDs($id); + } + if (!empty($resultset) || $id instanceof ReaktorFile) + { + foreach ($resultset as $resultsetrow) + { + if ($resultsetrow instanceof ReaktorArtworkFile) + { + sfContext::getInstance()->getLogger()->info("I was a ReaktorArtworkFile"); + $reaktorfile = $resultsetrow->getReaktorFile(); + } + else + { + sfContext::getInstance()->getLogger()->info("No I wasn't"); + $reaktorfile = $resultsetrow; + } + if ($reaktorfile->getId() == $id) + { + break; + } + } + } + } + else + { + $reaktorfile = $id; + } + $this->_reaktorfile = $reaktorfile; + + if ($parentArtwork instanceof genericArtwork ) + { + sfContext::getInstance()->getLogger()->info("I happened"); + $this->_parentartworks[$parentArtwork->getID()] = $parentArtwork; + $this->setParentArtworkId($parentArtwork->getID()); + } + elseif ($reaktorfile instanceof ReaktorFile) + { + sfContext::getInstance()->getLogger()->info("Getting New artwork"); + foreach ($reaktorfile->getReaktorArtworkFiles() as $anArtworkFile) + { + if ($anArtworkFile->getReaktorArtwork()->getStatus() != ReaktorArtwork::REMOVED) + { + $this->_parentartworks[$anArtworkFile->getReaktorArtwork()->getID()] = new genericArtwork($anArtworkFile->getReaktorArtwork(), null, array(), null, $this); + } + } + } + else + { + sfContext::getInstance()->getLogger()->info("Nothing happened"); + } + + if ($this->_reaktorfile instanceof ReaktorFile) + { + $this->_isunsaved = false; + $this->_identifier = $this->_reaktorfile->getIdentifier(); + } + else + { + throw new Exception('This file does not exist'); + } + } + else + { + $this->_reaktorfile = new ReaktorFile(); + } + + // If this file format is "crop safe" then we can set it now + if (in_array($this->getMimetype("thumbnail"), sfConfig::get("app_upload_crop_safe_mime", array()))) + { + $this->_hasStaticThumbnail = true; + } + + sfContext::getInstance()->getLogger()->info("Finished constructing Reaktorfile"); + } + + /** + * Saves the file to database + * + * @return void; + */ + function save() + { + $this->_reaktorfile->save(); + $this->_isunsaved = false; + } + + /** + * Returns the current license of the file. + * + * @see getMetadata() + * + * @return string + */ + function getLicense() + { + return $this->getMetadata('license'); + } + + /** + * Get the reason why this file has been reported as unsuitable + * + * @return string The unsuitable message as it was sent to the user + */ + function getRejectedMessage() + { + return $this->_rejectedMessage; + } + + /** + * Set the reason why this file has been reported as unsuitable + * + * @param string $message The unsuitable message as it was sent to the user + * @return boolean + */ + function setRejectedMessage($message) + { + $this->_rejectedMessage = $message; + return true; + } + /** + * Get subreaktors associated with this file + * + * @param boolean $ids Return an array of subreaktor IDs rather than objects + * + * @return array subreaktor references (from subreaktor table) + */ + function getSubreaktors($ids = false) + { + $c = new Criteria(); + $c->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->getId()); + + $results = SubreaktorArtworkPeer::doSelectJoinSubreaktor($c); + + $returnArray = array(); + foreach($results as $result) + { + if ($ids) + { + $returnArray[] = $result->getSubreaktorId(); + } + else + { + $returnArray[] = $result->getSubreaktor()->getReference(); + } + } + return $returnArray; + } + + /** + * Return the identifier of the file (image, pdf etc) + * + * @return string the identifier + */ + function getIdentifier() + { + return $this->_reaktorfile->getIdentifier(); + } + + /** + * Returns the file type, which is the identifier from the location table + * + * @return string + */ + function getFiletype() + { + if (isset($this->_identifier)) + { + $identifier = $this->_identifier; + } + else + { + $identifier = $this->_reaktorfile->getIdentifier(); + } + return $identifier; + } + + /** + * Sets the file path and name + * + * @param string $path filename, on disk + * + * @return void + */ + function setPath($path) + { + $this->_reaktorfile->setRealpath($path); + $this->_isunsaved = true; + } + + /** + * Marks the current file as unsuitable + * + * @param integer $adminUserId The ID of the user making this change + * + * @return void + */ + function setUnsuitable($adminUserId, $comment) + { + $this->_reaktorfile->setReported(0); + $this->_reaktorfile->setMarkedUnsuitable(1); + $this->_reaktorfile->setReportedAt(time()); + TaggingPeer::setTaggingApproved(null, "ReaktorFile", $this, 0); + ReaktorArtworkHistory::logAction($this->getId(), $adminUserId, $comment, 4, 0, 1); + + $this->_isunsaved = true; + } + + /** + * Marks the current file as suitable + * + * @param integer $adminUserId The ID of the user making this change + * + * @return void + */ + function setSuitable($adminUserId) + { + $this->_reaktorfile->setMarkedUnsuitable(0); + TaggingPeer::setTaggingApproved(null, "ReaktorFile", $this, 1); + HistoryPeer::logAction(2, $adminUserId, $this); + $this->_isunsaved = true; + } + + /** + * Return whether the files is marked as unsuitable or not. + */ + function isUnsuitable() + { + return $this->_reaktorfile->getMarkedUnsuitable(); + } + + /** + * Sets the Thumb name on the system + * + * @param string $thumb filename, on disk + * + * @return void + */ + function setThumbpath($thumb) + { + $this->_reaktorfile->setThumbpath($thumb); + $this->_isunsaved = true; + } + + /** + * Sets the Original name on the system + * + * @param string $name filename, on disk + * + * @return void + */ + function setOriginalpath($name) + { + $this->_reaktorfile->setOriginalpath($name); + $this->_isunsaved = true; + } + + /** + * Sets the file path and name + * + * @param string $filename Name of the file + * + * @return void + */ + function setFilename($filename) + { + $this->_reaktorfile->setFilename($filename); + $this->_isunsaved = true; + } + + /** + * Returns the order number for this file + * + * @return integer + */ + function getFileOrderPlacement() + { + return $this->_reaktorfile->getFileOrder(); + } + + + /** + * Set the title of the file + * + * @param string $title The title to set + * + * @return void + */ + function setTitle($title) + { + $this->_reaktorfile->setTitle($title); + $this->_isunsaved = true; + } + + /** + * Set the "uploaded at" time + * + * @param mixed $uploaded_at The time to set + * + * @return void + */ + function setUploadedAt($uploaded_at) + { + $this->_reaktorfile->setUploadedAt($uploaded_at); + $this->_isunsaved = true; + + } + + /** + * Get the "uploaded at" time + * + * @param boolean $timestamp Returns a timestamp if true + * + * @return string The date and time the file was uploaded + */ + function getUploadedAt($timestamp = false) + { + if ($timestamp) + { + return strtotime($this->_reaktorfile->getUploadedAt()); + } + else + { + return $this->_reaktorfile->getUploadedAt(); + } + } + + /** + * Get the "modified at" time + * + * @param boolean $timestamp Returns a timestamp if true + * + * @return string The date and time the file was last modified + */ + function getModifiedAt($timestamp = false) + { + if ($timestamp) + { + return strtotime($this->_reaktorfile->getmodifiedAt()); + } + else + { + return $this->_reaktorfile->getModifiedAt(); + } + } + + /** + * Set the "modified at" time + * + * @param datetime $time the time to set - leave empty for now, uses strtotime + * + * @return void + */ + function setModifiedAt($time = false) + { + if ($time) + { + $this->_reaktorfile->setModifiedAt($time); + } + else + { + $this->_reaktorfile->setModifiedAt(time()); + } + $this->_isunsaved = true; + } + + /** + * Set the file identifier + * + * @param string $identifier identifier + * + * @return void + */ + function setIdentifier($identifier) + { + if (!in_array($identifier, sfConfig::get("app_files_location_identifiers"))) + { + throw new exception ("Unsupported Identifier: ".$identifier); + } + + $this->_reaktorfile->setIdentifier($identifier); + $this->_isunsaved = true; + } + + /** + * Set the file mimetype, based on the mimetype from the file mimetype table + * + * @param string $mimetype The mimetype of the file + * @param string $format The format we are setting for (converted (d), thumbnail, original) + * + * @return void + */ + function setMimetype($mimetype, $format = "converted") + { + $crit = new Criteria(); + $crit->add(FileMimetypePeer::MIMETYPE, $mimetype); + $themimetype = FileMimetypePeer::doSelectOne($crit); + + if (!$themimetype) + { + $themimetype = new FileMimetype(); + $themimetype->setMimetype($mimetype); + if (!$this->getIdentifier()) + { + throw new Exception("You must set the identifier before setting a mime type that does not yet exist in the database"); + } + $themimetype->setIdentifier($this->getIdentifier()); + $themimetype->save(); + } + + if ($themimetype instanceof FileMimetype) + { + if (in_array(strtolower($format), $this->_allowedFormatArray)) + { + $funcToCall = "set".ucfirst($format)."MimetypeId"; + } + else + { + throw new Exception("Invalid format specified"); + } + $this->_reaktorfile->$funcToCall($themimetype->getId()); + } + else + { + if (sfContext::getInstance()->getUser()->hasCredential("viewdetailederrors")) + { + throw new Exception("Failed when trying to set mime type on file record: Invalid mime type: ".$mimetype); + } + throw new Exception("Invalid file type, the upload failed"); + } + $this->_isunsaved = true; + } + + /** + * Returns the mimetype of the file + * + * @param string $format converted (default), thumb or original + * + * @return string + */ + function getMimetype($format = "converted") + { + if (in_array(strtolower($format), $this->_allowedFormatArray)) + { + $funcToCall = "get".ucfirst($format)."MimetypeId"; + } + else + { + throw new Exception("Invalid format specified"); + } + $mimetype = FileMimetypePeer::retrieveByPK($this->_reaktorfile->$funcToCall()); + return $mimetype instanceof FileMimetype ? $mimetype->getMimetype() : ""; + } + + /** + * Returns the artwork file id + * + * @return integer + */ + function getId() + { + return $this->_reaktorfile->getId(); + } + + /** + * Set the user id of the file, to define who uploaded it + * + * @param integer $uid The user id to save + * + * @return void + */ + function setUserId($uid) + { + $this->_reaktorfile->setUserId($uid); + } + + /** + * Returns the user id of the user who submitted the file + * + * @return integer + */ + function getUserId() + { + return $this->_reaktorfile->getUserId(); + } + + /** + * Returns the user who submitted the file + * + * @return sfGuardUser + */ + function getUser() + { + return $this->_reaktorfile->getSfGuardUser(); + } + + /** + * Saves the user of the file, to define who uploaded it + * + * @param sfGuardUser $user The user to save + * + * @return void + */ + function setUser($user) + { + $this->_reaktorfile->setUserId($user->getId()); + } + + /** + * Stores the given metadata as a tag for the current object + * + * @param string $element The metadata element to save + * @param string $qualifier The metadata qualifier to save, or null to nut specify qualifier + * @param mixed $value The metadata value to save + * + * @return nothing + * + * @throws Exception + */ + function addMetadata($element, $qualifier = null, $value) + { + $element = strtolower($element); + + $qualifier = !$qualifier ? null : strtolower($qualifier); + if ($this->_isunsaved) + { + throw new Exception('You cannot add metadata to an unsaved file. Please save the file first.'); + } + try + { + if ($this->getMetadata($element, $qualifier) !== false ) + { + $crit = new Criteria(); + $crit->add(FileMetadataPeer::META_ELEMENT, $element); + $crit->add(FileMetadataPeer::FILE, $this->getId()); + if ($qualifier != null) + { + $crit->add(FileMetadataPeer::META_QUALIFIER, $qualifier); + } + $updatedMetadata = FileMetadataPeer::doSelectOne($crit); + $updatedMetadata->setMetaValue($value); + $updatedMetadata->save(); + if($this->_metadata) + { + $this->_metadata[$element][$qualifier] = $value; + } + } + else + { + $newMetadata = new FileMetadata(); + $newMetadata->setFile($this->_reaktorfile->getId()); + $newMetadata->setMetaElement($element); + if ($qualifier != null) + { + $newMetadata->setMetaQualifier($qualifier); + } + $newMetadata->setMetaValue($value); + $newMetadata->save(); + } + } + catch (Exception $e) + { + throw $e; + } + // The data has changes so let's update the holder + } + + /** + * Returns an array of FileMetadata objects of all metadata associated with that file + * Also populates the metadata array so we can access the values later if loaded + * + * @param $returnArray Returns an array, rather then objects, of metadatas + * @return array|FileMetadata + */ + function getMetadatas($returnArray = true) + { + $c = new Criteria(); + $c->addAscendingOrderByColumn(FileMetadataPeer::META_ELEMENT); + $c->addAscendingOrderByColumn(FileMetadataPeer::META_QUALIFIER); + + if (!$returnArray) + { + return $this->_reaktorfile->getFileMetadatas($c); + } + elseif (!$this->_metadata) + { + foreach($this->_reaktorfile->getFileMetadatas($c) as $metadataObject) + { + $this->_metadata[$metadataObject->getMetaElement()][$metadataObject->getMetaQualifier()] = $metadataObject->getMetaValue(); + } + } + + return $this->_metadata; + } + + /** + * Returns a FileMetadata object which has the specified $element and $qualifier + * + * @param string $element The element item to get + * @param string $qualifier The qualifier to get or empty string if none is set + * + * @return string + */ + function getMetadata($element, $qualifier = "") + { + $element = strtolower($element); + $qualifier = ($qualifier == null) ? null : strtolower($qualifier); + + if (is_null($this->_metadata)) + { + $this->getMetadatas(); + } + + if (isset($this->_metadata[$element][$qualifier])) + { + return $this->_metadata[$element][$qualifier]; + } + + return false; + } + + /** + * Set/Return the title from the metadata table + * + * @return string + */ + public function getTitle() + { + if (is_null($this->_title)) + { + $this->_title = $this->getMetadata("title"); + } + return $this->_title; + } + + /** + * Returns whether the file has been reported as unsuitable or not + * + * @return boolean + */ + function isReported() + { + return ($this->_reaktorfile->getReported() == 0) ? false : true; + } + + /** + * Get embed link to the current file. + * + * @param int|artworkFile $file The file or file id + * + * @return string $url + */ + function getEmbedLink() + { + return $this->_reaktorfile->getEmbedLink($this); + } + + /** + * Return the tally for the number of times this has been reported + * since the last time it was marked ok + * + * @return integer + */ + function getReportedCount() + { + return $this->_reaktorfile->getReported(); + } + + /** + * Return the tally for the number of times this has even been reported + * + * @return integer + */ + function getTotalReportedCountEver() + { + return $this->_reaktorfile->getTotalReportedEver(); + } + + /** + * Return when the file was last reported + * + * @return date + */ + function getReportedAt() + { + return date("d/m/y H:i", strtotime($this->_reaktorfile->getReportedAt())); + } + + /** + * Reports the file as unsuitable (User does this not admin) + * + * @param integer|sfGuardUser $user The user reporting the file + * + * @return void + */ + function reportAsUnsuitable($user) + { + $this->_reaktorfile->setReported($this->_reaktorfile->getReported() + 1); + $this->_reaktorfile->setTotalReportedEver($this->_reaktorfile->getTotalReportedEver() + 1); + $this->_reaktorfile->setReportedAt(time()); + $this->_reaktorfile->save(); + + HistoryPeer::logAction(1, $user, $this); + } + + /** + * Restores the file to a clean state (unreported) + * + * @param integer|sfGuardUser $user User id or object + * + * @return void + */ + function reportAsSuitable($user) + { + $this->_reaktorfile->setReported(0); + $this->_reaktorfile->setMarkedUnsuitable(0); + $this->_reaktorfile->save(); + + HistoryPeer::logAction(2, $user, $this); + } + + /** + * Marks the file as unsuitable (not just reporting it) + * + * @param integer|sfGuardUser $user User id or object + */ + function markAsUnsuitable($user) + { + $this->_reaktorfile->setMarkedUnsuitable(1); + $this->_reaktorfile->save(); + + HistoryPeer::logAction(3, $user, $this); + } + + /** + * Tags the artwork with the given tag + * + * @param string $tag The tag to add + * + * @return void + */ + function addTag($tag) + { + return $this->addOrRemoveTag($tag, "add"); + } + + /** + * Remove the given tag from the file and (optional) linked files + * If they are category tags only, since it will affect the whole artwork + * + * @param string $tag The tag to remove + * + * @return void + */ + function removeTag($tag) + { + return $this->addOrRemoveTag($tag, "remove"); + } + + /** + * The add and remove tag functions are very similar, so created this to prevent code duplication + * + * @param string $tag The tag to add + * @param boolean $recursive If true adds to linked files also + * @param boolean $approve Instantly approve the tag/tagging + * @param array $categoryMatches Used in recursive functions to save queries + * @param string $mode Called internally, add or remove + * + * @return void just does the job + */ + protected function addOrRemoveTag($tag, $mode) + { + switch ($mode) + { + case "add": + sfContext::getInstance()->getLogger()->info("Adding tag: ".$tag); + $this->_reaktorfile->addTag($tag); + TagPeer::setTagWidthByName($tag); + break; + case "remove": + sfContext::getInstance()->getLogger()->info("Removing tag: ".$tag." from ".$this->getId()); + $this->_reaktorfile->removeTag($tag); + break; + default: + throw new exception ("Mode not handled"); + break; + } + $this->_reaktorfile->save(); + $this->updateTagMetadata(); + } + + /** + * Function to update the "subject" meta element of a file's metadata + * for Dublin core purposes - should be run every time tags on a file are changed or tags are + * approved/unapproved, in which case all files with those tags will need to be updated. This will only + * ever affect a small number of files so is not a problem. + * + * @return null + */ + public function updateTagMetadata() + { + $tagArray = $this->getTags(false); + $tagString = !empty($tagArray) ? implode(", ", $tagArray) : ""; + $this->addMetadata("subject", null, $tagString); + + // We need to clear the tag lists of all the parent artworks since they have just changed + foreach ($this->getParentArtworks() as $artwork) + { + reaktorCache::delete("artwork_tag_list_".$artwork->getId()); + } + } + + /** + * Removes all tags from the file + * + * @return void + */ + function removeAllTags() + { + $this->_reaktorfile->removeAllTags(); + $this->updateTagMetadata(); + } + + /** + * Returns the number of tags + * + * @param bool $include_unapproved + * @return int + */ + public function countTags($include_unapproved = true) + { + return count($this->getTags($include_unapproved)); + } + + /** Returns all the tags attached to this file + * + * @param boolean $includeUnapproved show unapproved also + * @param boolean $returnObjects return tag objects instead of tag names + * + * @return array the name field from tag entry + */ + function getTags($includeUnapproved = false, $returnObjects = false) + { + $tags_arr = array(); + + $c = new Criteria(); + if ($includeUnapproved == false) + { + $c->add(TagPeer::APPROVED, 1); + } + $c->add(TaggingPeer::TAGGABLE_ID, $this->getId()); + $c->add(TaggingPeer::TAGGABLE_MODEL, "ReaktorFile"); + $c->addJoin(TagPeer::ID, TaggingPeer::TAG_ID); + + $tagObjectArray = TagPeer::doSelect($c); + if ($returnObjects) + { + return $tagObjectArray; + } + + foreach ($tagObjectArray as $tagObject) + { + $tags_arr[] = $tagObject->getName(); + } + + return $tags_arr; + } + + /** + * Returns the filename + * + * @return string + */ + function getFilename() + { + return $this->_reaktorfile->getFilename(); + } + + /** + * Returns the filename on the hard disk + * + * @return string + */ + function getRealpath() + { + return $this->_reaktorfile->getRealpath(); + } + + /** + * Returns the thumbnail filename on the hard disk or the complete path + * + * @param boolean $absolute if true, return the full path to the file on disk + * + * @return string + */ + function getThumbpath($absolute = false) + { + if ($absolute) + { + $path = sfConfig::get('sf_root_dir')."/".sfConfig::get('app_upload_upload_dir')."/"; + $path .= $this->getIdentifier()."/thumbnail/".$this->_reaktorfile->getThumbPath(); + } + else + { + $path = $this->_reaktorfile->getThumbPath(); + } + return $path; + } + + /** + * Returns the original filename on the hard disk + * + * @return string + */ + function getOriginalpath() + { + return $this->_reaktorfile->getOriginalPath(); + } + + /** + * Returns the path to the real file on the filesystem + * + * @param string $type The type to return default is normal (thumb, full, etc) + * @param boolean $dirOnly Set trur to return just the directory and not the file name + */ + function getFullFilePath($type = "normal", $dirOnly = false) + { + $basePath = sfConfig::get("sf_root_dir")."/".sfConfig::get("app_upload_upload_dir")."/".$this->getIdentifier()."/"; + + switch ($type) + { + case "normal": + $subdirs = ""; + $filename = $this->getRealpath(); + break; + case "thumb": + $subdirs = "thumbnail/"; + $filename = $this->getThumbpath(); + break; + case "mini": + $subdirs = "thumbnail/mini/"; + $filename = $this->getThumbpath(); + break; + case "original": + $subdirs = "original/"; + $filename = $this->getOriginalpath(); + break; + default: + throw new Exception("Unsupported type"); + break; + } + if ($dirOnly) + { + return $basePath.$subdirs; + } + else + { + return $basePath.$subdirs.$filename; + } + } + + /** + * Checks whether this file is linked to any artwork already + * + * @return boolean + */ + function hasArtwork() + { + if (!empty($this->_parentartworks)) + { + return true; + } + else + { + return false; + } + } + + /** + * Returns the artwork objects that are parents to this file + * It may be possible to use files with more than one artwork at + * some point + * + * @param boolean $ids Whether to return just an array of IDs + * + * @return genericArtwork + */ + function getParentArtworks($ids = false) + { + if (!is_array($this->_parentartworks)) + { + throw new Exception("Artwork array does not exist"); + } + if ($ids) + { + $resultArray = array(); + foreach ($this->_parentartworks as $artwork) + { + $resultArray[] = $artwork->getId(); + } + return $resultArray; + } + return $this->_parentartworks; + } + + /** + * Return how many artworks this file is part of + * + * @return integer + */ + public function countParentArtworks() + { + return count($this->_parentartworks); + } + + /** + * Temporary function so things don't break during refactoring + * + * @return genericArtwork + */ + function getParentArtwork() + { + if (!is_array($this->_parentartworks)) + { + throw new Exception("Artwork array does not exist"); + } + else + { + // Return first element only + reset($this->_parentartworks); + return current($this->_parentartworks); + } + } + + /** + * Make it possible to backtrack which artwork is working with the file + * + * @param mixed $id The parent artwork ID + * @return void + */ + function setParentArtworkId($id) + { + $this->_parentartworkid = (int)$id; + } + + /** + * Completely delete a file from the database, along with it's hard copies + * + * @return void + */ + public function deleteFile() + { + $baseDir = $this->getFullFilePath(); + $file = $baseDir.$this->getRealpath(); + $thumb = $baseDir."thumbnail/".$this->getThumbpath(); + $mini = $baseDir."thumbnail/mini/".$this->getThumbpath(); + $original = $baseDir."original/".$this->getOriginalpath(); + + // Check for related artwork, is this the only file? + if ($this->hasArtwork()) + { + try + { + $parentArtworks = $this->getParentArtworks(); + + // Remove this file from the artwork + foreach ($parentArtworks as $parentArtwork) + { + $parentArtwork->removeFile($this); + } + } + catch (Exception $e) + { + throw new exception($e->getMessage()); + } + } + try + { + $this->_reaktorfile->delete(); + $this->removeAllTags(); + } + catch (Exception $e) + { + throw new exception($e->getMessage()); + } + + if (file_exists($file)) + { + unlink($file); + } + if (file_exists($thumb)) + { + unlink($thumb); + } + if (file_exists($mini)) + { + unlink($mini); + } + if (file_exists($original)) + { + unlink($original); + } + + // Clean up metadata + $this->removeAllMeta(); + } + + /** + * Remove all meta data attached to file as part of clean up process + * + * @return void + */ + public function removeAllMeta() + { + $c = new Criteria(); + $c->add(FileMetadataPeer::FILE, $this->getId()); + FileMetadataPeer::doDelete($c); + } + + /** + * Returns true if this is an image file + * + * @return void + */ + public function isImage() + { + if ($this->_reaktorfile->getIdentifier() == "image") + { + return true; + } + return false; + } + + /** + * Return the taggable model string to use in the tagging table + * + * @return string + */ + public function getTaggableModel() + { + return "ReaktorFile"; + } + + /** + * Return whether the file is under discussion or not + * + * @return boolean Typecast in case caller is using strict checks + */ + public function isUnderDiscussion() + { + return (bool)$this->_reaktorfile->getUnderDiscussion(); + } + + /** + * Mark this file as under discussion + * + * @return void + */ + public function markUnderDiscussion() + { + $this->_reaktorfile->setUnderDiscussion(1); + $this->_reaktorfile->save(); + HistoryPeer::logAction(6, sfContext::getInstance()->getUser()->getId(), $this); + } + + public function markNotUnderDiscussion() + { + $this->_reaktorfile->setUnderDiscussion(0); + $this->_reaktorfile->save(); + HistoryPeer::logAction(7, sfContext::getInstance()->getUser()->getId(), $this); + } + + /** + * Get by who and when the file was marked for discussion last. + * + * @return History + */ + public function getDiscussionInfo() + { + return HistoryPeer::getAction(6, $this); + } + + + /** + * Get number of comments an file has + * + * @param unknown_type $namespace + * @return unknown + */ + public function getCommentCount($namespace) + { + return $this->_reaktorfile->getCommentCount($namespace); + } + + /** + * Return the reaktor file object that we are working with + * + * @return reaktorFile + */ + public function getBaseObject() + { + return $this->_reaktorfile; + } + + /** + * This is required by the RSS plugin to generate the correct artwork route automatically + * Since sf_culture is a required parameter, the feed parameter looks for this function in the object automatically + * + * @return string the culture provided in the url (if any) + */ + public function getFeedSfCulture() + { + return sfContext::getInstance()->getRequest()->getParameter('sf_culture', 'no'); + } + + /** + * Return the parent artwork Id rather than the comment Id + * This is so the link back to the artwork is correct + * + * @return integer the artwork ID + */ + public function getFeedId() + { + return $this->getParentArtwork()->getId(); + } + + /** + * For the Artwork file feed + * + * Returning null lets the sfFeed classess create an IRI so we don't have to + * do magic stuff here. + * + * @return void + */ + public function getUniqueId() { + return null; + } + + /** + * Return the feed description for use in the RSS body + * + * @return string description from parent artwork object + */ + public function getFeedDescription() + { + return $this->getMetadata('description', 'abstract'); + } + + /** + * Return the file title for use in the RSS + * + * @return string dash separated title of parent artwork and current title + */ + public function getFeedTitle() + { + $parentTitle = $this->getParentArtwork()->getTitle(); + if ($parentTitle != $this->getTitle()) + { + return $parentTitle.' - '.$this->getTitle(); + } + + return $parentTitle; + } + + /** + * Returns the link to the current artworkfile under correct artwork + * + * @return void + */ + public function getFeedLink() + { + foreach($this->getParentArtworks() as $parent) + { + if ($parent->getId() == $this->_parentartworkid) + { + //return "@show_artwork_file?id={$parent->getId()}&file={$this->getId()}&title={$parent->getTitle()}"; + } + } + // Fallback to the last parent + return "@show_artwork_file?id={$parent->getId()}&file={$this->getId()}&title={$parent->getTitle()}"; + } + + /** + * The ID required for the routing + * + * @return integer the file id + */ + public function getFeedFile() + { + return $this->getId(); + } + + /** + * Get the provided subreaktor for Feed generator + * + * @return subreaktor|null + */ + public function getFeedSubreaktor() + { + if (subreaktor::isValid()) + { + return Subreaktor::getProvided(); + } + } + + /** + * Generate url to a thumbnail + * + * @return void + */ + public function getUrl() + { + return sfContext::getInstance()->getController()->genUrl("@content_thumb?id={$this->getId()}&filename={$this->getFilename()}", true); + } + public function getLength() + { + } + + /** + * Whether the file has been hidden or not + * + * @return boolean true if the file has been hidden by the user (they think it has been deleted) + */ + public function isHidden() + { + return (bool) $this->_reaktorfile->getHidden(); + } + + /** + * Sets a file as hidden (user deleted) + * + * @return null + */ + public function setHidden() + { + $this->_reaktorfile->setHidden(1); + // We need to check artworks that this file is associated with, and disable the ones that have no files now + foreach($this->getParentArtworks() as $artwork) + { + $artwork->removeFile($this); + } + } + + /** + * Unhide a file + * + * @return null + */ + public function setUnhidden() + { + $this->_reaktorfile->setHidden(0); + } + + + public function isDeleted(){ + return $this->_reaktorfile->getDeleted(); + } + + + /** + * Fill inn metadataholder but do not store in database. Useful when update form + * errs, and we need to display the already entered values, but do not want to store it yet. + * + * @param string $element + * @param string $qualifier + * @param mixed $value + */ + public function fillinMetaData($element, $qualifier = null, $value) + { + if (!$this->_metadata) + { + $this->getMetadatas(); + } + $this->_metadata[$element][$qualifier] = $value; + } + + /** + * Get the people who have reported the artwork + * + * @return array an array of user objects + */ + public function getReportHistory() + { + if (!$this->isReported()) + { + return array(); + } + return HistoryPeer::getByObjectAndAction($this, 1, $this->getReportedCount()); + } + + /** + * Return the name of the database table where these objects are stored + * + * @return string + */ + public function getTableName() + { + return "reaktor_file"; + } + + public function getFeedPubdate() { + return strtotime($this->_reaktorfile->getModifiedAt()); + } + + /** + * Returns true if the thumbnail for this file is NOT animated + * this is safer than the opposite, since we want to err on the side of caution + * + * return boolean + */ + public function hasStaticThumbnail() + { + if (is_bool($this->_hasStaticThumbnail)) + { + return $this->_hasStaticThumbnail; + } + else + { + $framesInThumb = exec("identify -format '%n' ".$this->getThumbpath(true), $output, $code); + if (!empty($output)) + { + if (is_numeric($output[0])) + { + $allTheFrames[0] = $output[0]; + } + else + { + $allTheFrames = explode("'", substr($output[0], 1)); + } + if ($allTheFrames[0] == 1) + { + $this->_hasStaticThumbnail = true; + return true; + } + $this->_hasStaticThumbnail = false; + return false; + } + } + } +} + diff --git a/apps/reaktor/lib/audioinfo.class.php b/apps/reaktor/lib/audioinfo.class.php new file mode 100644 index 0000000..d3b62f5 --- /dev/null +++ b/apps/reaktor/lib/audioinfo.class.php @@ -0,0 +1,282 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +//Autoloading not working on lab for some reason +require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . "plugins/getId3Plugin/lib/getid3.php"; + +/** + * Class wrapper for accessing needed info from getID3 libraries + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class audioInfo +{ + + /** + * Result + * + * @var array + */ + var $result = null; + + /** + * Info + * + * @var array + */ + var $info = null; + + /** + * Class constructor + * + * @return void + */ + function __construct() + { + + // Initialize getID3 engine + $this->getID3 = new getID3; + $this->getID3->option_md5_data = true; + $this->getID3->option_md5_data_source = true; + $this->getID3->encoding = 'UTF-8'; + } + + /** + * Extract information - only public function + * + * @param string $file Audio file to extract info from. + * + * @access public + * @return array info array + */ + function info($file) + { + + // Analyze file + $this->info = $this->getID3->analyze($file); + + // Exit here on error + if (isset($this->info['error'])) + { + return array ('error' => $this->info['error']); + } + + // Init wrapper object + $this->result = array (); + $this->result['format_name'] = @$this->info['fileformat'].'/'.@$this->info['audio']['dataformat'].(isset($this->info['video']['dataformat']) ? '/'.@$this->info['video']['dataformat'] : ''); + $this->result['encoder_version'] = @$this->info['audio']['encoder']; + $this->result['encoder_options'] = @$this->info['audio']['encoder_options']; + $this->result['bitrate_mode'] = @$this->info['audio']['bitrate_mode']; + $this->result['channels'] = @$this->info['audio']['channels']; + $this->result['sample_rate'] = @$this->info['audio']['sample_rate']; + $this->result['bits_per_sample'] = @$this->info['audio']['bits_per_sample']; + $this->result['playing_time'] = @$this->info['playtime_seconds']; + $this->result['avg_bit_rate'] = @$this->info['audio']['bitrate']; + $this->result['tags'] = @$this->info['tags']; + + // Post getID3() data handling based on file format + $method = @$this->info['fileformat'].'Info'; + if (@$this->info['fileformat'] && method_exists($this, $method)) + { + $this->$method(); + } + + return $this->result; + } + + /** + * post-getID3() data handling for AAC files. + * + * @access private + * @return array result + */ + function aacInfo() + { + $this->result['format_name'] = 'AAC'; + } + + /** + * post-getID3() data handling for Wave files. + * + * @access private + * @return array result + */ + function riffInfo() + { + if ($this->info['audio']['dataformat'] == 'wav') + { + $this->result['format_name'] = 'Wave'; + } + else if (ereg('^mp[1-3]$', $this->info['audio']['dataformat'])) + { + $this->result['format_name'] = strtoupper($this->info['audio']['dataformat']); + } + else + { + $this->result['format_name'] = 'riff/'.$this->info['audio']['dataformat']; + } + } + + /** + * * post-getID3() data handling for FLAC files. + * + * @access private + * @return array result + */ + function flacInfo() + { + $this->result['format_name'] = 'FLAC'; + } + + /** + * post-getID3() data handling for Monkey's Audio files. + * + * @access private + * @return array result + */ + function macInfo() + { + $this->result['format_name'] = 'Monkey\'s Audio'; + } + + /** + * post-getID3() data handling for Lossless Audio files. + * + * @access private + * @return array result + */ + function laInfo() + { + $this->result['format_name'] = 'La'; + } + + /** + * post-getID3() data handling for Ogg Vorbis files. + * + * @access private + * @return array result + */ + + function oggInfo() + { + if ($this->info['audio']['dataformat'] == 'vorbis') + { + + $this->result['format_name'] = 'Ogg Vorbis'; + + } + else if ($this->info['audio']['dataformat'] == 'flac') + { + + $this->result['format_name'] = 'Ogg FLAC'; + + } + else if ($this->info['audio']['dataformat'] == 'speex') + { + + $this->result['format_name'] = 'Ogg Speex'; + + } else + { + + $this->result['format_name'] = 'Ogg '.$this->info['audio']['dataformat']; + + } + } + + /** + * post-getID3() data handling for Musepack files. + * + * @access private + * @return array result + */ + function mpcInfo() + { + $this->result['format_name'] = 'Musepack'; + } + + /** + * post-getID3() data handling for MPEG files. + * + * @access private + * @return array result + */ + function mp3Info() + { + $this->result['format_name'] = 'MP3'; + } + + /** + * post-getID3() data handling for MPEG files. + * + * @access private + * @return array result + */ + + function mp2Info() + { + $this->result['format_name'] = 'MP2'; + } + + + /** + * post-getID3() data handling for MPEG files. + * + * @access private + * @return array result + */ + function mp1Info() + { + $this->result['format_name'] = 'MP1'; + } + + /** + * post-getID3() data handling for WMA files. + * + * @access private + * @return array result + */ + function asfInfo() + { + $this->result['format_name'] = strtoupper($this->info['audio']['dataformat']); + } + + /** + * post-getID3() data handling for Real files. + * + * @access private + * @return array result + */ + function realInfo() + { + $this->result['format_name'] = 'Real'; + } + + /** + * post-getID3() data handling for VQF files. + * + * @access private + * @return array result + */ + function vqfInfo() + { + $this->result['format_name'] = 'VQF'; + } +} + + +?> \ No newline at end of file diff --git a/apps/reaktor/lib/ccLicense.class.php b/apps/reaktor/lib/ccLicense.class.php new file mode 100644 index 0000000..658bc21 --- /dev/null +++ b/apps/reaktor/lib/ccLicense.class.php @@ -0,0 +1,35 @@ +init($style); + } + + public function init($style = null) + { + if ($style && !is_string($style)) + { + throw new Exception("Unknown style type"); + } + switch($style) + { + case "by": + case "by-sa": + case "by-nd": + case "by-nc": + case "by-nc-sa": + case "by-nc-nd": + parent::initialize(array( + "href" => "http://creativecommons.org/licenses/{$style}/3.0/", + "type" => "text/html", + )); + break; + + default: + parent::initialize(array()); + } + + } +} + diff --git a/apps/reaktor/lib/commentCalendar.class.php b/apps/reaktor/lib/commentCalendar.class.php new file mode 100644 index 0000000..2d54449 --- /dev/null +++ b/apps/reaktor/lib/commentCalendar.class.php @@ -0,0 +1,304 @@ +setCalendar(new Date_Calc()); + + $this->setEventCalendar($type, strtotime($date)); + } + + /** + * Convert a passed date to a standard date stamp + * + * @param string $date + * @return string (formatted date) + */ + private function toDateStamp($date) + { + if (!is_numeric($date)) + { + $date = strtotime($date); + } + + return date('Y-m-d', $date); + } + + /** + * Set the Date_Calc object + * + * @param object $object + */ + private function setCalendar($object) + { + $this->calendar = $object; + } + + /** + * Initialize the event calendar based on the type of calendar + * + * @param string $type (day, week, month, year) + * @param int $time + */ + private function setEventCalendar($type, $time) + { + switch (strtolower($type)) + { + /*case "day": + $this->event_calendar = array(0 => array(0 => array($this->toDateStamp($time) => array()))); + //sfCommentPeer: + break;*/ + + case "week": + $this->event_calendar = $this->formatCalendarWeekArray($this->getCalendar()->getCalendarWeek(date('d', $time), date('m', $time), date('Y', $time), '%Y-%m-%d')); + break; + + case "month": + $this->event_calendar = $this->formatCalendarMonthArray($this->getCalendar()->getCalendarMonth(date('m', $time), date('Y', $time), '%Y-%m-%d')); + //print_r($this->events); + break; + + /*case "year": + $this->event_calendar = $this->formatCalendarYearArray($this->getCalendar()->getCalendarYear(date('Y', $time), '%Y-%m-%d')); + break; */ + + default: + throw new sfException('You must pass a valid calendar type: week, month'); + break; + } + + $from = date('Y-m', $time).'-01'; + $to = date('Y-m', $time).'-'.date('t', $time); + $comment_days = sfCommentPeer::getCommentCountInTimePeriod('ReaktorArtwork', 'frontend', 'month', $from, $to); + foreach ($comment_days as $key=>$value) + { + $this->events[$key]['count'] = $value; + $this->events[$key]['url'] = '@listcommentsbydate?date='.$key; + } + } + + /** + * Format the week calendar from the Date_Calc format to a more usable format + * + * @param array $array + * @return array + */ + private function formatCalendarWeekArray($array) + { + if (!empty($array)) + { + foreach ($array as $key => $day) + { + $array[$day] = array(); + unset ($array[$key]); + } + } + + $week_array[0][0] = $array; + + return $week_array; + } + + /** + * Format the month calendar from the Date_Calc format to a more usable format + * + * @param array $array + * @return array + */ + private function formatCalendarMonthArray($array) + { + if (!empty($array)) + { + foreach ($array as $week => $days) + { + foreach ($days as $key => $value) + { + $array[$week][$value] = array(); + unset ($array[$week][$key]); + } + } + } + + $month_array[0] = $array; + + return $month_array; + } + + /** + * Format the year calendar from the Date_Calc format to a more usable format + * + * @param array $array + * @return array + */ + private function formatCalendarYearArray($array) + { + if (!empty($array)) + { + foreach ($array as $year => $weeks) + { + foreach ($weeks as $week => $days) + { + foreach ($days as $key => $day) + { + $array[$year][$week][$day] = array(); + unset ($array[$year][$week][$key]); + } + } + } + } + + return $array; + } + + /** + * Get the Date_Calc calendar object + * + * @return object + */ + public function getCalendar() + { + return $this->calendar; + } + + /** + * Return an array off the specified calendar, optionally including events. + * + * @return array + */ + public function getEventCalendar($events = true) + { + if ($events === true) + { + foreach ($this->event_calendar as $year => $weeks) + { + foreach ($weeks as $week => $days) + { + foreach ($days as $day => $events) + { + $this->event_calendar[$year][$week][$day] = $this->getEvents($day); + } + } + } + + while (count($this->event_calendar) == 1 AND isset($this->event_calendar[0])) + { + $this->event_calendar = $this->event_calendar[0]; + } + } + + return $this->event_calendar; + } + + /** + * Return the number of events on any given date + * + * @param string $date + * @return int + */ + public function getEventCount($date) + { + $date = $this->toDateStamp($date); + if (array_key_exists($date, $this->events)) + { + return $this->events[$this->toDateStamp($date)]; + } + return 0; + /*$events = $this->getEvents($this->toDateStamp($date)); + return count($events);*/ + } + + /** + * Return an array of events for the specified date, no calendar included + * + * @param string $date + * @return array + */ + public function getEvents($date) + { + if (array_key_exists($date, $this->events))//getAllEvents())) + { + return $this->events[$this->toDateStamp($date)]; + } + + return array(); + } + + /** + * Return an array of all events, regardless of date. + * + * @return array + */ + public function getAllEvents() + { + return $this->events; + } + + /** + * Add an event to the events array + * + * @param string $date + * @param array $options + */ + public function addEvent($date, $options = array()) + { + $date = $this->toDateStamp($date); + + $event_count = $this->getEventCount($date); + + if (!empty($options)) + { + foreach ($options as $key => $value) + { + $this->events[$date][$event_count][$key] = $value; + } + } + } +} \ No newline at end of file diff --git a/apps/reaktor/lib/commentMagick.class.php b/apps/reaktor/lib/commentMagick.class.php new file mode 100644 index 0000000..1c216a7 --- /dev/null +++ b/apps/reaktor/lib/commentMagick.class.php @@ -0,0 +1,21 @@ + diff --git a/apps/reaktor/lib/genericArtwork.class.php b/apps/reaktor/lib/genericArtwork.class.php new file mode 100644 index 0000000..2d9bd45 --- /dev/null +++ b/apps/reaktor/lib/genericArtwork.class.php @@ -0,0 +1,2311 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseReaktorArtworkFile.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseArtworkStatus.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/ReaktorArtworkFile.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/ArtworkStatus.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseReaktorArtworkFilePeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/om/BaseArtworkStatusPeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/ReaktorArtworkFilePeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/ArtworkStatusPeer.php'; + require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/TaggingPeer.php'; + +/** + * Generic artwork class + * + * To use this class, instantiate a new instance of this class, with either + * a numeric $id to load an existing artwork, or a title to create a new one + * + * Loading an existing artwork: + * $example_artwork = new genericArtwork(1); + * + * Creating a new artwork: + * $example_artwork = new genericArtwork(null, genericArtwork::IMAGE); + * or + * $example_artwork = new genericArtwork('My fine artwork', genericArtwork::IMAGE); + * + * Set the user id on the new artwork, either by ID + * $example_artwork->setUserId(1); + * or by pointing to the sfUser object + * $example_artwork->setUser($sf_user->getGuardUser()); + * + * Set the title of the artwork (can be ommited if used in the constructor) + * $example_artwork->setTitle('My fine artwork'); + * + * Now, save the artwork so that it is stored + * $example_artwork->save(); + * + * Now you can add metadata or files to it. Format metadata is a stupid example, since this should be stored + * with the artwork in the database, but you should still get how it works from this example + * $example_artwork->addMetadata('format', 'jpg'); + * + * @package Reaktor + * @subpackage Artwork + * @author Daniel Andre Eikeland + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +class genericArtwork +{ + /** + * Attribute to define which kind of artwork this is + * + * @var integer + */ + protected $_artworkType; + + /** + * Filename of the stored artwork, relative to the media folder + * + * @var string + */ + protected $_realfilename; + + /** + * Filename of the file as accessible from the web, could be different from the + * actual file path on disk + * + * @var string + */ + protected $_downloadablefilename; + + /** + * Link to artwork + * + * @var unknown_type + */ + protected $_link; + + /** + * The item id used when retreiving related data, such as metadata + * + * @var integer + */ + protected $_itemid = 0; + + /** + * Points to the artwork stored in the artwork table + * + * @var ReaktorArtwork + */ + protected $_artwork; + + protected $_tags_arr = null; + + public $_artworkUserObject; + + /** + * Points to the history table + * + * @var ReaktorArtwork + */ + //protected $_history; + + + /** + * Checks whether or not this artwork exists in the database + * + * @var boolean + */ + protected $_isunsaved = true; + + /** + * Array of all the files in the artwork + * + * @var array + */ + protected $_files = array(); + protected $_numfiles = 0; + + /** + * Array of under discussion files - set in populatefiles function + * + * @var array Array of the files under discussion + */ + protected $_filesUnderDiscussion = array(); + + /** + * Whether all the files in this artwork are transcoded or not, saved to prevent multiple requests since + * this hits the hard disk + * + * @var boolean + */ + protected $_isTranscoded = null; + + const IMAGE = 'image'; + const VIDEO = 'video'; + const AUDIO = 'audio'; + const TEXT = 'text'; + const GALLERY = 'gallery'; + const COLLECTION = 'collection'; + const PDF = 'pdf'; + const FLASH_ANIMATION = 'flash_animation'; + + /** + * Creates a constructor connection object that can be used to load multiple images + * + * @param unknown_type $id + * @param unknown_type $options + */ + static function getResultsetFromIDs($id, $options = array()) + { + $crit = new Criteria(); + if (isset($options['isfileid'])) + { + $crit->add(ReaktorArtworkFilePeer::FILE_ID, $id, Criteria::IN); + $crit->addAscendingOrderByColumn(ReaktorArtworkFilePeer::FILE_ORDER); + if (!sfContext::getInstance()->getUser()->hasCredential("editusercontent")) + { + $crit->add(ReaktorFilePeer::HIDDEN, 0); + } + $resultset = ReaktorArtworkFilePeer::doSelectJoinAll($crit); + $id = array(); + foreach ($resultset as $result) + { + $id[] = $result->getReaktorArtwork()->getId(); + } + } + $crit = new Criteria(); + $crit->add(ReaktorArtworkPeer::ID, $id, Criteria::IN); + $resultset = ReaktorArtworkPeer::doSelectJoinAll($crit); + + return $resultset; + } + + /** + * Initializes the artwork and loads the necessary data + * + * @param integer|string|reaktorArtwork $id ID of the artwork to load, or the title of the new + * artwork that will be created. If empty, you must set the title later + * @param string $type The artwork type, defined by constant in this class + * + * @throws Exception + */ + function __construct($id = null, $type = null, $options = array(), $resultset = null, $passedFile = null) + { + if ($id instanceof genericArtwork) + { + throw new Exception('Why would you pass a genericartwork to a genericartwork constructor?? That doesn\'t make sense ...!'); + } + if (is_numeric($id) || $id instanceof ReaktorArtwork) + { + $itemid = ($id instanceof ReaktorArtwork) ? $id->getId() : $id; + sfContext::getInstance()->getLogger()->info("Constructing artwork with ID: ".$itemid); + if ($resultset === null && !$id instanceof ReaktorArtwork) + { + $resultset = self::getResultsetFromIDs($id, $options); + } + $cc = 0; + if (!$resultset && !$id instanceof ReaktorArtwork) + { + sfContext::getInstance()->getLogger()->info("Artwork with ID: ".$itemid." does not exist"); + throw new exception ("Artwork does not exist"); + } + if ($id instanceof ReaktorArtwork) + { + $this->_artwork = $id; + } + elseif (is_array($resultset)) + { + foreach ($resultset as $r) + { + if (!$r instanceof ReaktorArtwork) + { + throw new Exception('If you\'re passing a resultset to the genericArtwork constructor, it needs to be an array of results from reaktorartworkfile::doSelect...()'); + } + if ($r->getId() == $id) + { + $cc++; + if (!$this->_artwork instanceof ReaktorArtwork) + { + $this->_artwork = $r; + } + /*$this->_files[$r->getFileId()] = $r->getFileId(); // new artworkFile($r->getReaktorFile(), $this); + $this->_numfiles = $cc;*/ + } + } + } + else + { + sfContext::getInstance()->getLogger()->info("Cannot use " . get_class($resultset) . " as resultset"); + throw new Exception("Unhandled result set: ".get_class($resultset)); + } + + if ($this->_numfiles == 0 && $passedFile instanceof ReaktorFile) + { + $this->_numfiles = 1; + $this->_files[$passedFile->getId()] = $passedFile; + } + + if (count($this->_files) > 0) + { + sfContext::getInstance()->getLogger()->info("Found Lots of files: ".count($this->_files)); + if ($resultset instanceof ReaktorArtworkFile) + { + $fileconn = $resultset; + } + else + { + $fileconn = artworkFile::getResultsetFromIDs($this->_files); + } + foreach ($this->_files as &$file) + { + if ($passedFile instanceof artworkFile && $file == $passedFile->getId()) + { + sfContext::getInstance()->getLogger()->info("Found passed file: ".$passedFile->getId()); + $file = $passedFile; + } + else + { + sfContext::getInstance()->getLogger()->info("Looping with File: ".$file); + $file = new artworkFile($file, $this, $fileconn); + } + } + } + $this->_itemid = $this->_artwork->getId(); + $this->_isunsaved = false; + } + else + { + sfContext::getInstance()->getLogger()->info("Constructing brand new artwork"); + $this->_artwork = new ReaktorArtwork(); + if ($id != null) + { + $this->_artwork->setTitle($id); + } + + if ($type) + { + $this->setArtworktype($type); + } + $this->_artwork->setStatus(ReaktorArtwork::DRAFT); + $this->_artwork->setCreatedAt(time()); + $defaultTeam = sfGuardGroupPeer::retrieveByName(sfConfig::get("app_editorial_team_default", "deichman_redaksjon")); + $this->setEditorialTeam($defaultTeam); + sfContext::getInstance()->getLogger()->info("Created artwork with ID: ".$this->_artwork->getId()); + } + + if (!$this->_artwork instanceof ReaktorArtwork) + { + sfContext::getInstance()->getLogger()->info("An unknown error occured"); + $error_msg = (is_numeric($id)) ? 'This artwork does not exist' : 'Error creating new artwork'; + throw new Exception($error_msg); + } + $this->_artworkType = $this->_artwork->getArtworkIdentifier(); + $this->_artworkUserObject = $this->_artwork->getUserId(); // s fGuardUser(); // sfGuardUserRelatedByUserId(); //sfGuardUserPeer::retrieveByPK($this->_artwork->getUserId()); + } + + /** + * Get link to artwork. + * Which file in the artwork that is be displayed on top can be sent in + * as a parameter. Useful in artworks with more than one file. + * + * @param string $mode The mode + * @param integer $file_id The file ID + * @param boolean $external Format the URL correctly, useful for functional testing + * + * @return string $url + */ + function getLink($mode = 'show', $file_id = null, $external = false, $nocache = false) + { + $cachekey = 'artwork_link_' . $this->getId() . '_' .$file_id.'_'.$external.'_'.$mode . '_' .Subreaktor::getProvidedIfValid(); + $cache = reaktorCache::singleton($cachekey); + if (!($linkstring = $cache->get()) || $nocache) + { + $subreaktorlinktext = ''; + if (Subreaktor::isValid()) + { + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + if (!in_array(Subreaktor::getProvidedLokalReference(), $this->getLokalreaktors())) + { + $lr = $this->getLokalreaktors(true); + $lr = array_shift($lr); + $subreaktorlinktext = $lr; + } + } + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + if (!in_array(Subreaktor::getProvidedSubreaktorReference(), $this->getSubreaktors())) + { + $sr = $this->getSubreaktors(true, array('subreaktor')); + $sr = array_shift($sr); + if ($subreaktorlinktext != '') $subreaktorlinktext .= '-'; + $subreaktorlinktext .= $sr; + } + } + } + if ($subreaktorlinktext != '') $subreaktorlinktext = '&subreaktor=' . $subreaktorlinktext; + $linkstring = $this->_artwork->getLink($mode, $file_id, $external) . $subreaktorlinktext; + $cache->set($linkstring); + } + + return $linkstring; + } + + /** + * Returns true if the artwork is one of the allowed text based artwork types + * Useful when making collections that can allow different types of text file (pdf/text for example) + * + * @return boolean true if artwork is text based + */ + function isTextBased() + { + $textBasedTypes = array(self::TEXT, self::PDF); + + return (bool) (in_array($this->getArtworkType(), $textBasedTypes)); + } + + function clearLinkCache() + { + $cachekey = 'artwork_link_' . $this->getId() . '_'; + reaktorCache::deleteSimilar($cachekey); + } + + /** + * Set the time for when the artwork was submitted + * + * @param timestamp $time The time it was created + * + * @return void The created time is set + */ + function setCreatedAt($time = null) + { + $time = ($time == null) ? time() : $time; + $this->_artwork->setCreatedAt($time); + } + + /** + * Returns the time when the artwork was created + * + * @return string + */ + function getCreatedAt() + { + return $this->_artwork->getCreatedAt(); + } + + /** + * Returns the average rating + * + * @return float + */ + function getAverageRating() + { + return $this->_artwork->getAverageRating(); + } + + /** + * Return who changed the status of the artwork last + * + * @param boolean $return_id Return the user if of approving user + * + * @return string Approved by name + */ + function getActionedBy($return_id = true) + { + static $usernames = array(); + if ($return_id) + { + return $this->_artwork->getActionedBy(); + } + + $id = $this->_artwork->getActionedBy(); + if (isset($usernames[$id])) + { + return $usernames[$id]; + } + $user = sfGuardUserPeer::retrieveByPK($id); + + if ($user) + { + $usernames[$id] = reaktorQuickStorage::set("USERNAME_$id", $user->__toString()); + return $usernames[$id]; + } + return __('none'); + } + + /** + * Return date and time when the artwork status last changed. + * + * @return date Status change date + */ + function getActionedAt() + { + + return $this->_artwork->getActionedAt(); + } + + /** + * Set the time for when the artwork was submitted + * + * @param timestamp $time The time it was submitted + * + * @return void Sets the submitted at time + */ + function setSubmittedAt($time = null) + { + $time = ($time == null) ? time() : $time; + $this->_artwork->setSubmittedAt($time); + } + + /** + * Returns the time when the artwork was submitted + * + * @return string + */ + function getSubmittedAt() + { + return $this->_artwork->getSubmittedAt(); + } + + /** + * Returns the artwork status + * + * @param boolean $return_id Return ID rather than object + * + * @return mixed id or description of status + */ + function getStatus($return_id = true) + { + if ($return_id) + { + return $this->_artwork->getStatus(); + } + else + { + $statusId = $this->_artwork->getStatus(); + $artworkStatus = artworkStatusPeer::retrieveByPK($statusId); + + if ($artworkStatus) + { + return $artworkStatus->__toString(); + } + else + { + throw new Exception('Cant get status for artwork object - tried to get status '.$statusId); + } + } + } + + /** + * Simple function to check if an artwork is in "ready for approval" status + * + * @return boolean true if submitted or false if not + */ + public function isSubmitted() + { + if ($this->getStatus() == ReaktorArtwork::SUBMITTED) + { + return true; + } + return false; + } + + /** + * Simple function to check if an artwork is in "draft" status + * + * @return boolean true if draft or false if not + */ + public function isDraft() + { + if ($this->getStatus() == ReaktorArtwork::DRAFT) + { + return true; + } + return false; + } + + /** + * Simple function to check if an artwork is in "rejected" status + * + * @return boolean true if rejected or false + */ + public function isRejected() + { + if ($this->getStatus() == ReaktorArtwork::REJECTED) + { + return true; + } + return false; + } + + /** + * Simple function to check if an artwork is in "user removed" status + * + * @return boolean true if the user has removed this artwork + */ + public function isRemoved() + { + if ($this->getStatus() == ReaktorArtwork::REMOVED) + { + return true; + } + return false; + } + + /** + * Simple function to check if an artwork is in "approved" status + * + * @return boolean true if approved or false + */ + public function isApproved() + { + if ($this->getStatus() == ReaktorArtwork::APPROVED) + { + return true; + } + return false; + } + + /** + * Simple function to check if an artwork is in "approved hidden" status + * + * @return boolean true if approved and hidden by user or false + */ + public function isApprovedHidden() + { + if ($this->getStatus() == ReaktorArtwork::APPROVED_HIDDEN) + { + return true; + } + return false; + } + + /** + * Returns whether or not the artwork has more than one image in it + * + * @return boolean + */ + function isSlideshow() + { + $ic = 0; + if (count($this->_files) == 0) + { + $this->populateFiles(); + } + foreach ($this->_files as $afile) + { + ($afile->getFiletype() == 'image') ? $ic++ : ''; + if ($ic > 1) + { + return true; + } + } + return false; + } + + /** + * Add a file to the artwork + * + * @param artworkFile|integer $file The file or file id to add + * + * @return void + */ + function addFile($file) + { + // Save the relation between the file and the artwork + if ($this->_itemid == 0) + { + throw new Exception('The artwork is not saved yet. Please call the save() function before adding a file to the artwork.'); + } + $reaktorArtworkFile = new ReaktorArtworkFile(); + $reaktorArtworkFile->setArtworkId($this->_itemid); + + if (is_numeric($file)) + { + $file = ReaktorFilePeer::retrieveByPK($file, null, true); + } + + $reaktorArtworkFile->setFileId($file->getId()); + + $reaktorArtworkFile->setFileOrder($this->_numfiles + 1); + $reaktorArtworkFile->save(); + + // If the file is from a different user to the artwork, we must be creating a multi-user artwork! + if ($file->getUserId() != $this->getUserId()) + { + $this->setMultiUser(); + $this->save(); + } + + // Add the new file to the internal $_files collection + if ($file instanceof artworkFile) + { + $this->_files[$file->getId()] = $file; + } + + $this->_numfiles = count($this->_files); + } + + /** + * Adds an array of files to the artwork + * The array can be either file_ids or file objects + * + * @param array $files + */ + function addFiles($files) + { + foreach ($files as $file) + { + $this->addFile($file); + } + } + + + /** + * Remove a file from the artwork + * + * @param artworkFile|integer $file The file or file id to remove + * + * @return void + */ + function removeFile($file) + { + if ($this->_itemid == 0) + { + throw new Exception('Somehow this artwork does not exist'); + } + if ($file instanceof artworkFile) + { + $fileId = $file->getId(); + } + elseif (is_numeric($file)) + { + $fileId = $file; + } + else + { + throw new Exception ("Cant find file"); + } + + if ($this->getFilesCount() == 1) + { + $this->userRemoveArtwork(sfContext::getInstance()->getUser(), "No files left"); + return false; + } + + if ($thisFileLink = ReaktorArtworkFilePeer::retrieveByPK($this->getId(), $fileId)) + { + $thisFileLink->Delete(); + } + // Remove the file from the internal $_files collection + if (isset($this->_files[$fileId])) + { + unset($this->_files[$fileId]); + } + $this->_numfiles = count($this->_files); + + $this->resetFirstFile(); + return true; + } + + /** + * Returns an array with all the files attached to this artwork + * + * @param boolean $ids If true return just the file IDs and not the objects + * + * @return array + */ + function getFiles($ids = false) + { + if (count($this->_files) == 0) + { + $this->populateFiles(); + } + + if ($ids) + { + $returnArray = array(); + foreach ($this->_files as $file) + { + $returnArray[] = $file->getId(); + } + return $returnArray; + } + return $this->_files; + } + + /** + * Counts the files attached to the artwork + * + * @return void + */ + protected function _countFiles() + { + $crit = new Criteria(); + $crit->add(ReaktorArtworkFilePeer::ARTWORK_ID, $this->_itemid); + $crit->add(ReaktorFilePeer::HIDDEN, 0); + $crit->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID); + $this->_numfiles = ReaktorArtworkFilePeer::doCount($crit); + } + + /** + * Returns the number of files attached to this artwork + * + * @param boolean $force Whether to force a recount from the db + * + * @return integer + */ + function getFilesCount($force = false) + { + if ($force || $this->_numfiles == 0) + { + $this->_countFiles(); + } + return $this->_numfiles; + } + + /** + * returns id of first file + * + */ + function getFeedFile() + { + return $this->getFirstFile()->getId(); + } + + /** + * Get the file with the id specified + * + * @param integer $id The id of the file to retrieve + * + * @return artworkFile + * + * @throws Exception + */ + function getFile($id) + { + if (count($this->_files) == 0) + { + $this->populateFiles(); + } + if (isset($this->_files[$id])) + { + return $this->_files[$id]; + } + else + { + throw new Exception('This file does not exist, or is not a part of this artwork. Fileid: ' . $id); + } + } + + /** + * Move the selected file up or down in the order + * (only needs to be called on the file that is moved) + * + * @param artworkFile $file The file to move + * @param string $direction "up" or "down" + * + * @return void Sets the file order + */ + function changeFileOrder($file, $direction) + { + if ($direction == 'up') + { + $switchfile = $this->getNextFile($file->getId()); + } + else + { + $switchfile = $this->getPreviousFile($file->getId()); + } + if ($switchfile instanceof artworkFile) + { + $this->switchFileOrderPlacement($file, $switchfile); + } + $this->resetFirstFile(); + } + + /** + * Switch order placement between two files + * + * @param artworkFile $file1 The first file + * @param artworkFile $file2 The second file + * + * @return void Switches file order + */ + function switchFileOrderPlacement($file1, $file2) + { + $file1_placement = $file1->getFileOrderPlacement(); + $file2_placement = $file2->getFileOrderPlacement(); + ReaktorArtworkFilePeer::setFileOrderPlacement($file2_placement, $file1->getId(), $this->getId()); + ReaktorArtworkFilePeer::setFileOrderPlacement($file1_placement, $file2->getId(), $this->getId()); + } + + + /** + * Returns the next file in the artwork + * + * @param integer $id The id of the current file + * + * @return artworkFile + */ + function getNextFile($id) + { + $next = false; + foreach ($this->_files as $afile) + { + if ($afile->getId() == $id) + { + $next = true; + } + elseif ($next) + { + return $afile; + } + } + return false; + } + + /** + * Returns the previous file in the artwork + * + * @param integer $id The ID of the file we're at + * + * @return artworkFile + */ + function getPreviousFile($id) + { + $rfiles = array_reverse($this->_files, true); + $next = false; + + foreach ($rfiles as $afile) + { + if ($afile->getId() == $id) + { + $next = true; + } + elseif ($next) + { + return $afile; + } + } + return false; + } + + /** + * Return the first file object attached to the artwork + * + * @return object reaktorFile + */ + function getFirstFile() + { + if ($this->_artwork->getReaktorFile()) + { + return new artworkFile($this->_artwork->getReaktorFile(), $this); + } + else + { + return $this->resetFirstFile(); + } + } + + /** + * Return the last element of the file array + * + * @return artworkFile object + */ + public function getLastFile() + { + return end($this->_files); + } + + /** + * This function resets the first file value stored in the artwork table + * It should always be populated as artworks must have at least one file, and if it's null + * a lot of the "join all" queries will fail + * + * @return artworkFile The artworkfile that was set as the first file + */ + function resetFirstFile() + { + $this->populateFiles(); + $file = current($this->_files); + + $this->_artwork->setFirstFileId($file->getId()); + $this->save(); + + return $file; + } + + /** + * Loads all files attached to this artwork into the $_files array + * + * @return unknown + */ + protected function populateFiles() + { + $this->_files = array(); + $c = new Criteria(); + + if (sfContext::getInstance()->getUser()->isAuthenticated() && + sfContext::getInstance()->getUser()->hasCredential("viewallcontent")) + { + $c->addAscendingOrderByColumn(ReaktorFilePeer::HIDDEN); + } + else + { + $c->add(ReaktorFilePeer::HIDDEN, 0); + } + + $c->addAscendingOrderByColumn(ReaktorArtworkFilePeer::FILE_ORDER); + $c->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID); + + $resultset = $this->_artwork->getReaktorArtworkFilesJoinReaktorFile($c); + + foreach ($resultset as $artfile) + { + $this->_files[$artfile->getFileId()] = new artworkFile($artfile->getReaktorFile(), $this, $resultset); + + // For efficiency, we can check for discussed files now and add them to a seperate array + if ($artfile->getReaktorFile()->getUnderDiscussion()) + { + $this->_filesUnderDiscussion[$artfile->getFileId()] = $this->_files[$artfile->getFileId()]; + } + } + $this->_numfiles = count($this->_files); + } + + /** + * Saves the artwork with all its associated data and stuff + * + * @throws PropelException + * @return boolean + */ + function save() + { + try + { + $this->_artwork->save(); + $this->_itemid = $this->_artwork->getId(); + $this->_isunsaved = false; + } + catch (PropelException $e) + { + throw $e; + } + return true; + } + + /** + * Sets the user id on the artwork + * + * @param integer $uid The user id of the user who saved the artwork + * + * @return boolean + */ + function setUserId($uid) + { + $this->_artwork->setUserId($uid); + return true; + } + + /** + * Returns the user id for the user who saved the artwork + * + * @return integer + */ + function getUserId() + { + return $this->_artwork->getUserId(); + } + + /** + * Set the user for this artwork + * + * @param sfGuardUser $user The sfGuardUser object of the user who saved the artwork + * + * @throws Exception + * + * @return boolean + */ + function setUser($user) + { + if ($user instanceof sfGuardUser) + { + $this->_artwork->setsfGuardUser($user); + } + else + { + throw new Exception('The user parameter has to be an sfGuardUser object'); + } + return true; + } + + /** + * Returns the sfGuardUser object for the user who created the artwork + * + * @return sfGuardUser + */ + function getUser() + { + if (!$this->_artworkUserObject instanceof sfGuardUser) + { + $this->_artworkUserObject = $this->_artwork->getsfGuardUser(); + } + return $this->_artworkUserObject; + } + + /** + * Tags the artwork with the given tag + * + * @param string $tag The tag to add + * + * @return void + */ + function addTag($tag) + { + reaktorCache::deleteSimilar("artwork_tag_list_".$this->getId()); + $this->_artwork->addTag($tag); + } + + /** + * Remove the given tag from the artwork + * + * @param string $tag The tag to remove + * + * @return void + */ + function removeTag($tag) + { + reaktorCache::deleteSimilar("artwork_tag_list_".$this->getId()); + $this->_artwork->removeTag($tag); + } + + /** + * Returns the number of tags + * + * @param bool $include_unapproved + * @return int + */ + public function countTags($include_unapproved = true) + { + return count($this->getTags(false, false, $include_unapproved)); + } + + /** + * Returns all tags attached to this artwork + * + * @param boolean $include_files Whether to include filetags or just return tags attached to the artwork itself + * @param boolean $groupByStatus Whether to include the status in the returned array - implies unapproved tags can be shown + * + * @return array + */ + function getTags($include_files = true, $groupByStatus = false, $include_unapproved = false) + { + // See if we have this list in the APC cache + $key = "artwork_tag_list_".$this->getId()."if{$include_files}gBS{$groupByStatus}iu{$include_unapproved}"; + $cache = reaktorCache::singleton($key); + + if (!($tags_arr = $cache->get())) + { + $tags_arr = array(); + + $c = new Criteria(); + + $ctn1 = $c->getNewCriterion(TaggingPeer::TAGGABLE_ID, "(" . TaggingPeer::TAGGABLE_ID. " = ".$this->getId()." AND ".TaggingPeer::TAGGABLE_MODEL." = 'ReaktorArtwork')", Criteria::CUSTOM); + $c->setDistinct(); + + if (!$groupByStatus && !$include_unapproved) + { + $c->add(TagPeer::APPROVED, 1); + } + + if ($include_files) + { + $ctn2 = $c->getNewCriterion(TaggingPeer::TAGGABLE_MODEL, "(" . TaggingPeer::TAGGABLE_MODEL." = 'ReaktorFile' AND ".ReaktorArtworkFilePeer::ARTWORK_ID." = ".$this->getId() . ')', Criteria::CUSTOM); + $ctn1->addOr($ctn2); + } + $c->add($ctn1); + + $c->addJoin(TagPeer::ID, TaggingPeer::TAG_ID); + $c->addJoin(TaggingPeer::TAGGABLE_ID, ReaktorArtworkFilePeer::FILE_ID, Criteria::LEFT_JOIN); + $tagObjectArray = TagPeer::doSelect($c); + + foreach ($tagObjectArray as $tagObject) + { + if ($groupByStatus) + { + $tags_arr[$tagObject->getApproved()][$tagObject->getId()] = $tagObject->getName(); + } + else + { + $tags_arr[] = $tagObject->getName(); + } + } + asort($tags_arr); + $cache->set($tags_arr, 10000); + } + return $tags_arr; + } + + /** + * Returns categories this artwork belongs to + * + * @return array of categories with category_id as key + */ + function getCategories() + { + return CategoryArtworkPeer::getCategoriesFromArtwork($this); + } + + /** + * Add a new category to this artwork + * + * @param integer $categoryId Category Id + * @param integer|sfGuardUser $user The user adding the category + * + * @return void + */ + function addCategory($categoryId, $user) + { + CategoryArtworkPeer::addArtworkCategory($this, $categoryId, $user); + } + + /** + * Remove a category from artwork + * + * @param integer $categoryId the ID of the category to remove + */ + function removeCategory($categoryId) + { + CategoryArtworkPeer::removeArtworkCategory($this, $categoryId); + } + + /** + * Set the artwork title + * + * @param string $title The title to set + * + * @return void + */ + function setTitle($title) + { + $this->_artwork->setTitle($title); + $this->clearLinkCache(); + } + + /** + * Returns the artwork title + * + * @return string + */ + function getTitle() + { + return $this->_artwork->getTitle(); + } + + /** + * Smart title handling, cuts the title at $max if necessary on spaces, dots, + * questionmarks... + * + * @param int $max + * @return chopped string + */ + function getShortTitle($max = 0) + { + if (!$max) + { + $max = sfConfig::get('app_artwork_teaser_len', 80); + } + return stringMagick::chop($this->getTitle(), $max); + } + + /** + * Returns the artwork description + * + * @return string + */ + function getDescription() + { + return $this->_artwork->getDescription(); + } + + /** + * Set the artwork description + * + * @param string $description The description to set + * + * @return void + */ + function setDescription($description) + { + return $this->_artwork->setDescription($description); + } + + /** + * Returns the id of the artwork + * + * @return integer + */ + function getId() + { + return $this->_artwork->getId(); + } + + /** + * Returns the primary key of the artwork + * + * @return integer + */ + function getPrimaryKey() + { + return $this->_artwork->getPrimaryKey(); + } + + /** + * Returns the artwork type - see the constants defined in this class + * + * @return string + */ + function getArtworkType() + { + return $this->_artworkType; + } + + /** + * Returns an array of file types that this artwork can contain + * Normally this is the same as the artwork type (identifier) but if the app.yml has + * specified other types are allowed (like text/pdf) then they will be returned here + * + * @return array The array of eligible types as strings + */ + function getEligbleFileTypes() + { + $returnArray = array($this->getArtworkType()); + $additionalFileTypes = sfConfig::get("app_artwork_additional_file_types", array()); + + if (isset($additionalFileTypes[$this->getArtworkType()])) + { + return array_merge($returnArray, $additionalFileTypes[$this->getArtworkType()]); + } + return $returnArray; + } + + /** + * Set the artwork type - use the constants defined in this class + * + * @param string $type The artwork type to set + * + * @return void + */ + function setArtworkType($type) + { + $this->_artwork->setArtworkIdentifier($type); + $this->_artworkType = $type; + } + + /** + * Flag to show an artwork has been modified, so the admin can check it in a list + * + * @param object $user The user object for checking credentials + * @param string $message A message to add to the admin comments field + * + * @return void sets modified note in DB + */ + function flagChanged($user, $message = "unknown") + { + // Only need to flag it if user is not admin + if (!$user->hasCredential("editusercontent")) + { + $message = $this->_artwork->getModifiedNote().$message."\n"; + $this->_artwork->setModifiedNote($message); + $this->_artwork->setModifiedFlag(time()); + } + } + + /** + * Clear the modified flag (after admin is happy) + * + * @return void Clears modified flag in DB + */ + function flagCleared() + { + $this->_artwork->setModifiedFlag(null); + } + + /** + * Returns true if $user is athorized to view the artwork. + * + * @return bool true when $user are allowed to view the artwork + */ + function isViewable() + { + + if (sfContext::getInstance()->getUser()->hasCredential("viewallcontent")) + { + sfContext::getInstance()->getLogger()->info("You have the fu, you can see me."); + return true; + } + + // Access to approved artork is for anyone + if ($this->isApproved()) + { + sfContext::getInstance()->getLogger()->info("This artwork is approved, so it is viewable"); + return true; + } + + // Access to removed artwork is only for admin (returned true above) + if ($this->isRemoved()) + { + sfContext::getInstance()->getLogger()->info("This artwork is removed, and cannot be seen"); + return false; + } + + // also allow access to owner of artwork - unless they have removed it + if (sfContext::getInstance()->getUser()->isAuthenticated() + && $this->getUserId() == sfContext::getInstance()->getUser()->getGuardUser()->getId()) + { + sfContext::getInstance()->getLogger()->info("You can see this artwork since you are the owner"); + return true; + } + + sfContext::getInstance()->getLogger()->info("This artwork is not approved, and cannot be seen"); + return false; + } + + /** + * Delete the artwork from the database + * + * @return void Deletes the artwork + */ + function deleteArtwork() + { + $this->_artwork->delete(); + } + + function isDeleted() + { + $this->_artwork->getDeleted(); + } + + + + + /** + * Non destructive artwork removal from a user perspective + * The artwork will effectively disappear, but will still be available for admin users + * for historical reasons (and possible future recovery) + * + * @param myUser $user The user actioning the change + * @param string $comment A comment for the history table + * + * @return boolean true on success, exception on failure + */ + public function userRemoveArtwork($user, $comment) + { + return $this->changeStatus($user, ReaktorArtwork::REMOVED, $comment); + } + + /** + * Change the status of an artwork + * + * @param integer $user The user changing the status + * @param integer $status The status id to set + * @param string $comment Comment to add to history + * @param boolean $quiet If true then no action timestamp is applied + * + * @return void Sets status + */ + function changeStatus($user, $status, $comment = null, $quiet = false) + { + $oldStatus = $this->getStatus(); + if ($user instanceof sfGuardUser || $user instanceof myUser ) + { + $user = $user->getId(); + } + + if (!$quiet) + { + $this->_artwork->setActionedAt(time("Y-m-d H:i:s")); + $this->_artwork->setActionedBy($user); + } + $this->_artwork->setStatus($status); + $this->_artwork->save(); + ReaktorArtworkHistory::logAction($this->getId(), $user, $comment, $status); + + switch($status) + { + case ReaktorArtwork::APPROVED: + $this->flagCleared(); + + // User did something, change his status + $this->setStatus($status) ; + break; + case ReaktorArtwork::REJECTED: + if ($status == ReaktorArtwork::REJECTED) + { + foreach($this->getFiles() as $file) + { + foreach($file->getParentArtworks() as $partwork) + { + if ($partwork->isApproved()) + { + // Back to ->getFiles() + continue 2; + } + } + // Found no approved parents, disable all tags from this file + TaggingPeer::setTaggingApproved(null, "ReaktorFile", $file->getId(), 0); + } + + // Disable all tags by this artwork + TaggingPeer::setTaggingApproved(null, "ReaktorArtwork", $this->getId(), 0); + } + + return 'rejectArtwork'; + break; + case ReaktorArtwork::DRAFT: + // If the artwork was previously removed we should resurrect it's files when restoring it + if ($oldStatus == ReaktorArtwork::REMOVED) + { + $this->unHideFiles(); + } + break; + default: + break; + } + $tagging_status = ($status == ReaktorArtwork::APPROVED ? 1 : 0); + + TaggingPeer::setTaggingApproved(null, "ReaktorArtwork", $this, $tagging_status); + + $files = $this->getFiles(); + foreach ($files as $fileObject) + { + TaggingPeer::setTaggingApproved(null, "ReaktorFile", $fileObject, $tagging_status); + } + return true; + } + + /** + * Go through all the artwork's files and unhide them + * Since you need credentials to do this, the internal file list + * should already be populated with hidden files (if any exist) along with the + * other (regular) files + * + * @return null + */ + protected function unHideFiles() + { + foreach($this->getFiles() as $file) + { + if ($file->isHidden()) + { + $file->setUnHidden(); + $file->save(); + } + } + } + + /** + * Returns the artwork modified date if it was since it was approved + * + * @return date or null if not modified + */ + function getModifiedDate() + { + return $this->_artwork->getModifiedFlag(); + } + + /** + * Get the notes that are linked to a modified artwork + * + * @param $translate Whether to run each line through translator + * + * @return string + */ + function getModifiedNote($translate = true) + { + if ($translate) + { + $note = $this->_artwork->getModifiedNote(); + $noteLines = preg_split('/[\n\r]+/', $note, -1, PREG_SPLIT_NO_EMPTY); + $newText = ""; + + foreach($noteLines as $line) + { + $newText .= sfContext::getInstance()->getI18n()->__($line)."\n"; + } + + return $newText; + } + + return $this->_artwork->getModifiedNote(); + } + + /** + * Get a list of lokalreaktors for this artwork + * + * @param boolean $references Return references only instead of objects + * + * @return array Subreaktors (lokalreaktors) that are linked to this artwork + * + */ + function getLokalreaktors($references = false) + { + return $this->getSubreaktors($references, array('lokalreaktor')); + } + + /** + * Get subreaktors + * + * @param boolean $references Return references only instead of objects + * @param array $returnTypes The type of reaktors to return (subreaktor, lokalreaktor) + * + * @return array Subreaktors that are linked to this artwork + */ + function getSubreaktors($references = false, $returnTypes = array("subreaktor", "lokalreaktor")) + { + $returnArray = array(); + + if (in_array("subreaktor", $returnTypes)) + { + $c = new Criteria(); + $c->addJoin(SubreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID); + $c->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->getId()); + $c->addAscendingOrderByColumn(SubreaktorPeer::SUBREAKTOR_ORDER); + + $subreaktors = SubreaktorArtworkPeer::doSelectJoinSubreaktor($c); + + foreach($subreaktors as $asubreaktor) + { + $returnArray[$asubreaktor->getSubreaktor()->getId()] = $references ? $asubreaktor->getSubreaktor()->getReference() : $asubreaktor->getSubreaktor(); + } + } + + if (in_array("lokalreaktor", $returnTypes)) + { + $c = new Criteria(); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID); + $c->add(LokalreaktorArtworkPeer::ARTWORK_ID, $this->getId()); + $c->addAscendingOrderByColumn(SubreaktorPeer::SUBREAKTOR_ORDER); + + $lokalreaktors = LokalreaktorArtworkPeer::doSelectJoinSubreaktor($c); + + foreach($lokalreaktors as $alokalreaktor) + { + $returnArray[$alokalreaktor->getSubreaktor()->getId()] = $references ? $alokalreaktor->getSubreaktor()->getReference() : $alokalreaktor->getSubreaktor(); + } + } + + return $returnArray; + } + + function getSubreaktorNames() + { + $subreaktornames = array(); + $subreaktors = $this->getSubreaktors(); + foreach ($subreaktors as $aSubreaktor) + { + $subreaktornames[] = $aSubreaktor->getName(); + } + return $subreaktornames; + } + + /** + * Add subreaktor to artwork + * + * @param integer|string $subreaktor ID or reference string + */ + function addSubreaktor($subreaktor) + { + if ($this->_isunsaved) + { + throw new Exception("Must save artwork first or it won't have a DB ID"); + } + + if (is_numeric($subreaktor)) + { + $res = SubreaktorPeer::retrieveByPK($subreaktor); + } + else + { + $res = SubreaktorPeer::retrieveByReference($subreaktor); + $subreaktor = $res->getId(); + + } + + if ($res->getLokalreaktor()) + { + $this->_addLokalreaktor($subreaktor); + } + else + { + // Check that this is a relevant subreaktor + $eligible = SubreaktorIdentifierPeer::getEligibleSubreaktors($this, true); + if (is_numeric($subreaktor)) + { + $eligible = array_keys($eligible); + } + if (in_array($subreaktor, $eligible)) + { + $this->_addSubreaktor($subreaktor); + } + } + $this->clearLinkCache(); + } + + /** + * Get a list of eligible categories for this artwork + * + * @return array + */ + function getEligibleCategories() + { + return CategorySubreaktorPeer::getCategoriesUsedBySubreaktor($this->artwork->getSubreaktors(), false); + } + + /** + * Compare the new list of subreaktors to the old one, if there are differences, + * add or delete to make sure the database is updated. + * + * This is useful when using checkboxes in forms to keep score. + * + * @param array $newSubreaktors The new Subreaktors + * @param array $oldSubreaktors The old subreaktors + */ + function updateSubreaktors($newSubreaktors, $oldSubreaktors) + { + //Add all new subreaktors that haven't already been added + foreach($newSubreaktors as $subreaktor) + { + if (!in_array($subreaktor, $oldSubreaktors)) + { + $this->addSubreaktor($subreaktor); + } + } + //Remove all old subreaktors that aren't in the new list + foreach($oldSubreaktors as $subreaktor) + { + if (!in_array($subreaktor, $newSubreaktors)) + { + $this->removeSubreaktor($subreaktor); + } + } + } + + /** + * Remove subreaktor from artwork + * + * @param integer $subreaktor_id + */ + function removeSubreaktor($subreaktor_id) + { + $c = new Criteria(); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $subreaktor_id); + $c->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->getId()); + SubreaktorArtworkPeer::doDelete($c); + + CategoryArtworkPeer::removeAllInSubreaktor($this, $subreaktor_id); + + $c = new Criteria(); + $c->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $subreaktor_id); + $c->add(LokalreaktorArtworkPeer::ARTWORK_ID, $this->getId()); + LokalreaktorArtworkPeer::doDelete($c); + $this->clearLinkCache(); + } + + protected function _addSubreaktor($subreaktorId) + { + SubreaktorArtworkPeer::addSubreaktorArtwork($this, $subreaktorId); + } + + protected function _addLokalreaktor($lokalreaktor_id) + { + $lokalreaktorartworkitem = new LokalreaktorArtwork(); + $lokalreaktorartworkitem->setArtworkId($this->getId()); + $lokalreaktorartworkitem->setSubreaktorId($lokalreaktor_id); + $lokalreaktorartworkitem->save(); + } + + /** + * Return true if logged in user can administer this artwork, + * false if not. + * + * @return boolean + */ + function canApprove() + { + $subreaktors = $this->getSubreaktors(); + $canApprove = false; + foreach ($subreaktors as $subreaktor) + { + if (sfContext::getInstance()->getUser()->hasGroup($subreaktor->getReference().'_redaksjon')) + { + $canApprove = true; + break; + } + } + + return $canApprove; + } + + + /** + * Get the rejection comment + * + * @return string The comment linked to the rejection + */ + function getRejectionMsg() + { + $c = new Criteria(); + $c->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->getId()); + $c->add(ReaktorArtworkPeer::STATUS, 4); + $c->addDescendingOrderByColumn(ReaktorArtworkHistoryPeer::CREATED_AT); + $history_entry = ReaktorArtworkHistoryPeer::doSelectOne($c); + if ($history_entry) + { + return $history_entry->getComment(); + } + else + { + return ''; + } + } + + /** + * Get array of related artworks as linked by the user and stored in related_artwork table + * + * @param integer $limit How many results to return (null to get all) + * @param boolean $approved Whether to return only approved artworks + * + * @return array of Artwork objects + */ + function getRelatedArtworks($limit = 6, $approved = true) + { + sfContext::getInstance()->getLogger()->info("Getting all related artworks"); + return RelatedArtworkPeer::getRelatedArtworkObjects($this->getId(), $limit, $approved); + } + + function isRelated($id) + { + return RelatedArtworkPeer::isRelated($this->getId(), $id); + } + + /** + * Return the editorial team (group) object assigned to this artwork + * + * @return sfGuardGroup The guard group object + */ + function getEditorialTeam() + { + if ($this->_artwork->getTeamId()) + { + return $this->_artwork->getsfGuardGroup(); + } + else + { + throw new exception ("No editorial team assigned"); + } + } + + /** + * Set the editorial team based on the group ID or group object + * + * @param integer|sfGuardGroup $teamId + */ + function setEditorialTeam($teamId) + { + if ($teamId instanceof sfGuardGroup) + { + $teamId = $teamId->getId(); + } + + $this->_artwork->setTeamId($teamId); + $this->_isunsaved = true; + + return true; + } + + + /** + * Initially set or reset the editorial team based on the artwork subreaktors etc + * Returns the team that was set based on the decision making process + * + * @return sfGuardGroup The chosen team + */ + function resetEditorialTeam() + { + // Get all the subreaktors and lokal reaktors + $subreaktorArray = $this->getSubreaktors(); + $subreaktorReferenceArray = $this->getSubreaktors(true); + // First we check if this artwork matches a competition that has been set in app.yml + $competitionsArray = sfConfig::get("app_editorial_team_competitions", array()); + foreach ($competitionsArray as $competition) + { + if (time() > strtotime($competition["start"]) && time() < strtotime($competition["end"]) + && count(array_diff($subreaktorReferenceArray, $competition["subreaktors"])) < count($subreaktorReferenceArray)) + { + // We matched a subreaktor, now we need to see if any categories match + $categories = array_keys($this->getCategories()); + if (count(array_diff($categories, $competition["categories"])) < count($categories)) + { + // We matched a subreaktor and a category, assign the team if it exists in the database + if ($team = sfGuardGroupPeer::retrieveByName($competition["team"])) + { + $this->setEditorialTeam($team); + return $competition["team"]; + } + } + } + } + + // Next we check for lokalreaktors as they will always be chosen over normal subreaktors if set + if ($result = $this->_checkSubreaktorForTeams($subreaktorArray, true)) + { + $this->setEditorialTeam($result); + return $result; + } + // Now check the rest of the normal subreaktors + elseif ($result = $this->_checkSubreaktorForTeams($subreaktorArray, false)) + { + $this->setEditorialTeam($result); + return $result; + } + // Ok no hits - must be some teams on holiday or the app.yml hasn't been set very well + $defaultTeam = sfGuardGroupPeer::getGroupByName(sfConfig::get("app_editorial_team_default", "deichman_redaksjon")); + $this->setEditorialTeam($defaultTeam); + return $defaultTeam; + } + + /** + * This function called twice by the reset editorial team function so moved here to promote code reuse + * + * @param array $subreaktorArray The array of subreaktors to check + * @param boolean $lokal whether we are checking lokal reaktors or not + * + * @return sfGuardgroup or false + */ + protected function _checkSubreaktorForTeams($subreaktorArray = array(), $lokal = false) + { + foreach($subreaktorArray as $subreaktor) + { + if ($subreaktor instanceof SubreaktorArtwork) + { + $subreaktorObject = $subreaktor->getSubreaktor(); + } + else + { + $subreaktorObject = $subreaktor; + } + + // Only check lokalreaktors if we have the $lokal parameter set true & normal Subreaktors if false + if ($subreaktorObject->getLokalreaktor() == $lokal) + { + // See if this subreaktor/lokalreaktor has any editorial teams in it's list + if (sfConfig::get("app_editorial_team_assignment_".$subreaktorObject->getReference())) + { + // We need to check through the list and find the first one that is enabled, preserving the yml file order + foreach (sfConfig::get("app_editorial_team_assignment_".$subreaktorObject->getReference()) as $ref) + { + // Special residence list hit? + if ($ref == "assign_by_residence") + { + $residenceId = $this->getUser()->getResidenceId(); + foreach(sfConfig::get("app_editorial_team_assign_by_residence", array()) as $team => $residenceArray) + { + if (in_array($residenceId, $residenceArray)) + { + $residenceTeam = sfGuardGroupPeer::retrieveByName($team); + if ($residenceTeam->isEnabled()) + { + return $residenceTeam; + } + // If we got a hit but the team is not enabled, we go to the backup team + elseif (sfConfig::get("app_editorial_team_backup_teams_".$team)) + { + foreach (sfConfig::get("app_editorial_team_backup_teams_".$team) as $backupTeamName) + { + $backupTeam = sfGuardGroupPeer::retrieveByName($backupTeamName); + if ($backupTeam->isEnabled()) + { + return $backupTeam; + } + } + } + } + } + } + else + { + $team = sfGuardGroupPeer::retrieveByName($ref); + if ($team->isEnabled()) + { + return $team; + } + } + } + } + } + } + // No hits, not a problem because the calling function will set a default + return false; + } + + /** + * This function will return editorial users when new artwork is submitted + * + * + * @param team string, name of team + * + * @return sfGuardgroup array + */ + public function getEditorialTeamMembers($team) + { + $group = sfGuardGroupPeer::getGroupByName($team); + $numUnapprovedArtworksInEditorialTeam = ReaktorArtworkPeer::getNumberofArtworksByEditorialTeam(array($group->getId() => $team), 2); + + return $group->getMembers($numUnapprovedArtworksInEditorialTeam); + + } + + /** + + * Return the taggable model string to use in the tagging table + * + * @return string + */ + public function getTaggableModel() + { + return "ReaktorArtwork"; + } + + /** + * Check whether this artwork has files under discussion + * + * @return unknown + */ + public function hasFilesUnderDiscussion() + { + // Should check that there are some files first or this won't return an accurate value + if (count($this->_files) == 0) + { + $this->populateFiles(); + } + + if (count($this->_filesUnderDiscussion) > 0) + { + return true; + } + + return false; + } + + /** + * Return the files under discussion + * + * @return array of file objects that are under discussion + */ + public function getFilesUnderDiscussion() + { + // Should check that there are some files first or this won't return an accurate value + if (count($this->_files) == 0) + { + $this->populateFiles(); + } + + return $this->_filesUnderDiscussion; + } + + /** + * Return whether this artwork is under discussion or not + * + * @return boolean whether under discussion or not + */ + public function isUnderDiscussion() + { + return (bool)$this->_artwork->getUnderDiscussion(); + } + + /** + * Set this artwork under discussion + * + * @return null + */ + public function markUnderDiscussion() + { + $this->_artwork->setUnderDiscussion(1); + $this->_artwork->save(); + HistoryPeer::logAction(8, sfContext::getInstance()->getUser()->getId(), $this); + } + + /** + * Get by who and when the artwork was marked for discussion last. + * + * @return History + */ + public function getDiscussionInfo() + { + if (HistoryPeer::getAction(8, $this)) + { + return HistoryPeer::getAction(8, $this); + } + else + { + throw new Exception("Article discussion has no history"); + } + } + + /** + * Mark this artwork as not under discussion + * + * @return null + */ + public function markNotUnderDiscussion() + { + $this->_artwork->setUnderDiscussion(0); + $this->_artwork->save(); + HistoryPeer::logAction(9, sfContext::getInstance()->getUser()->getId(), $this); + } + + public function getCommentCount($namespace) + { + return $this->_artwork->getCommentCount($namespace); + } + /** + * Return the artwork object that we are working with + * + * @return reaktorArtwork + */ + public function getBaseObject() + { + return $this->_artwork; + } + + /** + * This is required by the RSS plugin to generate the correct artwork route automatically + * Since sf_culture is a required parameter, the feed parameter looks for this function in the object automatically + * + * @return string the culture provided in the url (if any) + */ + public function getFeedSfCulture() + { + return sfContext::getInstance()->getRequest()->getParameter('sf_culture', 'no'); + } + + /** + * Return the publish date of this artwork for the feed generator + * If this function is not here, the plugin looks for getCreatedAt() which exists above but returns + * A formatted date which I don't think the feed generator likes too much... + * + * @return + */ + public function getFeedPubDate() + { + return strtotime($this->_artwork->getCreatedAt()); + } + + /** + * Get the provided subreaktor for Feed generator + * + * @return subreaktor|null + */ + public function getFeedSubreaktor() + { + if (subreaktor::isValid()) + { + return Subreaktor::getProvided(); + } + } + + /** + * Custom title for RSS feeds which includes the username of the owner + * + * @return string the i18n title/username combo + */ + public function getCustomFeedTitle() + { + return sfContext::getInstance()->getI18N()->__("%title% by %username%", + array("%title%" => $this->getTitle(), + "%username%" => $this->getUser()->getUsername())); + } + + /** + * Include the first file in the artwork as a feed enclosure + * + * @return void + */ + public function getFeedEnclosure() + { + return $this->getFirstFile(); + } + + // Used by the feed plugin to generate content, see bug#425 + public function getContent() + { + sfLoader::loadHelpers(array("Url", "content", "Asset", "Tag")); + return showMiniThumb($this, true, false, false); + } + + + public function getLicense() + { + return new ccLicense($this->getFirstFile()->getMetadata('license')); + } + + /** + * Generate valid absolute url for Atom IDs + * + * @return void + */ + public function getFeedUniqueId() + { + return sfContext::getInstance()->getController()->genUrl($this->getLink(), true); + } + + /** + * Return details of whether this is a multi-user artwork + * + * @return boolean true if this is an admin created multi-user artwork + */ + public function isMultiUser() + { + return (bool)$this->_artwork->getMultiUser(); + } + + /** + * Set the multi user flag for composite artworks + * + * @param boolean $setting true if this is a multi user artwork + */ + public function setMultiUser($setting = true) + { + $this->_artwork->setMultiUser($setting); + $this->_isunsaved = true; + } + + /** + * Return whether an artwork can be embedded in other sites based on the file type + * At present, the only criteria is that it is not a flash animation, but this function + * allows for better flexibility in future + * + * @return boolean true if it can be embedded in other sites + */ + public function canEmbed() + { + if ($this->getArtworkType() != "flash_animation") + { + return true; + } + return false; + } + + /** + * Returns true if all the elements are present and have finished transcoding + * + * @return boolean + */ + public function isTranscoded() + { + if (!is_null($this->_isTranscoded)) + { + return $this->_isTranscoded; + } + + foreach ($this->getFiles() as $file) + { + switch ($file->getIdentifier()) + { + case "audio": + if (file_exists($file->getFullFilePath().".temp.mp3")) + { + $this->_isTranscoded = false; + return false; + } + case "video": + if (file_exists($file->getFullFilePath().".temp.flv")) + { + $this->_isTranscoded = false; + return false; + } + default: + break; + } + } + $this->_isTranscoded = true; + return true; + } + + /** + * Get list of relevant help articles by matching article and artwork categories and subreaktors. + * + */ + public function getHelpArticles() + { + + //echo implode(',', array_keys($this->getCategories())).'
'; + //echo implode(',', array_keys($this->getSubreaktors(true))).'
'; + + return $this->_artwork->getHelpArticles($this->getSubreaktors(true), $this->getCategories()); + + } + + public function getFeedAuthorName() + { + $user = $this->getUser(); + return $user->getNamePrivate() ? $user->getUsername() : $user->getName(); + } + public function getFeedAuthorEmail() + { + $user = $this->getUser(); + return $user->getEmailPrivate() ? null : $user->getEmail(); + } + + public function setStatus($status) + { + // New approved artwork, clear the count cache + if ($status == ReaktorArtwork::APPROVED) + { + if (!$artworkUser = $this->getUser()) + { + throw new Exception("You must set the user ID of the artwork before changing the status"); + } + + //Update last action flag for owner of artwork + $artworkUser->setLastActive(date('Y-m-d H:i:s')); + $artworkUser->save(); + + reaktorCache::delete("artworkCount"); + + + } + + + } + + /** + * Whether this artwork should show next/previous links + * Based on app.yml configuration + * + * @return boolean true if this artwork should display navigation links + */ + public function showNavigationOnDisplay() + { + return (in_array($this->getArtworkType(), sfConfig::get("app_artwork_show_navigation", array()))); + } + + /** + * Return the name of the database table where these objects are stored + * + * @return string + */ + public function getTableName() + { + return "reaktor_artwork"; + } +} diff --git a/apps/reaktor/lib/helper/PagerNavigationHelper.php b/apps/reaktor/lib/helper/PagerNavigationHelper.php new file mode 100644 index 0000000..6e9ab98 --- /dev/null +++ b/apps/reaktor/lib/helper/PagerNavigationHelper.php @@ -0,0 +1,46 @@ +haveToPaginate()) + { + $uri .= (preg_match('/\?/', $uri) ? '&' : '?').'page='; + + // First and previous page + if ($pager->getPage() != 1) + { + $navigation .= link_to(image_tag('/sf/images/sf_admin/first.png', 'align=middle'), $uri.'1'); + $navigation .= link_to(image_tag('/sf/images/sf_admin/previous.png', 'align=middle'), $uri.$pager->getPreviousPage()).' '; + } + + // Pages one by one + $links = array(); + foreach ($pager->getLinks() as $page) + { + $links[] = link_to_unless($page == $pager->getPage(), $page, $uri.$page, array('class' => 'navigation')); + } + $navigation .= join('  ', $links); + + // Next and last page + if ($pager->getPage() != $pager->getLastPage()) + { + $navigation .= ' '.link_to(image_tag('/sf/images/sf_admin/next.png', 'align=middle'), $uri.$pager->getNextPage()); + $navigation .= link_to(image_tag('/sf/images/sf_admin/last.png', 'align=middle'), $uri.$pager->getLastPage()); + } + + } + return $navigation; +} diff --git a/apps/reaktor/lib/helper/arrayHelper.php b/apps/reaktor/lib/helper/arrayHelper.php new file mode 100644 index 0000000..2a76889 --- /dev/null +++ b/apps/reaktor/lib/helper/arrayHelper.php @@ -0,0 +1,32 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + + +function countKeyOccurenceRecursive($array,$key) +{ + global $theKey ; + global $count ; + $theKey = $key; + $count = 0; + array_walk_recursive($array,'countKey'); + return $count; +} + +function countkey($item,$key) +{ + global $theKey,$count; + + if ($key == $theKey) + $count++; + + +}*/ +?> \ No newline at end of file diff --git a/apps/reaktor/lib/helper/browserDetectionHelper.php b/apps/reaktor/lib/helper/browserDetectionHelper.php new file mode 100644 index 0000000..7297da5 --- /dev/null +++ b/apps/reaktor/lib/helper/browserDetectionHelper.php @@ -0,0 +1,654 @@ += 5, opera >= 5, all new mozillas, safaris, konquerors +5. os - returns which os is being used +6. os_number - returns windows versions, 95, 98, me, nt 4, nt 5 [windows 2000], nt 5.1 [windows xp], + Just added: os x detection[crude] otherwise returns false +7. browser - returns the browser name, in shorthand: ie, ie4, ie5x, op, moz, konq, saf, ns4 +8. number - returns the browser version number, if available, otherwise returns '' [not available] +9. full - returns this array: $browser_name, $version_number, $ie_version, $dom_browser, + $safe_browser, $os, $os_number, $s_browser [the browser search string from the browser array], $type +10. type - returns whether it's a bot or a browser +11. math_number - returns basic version number, for math comparison, ie. 1.2rel2a becomes 1.2 +*******************************************/ + +// main script, uses two other functions, which_os() and browser_version() as needed +function browser_detection( $which_test ) { + /* + uncomment the global variable declaration if you want the variables to be available on a global level + throughout your php page, make sure that php is configured to support the use of globals first! + Use of globals should be avoided however, and they are not necessary with this script + */ + + /*global $dom_browser, $safe_browser, $browser_user_agent, $os, $browser_name, $s_browser, $ie_version, + $version_number, $os_number, $b_repeat, $moz_version, $moz_version_number, $moz_rv, $moz_rv_full, $moz_release;*/ + + static $dom_browser, $safe_browser, $browser_user_agent, $os, $browser_name, $s_browser, $ie_version, + $version_number, $os_number, $b_repeat, $moz_version, $moz_version_number, $moz_rv, $moz_rv_full, $moz_release, + $type, $math_version_number; + + /* + this makes the test only run once no matter how many times you call it + since all the variables are filled on the first run through, it's only a matter of returning the + the right ones + */ + if ( !$b_repeat ) + { + //initialize all variables with default values to prevent error + $dom_browser = false; + $type = 'bot';// default to bot since you never know with bots + $safe_browser = false; + $os = ''; + $os_number = ''; + $a_os_data = ''; + $browser_name = ''; + $version_number = ''; + $math_version_number = ''; + $ie_version = ''; + $moz_version = ''; + $moz_version_number = ''; + $moz_rv = ''; + $moz_rv_full = ''; + $moz_release = ''; + $b_success = false;// boolean for if browser found in main test + + //make navigator user agent string lower case to make sure all versions get caught + // isset protects against blank user agent failure + $browser_user_agent = ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) ? strtolower( $_SERVER['HTTP_USER_AGENT'] ) : ''; + + /* + pack the browser type array, in this order + the order is important, because opera must be tested first, then omniweb [which has safari data in string], + same for konqueror, then safari, then gecko, since safari navigator user agent id's with 'gecko' in string. + note that $dom_browser is set for all modern dom browsers, this gives you a default to use. + + array[0] = id string for useragent, array[1] is if dom capable, array[2] is working name for browser, + array[3] identifies navigator useragent type + + Note: all browser strings are in lower case to match the strtolower output, this avoids possible detection + errors + + Note: There are currently 5 navigator user agent types: + bro - modern, css supporting browser. + bbro - basic browser, text only, table only, defective css implementation + bot - search type spider + dow - known download agent + lib - standard http libraries + */ + // known browsers, list will be updated routinely, check back now and then + $a_browser_types[] = array( 'opera', true, 'op', 'bro' ); + $a_browser_types[] = array( 'omniweb', true, 'omni', 'bro' );// mac osx browser, now uses khtml engine: + $a_browser_types[] = array( 'msie', true, 'ie', 'bro' ); + $a_browser_types[] = array( 'konqueror', true, 'konq', 'bro' ); + $a_browser_types[] = array( 'safari', true, 'saf', 'bro' ); + // covers Netscape 6-7, K-Meleon, Most linux versions, uses moz array below + $a_browser_types[] = array( 'gecko', true, 'moz', 'bro' ); + $a_browser_types[] = array( 'netpositive', false, 'netp', 'bbro' );// beos browser + $a_browser_types[] = array( 'lynx', false, 'lynx', 'bbro' ); // command line browser + $a_browser_types[] = array( 'elinks ', false, 'elinks', 'bbro' ); // new version of links + $a_browser_types[] = array( 'elinks', false, 'elinks', 'bbro' ); // alternate id for it + $a_browser_types[] = array( 'links ', false, 'links', 'bbro' ); // old name for links + $a_browser_types[] = array( 'links', false, 'links', 'bbro' ); // alternate id for it + $a_browser_types[] = array( 'w3m', false, 'w3m', 'bbro' ); // open source browser, more features than lynx/links + $a_browser_types[] = array( 'webtv', false, 'webtv', 'bbro' );// junk ms webtv + $a_browser_types[] = array( 'amaya', false, 'amaya', 'bbro' );// w3c browser + $a_browser_types[] = array( 'dillo', false, 'dillo', 'bbro' );// linux browser, basic table support + $a_browser_types[] = array( 'ibrowse', false, 'ibrowse', 'bbro' );// amiga browser + $a_browser_types[] = array( 'icab', false, 'icab', 'bro' );// mac browser + $a_browser_types[] = array( 'crazy browser', true, 'ie', 'bro' );// uses ie rendering engine + $a_browser_types[] = array( 'sonyericssonp800', false, 'sonyericssonp800', 'bbro' );// sony ericsson handheld + + // search engine spider bots: + $a_browser_types[] = array( 'googlebot', false, 'google', 'bot' );// google + $a_browser_types[] = array( 'mediapartners-google', false, 'adsense', 'bot' );// google adsense + $a_browser_types[] = array( 'yahoo-verticalcrawler', false, 'yahoo', 'bot' );// old yahoo bot + $a_browser_types[] = array( 'yahoo! slurp', false, 'yahoo', 'bot' ); // new yahoo bot + $a_browser_types[] = array( 'yahoo-mm', false, 'yahoomm', 'bot' ); // gets Yahoo-MMCrawler and Yahoo-MMAudVid bots + $a_browser_types[] = array( 'inktomi', false, 'inktomi', 'bot' ); // inktomi bot + $a_browser_types[] = array( 'slurp', false, 'inktomi', 'bot' ); // inktomi bot + $a_browser_types[] = array( 'fast-webcrawler', false, 'fast', 'bot' );// Fast AllTheWeb + $a_browser_types[] = array( 'msnbot', false, 'msn', 'bot' );// msn search + $a_browser_types[] = array( 'ask jeeves', false, 'ask', 'bot' ); //jeeves/teoma + $a_browser_types[] = array( 'teoma', false, 'ask', 'bot' );//jeeves teoma + $a_browser_types[] = array( 'scooter', false, 'scooter', 'bot' );// altavista + $a_browser_types[] = array( 'openbot', false, 'openbot', 'bot' );// openbot, from taiwan + $a_browser_types[] = array( 'ia_archiver', false, 'ia_archiver', 'bot' );// ia archiver + $a_browser_types[] = array( 'zyborg', false, 'looksmart', 'bot' );// looksmart + $a_browser_types[] = array( 'almaden', false, 'ibm', 'bot' );// ibm almaden web crawler + $a_browser_types[] = array( 'baiduspider', false, 'baidu', 'bot' );// Baiduspider asian search spider + $a_browser_types[] = array( 'psbot', false, 'psbot', 'bot' );// psbot image crawler + $a_browser_types[] = array( 'gigabot', false, 'gigabot', 'bot' );// gigabot crawler + $a_browser_types[] = array( 'naverbot', false, 'naverbot', 'bot' );// naverbot crawler, bad bot, block + $a_browser_types[] = array( 'surveybot', false, 'surveybot', 'bot' );// + $a_browser_types[] = array( 'boitho.com-dc', false, 'boitho', 'bot' );//norwegian search engine + $a_browser_types[] = array( 'objectssearch', false, 'objectsearch', 'bot' );// open source search engine + $a_browser_types[] = array( 'answerbus', false, 'answerbus', 'bot' );// http://www.answerbus.com/, web questions + $a_browser_types[] = array( 'sohu-search', false, 'sohu', 'bot' );// chinese media company, search component + $a_browser_types[] = array( 'iltrovatore-setaccio', false, 'il-set', 'bot' ); + + // various http utility libaries + $a_browser_types[] = array( 'w3c_validator', false, 'w3c', 'lib' ); // uses libperl, make first + $a_browser_types[] = array( 'wdg_validator', false, 'wdg', 'lib' ); // + $a_browser_types[] = array( 'libwww-perl', false, 'libwww-perl', 'lib' ); + $a_browser_types[] = array( 'jakarta commons-httpclient', false, 'jakarta', 'lib' ); + $a_browser_types[] = array( 'python-urllib', false, 'python-urllib', 'lib' ); + + // download apps + $a_browser_types[] = array( 'getright', false, 'getright', 'dow' ); + $a_browser_types[] = array( 'wget', false, 'wget', 'dow' );// open source downloader, obeys robots.txt + + // netscape 4 and earlier tests, put last so spiders don't get caught + $a_browser_types[] = array( 'mozilla/4.', false, 'ns', 'bbro' ); + $a_browser_types[] = array( 'mozilla/3.', false, 'ns', 'bbro' ); + $a_browser_types[] = array( 'mozilla/2.', false, 'ns', 'bbro' ); + + //$a_browser_types[] = array( '', false ); // browser array template + + /* + moz types array + note the order, netscape6 must come before netscape, which is how netscape 7 id's itself. + rv comes last in case it is plain old mozilla + */ + $moz_types = array( 'firebird', 'phoenix', 'firefox', 'iceweasel', 'galeon', 'k-meleon', 'camino', 'epiphany', 'netscape6', 'netscape', 'multizilla', 'swiftfox', 'rv' ); + + /* + run through the browser_types array, break if you hit a match, if no match, assume old browser + or non dom browser, assigns false value to $b_success. + Topherbyte pointed out that looping a count counts each time, so that's fixed + */ + $i_count = count($a_browser_types); + for ($i = 0; $i < $i_count; $i++) + { + //unpacks browser array, assigns to variables + $s_browser = $a_browser_types[$i][0];// text string to id browser from array + + if (stristr($browser_user_agent, $s_browser)) + { + // it defaults to true, will become false below if needed + // this keeps it easier to keep track of what is safe, only + //explicit false assignment will make it false. + $safe_browser = true; + + // assign values based on match of user agent string + $dom_browser = $a_browser_types[$i][1];// hardcoded dom support from array + $browser_name = $a_browser_types[$i][2];// working name for browser + $type = $a_browser_types[$i][3];// sets whether bot or browser + + switch ( $browser_name ) + { + // this is modified quite a bit, now will return proper netscape version number + // check your implementation to make sure it works + case 'ns': + $safe_browser = false; + $version_number = browser_version( $browser_user_agent, 'mozilla' ); + break; + case 'moz': + /* + note: The 'rv' test is not absolute since the rv number is very different on + different versions, for example Galean doesn't use the same rv version as Mozilla, + neither do later Netscapes, like 7.x. For more on this, read the full mozilla numbering + conventions here: + http://www.mozilla.org/releases/cvstags.html + */ + + // this will return alpha and beta version numbers, if present + $moz_rv_full = browser_version( $browser_user_agent, 'rv' ); + // this slices them back off for math comparisons + $moz_rv = substr( $moz_rv_full, 0, 3 ); + + // this is to pull out specific mozilla versions, firebird, netscape etc.. + $i_count = count( $moz_types ); + for ( $i = 0; $i < $i_count; $i++ ) + { + if ( stristr( $browser_user_agent, $moz_types[$i] ) ) + { + $moz_version = $moz_types[$i]; + $moz_version_number = browser_version( $browser_user_agent, $moz_version ); + break; + } + } + // this is necesary to protect against false id'ed moz'es and new moz'es. + // this corrects for galeon, or any other moz browser without an rv number + if ( !$moz_rv ) + { + $moz_rv = substr( $moz_version_number, 0, 3 ); + $moz_rv_full = $moz_version_number; + /* + // you can use this instead if you are running php >= 4.2 + $moz_rv = floatval( $moz_version_number ); + $moz_rv_full = $moz_version_number; + */ + } + // this corrects the version name in case it went to the default 'rv' for the test + if ( $moz_version == 'rv' ) + { + $moz_version = 'mozilla'; + } + + //the moz version will be taken from the rv number, see notes above for rv problems + $version_number = $moz_rv; + // gets the actual release date, necessary if you need to do functionality tests + $moz_release = browser_version( $browser_user_agent, 'gecko/' ); + /* + Test for mozilla 0.9.x / netscape 6.x + test your javascript/CSS to see if it works in these mozilla releases, if it does, just default it to: + $safe_browser = true; + */ + if ( ( $moz_release < 20020400 ) || ( $moz_rv < 1 ) ) + { + $safe_browser = false; + } + break; + case 'ie': + $version_number = browser_version( $browser_user_agent, $s_browser ); + // first test for IE 5x mac, that's the most problematic IE out there + if ( stristr( $browser_user_agent, 'mac') ) + { + $ie_version = 'ieMac'; + } + // this assigns a general ie id to the $ie_version variable + elseif ( $version_number >= 5 ) + { + $ie_version = 'ie5x'; + } + elseif ( ( $version_number > 3 ) && ( $version_number < 5 ) ) + { + $dom_browser = false; + $ie_version = 'ie4'; + // this depends on what you're using the script for, make sure this fits your needs + $safe_browser = true; + } + else + { + $ie_version = 'old'; + $dom_browser = false; + $safe_browser = false; + } + break; + case 'op': + $version_number = browser_version( $browser_user_agent, $s_browser ); + if ( $version_number < 5 )// opera 4 wasn't very useable. + { + $safe_browser = false; + } + break; + case 'saf': + $version_number = browser_version( $browser_user_agent, $s_browser ); + break; + /* + Uncomment this section if you want omniweb to return the safari value + Omniweb uses khtml/safari rendering engine, so you can treat it like + safari if you want. + */ + /* + case 'omni': + $s_browser = 'safari'; + $browser_name = 'saf'; + $version_number = browser_version( $browser_user_agent, 'applewebkit' ); + break; + */ + default: + $version_number = browser_version( $browser_user_agent, $s_browser ); + break; + } + // the browser was id'ed + $b_success = true; + break; + } + } + + //assigns defaults if the browser was not found in the loop test + if ( !$b_success ) + { + /* + this will return the first part of the browser string if the above id's failed + usually the first part of the browser string has the navigator useragent name/version in it. + This will usually correctly id the browser and the browser number if it didn't get + caught by the above routine. + If you want a '' to do a if browser == '' type test, just comment out all lines below + except for the last line, and uncomment the last line. If you want undefined values, + the browser_name is '', you can always test for that + */ + // delete this part if you want an unknown browser returned + $s_browser = substr( $browser_user_agent, 0, strcspn( $browser_user_agent , '();') ); + // this extracts just the browser name from the string + ereg('[^0-9][a-z]*-*\ *[a-z]*\ *[a-z]*', $s_browser, $r ); + $s_browser = $r[0]; + $version_number = browser_version( $browser_user_agent, $s_browser ); + + // then uncomment this part + //$s_browser = '';//deletes the last array item in case the browser was not a match + } + // get os data, mac os x test requires browser/version information, this is a change from older scripts + $a_os_data = which_os( $browser_user_agent, $browser_name, $version_number ); + $os = $a_os_data[0];// os name, abbreviated + $os_number = $a_os_data[1];// os number or version if available + + // this ends the run through once if clause, set the boolean + //to true so the function won't retest everything + $b_repeat = true; + + // pulls out primary version number from more complex string, like 7.5a, + // use this for numeric version comparison + $m = array(); + if ( ereg('[0-9]*\.*[0-9]*', $version_number, $m ) ) + { + $math_version_number = $m[0]; + //print_r($m); + } + + } + //$version_number = $_SERVER["REMOTE_ADDR"]; + /* + This is where you return values based on what parameter you used to call the function + $which_test is the passed parameter in the initial browser_detection('os') for example call + */ + switch ( $which_test ) + { + case 'safe':// returns true/false if your tests determine it's a safe browser + // you can change the tests to determine what is a safeBrowser for your scripts + // in this case sub rv 1 Mozillas and Netscape 4x's trigger the unsafe condition + return $safe_browser; + break; + case 'ie_version': // returns ieMac or ie5x + return $ie_version; + break; + case 'moz_version':// returns array of all relevant moz information + $moz_array = array( $moz_version, $moz_version_number, $moz_rv, $moz_rv_full, $moz_release ); + return $moz_array; + break; + case 'dom':// returns true/fale if a DOM capable browser + return $dom_browser; + break; + case 'os':// returns os name + return $os; + break; + case 'os_number':// returns os number if windows + return $os_number; + break; + case 'browser':// returns browser name + return $browser_name; + break; + case 'number':// returns browser number + return $version_number; + break; + case 'full':// returns all relevant browser information in an array + $full_array = array( $browser_name, $version_number, $ie_version, $dom_browser, $safe_browser, + $os, $os_number, $s_browser, $type, $math_version_number ); + return $full_array; + break; + case 'type':// returns what type, bot, browser, maybe downloader in future + return $type; + break; + case 'math_number':// returns numerical version number, for number comparisons + return $math_version_number; + break; + default: + break; + } +} + +// gets which os from the browser string +function which_os ( $browser_string, $browser_name, $version_number ) +{ + // initialize variables + $os = ''; + $os_version = ''; + /* + packs the os array + use this order since some navigator user agents will put 'macintosh' in the navigator user agent string + which would make the nt test register true + */ + $a_mac = array( 'mac68k', 'macppc' );// this is not used currently + // same logic, check in order to catch the os's in order, last is always default item + $a_unix = array( 'freebsd', 'openbsd', 'netbsd', 'bsd', 'unixware', 'solaris', 'sunos', 'sun4', 'sun5', 'suni86', 'sun', 'irix5', 'irix6', 'irix', 'hpux9', 'hpux10', 'hpux11', 'hpux', 'hp-ux', 'aix1', 'aix2', 'aix3', 'aix4', 'aix5', 'aix', 'sco', 'unixware', 'mpras', 'reliant', 'dec', 'sinix', 'unix' ); + // only sometimes will you get a linux distro to id itself... + $a_linux = array( 'ubuntu', 'kubuntu', 'xubuntu', 'mepis', 'xandros', 'linspire', 'sidux', 'kanotix', 'debian', 'opensuse', 'suse', 'fedora', 'redhat', 'slackware', 'slax', 'mandrake', 'mandriva', 'gentoo', 'sabayon', 'linux' ); + $a_linux_process = array ( 'i386', 'i586', 'i686' );// not use currently + // note, order of os very important in os array, you will get failed ids if changed + $a_os = array( 'beos', 'os2', 'amiga', 'webtv', 'mac', 'nt', 'win', $a_unix, $a_linux ); + + //os tester + $i_count = count( $a_os ); + for ( $i = 0; $i < $i_count; $i++ ) + { + //unpacks os array, assigns to variable + $s_os = (isset($a_os[$i])) ? $a_os[$i] : ' '; + + // assign os to global os variable, os flag true on success + // !stristr($browser_string, "linux" ) corrects a linux detection bug + if ( !is_array( $s_os ) && stristr( $browser_string, $s_os ) && !stristr( $browser_string, "linux" ) ) + { + $os = $s_os; + + switch ( $os ) + { + case 'win': + if ( strstr( $browser_string, '95' ) ) + { + $os_version = '95'; + } + elseif ( ( strstr( $browser_string, '9x 4.9' ) ) || ( strstr( $browser_string, 'me' ) ) ) + { + $os_version = 'me'; + } + elseif ( strstr( $browser_string, '98' ) ) + { + $os_version = '98'; + } + elseif ( strstr( $browser_string, '2000' ) )// windows 2000, for opera ID + { + $os_version = 5.0; + $os = 'nt'; + } + elseif ( strstr( $browser_string, 'xp' ) )// windows 2000, for opera ID + { + $os_version = 5.1; + $os = 'nt'; + } + elseif ( strstr( $browser_string, '2003' ) )// windows server 2003, for opera ID + { + $os_version = 5.2; + $os = 'nt'; + } + elseif ( strstr( $browser_string, 'vista' ) )// windows vista, for opera ID + { + $os_version = 6.0; + $os = 'nt'; + } + elseif ( strstr( $browser_string, 'ce' ) )// windows CE + { + $os_version = 'ce'; + } + break; + case 'nt': + if ( strstr( $browser_string, 'nt 6.1' ) )// windows 7 + { + $os_version = 6.1; + $os = 'nt'; + } + elseif ( strstr( $browser_string, 'nt 6.0' ) )// windows vista/server 2008 + { + $os_version = 6.0; + $os = 'nt'; + } + elseif ( strstr( $browser_string, 'nt 5.2' ) )// windows server 2003 + { + $os_version = 5.2; + $os = 'nt'; + } + elseif ( strstr( $browser_string, 'nt 5.1' ) || strstr( $browser_string, 'xp' ) )// windows xp + { + $os_version = 5.1;// + } + elseif ( strstr( $browser_string, 'nt 5' ) || strstr( $browser_string, '2000' ) )// windows 2000 + { + $os_version = 5.0; + } + elseif ( strstr( $browser_string, 'nt 4' ) )// nt 4 + { + $os_version = 4; + } + elseif ( strstr( $browser_string, 'nt 3' ) )// nt 4 + { + $os_version = 3; + } + break; + case 'mac': + if ( strstr( $browser_string, 'os x' ) ) + { + $os_version = 10; + } + //this is a crude test for os x, since safari, camino, ie 5.2, & moz >= rv 1.3 + //are only made for os x + elseif ( ( $browser_name == 'saf' ) || ( $browser_name == 'cam' ) || + ( ( $browser_name == 'moz' ) && ( $version_number >= 1.3 ) ) || + ( ( $browser_name == 'ie' ) && ( $version_number >= 5.2 ) ) ) + { + $os_version = 10; + } + break; + default: + break; + } + break; + } + // check that it's an array, check it's the second to last item + //in the main os array, the unix one that is + elseif ( is_array( $s_os ) && ( $i == ( count( $a_os ) - 2 ) ) ) + { + $i_count = count($s_os); + for ($j = 0; $j < $i_count; $j++) + { + if ( stristr( $browser_string, $s_os[$j] ) ) + { + $os = 'unix'; //if the os is in the unix array, it's unix, obviously... + $os_version = ( $s_os[$j] != 'unix' ) ? $s_os[$j] : '';// assign sub unix version from the unix array + break; + } + } + } + // check that it's an array, check it's the last item + //in the main os array, the linux one that is + elseif ( is_array( $s_os ) && ( $i == ( count( $a_os ) - 1 ) ) ) + { + $i_count = count($s_os); + for ($j = 0; $j < $i_count; $j++) + { + if ( stristr( $browser_string, $s_os[$j] ) ) + { + $os = 'lin'; + // assign linux distro from the linux array, there's a default + //search for 'lin', if it's that, set version to '' + $os_version = ( $s_os[$j] != 'linux' ) ? $s_os[$j] : ''; + break; + } + } + } + } + + // pack the os data array for return to main function + $os_data = array( $os, $os_version ); + return $os_data; +} + +// function returns browser number, gecko rv number, or gecko release date +//function browser_version( $browser_user_agent, $search_string, $substring_length ) +function browser_version( $browser_user_agent, $search_string ) +{ + // 12 is the longest that will be required, handles release dates: 20020323; 0.8.0+ + $substring_length = 12; + //initialize browser number, will return '' if not found + $browser_number = ''; + + // use the passed parameter for $search_string + // start the substring slice right after these moz search strings + // there are some cases of double msie id's, first in string and then with then number + $start_pos = 0; + /* this test covers you for multiple occurrences of string, only with ie though + with for example google bot you want the first occurance returned, since that's where the + numbering happens */ + for ( $i = 0; $i < 4; $i++ ) + { + //start the search after the first string occurrence + if ( strpos( $browser_user_agent, $search_string, $start_pos ) !== false ) + { + //update start position if position found + $start_pos = strpos( $browser_user_agent, $search_string, $start_pos ) + strlen( $search_string ); + if ( $search_string != 'msie' ) + { + break; + } + } + else + { + break; + } + } + + // this is just to get the release date, not other moz information + // also corrects for the omniweb 'v' + if ( $search_string != 'gecko/' ) + { + if ( $search_string == 'omniweb' ) + { + $start_pos += 2;// handles the v in 'omniweb/v532.xx + } + else + { + $start_pos++; + } + } + + // Initial trimming + $browser_number = substr( $browser_user_agent, $start_pos, $substring_length ); + + // Find the space, ;, or parentheses that ends the number + $browser_number = substr( $browser_number, 0, strcspn($browser_number, ' );') ); + + //make sure the returned value is actually the id number and not a string + // otherwise return '' + if ( !is_numeric( substr( $browser_number, 0, 1 ) ) ) + { + $browser_number = ''; + } + //$browser_number = strrpos( $browser_user_agent, $search_string ); + return $browser_number; +} + +/* +Here are some typical navigator.userAgent strings so you can see where the data comes from +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031007 Firebird/0.7 +Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4) Gecko/20011128 Netscape6/6.2.1 +*/ +?> \ No newline at end of file diff --git a/apps/reaktor/lib/helper/buttonHelper.php b/apps/reaktor/lib/helper/buttonHelper.php new file mode 100644 index 0000000..a155564 --- /dev/null +++ b/apps/reaktor/lib/helper/buttonHelper.php @@ -0,0 +1,66 @@ +', fake_link_to($text, $link, $options,$enabled), ''; + } + elseif (is_array($link)) + { + return fake_button_function($text, remote_function($link) . '; return false;', $options, "#", $class,$enabled); + } +} + +/** + * fake_button_function + * + * @param string $text The "button" text + * @param string $function Raw JavaScript code + * @param array $options See link_to() $options + * @param string $id The ID/name to scroll down to + * @return string + */ +function fake_button_function($text, $function, $options = array(), $id = "#", $class = "fakebutton",$enabled=true) +{ + $options["onclick"] = $function; + echo '
', fake_link_to($text, $id, $options,$enabled), '
'; +} + +function fake_link_to($text, $link = "#", $options = array(),$enabled=true) +{ + if (!$enabled) + return $text; + if ($link[0] != "#") + { + return link_to($text, $link, $options); + } + + $attributes = array(); + if (!isset($options["href"])) + { + $options["href"] = $link; + } + foreach($options as $key => $value) + { + $attributes[] = $key. '="' .$value. '"'; + } + return "$text"; + +} + diff --git a/apps/reaktor/lib/helper/cloudHelper.php b/apps/reaktor/lib/helper/cloudHelper.php new file mode 100644 index 0000000..fcf9999 --- /dev/null +++ b/apps/reaktor/lib/helper/cloudHelper.php @@ -0,0 +1,71 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * Generates a tag cload + * + * @param Array $tags Hash with tag name as keys and FIX as value + * @param String $route A route as given to link_to() + * @param Array $options FIX + * + * @return String the cloud + */ +function tag_cloud_with_count($tags, $route, $options = array(), $title = '') +{ + + $result = ''; + if ($title != '') + { + $result .= '

' . $title . '

'; + } + + if (count($tags) > 0) + { + $emphasizers_begin = array(-2 => '', + -1 => '', + 0 => '', + 1 => '', + 2 => ''); + $emphasizers_end = array(-2 => '', + -1 => '', + 0 => '', + 1 => '', + 2 => ''); + + $class = isset($options['class']) ? $options['class'] : 'tag-cloud'; + $result .= '
    '; + + foreach ($tags as $name => $valuesArray) + { + if ($valuesArray['count'] > 0 || isset($options['detailed'])) + { + $linktext = ''; + $linktext .= (!isset($options['detailed'])) + ? $emphasizers_begin[$valuesArray["emphasisValue"]].$valuesArray["displayName"].$emphasizers_end[$valuesArray["emphasisValue"]] + : $name; + + $linktext .= (!isset($options['detailed'])) + ? '(' . $valuesArray['count'] . ')' + : ''; + $link = reaktor_link_to($linktext, $route.$valuesArray["displayName"], array('rel' => 'tag')); + $result .= '
  • '.$link.' '; + $result .= (isset($options['detailed'])) + ? ' ' . $valuesArray['count'] . ' items in this category' + : ''; + $result .= '
  • '; + } + } + + $result .= '
'; + } + + return $result; +} diff --git a/apps/reaktor/lib/helper/commentHelper.php b/apps/reaktor/lib/helper/commentHelper.php new file mode 100644 index 0000000..1eb4ec0 --- /dev/null +++ b/apps/reaktor/lib/helper/commentHelper.php @@ -0,0 +1,19 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +function zeroOrOne() +{ + static $flip = 1; + $flip = !$flip; + return (int)$flip; +} +?> diff --git a/apps/reaktor/lib/helper/contentHelper.php b/apps/reaktor/lib/helper/contentHelper.php new file mode 100644 index 0000000..b160c25 --- /dev/null +++ b/apps/reaktor/lib/helper/contentHelper.php @@ -0,0 +1,201 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Get the correct link to stored content, based on the file ID + * + * @param int|artworkFile $item The file ID or object of the file/artwork (required) + * @param string $type "thumb" or "original" (default is "normal") + * @param boolean $relative Whether to return a relative URL or not + * + * @return string the generated path to file (e.g. /content/1/myimage.jpg) + */ +function contentPath($item, $type = "normal", $relative = false, $randomize = false) +{ + if (is_numeric($item)) + { + try + { + $selectedFile = new artworkFile($item); + } + catch (Exception $e) + { + return ""; + } + } + elseif ($item instanceof genericArtwork) + { + $selectedFile = $item->getFirstFile(); + } + else + { + $selectedFile = $item; + } + + if ($selectedFile instanceof artworkFile) + { + $filename = $selectedFile->getFilename(); + $file_id = $selectedFile->getId(); + } + else + { + return ""; + } + $ext=''; + $routing_rule = '@content_server'; + sfLoader::loadHelpers('string'); + switch ($type) + { + case "thumb": + $routing_rule = '@content_thumb'; + $filename=getThumbNameFromFile($filename); + break; + case "original": + $routing_rule = '@content_original'; + break; + case "mini": + $filename=getThumbNameFromFile($filename); + $routing_rule = '@content_mini'; + break; + case "": + case "normal": + // routing rule already set for this case + break; + default: + return ""; + break; + } + + if ($relative) + { + return "$routing_rule?id=$file_id&filename=$filename"; + } + else + { + $retval = url_for("$routing_rule?id=$file_id&filename=$filename"); + if ($randomize) + { + $retval .= "?id" . rand(); + } + return $retval; + } +} + +/** + * Show mini thumbnail with mouseover tooltip + * + * @param genericArtwork $object The Artwork object + * @param boolean $nomouseover True to hide mouseover + */ +function showMiniThumb($object, $nomouseover = false, $nolink = false, $relative = true) +{ + if (!$object instanceof genericArtwork ) + { + return ""; + } + + sfLoader::loadHelpers(array('Partial')); + + return get_partial("contentServer/showMini", array("artwork" => $object, "nomouseover" => $nomouseover, "nolink" => $nolink, "relative" => $relative)); +} + +/** + * This function calculates how long time it is since a given time + * + * @param time Time + */ +function timeToAgo($time) +{ + $timestamp = strtotime($time); + $now = time(); + $diff = $now - $timestamp; + if ($diff > 31536000) + { + return ((int) ($diff / 31536000)) . " " . __('year(s) ago'); + } + if ($diff > 84600) + { + return ((int) ($diff / 84600)) ." " . __('day(s) ago'); + } + if ($diff > 3600) + { + return ((int) ($diff / 3600)) . " " . __('hour(s) ago'); + } + if ($diff > 60) + { + return ((int) ($diff / 60)) . " " . __('minute(s) ago'); + } else + { + return $diff . " " . __('second(s) ago'); + } +} + +/** + * Return the collection type for a specified artwork + * Placed here to make translation easier, since I don't want to create another i18n table... + * Can also return the type as text if second param is false - partly written here so the translation helpers + * will find them and add them to the translation batch too. + * + * @param genericArtwork|string $artwork The artwork object we are querying or the type if known + * @param boolean $collectionValue Whether to return collection name, or false if you want the content type + * @param boolean $upper Whether to uppercase the first letter of the response + * + * @return string the translated collection type + */ +function collectionType($artwork, $collectionValue = true, $upper = false) +{ + if (is_object($artwork)) + { + $type = $artwork->getArtworkType(); + } + else + { + $type = $artwork; + } + + switch($type) + { + case "image": //image + $result = array (__("gallery"), __("image")); + break; + case "audio": //audio + $result = array (__("playlist"), __("audio")); + break; + case "text": //text + $result = array (__("collection"), __("text")); + break; + case "video": //video + $result = array (__("playlist"), __("video")); + break; + case "pdf": //pdf + $result = array (__("collection"), __("pdf")); + break; + case "flash_animation": //Flash animation + $result = array(__("collection"), __("flash animation")); + break; + default: + return ""; + break; + } + if ($collectionValue) + { + return $upper ? ucfirst($result[0]) : $result[0]; + } + else + { + return $upper ? ucfirst($result[1]) : $result[1]; + } +} diff --git a/apps/reaktor/lib/helper/doubleListHelper.php b/apps/reaktor/lib/helper/doubleListHelper.php new file mode 100644 index 0000000..75c9685 --- /dev/null +++ b/apps/reaktor/lib/helper/doubleListHelper.php @@ -0,0 +1,90 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +function _remove_recursive_from_list($remove, $list) +{ + $retval = $list; + foreach($list as $key => $element) { + if (is_array($element)) { + $retval[$key] = _remove_recursive_from_list($remove, $element); + } else { + if (in_array($element, (array)$remove)) { + unset($retval[$key]); + } + } + } + return $retval; +} + +/** + * Takes two arrays to create "add/remove" list boxes + * + * @param array $list All elements to list + * @param array $pick Choicen elements (will be removed from $list) + * @param array $options HTML options array + * @return string The generated html + */ +function reaktor_double_list(array $list, array $pick = array(), array $options = array()) +{ + $options = _parse_attributes($options); + + $options['multiple'] = true; + $options['class'] = 'sf_admin_multiple'; + if (!isset($options['size'])) + { + $options['size'] = 10; + } + $label_all = __(isset($options['unassociated_label']) ? $options['unassociated_label'] : 'Unassociated'); + $label_assoc = __(isset($options['associated_label']) ? $options['associated_label'] : 'Associated'); + + $list = _remove_recursive_from_list($pick, $list); + + $name = "lokalreaktor_residence"; + $name1 = 'unassociated_'.$name; + $name2 = 'associated_'.$name; + $select1 = select_tag($name1, options_for_select($list, '', $options), $options); + $options['class'] = 'sf_admin_multiple-selected'; + $select2 = select_tag($name2, options_for_select($pick, '', $options), $options); + + $html = +'
+
+
%s
+ %s +
+
+ %s
+ %s +
+
+
%s
+ %s +
+
+
+'; + + $response = sfContext::getInstance()->getResponse(); + $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/prototype'); + $response->addJavascript(sfConfig::get('sf_admin_web_dir').'/js/double_list'); + + return sprintf($html, + $label_all, + $select1, + submit_image_tag(sfConfig::get('sf_admin_web_dir').'/images/next.png', "style=\"border: 0\" onclick=\"double_list_move(\$('{$name1}'), \$('{$name2}')); return false;\""), + submit_image_tag(sfConfig::get('sf_admin_web_dir').'/images/previous.png', "style=\"border: 0\" onclick=\"double_list_move(\$('{$name2}'), \$('{$name1}')); return false;\""), + $label_assoc, + $select2 + ); +} + + diff --git a/apps/reaktor/lib/helper/homeHelper.php b/apps/reaktor/lib/helper/homeHelper.php new file mode 100644 index 0000000..e6998c8 --- /dev/null +++ b/apps/reaktor/lib/helper/homeHelper.php @@ -0,0 +1,139 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + /** + * Show score using images. + * Make sure we cannot display more then the maximum score set in the config + * files. Note that changing the max score could break the styling. + * + * @param integer $score + * @return string html for displaying imagescores + */ + function showScore($score) + { + $buf = ""; + $max_score = sfConfig::get('app_artwork_max_score', 6); + + $score = $score > $max_score ? $max_score : $score; + + + // Whole numbers (0-9) + $full = $score % 10; + + if ($full > 0) + { + $buf = str_repeat(mkscore("propellhel.gif"), $full); + } + // Max score, no need to continue + if ($full == $max_score) + { + return $buf; + } + + // OK. Now we have done the full images, time to figure out how many 1/3rds + // we have + $left = $score - $full; + + if ($left > 0.84) + { + $buf .= mkscore("propellhel.gif"); + } + elseif ($left > 0.5) + { + $buf .= mkscore("propell2.gif"); + } + elseif ($left > 0.16) + { + $buf .= mkscore("propell1.gif"); + } + + // Append empty images if needed + if ($score < $max_score) + { + $buf .= str_repeat(mkscore("propellgraa.gif"), $max_score-ceil($score)); + } + + return $buf; + } + + /** + * Little helper to print score images + * + * @param mixed $img + * @return string + */ + function mkscore($img) + { + return '
' . image_tag($img) . '
'; + } + + + /** + * Show score using images.This function pads with gray images + * + * @param integer $score + * @return string html for displaying imagescores + */ +/* function showScorePadded($score) + { + $buf = ""; + $max_score = sfConfig::get('app_artwork_max_score', 6); + $score = $score>$max_score ? $max_score : $score; + $buf .= '
  • '; + $buf .= '
'; + return $buf; + } + */ + + function showScorePadded($score) + { + $buf = ""; + $max_score = sfConfig::get('app_artwork_max_score', 6); + + $score = $score > $max_score ? $max_score : $score; + + $buf .= '
    '; + for ($i = $score ; $i > 0 ; $i--) + { + $buf .= '
  • '; + switch (true) + { + case ($i > 0.84): + $buf .= image_tag('reaktor_full_blue.gif'); + break; + case ($i > 0.5): + $buf .= image_tag('reaktor_bottom_grey.gif'); + break; + case ($i > 0.16): + $buf .= image_tag('reaktor_bottom_right_grey.gif'); + break; + default: + $buf .= image_tag('reaktor_grey.gif'); + } + $max_score--; + //$buf .= $i==0.5?image_tag("propellhalv.gif", array()):image_tag("propellhel.gif", array()); + $buf .= '
  • '; + } + while ($max_score > 0) + { + $buf .= '
  • '; + $buf .= image_tag('reaktor_grey.gif'); + $buf .= '
  • '; + $max_score--; + } + + $buf .= '
'; + + return $buf; + + } +?> diff --git a/apps/reaktor/lib/helper/m2mCheckBoxHelper.php b/apps/reaktor/lib/helper/m2mCheckBoxHelper.php new file mode 100644 index 0000000..cbafb8e --- /dev/null +++ b/apps/reaktor/lib/helper/m2mCheckBoxHelper.php @@ -0,0 +1,54 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + + + +/** + * Accepts a container of objects, the method name to use for the value, + * and the method name to use for the display. + * It returns a string of option tags. + * + * @param object $options + * @param string $value_method + * @param string $text_method + * @param array $selected + * @return unknown + */ +function items_for_select($options = array(), $value_method, $text_method = null, $selected = array()) +{ + $select_options = array(); + foreach ($options as $option) + { + // text method exists? + if ($text_method && !is_callable(array($option, $text_method))) + { + $error = sprintf('Method "%s" doesn\'t exist for object of class "%s"', $text_method, _get_class_decorated($option)); + throw new sfViewException($error); + } + + // value method exists? + if (!is_callable(array($option, $value_method))) + { + $error = sprintf('Method "%s" doesn\'t exist for object of class "%s"', $value_method, _get_class_decorated($option)); + throw new sfViewException($error); + } + + $value = $option->$value_method(); + $key = ($text_method != null) ? $option->$text_method() : $value; + + $select_options[$value] = $key; + } + + return $select_options; +} + + diff --git a/apps/reaktor/lib/helper/reportHistoryHelper.php b/apps/reaktor/lib/helper/reportHistoryHelper.php new file mode 100644 index 0000000..3117e54 --- /dev/null +++ b/apps/reaktor/lib/helper/reportHistoryHelper.php @@ -0,0 +1,31 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + * + */ + +function displayReportHistory($historyArray = array(), $tooltipFormat = true) +{ + $block = "
"; + foreach($historyArray as $aHistoryRow) + { + $block .= ""; + $block .= ""; + $block .= ""; + $block .= ""; + } + $block .= "
".$aHistoryRow->getSfGuardUser()->getUserName()."(".date("d/m/Y H:i", strtotime($aHistoryRow->getCreatedAt())).")
"; + + if ($tooltipFormat) + { + $block = str_replace("'", "\\'", $block); + } + + return $block; +} \ No newline at end of file diff --git a/apps/reaktor/lib/helper/secondsHelper.php b/apps/reaktor/lib/helper/secondsHelper.php new file mode 100644 index 0000000..838d5e9 --- /dev/null +++ b/apps/reaktor/lib/helper/secondsHelper.php @@ -0,0 +1,44 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +function format_duration($seconds) { + + $periods = array( + 'centuries' => 3155692600, + 'decades' => 315569260, + 'years' => 31556926, + 'months' => 2629743, + 'weeks' => 604800, + 'days' => 86400, + 'hours' => 3600, + 'minutes' => 60, + 'seconds' => 1 + ); + + $durations = array(); + + foreach ($periods as $period => $seconds_in_period) { + if ($seconds >= $seconds_in_period) { + $durations[$period] = floor($seconds / $seconds_in_period); + $seconds -= $durations[$period] * $seconds_in_period; + } + else + { + $durations[$period] = 0; + } + } + + return $durations; + +} + +?> diff --git a/apps/reaktor/lib/helper/sfRatingHelper.php b/apps/reaktor/lib/helper/sfRatingHelper.php new file mode 100644 index 0000000..979495b --- /dev/null +++ b/apps/reaktor/lib/helper/sfRatingHelper.php @@ -0,0 +1,123 @@ + + */ +sfLoader::loadHelpers(array('Javascript', 'Tag', 'I18N')); + +$response = sfContext::getInstance()->getResponse(); + +$css = 'sf_rating'; +$response->addStylesheet($css, '', array("media" => "all")); + +$js = 'prototype'; +$response->addJavascript($js); + +/** + * Return the HTML code for a unordered list showing rating stars + * + * @param BaseObject $object Propel object instance + * @param array $options Array of HTML options to apply on the HTML list + * @throws sfPropelActAsRatableException + * @return string + **/ +function sf_rater($object, $options = array()) +{ + if (is_null($object)) + { + sfLogger::getInstance()->debug('A NULL object cannot be rated'); + } + + if (!isset($options['star-width'])) + { + $star_width = sfConfig::get('app_rating_star_width', 25); + } + else + { + $star_width = $options['star-width']; + unset($options['star-width']); + } + + try + { + $max_rating = $object->getMaxRating(); + $actual_rating = $object->getRating(); + $bar_width = floor($actual_rating) * $star_width; + $rest = ($actual_rating - floor($actual_rating)); + + $options = _parse_attributes($options); + if (!isset($options['class'])) + { + $options = array_merge($options, array('class' => 'star-rating')); + } + if (!isset($options['style']) or !preg_match('/width:/i', $options['style'])) + { + $full_bar_width = $max_rating * $star_width; + $options = array_merge($options, + array('style' => 'width:'.$full_bar_width.'px')); + } + + if ($object instanceof sfOutputEscaperObjectDecorator) + { + $object_class = get_class($object->getRawValue()); + } + else + { + $object_class = get_class($object); + } + $object_id = $object->getReferenceKey(); + $token = sfPropelActAsRatableBehaviorToolkit::addTokenToSession($object_class, $object_id); + + $msg_domid = sprintf('rating_message_%s', $token) ; + $bar_domid = sprintf('current_rating_%s', $token) ; + + if( $rest > 0.84 ) //Rest is enough to fill three reaktor blades = a whole reaktor blade + { + $bar_width += (1 * $star_width); + $list_content = '
  • '; + } + else //Rest eqals 0, 1 or 2 reaktor blades + { + $list_content = '
  • '; + if ( $rest > 0.16 && $rest <= 0.5 ) //Rest equals one blade + { + $list_content .= '
  • '; + $list_content .= ' '; + } + else if ( $rest > 0.5 && $rest <= 0.84) //Rest equals two blades + { + $list_content .= ' '; + $list_content .= '
  • '; + } + } + + $list_content .= ' '; + + for ($i=1; $i <= $max_rating; $i++) + { + $label = __('Rate it %number_of_stars% stars', array('%number_of_stars%' => $i)); + $list_content .= + '
  • '.link_to_remote($label, + array('url' => sprintf('sfRating/rate?token=%s&rating=%d&star_width=%d', + $token, + $i, + $star_width), + 'update' => $msg_domid, + 'script' => true, + 'complete' => visual_effect('appear', $msg_domid). + visual_effect('highlight', $msg_domid)), + array('class' => 'r'.$i.'stars', + 'title' => $label)).'
  • '; + } + + return content_tag('ul', $list_content, $options). + content_tag('div', __('Click the symbols to vote'), array('id' => $msg_domid, 'class' => 'clearboth')); + } + catch (Exception $e) + { + sfLogger::getInstance()->err('Exception catched from sf_rater helper: '.$e->getMessage()); + } +} diff --git a/apps/reaktor/lib/helper/stringHelper.php b/apps/reaktor/lib/helper/stringHelper.php new file mode 100644 index 0000000..8948562 --- /dev/null +++ b/apps/reaktor/lib/helper/stringHelper.php @@ -0,0 +1,36 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +function getThumbNameFromFile($fileName){ + $ptch=pathinfo($fileName); +return $ptch['filename'].'.jpg'; +} + +/** + * cut string, and add trailing '...'. + * + * @param string $str is the string to be cutted + * @param int $len is the length before the string is cutted + * @param bool $trailingDots should the function add trailing dots (optional, defailt=true) + * @return string the generated path to file (e.g. /content/1/myimage.jpg) + */ + + +function stringCut($str, $len, $trailingDots = true) +{ + if (mb_strlen($str, 'UTF-8') > $len) + return substr($str, 0, $len).(($trailingDots) ? "..." : ""); + else + return $str; +} + +?> diff --git a/apps/reaktor/lib/helper/subreaktorHelper.php b/apps/reaktor/lib/helper/subreaktorHelper.php new file mode 100644 index 0000000..7ba23ac --- /dev/null +++ b/apps/reaktor/lib/helper/subreaktorHelper.php @@ -0,0 +1,36 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +function reaktor_url_for($internal_uri, $absolute = false) +{ + $internal_uri = Subreaktor::addSubreaktorToRoute($internal_uri); + return url_for($internal_uri, $absolute); +} + +function reaktor_link_to($name = '', $internal_uri = '', $options = array()) +{ + $internal_uri = Subreaktor::addSubreaktorToRoute($internal_uri); + return link_to($name, $internal_uri, $options); +} + +function reaktor_button_to($name = '', $internal_uri = '', $options = array()) +{ + $internal_uri = Subreaktor::addSubreaktorToRoute($internal_uri); + return button_to($name, $internal_uri, $options); +} + +function reaktor_form_tag($internal_uri = '', $options = array()) +{ + $internal_uri = Subreaktor::addSubreaktorToRoute($internal_uri); + return form_tag($internal_uri, $options); +} + +?> \ No newline at end of file diff --git a/apps/reaktor/lib/helper/waiHelper.php b/apps/reaktor/lib/helper/waiHelper.php new file mode 100644 index 0000000..449c8e0 --- /dev/null +++ b/apps/reaktor/lib/helper/waiHelper.php @@ -0,0 +1,22 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Resize and move image maintaining aspect ratio + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class imageResize +{ + /** + * Main class constructor + * + * @param string $postImage location of image + * @param string $newFile file to be created + * @param int $maxWidth maximum allowed image width + * @param int $maxHeight maximum allowed image height + * + * @return null + */ + function __construct($postImage, $newFile, $maxWidth = 10000, $maxHeight = 10000, $forceSize = false ) + { + $this->originalFile = $postImage; + $this->newFile = $newFile; + + if (!$picInfo = @getimagesize($this->originalFile)) + { + throw new Exception ("Reading the image ($postImage) failed"); + } + + $width = $picInfo[0]; + $height = $picInfo[1]; + $mime = $picInfo["mime"]; + + if ($width > $maxWidth && $height <= $maxHeight ) + { + $this->ratio = $maxWidth / $width; + } + elseif ($height > $maxHeight && $width <= $maxWidth ) + { + $this->ratio = $maxHeight / $height; + } + elseif ($width > $maxWidth && $height > $maxHeight ) + { + $ratio1 = $maxWidth / $width; + $ratio2 = $maxHeight / $height; + $this->ratio = $ratio1 < $ratio2 ? $ratio1 : $ratio2; + } + else + { + $this->ratio = 1; + } + + $this->nWidth = floor($width * $this->ratio); + $this->nHeight = floor($height * $this->ratio); + + if (!$forceSize) + { + $this->force = false; + } + else + { + $difference = floor(intval($this->nWidth - $this->nHeight)); + $this->nWidth += $difference; + $this->nHeight += $difference; + + if ($this->nWidth < $maxWidth) + { + $widthDifference = floor($maxWidth - $this->nWidth); + $this->nWidth += $widthDifference; + $this->nHeight += $widthDifference; + } + + if ($this->nHeight < $maxHeight) + { + $heightDifference = floor($maxHeight - $this->nHeight); + $this->nWidth += $heightDifference; + $this->nHeight += $heightDifference; + } + + $this->forceWidth = $maxWidth; + $this->forceHeight = $maxHeight; + $this->force = true; + } + } + + /** + * convert and write the image to disk + * + * @return null - image is written to disk + */ + public function imageWrite() + { + // Send to imagemagick for resizing + // ZOID: Needs some error checking & QC, should also check mime in db + /* + * Bugfix for #21554: Major: Gif-animation does not play + * @author Robert Strind + * + * Try first to find out if this is a gif file we are resizing + * If that is the case add coalesce parameter to the convert command. + * + * This fix does not adress cropped files. + * + * Fully define the look of each frame of an GIF animation sequence, to form + * a 'film strip' animation. + * + * This will not affect gifs that are not animated. + */ + $coalesce = ''; + + if (class_exists('Transcoder')) { + $transcoder = new Transcoder(); + $mimetype = $transcoder->getFileType2($this->originalFile); + if( $mimetype == 'image/gif' ) { + $coalesce = ' -coalesce'; + } + } + $command = "convert ".$this->originalFile.$coalesce." -resize ".$this->nWidth."x".$this->nHeight."! ".$this->newFile." 2>&1"; + + exec($command, &$result, &$returnVal); + + if ($this->force) + { + $command = "convert ".$this->newFile." -gravity center -crop ".$this->forceWidth."x".$this->forceHeight."+0+0 ".$this->newFile." 2>&1"; + exec($command, &$result2, &$returnVal2); + } + + if ($returnVal != 0 || !file_exists($this->newFile)) + { + if (sfContext::getInstance()->getUser()->hasCredential("debug")) + { + $extra = $result[0]; + } + else + { + $extra = ""; + } + throw new Exception("Writing the new image failed ".$extra); + } + } +} diff --git a/apps/reaktor/lib/myArtworkTitleValidator.class.php b/apps/reaktor/lib/myArtworkTitleValidator.class.php new file mode 100644 index 0000000..acfb542 --- /dev/null +++ b/apps/reaktor/lib/myArtworkTitleValidator.class.php @@ -0,0 +1,87 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Validator for Artwork titles + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class myArtworkTitleValidator extends sfValidator +{ + /** + * Validator looking for URL on each line of text field + * + * @param mixed &$value Pointer to the value to validate + * @param string &$error Pointer to the error + * + * @return boolean + */ + public function execute (&$value, &$error) + { + if (mb_strlen($value, 'UTF-8') > $this->getParameterHolder()->get('max_length')) + { + $error = $this->getParameterHolder()->get('max_length_error'); + return false; + } + + if (mb_strlen($value, 'UTF-8') < $this->getParameterHolder()->get('min_length')) + { + $error = $this->getParameterHolder()->get('min_length_error'); + return false; + } + + + if (preg_match("/[^".$this->getParameterHolder()->get("valid_chars")."]/i", $value)) + { + $error = $this->getParameterHolder()->get('invalid_error'); + return false; + } + + return true; + } + + /** + * Initializes the validator + * + * @param unknown_type $context Context + * @param unknown_type $parameters Parameters + * + * @return boolean + */ + public function initialize ($context, $parameters = null) + { + // Initialize parent + parent::initialize($context); + + // Set default parameters value (in case yml is missing) + $minError = $this->getContext()->getI18n()->__('Please enter at least %1% characters', array("%1%" => sfConfig::get('app_artwork_min_title_length', 3))); + $maxError = $this->getContext()->getI18n()->__('Please enter less than %1% characters', array("%1%" => sfConfig::get('app_artwork_max_title_length', 40))); + + $this->setParameter('invalid_error', 'Title contains invalid characters'); + $this->setParameter('min_length_error', $minError); + $this->setParameter('max_length_error', $maxError); + + $this->setParameter("valid_chars", sfConfig::get('app_artwork_valid_title_chars', 'a-z0-9-_\søåæäöØÅÆÖÄ!?\'"')); + $this->setParameter('max_length', sfConfig::get('app_artwork_max_title_length', 40)); + $this->setParameter('min_length', sfConfig::get('app_artwork_min_title_length', 3)); + + // Set parameters + $this->getParameterHolder()->add($parameters); + + return true; + } +} diff --git a/apps/reaktor/lib/myMagickArrayValidator.class.php b/apps/reaktor/lib/myMagickArrayValidator.class.php new file mode 100644 index 0000000..1ea7ceb --- /dev/null +++ b/apps/reaktor/lib/myMagickArrayValidator.class.php @@ -0,0 +1,59 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +class myMagickArrayValidator extends sfValidator { + + public function execute(&$value, &$error) + { + if(!is_array($value)) + { + // Wrong type + $error = $this->getParameterHolder()->get('type_error'); + return false; + } + + $min = $this->getParameterHolder()->get('min'); + if($min !== null && count($value) < $min) + { + // Array too small + $error = $this->getParameterHolder()->get('min_error'); + return false; + } + + $max = $this->getParameterHolder()->get('max'); + if($max !== null && count($value) > $max) + { + // Array too large + $error = $this->getParameterHolder()->get('max_error'); + return false; + } + return true; + } + + public function initialize($context, $parameters = null) + { + // Initialize parent + parent::initialize($context); + + // Set default parameters value + $this->setParameter('min', null); + $this->setParameter('min_error', 'Insufficient elements checked.'); + $this->setParameter('max', null); + $this->setParameter('max_error', 'Too many elements checked.'); + $this->setParameter('type_error', 'Wrong type.'); + + // Set parameters + $this->getParameterHolder()->add($parameters); + + return true; + } +} +?> \ No newline at end of file diff --git a/apps/reaktor/lib/myMagickDateValidator.class.php b/apps/reaktor/lib/myMagickDateValidator.class.php new file mode 100644 index 0000000..e324824 --- /dev/null +++ b/apps/reaktor/lib/myMagickDateValidator.class.php @@ -0,0 +1,73 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * Same as above + * + * @author Daniel Andre Eikeland + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +class myMagickDateValidator extends sfDateValidator +{ + /** + * Validates value and provides error + * + * @param mixed &$value Pointer to the value to validate + * @param string &$error Pointer to the error + * + * @return boolean + */ + public function execute (&$value, &$error) + { + if (!isset($value['day'], $value['month'], $value['year']) || !$value['day'] || !$value['month'] || !$value['year']) + { + $error = parent::getParameter('date_incomplete'); + return false; + } + + //this check only works if year is between 1901 and 2038. On some machines the lower range is 1970. + //See php.net mktime for more information. + $var_dob = $value['day'] . '/' . $value['month'] . '/' . $value['year']; + $chk_dob = date('j/n/Y', mktime(0, 0, 1, $value['month'], $value['day'], $value['year'])); + + if ($var_dob == $chk_dob) + { + $value = $var_dob; + return true; + } + $error = parent::getParameter('date_error'); + return false; + } + + /** + * Initializes the validator + * + * @param unknown_type $context Context + * @param unknown_type $parameters Parameters + * + * @return boolean + */ + public function initialize ($context, $parameters = null) + { + // Initialize parent + parent::initialize($context); + + // Set default parameters value + $this->setParameter('date_error', 'This date is not valid'); + + // Set parameters + $this->getParameterHolder()->add($parameters); + + return true; + } +} diff --git a/apps/reaktor/lib/myMagickWorkingRegexValidator.class.php b/apps/reaktor/lib/myMagickWorkingRegexValidator.class.php new file mode 100644 index 0000000..2cd57ae --- /dev/null +++ b/apps/reaktor/lib/myMagickWorkingRegexValidator.class.php @@ -0,0 +1,39 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +class myMagickWorkingRegexValidator extends sfValidator { + + public function execute(&$value, &$error) + { + preg_match($this->getParameterHolder()->get('pattern'), $value, $matches); + if (strlen($matches[0]) != strlen($value) || strtolower($this->getParameterHolder()->get('match')) == 'no') + { + $error = $this->getParameterHolder()->get('match_error'); + return false; + } + else + { + return true; + } + } + + public function initialize($context, $parameters = null) + { + // Initialize parent + parent::initialize($context); + + // Set parameters + $this->getParameterHolder()->add($parameters); + + return true; + } +} +?> \ No newline at end of file diff --git a/apps/reaktor/lib/myPasswordValidator.class.php b/apps/reaktor/lib/myPasswordValidator.class.php new file mode 100644 index 0000000..6241486 --- /dev/null +++ b/apps/reaktor/lib/myPasswordValidator.class.php @@ -0,0 +1,107 @@ + + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class myPasswordValidator extends sfValidator +{ + /** + * Executes this validator. + * + * @param mixed A parameter value + * @param error An error message reference + * + * @return bool true, if this validator executes successfully, otherwise false + */ + public function execute(&$value, &$error) + { + $decodedValue = sfToolkit::isUTF8($value) && function_exists('utf8_decode') ? utf8_decode($value) : $value; + + $min = $this->getParameterHolder()->get('min'); + if ($min !== null && strlen($decodedValue) < $min) + { + // too short + $error = $this->getParameterHolder()->get('min_error'); + + return false; + } + + $max = $this->getParameterHolder()->get('max'); + if ($max !== null && strlen($decodedValue) > $max) + { + // too long + $error = $this->getParameterHolder()->get('max_error'); + + return false; + } + + $values = $this->getParameterHolder()->get('values'); + if ($values !== null) + { + if ($this->getParameterHolder()->get('insensitive')) + { + $value = strtolower($value); + $found = false; + foreach ($values as $avalue) + { + if ($value == strtolower($avalue)) + { + $found = true; + break; + } + } + if (!$found) + { + // can't find a match + $error = $this->getParameterHolder()->get('values_error'); + + return false; + } + } + else + { + if (!in_array($value, (array) $values)) + { + // can't find a match + $error = $this->getParameterHolder()->get('values_error'); + + return false; + } + } + } + + return true; + } + + /** + * Initializes this validator. + * + * @param sfContext The current application context + * @param array An associative array of initialization parameters + * + * @return bool true, if initialization completes successfully, otherwise false + */ + public function initialize($context, $parameters = null) + { + // initialize parent + parent::initialize($context); + + // set defaults + $this->getParameterHolder()->set('insensitive', false); + $this->getParameterHolder()->set('max', null); + $this->getParameterHolder()->set('max_error', 'Input is too long'); + $this->getParameterHolder()->set('min', null); + $this->getParameterHolder()->set('min_error', 'Input is too short'); + $this->getParameterHolder()->set('values', null); + $this->getParameterHolder()->set('values_error', 'Invalid selection'); + + $this->getParameterHolder()->add($parameters); + + return true; + } +} diff --git a/apps/reaktor/lib/myUser.class.php b/apps/reaktor/lib/myUser.class.php new file mode 100644 index 0000000..026f077 --- /dev/null +++ b/apps/reaktor/lib/myUser.class.php @@ -0,0 +1,90 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * This is the basic class for the user management class built into Symfony + * + * This class will probably not be used as we plan to use the extended features of the enhanced security module, + * but this does not mean it can be deleted. It is referenced in symfony/user/sfUser.class.php on line 107. + * + * PHP version 5 + * + * @author Symfony auto-generated code + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class myUser extends sfGuardSecurityUser +{ + /** + * Return the number of artworks this user has submitted + * + * @param string $type The type to filter by + * + * @return integer number of artworks + */ + public function getArtworkCount($type = null) + { + return ReaktorArtworkPeer::countUserArtworks($this, $type); + } + + /** + * Return the user ID or false if not authed + * + * @return unknown + */ + public function getId() + { + if ($this->isAuthenticated()) + { + return $this->getGuardUser()->getId(); + } + return false; + } + + /** + * Get the full name of the current user culture + * + * @return string The culture name + */ + public function getCultureName() + { + $c = new Criteria(); + $c->add(CataloguePeer::TARGET_LANG, $this->getCulture()); + + $catalogueRow = CataloguePeer::doSelectOne($c); + + if ($catalogueRow) + { + return $catalogueRow->getDescription(); + } + } + + /** + * Adding some functionality to the plugin signin function, need to set the reaktor login timestamp + * Will be useful for seeing which users from the Prototype have used the new Reaktor, and when they came + * + * @param myUser $user The user object that has just signed in + * @param boolean $remember Whethe the remember me checkbox was checked (or from cookie etc) + * @param criteria $con Extra criteria to pass to the save function + */ + public function signIn($user, $remember = false, $con = null) + { + if (!$user->getFirstReaktorLogin()) + { + $user->setFirstReaktorLogin(time()); + } + parent::signIn($user, $remember, $con); + } +} \ No newline at end of file diff --git a/apps/reaktor/lib/reaktor.class.php b/apps/reaktor/lib/reaktor.class.php new file mode 100644 index 0000000..8d62b58 --- /dev/null +++ b/apps/reaktor/lib/reaktor.class.php @@ -0,0 +1,42 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +class reaktor +{ + /** + * Set the page title in for the browser, you should do any translation operations before calling this function + * + * @param string $extraTitle appended after the site title and default seperator + */ + public static function setReaktorTitle($extraTitle) + { + $currentTitle = sfConfig::get("app_site_title"); + + $seperator = sfConfig::get("app_title_seperator", " ~ "); + $newTitle = $currentTitle.$seperator.$extraTitle; + + sfContext::getInstance()->getResponse()->setTitle($newTitle); + } + + /** + * Function to add javascript that will be loaded in the footer template + * Useful when accessing dom elements that appear later in the loading process than the template you are working on + * + * @param string $js The javascript you want to add + */ + public static function addJsToFooter($js) + { + $footerJs = sfContext::getInstance()->getRequest()->getAttribute('footer_js', array()); + $footerJs[] = $js; + sfContext::getInstance()->getRequest()->setAttribute('footer_js', $footerJs); + } +} \ No newline at end of file diff --git a/apps/reaktor/lib/reaktorCache.class.php b/apps/reaktor/lib/reaktorCache.class.php new file mode 100644 index 0000000..94ec78c --- /dev/null +++ b/apps/reaktor/lib/reaktorCache.class.php @@ -0,0 +1,198 @@ +shouldUpdate = false; + unset(self::$_instance[$key]); + $retval = true; + } + + if (self::$APC || self::$APC == null) + { + if (function_exists("apc_delete")) + { + apc_delete(sfProcessCache::getPrefix().$key); + } + $retval = true; + } + return $retval; + } + + /** + * Deletes items from the cache similar to $key + * + * @param string $key reaktorCache key + * @return integer The deleted key count + */ + public static function deleteSimilar($key) + { + if (self::$APC == false) + { + return false; + } + + $keys = array(); + $cached_keys = @apc_cache_info('user'); + if (!is_array($cached_keys)) { return false;} // To avoid functional test fails + foreach ($cached_keys['cache_list'] as $i => $ck) + { + if (strpos($ck['info'], $key) !== false) + { + $keys[] = substr($ck['info'], strpos($ck['info'], '_') + 1); + } + } + + $retval = 0; + foreach ($keys as $retval => $key) + { + self::delete($key); + ++$retval; + } + return $retval; + } + + /** + * Constructs the reaktorCache object + * + * @param mixed $key + * @param sfComponents $that + * @return void + */ + private function __construct($key, sfComponents $that = null) + { + $this->key = $key; + $this->that = $that; + + + $this->local = (self::$APC ? + sfProcessCache::get($key) : + ($that = $this->that && $that->hasFlash($key) ? + $that->getFlash($key) : + null + ) + ); + $this->shouldUpdate = ! (bool) $this->local; + } + + /** + * Retrieves the cached item + * + * @return mixed + */ + public function get() + { + return $this->local; + } + + /** + * Throws $local into in-memory cache + * NOTE: You cannot overwrite the previous cache + * + * @param mixed $local + * @param int $lifetime + * @return void + */ + public function set($local, $lifetime = self::DEFAULT_LIFETIME) + { + $this->lifetime = $lifetime; + + if ($this->shouldUpdate === false) + { + return; + } + + self::$APC ? sfProcessCache::set($this->key, $local, $lifetime) : ($that = $this->that && $that->setFlash($this->key, $local, false)); + $this->local = $local; + } + + /** + * Updates the cache with new values + * + * @param mixed $local + * @param mixed $lifetime + * @return void + */ + public function update($local, $lifetime = self::DEFAULT_LIFETIME) + { + self::$APC ? sfProcessCache::set($this->key, $local, $lifetime) : ($that = $this->that && $that->setFlash($this->key, $local, false)); + $this->local = $local; + } + + /** + * Wether or not updating of the cache is nessicery + * + * @return bool + */ + public function shouldUpdate() + { + return $this->shouldUpdate; + } + + /** + * Updates the lifetime of the cache + * + * @return void + */ + public function __destruct() + { + if ($this->shouldUpdate === false) + { + return; + } + + self::$APC ? + sfProcessCache::set($this->key, $this->local, $this->lifetime) : + ($that = $this->that && $that->setFlash($this->key, $this->local)); + } +} + diff --git a/apps/reaktor/lib/reaktorQuickStorage.php b/apps/reaktor/lib/reaktorQuickStorage.php new file mode 100644 index 0000000..74c00f6 --- /dev/null +++ b/apps/reaktor/lib/reaktorQuickStorage.php @@ -0,0 +1,32 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +class rememberMeFilter extends sfFilter +{ + public function execute ($filterChain) + { + // execute this filter only once, and if the user is not already logged in, and has a cookie set + if ($this->isFirstCall() && !$this->getContext()->getUser()->isAuthenticated()) + { + if ($this->getContext()->getRequest()->getCookie(sfConfig::get('app_sf_guard_plugin_remember_cookie_name', 'sfRemember'))) + { + // See if a user exists with this cookie in the remember database + $c = new Criteria(); + $c->add(sfGuardRememberKeyPeer::REMEMBER_KEY, $this->getContext()->getRequest()->getCookie(sfConfig::get('app_sf_guard_plugin_remember_cookie_name', 'sfRemember'))); + $c->add(sfGuardRememberKeyPeer::IP_ADDRESS, $this->getContext()->getRequest()->getHttpHeader ('addr','remote')); + + if ($resultArray = sfGuardRememberKeyPeer::doSelectJoinsfGuardUser($c)) + { + $resultRow = current($resultArray); + $this->getContext()->getUser()->signIn($resultRow->getSfGuardUser(), true); + } + + // Redirect to admin home page if we are an admin user accessing the default home index + if ($this->getContext()->getUser()->hasCredential('staff') && $this->getContext()->getRequest()->getParameter("module") == "home") + { + $this->getContext()->getController()->redirect($this->getContext()->getController()->genUrl('@admin_home', true)); + } + } + // Check for i18n cookie + if ($lang = $this->getContext()->getRequest()->getCookie(sfConfig::get('app_sf_guard_plugin_lang_cookie_name', 'lang'))) + { + $this->getContext()->getUser()->setCulture($lang); + } + } + // execute next filter + $filterChain->execute(); + } +} \ No newline at end of file diff --git a/apps/reaktor/lib/sfLokalReaktorNameValidator.class.php b/apps/reaktor/lib/sfLokalReaktorNameValidator.class.php new file mode 100644 index 0000000..897e48f --- /dev/null +++ b/apps/reaktor/lib/sfLokalReaktorNameValidator.class.php @@ -0,0 +1,94 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Validator for Artwork titles + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class sfLokalReaktorNameValidator extends sfValidator +{ + /** + * Validator looking for URL on each line of text field + * + * @param mixed &$value Pointer to the value to validate + * @param string &$error Pointer to the error + * + * @return boolean + */ + public function execute (&$value, &$error) + { + sfLoader::loadHelpers("Url"); + $link = null; + + if (strlen($value) > $this->getParameterHolder()->get("max_len")) { + $error = $this->getParameterHolder()->get("max_len_error"); + return false; + } + + $error = $this->getParameterHolder()->get("url_error"); + + try { + // Check if the exact routing exists + $link = url_for("@$value"); + + } catch(sfConfigurationException $ex) { + /* Configuration exception is thrown when url_for() does not find a match, + * which in our case is exactly what we want */ + } catch(sfException $ex) { + /* Thrown when the routing exists, but is missing some components, which + * in our case is very very bad */ + return false; + } + // Now make really sure we have no similar URIs + $yml = sfYaml::load(sfConfig::get('sf_root_dir')."/apps/reaktor/config/routing.yml"); + $val = "/" . strtolower($value) . "/"; + foreach($yml as $route) { + if (strpos($route["url"], $val) !== false) { + return false; + } + } + + /* Check if url_for() did resolve to anything, bad if it did */ + return $link == null; + } + + /** + * Initializes the validator + * + * @param unknown_type $context Context + * @param unknown_type $parameters Parameters + * + * @return boolean + */ + public function initialize ($context, $parameters = null) + { + // Initialize parent + parent::initialize($context); + + $this->setParameter("url_error", "I am sorry but the reference you entered is not available for the moment."); + // The database scheme limits this to 15 chars, so lets be nice and error + // out rather then silently chop of the rest + $this->setParameter("max_len", 15); + $this->setParameter("max_len_error", "The reference URI is limited to 15 characters"); + + // Set parameters + $this->getParameterHolder()->add($parameters); + + return true; + } +} diff --git a/apps/reaktor/lib/stringMagick.class.php b/apps/reaktor/lib/stringMagick.class.php new file mode 100644 index 0000000..0febf10 --- /dev/null +++ b/apps/reaktor/lib/stringMagick.class.php @@ -0,0 +1,159 @@ + + * @author Russ + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @copyright 2008 Linpro + * + */ +class stringMagick +{ + + /** + * Returns random string of $length. + * + * @param integer $length + * @return string $newstring + */ + public static function randomString($length = 5) + { + if (!is_int($length) || $length < 0) { + throw new Exception("Illegal argument"); + } + + // Shuffle the pool + $str = str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'); + // And ones more before announcing the winners + return substr(str_shuffle($str), 0, $length); + } + + /** + * Generates secure salts, useful for "forgotten password" + * + * @return string + */ + public static function generateSalt() + { + return md5(microtime() . uniqid(mt_rand(), true) . implode("", fstat(fopen(__FILE__, 'r')))); + } + + /** + * Return cleaned tag or false if invalid tag + * + * @param string $tag the tag to clean + * @return false|string the clean tag or false if invalid + */ + public static function cleanTag($tag) + { + $tag = mb_strtolower($tag, 'UTF-8'); + $tag = trim(str_replace(array("_", ":"), " ", $tag)); + $tag = str_replace(" ", " ", $tag); + + $returnArray["cleantag"] = $tag; + + if (mb_strlen($tag, 'UTF-8') < sfConfig::get("app_tagging_min_length") || mb_strlen($tag, 'UTF-8') > sfConfig::get("app_tagging_max_length")) + { + if (trim($tag) != '') + { + $returnArray["error"] = sfContext::getInstance()->getI18n()->__( + "The tag \"%tag%\" could not be added. Tags should be between %min_length% and %max_length% characters", + array("%min_length%" => sfConfig::get("app_tagging_min_length"), + "%max_length%" => sfConfig::get("app_tagging_max_length"), + "%tag%" => $tag != "" ? $tag : sfContext::getInstance()->getI18n()->__("Empty tag"))); + } + } + elseif (preg_match("/[^a-z0-9-_\søåæØÅÆäö]/i", $tag)) + { + $returnArray["error"] = sfContext::getInstance()->getI18n()->__( + "%tag% could not be added. Invalid characters were found! Use only numbers, letters, spaces and dashes", + array("%tag%" => $tag)); + } + + return $returnArray; + + } + + /** + * Smart chopping of strings. + * + * Chops $txt at ca $max, on spaces, commans, dots, dashes... + * For optimization reason you can pass the original string + * length as the 3rd parameter. + * + * You can check if the string was chopped or not by passing + * $txt_len and $cut_len (no need to initialize them), and + * compare them afterwards. (Useful to know if you should + * print "read more" links). + * + * NOTE: + * - This function will append the string "[...]" if chopped. + * - The returned string can underflow down to 50% of $max + * - The returned string can overflow 15 chars + * + * + * @param mixed $txt The text to cut + * @param int $max Max strlen + * @param int &$txt_len The string length (optional) + * @param int &$cut_len The string length after cutting (optional) + * @return string The chopped string + */ + public static function chop($txt, $max, &$txt_len = 0, &$cut_len = 0) + { + $cut_len = PHP_INT_MAX; + + if ($txt_len < 1) + { + $txt_len = strlen($txt); + } + if ($txt_len < $max) + { + return $txt; + } + + // Try to find a reasonable cutting point + $cut_len = strcspn($txt, " ,-!?", $max); + $cut_len += $max; + + if ($cut_len > $max+8) + { + // If the cutting poing is way to long, or nonexistent we try again, this + // time with using much lower offset + $half = (int)$max*0.5; + $cut_len = strcspn($txt, " ,.-", $half); + $cut_len += $half; + + if ($cut_len > $max) + { + // Still out-of-bounds? Lets hardcut it to $max then + $cut_len = $max; + } + } + if ($cut_len == $txt_len) + { + return $txt; + } + return substr($txt, 0, $cut_len). '[...]'; + + } + + /** + * Convert a camelcased string to lowercase with underscores + * + * @param string $word + * + * @return string + */ + public static function camelCaseToUnderscores($word) + { + return strtolower(preg_replace( + array('/[^A-Z^a-z^0-9^\/]+/','/([a-z\d])([A-Z])/','/([A-Z]+)([A-Z][a-z])/'), + array('_','\1_\2','\1_\2'), $word)); + } + +} + + diff --git a/apps/reaktor/lib/subreaktorFilter.class.php b/apps/reaktor/lib/subreaktorFilter.class.php new file mode 100644 index 0000000..308497d --- /dev/null +++ b/apps/reaktor/lib/subreaktorFilter.class.php @@ -0,0 +1,43 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +class subreaktorFilter extends sfFilter +{ + public function execute ($filterChain) + { + // execute this filter only once + if ($this->isFirstCall()) + { + sfContext::getInstance()->getRequest()->setAttribute("subreaktor", Subreaktor::getProvidedSubreaktor()); + sfContext::getInstance()->getRequest()->setAttribute("lokalreaktor", Subreaktor::getProvidedLokalreaktor()); + + if (Subreaktor::getProvidedSubreaktor() && !Subreaktor::getProvidedLokalreaktor()) + { + sfContext::getInstance()->getResponse()->setTitle(sfConfig::get("app_site_title")." ".Subreaktor::getProvidedSubreaktor()->getName()); + sfConfig::set("app_site_title", sfConfig::get("app_site_title")." ".Subreaktor::getProvidedSubreaktor()->getName()); + } + elseif (Subreaktor::getProvidedLokalreaktor() && !Subreaktor::getProvidedSubreaktor()) + { + sfContext::getInstance()->getResponse()->setTitle(sfConfig::get("app_site_title")." ".Subreaktor::getProvidedLokalreaktor()->getName()); + sfConfig::set("app_site_title", sfConfig::get("app_site_title")." ".Subreaktor::getProvidedLokalreaktor()->getName()); + } + elseif (Subreaktor::getProvidedLokalreaktor() && Subreaktor::getProvidedSubreaktor()) + { + sfContext::getInstance()->getResponse()->setTitle(sfConfig::get("app_site_title")." ".Subreaktor::getProvidedLokalreaktor()->getName()." (".Subreaktor::getProvidedSubreaktor()->getName().")"); + sfConfig::set("app_site_title", sfConfig::get("app_site_title")." ".Subreaktor::getProvidedLokalreaktor()->getName()." (".Subreaktor::getProvidedSubreaktor()->getName().")"); + } + + } + // execute next filter + $filterChain->execute(); + } +} \ No newline at end of file diff --git a/apps/reaktor/lib/transcode/getcontainertype.sh b/apps/reaktor/lib/transcode/getcontainertype.sh new file mode 100755 index 0000000..fa13052 --- /dev/null +++ b/apps/reaktor/lib/transcode/getcontainertype.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# File identification script +# + +MPLAYER="`type -p mplayer`" +WC="`type -p wc`" + +FILENAME="$1" +FILETYPE="unknown" + +AUDIO_PARAM=" -identify -vo null -ao null -frames 0 \"$FILENAME\" 2> /dev/null |grep ID_AUDIO_ID|$WC -l" +VIDEO_PARAM=" -identify -vo null -ao null -frames 0 \"$FILENAME\" 2> /dev/null |grep ID_VIDEO_ID|$WC -l" + +AUDIO_TEST="`echo \"$MPLAYER $AUDIO_PARAM \"|/bin/bash`" +VIDEO_TEST="`echo \"$MPLAYER $VIDEO_PARAM \"|/bin/bash`" + + +if [ "$AUDIO_TEST" != "0" ]; then + FILETYPE="audio" +fi + + +if [ "$VIDEO_TEST" != "0" ]; then + FILETYPE="video" +fi + +echo $FILETYPE; diff --git a/apps/reaktor/lib/transcode/getgiftype.sh b/apps/reaktor/lib/transcode/getgiftype.sh new file mode 100755 index 0000000..c10cd32 --- /dev/null +++ b/apps/reaktor/lib/transcode/getgiftype.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# File identification script +# + +WC="`type -p wc`" +IDENTIFY="`type -p identify`" + +FILENAME="$1" +MIMETYPE="$2" +FILETYPE="unknown" + + + +GIF_TEST="`echo \"$IDENTIFY \"$FILENAME\" |grep \" GIF\"|$WC -l \"|/bin/bash`" + + + + +if [ $GIF_TEST != "0" ] && [ $GIF_TEST != "1" ]; then +FILETYPE="video" +fi + +if [ $GIF_TEST == "1" ]; then +FILETYPE="image" +fi + + + + + +echo $FILETYPE; + +echo $FILETYPE > /tmp/gtype \ No newline at end of file diff --git a/apps/reaktor/lib/transcode/getmimetype.sh b/apps/reaktor/lib/transcode/getmimetype.sh new file mode 100755 index 0000000..eb82c49 --- /dev/null +++ b/apps/reaktor/lib/transcode/getmimetype.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Mimetype identification script +# +# Please remember to give write permission to apache user to its own home directory +# jus to avoid this message: (gnomevfs-info:20527): libgnomevfs-WARNING **: Unable to create ~/.gnome2 directory: Permission denied +# +# + +gfsinfocmd="`type -p gnomevfs-info`" +awkcmd="`type -p awk`" +grepcmd="`type -p grep`" +tailcmd="`type -p tail`" +filecmd="`type -p file`" + + +FILENAME="$1" +RES=`$gfsinfocmd -s "$FILENAME" |$grepcmd "MIME type"| $tailcmd -c +21 2>/dev/null ` + + +if [ $RES == "application/octet-stream" ]; then +RES=`$filecmd -b -i "$FILENAME" 2>/dev/null ` + +fi + + +echo $RES + diff --git a/apps/reaktor/lib/transcode/transcodeMidi.sh b/apps/reaktor/lib/transcode/transcodeMidi.sh new file mode 100755 index 0000000..0ee66f1 --- /dev/null +++ b/apps/reaktor/lib/transcode/transcodeMidi.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +REALFILE=$3; +TEMPFILE=$REALFILE.temp.wav +TOUCHED=$4.temp.mp3 + +touch $TOUCHED +$1 $3 -Ow -o $TEMPFILE +rm $TOUCHED +$5 $2 $TEMPFILE $4 +rm $TEMPFILE diff --git a/apps/reaktor/lib/transcode/transcodeaudio.sh b/apps/reaktor/lib/transcode/transcodeaudio.sh new file mode 100755 index 0000000..92eac98 --- /dev/null +++ b/apps/reaktor/lib/transcode/transcodeaudio.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +REALFILE=$3; +TEMPFILE=$REALFILE.temp.mp3 + +$1 -map_meta_data infile:outfile -i $2 -acodec mp3 -ar 22050 $TEMPFILE +mv $TEMPFILE $REALFILE diff --git a/apps/reaktor/lib/transcode/transcodevideo.sh b/apps/reaktor/lib/transcode/transcodevideo.sh new file mode 100755 index 0000000..422125c --- /dev/null +++ b/apps/reaktor/lib/transcode/transcodevideo.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +REALFILE=$3; +TEMPFILE=$REALFILE.temp.flv +THUMBFILE=$REALFILE.thumb.jpg + +$1 -map_meta_data infile:outfile -i $2 -acodec mp3 -ab 192000 -ar 44100 $TEMPFILE && \ +$4 -U $TEMPFILE && \ +mv $TEMPFILE $REALFILE + +VLENGTH=`/usr/bin/mplayer -identify $REALFILE -nojoystick -nolirc -nosound -vc dummy -vo null 2>&1| grep ID_LENGTH | sed -e "s/ID_LENGTH=//g"` +LENGTH=`echo $VLENGTH | sed -e 's/\.[0-9]*//g'` +VIDEOLENGTH=`echo $(( $LENGTH / 2))| sed -e 's/\.[0-9]*//g'` +OUTPATH=`echo $REALFILE | sed -e 's/\/[^\/]*$//'` +/usr/bin/mplayer -ss $VIDEOLENGTH -really-quiet -nojoystick -nolirc -nocache -nortc -noautosub -vf scale -nosound -frames 1 -zoom -vo jpeg:outdir=$OUTPATH:quality=100 $REALFILE 2>&1 +mv $OUTPATH/00000001.jpg $THUMBFILE + diff --git a/apps/reaktor/lib/transcoder.class.php b/apps/reaktor/lib/transcoder.class.php new file mode 100644 index 0000000..ded2f73 --- /dev/null +++ b/apps/reaktor/lib/transcoder.class.php @@ -0,0 +1,668 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id:transcoder.php 294 2008-02-21 10:46:58Z russ $ + */ + +/** + * Transcodes media files to format suitable for serving through a + * flash player. + * + * PHP version 5 + * + * @author Kjell-Magne Oierud + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +final class transcoder +{ + + const MIME_CONTENT_TYPE_CATEGORY_VIDEO = 'video'; + const MIME_CONTENT_TYPE_CATEGORY_AUDIO = 'audio'; + + const MIME_CONTENT_TYPE_OGG = 'application/ogg'; + const MIME_CONTENT_TYPE_WAV = 'audio/x-wav'; + const MIME_CONTENT_TYPE_MPEG = 'audio/mpeg'; + + // FIX make below constants into instance variables? + + const TRANSCODE_TMP_DIR = '/tmp'; + + const TRANSCODE_MPLAYER_CMD = '/usr/bin/mplayer'; + const TRANSCODE_LAME_CMD = '/usr/bin/lame'; + const TRANSCODE_FFMPEG_CMD = '/usr/bin/ffmpeg'; + const TRANSCODE_FLVTOOL2_CMD = '/usr/bin/flvtool2'; + const TRANSCODE_TIMIDITY_CMD = '/usr/bin/timidity'; + + /** + * The transcoded files will be stored in subdirectories of this directory. + */ + private $_outputBaseDir; + + /** + * The name of the original file + * + * @var string + */ + private $_originalName; + + /** + * Detecetd mime type to return with the transcoding results + * + * @var string + */ + private $_detectedMime = null; + + /** + * An array of extra info that can be passed to transcoder function + * + * @var array + */ + private $_extraInfo = array(); + + /** + * Constructor + * + * @param string $outputBaseDir The transcoded files will be stored in + * subdirectories of this directory. + */ + function __construct($outputBaseDir = null) + { + if (!$outputBaseDir) + { + $outputBaseDir = sfConfig::get('sf_root_dir')."/".sfConfig::get('app_upload_upload_dir')."/"; + } + + if (!is_dir($outputBaseDir)) + { + throw new Exception("Not a folder"); + } + if (!is_writable($outputBaseDir)) + { + throw new Exception("Can't write to output directory."); + } + + $this->_outputBaseDir = $outputBaseDir; + } + + + /** + * Transcodes a media file + * + * @param string $fileName the full path to the file to be converted + * @param string $newName the name of the transcoded file is + * extracted from this. + * @param array $extraInfo Extra info that may be useful + * + * @return array Filename and mime type of the generated file + */ + function transcode($fileName, $newName, $extraInfo = array()) + { + if (!file_exists($fileName)) + { + throw new Exception("File not found: '$fileName'"); + } + elseif (filesize($fileName) == 0) + { + throw new Exception("Don't know how to transcode an empty file: '$fileName'"); + } + + $this->_extraInfo = $extraInfo; + $this->_originalName = $newName; + $outputFile = $this->_removeDirsAndSuffix($newName); + $mime = $this->_getMime($fileName); + $this->_detectedMime = $mime; + if ($this->_isVideo($fileName, $mime)) + { + return $this->_transcodeVideo($fileName, $this->_outputBaseDir."video/".$outputFile, $mime); + } + else if ($this->_isAudio($fileName, $mime)) + { + return $this->_transcodeAudio($fileName, $this->_outputBaseDir."audio/".$outputFile, $mime); + } + + + throw new Exception("Unrecognised media format: File:".$fileName."
    ". + "TranscoderMime: ".$mime."
    ". + "UploadedMime: ".$this->_extraInfo["suggested_mime"]."
    ". + "ExtraFileDetails: ".$this->_getFileType($fileName)."
    ". + "Extension: ".$this->_getFileSuffix()); + } + + + /** + * Checks if a file is a video. + * + * @param string $fileName name of the file that should be checked + * @param string $mime the mime type + * + * @return bool TRUE if the file is a video file, FALSE otherwise + */ + private function _isVideo($fileName, $mime) + { + +/* return strpos($mime, self::MIME_CONTENT_TYPE_CATEGORY_VIDEO) === 0 + || $this->_isOggTheora($fileName, $mime) + || $this->_isFlv($fileName, $mime) + || $this->_isWmv($fileName); +// Functions _isOggTheora, _isFlv and _isWmv below, are executed to handle backward compatibility (they converts mimeType) - Needs to be improve + +*/ +$this->_isOggTheora($fileName, $mime); +$this->_isFlv($fileName, $mime); +$this->_isWmv($fileName); +//echo $this->_getContainerType($fileName,$mime); +//die(); + return $this->_getContainerType($fileName,$mime)=="video"; + + } + + + /** + * Checks if a file is an audio file. + * + * @param string $fileName name of the file that should be checked + * @param string $mime the mime type + * + * @return bool TRUE if the file is an audio file, FALSE otherwise + */ + private function _isAudio($fileName, $mime) + { + + /*return strpos($mime, self::MIME_CONTENT_TYPE_CATEGORY_AUDIO) === 0 + || $this->_isOggVorbis($fileName, $mime) + || $this->_getContainerType($fileName)=="audio" + || $this->_isWma($fileName); +// Functions _isOggVorbis and _isWma below, are executed to handle backward compatibility (they converts mimeType) - Needs to be improved +*/ + + + $this->_isOggVorbis($fileName, $mime); + $this->_isWma($fileName); +//echo $this->_getContainerType($fileName)=="audio".$this->_isMidi($fileName)."wojak"; + + return $this->_getContainerType($fileName)=="audio" || $this->_isMidi($fileName); + + } + + + /** + * Checks if a file is a flv file. + * + * @param string $fileName name of the file that should be checked + * @param string $mime the mime type + * + * @return bool TRUE if the file is a flv file, FALSE otherwise + */ + private function _isFlv($fileName, $mime) + { + if (strpos($this->_getFileType($fileName), 'Macromedia Flash Video') !== false) + { + $this->_detectedMime = "video/x-flv"; + return true; + } + } + + + /** + * Checks if a file is a Ogg/Theora file + * + * @param string $fileName name of the file that should be checked + * @param string $mime the mime type + * + * @return bool TRUE if the file is an Ogg/Theora file, FALSE otherwise + * FIX + */ + private function _isOggTheora($fileName, $mime) + { + if ($mime == self::MIME_CONTENT_TYPE_OGG + && strpos($this->_getFileType($fileName), 'Theora video') !== false) + { + $this->_detectedMime = "video/ogg-theora"; + return true; + } + } + + + /** + * Checks if a file is a WMV file. + * + * @param string $fileName name of the file that should be checked + * + * @return bool TRUE if the file is a WMV file, FALSE otherwise + */ + private function _isWmv($fileName) + { + if ($this->_isWmx($fileName, 'wmv')) + { + $this->_detectedMime = " audio/x-ms-wmv"; + return; + } + } + + /** + * Checks if a file is a WMA file. + * + * @param string $fileName name of the file that should be checked + * + * @return bool TRUE if the file is a WMV file, FALSE otherwise + */ + private function _isWma($fileName) + { + if ($this->_isWmx($fileName, 'wma')) + { + $this->_detectedMime = "audio/x-ms-wma"; + return true; + } + } + + private function _isMidi($fileName) + { +//$mesg= "_getFileType=".$this->_getFileType($fileName)." strpos_result=". strpos($this->_getFileType($fileName), 'MIDI'); +//sfLoader::loadHelpers(array("Debug")); log_message($mesg); + +if (strpos($this->_getFileType($fileName), 'Standard MIDI data') !== false) + { + + $this->_detectedMime = "audio/midi"; + return true; + } + return false; + } + + /** + * Checks if a file is a WMA or WMV file. Helper for _isWmv() and + * _isWma(). + * + * @param string $fileName name of the file that should be checked + * @param string $type either 'wma' or 'wmv' + * + * @return bool TRUE if the file is a WMV or WMA file, FALSE otherwise + */ + private function _isWmx($fileName, $type) + { + return strpos($this->_getFileType($fileName), 'Microsoft ASF') !== false + && strcasecmp($this->_getFileSuffix(), $type) == 0; + } + + /** + * Checks if a file is Ogg/Vorbis. + * + * @param string $fileName name of the file that should be checked + * @param string $mime the mime type + * + * @return bool TRUE if the file is an Ogg/Vorbis file, FALSE otherwise + */ + private function _isOggVorbis($fileName, $mime) + { + if ($mime == self::MIME_CONTENT_TYPE_OGG + && strpos($this->_getFileType($fileName), 'Vorbis audio') !== false) + { + $this->_detectedMime = "application/ogg"; + return true; + } + } + + + /** + * Removes directories and the suffix from a file name. + * + * @param string $filePath the file name that should be stripped + * + * @return the stripped file name + */ + private function _removeDirsAndSuffix($filePath) + { + $filePath = basename($filePath); + if (strrpos($filePath, '.')) + { + $filePath = substr($filePath, 0, strrpos($filePath, '.')); + } + return $filePath; + } + + + /** + * Returns the suffix part of a file name + * + * @param string $filePath get suffix of this + * + * @return string the suffix or '' (the empty string) if there are + * no suffix + */ + private function _getFileSuffix() + { + if (strrpos($this->_originalName, '.')) + { + return substr($this->_originalName, strrpos($this->_originalName, '.') +1); + } + else + { + return ''; + } + } + + + /** + * Finds the mime type of a file + * + * @param string $fileName name of the file that should be analyzed + * + * @return string the mime type + */ + private function _getMime($fileName) + { + /* Using the unix comand 'file' to get mime type. PHP has a built in + * function for this, mime_content_type(), but it is + * depreciated. Instead you are supposed to use a PECL extension + * 'Fileinfo'. However, that is a bit inconvinient ... */ + $safeFileName = escapeshellarg($fileName); + return trim(exec("file -i -b $safeFileName")); + } + + + + + +function getFileType2($fileName) + { + + $execCommand = sprintf(str_replace("transcoder.class.php", 'transcode/getmimetype.sh', __file__).' %s', escapeshellarg($fileName)); + + +// exec($execCommand); +//if(!file_exists($fileName)) echo "No file!"; + exec($execCommand, $cmdOutput, $exitCode); +//var_dump($cmdOutput); + return trim($cmdOutput[0]); + + } + + + + /** + * Finds the file type of a file + * + * @param string $fileName name of the file that should be analyzed + * + * @return string the file type + */ + private function _getFileType($fileName) + { + $safeFileName = escapeshellarg($fileName); + return trim(exec("file -b $safeFileName")); + +//return $this->getFileType2($fileName); + } + + + + + + + + + /** + * Finds the data type in container + * + * @param string $fileName name of the file that should be analyzed + * + * @return string: audio video unknown + */ + private function _getContainerType($fileName,$mime='') + { + $exitCode = false; +# file_put_contents($outputFilePath.".log",''); + $execCommand = sprintf(str_replace("transcoder.class.php", 'transcode/getcontainertype.sh', __file__).' %s "%s"', + escapeshellarg($fileName),$mime); + + + + exec($execCommand, $cmdOutput, $exitCode); + + + + if ($exitCode !== 0) + { + throw new Exception("Transcode failed!\nTranscode Output:\n" . $exitCode); + } + + + + + return trim($cmdOutput[0]); + } + + + + + + + public function getGifType($fileName) + { + $exitCode = false; +# file_put_contents($outputFilePath.".log",''); + + $execCommand = sprintf(str_replace("transcoder.class.php", 'transcode/getgiftype.sh', __file__).' %s ', + escapeshellarg($fileName)); + + + + exec($execCommand, $cmdOutput, $exitCode); + + + + if ($exitCode !== 0) + { + throw new Exception("Transcode failed!\nTranscode Output:\n" . $exitCode); + } + + + + + return trim($cmdOutput[0]); + } + + + + + + + + + + + + + + /** + * Transcodes a audio file to flv + * + * This function uses ffmpeg for the transcoding. So make shure that + * you have a version with compiled support for mp3. The one that is + * packaged with Ubuntu is not. + * + * You also need flvtool2 which is not packaged for Ubuntu. + * + * @param string $fileName the path to the file to be converted + * @param string $outputFilePath transcoding result goues here (should + * not include the file name suffix) + * @param string $mime the mime type of $file_name + * + * @return array Filename and mime type of the generated file + */ + private function _transcodeVideo($fileName, $outputFilePath, $mime) + { + $outputFilePath .= '.flv'; + + if ($this->_isFlv($fileName, $mime)) + { + // Don't need to transcode FIX should we recode? + // FIX check for errors! + copy($fileName, $outputFilePath); + } + else + { + // FIX Does the -ar param nprint $fileName;eed to be set according to input file? + /*$transcodeCmd = sprintf('%s -map_meta_data infile:outfile -i %s -acodec libmp3lame -ab 192 -ar 44100 %s > /dev/null 2>&1', + self::TRANSCODE_FFMPEG_CMD, + escapeshellarg($fileName), + escapeshellarg($outputFilePath)); + + $flvtoolCmd = sprintf("%s -U %s > /dev/null 2>&1 &", + self::TRANSCODE_FLVTOOL2_CMD, + escapeshellarg($outputFilePath)); + + */; + $exitCode = false; + file_put_contents($outputFilePath.".log",''); + $execCommand = sprintf(str_replace("transcoder.class.php", 'transcode/transcodevideo.sh', __file__).' %s %s %s %s %s > '.$outputFilePath.'.log 2>&1 &', + self::TRANSCODE_FFMPEG_CMD, + escapeshellarg($fileName), + escapeshellarg($outputFilePath), + self::TRANSCODE_FLVTOOL2_CMD, + $mime +); + + + + exec($execCommand, $cmdOutput, $exitCode); + + + + if ($exitCode !== 0) + { + throw new Exception("Transcode failed!\nTranscode Output:\n" . $exitCode); + } + //unset($cmdOutput); + //exec($flvtoolCmd, $cmdOutput, $exitCode); + } + + return array('newFileName' => basename($outputFilePath), + 'convertedMime' => 'video/flv', + 'detectedMime' => $this->_detectedMime, + ); + } + + + /** + * Transcodes a audio file to mp3 + * + * @param string $fileName the file that should be transcoded + * @param string $outputFilePath transcoding result goues here (should + * not include the file name suffix) + * @param string $mime the mime type of $file_name + * + * @return array Filename and mime type of the generated file + */ + private function _transcodeAudio($fileName, $outputFilePath, $mime) + { + $outputFilePath .= '.mp3'; + + if ($mime == self::MIME_CONTENT_TYPE_MPEG) + { + // MP3 - Don't need to transcode FIX should we recode? + // FIX check that it actually is a MPEG-1 Audio Layer 3 file + // FIX check for errors! + copy($fileName, $outputFilePath); + } + // We use mplayer with wma files to dump wav before encoding to mp3 with lame + else //if ($this->_isWma($fileName)) + { + + if ($this->_isMidi($fileName) !== false) + { + $midiToWaveCmd = sprintf(str_replace("transcoder.class.php", 'transcode/transcodeMidi.sh', __file__). " %s %s %s %s %s > /dev/null 2>&1 &", + self::TRANSCODE_TIMIDITY_CMD, + self::TRANSCODE_FFMPEG_CMD, + escapeshellarg($fileName), + escapeshellarg($outputFilePath), + str_replace("transcoder.class.php", 'transcode/transcodeaudio.sh', __file__)); + + exec($midiToWaveCmd, $cmdOutput, $exitCode); + } else + { + $transcodeWmaCommand = sprintf(str_replace("transcoder.class.php", 'transcode/transcodeaudio.sh', __file__).' %s %s %s >/dev/null 2>&1 &', + self::TRANSCODE_FFMPEG_CMD, + escapeshellarg($fileName), + escapeshellarg($outputFilePath)); + //echo $transcodeWmaCommand."

    "; + exec($transcodeWmaCommand, $cmdOutput, $exitCode); + file_put_contents($fileName.".log",$cmdOutput); + } +/*foreach($cmdOutput as $line) + { + echo $line."
    \n"; + } + die();*/ + } + /*else + { + + $pcmFile = $fileName; + $pcmIsTmp = false; + if ($mime != self::MIME_CONTENT_TYPE_WAV) + { + $pcmFile = tempnam(self::TRANSCODE_TMP_DIR, 'transcode'); + $this->_decodeAudio($fileName, $pcmFile); + $pcmIsTmp = true; + } + + $transcodeMp3Cmd = sprintf('%s --quiet --abr 192 %s %s 2>&1', + self::TRANSCODE_LAME_CMD, $pcmFile, + escapeshellarg($outputFilePath)); + + // FIX check for errors! + exec($transcodeMp3Cmd); + + if ($pcmIsTmp) + { + unlink($pcmFile); + } + + }*/ + + return array('newFileName' => basename($outputFilePath), + 'convertedMime' => 'audio/mpeg', + 'detectedMime' => $this->_detectedMime); + } + + + /** + * Decodes an audio file into a PCM WAV file. + * + * @param string $fileName the file that should be decoded + * @param string $outputFileName put result in this file + * + * @return void + */ + private function _decodeAudio($fileName, $outputFileName) + { + if (strpos($this->_getFileType($fileName), 'Standard MIDI data') !== false) + { + $transcodeWavCmd = sprintf('%s -Ow -o %s %s 2>&1', + self::TRANSCODE_TIMIDITY_CMD, $outputFileName, + escapeshellarg($fileName)); + + } + else + { + $transcodeWavCmd = sprintf('/usr/bin/env MPLAYER_VERBOSE=-2 %s -msglevel all=5 -nolirc -nojoystick -vo null -vc null -ao pcm:fast:waveheader:file=%s %s 2>&', + self::TRANSCODE_MPLAYER_CMD, + $outputFileName, + escapeshellarg($fileName)); + + /* MPlayer doesn't seem to give any exit status codes :( */ + } + // FIX check for errors! + exec($transcodeWavCmd); + } +} + diff --git a/apps/reaktor/lib/upload.class.php b/apps/reaktor/lib/upload.class.php new file mode 100644 index 0000000..70227f6 --- /dev/null +++ b/apps/reaktor/lib/upload.class.php @@ -0,0 +1,16 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + + class upload + { + // To come + } \ No newline at end of file diff --git a/apps/reaktor/lib/userFilter.class.php b/apps/reaktor/lib/userFilter.class.php new file mode 100644 index 0000000..d628578 --- /dev/null +++ b/apps/reaktor/lib/userFilter.class.php @@ -0,0 +1,31 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +class userFilter extends sfFilter +{ + public function execute ($filterChain) + { + // execute this filter only once + if ($this->isFirstCall()) + { + if (sfContext::getInstance()->getUser()->isAuthenticated() && !sfConfig::get("admin_mode") + && (sfContext::getInstance()->getModuleName() == 'userContent' || strpos(sfContext::getInstance()->getRequest()->getUri(), '/mypage/') !== false)) + { + sfConfig::set("mypage_mode", true); + sfContext::getInstance()->getResponse()->setTitle(sfConfig::get("app_site_title")." ".sfContext::getInstance()->getI18N()->__("editorial centre")); + sfConfig::set("app_site_title", sfConfig::get("app_site_title")." ".sfContext::getInstance()->getI18N()->__("My page")); + } + } + // execute next filter + $filterChain->execute(); + } +} \ No newline at end of file diff --git a/apps/reaktor/lib/videoFrame.class.php b/apps/reaktor/lib/videoFrame.class.php new file mode 100644 index 0000000..e702f19 --- /dev/null +++ b/apps/reaktor/lib/videoFrame.class.php @@ -0,0 +1,128 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: videoFrame.class.php 3031 2009-02-17 18:46:40Z wojak $ + */ + +/** + * Class that represents a videoFrame + * + * PHP version 5 + * + * @author Kjell-Magne Oierud + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +require_once 'videoInfo.class.php'; + +final class videoFrame +{ + + private $content; + + private $frameOffset; + + private $mime; + + private $sourceFile; + + /** + * Content accessor. + * + * @return string the content of the video frame. + */ + function getContent() + { + return $this->content; + } + + /** + * Mime accessor. + * + * @return string the mime type of the video frame + */ + function getMime() + { + return $this->mime; + } + + + /** + * Creates a videoFrame from a file. + * + * @param string $videoFile the file name of the video + * + * @return videoFrame the newly created + */ + static function fromVideoFile($videoFile,$mime='') + { + if (!file_exists($videoFile)) + { + throw new Exception("File not found: $videoFile"); + } + + $safeFile = escapeshellarg($videoFile); + + $outDir = self::_tempdir('/tmp', 'videoFrame-'); + $outFile = '00000002.jpg'; + + $offset = round(videoInfo::videoLength($videoFile)) / 2; + + $command = "/usr/bin/mplayer -ss $offset -really-quiet -nojoystick -nolirc -nocache -nortc -noautosub -vf scale -nosound -frames 4 -zoom -vo jpeg:outdir=$outDir:quality=100 $safeFile 2>&1"; + //die($command); + exec($command, &$output, &$returnVal); + + $vf = new videoFrame(); + $vf->frameOffset = $offset; + if (!file_exists($outDir.'/'.$outFile)) + { + return false; + } + $vf->content = file_get_contents($outDir.'/'.$outFile); + $vf->mime = 'image/jpeg'; + $vf->sourceFile = $videoFile; + + unlink($outDir.'/'.$outFile); + unlink($outDir.'/00000001.jpg'); + unlink($outDir.'/00000003.jpg'); + unlink($outDir.'/00000004.jpg'); + rmdir($outDir); + + return $vf; + } + + + /** + * Creates a temporary folder with a unique name. + * + * @param string $dir Where to create it + * @param string $prefix Prepend this to the directory name + * @param int $mode Permissions + * + * @return string the name of the folder + */ + private static function _tempdir($dir, $prefix='', $mode=0700) + { + if (substr($dir, -1) != '/') + { + $dir .= '/'; + } + + do + { + $path = $dir.$prefix.mt_rand(0, 9999999); + } + while (!mkdir($path, $mode)); + + return $path; + } + + +} \ No newline at end of file diff --git a/apps/reaktor/lib/videoInfo.class.php b/apps/reaktor/lib/videoInfo.class.php new file mode 100644 index 0000000..5b96fee --- /dev/null +++ b/apps/reaktor/lib/videoInfo.class.php @@ -0,0 +1,51 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id$ + */ + +/** + * Class that extracts meta information from video files + * + * PHP version 5 + * + * @author Kjell-Magne Oierud + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +final class videoInfo +{ + + + /** + * Finds the length of a video + * + * @param string $videoFile the file name of the video + * + * @return float the length of the video in seconds. + */ + public static function videoLength($videoFile) + { + + if (!file_exists($videoFile)) + { + throw new Exception("File not found: $videoFile"); + } + + $pattern = 'ID_LENGTH='; + exec("/usr/bin/mplayer -identify \"$videoFile\" -nojoystick -nolirc -nosound -vc dummy -vo null", $mplayerOut); + $len = preg_grep("/^$pattern/", $mplayerOut); + $len = array_pop($len); + $len = substr($len, strlen($pattern)); + + return $len + 0.0; /* Convert string to float */ + } + + +} \ No newline at end of file diff --git a/apps/reaktor/modules/admin/actions/actions.class.php b/apps/reaktor/modules/admin/actions/actions.class.php new file mode 100644 index 0000000..d36dc45 --- /dev/null +++ b/apps/reaktor/modules/admin/actions/actions.class.php @@ -0,0 +1,930 @@ + + * @author June + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Admin home page + * + * PHP Version 5 + * + * @author Russ Flynn + * @author June + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class adminActions extends sfActions +{ + /** + * Login to PHPMyAdmin with a read only user + * + * @return void + */ + public function executePMA() + { + //Check credentials + $this->forward404Unless($this->getUser()->isAuthenticated()); + $this->forward404Unless($this->getUser()->hasCredential('phpmyadmin')); + + //Get info on db read-only user + $pma_user = sfConfig::get("app_admin_pma_readonly_user"); + $pma_password = sfConfig::get("app_admin_pma_password"); + + // Apparently symfony is highly dependent upon cookies so we don't have to + // do any sanitychecks here as symfony would have already bailed out + if (!isset($_COOKIE["pmaCookieVer"])) { + // phpMyAdmin clears all cookies unless it gets a version cookie + setcookie("pmaCookieVer", "5", null, "/"); + $this->redirect("@pma"); + } + + //Create session info, when logging out these will be deleted + $_SESSION['PMA_single_signon_user'] = $pma_user; + $_SESSION['PMA_single_signon_password'] = $pma_password; + + //get reaktor root from config and redirect to phpmyadmin + $this->redirect('http://'.$this->getRequest()->getHost().'/phpmyadmin/'); + } + + public function executeAdminFunctions() + { + $messages = array(); + $mode = $this->getRequestParameter("mode"); + + if ($mode == "clearhtml" || $mode == "clearall") + { + exec(sfConfig::get("sf_root_dir").DIRECTORY_SEPARATOR."symfony clear-cache reaktor template", &$output, &$returnVar); + if ($returnVar == 0) + { + $messages[] = sfContext::getInstance()->getI18n()->__("Html cache cleared successfully"); + } + else + { + $messages[] = sfContext::getInstance()->getI18n()->__("The command to clear the html cache failed!"); + } + } + if ($mode == "clearconfig" || $mode == "clearall") + { + exec(sfConfig::get("sf_root_dir").DIRECTORY_SEPARATOR."symfony clear-cache reaktor config", &$output, &$returnVar); + if ($returnVar == 0) + { + $messages[] = sfContext::getInstance()->getI18n()->__("Configuration cache cleared successfully"); + } + else + { + $messages[] = sfContext::getInstance()->getI18n()->__("The command to clear the configuration cache failed!"); + } + } + if ($mode == "clearmemory" || $mode == "clearall") + { + sfProcessCache::clear(); + $messages[] = sfContext::getInstance()->getI18n()->__("Memory cache cleared successfully"); + } + $appYmlCacheFile = sfConfig::get("sf_root_dir").DIRECTORY_SEPARATOR."cache".DIRECTORY_SEPARATOR."reaktor".DIRECTORY_SEPARATOR. + "prod".DIRECTORY_SEPARATOR."config".DIRECTORY_SEPARATOR."config_app.yml.php"; + if (file_exists($appYmlCacheFile)) + { + $this->configCacheTimestamp = filemtime($appYmlCacheFile); + } + else + { + // Shouldn't happen, but this will do as a backup + $this->configCacheTimestamp = time(); + } + $this->messages = $messages; + } + + /** + * Executes before the action + * + * @return void + */ + public function preExecute() + { + } + + /** + * Executes index action + * + * @return void + */ + public function executeIndex() + { + $this->editorialteams = array(); + foreach ($this->getUser()->getGuardUser()->getEditorialTeams() as $aTeam) + { + $this->editorialteams[$aTeam->getId()] = $aTeam; + } + if (sfContext::getInstance()->getUser()->hasCredential('viewothereditorialteams')) + { + $this->othereditorialteams = array(); + foreach (sfGuardGroupPeer::getActiveEditorialTeams() as $aTeam) + { + if (!isset($this->editorialteams[$aTeam->getId()])) + { + $this->othereditorialteams[$aTeam->getId()] = $aTeam; + } + } + } + $this->editorialteamartworks = ReaktorArtworkPeer::getNumberofArtworksByEditorialTeam($this->editorialteams, 2, true); + $this->modifiedartworks = ReaktorArtworkPeer::getNumberOfArtworkByStatusAndCredentials(3, $this->getUser()->listCredentials(), null, null, true); + $this->othereditorialteamartworks = ReaktorArtworkPeer::getNumberofArtworksByEditorialTeam($this->othereditorialteams, 2, true); + $this->discussionFiles = ReaktorFilePeer::getNumberofFilesUnderDiscussion(); + $this->discussionArtworks = ReaktorArtworkPeer::getNumberOfArtworksUnderDiscussion(); + $this->reportedfiles = ReaktorFilePeer::getNumberofReportedFiles(); + $this->reportedcomments = sfCommentPeer::getNumberofCommentsByUnsuitableStatus(); + $this->unapprovedtags = TagPeer::getNumberofTagsByApprovedStatus(); + } + + /** + * Show list of artwork flagged for discussion + * + * @return void + */ + public function executeListDiscussion() + { + $this->forward('artwork', 'listDiscussion'); + } + + /** + * Show list of unapproved artwork + * + * @return void + */ + public function executeListUnapproved() + { + $this->forward('artwork', 'listUnapproved'); + } + + /** + * Show list of rejected artwork + * + * @return void + */ + public function executeListRejected() + { + $this->forward('artwork', 'listRejected'); + } + + /** + * Show list of unsuitable files + * + * @return void + */ + public function executeListRejectedFiles() + { + $this->forward('artwork', 'listRejectedFiles'); + } + + /** + * Show list of subreaktors + * + * @return void + */ + public function executeListSubreaktors() + { + $this->forward('subreaktors', 'listSubreaktors'); + } + + /** + * Show list of comments within a time period + * + * @return void + */ + public function executeListComments() + { + $this->forward('sfComment', 'listComments'); + } + + /** + * Show calendar with links to comments + * + * @return void + */ + public function executeCommentsCalendar() + { + $this->forward('sfComment', 'commentsCalendar'); + } + + /** + * Return description of the chosen rejection type, used in ajax call. + * + * @return void + */ + public function executeRejectionTypeChosen() + { + if (!$this->getRequest()->isXmlHttpRequest()) + { + //The user should not be here + die(); + } + $id = $this->getRequestParameter('rejectiontype'); + $rejection_type = $id?RejectionTypePeer::retrieveByPK($id):''; + $output = $rejection_type?$rejection_type->getDescription():''; + return $this->renderText($output); + + } + + /** + * Display list of rejection types + * + * @return forward + */ + public function executeRejectionType() + { + return $this->forward('admin', 'rejectionTypeList'); + } + + /** + * Display list of rejection types + * + * @return void + */ + public function executeRejectionTypeList() + { + $this->rejection_types = RejectionTypePeer::doSelect(new Criteria()); + } + + /** + * Show rejection type and attributes + * + * @return void + */ + public function executeRejectionTypeShow() + { + $this->rejection_type = RejectionTypePeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($this->rejection_type); + } + + /** + * Show rejection type form + * + * @return void + */ + public function executeRejectionTypeCreate() + { + $this->rejection_type = new RejectionType(); + + $this->setTemplate('rejectionTypeEdit'); + } + + /** + * Show rejection type form + * + * @return void + */ + public function executeRejectionTypeEdit() + { + $this->rejection_type = RejectionTypePeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($this->rejection_type); + } + + /** + * Save/update rejection type + * + * @return redirect + */ + public function executeRejectionTypeUpdate() + { + if (!$this->getRequestParameter('id')) + { + $rejection_type = new RejectionType(); + } + else + { + $rejection_type = RejectionTypePeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($rejection_type); + } + + $rejection_type->setId($this->getRequestParameter('id')); + $rejection_type->setName($this->getRequestParameter('name')); + $rejection_type->setDescription($this->getRequestParameter('description')); + + $rejection_type->save(); + + return $this->redirect('@rejectiontypeshow?id='.$rejection_type->getId()); + } + + /** + * Delete entry from rejection type table + * + * @return redirect + */ + public function executeRejectionTypeDelete() + { + $rejection_type = RejectionTypePeer::retrieveByPk($this->getRequestParameter('id')); + + $this->forward404Unless($rejection_type); + + $rejection_type->delete(); + + return $this->redirect('@rejectiontypes'); + } + + /** + * List reported comments + * + * @return void + */ + public function executeListReportedComments() + { + $this->forward('sfComment', 'listReportedComments'); + } + + /** + * List unsuitable comments + * + * @return void + */ + public function executeListUnsuitableComments() + { + $this->forward('sfComment', 'listUnsuitableComments'); + } + + /** + * List artwork where the content has been reported + * + * @return void + */ + public function executeListReportedContent() + { + $this->forward('artwork', 'listReportedContent'); + } + + /** + * List all users who would like to receive promotional e-mails + * + * @return void + */ + public function executeListPromotionalEmailRecipients() + { + $this->emails = sfGuardUserPeer::retrieveOptInEmails(); + } + + /** + * Display list of artwork statuses + * + * @return forward + */ + public function executeArtworkStatus() + { + return $this->forward('admin', 'artworkStatusList'); + } + + /** + * Display list of artwork statuses + * + * @return void + */ + public function executeArtworkStatusList() + { + $this->artwork_statuses = ArtworkStatusPeer::doSelect(new Criteria()); + } + + /** + * Show artwork status form + * + * @return void + */ + public function executeArtworkStatusEdit() + { + $this->artwork_status = ArtworkStatusPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($this->artwork_status); + } + + /** + * Save/update artwork status + * + * @return redirect + */ + public function executeArtworkStatusUpdate() + { + $artwork_status = ArtworkStatusPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($artwork_status); + + $artwork_status->setDescription($this->getRequestParameter('description')); + + $artwork_status->save(); + + return $this->redirect('@artworkstatuses'); + } + + /** + * Display list of artwork statuses + * + * @return forward + */ + public function executeHistoryActions() + { + return $this->forward('admin', 'historyActionList'); + } + + /** + * Display list of artwork statuses + * + * @return void + */ + public function executeHistoryActionList() + { + $this->history_actions = HistoryActionPeer::doSelect(new Criteria()); + } + + /** + * Show artwork status form + * + * @return void + */ + public function executeHistoryActionEdit() + { + $this->history_action = HistoryActionPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($this->history_action); + } + + /** + * Save/update artwork status + * + * @return redirect + */ + public function executeHistoryActionUpdate() + { + $history_action = HistoryActionPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($history_action); + + $history_action->setDescription($this->getRequestParameter('description')); + + $history_action->save(); + + return $this->redirect('@historyactions'); + } + + /** + * Display list of subreaktors + * + * @return forward + */ + public function executeSubreaktorNames() + { + return $this->forward('admin', 'subreaktorNameList'); + } + + /** + * Display list of subreaktors + * + * @return void + */ + public function executeSubreaktorNameList() + { + $this->subreaktor_names = SubreaktorPeer::doSelectWithI18n(new Criteria()); + } + + /** + * List categories for editing + * + * @return void + */ + public function executeCategoryList() + { + $c = new Criteria(); + $c->addAscendingOrderByColumn(CategoryPeer::BASENAME); + $this->categories = CategoryPeer::doSelectWithI18n($c); + } + + /** + * Show subreaktor name edit form + * + * @return void + */ + public function executeSubreaktorNameEdit() + { + $this->edit_subreaktor = SubreaktorPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($this->edit_subreaktor); + } + + /** + * Show the edit category i18n form + * + * @return void render the temlate + */ + public function executeCategoryEdit() + { + // For some reason the correct method for doing this is not working - so the long way round we go + $c = new Criteria(); + $c->add(CategoryPeer::ID, $this->getRequestParameter("id")); + $result = CategoryPeer::doSelectWithI18n($c); + if (!$result) + { + $this->forward404(); + } + $this->edit_category = current($result); + $this->forward404Unless($this->edit_category); + } + + /** + * Execute the category i18n update form + * + * @return void - the success template + */ + public function executeCategoryUpdate() + { + // This is also not working as intended, but ok the long way round + $edit_category = CategoryI18nPeer::retrieveByPK($this->getRequestParameter('id'), $this->getUser()->getCulture()); + $this->forward404Unless($edit_category); + + $edit_category->setName($this->getRequestParameter('name')); + + $edit_category->save(); + + return $this->redirect('@listcategories'); + } + + /** + * Save/update subreaktor name + * + * @return redirect + */ + public function executeSubreaktorNameUpdate() + { + $edit_subreaktor = SubreaktorPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($edit_subreaktor); + + $edit_subreaktor->setName($this->getRequestParameter('name')); + + $edit_subreaktor->save(); + + return $this->redirect('@subreaktornames'); + } + + /** + * List all recommended artworks across the site + * + * @return void + */ + public function executeListRecommended() + { + $this->artworks = array(); + + //Get all the latest recommended artworks in each subreaktor/lokalreaktor + $this->recommended_artworks = RecommendedArtworkPeer::doSelectAllRecommendedArtwork(new Criteria()); + foreach ($this->recommended_artworks as $recommendedartwork) + { + //Create a list of artworks, and where they are recommended + $this->artworks[$recommendedartwork->getId()] = array( + 'artwork' => new genericArtwork($recommendedartwork->getArtwork(), null, array()), + 'subreaktor' => $recommendedartwork->getSubreaktor(), + 'lokalreaktor' => $recommendedartwork->getLocalsubreaktor(), + 'updatedat' => $recommendedartwork->getUpdatedAt(), + ); + } + } + + /** + * List composite artworks + * + * @return null + */ + public function executeListComposite() + { + $this->artworks = array(); + + //Get all the composite artworks + $this->artworks = ReaktorArtworkPeer::getCompositeArtworks(); + } + + + public function executeListApproved() + { + $this->selected_year = ($this->getRequestParameter('year') != '') ? $this->getRequestParameter('year') : date('Y'); + if ($this->getRequestParameter('month') != '') + { + $this->selected_month = $this->getRequestParameter('month'); + } + elseif ($this->getRequestParameter('year') == '') + { + $this->selected_month = date('n'); + } + else + { + $this->selected_month = null; + } + $this->months = array(); + for ($cc = 1; $cc <= 12; $cc++) + { + $count = 0; + $this->months[] = array('month' => $cc, 'artworkcount' => ReaktorArtworkPeer::countArtworksByDateAndStatus(3, $this->selected_year, $cc)); + } + $this->artworks = array(); + $this->page = $this->getRequestParameter('page', 1); + $this->pager = ReaktorArtworkPeer::getArtworksByDateAndStatus(3, $this->selected_year, $this->selected_month); + $this->pager->setPage($this->page); + $this->pager->init(); + foreach ($this->pager->getResults() as $reaktor_artwork) + { + $this->artworks[] = new genericArtwork($reaktor_artwork, null, null); + } + $this->route = '@approvedartwork_month?year='.$this->selected_year.'&month='.$this->selected_month; + } + + public function executeListIgnoredUsers() + { + $this->countlimit = 3; + if ($this->getRequestParameter('min_count') != '') + { + $this->countlimit = $this->getRequestParameter('min_count'); + } + $c = new Criteria(); + $c->clearSelectColumns(); + $c->addSelectColumn(MessagesIgnoredUserPeer::IGNORES_USER_ID); + $c->addSelectColumn(sfGuardUserPeer::USERNAME); + $c->addSelectColumn(sfGuardUserPeer::NAME); + $c->addSelectColumn('count('.MessagesIgnoredUserPeer::IGNORES_USER_ID.') as countusers'); + $c->addDescendingOrderByColumn('countusers'); + $c->addGroupByColumn(MessagesIgnoredUserPeer::IGNORES_USER_ID); + $having = $c->getNewCriterion(MessagesIgnoredUserPeer::IGNORES_USER_ID, ' countusers >= ' . $this->countlimit, Criteria::CUSTOM); + //$having = $c->getNewCriterion(MessagesIgnoredUserPeer::COUNT, $this->countlimit, Criteria::GREATER_EQUAL); + $c->addHaving($having); + $c->addJoin(MessagesIgnoredUserPeer::IGNORES_USER_ID, sfGuardUserPeer::ID); + $res = MessagesIgnoredUserPeer::doSelectRS($c); + + $this->users = array(); + + while ($res->next()) + { + $this->users[$res->getInt(1)] = array('id' => $res->getInt(1), 'username' => $res->getString(2), 'realname' => $res->getString(3), 'count' => $res->getInt(4)); + } + } + + public function executeNewCategory() + { + } + + public function executeEditorialTeams() + { + + $this->forward404Unless( + $this->getUser()->hasCredential('approveartwork') && + // Allow users to modify thier own notifications + ( $this->getUser()->hasCredential('managenotifications') || ($this->getRequestParameter('user_id')==sfContext::getInstance()->getUser()->getGuardUser()->getId() ) ) + ); + + if ($this->getRequest()->isXmlHttpRequest()) + { + $user_id = $this->getRequestParameter('user_id'); + $notify_value = $this->getRequestParameter('notify_value'); + $user = sfGuardUserPeer::retrieveByPK($user_id); + $user->setEditorialNotification($notify_value); + $user->save(); + return $this->renderText(sfcontext::getInstance()->getI18N()->__('Saved successfully!')); + } + $this->teams = sfGuardGroupPeer::getEditorialTeams(false); + if ($this->getRequestParameter('team')) + { + $this->theteam = sfGuardGroupPeer::retrieveByPK($this->getRequestParameter('team')); + $this->members = sfGuardUserGroupPeer::getMembersofEditorialTeam($this->getRequestParameter('team'), true); + } + else + { + $this->members = null; + } + } + + public function executeOnlineNow() + { + $this->onlineCount = sfGuardUserPeer::getOnlineCount(); + $this->usersOnline = sfGuardUserPeer::getOnlineUsers(); + $this->anonUsers = $this->onlineCount - count($this->usersOnline); + } + + public function executeCreateCompositeArtwork() + { + $this->from_date = ($this->getRequestParameter('from_date')) ? $this->getRequestParameter('from_date') : ''; + $this->to_date = ($this->getRequestParameter('to_date')) ? $this->getRequestParameter('to_date') : ''; + $this->filetypes = array('image' => sfContext::getInstance()->getI18n()->__('Images'), + 'video' => sfContext::getInstance()->getI18n()->__('Videos'), + 'audio' => sfContext::getInstance()->getI18n()->__('Audio'), + 'pdf' => sfContext::getInstance()->getI18n()->__('PDFs'), + 'text' => sfContext::getInstance()->getI18n()->__('Text')); + + // Sanitycheck the date, if provided + if ($this->getRequestParameter('date_check')) + { + if ($this->from_date['year'] == 0 || $this->from_date['month'] == 0 || $this->from_date['year'] == 0) + { + $this->getRequest()->setError('date', sfContext::getInstance()->getI18n()->__('Please specify a valid date')); + } + elseif ($this->to_date['year'] == 0 || $this->to_date['month'] == 0 || $this->to_date['year'] == 0) + { + $this->getRequest()->setError('date', sfContext::getInstance()->getI18n()->__('Please specify a valid date')); + } + else + { + $fromdate = $this->from_date['year'].'-'.$this->from_date['month'].'-'.$this->from_date['day'].' 00:00:00'; + $unixfromdate = strtotime($fromdate); + $todate = $this->to_date['year'].'-'.$this->to_date['month'].'-'.$this->to_date['day'].' 00:00:00'; + $unixtodate = strtotime($todate); + + if (!$unixfromdate || !$unixtodate) + { + $this->getRequest()->setError('date', sfContext::getInstance()->getI18n()->__('Please specify a valid date')); + } + elseif ($unixfromdate > $unixtodate) + { + $this->getRequest()->setError('date', sfContext::getInstance()->getI18n()->__('The from-date must be before the to-date')); + } + + } + } + + // Sanitycheck the tags, if provided + if ($this->getRequestParameter('tags_check')) + { + if (trim($this->getRequestParameter('tags')) == '') + { + $this->getRequest()->setError('tags', sfContext::getInstance()->getI18n()->__('Please specify some tags')); + } + } + + // Bail out if we found any errors, or we are just visiting the page + if ($this->getRequest()->hasErrors() || $this->getRequest()->getMethod() != sfRequest::POST) + { + return; + } + + if ($this->getRequestParameter('docreate')) + { + if (is_array($this->getRequestParameter('include_file')) && count($this->getRequestParameter('include_file')) > 0) + { + $files = array(); + foreach ($this->getRequestParameter('include_file') as $file_id => $unimportant_value) + { + $files[] = new artworkFile($file_id); + } + $artwork = new genericArtwork('New composite ' . $files[0]->getFiletype() . ' artwork', $files[0]->getFiletype()); + $artwork->setDescription('Artwork description goes here'); + $artwork->setMultiUser(true); + $artwork->setUser($this->getUser()->getGuardUser()); + $artwork->save(); + + $artwork->addFiles($files); + $artwork->resetFirstFile(); + return $this->redirect($artwork->getLink('edit')); + } + else + { + $this->getRequest()->setError('nofiles', sfContext::getInstance()->getI18n()->__('Cannot create artwork: no files selected')); + return; + } + } + + $files = array(); + // Tags search + if ($this->getRequestParameter('tags_check')) + { + $files = TagPeer::getFilesTaggedWith($this->getRequestParameter('tags')); + } + // Only date search + elseif ($this->getRequestParameter('date_check')) + { + $files = ReaktorFilePeer::getByDate($fromdate, $todate); + } + + $allfiles = array(); + // Now filter the files by the type the user requested + foreach ((array)$files as $file) + { + if ($file instanceof genericArtwork) + { + foreach($file->getFiles() as $file) + { + if ($file->getFiletype() == $this->getRequestParameter('filetype')) + { + $artworkExists = false; + foreach($allfiles as $f) + if($file->getId()==$f->getId()) + $artworkExists = true; + if(!$artworkExists && !$file->isDeleted() && $file->getParentArtwork()!=null && $file->getParentArtwork()->getStatus()==3 && !$file->getParentArtwork()->isDeleted()) + $allfiles[] = $file; + } + } + } + elseif ($file instanceof artworkFile) + { + if ($file->getFiletype() == $this->getRequestParameter('filetype')) + { + $artworkExists = false; + + foreach($allfiles as $f) + if($file->getId()==$f->getId()) + $artworkExists = true; + + if(!$artworkExists && !$file->isDeleted() && $file->getParentArtwork()!=null && $file->getParentArtwork()->getStatus()==3 && !$file->getParentArtwork()->isDeleted()) + $allfiles[] = $file; + } + } + } + + // Date search too, remove files that fall out of range + if ($this->getRequestParameter('date_check')) + { + foreach ($allfiles as $key => $aFile) + { + if (!(strtotime($aFile->getUploadedAt()) >= $unixfromdate && + strtotime($aFile->getUploadedAt()) <= $unixtodate)) + { + unset($allfiles[$key]); + } + } + } + + $this->files = $allfiles; + } + + /** + * Display list of permission descriptions + * + * @return void + */ + public function executePermissionDescriptionsList() + { + $this->permissions = sfGuardPermissionPeer::doSelect(new Criteria()); + } + + /** + * Show permission description edit form + * + * @return void + */ + public function executePermissionDescriptionEdit() + { + $this->edit_permission = sfGuardPermissionPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($this->edit_permission); + } + + /** + * Save/update permission description + * + * @return redirect + */ + public function executePermissionDescriptionUpdate() + { + $edit_permission = sfGuardPermissionPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($edit_permission); + + $edit_permission->setDescription($this->getRequestParameter('description')); + + $edit_permission->save(); + + return $this->redirect('@sfguardpermissiondescriptionlist'); + } + + public function executeCategoryRename() + { + $artworks = CategoryArtwork::getArtworkIdFromCategoryId($this->getRequestParameter('id')); + $oldCat = Category::getByBasename($this->getRequestParameter('basename')); + $newCat = Category::getByBasename($this->getRequestParameter('new_cat')); + if (count($artworks) == 0) + { + //we should be able to merge categories even though there are no artworks connected to it. + $artwork = array(); + //return $this->renderText(sfContext::getInstance()->getI18n()->__("This category does not exist")); + } + if (!$newCat) + { + return $this->renderText(sfContext::getInstance()->getI18n()->__("Failed,category doesn't exist")); + } + //the "new" category exitst and we have to merge wit existing tag + $artworkObjs = array(); + foreach ($artworks as $artwork) + { + $tmpArtworkObj = new genericArtwork($artwork->getArtworkId()); + $tmpArtworkObj->addCategory( $newCat->getId(), $this->getUser() ); + $tmpArtworkObj->removeCategory( $oldCat->getId() ); + $tmpArtworkObj->save(); + } + //if we want to delete the category afterwards, uncomment this + $oldCat->delete(); + $output = json_encode(array("success" => true)); + $this->getResponse()->setHttpHeader("X-JSON", '('.$output.')'); + return sfView::HEADER_ONLY; + } + + public function executeCategoryAutocomplete() + { + $this->categories = Category::getByBasenameLike($this->getRequestParameter('new_cat')); + + } + + public function executeGetMostActiveUsers() { + $this->forward404Unless($this->getUser()->hasCredential('viewreports')); + } +} + + diff --git a/apps/reaktor/modules/admin/actions/components.class.php b/apps/reaktor/modules/admin/actions/components.class.php new file mode 100644 index 0000000..c41c59a --- /dev/null +++ b/apps/reaktor/modules/admin/actions/components.class.php @@ -0,0 +1,32 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +class adminComponents extends sfComponents +{ + + public function executeAdminArtworkList() + { + } + + /** + * Print a summary of the logged in admin user's useful links and information. + * Used in the sidebar. + * + */ + public function executeAdminSummary() + { + $this->editorialteams = array(); + foreach ($this->getUser()->getGuardUser()->getEditorialTeams() as $aTeam) + { + $this->editorialteams[$aTeam->getId()] = $aTeam; + } + } +} \ No newline at end of file diff --git a/apps/reaktor/modules/admin/config/security.yml b/apps/reaktor/modules/admin/config/security.yml new file mode 100644 index 0000000..442169a --- /dev/null +++ b/apps/reaktor/modules/admin/config/security.yml @@ -0,0 +1,11 @@ +all: + is_secure: on + credentials: [[staff]] #OR + + + +listPromotionalEmailRecipients: + is_secure: on + credentials: listoptinuseremails + + diff --git a/apps/reaktor/modules/admin/config/view.yml b/apps/reaktor/modules/admin/config/view.yml new file mode 100644 index 0000000..ee74b6f --- /dev/null +++ b/apps/reaktor/modules/admin/config/view.yml @@ -0,0 +1,15 @@ +all: + stylesheets: [/css/lightwindow] + javascripts: [lightwindow] + +indexSuccess: + http_metas: + Pragma: no-cache + Cache-Control: no-cache + +listUnapprovedOtherTeamsSuccess: + http_metas: + Pragma: no-cache + Cache-Control: no-cache + + diff --git a/apps/reaktor/modules/admin/templates/_adminArtworkList.php b/apps/reaktor/modules/admin/templates/_adminArtworkList.php new file mode 100644 index 0000000..bca44af --- /dev/null +++ b/apps/reaktor/modules/admin/templates/_adminArtworkList.php @@ -0,0 +1,80 @@ + $files)) + * Ex.: include_component('admin', 'adminArtworkList', array('artworks' => $artworks, 'show_recommended' => true)) + * + * This template gets all of its information from the parameters passed + * - $files : An array of files + * - $artworks : Array of artworks + * - $show_recommended : If this is passed, the subreaktors this file is recommended are displayed + * + * PHP version 5 + * + * @author Daniel Andre Eikeland + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +$rowCount = 0; +?> +
      + +
    • + + + + + + + + + + +
    • + + $artwork,'showDetails'=>true)); //Display artwork?> + $artwork, + 'type' => 'artwork' )) ?> + + $artwork, 'show_recommended_at' => $art["updatedat"])); //Display artwork?> +
      +

      '')); ?>

      + getLokalreaktor()): ?> + getReference() . '-' . $art['lokalreaktor']->getReference(); ?> + + getReference(); ?> + +
      + +
    • + + + + + +
    • + + + $file): //Print list of files?> +
    • + $file)); //Display file?> + + $file, + 'type' => 'file', + 'showRejectionMsg' => 'rejection_message_'.$file->getId() + )) //Display buttons?> + isUnsuitable()): //Print rejected message in lightwindow box?> + +
    • + + + +
    diff --git a/apps/reaktor/modules/admin/templates/_adminSummary.php b/apps/reaktor/modules/admin/templates/_adminSummary.php new file mode 100644 index 0000000..7f7c674 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/_adminSummary.php @@ -0,0 +1,62 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +
    +

    + '' . $sf_user->getUsername() . '')); ?> +
    + [] +
    +
    +
      + +
    • + +
    + hasCredential('approveartwork')): ?> +
      +
    • +
    + + hasCredential('approvetags') || + $sf_user->hasCredential('tagadministrator') || + $sf_user->hasCredential('listuser')): ?> +
      + hasCredential('tagadministrator')): ?> +
    • + + hasCredential('listuser')): ?> +
    • + +
    + +
      + hasCredential('viewallcontent')): ?> +
    • + + +
    • + +
    +
      +
    • getUsername()); ?>
    • +
    • +
    • getUsername().'&key=0'); ?>
    • +
    +
      +
    • +
    +
    diff --git a/apps/reaktor/modules/admin/templates/_discussButtons.php b/apps/reaktor/modules/admin/templates/_discussButtons.php new file mode 100644 index 0000000..37ec3ab --- /dev/null +++ b/apps/reaktor/modules/admin/templates/_discussButtons.php @@ -0,0 +1,54 @@ + $artwork)) + * + * The paramenters sent are: + * - $object : a genericArtwork or a ReaktorFile + * - $type : file or artwork + * - $update_div : the div that should be updated when a button has carried out its action + * + * PHP Version 5 + * + * @author Russ + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/_renameComponent.php b/apps/reaktor/modules/admin/templates/_renameComponent.php new file mode 100644 index 0000000..6565116 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/_renameComponent.php @@ -0,0 +1,48 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + + + + diff --git a/apps/reaktor/modules/admin/templates/_userEditorialTeam.php b/apps/reaktor/modules/admin/templates/_userEditorialTeam.php new file mode 100644 index 0000000..f443223 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/_userEditorialTeam.php @@ -0,0 +1,25 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +
    + '@listmyteams', + 'update' => "message_".substr(md5($user->getId()), 0, 5), + 'success' => visual_effect('highlight', "list_".substr(md5($user->getId()), 0, 5)))); ?> + getId()); ?> + getEditorialNotification()), + array("onchange" => "$('message_".substr(md5($user->getId()), 0, 5)."').innerHTML='';")); ?> + + + '; ?> +
    \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/adminFunctionsSuccess.php b/apps/reaktor/modules/admin/templates/adminFunctionsSuccess.php new file mode 100644 index 0000000..e3f26e9 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/adminFunctionsSuccess.php @@ -0,0 +1,47 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + +

    + +

    + +

    + +
    + +

    + +

    + date("d/m/Y", $configCacheTimestamp), + "%change_time%" => date("h:i", $configCacheTimestamp), + "%button_text%" => __("Clear configuration cache"))); ?> +

    +

    + __("Clear html (template) cache"))); ?> +

    +

    + +

    + + + + "delete", "confirm" => __("Are you sure you wish to delete the entire cached content? ". + "Whilst this is a non-destructive process, the performance of the site ". + "will be affected for the first few hours of use.") + )); ?> \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/artworkStatusEditSuccess.php b/apps/reaktor/modules/admin/templates/artworkStatusEditSuccess.php new file mode 100644 index 0000000..d0aa7b2 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/artworkStatusEditSuccess.php @@ -0,0 +1,43 @@ + + * @author Russ + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__("Edit artwork status")); +use_helper('Object'); + +?> + + + + + +

    $artwork_status->getName())); ?>

    + + + + + + + + + + + +
    :getName(); ?>
    $sf_user->getCultureName()));?> false, + )) ?>
    +
    +
    +'; ?> diff --git a/apps/reaktor/modules/admin/templates/artworkStatusListSuccess.php b/apps/reaktor/modules/admin/templates/artworkStatusListSuccess.php new file mode 100644 index 0000000..9c2b9e3 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/artworkStatusListSuccess.php @@ -0,0 +1,33 @@ + + * @author Russ + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + +getResponse()->setTitle(__('Reaktor - Admin - List artworks')); ?> +

    + + + + + + + + + + + + + + + + +
    getDescription() ?>getId()) ?>
    diff --git a/apps/reaktor/modules/admin/templates/categoryAutocompleteSuccess.php b/apps/reaktor/modules/admin/templates/categoryAutocompleteSuccess.php new file mode 100644 index 0000000..b276df5 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/categoryAutocompleteSuccess.php @@ -0,0 +1,7 @@ +
      + + +
    • getBasename() ?>
    • + + +
    \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/categoryEditSuccess.php b/apps/reaktor/modules/admin/templates/categoryEditSuccess.php new file mode 100644 index 0000000..a9098bf --- /dev/null +++ b/apps/reaktor/modules/admin/templates/categoryEditSuccess.php @@ -0,0 +1,43 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__("Edit categories")); +use_helper('Object', 'Javascript'); + +?> + + + + + + +

    $edit_category->getName())); ?>

    + + + + + + + + + + + +
    getBasename(); ?>
    $sf_user->getCultureName()));?> false, + )) ?>
    +
    + + +'; ?> \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/categoryListSuccess.php b/apps/reaktor/modules/admin/templates/categoryListSuccess.php new file mode 100644 index 0000000..6ad0074 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/categoryListSuccess.php @@ -0,0 +1,50 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('List categories')); +use_helper('Javascript'); +?> + +

    [ ]

    +
    + + + + + + + + + + + + + + + + + + + + + + +
    IDgetCulture()." )"; ?>
    getId(); ?>getBasename(); ?> + + $category)); ?> + + + getName(); ?>getId()); ?> 10)), + "Effect.toggle('categoryeditor_".$category->getId()."','appear')"); ?>
    \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/createCompositeArtworkSuccess.php b/apps/reaktor/modules/admin/templates/createCompositeArtworkSuccess.php new file mode 100644 index 0000000..714c3ad --- /dev/null +++ b/apps/reaktor/modules/admin/templates/createCompositeArtworkSuccess.php @@ -0,0 +1,95 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('content', 'Javascript', 'wai'); + reaktor::setReaktorTitle(__('Create composite artwork')); + +?> +
    +

    +

    +

    + "post")); ?> +
    +
    + get('tags_check')); ?> + +

    '(', ')' => ')')); ?>

    +

    +
    + get('tags'), 'tags/autocompletetag', null, array('use_style' => false, 'tokens' => ',', 'frequency' => 0.1)); ?> +
    +

    get('date_check')); ?> + +

    +
    +

    '', ', to %date%' => '')); ?> + false, + 'culture' => $sf_user->getCulture(), + 'year_end' => date('Y'), + 'year_start' => 2004, + 'date_seperator' => ' ', + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) + )); ?> + '', '%date%' => '')); ?> + false, + 'culture' => $sf_user->getCulture(), + 'year_end' => date('Y'), + 'year_start' => 2004, + 'date_seperator' => ' ', + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) + )); ?> +

    +

    +

    get('filetype'))); ?>

    + +
    + '); ?> +
    +

    + +
    +

    + +

    + "listform", "name" => "listform")); ?> +
      + +
    • + $file)) //Display file ?> + +
    • + +
    + +
    +

    + [ + / ] +

    +

    + +

    +

    + +

    +
    + '; ?> + +

    + +
    + diff --git a/apps/reaktor/modules/admin/templates/editorialTeamsSuccess.php b/apps/reaktor/modules/admin/templates/editorialTeamsSuccess.php new file mode 100644 index 0000000..26c5add --- /dev/null +++ b/apps/reaktor/modules/admin/templates/editorialTeamsSuccess.php @@ -0,0 +1,35 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__('Editorial team settings')); + +use_helper('Javascript'); + +?> +
    +

    +
      + +
    • getDescription(), '@listmyteams?team=' . $team->getId()); ?>
    • + +
    +
    + +
    +

    getDescription(); ?>

    + ' . + __('Remember that changing the notification setting changes it for this user in all teams
    - not just the current one.'); ?> + +

    getUsername() . ' (' . $member->getName() . ')'; ?>

    + $member)); ?> + +
    + \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/getMostActiveUsersSuccess.php b/apps/reaktor/modules/admin/templates/getMostActiveUsersSuccess.php new file mode 100644 index 0000000..702b3d7 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/getMostActiveUsersSuccess.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/historyActionEditSuccess.php b/apps/reaktor/modules/admin/templates/historyActionEditSuccess.php new file mode 100644 index 0000000..f326bbc --- /dev/null +++ b/apps/reaktor/modules/admin/templates/historyActionEditSuccess.php @@ -0,0 +1,31 @@ + + + + + + +

    $history_action->getName())); ?>

    + + + + + + + + + + + +
    :getName(); ?>
    $sf_user->getCultureName()));?> false, + )) ?>
    +
    + + diff --git a/apps/reaktor/modules/admin/templates/historyActionListSuccess.php b/apps/reaktor/modules/admin/templates/historyActionListSuccess.php new file mode 100644 index 0000000..eff5459 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/historyActionListSuccess.php @@ -0,0 +1,22 @@ + +

    + + + + + + + + + + + + + + + + +
    getDescription()? $history_action->getDescription() : $history_action->getName()) ?>getId()) ?>
    diff --git a/apps/reaktor/modules/admin/templates/indexSuccess.php b/apps/reaktor/modules/admin/templates/indexSuccess.php new file mode 100644 index 0000000..559e288 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/indexSuccess.php @@ -0,0 +1,95 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('Admin portal')); +$counter = 0; +?> +
    +hasCredential('approveartwork')): ?> + + + +hasCredential('viewothereditorialteams')): ?> + + + + + + + +
    +hasCredential('viewallcontent')): ?> + + + +hasCredential('tagadministrator')): ?> + + + + + + + +
    +hasCredential('editusercontent') || $sf_user->hasCredential('viewallcontent')): ?> + + + +hasCredential('commentadmin')): ?> + + + + + + + +
    +hasCredential('editusercontent') || $sf_user->hasCredential('viewallcontent')): ?> + + + + + + + +
    \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/listApprovedSuccess.php b/apps/reaktor/modules/admin/templates/listApprovedSuccess.php new file mode 100644 index 0000000..16eecd0 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/listApprovedSuccess.php @@ -0,0 +1,48 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'content', 'Url', 'PagerNavigation', 'Date'); +reaktor::setReaktorTitle(__('List approved artworks')); +reaktor::addJsToFooter("$('approved_calendar').setStyle({height: $('sidebar').offsetHeight + 'px'});"); + +?> + +hasCredential('approveartwork')): ?> +
    +
    +

    +
    +
      + = 2004; $ccY--): ?> +
    • + +
        + + > + +
      + +
    • + +
    +
    +
    + +

    format_date(date('Y-m-d', mktime(null, null, null, $selected_month, 1, $selected_year)), 'MMMM'), '%year%' => $selected_year)) ?>

    + $artworks)); ?> + + + + +
    +
    + diff --git a/apps/reaktor/modules/admin/templates/listCompositeSuccess.php b/apps/reaktor/modules/admin/templates/listCompositeSuccess.php new file mode 100644 index 0000000..fc4401a --- /dev/null +++ b/apps/reaktor/modules/admin/templates/listCompositeSuccess.php @@ -0,0 +1,22 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper('content'); + +reaktor::setReaktorTitle(__('Admin galleries/composite artworks')); +?> +

    + $artworks)); ?> diff --git a/apps/reaktor/modules/admin/templates/listIgnoredUsersSuccess.php b/apps/reaktor/modules/admin/templates/listIgnoredUsersSuccess.php new file mode 100644 index 0000000..c2ae536 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/listIgnoredUsersSuccess.php @@ -0,0 +1,45 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__('List ignored users')); + +use_helper('wai'); +?> + +

    + + + 3, 'length' => 3)) ?> + +'; ?> + + + + + + + + + + + + + + + + + + + + +
    () $a_user['count'])) ?> | +
    + diff --git a/apps/reaktor/modules/admin/templates/listPromotionalEmailRecipientsSuccess.php b/apps/reaktor/modules/admin/templates/listPromotionalEmailRecipientsSuccess.php new file mode 100644 index 0000000..28af4b0 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/listPromotionalEmailRecipientsSuccess.php @@ -0,0 +1,51 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__('Mailing list')); + +?> +

    +
    + 1): + ?> + + + + $email_count_in_block): + $counter = 0; + ?> +
    +
    + + + +
    diff --git a/apps/reaktor/modules/admin/templates/listRecommendedSuccess.php b/apps/reaktor/modules/admin/templates/listRecommendedSuccess.php new file mode 100644 index 0000000..e21efef --- /dev/null +++ b/apps/reaktor/modules/admin/templates/listRecommendedSuccess.php @@ -0,0 +1,25 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper('content'); + +reaktor::setReaktorTitle(__('Recommended artworks')); +?> +

    + $artworks, 'show_recommended' => true)); ?> diff --git a/apps/reaktor/modules/admin/templates/newCategorySuccess.php b/apps/reaktor/modules/admin/templates/newCategorySuccess.php new file mode 100644 index 0000000..0e4fdaf --- /dev/null +++ b/apps/reaktor/modules/admin/templates/newCategorySuccess.php @@ -0,0 +1,20 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('Language settings')); + +?> + + "@listcategories", + "translateObject" => "Category", + "translateField" => "Name")); ?> \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/onlineNowSuccess.php b/apps/reaktor/modules/admin/templates/onlineNowSuccess.php new file mode 100644 index 0000000..ac4fbd4 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/onlineNowSuccess.php @@ -0,0 +1,41 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> +

    +

    + $anonUsers)); ?> +
    + count($usersOnline))); ?> +

    + + + + + + + + + + + + +
    getUserName(), "@portfolio?user=".$user->getUsername()); ?>getLastLogin(); ?>
    + + + \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/permissionDescriptionEditSuccess.php b/apps/reaktor/modules/admin/templates/permissionDescriptionEditSuccess.php new file mode 100644 index 0000000..384fdb0 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/permissionDescriptionEditSuccess.php @@ -0,0 +1,30 @@ + + + + + + + + +

    $edit_permission->getName())); ?>

    + + + + + + + + + + + +
    :getName(); ?>
    false, +)) ?>
    +
    + +'; ?> \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/permissionDescriptionsListSuccess.php b/apps/reaktor/modules/admin/templates/permissionDescriptionsListSuccess.php new file mode 100644 index 0000000..1d15887 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/permissionDescriptionsListSuccess.php @@ -0,0 +1,23 @@ + +

    + + + + + + + + + + + + + + + + + +
    getName() ?>getId()) ?>
    diff --git a/apps/reaktor/modules/admin/templates/rejectionTypeEditSuccess.php b/apps/reaktor/modules/admin/templates/rejectionTypeEditSuccess.php new file mode 100644 index 0000000..afe2a2b --- /dev/null +++ b/apps/reaktor/modules/admin/templates/rejectionTypeEditSuccess.php @@ -0,0 +1,36 @@ + + + + + + + +

    $rejection_type->getName())); ?>

    + + + + + + + + + + + +
    Name*: 80, +)) ?>
    Description*: false, +)) ?>
    +
    + +getId()): ?> +  getId(), 'post=true&confirm=Are you sure?') ?> +  getId()) ?> + +   + +'; ?> \ No newline at end of file diff --git a/apps/reaktor/modules/admin/templates/rejectionTypeListSuccess.php b/apps/reaktor/modules/admin/templates/rejectionTypeListSuccess.php new file mode 100644 index 0000000..24a986b --- /dev/null +++ b/apps/reaktor/modules/admin/templates/rejectionTypeListSuccess.php @@ -0,0 +1,26 @@ + +

    + + + + + + + + + + + + + + + + + + +
    IdName
    getId() ?>getName(), '@rejectiontypeshow?id='.$rejection_type->getId()) ?>
    + + diff --git a/apps/reaktor/modules/admin/templates/rejectionTypeShowSuccess.php b/apps/reaktor/modules/admin/templates/rejectionTypeShowSuccess.php new file mode 100644 index 0000000..a0633a3 --- /dev/null +++ b/apps/reaktor/modules/admin/templates/rejectionTypeShowSuccess.php @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + +
    getId() ?>
    getName() ?>
    getDescription() ?>
    +
    +getId()) ?> +  diff --git a/apps/reaktor/modules/admin/templates/subreaktorNameEditSuccess.php b/apps/reaktor/modules/admin/templates/subreaktorNameEditSuccess.php new file mode 100644 index 0000000..f586d3b --- /dev/null +++ b/apps/reaktor/modules/admin/templates/subreaktorNameEditSuccess.php @@ -0,0 +1,30 @@ + + + + + + + + +

    $edit_subreaktor->getName())); ?>

    + + + + + + + + + + + +
    :getReference(); ?>
    false, +)) ?>
    +
    + +'; ?> diff --git a/apps/reaktor/modules/admin/templates/subreaktorNameListSuccess.php b/apps/reaktor/modules/admin/templates/subreaktorNameListSuccess.php new file mode 100644 index 0000000..32c81fe --- /dev/null +++ b/apps/reaktor/modules/admin/templates/subreaktorNameListSuccess.php @@ -0,0 +1,24 @@ + +

    + + + + + + + + + + + + + + + + + + +
    getName() ?>getReference() ?>getId()) ?>
    diff --git a/apps/reaktor/modules/admin/validate/editorialTeams.yml b/apps/reaktor/modules/admin/validate/editorialTeams.yml new file mode 100644 index 0000000..047df04 --- /dev/null +++ b/apps/reaktor/modules/admin/validate/editorialTeams.yml @@ -0,0 +1,6 @@ +fillin: + enabled: true + +fields: + notify_value: + required: true \ No newline at end of file diff --git a/apps/reaktor/modules/adminmessage/actions/actions.class.php b/apps/reaktor/modules/adminmessage/actions/actions.class.php new file mode 100644 index 0000000..ec5c34d --- /dev/null +++ b/apps/reaktor/modules/adminmessage/actions/actions.class.php @@ -0,0 +1,28 @@ +admin_message->setAuthor($this->getUser()->getGuardUser()->getId()); + + //Let symfony handle the other fields + parent::updateAdminMessageFromRequest(); + + } + +} diff --git a/apps/reaktor/modules/adminmessage/actions/components.class.php b/apps/reaktor/modules/adminmessage/actions/components.class.php new file mode 100644 index 0000000..1ec24c9 --- /dev/null +++ b/apps/reaktor/modules/adminmessage/actions/components.class.php @@ -0,0 +1,42 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Components for admin system messages + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class adminmessageComponents extends sfComponents +{ + /** + * Get the next message due to expire and display it in the sidebar. + * All admin messages have a date on them saying when they expire, and + * this is used to decide which message is next. + * + * This should only be used in special cases, i.e when the system + * has to be taken down for a short period of time. Consider sending a + * message to all users using the flash messaging system before using this. + * + * This message cannot be translated, because it is intended to be as + * simple as possible. + * + * @return void + */ + function executeNextMessageDueToExpire() + { + $this->admin_message = AdminMessagePeer::getNextMessageDueToExpire(); + } +} \ No newline at end of file diff --git a/apps/reaktor/modules/adminmessage/config/generator.yml b/apps/reaktor/modules/adminmessage/config/generator.yml new file mode 100644 index 0000000..96fe786 --- /dev/null +++ b/apps/reaktor/modules/adminmessage/config/generator.yml @@ -0,0 +1,28 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: AdminMessage + theme: default + + edit: + title: Add a new system message + display: [message, expires_at] + fields: + expires_at: + params: readonly=readonly + + list: + peer_method: doSelectJoinsfGuardUser + title: System messages outbox + display: [=message, sender, updated_at, expires_at] + fields: + sender: + name: Sent/Updated by + object_actions: + _delete: ~ + _edit: ~ + max_per_page: 10 + + + + \ No newline at end of file diff --git a/apps/reaktor/modules/adminmessage/config/security.yml b/apps/reaktor/modules/adminmessage/config/security.yml new file mode 100644 index 0000000..bc4b8d0 --- /dev/null +++ b/apps/reaktor/modules/adminmessage/config/security.yml @@ -0,0 +1,15 @@ +edit: + credentials: createsystemadminmessages + is_secure: on + +delete: + credentials: deletesystemadminmessages + is_secure: on + +list: + credentials: listsystemadminmessages + is_secure: on + +all: + credentials: listsystemadminmessages + is_secure: on \ No newline at end of file diff --git a/apps/reaktor/modules/adminmessage/templates/_nextMessageDueToExpire.php b/apps/reaktor/modules/adminmessage/templates/_nextMessageDueToExpire.php new file mode 100644 index 0000000..9903d4f --- /dev/null +++ b/apps/reaktor/modules/adminmessage/templates/_nextMessageDueToExpire.php @@ -0,0 +1,21 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + +
    +

    + getMessage() ?> +
    +
    + diff --git a/apps/reaktor/modules/adminmessage/validate/edit.yml b/apps/reaktor/modules/adminmessage/validate/edit.yml new file mode 100644 index 0000000..6ee9af8 --- /dev/null +++ b/apps/reaktor/modules/adminmessage/validate/edit.yml @@ -0,0 +1,17 @@ +methods: + post: + - "admin_message{message}" + - "admin_message{expires_at}" + +names: + admin_message{message}: + required: yes + required_msg: Please write the system message, this field cannot be blank + admin_message{expires_at}: + required: yes + required_msg: Please choose a date and time this message should expire + sfDateValidator: + + +fillin: + activate: on diff --git a/apps/reaktor/modules/articles/actions/actions.class.php b/apps/reaktor/modules/articles/actions/actions.class.php new file mode 100644 index 0000000..921ec55 --- /dev/null +++ b/apps/reaktor/modules/articles/actions/actions.class.php @@ -0,0 +1,621 @@ +forward('default', 'module'); + } + + public function executeCalendar() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + sfLoader::loadHelpers('Partial'); + return $this->renderText(get_component('articles', 'articleCalendar', array( + 'year' => $this->getRequestParameter('year'), + 'article_type' => $this->getRequestParameter('article_type'), + 'month' => $this->getRequestParameter('month'), + 'article_id' => $this->getRequestParameter('article_id'), + 'only' => $this->getRequestParameter('only'), + 'edit' => $this->getRequestParameter('edit'), + 'chosen_format' => $this->getRequestParameter('chosen_format'), + 'status' => $this->getRequestParameter('status', 'all'), + 'live' => $this->getRequestParameter('live'), + ))); + } + + /** + * List helparticles divided into format/subReaktor sections + */ + public function executeHelpArticlesBrowser() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + sfLoader::loadHelpers('Partial'); + return $this->renderText(get_component('articles', 'browseTypes', array( + 'view_article' => $this->getRequestParameter('view_article'), + 'chosen_format' => $this->getRequestParameter('chosen_format'), + ))); + } + + public function executeSetExpirationDate() + { + $article = ArticlePeer::retrieveByPK($this->getRequestParameter('article_id')); + $this->forward404Unless($article instanceof Article); + $this->error = ''; + try + { + $v = $this->getRequestParameter('expiry_date'); + $article->setExpiresAt($v['year'].'-'.$v['month'].'-'.$v['day']); + $article->save(); + } + catch (Exception $e) + { + $this->getRequest()->setError('expiry_date', sfContext::getInstance()->getI18N()->__('Could not save this expiry date')); + } + + sfLoader::loadHelpers('Partial'); + return $this->renderText(get_component('articles', 'expirationDate', array('article' => $article))); + } + + public function validateEdit() + { + $i18n = sfContext::getInstance()->getI18N(); + $this->article_type = $this->getRequestParameter('article_type'); + $this->year = $this->getRequestParameter('year'); + $this->month = $this->getRequestParameter('month'); + $article_id = $this->getRequestParameter('article_id'); + $subreaktors = $this->getRequestParameter('subreaktorChecked'); + $article = null; + $new = false; + + if ($this->getRequest()->getMethod() != sfRequest::POST) + { + return true; + } + + if ($article_id) + { + $article = ArticlePeer::retrieveByPK($article_id); + } + if (!$article) + { + // Make sure we have an article + $article = new Article; + $new = true; + } + + $article_types = ArticlePeer::getArticleTypes(); + if (!isset($article_types[$this->getRequestParameter('article_type', 0)])) + { + $this->getRequest()->setError("article_type", $i18n->__("Unknown article type")); + } + + // Check for internationalised title + if ($this->getRequestParameter('article_title_i18n') && $article->hasTranslatableTitle()) + { + $titleArray = (array)$this->getRequestParameter("article_title_i18n"); + if (!isset($titleArray["no"]) || !trim($titleArray["no"])) + { + $this->getRequest()->setError('article_title', $i18n->__('You must enter a Bokmål title')); + } + else + { + $title = $titleArray["no"]; + } + + foreach(CataloguePeer::getCatalogues(true) as $lang => $desc) + { + if (empty($titleArray[$lang])) + { + $titleArray[$lang] = $title; + } + } + $this->getRequest()->getParameterHolder()->set('article_title_i18n', $titleArray); + } + // Regular title + else + { + if (!trim($this->getRequestParameter('article_title'))) + { + $this->getRequest()->setError("article_title", $i18n->__('You must enter a title')); + } + else + { + $title = $this->getRequestParameter('article_title'); + } + } + + + // Check the permlink + if (!$article->getPermalink() || $this->getRequestParameter("reset_permalink")) + { + $permalink = ArticlePeer::sanitizePermlink(trim($title)); + + $crit = new Criteria(); + + $ctn = $crit->getNewCriterion(ArticlePeer::BASE_TITLE, $title); + $ctn2 = $crit->getNewCriterion(ArticlePeer::PERMALINK, $permalink); + $ctn->addOr($ctn2); + $crit->add($ctn); + + $crit->add(ArticlePeer::ID, $article->getId(), Criteria::NOT_EQUAL); + $crit->addAscendingOrderByColumn(ArticlePeer::BASE_TITLE); + + if (ArticlePeer::doCount($crit) > 0) + { + $this->getRequest()->setError('article_title', $i18n->__('Please enter a unique title')); + } + } + + // Check the article content + if (!($this->getRequestParameter("article_ingress") || $this->getRequestParameter("article_content"))) + { + $this->getRequest()->setError('article_content', $i18n->__('Article should atleast have either intro or content')); + } + if (!$new) { + switch($this->getRequestParameter("article_type")) { + // Theme articles must expire and have a banner + case ArticlePeer::THEME_ARTICLE: + if (!$article->getExpiresAt() || !$article->getBannerFileId()) + { + if (!$article->getExpiresAt()) + { + $this->getRequest()->setError('expiry_date', $i18n->__('Theme articles must expire sometime')); + } + if (!$article->getBannerFileId()) + { + $this->getRequest()->setError('banner_error', $i18n->__('Theme articles must have a banner')); + } + } + break; + //There must be at least one subreaktor on the article when it's published + case ArticlePeer::HELP_ARTICLE: + + if(!$article->getSubreaktors()) + { + $this->getRequest()->setError('subreaktors', sfContext::getInstance()->getI18N()->__('Help articles must have at least one subReaktor')); + } + break; + } + } + return !$this->getRequest()->hasErrors(); + } + + public function executeEdit() + { + $this->forward404Unless($this->getUser()->isAuthenticated() && $this->getUser()->hasCredential('staff')); + $access = ArticlePeer::getArticleTypesByPermission($this->getUser()); + + $this->show_subreaktor_and_categories_edit = false; + $this->show_tags_edit = false; + $this->show_attachments_edit = false; + $this->show_related_artworks_edit = false; + $this->show_related_edit = false; + $this->show_banner = false; + $this->show_expiry_date = false; + $isSaved = false; + $this->article_type = $this->getRequestParameter('article_type'); + $this->year = $this->getRequestParameter('year'); + $this->month = $this->getRequestParameter('month'); + $article_id = $this->getRequestParameter('article_id'); + $article = null; + + $this->forward404If($this->article_type && !isset($access[$this->article_type])); + + if ($article_id && $article = ArticlePeer::retrieveByPK($article_id)) + { + //Edit article + $this->show_related_edit = true; + $this->show_attachments_edit = true; + $this->show_related_artworks_edit = true; + $this->show_tags_edit = true; + + $this->year = date('Y', strtotime($article->getCreatedAt())); + $this->month = date('n', strtotime($article->getCreatedAt())); + $this->article_type = $article->getArticleType(); + } + else + { + // New article + $article = new Article(); + } + + + if ($this->getRequest()->getMethod() == sfRequest::POST && !$this->getRequest()->hasErrors()) + { + $article->setArticleType($this->getRequestParameter('article_type')); + + // Set internationalised titles if set + if ($this->getRequestParameter('article_title_i18n') && $article->hasTranslatableTitle()) + { + $titleArray = $this->getRequestParameter("article_title_i18n"); + $article->setI18nTitles($titleArray); + $article->setTitle($titleArray["no"]); + } + else + { + $article->setTitle(trim($this->getRequestParameter('article_title', $article->getBaseTitle()))); + if ($article->hasTranslatableTitle()) + { + $article->setI18nTitles(array(sfContext::getInstance()->getUser()->getCulture() => $this->getRequestParameter("article_title"))); + } + } + if (!$article->getPermalink() || $this->getRequestParameter("reset_permalink")) + { + $title = ArticlePeer::sanitizePermlink($article->getBaseTitle()); + $article->setPermalink($title); + } + + $this->month = date('n', $_SERVER['REQUEST_TIME']); + + + $article->setIngress($this->getRequestParameter('article_ingress')); + $article->setContent($this->getRequestParameter('article_content')); + + if ($article_id) + { + $article->setUpdatedAt($_SERVER["REQUEST_TIME"]); + $article->setUpdatedBy($this->getUser()->getId()); + + $frontpage=0; + if((bool)$this->getRequestParameter("frontpage")) $frontpage|=ArticlePeer::REAKTOR_FRONTPAGE; + if((bool)$this->getRequestParameter("subfrontpage")) $frontpage|=ArticlePeer::SUBREAKTOR_FRONTPAGE; + + $article->setFrontpage($frontpage); + + $article->setStatus($this->getRequestParameter("status")); + } + else + { + $article->setCreatedAt($_SERVER["REQUEST_TIME"]); + $article->setAuthorId($this->getUser()->getId()); + } + $this->article_type = $article->getArticleType(); + + $article->save(); + HistoryPeer::logAction(10, $this->getUser()->getId(), $article); + $isSaved = true; + + $this->redirect("@editarticle?article_id=".$article->getId()); + } + if ($article->getId()) + { + $this->show_related_edit = true; + $this->show_attachments_edit = true; + $this->show_related_artworks_edit = true; + $this->show_tags_edit = true; + + //Provide order option for selected articles + $this->order = ArticlePeer::ArticleCount($this->article_type)>1 && + ($this->article_type == ArticlePeer::REGULAR_ARTICLE || + $this->article_type == ArticlePeer::MY_PAGE_ARTICLE || + $this->article_type == ArticlePeer::FOOTER_ARTICLE || + $this->article_type == ArticlePeer::INTERNAL_ARTICLE) ? true : false; + + if (in_array($article->getArticleType(), array(ArticlePeer::HELP_ARTICLE, ArticlePeer::REGULAR_ARTICLE, ArticlePeer::THEME_ARTICLE))) + { + $this->show_subreaktor_and_categories_edit = true; + } + + if ($this->getRequestParameter('article_type', $article->getArticleType()) == ArticlePeer::THEME_ARTICLE) + { + $this->show_expiry_date = true; + $this->show_banner = true; + } + } + + $this->article = $article; + } + + public function executeList() + { + $this->article = new Article; + $this->status = $this->getRequestParameter("status", "all"); + $this->year = date('Y', $_SERVER["REQUEST_TIME"]); + $this->month = date('n', $_SERVER["REQUEST_TIME"]); + $this->article_type = $this->getRequestParameter("article_type", $this->article->getArticleType()); + + } + + public function handleErrorEdit() + { + $this->getRequest()->setError("fred", "fail"); + $this->executeEdit(); + return sfView::SUCCESS; + } + + /** + * Display article relations component. This is needed to display error messsages. Validation doesn't + * work with components. + * + * @return void + */ + public function executeArticleRelations() + { + $this->article = ArticlePeer::retrieveByPK($this->getRequestParameter('id')); + } + + /** + * Handle validation errors when relating articles + * + * @return void + */ + public function handleErrorRelateArticle() + { + $this->getResponse()->setStatusCode(500); + $this->forward('articles', 'articleRelations'); + } + + /** + * Ajax request to add relation + * + * @return Rendered updated component + */ + public function executeRelateArticle() + { + //Get request parameters + $first_article = $this->getRequestParameter('id'); + $second_article = $this->getRequestParameter('relate_article_select'); + + //Check credentials and paramters + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + $this->forward404Unless($this->getUser()->isAuthenticated()&&$this->getuser()->hasCredential('staff')); + $this->forward404Unless($first_article&&$second_article); + $user = $this->getUser()->getGuardUser()->getId(); + + //Add relation + ArticleArticleRelationPeer::addRelatedArticle($first_article, $second_article, $user); + + //Return updated relateArticles Component + sfLoader::loadHelpers('Partial'); + $article = ArticlePeer::retrieveByPK($first_article); + + return $this->renderText(get_component('articles', 'articleRelations', array('article'=> $article))); + } + + /** + * Ajax request to delete relation + * + * @return Rendedered updated component + */ + public function executeUnrelateArticle() + { + //Get request parameters + $first_article = $this->getRequestParameter('article1'); + $second_article = $this->getRequestParameter('article2'); + + //Check credentials and parameters + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + $this->forward404Unless($this->getUser()->isAuthenticated()&&$this->getuser()->hasCredential('staff')); + $this->forward404Unless($first_article&&$second_article); + + //Delete relation + ArticleArticleRelationPeer::deleteRelation($first_article,$second_article); + + //Return updated relateArticles Component + sfLoader::loadHelpers('Partial'); + $article = ArticlePeer::retrieveByPK($first_article); + + return $this->renderText(get_component('articles', 'articleRelations', array('article'=> $article))); + } + + public function executeRelateToArtwork() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + $this->forward404Unless($this->getUser()->isAuthenticated()&&$this->getuser()->hasCredential('staff')); + + $id = $this->getRequestParameter("article_id"); + $artwork = $this->getRequestParameter("artwork_id"); + + $this->forward404Unless(is_numeric($id) && is_numeric($artwork)); + + $article = ArticlePeer::retrieveByPK($id); + $article->relateToArtwork((int)$artwork); + return $this->renderText("OK"); + } + + /** + * Execute the article view template + * + * @return null + */ + public function executeView() + { + $staff = $this->getUser()->isAuthenticated() && $this->getuser()->hasCredential('staff'); + $permalink = $this->getRequestParameter('permalink'); + + if ($type = $this->getRequestParameter("latest")) + { + $this->article = $article = ArticlePeer::retrieveLatestByType($this->getRequestParameter("type")); + } + else + { + $this->article = $article = ArticlePeer::retrieveByPermalink($permalink, $staff); + } + + $this->forward404Unless($article); + + if ($this->article->getArticleType() == ArticlePeer::INTERNAL_ARTICLE) + { + $this->forward404Unless($staff); + } + } + + public function executeShowArticleAttachments() + { + $id = $this->getRequestParameter("article_id"); + $this->article = ArticlePeer::retrieveByPK($id); + $this->forward404Unless($this->article); + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_component('articles', 'articleAttachments', array("article" => $this->article))); + } + + public function executeAttachToArticle() + { + $user = $this->getUser(); + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + $this->forward404Unless($user->isAuthenticated()); + + $access = ArticlePeer::getArticleTypesByPermission($user); + $article_id = $this->getRequestParameter("article_id"); + $file_id = $this->getRequestParameter("file_id"); + + $this->forward404Unless($article_id && $file_id); + + $article = ArticlePeer::retrieveByPK($article_id); + $this->forward404Unless(isset($access[$article->getArticleType()])); + + + $file = ArticleFilePeer::retrieveByPK($file_id); + + $this->forward404Unless($article && $file); + + $attachment = new ArticleAttachment; + $attachment->setArticleFile($file); + $article->addArticleAttachment($attachment); + $article->setBannerFileId($file->getId()); + $attachment->save(); + $article->save(); + + return $this->renderText(""); + } + + public function executeAttachBannerToArticle() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + $this->forward404Unless($this->getUser()->isAuthenticated()); + + $access = ArticlePeer::getArticleTypesByPermission($this->getUser()); + $article_id = $this->getRequestParameter("article_id"); + $file_id = $this->getRequestParameter("banner"); + + $this->forward404Unless($article_id && $file_id); + + $access = ArticlePeer::getArticleTypesByPermission($this->getUser()); + $article = ArticlePeer::retrieveByPK($article_id); + $attachment = ArticleAttachmentPeer::retrieveByPK($file_id); + $file = $attachment->getArticleFile(); + + $this->forward404Unless($article && $file); + $this->forward404Unless(isset($access[$article->getArticleType()])); + + $article->setBannerFileId($file->getId()); + $article->save(); + + $this->forward("articles", "showArticleAttachments"); + } + + public function executeNukeAttachment() + { + $article_id = $this->getRequestParameter("article_id"); + $attachment_id = $this->getRequestParameter("attachment_id"); + + $this->forward404Unless($article_id && $attachment_id); + $this->forward404Unless($this->getUser()->isAuthenticated()); + + $access = ArticlePeer::getArticleTypesByPermission($this->getUser()); + $article = ArticlePeer::retrieveByPK($article_id); + $this->forward404Unless(isset($access[$article->getArticleType()])); + + $attachment = ArticleAttachmentPeer::retrieveByPK($attachment_id); + if ($attachment->getArticleId() != $article_id) + { + // H4x0R alert, just ignore him + return; + } + $attachment->delete(); + + $this->forward("articles", "showArticleAttachments"); + } + + public function executeNukeArtworkRelation() + { + $article_id = $this->getRequestParameter("article_id"); + $artwork_id = $this->getRequestParameter("artwork_id"); + + $this->forward404Unless($article_id && $artwork_id); + $this->forward404Unless($this->getUser()->isAuthenticated()); + + $access = ArticlePeer::getArticleTypesByPermission($this->getUser()); + $article = ArticlePeer::retrieveByPK($article_id); + $this->forward404Unless(isset($access[$article->getArticleType()])); + + $artwork = ArticleArtworkRelationPeer::retrieveByPK($artwork_id); + if ($artwork->getArticleId() != $article_id) + { + // H4x0R alert, just ignore him + return; + } + $artwork->delete(); + + $this->forward("articles", "showArticleArtworkRelations"); + } + + public function executeShowArticleArtworkRelations() + { + $id = $this->getRequestParameter("article_id"); + $this->article = ArticlePeer::retrieveByPK($id); + $this->forward404Unless($this->article); + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_component('articles', 'articleRelatedArtworks', array("article" => $this->article))); + } + + /** + * Drag-and-drop list to order articles. + * + */ + public function executeOrderArticles() + { + $this->forward404Unless($this->getUser()->isAuthenticated() && + $this->getUser()->hasCredential('staff')); + //If article type isn't set, choose regular + $this->article_type = $this->getRequestParameter('status') ? + $this->getRequestParameter('status') : + ArticlePeer::REGULAR_ARTICLE; + + //If article id is given, this article should have a different background in the list + $this->article_id = $this->getRequestParameter('article') ? + $this->getRequestParameter('article') : + null; + + //Return an array of matching articles + $this->articles = ArticlePeer::getAllByOrder($this->article_type); + + } + + public function executeOrderArticlesUpdate() + { + $this->forward404Unless($this->getUser()->isAuthenticated() && + $this->getUser()->hasCredential('staff')); + + $theorder = 1; + + //Add order to articles as array is traversed + try + { + foreach ($this->getRequestParameter('article_ordered_list', array()) as $article) + { + ArticlePeer::setArticleOrder($theorder, $article); + $theorder++; + } + } + catch(Exception $e){ + return $this->renderText("Rekkefølgen er ikke lagret [Error]."); + } + return $this->renderText('Ny rekkefølge på artikler er lagret.'); + } +} + diff --git a/apps/reaktor/modules/articles/actions/components.class.php b/apps/reaktor/modules/articles/actions/components.class.php new file mode 100644 index 0000000..67727a4 --- /dev/null +++ b/apps/reaktor/modules/articles/actions/components.class.php @@ -0,0 +1,189 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +class articlesComponents extends sfComponents +{ + /** + * Show article relations + * + */ + function executeArticleRelations() + { + $this->related_articles = ArticleArticleRelationPeer::getRelatedArticles($this->article); + $this->unrelatedArticles = $this->article->getUnrelatedArticles(); + } + + /** + * Show (and edit) article expiration date + * + */ + function executeExpirationDate() + { + $this->date = ''; + if ($this->article->getExpiresAt()) + { + $this->date = $this->article->getExpiresAt(); + } + } + + /** + * Shows the article calendar in the sidebar + * + */ + function executeArticleCalendar() + { + $this->only = (isset($this->only)) ? $this->only : 0; + $this->edit = (isset($this->edit)) ? $this->edit : 0; + $this->article_id = (isset($this->article_id)) ? $this->article_id : 0; + $this->status = (isset($this->status)) ? $this->status : "all"; + $this->live = (isset($this->live) ? $this->live : 1); + $this->chosen_format = (isset($this->chosen_format)) ? $this->chosen_format : 0; + $this->article = ($this->article_id) ? ArticlePeer::retrieveByPK($this->article_id) : new Article(); + + if ($this->article_type == ArticlePeer::HELP_ARTICLE) + { + $this->formats = array(); + if (!$this->chosen_format && $this->article_id) + { + $formats = $this->article->getSubreaktors(true); + $this->chosen_format = array_shift($formats); + } + $subreaktors = $this->live ? SubreaktorPeer::getLiveReaktors('subReaktor') : SubreaktorPeer::getSubReaktors(); + foreach ($subreaktors as $areaktor) + { + if ($this->chosen_format && $this->chosen_format == $areaktor->getReference()) + { + $format = array('name' => $areaktor->getName(), 'articles' => ArticleSubreaktorPeer::getHelpArticleArchive($this->chosen_format, $this->status)); + } + else + { + $format = array('name' => $areaktor->getName(), 'articles' => array()); + } + $this->formats[] = array($areaktor->getReference() => $format); + } + + } + elseif (in_array($this->article_type, array(ArticlePeer::INTERNAL_ARTICLE, ArticlePeer::FOOTER_ARTICLE, ArticlePeer::SPECIAL_ARTICLE))) + { + $this->articles = array((int) $this->article_type => ArticlePeer::getByFieldAndOrType($this->article_type, 'title', null, null, $this->status)); + uasort($this->articles[$this->article_type], array($this, 'sortArticleByTitle')); + } + else + { + $this->articles = ArticlePeer::retrieveAllSortedByTypeYearAndMonth($this->only, $this->status); + } + } + + /** + * shows a list of articles for a given month + * + */ + function executeMonthlist() + { + $this->articles = ArticlePeer::getByFieldAndOrType($this->article_type, 'date', $this->year, $this->month, !$this->edit ? ArticlePeer::PUBLISHED : 0); + } + + /** + * Shows created&updated by and dates + * + */ + function executeListCreators() + { + $created_by = null; + $created_at = null; + $updated_by = null; + $updated_at = null; + + if (isset($this->article) && $this->article instanceof Article) + { + $article = $this->article; + $created_by = sfGuardUserPeer::retrieveByPK($article->getAuthorId()); + $created_at = $article->getCreatedAt(); + if ($updated_at = $article->getUpdatedAt()) + { + $updated_by = sfGuardUserPeer::retrieveByPK($article->getUpdatedBy()); + } + } + + $this->created_by = $created_by; + $this->created_at = $created_at; + $this->updated_by = $updated_by; + $this->updated_at = $updated_at; + + } + + /** + * Display my page articles (slot) + * + */ + function executeMyPageArticles() + { + $this->articles = ArticlePeer::getByFieldAndOrType(ArticlePeer::MY_PAGE_ARTICLE, 'date', null, null, ArticlePeer::PUBLISHED, 3); + + } + + public function executeArticleAttachments() + { + $tfiles = $this->article->getArticleAttachments(); + $files = array(); + foreach($tfiles as $file) { + $files[$file->getId()] = $file->getArticleFile(); + } + $this->files = $files; + $this->banner = $this->article->getArticleType() == ArticlePeer::THEME_ARTICLE || $this->getRequestParameter("article_type") == ArticlePeer::THEME_ARTICLE; + $this->bannerid = $this->article->getBannerFileId(); + } + + public function executeArticleRelatedArtworks() + { + $tfiles = $this->article->getArticleArtworkRelations(); + $files = array(); + foreach($tfiles as $artwork) + { + $files[$artwork->getId()] = $artwork->getReaktorArtwork(); + } + $this->files = $files; + } + + public function executeFrontPageArticles() + { + $this->theme_article = ArticlePeer::getThemeArticle('frontpage'); + if (!$this->theme_article instanceof Article) + { + $this->articles = ArticlePeer::getByFieldAndOrType(ArticlePeer::REGULAR_ARTICLE, 'date', null, null, ArticlePeer::PUBLISHED, 2, 'frontpage'); + } + } + + public function executeArticleBanner() + { + $this->banner = null; + $banner_id = $this->article->getBannerFileId(); + if ($banner_id) { + $this->banner = ArticleFilePeer::retrieveByPK($banner_id); + } + } + + /** + * Sorts articles by translated title if exists + * + * @param Article $article_a + * @param Article $article_b + * + * @returns array + */ + public function sortArticleByTitle($article_a, $article_b) + { + return (strcmp ($article_a->getTitle(),$article_b->getTitle())); + } + +} + diff --git a/apps/reaktor/modules/articles/config/security.yml b/apps/reaktor/modules/articles/config/security.yml new file mode 100644 index 0000000..9ca7946 --- /dev/null +++ b/apps/reaktor/modules/articles/config/security.yml @@ -0,0 +1,3 @@ +all: + is_secure: off + diff --git a/apps/reaktor/modules/articles/config/view.yml b/apps/reaktor/modules/articles/config/view.yml new file mode 100644 index 0000000..7d15d15 --- /dev/null +++ b/apps/reaktor/modules/articles/config/view.yml @@ -0,0 +1,8 @@ +editSuccess: + javascripts: [lightwindow, effects] #tiny_mce/tiny_mce + stylesheets: [/css/genericajax: {media: all}, /css/lightwindow: {media: all}] + +orderArticlesSuccess: + javascripts: [effects] + stylesheets: [/css/genericajax: {media: all} ] + \ No newline at end of file diff --git a/apps/reaktor/modules/articles/templates/_articleAttachments.php b/apps/reaktor/modules/articles/templates/_articleAttachments.php new file mode 100644 index 0000000..fb9daaa --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_articleAttachments.php @@ -0,0 +1,62 @@ + + +
    +

    + + "banner_form")); ?> + +
    + + +

    image_tag("/js/tiny_mce/plugins/upload/img/upload.gif"))); ?>

    + + + + +
    +
    + + +
      + $file): ?> + +
    • + + getId() : false ?> + "setBanner();")); ?> + + + + "10", )), array( + 'update' => 'article_attachments_container', + 'url' => '@nuke_article_attachment?attachment_id='.$id. '&article_id=' . $article->getId(), + 'loading' => "Element.show('attachment_delete')", + 'complete' => "setTimeout('Element.hide(\'attachment_delete\')', 500)", + 'confirm' => __('Are you sure you wish to remove %attachment% from this article?', array('%attachment%' => $file)), + )); ?> + + getFullPath()); + if ($size && ($size[0] > 240 || $size[1] > 160)): ?> + "message")); ?> + + "message")); ?> + + +
    • + + +
    • + +
    + + + + + + +
    + diff --git a/apps/reaktor/modules/articles/templates/_articleCalendar.php b/apps/reaktor/modules/articles/templates/_articleCalendar.php new file mode 100644 index 0000000..e22160b --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_articleCalendar.php @@ -0,0 +1,147 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript','Date'); + +reaktor::addJsToFooter("$('article_calendar_container').setStyle({height: $('sidebar').offsetHeight + 'px'});"); + +if ($only): + $types = is_array($only) ? $only : array($only => __("Archive")); +else: + /*$only = false;*/ + $types = ArticlePeer::getArticleTypesByPermission($sf_user); +endif; + +?> + +
    +

    + +

    + $type_name): ?> +
    + +

    + + +

    +
    + + +
      + + getId() == $anarticle->getId()): ?> +
    • getTitle(); ?>
    • + + +
    • getTitle(), '@editarticle?article_id='.$anarticle->getId()); ?>
    • + +
    • getTitle(), $anarticle->getLink()); ?>
    • + + + +
    + + + + $format): //Print the rest of the formats?> +

    + 'article_calendar', + 'url' => '@articlecalendar_type?article_type='.$type_id.'&article_id='.$article->getId(). + '&edit='.$edit.(($only) ? '&only='.$only : ''). + '&chosen_format='.$reference. '&status=' .$status. + '&live='.$live + ));?> +

    + +
      + 0): ?> + + getId() == $view_article->getId()): //This is the article being viewd?> +
    • getTitle(); ?>
    • + + +
    • getTitle(), '@editarticle?article_id='.$view_article->getId()); ?>
    • + +
    • getTitle(), $view_article->getLink()); ?>
    • + + + + +
    • + +
    +
    + + + + +
      + $a): ?> +
    • + +
        + $as): ?> +
      • + () + +
          + + getId() == $anarticle->getId()): ?> +
        • getTitle(); ?>
        • + + +
        • getTitle(), '@editarticle?article_id='.$anarticle->getId()); ?>
        • + +
        • getTitle(), $anarticle->getLink()); ?>
        • + + + +
        + +
      • + +
      +
    • + +
    + +

    +
    + + + + + + 'article_calendar', + 'url' => '@articlecalendar_type?article_type='.$type_id.'&edit='.$edit.(($only) ? '&only='.$only : ''). + '&article_id='.$article->getId(). '&only=' .$only. '&status=' .$status. + '&live='.$live + ));?> + + + + + + diff --git a/apps/reaktor/modules/articles/templates/_articleList.php b/apps/reaktor/modules/articles/templates/_articleList.php new file mode 100644 index 0000000..8daf869 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_articleList.php @@ -0,0 +1,81 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + $mode = (isset($mode)) ? $mode : 'full'; + $current = current($articles); + if ($current) { + $type = current($articles)->getArticleType(); + } + else { + $type = -1; // Just use the default count + } + $breakAt = ArticlePeer::getShowCountFor($type); + $count = 0; + +?> + +
      + + + + $breakAt) break; ?> + getContent(); ?> +
    • + + getBannerFile()->getDirectLink()) ; + $exts = split("[/\\.]", $filename) ; + $n = count($exts)-1; + $exts = $exts[$n]; + ?> + + + + '. + ' '. + ''. + ''. + ''; ?> + + + getBannerFile()->getDirectLink(), array("alt" => $article->getTitle())), $article->getLink()); ?> + + + + getTitle(), $article->getLink()); ?> + +
      getTitle(); ?>
      + getIngress() : $article->getTeaser(0, $tlen, $tcut, ArticlePeer::INGRESS) ); ?> + + + + $1', $article->getTeaser(0, $len, $cut)) ?> + + + $cut) || !isset($len, $cut) && trim($content)): ?> + getLink()); ?> + + +
    • + + + +
    + + diff --git a/apps/reaktor/modules/articles/templates/_articleRelatedArtworks.php b/apps/reaktor/modules/articles/templates/_articleRelatedArtworks.php new file mode 100644 index 0000000..d37e7c2 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_articleRelatedArtworks.php @@ -0,0 +1,27 @@ + + +
    +

    +
      + $file): ?> +
    • + getTitle() ?> + "10", )), array( + 'update' => 'article_artworks_container', + 'url' => '@nuke_related_artwork_from_article?artwork_id='.$id. '&article_id=' . $article->getId(), + 'loading' => "Element.show('related_artwork_delete')", + 'complete' => "setTimeout('Element.hide(\'related_artwork_delete\')', 500)", + 'confirm' => __('Are you sure you wish to remove %artwork% from this article?', array('%artwork%' => $file->getTitle())), + )); ?> +
    • + + +
    • + +
    + + +
    + diff --git a/apps/reaktor/modules/articles/templates/_articleRelations.php b/apps/reaktor/modules/articles/templates/_articleRelations.php new file mode 100644 index 0000000..02208a6 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_articleRelations.php @@ -0,0 +1,83 @@ + $article)); + * + * The component needs to pass the following: + * $article- An article object + * + * The controller passes the following + * $related_articles - an array of article objects + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'wai'); +?> + +
    + 0): //There are articles to relate to?> + + 'relate_article', + 'url' => '@relatearticle?id='.$article->getId(), + 'loading' => "Element.show('relate_article_ajax_indicator')", + 'complete' => "Element.hide('relate_article_ajax_indicator')", + 'script' => true), array( + 'class' => 'relate_article_form', + 'id' => 'relate_article_form', + 'name' => 'relate_article_form' + )) ?> + + +
    + + + + __('--- Select an article to relate ---') + ))) ?> + + 'submit' + )) ?> + + + + + 0) : //print list of all related articles?> + +

    + + +
    diff --git a/apps/reaktor/modules/articles/templates/_editarticlecontents.php b/apps/reaktor/modules/articles/templates/_editarticlecontents.php new file mode 100644 index 0000000..8e7d708 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_editarticlecontents.php @@ -0,0 +1,267 @@ + $article, + * 'buttons' => $show_attachments_edit)); + * + * $article : Article Object - The article to be edited + * $buttons : boolean - If true, display the attach artwork to this article button in tinymce + * + * PHP version 5 + * + * @author Daniel Andre Eikeland + * @author Hannes Magnusson + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @param Article $article The article to be edited + * @param boolean $buttons If true, display the attach artwork to this article button in tinymce + */ + +$article_types = ArticlePeer::getArticleTypesByPermission($sf_user); +$article_types = array(0 => ' -- ' . sfContext::getInstance()->getI18N()->__('Please select an article type') . ' -- ') + $article_types; +$statuses = array( + ArticlePeer::DRAFT => __("Draft"), + ArticlePeer::PUBLISHED => __("Publish"), + ArticlePeer::ARCHIVED => __("Archive"), + //ArticlePeer::DELETED => __("Delete"), +); + +$buttons_line = array(); +if($buttons) +{ + $buttons_line += array("artworklist", "upload"); +} +if($article->getArticletype() == ArticlePeer::THEME_ARTICLE) +{ + $buttons_line[] = 'insertbanner'; +} + +use_helper('wai'); +?> + + + + +
    + getId()): ?> + + + getId()); ?> + getId()) ?> + +
    + + getArticletype())); ?> +
    + getId()): ?> +

    + +

    "
    ".reaktor_link_to($article->getTitle(), "@article?permalink=".$article->getPermalink()))); ?>

    + $article)); ?> + +
    + + hasTranslatableTitle()): ?> +
    + $langName): ?> + "language_label")); ?> + getTitle($lang)); ?> +
    + + + + getParameter('article_title') ? $sf_request->getParameter('article_title') : $article->getBaseTitle())); ?> + + getPermalink()): ?> +
    ;"> + "display:inline;")); ?> + +
    + + + + + + getParameter('article_ingress') ? $sf_request->getParameter('article_ingress') : $article->getIngress()), array('size' => '80x32', 'class' => 'article_edit_area')); ?> + + + getParameter('article_ingress') ? $sf_request->getParameter('article_ingress') : $article->getIngress())); */?> + + + getParameter('article_content') ? $sf_request->getParameter('article_content') : $article->getContent()), array('size' => '80x52', 'class' => 'article_edit_area')); ?> + +
    + getId()): ?> +
      + +
    • + getIsSticky()); ?> + "display:inline;")); ?> +
    • + + getArticleType() == ArticlePeer::THEME_ARTICLE || $article->getArticleType() == ArticlePeer::REGULAR_ARTICLE): //Only display frontpage option for theme and regular articles?> + +
    • + + + getFrontpage() & ArticlePeer::REAKTOR_FRONTPAGE ); ?> + "display:inline;")); ?> +
    • +
    • + + getFrontpage() & ArticlePeer::SUBREAKTOR_FRONTPAGE); ?> + "display:inline;")); ?> +
    • + + + +
    + + +

    + getId() == 0): ?> + + + getArticleStatus()), array('onChange' => 'javascript:this.form.submit();')); ?> + + +

    +
    + + '; ?> +
    + diff --git a/apps/reaktor/modules/articles/templates/_expirationDate.php b/apps/reaktor/modules/articles/templates/_expirationDate.php new file mode 100644 index 0000000..bc5f942 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_expirationDate.php @@ -0,0 +1,44 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + use_helper('Javascript'); + +?> +
    +

    +

    + 'article_expiration_date', + 'url' => '@setarticleexpirationdate?article_id='.$article->getId(), + 'loading' => "Element.show('relate_article_ajax_indicator')", + 'complete' => "Element.hide('relate_article_ajax_indicator')", + 'script' => true), array( + 'id' => 'article_setexpirationdate_form', + 'name' => 'article_setexpirationdate_form' + )); ?> + + false, + 'culture' => $sf_user->getCulture(), + 'year_start' => date('Y'), + 'year_end' => date('Y')+2, + 'date_seperator' => ' ', + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) + )); ?> + + '; ?> + get("expiry_date") && !form_has_error('expiry_date')): ?> + + +
    + diff --git a/apps/reaktor/modules/articles/templates/_frontPageArticles.php b/apps/reaktor/modules/articles/templates/_frontPageArticles.php new file mode 100644 index 0000000..09dd2d6 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_frontPageArticles.php @@ -0,0 +1,25 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + +
    + $theme_article, 'mode' => 'theme')); ?> +
    + +
    + $articles)); ?> +
    + + diff --git a/apps/reaktor/modules/articles/templates/_listCreators.php b/apps/reaktor/modules/articles/templates/_listCreators.php new file mode 100644 index 0000000..e09ede8 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_listCreators.php @@ -0,0 +1,41 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + +
    + +
    + + "".$created_by."", + "%date%" => "".date("d/m/Y", strtotime($created_at)), + "%time%" => date("H:i", strtotime($created_at))."")); ?> + +
    + +
    + + "".$updated_by."", + "%date%" => "".date("d/m/Y", strtotime($updated_at)), + "%time%" => date("H:i", strtotime($updated_at))."")); ?> + +
    + + +
    \ No newline at end of file diff --git a/apps/reaktor/modules/articles/templates/_monthlist.php b/apps/reaktor/modules/articles/templates/_monthlist.php new file mode 100644 index 0000000..3423776 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_monthlist.php @@ -0,0 +1,22 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + + getId() == $anarticle->getId()): ?> +
  • getTitle(); ?>
  • + + +
  • getTitle(), '@editarticle?article_id='.$anarticle->getId()); ?>
  • + +
  • getTitle(), $anarticle->getLink()); ?>
  • + + + diff --git a/apps/reaktor/modules/articles/templates/_myPageArticles.php b/apps/reaktor/modules/articles/templates/_myPageArticles.php new file mode 100644 index 0000000..15f2ec4 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/_myPageArticles.php @@ -0,0 +1,16 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + +
    + $articles)); ?> +
    + diff --git a/apps/reaktor/modules/articles/templates/articleRelationsSuccess.php b/apps/reaktor/modules/articles/templates/articleRelationsSuccess.php new file mode 100644 index 0000000..2824a09 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/articleRelationsSuccess.php @@ -0,0 +1,17 @@ + + + $article)) ?> \ No newline at end of file diff --git a/apps/reaktor/modules/articles/templates/editSuccess.php b/apps/reaktor/modules/articles/templates/editSuccess.php new file mode 100644 index 0000000..f5ddae0 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/editSuccess.php @@ -0,0 +1,80 @@ + + * @author June Henriksen + * @author Hannes Magnusson + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper('Javascript', 'button'); +?> +getId()): ?> +
    + $year, 'month' => $month, 'article_type' => $article_type, 'article_id' => $article->getId(), 'edit' => 1, 'live' => 0)); ?> +
    + +
    + hasErrors()): ?> +

    + + +

    + +
    + $article, + 'buttons' => $show_attachments_edit)); ?> +
    + + + +
    + $article)); ?> +
    + + +
    + $article)); ?> +
    + +
    + + $article)); ?> + +
    +
    + +
    + $article)) ?> +
    + + + $article, + 'banner' => $show_banner,)) ?> + + + $article)) ?> + + + +

    + + getArticleType().'&article='.$article->getId(), array( + 'class' => "lightwindow", + "closetext" => __("close"), + 'params' => "lightwindow_type=external,lightwindow_width=980,lightwindow_height=800", + 'title' => 'Artikkelprioritering')) ?> + + + +
    + diff --git a/apps/reaktor/modules/articles/templates/listSuccess.php b/apps/reaktor/modules/articles/templates/listSuccess.php new file mode 100644 index 0000000..05b83ff --- /dev/null +++ b/apps/reaktor/modules/articles/templates/listSuccess.php @@ -0,0 +1,4 @@ +
    + $year, 'month' => $month, 'article_type' => $article_type, 'article_id' => $article->getId(), 'edit' => 1, 'status' => isset($status) ? $status : 'all')); ?> +
    + diff --git a/apps/reaktor/modules/articles/templates/orderArticlesSuccess.php b/apps/reaktor/modules/articles/templates/orderArticlesSuccess.php new file mode 100644 index 0000000..8e018bf --- /dev/null +++ b/apps/reaktor/modules/articles/templates/orderArticlesSuccess.php @@ -0,0 +1,94 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('content', 'Javascript'); +?> + + + ArticlePeer::getArticleTypeName(ArticlePeer::REGULAR_ARTICLE), + ArticlePeer::FOOTER_ARTICLE => ArticlePeer::getArticleTypeName(ArticlePeer::FOOTER_ARTICLE), + ArticlePeer::INTERNAL_ARTICLE => ArticlePeer::getArticleTypeName(ArticlePeer::INTERNAL_ARTICLE), + ArticlePeer::MY_PAGE_ARTICLE => ArticlePeer::getArticleTypeName(ArticlePeer::MY_PAGE_ARTICLE), + ); ?> + +
    + + + 'javascript:this.form.submit();')); ?> + + + + + + + + +
    + +
    + +
    +
    + + +
      + +
    • getId()) echo 'style="background-color: #F58426"'?>> +
      getTitle().' ['.$article->getStatus().']'; ?>
      + getTeaser(0, $tlen, $tcut, ArticlePeer::INGRESS); ?> + getTeaser(0, $len, $cut) ?> + $cut) || !isset($len, $cut) && $article->getContent()): ?> + getLink()); ?> + +
    • + + +
    + + + + + + + diff --git a/apps/reaktor/modules/articles/templates/viewSuccess.php b/apps/reaktor/modules/articles/templates/viewSuccess.php new file mode 100644 index 0000000..e16ef77 --- /dev/null +++ b/apps/reaktor/modules/articles/templates/viewSuccess.php @@ -0,0 +1,116 @@ + + * @author Russell Flynn + * @author June Henriksen + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + +
    +getArticleType(), array(ArticlePeer::THEME_ARTICLE, ArticlePeer::MY_PAGE_ARTICLE, ArticlePeer::REGULAR_ARTICLE))): + include_component("articles", "articleCalendar", array( + "article_type" => $article->getArticleType(), + "only" => $article->getArticleType(), + "article" => $article, + "article_id" => $article->getId(), + "edit" => 0, + "month" => date("n", strtotime($article->getUpdatedAt())), + )); + /*else: + include_component("articles", "browseTypes", array("view_article" => $article, 'edit' => 0)); + endif;*/ + //include_component('articles', 'articleCalendar', array('year' => $year, 'month' => $month, 'article_type' => $article_type, 'article_id' => $article->getId())); +?> +
    +
    +
    + false, 'user_id' => false, 'article_id' => $article->getId(), 'list' => 'article', 'nofavload' => 'true')); ?> +
    + +

    + getTitle()?> + hasCredential("staff")): ?> + [getId()); ?>] + +

    + getCreatedAt())); + $changed = strftime("%e. %B %Y", strtotime($article->getUpdatedAt())); + ?> +
    +
    +
    getCreatedAt(),'d. MMMM yyyy'); ?>
    + +
    +
    getUpdatedAt(),'d. MMMM yyyy'); ?>
    + +
    + getIngress()): ?> +

    getParsedIngress(); ?>

    + + +
    + getParsedContent(); ?> +
    + +
    + getRelatedArticles(true)):?> +

    + + + + getRelatedArtwork()):?> +

    +

    + + + + getTags()):?> +

    +

    + $tags)) ?> + + + + getArticleAttachments()): ?> + + getArticleType() == ArticlePeer::THEME_ARTICLE) && count($attachments) == 1 ) break; ?> +

    +

    +
      + + + getArticleFile()->getId() == $article->getBannerFileId()) continue ?> +
    • getArticleFile()->getFilename(), array("href" => $attachment->getArticleFile()->getDirectLink()))?>
    • + +
    + + +
    + diff --git a/apps/reaktor/modules/articles/validate/edit.yml b/apps/reaktor/modules/articles/validate/edit.yml new file mode 100644 index 0000000..531092f --- /dev/null +++ b/apps/reaktor/modules/articles/validate/edit.yml @@ -0,0 +1,18 @@ +methods: [ post ] + +fillin: + enabled: true + param: + content_type: xml + +fields: + article_type: + sfNumberValidator: + nan_error: "You must specify an article type" + min: 1 + min_error: "You must specify an article type" + sfRegexValidator: + match: Yes + match_error: Only letters (A-Å), numbers, and -_? are valid characters + pattern: /^([A-Za-z0-9\?_-\søåæäöØÅÆÖÄ])+$/ + diff --git a/apps/reaktor/modules/articles/validate/relateArticle.yml b/apps/reaktor/modules/articles/validate/relateArticle.yml new file mode 100644 index 0000000..14b12c5 --- /dev/null +++ b/apps/reaktor/modules/articles/validate/relateArticle.yml @@ -0,0 +1,8 @@ +fillin: + enabled: true + +fields: + relate_article_select: + required: + msg: Please choose article to relate + \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/actions/actions.class.php b/apps/reaktor/modules/artwork/actions/actions.class.php new file mode 100644 index 0000000..56c2cc4 --- /dev/null +++ b/apps/reaktor/modules/artwork/actions/actions.class.php @@ -0,0 +1,1674 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * artwork actions. + * + * @package Reaktor + * @subpackage Artwork + * @author Daniel Andre Eikeland + * @author Russ Flynn + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class artworkActions extends sfActions +{ + /** + * Forward to list artwork + * + * @return void + */ + public function executeIndex() + { + $this->forward('artwork', 'list'); + } + + public function executeShowXML() + { + $this->setFlash('format', 'xspf'); + $this->forward('artwork', 'show'); + } + + public function executeShowMetadata() + { + if ($this->getUser()->hasCredential('viewmetadata')) + { + $this->setFlash('template', 'metadata'); + } + $this->forward('artwork', 'show'); + } + + public function executeRemoveMetadata() + { + $c = new Criteria(); + $c->add(FileMetadataPeer::ID, $this->getRequestParameter('id')); + $res = FileMetadataPeer::doDelete($c); + return $this->renderText(''); + } + + /** + * Show a specific work of art + * + * @return void + */ + public function executeShow() + { + $this->logMessage("Starting the executeShow action"); + $this->editmode = $this->getFlash('editmode'); + $this->forward404Unless($this->getRequestParameter('id')); + + // Create a new genericArtwork object based on the id parameter + + try + { + $this->artwork = new genericArtwork($this->getRequestParameter('id')); + } + catch (Exception $e) + { + // Throw a 404 error if the artwork doesn't exist + $this->forward404(); + } + + $this->logMessage("After getting artwork with ID: ".$this->getRequestParameter('id')); + + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + if (!(in_array(Subreaktor::getProvidedLokalReference(), $this->artwork->getSubreaktors(true)))) + { + $this->logMessage("The artwork was not in the specified lokalreaktor"); + if (!(in_array($this->artwork->getUser()->getResidenceId(), Subreaktor::getProvidedLokalreaktor()->getResidences()))) + { + $this->forward404(); + } + else + { + $this->logMessage("But the user who published it lives in the area defined by the lokalreaktor"); + } + } + } + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + $this->logMessage("The artwork was not in the specified subreaktor"); + $this->forward404Unless(in_array(Subreaktor::getProvidedSubreaktorReference(), $this->artwork->getSubreaktors(true))); + } + + // Throw a 404 error if the artwork can't be viewed by the user + $this->forward404Unless($this->artwork->isViewable()); + $this->usercanedit = ($this->getUser()->isAuthenticated() && ($this->getUser()->getGuardUser()->getId() == $this->artwork->getUserId() || $this->getUser()->hasCredential('editusercontent'))) ? true : false; + + /* + // Throw a 404 error if the title isn't correct and the user is not the author, or if the title is not set in the url + if (($this->artwork->getTitle() != urlencode($this->getRequestParameter('title')) && $this->usercanedit == false && $this->getFlash('format') != 'xspf') || ( $this->getFlash('format') != 'xspf' && $this->getRequestParameter('title') == '')) + { + print $this->getFlash('format'); + $this->forward404(); + }*/ + + if ($this->getRequest()->isXmlHttpRequest()) + { + $this->stripmode = true; + } + else + { + $this->stripmode = false; + } + // Get the artworkfiles and check if there is more than one file + $awfiles = $this->artwork->getFiles(); + if (count($awfiles) > 1 && $this->getRequestParameter('file') != '') + { + // If we have specified a file id and there are more than one file in the artwork + try + { + $this->thefile = $this->artwork->getFile($this->getRequestParameter('file')); + } + catch (Exception $e) + { + // Throw a 404 error if the specified file isn't found + $this->forward404(); + } + } + else + { + // If there is only one file in the artwork, or no file id is specified, use the first file + $this->thefile = array_shift($awfiles); + } + + if ($this->getFlash('format') == 'xspf') + { + sfLoader::loadHelpers(array('Partial')); + $this->getResponse()->setHttpHeader('Content-Type', 'text/xml'); + $this->setLayout(false); + $this->setFlash('format', '', false); + $this->setTemplate('xspfOutput'); + } + elseif ($this->getFlash('template') == 'metadata') + { + $this->setFlash('template', '', false); + $this->setTemplate('metadata'); + } + + //Get artwork's matching articles + $articles = $this->artwork->getHelpArticles(); + $this->articles = array(); + if($articles) + { + $this->articles = $articles; + } + } + + /** + * User unlinking/removing a file from artwork + * + * @return void + */ + public function executeUnlink() + { + try + { + $thisFile = new artworkFile($this->getRequestParameter("fileId")); + $thisArtworks = $thisFile->getParentArtworks(); + $thisArtwork = $thisArtworks[$this->getRequestParameter("artworkId")]; + } + catch (Exception $e) + { + $this->forward404(); + } + + $this->forward404Unless($this->getUser()->isAuthenticated() && ($this->getUser()->getGuardUser()->getId() == $thisArtwork->getUserId() || $this->getUser()->hasCredential('editusercontent'))); + switch($this->getRequestParameter("mode")) + { + case "remove": + $thisArtwork->removeFile($thisFile); + $this->redirect(Subreaktor::addSubreaktorToRoute("@show_artwork?id=".$thisArtwork->getId()."&title=".$thisArtwork->getTitle())); + break; + case "create": + $thisArtwork->removeFile($thisFile->getId()); + $newArtwork = new genericArtwork(); + $newArtwork->setCreatedAt(time()); + $newArtwork->setSubmittedAt(time()); + $newArtwork->setTitle($thisFile->getTitle()); + $newArtwork->setUserId($thisFile->getUserId()); + $newArtwork->setArtworkType($thisFile->getIdentifier()); + $newArtwork->save(); + $newArtwork->changeStatus($this->getUser()->getGuardUser()->getId(), 2); // Ready for approval + $newArtwork->addFile($thisFile); + $thisFile->setModifiedAt(); + $thisFile->save(); + $this->redirect(Subreaktor::addSubreaktorToRoute("@show_artwork?id=".$newArtwork->getId()."&title=".$newArtwork->getTitle())); + break; + case "link": + $thisArtwork->removeFile($thisFile->getId()); + $this->redirect("@edit_upload?fileId=".$thisFile->getId()."&link=0"); + break; + default: + $this->forward404(); + break; + } + } + + /** + * Report file + * + * @return void + */ + public function executeReportfile() + { + + if (!$this->getRequest()->isXmlHttpRequest()) + { + //The user should not be here + die(); + } + try + { + $username = $this->getUser()->getGuardUser()->getUsername(); + $userid = $this->getUser()->getGuardUser()->getId(); + $cookiename = md5($username.$this->getRequestParameter('file')); + $this->artwork = new genericArtwork($this->getRequestParameter('id')); + $this->artwork->getFile($this->getRequestParameter('file'))->reportAsUnsuitable($userid); + + $this->getResponse()->setCookie('reported_'.$cookiename, 1, time()+60*60*24*10); + } + catch (Exception $e) + { + $this->forward404(); + } + $this->forward404Unless($this->artwork->isViewable($this->getUser())); + $output = sfContext::getInstance()->getI18n()->__("You have reported this file, it will be reviewed by a staff member shortly"); + + return $this->renderText($output); + } + + /** + * Flag file as ok by resetting reported flag + * + * @return true + */ + public function executeOkFile() + { + if (!$this->getRequest()->isXmlHttpRequest()) + { + //The user should not be here + die(); + } + $this->forward404Unless($this->getUser()->hasCredential('editusercontent')); + $file = new artworkFile($this->getRequestParameter('id')); + $file->reportAsSuitable($this->getUser()->getGuardUser()->getId()); + + return $this->renderText('File marked OK'); + } + + /** + * Flag file as ok by resetting reported flag + * + * @return true + */ + public function executeSuitableFile() + { + if (!$this->getRequest()->isXmlHttpRequest()) + { + //The user should not be here + die(); + } + $this->forward404Unless($this->getUser()->hasCredential('editusercontent')); + $file = new artworkFile($this->getRequestParameter('id')); + $file->reportAsSuitable($this->getUser()->getGuardUser()->getId()); + + return $this->renderText('File marked suitable'); + } + + /** + * Write a message to user explaining why the file has been removed. + * + * @return void + */ + public function executeRemoveFileMessage() + { + $this->forward404Unless($this->getUser()->hasCredential('editusercontent')); + $this->artwork_file = new artworkFile($this->getRequestParameter('id')); + $this->rejectiontypes = RejectionTypePeer::doSelect(new Criteria()); + } + + /** + * Display rejection form again with error messages + * + * @return void + */ + public function handleErrorRemoveFile() + { + $this->forward('artwork', 'removeFileMessage'); + } + + /** + * Remove the file from the artwork, send message to user about it, and log + * it in history. + * + * @return void + */ + public function executeRemoveFile() + { + $fileId = $this->getRequestParameter('id'); + $this->forward404Unless($this->getUser()->hasCredential('editusercontent') && $fileId); + $file = new artworkFile($fileId); + + //reset flag so it is not shown in reported files list + $file->setUnsuitable($this->getUser()->getGuardUser()->getId(), $this->getRequestParameter('rejectionmsg')); + $file->save(); + + //remove from all artworks that this file belongs to + foreach ($file->getParentArtworks() as $artwork) + { + if ($artwork->getFilesCount() == 1) + { + $artwork->changeStatus($this->getUser()->getGuardUser()->getId(), 4, $this->getRequestParameter('rejectionmsg')); + + $artwork->save(); + } + else + { + $artwork->removeFile($fileId); + $artwork->resetFirstFile(); + } + } + + //send email to user + $raw_mail = $this->sendEmail('mail', 'sendRejectArtworkOrFile'); + $this->logMessage($raw_mail, 'debug'); + + $this->redirect('@listrejectedfiles'); + } + + /** + * Executes edit action + * + * @return void + */ + public function executeEdit() + { + try + { + $this->artwork = new genericArtwork($this->getRequestParameter('id')); + $this->firstfile = $this->artwork->getFirstFile(); + } + catch (Exception $e) + { + // Throw a 404 error if the artwork doesn't exist + $this->forward404(); + } + //If artwork has only one file, then tagging should be just on that file object + // fix for issue #466, tag the artwork instead, and let users specifically + // add tags to files if the want to + /*if ($this->artwork->getFilesCount() == 1) + { + $this->objectToTag = $this->firstfile; + } + else + { + $this->objectToTag = $this->artwork; + }*/ + $this->objectToTag = $this->artwork; + + $this->forward404Unless(!$this->artwork->isRemoved() || $this->getUser()->hasCredential("editusercontent")); + + $this->forward404Unless($this->getUser()->isAuthenticated() + && ($this->getUser()->getGuardUser()->getId() == $this->artwork->getUserId() + || $this->getUser()->hasCredential("editusercontent"))); + + if ($this->getRequest()->hasErrors()) + { + return sfView::SUCCESS; + } + + if (strpos(sfContext::getInstance()->getRequest()->getUri(), 'edit_nodecor')) + { + $this->setLayout('no_decor_layout'); + } + + if ($this->getRequest()->getMethod() == sfRequest::POST) + { + if ($this->getRequestParameter("submit_artwork")) + { + + // Get artwork object + $artworkId = $this->getRequestParameter("id"); + $artwork = new genericArtwork($artworkId); + + // Set the artwork submitted + $artwork->setSubmittedAt(time()); + $artwork->changeStatus($this->getUser()->getGuardUser()->getId(), 2); + + // Assign this artwork to an editorial team, then + // trigger notification to the selected team members + + $teamMembers = $artwork->resetEditorialTeam()->getMembers(); + + // + // Create and send e-mail + // + $this->logMessage('Am I gonna send email????', 'debug'); + if (count($teamMembers)) + { + global $mail_data; + $mail_data = array('users' => $teamMembers); + $raw_email = $this->sendEmail('mail', 'editorialTeamNotification'); + $this->logMessage($raw_email, 'debug'); + } + + $artwork->save(); + + // Pass the new artwork object back to the template + $this->artwork = $artwork; + } + } + } + +/** + * Validate edit, the required fields are added by ajax and submitted elsewhere, + * so they can't be validated in the normal way - well, maybe but this is easier + * + * @return boolean only if validation success + */ + public function validateEdit() + { + if ($this->getRequest()->getMethod() != sfRequest::POST) + { + return true; + } + + $artworkId = $this->getRequestParameter("id"); + $artwork = new genericArtwork($artworkId); + + if ($this->getRequestParameter("submit_artwork")) + { + // We need to check subreaktors and categories have been set - tags are optional at this level + $artworkSubreaktors = $artwork->getSubreaktors(false, array("subreaktor")); + if (empty($artworkSubreaktors)) + { + $this->getRequest()->setError("subreaktors", $this->getContext()->getI18n()->__("Please select at least one")); + } + + $artworkCategories = $artwork->getCategories(); + if (!$artworkCategories) + { + $this->getRequest()->setError("categories", $this->getContext()->getI18n()->__("Please select at least one")); + } + + $artworkTags = $artwork->getTags(false, true); + if (!$artworkTags) + { + $this->getRequest()->setError("tags", $this->getContext()->getI18n()->__("Please add at least one tag")); + } + } + + if ($this->getRequest()->hasErrors()) + { + return false; + } + return true; + } + + /** + * Direct form errors back to main template + * + * @return void + */ + public function handleErrorEdit() + { + $this->executeEdit(); + return sfView::SUCCESS; + } + + /** + * Executes update action + * + * @return void + */ + public function executeUpdate() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + $theartwork = new genericArtwork($this->getRequestParameter('id')); + $returntext = ""; + + if ($this->getRequestParameter("getText")) + { + switch ($this->getRequestParameter('field')) + { + case 'description': + $returntext = htmlspecialchars_decode($theartwork->getDescription()); + return $this->renderText($returntext); + break; + default: + $this->forward404(); + break; + } + } + if (!$this->getUser()->isAuthenticated()) + { + return $this->renderText("**Update failed, please refresh the page and try again**"); + } + + if ($this->getUser()->getGuardUser()->getId() == $theartwork->getUserId() || $this->getUser()->hasCredential('viewallcontent')) + { + switch ($this->getRequestParameter('field')) + { + case 'title': + $checkTitle = new myArtworkTitleValidator($this->getRequestParameter()); + $checkTitle->initialize(sfContext::getInstance()); + $error = ""; + $title = $this->getRequestParameter('value'); + + $modifiedField = "Title field modified"; + $translateMe = sfContext::getInstance()->getI18N()->__("Title field modified"); + + if ($checkTitle->execute($title, $error)) + { + $theartwork->setTitle(trim($this->getRequestParameter('value'))); + //$returntext = substr(trim($this->getRequestParameter('value')), 0, sfConfig::get("app_artwork_max_title_length")); + $returntext = sfContext::getInstance()->getI18N()->__("Title updated!"); + } + else + { + $returntext = $this->getContext()->getI18n()->__("FAIL").": **".$error."**"; + } + break; + case 'description': + $description = trim(strip_tags($this->getRequestParameter('value'),"


    ', + $style, + ($coverage_percent == 100 + ? $test_file_name + : '' . $test_file_name . ''), + $coverage_percent) + ); +} + + +/** + * FIX + */ +function write_file_report($analyzed_file, $id, $missing_str) { + global $html_head, $html_tail; + + $file_real_name = SF_ROOT_DIR.'/'.$analyzed_file.'.php'; + $test_file = file_get_contents($file_real_name); + if (!$test_file) { + echo 'failed to read file: ', $file_real_name, "\n"; + } + else { + /* The call to substr removes the tag that surrounds the + * highlighted source code. The tag is added later but then with + * the first line number inside. */ + $test_file = substr(highlight_string($test_file, true), 6); + $test_file = split("
    ", $test_file); + + $html_file = fopen(SF_OUTPUT_DIR . '/' . file_report_file_name($id, $analyzed_file), "w"); + fwrite($html_file, $html_head); + fwrite($html_file, ''); + + $line_info = parse_missing_str($missing_str); + + $prev_bg = 'green'; + for ($i = 0; $i < count($test_file); $i++) { + if (preg_match('/^\s*$/', $test_file[$i])) { + $bg = $prev_bg; + } + elseif (array_key_exists($i+1, $line_info)) { + $bg = 'red'; + } + else { + $bg = 'green'; + } + fwrite($html_file, "" . format_line_number($i+1) . ' '); + fwrite($html_file, $test_file[$i]); + fwrite($html_file, "
    \n"); + $prev_bg = $bg; + } + + fwrite($html_file, $html_tail); + fclose($html_file); + } +} + + +/** + * FIX + */ +function format_line_number($num) { + return str_replace(' ', ' ', sprintf('% 4d', $num)); +} + + +/** + * FIX + */ +function parse_missing_str($missing_str) { + $token = strtok(substr($missing_str, strpos($missing_str, ':')+1), ' '); + $lines = array(); + while ($token !== false) { + if (is_numeric($token)) { + $lines[$token] = 1; + } + else { + /* Range [X - Y] */ + $start = (int)substr($token, 1); + $token = strtok(' '); /* A dash */ + $stop = (int)substr(strtok(' '), 0, -1); + + for ($i = $start; $i <= $stop; $i++) { + $lines[$i] = 1; + } + } + + $token = strtok(' '); + } + return $lines; +} \ No newline at end of file diff --git a/test/bin/reaktorTestBrowser.class.php b/test/bin/reaktorTestBrowser.class.php new file mode 100644 index 0000000..96bba4d --- /dev/null +++ b/test/bin/reaktorTestBrowser.class.php @@ -0,0 +1,437 @@ + + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +// Define bogus missing functions if xdebug is disabled +if (!function_exists("xdebug_call_file")) { + function xdebug_call_file() { + return null; + } + function xdebug_call_line() { + return null; + } +} + +class reaktorTestBrowser extends sfTestBrowser +{ + /** + * Contains the file currently being tested + * + * @var string + */ + private $TESTFILE; + + /** + * Contains the user visible test descriptions + * + * @var array(linenr => testdesc) + */ + private $TESTNAMES = array(); + + /** + * The prepared statement used by the dtor + * @var resource + */ + private static $stmt = null; + + /** + * Stores failure count between tests + * + * @var int + */ + private $lastFailed = 0; + + /** + * Initialize the reaktor test browser, optionally passing + * /path/to/sqlite/db.file + * + * @param string $db SQLite3 db location + */ + public function __construct($db = null) { + // Store the test filename and fetch all the test descriptions + $this->TESTFILE = $filename = (xdebug_call_file() ? xdebug_call_file() : "unknown"); + // Disable per-test-stats if xdebug is disabled + if ($filename != "unknown") { + $this->TESTNAMES = self::getTokens($filename); + } else { + $this->TESTNAMES = array(); + } + + // Prepare the insert statement if we don't have one + if ($filename != "unknown" && self::$stmt === null) { + // ..but first we need to connect to the database + if (!$db) { + $db = "/tmp/tests.db"; + } + $old = file_exists($db); + $pdo = new PDO("sqlite:$db"); + + // If the file didn't exist before we need to create the database then + if (!$old) { + $create = <<< EOT +CREATE TABLE tests ( +filename TINYTEXT, +description TINYTEXT, +line TINYINT, +status TINYINT, +date INT +) +EOT; + + $pdo->exec($create); + } + self::$stmt = $pdo->prepare("INSERT INTO tests ". + "VALUES(:filename, :description, :line, :status, :date)"); + + if (!self::$stmt) { + throw new RuntimeException($pdo->errorInfo()); + } + } + + // sfTestBrowser doesn't have a ctor atm, but it may in the future.. + if (is_callable(array("parent", __FUNCTION__), false)) { + $args = func_get_args(); + return call_user_func_array(array("parent", __FUNCTION__), $args); + } + } + + /** + * Stores the test results in the database + * + * @return void + */ + public function __destruct() { + $filename = $this->TESTFILE; + $t = $_SERVER["REQUEST_TIME"]; + + // Loop over the results and insert into db + foreach($this->TESTNAMES as $nfo) { + $ret = self::$stmt->execute(array( + ":filename" => $filename, + ":description" => $nfo["desc"], + ":line" => (int)$nfo["line"], + ":status" => (int)$nfo["success"], + ":date" => $t, + )); + if (!$ret) { + trigger_error(self::$stmt->errorInfo(), E_USER_WARNING); + break; + } + } + // sfTestBrowser doesn't have a dtor atm, but it may in the future.. + if (is_callable(array("parent", __FUNCTION__), false)) { + $args = func_get_args(); + return call_user_func_array(array("parent", __FUNCTION__), $args); + } + } + + public static function getTokens($filename) { + $tests = array(); + $lastline = -1; + + $count = 0; + foreach (token_get_all(file_get_contents($filename)) as $tokens) { + if ($tokens[0] == T_COMMENT) { + // Only "//" are user-intended-descriptions + if (!($tokens[1][0] == "/" && $tokens[1][1] == "/")) { + continue; + } + + // Chop the comment characters + $testdesc = substr($tokens[1], 2); + $testdesc = trim($testdesc); + + // If it was a multiline comment, merge it + if ($lastline == $tokens[2]-1) { + $tests[$count-1]["desc"] .= "\n" . $testdesc; + } else { + ++$count; + $tests[] = array( + "line" => $tokens[2], + "desc" => ucfirst($testdesc), + "success" => true, + ); + } + $lastline = $tokens[2]; + } + } + return $tests; + } + + /** + * Mark a test as passed/failed + * + * @param mixed $line + * @return void + */ + protected function markTest($line, $pass) { + foreach($this->TESTNAMES as $k => $test) { + if ($test["line"] < $line) { + $mark = $test; + $key = $k; + } + } + $mark["success"] = $pass; + $this->TESTNAMES[$key] = $mark; + } + + // Overwrite various sfTestBrowser methods + public function test() { + // Call the parent with whatever arguments we got + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + // Check if the failure count has increased + if ($this->lastFailed != $failed) { + // Check if it was the test itself that called us + // or if it was a $this->method() call + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + + $this->lastFailed = $failed; + + return $retval; + } + public function call() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function forward() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function isRedirected() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function isStatusCode() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function responseContains() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function isRequestParameter() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function isForwardedTo() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function isResponseHeader() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function checkResponseElement() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function setVar() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function post() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function getResponse() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + public function getRequest() { + $args = func_get_args(); + $retval = call_user_func_array(array("parent", __FUNCTION__), $args); + + $failed = $this->test->failed; + if ($this->lastFailed != $failed) { + if (xdebug_call_file() == $this->TESTFILE) { + $line = xdebug_call_line(); + $this->markTest($line, false); + } + } + $this->lastFailed = $failed; + + return $retval; + } + + // Helper methods for repeated actions + + + /** + * Login as $username, $password to the $uri + * + * @param string $username + * @param string $password + * @param string $uri + * @return reaktorTestBrowser + */ + function login($username, $password, $uri = "/no", $followRedirect = true) { + return $this + ->logout() + ->get($uri) + ->setField('username', $username) + ->setField('password', $password) + ->click('Sign in') && $followRedirect ? + $this->followRedirect() : + $this; + } + + /** + * logout + * + * @param void + */ + function logout() { + sfConfig::set("mypage_mode", false); + sfConfig::set("admin_mode", false); + return $this->get("/no/logout"); + } + +} +# vim: et sw=2 ts=2 + diff --git a/test/bootstrap/functional.php b/test/bootstrap/functional.php new file mode 100644 index 0000000..53b49ce --- /dev/null +++ b/test/bootstrap/functional.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +// guess current application +if (!isset($app)) +{ + $traces = debug_backtrace(); + $caller = $traces[0]; + $array = explode(DIRECTORY_SEPARATOR, dirname($caller['file'])); + $app = array_pop($array); +} + +// define symfony constant +if (!defined('SF_ROOT_DIR')) +{ + define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/../..')); + define('SF_APP', $app); + define('SF_ENVIRONMENT', 'test'); + define('SF_DEBUG', true); +} +// initialize symfony +require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'); + +$ds = DIRECTORY_SEPARATOR; +require_once(SF_ROOT_DIR.$ds.'test'.$ds.'bin'.$ds.'reaktorTestBrowser.class.php'); +// remove all cache +sfToolkit::clearDirectory(sfConfig::get('sf_cache_dir')); + +// initialize test data +$databaseManager = new sfDatabaseManager(); +$databaseManager->initialize(); + +// Clear and load sql table structure +if (!defined("NO_CLEAR")) +{ + $dirHandle = opendir(sfConfig::get('sf_root_dir').'/data/sql'); + while ($file = readdir($dirHandle)) + { + if (substr($file, strlen($file) - 3, 3) == "sql") + { + exec("mysql -u reaktor_user --password=cT0PHPCm reaktor_test < ".sfConfig::get("sf_root_dir")."/data/sql/".$file); + } + } + + // Load the fixtures + $data = new sfPropelData(); + $data->loadData(sfConfig::get('sf_root_dir').'/data/fixtures/'); +} + +// If the magical $extract18n isset and the $i18ndata variable contains data, +// then dump it into file and import it +if (isset($extract18n) && $extract18n && strlen($i18ndata)) { + $fp = tmpfile(); + fwrite($fp, $i18ndata); + $tmp = stream_get_meta_data($fp); + system("mysql -u reaktor_user --password=cT0PHPCm reaktor_test < " . $tmp["uri"]); +} + + diff --git a/test/bootstrap/unit.php b/test/bootstrap/unit.php new file mode 100644 index 0000000..54387ac --- /dev/null +++ b/test/bootstrap/unit.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$_test_dir = realpath(dirname(__FILE__).'/..'); +define('SF_ROOT_DIR', realpath($_test_dir.'/..')); + +// symfony directories +include(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'); + +require_once($sf_symfony_lib_dir.'/vendor/lime/lime.php'); + +include($base_dir.'/plugins/sfModelTestPlugin/bootstrap/model-unit.php'); + +class newLimeTest extends sfPropelTest +{ + + function __construct($fixturesDirOrFile = null) + { + parent::__construct($fixturesDirOrFile); + } + +} + +// initialize test data +$databaseManager = new sfDatabaseManager(); +$databaseManager->initialize(); + +// Clear and load sql table structure +if (!defined("NO_CLEAR")) +{ + $dirHandle = opendir(sfConfig::get('sf_root_dir').'/data/sql'); + while ($file = readdir($dirHandle)) + { + if (substr($file, strlen($file) - 3, 3) == "sql") + { + exec("mysql -u reaktor_user --password=cT0PHPCm reaktor_test < ".sfConfig::get("sf_root_dir")."/data/sql/".$file); + } + } + + // Load the fixtures + $data = new sfPropelData(); + $data->loadData(sfConfig::get('sf_root_dir').'/data/fixtures/'); +} + diff --git a/test/codesniff/Reaktor/Docs/Files/IncludingFileStandard.xml b/test/codesniff/Reaktor/Docs/Files/IncludingFileStandard.xml new file mode 100755 index 0000000..6d115be --- /dev/null +++ b/test/codesniff/Reaktor/Docs/Files/IncludingFileStandard.xml @@ -0,0 +1,24 @@ + + + require_once. Anywhere you are conditionally including a class file (for example, factory methods), use include_once. Either of these will ensure that class files are included only once. They share the same file list, so you don't need to worry about mixing them - a file included with require_once will not be included again by include_once. + ]]> + + + include_once and require_once are statements, not functions. Parentheses should not surround the subject filename. + ]]> + + + + + + + ('PHP/CodeSniffer.php'); + ]]> + + + diff --git a/test/codesniff/Reaktor/Docs/Files/LineLengthStandard.xml b/test/codesniff/Reaktor/Docs/Files/LineLengthStandard.xml new file mode 100755 index 0000000..e4911ef --- /dev/null +++ b/test/codesniff/Reaktor/Docs/Files/LineLengthStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/test/codesniff/Reaktor/Docs/Functions/FunctionCallArgumentSpacingStandard.xml b/test/codesniff/Reaktor/Docs/Functions/FunctionCallArgumentSpacingStandard.xml new file mode 100755 index 0000000..be6f0cc --- /dev/null +++ b/test/codesniff/Reaktor/Docs/Functions/FunctionCallArgumentSpacingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + , $baz, $quux); + ]]> + + + ,$baz,$quux); + ]]> + + + diff --git a/test/codesniff/Reaktor/Docs/Functions/FunctionCallSignatureStandard.xml b/test/codesniff/Reaktor/Docs/Functions/FunctionCallSignatureStandard.xml new file mode 100755 index 0000000..f874227 --- /dev/null +++ b/test/codesniff/Reaktor/Docs/Functions/FunctionCallSignatureStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + ( $bar, $baz, $quux ) ; + ]]> + + + diff --git a/test/codesniff/Reaktor/Docs/Functions/ValidDefaultValueStandard.xml b/test/codesniff/Reaktor/Docs/Functions/ValidDefaultValueStandard.xml new file mode 100755 index 0000000..56196cb --- /dev/null +++ b/test/codesniff/Reaktor/Docs/Functions/ValidDefaultValueStandard.xml @@ -0,0 +1,25 @@ + + + + + + + $persistent = false) +{ + ... +} + ]]> + + + $persistent = false, $dsn) +{ + ... +} + ]]> + + + diff --git a/test/codesniff/Reaktor/Docs/NamingConventions/ValidClassNameStandard.xml b/test/codesniff/Reaktor/Docs/NamingConventions/ValidClassNameStandard.xml new file mode 100755 index 0000000..ea446be --- /dev/null +++ b/test/codesniff/Reaktor/Docs/NamingConventions/ValidClassNameStandard.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/test/codesniff/Reaktor/Docs/NamingConventions/ValidFunctionNameStandard.xml b/test/codesniff/Reaktor/Docs/NamingConventions/ValidFunctionNameStandard.xml new file mode 100755 index 0000000..60841dd --- /dev/null +++ b/test/codesniff/Reaktor/Docs/NamingConventions/ValidFunctionNameStandard.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/test/codesniff/Reaktor/ReaktorCodingStandard.php b/test/codesniff/Reaktor/ReaktorCodingStandard.php new file mode 100755 index 0000000..15c6f19 --- /dev/null +++ b/test/codesniff/Reaktor/ReaktorCodingStandard.php @@ -0,0 +1,60 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ReaktorCodingStandard.php,v 1.6 2007/08/02 23:18:31 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_CodingStandard', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_CodingStandard not found'); +} + +/** + * Reaktor Coding Standard. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @author Russ Flynn + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class PHP_CodeSniffer_Standards_Reaktor_ReaktorCodingStandard extends PHP_CodeSniffer_Standards_CodingStandard +{ + + + /** + * Return a list of external sniffs to include with this standard. + * + * The Reaktor standard uses some generic sniffs. + * + * @return array + */ + public function getIncludedSniffs() + { + return array( + 'Generic/Sniffs/Formatting/MultipleStatementAlignmentSniff.php', + 'Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php', + 'Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', + 'Generic/Sniffs/PHP/LowerCaseConstantSniff.php', + 'Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', + 'Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php', + ); + + }//end getIncludedSniffs() + + +}//end class +?> diff --git a/test/codesniff/Reaktor/Sniffs/Classes/ClassDeclarationSniff.php b/test/codesniff/Reaktor/Sniffs/Classes/ClassDeclarationSniff.php new file mode 100755 index 0000000..6a12fd0 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Classes/ClassDeclarationSniff.php @@ -0,0 +1,108 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ClassDeclarationSniff.php,v 1.4 2007/12/05 03:31:45 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Class Declaration Test. + * + * Checks the declaration of the class is correct. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Classes_ClassDeclarationSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $curlyBrace = $tokens[$stackPtr]['scope_opener']; + $lastContent = $phpcsFile->findPrevious(T_WHITESPACE, ($curlyBrace - 1), $stackPtr, true); + $classLine = $tokens[$lastContent]['line']; + $braceLine = $tokens[$curlyBrace]['line']; + if ($braceLine === $classLine) { + $error = 'Opening brace of a '; + $error .= $tokens[$stackPtr]['content']; + $error .= ' must be on the line after the definition'; + $phpcsFile->addError($error, $curlyBrace); + return; + } else if ($braceLine > ($classLine + 1)) { + $difference = ($braceLine - $classLine - 1); + $difference .= ($difference === 1) ? ' line' : ' lines'; + $error = 'Opening brace of a '; + $error .= $tokens[$stackPtr]['content']; + $error .= ' must be on the line following the '; + $error .= $tokens[$stackPtr]['content']; + $error .= ' declaration; found '.$difference; + $phpcsFile->addError($error, $curlyBrace); + return; + } + + if ($tokens[($curlyBrace + 1)]['content'] !== $phpcsFile->eolChar) { + $type = strtolower($tokens[$stackPtr]['content']); + $error = "Opening $type brace must be on the next line"; + $phpcsFile->addError($error, $curlyBrace); + } + + if ($tokens[($curlyBrace - 1)]['code'] === T_WHITESPACE) { + $prevContent = $tokens[($curlyBrace - 1)]['content']; + if ($prevContent !== $phpcsFile->eolChar) { + $blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar)); + $spaces = strlen($blankSpace); + if ($spaces !== 0) { + $error = "Expected 0 spaces before opening brace; $spaces found"; + $phpcsFile->addError($error, $curlyBrace); + } + } + } + + }//end process() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Commenting/ClassCommentSniff.php b/test/codesniff/Reaktor/Sniffs/Commenting/ClassCommentSniff.php new file mode 100755 index 0000000..ea31caf --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Commenting/ClassCommentSniff.php @@ -0,0 +1,213 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ClassCommentSniff.php,v 1.17 2007/11/26 22:11:18 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'); +} + +if (class_exists('Reaktor_Sniffs_Commenting_FileCommentSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Reaktor_Sniffs_Commenting_FileCommentSniff not found'); +} + +/** + * Parses and verifies the doc comments for classes. + * + * Verifies that : + *
      + *
    • A doc comment exists.
    • + *
    • There is a blank newline after the short description.
    • + *
    • There is a blank newline between the long and short description.
    • + *
    • There is a blank newline between the long description and tags.
    • + *
    • Check the order of the tags.
    • + *
    • Check the indentation of each tag.
    • + *
    • Check required and optional tags and the format of their content.
    • + *
    + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Commenting_ClassCommentSniff extends Reaktor_Sniffs_Commenting_FileCommentSniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_CLASS); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + + $tokens = $phpcsFile->getTokens(); + $find = array( + T_ABSTRACT, + T_WHITESPACE, + T_FINAL, + ); + + // Extract the class comment docblock. + $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); + + if ($commentEnd !== false && $tokens[$commentEnd]['code'] === T_COMMENT) { + $phpcsFile->addError('You must use "/**" style comments for a class comment', $stackPtr); + return; + } else if ($commentEnd === false || $tokens[$commentEnd]['code'] !== T_DOC_COMMENT) { + $phpcsFile->addError('Missing class doc comment', $stackPtr); + return; + } + + $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); + $commentNext = $phpcsFile->findPrevious(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); + + // Distinguish file and class comment. + $prevClassToken = $phpcsFile->findPrevious(T_CLASS, ($stackPtr - 1)); + if ($prevClassToken === false) { + // This is the first class token in this file, need extra checks. + $prevNonComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($commentStart - 1), null, true); + if ($prevNonComment !== false) { + $prevComment = $phpcsFile->findPrevious(T_DOC_COMMENT, ($prevNonComment - 1)); + if ($prevComment === false) { + // There is only 1 doc comment between open tag and class token. + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $stackPtr, false, $phpcsFile->eolChar); + if ($newlineToken !== false) { + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($newlineToken + 1), $stackPtr, false, $phpcsFile->eolChar); + if ($newlineToken !== false) { + // Blank line between the class and the doc block. + // The doc block is most likely a file comment. + $phpcsFile->addError('Missing class doc comment', ($stackPtr + 1)); + return; + } + }//end if + }//end if + }//end if + }//end if + + $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + + // Parse the class comment.docblock. + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'Class doc comment is empty'; + $phpcsFile->addError($error, $commentStart); + return; + } + + // No extra newline before short description. + $short = $comment->getShortComment(); + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $line = ($newlineSpan > 1) ? 'newlines' : 'newline'; + $error = "Extra $line found before class comment short description"; + $phpcsFile->addError($error, ($commentStart + 1)); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in class comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1)); + } + + $newlineCount += $newlineBetween; + } + + // Exactly one blank line before tags. + $tags = $this->commentParser->getTagOrders(); + if (count($tags) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in class comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount)); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + // Check each tag. + $this->processTags($commentStart, $commentEnd); + + }//end process() + + + /** + * Process the version tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processVersion($errorPos) + { + $version = $this->commentParser->getVersion(); + if ($version !== null) { + $content = $version->getContent(); + $matches = array(); + if (empty($content) === true) { + $error = 'Content missing for @version tag in class comment'; + $this->currentFile->addError($error, $errorPos); + } else if ((strstr($content, 'Release:') === false)) { + $error = "Invalid version \"$content\" in class comment; consider \"Release: \" instead"; + $this->currentFile->addWarning($error, $errorPos); + } + } + + }//end processVersion() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Commenting/FileCommentSniff.php b/test/codesniff/Reaktor/Sniffs/Commenting/FileCommentSniff.php new file mode 100755 index 0000000..ef8af97 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Commenting/FileCommentSniff.php @@ -0,0 +1,672 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: FileCommentSniff.php,v 1.25 2007/11/26 22:11:18 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_ClassCommentParser', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_ClassCommentParser not found'); +} + +/** + * Parses and verifies the doc comments for files. + * + * Verifies that : + *
      + *
    • A doc comment exists.
    • + *
    • There is a blank newline after the short description.
    • + *
    • There is a blank newline between the long and short description.
    • + *
    • There is a blank newline between the long description and tags.
    • + *
    • A PHP version is specified.
    • + *
    • Check the order of the tags.
    • + *
    • Check the indentation of each tag.
    • + *
    • Check required and optional tags and the format of their content.
    • + *
    + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +class Reaktor_Sniffs_Commenting_FileCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The header comment parser for the current file. + * + * @var PHP_CodeSniffer_Comment_Parser_ClassCommentParser + */ + protected $commentParser = null; + + /** + * The current PHP_CodeSniffer_File object we are processing. + * + * @var PHP_CodeSniffer_File + */ + protected $currentFile = null; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_OPEN_TAG); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $this->currentFile = $phpcsFile; + + // We are only interested if this is the first open tag. + if ($stackPtr !== 0) { + if ($phpcsFile->findPrevious(T_OPEN_TAG, ($stackPtr - 1)) !== false) { + return; + } + } + + $tokens = $phpcsFile->getTokens(); + + // Find the next non whitespace token. + $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + // Ignore vim header. + if ($tokens[$commentStart]['code'] === T_COMMENT) { + if (strstr($tokens[$commentStart]['content'], 'vim:') !== false) { + $commentStart = $phpcsFile->findNext(T_WHITESPACE, ($commentStart + 1), null, true); + } + } + + if ($tokens[$commentStart]['code'] === T_CLOSE_TAG) { + // We are only interested if this is the first open tag. + return; + } else if ($tokens[$commentStart]['code'] === T_COMMENT) { + $phpcsFile->addError('You must use "/**" style comments for a file comment', ($stackPtr + 1)); + return; + } else if ($commentStart === false || $tokens[$commentStart]['code'] !== T_DOC_COMMENT) { + $phpcsFile->addError('Missing file doc comment', ($stackPtr + 1)); + return; + } else { + + // Extract the header comment docblock. + $commentEnd = ($phpcsFile->findNext(T_DOC_COMMENT, ($commentStart + 1), null, true) - 1); + + // Check if there is only 1 doc comment between the open tag and class token. + $nextToken = array( + T_ABSTRACT, + T_CLASS, + T_FUNCTION, + T_DOC_COMMENT, + ); + $commentNext = $phpcsFile->findNext($nextToken, ($commentEnd + 1)); + if ($commentNext !== false && $tokens[$commentNext]['code'] !== T_DOC_COMMENT) { + // Found a class token right after comment doc block. + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($commentEnd + 1), $commentNext, false, $phpcsFile->eolChar); + if ($newlineToken !== false) { + $newlineToken = $phpcsFile->findNext(T_WHITESPACE, ($newlineToken + 1), $commentNext, false, $phpcsFile->eolChar); + if ($newlineToken === false) { + // No blank line between the class token and the doc block. + // The doc block is most likely a class comment. + $phpcsFile->addError('Missing file doc comment', ($stackPtr + 1)); + return; + } + } + } + + $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + + // Parse the header comment docblock. + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_ClassCommentParser($comment, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'File doc comment is empty'; + $phpcsFile->addError($error, $commentStart); + return; + } + + // No extra newline before short description. + $short = $comment->getShortComment(); + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $line = ($newlineSpan > 1) ? 'newlines' : 'newline'; + $error = "Extra $line found before file comment short description"; + $phpcsFile->addError($error, ($commentStart + 1)); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in file comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1)); + } + + $newlineCount += $newlineBetween; + } + + // Exactly one blank line before tags. + $tags = $this->commentParser->getTagOrders(); + if (count($tags) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in file comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount)); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + // Check the PHP Version. + if (strstr(strtolower($long), 'php version') === false) { + $error = 'PHP version not specified'; + $phpcsFile->addWarning($error, $commentEnd); + } + + // Check each tag. + $this->processTags($commentStart, $commentEnd); + }//end if + + }//end process() + + + /** + * Processes each required or optional tag. + * + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function processTags($commentStart, $commentEnd) + { + // Tags in correct order and related info. + $tags = array( + 'category' => array( + 'required' => false, //Russ Flynn edit + 'allow_multiple' => false, + 'order_text' => 'precedes @package', + ), + 'package' => array( + 'required' => false, // Russ Flynn edit + 'allow_multiple' => false, + 'order_text' => 'follows @category', + ), + 'subpackage' => array( + 'required' => false, + 'allow_multiple' => false, + 'order_text' => 'follows @package', + ), + 'author' => array( + 'required' => true, + 'allow_multiple' => true, + 'order_text' => 'follows @subpackage (if used) or @package', + ), + 'copyright' => array( + 'required' => true, //Russ Flynn edit + 'allow_multiple' => true, + 'order_text' => 'follows @author', + ), + 'license' => array( + 'required' => true, + 'allow_multiple' => false, + 'order_text' => 'follows @copyright (if used) or @author', + ), + 'version' => array( + 'required' => false, + 'allow_multiple' => false, + 'order_text' => 'follows @licence', + ), + 'link' => array( + 'required' => false, //Russ Flynn edit + 'allow_multiple' => true, + 'order_text' => 'follows @version', + ), + 'see' => array( + 'required' => false, + 'allow_multiple' => true, + 'order_text' => 'follows @link', + ), + 'since' => array( + 'required' => false, + 'allow_multiple' => false, + 'order_text' => 'follows @see (if used) or @link', + ), + 'deprecated' => array( + 'required' => false, + 'allow_multiple' => false, + 'order_text' => 'follows @since (if used) or @see (if used) or @link', + ), + ); + + $docBlock = (get_class($this) === 'Reaktor_Sniffs_Commenting_FileCommentSniff') ? 'file' : 'class'; + $foundTags = $this->commentParser->getTagOrders(); + $orderIndex = 0; + $indentation = array(); + $longestTag = 0; + $errorPos = 0; + + foreach ($tags as $tag => $info) { + + // Required tag missing. + if ($info['required'] === true && in_array($tag, $foundTags) === false) { + $error = "Missing @$tag tag in $docBlock comment"; + $this->currentFile->addError($error, $commentEnd); + continue; + } + + // Get the line number for current tag. + $tagName = ucfirst($tag); + if ($info['allow_multiple'] === true) { + $tagName .= 's'; + } + + $getMethod = 'get'.$tagName; + $tagElement = $this->commentParser->$getMethod(); + if (is_null($tagElement) === true || empty($tagElement) === true) { + continue; + } + + $errorPos = $commentStart; + if (is_array($tagElement) === false) { + $errorPos = ($commentStart + $tagElement->getLine()); + } + + // Get the tag order. + $foundIndexes = array_keys($foundTags, $tag); + + if (count($foundIndexes) > 1) { + // Multiple occurance not allowed. + if ($info['allow_multiple'] === false) { + $error = "Only 1 @$tag tag is allowed in a $docBlock comment"; + $this->currentFile->addError($error, $errorPos); + } else { + // Make sure same tags are grouped together. + $i = 0; + $count = $foundIndexes[0]; + foreach ($foundIndexes as $index) { + if ($index !== $count) { + $errorPosIndex = ($errorPos + $tagElement[$i]->getLine()); + $error = "@$tag tags must be grouped together"; + $this->currentFile->addError($error, $errorPosIndex); + } + + $i++; + $count++; + } + } + }//end if + + // Check tag order. + if ($foundIndexes[0] > $orderIndex) { + $orderIndex = $foundIndexes[0]; + } else { + if (is_array($tagElement) === true && empty($tagElement) === false) { + $errorPos += $tagElement[0]->getLine(); + } + + $orderText = $info['order_text']; + $error = "The @$tag tag is in the wrong order; the tag $orderText"; + $this->currentFile->addError($error, $errorPos); + } + + // Store the indentation for checking. + $len = strlen($tag); + if ($len > $longestTag) { + $longestTag = $len; + } + + if (is_array($tagElement) === true) { + foreach ($tagElement as $key => $element) { + $indentation[] = array( + 'tag' => $tag, + 'space' => $this->getIndentation($tag, $element), + 'line' => $element->getLine(), + ); + } + } else { + $indentation[] = array( + 'tag' => $tag, + 'space' => $this->getIndentation($tag, $tagElement), + ); + } + + $method = 'process'.$tagName; + if (method_exists($this, $method) === true) { + // Process each tag if a method is defined. + call_user_func(array($this, $method), $errorPos); + } else { + if (is_array($tagElement) === true) { + foreach ($tagElement as $key => $element) { + $element->process($this->currentFile, $commentStart, $docBlock); + } + } else { + $tagElement->process($this->currentFile, $commentStart, $docBlock); + } + } + }//end foreach + + foreach ($indentation as $indentInfo) { + if ($indentInfo['space'] !== 0 && $indentInfo['space'] !== ($longestTag + 1)) { + $expected = (($longestTag - strlen($indentInfo['tag'])) + 1); + $space = ($indentInfo['space'] - strlen($indentInfo['tag'])); + $error = "@$indentInfo[tag] tag comment indented incorrectly. "; + $error .= "Expected $expected spaces but found $space."; + $getTagMethod = 'get'.ucfirst($indentInfo['tag']); + if ($tags[$indentInfo['tag']]['allow_multiple'] === true) { + $line = $indentInfo['line']; + } else { + $tagElem = $this->commentParser->$getTagMethod(); + $line = $tagElem->getLine(); + } + + $this->currentFile->addError($error, ($commentStart + $line)); + } + } + + }//end processTags() + + + /** + * Get the indentation information of each tag. + * + * @param string $tagName The name of the doc comment element. + * @param PHP_CodeSniffer_CommentParser_DocElement $tagElement The doc comment element. + * + * @return void + */ + protected function getIndentation($tagName, $tagElement) + { + if ($tagElement instanceof PHP_CodeSniffer_CommentParser_SingleElement) { + if ($tagElement->getContent() !== '') { + return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeContent(), ' ')); + } + } else if ($tagElement instanceof PHP_CodeSniffer_CommentParser_PairElement) { + if ($tagElement->getValue() !== '') { + return (strlen($tagName) + substr_count($tagElement->getWhitespaceBeforeValue(), ' ')); + } + } + + return 0; + + }//end getIndentation() + + + /** + * Process the category tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processCategory($errorPos) + { + $category = $this->commentParser->getCategory(); + if ($category !== null) { + $content = $category->getContent(); + if ($content !== '') { + if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { + $newContent = str_replace(' ', '_', $content); + $nameBits = explode('_', $newContent); + $firstBit = array_shift($nameBits); + $newName = ucfirst($firstBit).'_'; + foreach ($nameBits as $bit) { + $newName .= ucfirst($bit).'_'; + } + + $validName = trim($newName, '_'); + $error = "Category name \"$content\" is not valid; consider \"$validName\" instead"; + $this->currentFile->addError($error, $errorPos); + } + } else { + $error = '@category tag must contain a name'; + $this->currentFile->addError($error, $errorPos); + } + } + + }//end processCategory() + + + /** + * Process the package tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processPackage($errorPos) + { + $package = $this->commentParser->getPackage(); + if ($package !== null) { + $content = $package->getContent(); + if ($content !== '') { + if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { + $newContent = str_replace(' ', '_', $content); + $nameBits = explode('_', $newContent); + $firstBit = array_shift($nameBits); + $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; + foreach ($nameBits as $bit) { + $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $validName = trim($newName, '_'); + $error = "Package name \"$content\" is not valid; consider \"$validName\" instead"; + $this->currentFile->addError($error, $errorPos); + } + } else { + $error = '@package tag must contain a name'; + $this->currentFile->addError($error, $errorPos); + } + } + + }//end processPackage() + + + /** + * Process the subpackage tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processSubpackage($errorPos) + { + $package = $this->commentParser->getSubpackage(); + if ($package !== null) { + $content = $package->getContent(); + if ($content !== '') { + if (PHP_CodeSniffer::isUnderscoreName($content) !== true) { + $newContent = str_replace(' ', '_', $content); + $nameBits = explode('_', $newContent); + $firstBit = array_shift($nameBits); + $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; + foreach ($nameBits as $bit) { + $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $validName = trim($newName, '_'); + $error = "Subpackage name \"$content\" is not valid; consider \"$validName\" instead"; + $this->currentFile->addError($error, $errorPos); + } + } else { + $error = '@subpackage tag must contain a name'; + $this->currentFile->addError($error, $errorPos); + } + } + + }//end processSubpackage() + + + /** + * Process the author tag(s) that this header comment has. + * + * This function is different from other _process functions + * as $authors is an array of SingleElements, so we work out + * the errorPos for each element separately + * + * @param int $commentStart The position in the stack where + * the comment started. + * + * @return void + */ + protected function processAuthors($commentStart) + { + $authors = $this->commentParser->getAuthors(); + // Report missing return. + if (empty($authors) === false) { + foreach ($authors as $author) { + $errorPos = ($commentStart + $author->getLine()); + $content = $author->getContent(); + if ($content !== '') { + $local = '\da-zA-Z-_+'; + // Dot character cannot be the first or last character in the local-part. + $localMiddle = $local.'.\w'; + if (preg_match('/^([^<]*)\s+<(['.$local.']['.$localMiddle.']*['.$local.']@[\da-zA-Z][-.\w]*[\da-zA-Z]\.[a-zA-Z]{2,7})>$/', $content) === 0) { + $error = 'Content of the @author tag must be in the form "Display Name "'; + $this->currentFile->addError($error, $errorPos); + } + } else { + $docBlock = (get_class($this) === 'Reaktor_Sniffs_Commenting_FileCommentSniff') ? 'file' : 'class'; + $error = "Content missing for @author tag in $docBlock comment"; + $this->currentFile->addError($error, $errorPos); + } + } + } + + }//end processAuthors() + + + /** + * Process the copyright tags. + * + * @param int $commentStart The position in the stack where + * the comment started. + * + * @return void + */ + protected function processCopyrights($commentStart) + { + $copyrights = $this->commentParser->getCopyrights(); + foreach ($copyrights as $copyright) { + $errorPos = ($commentStart + $copyright->getLine()); + $content = $copyright->getContent(); + if ($content !== '') { + $matches = array(); + if (preg_match('/^([0-9]{4})((.{1})([0-9]{4}))? (.+)$/', $content, $matches) !== 0) { + // Check earliest-latest year order. + if ($matches[3] !== '') { + if ($matches[3] !== '-') { + $error = 'A hyphen must be used between the earliest and latest year'; + $this->currentFile->addError($error, $errorPos); + } + + if ($matches[4] !== '' && $matches[4] < $matches[1]) { + $error = "Invalid year span \"$matches[1]$matches[3]$matches[4]\" found; consider \"$matches[4]-$matches[1]\" instead"; + $this->currentFile->addWarning($error, $errorPos); + } + } + } else { + $error = '@copyright tag must contain a year and the name of the copyright holder'; + $this->currentFile->addError($error, $errorPos); + } + } else { + $error = '@copyright tag must contain a year and the name of the copyright holder'; + $this->currentFile->addError($error, $errorPos); + }//end if + }//end if + + }//end processCopyrights() + + + /** + * Process the license tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processLicense($errorPos) + { + $license = $this->commentParser->getLicense(); + if ($license !== null) { + $value = $license->getValue(); + $comment = $license->getComment(); + if ($value === '' || $comment === '') { + $error = '@license tag must contain a URL and a license name'; + $this->currentFile->addError($error, $errorPos); + } + } + + }//end processLicense() + + + /** + * Process the version tag. + * + * @param int $errorPos The line number where the error occurs. + * + * @return void + */ + protected function processVersion($errorPos) + { + $version = $this->commentParser->getVersion(); + if ($version !== null) { + $content = $version->getContent(); + $matches = array(); + if (empty($content) === true) { + $error = 'Content missing for @version tag in file comment'; + $this->currentFile->addError($error, $errorPos); + } else if (strstr($content, 'CVS:') === false && strstr($content, 'SVN:') === false) { + $error = "Invalid version \"$content\" in file comment; consider \"CVS: \" or \"SVN: \" instead"; + $this->currentFile->addWarning($error, $errorPos); + } + } + + }//end processVersion() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Commenting/FunctionCommentSniff.php b/test/codesniff/Reaktor/Sniffs/Commenting/FunctionCommentSniff.php new file mode 100755 index 0000000..51be69a --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Commenting/FunctionCommentSniff.php @@ -0,0 +1,462 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: FunctionCommentSniff.php,v 1.24 2007/11/23 01:04:48 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_CommentParser_FunctionCommentParser', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_CommentParser_FunctionCommentParser not found'); +} + +/** + * Parses and verifies the doc comments for functions. + * + * Verifies that : + *
      + *
    • A comment exists
    • + *
    • There is a blank newline after the short description.
    • + *
    • There is a blank newline between the long and short description.
    • + *
    • There is a blank newline between the long description and tags.
    • + *
    • Parameter names represent those in the method.
    • + *
    • Parameter comments are in the correct order
    • + *
    • Parameter comments are complete
    • + *
    • A space is present before the first and after the last parameter
    • + *
    • A return type exists
    • + *
    • There must be one blank line between body and headline comments.
    • + *
    • Any throw tag must have an exception class.
    • + *
    + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Commenting_FunctionCommentSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * The name of the method that we are currently processing. + * + * @var string + */ + private $_methodName = ''; + + /** + * The position in the stack where the fucntion token was found. + * + * @var int + */ + private $_functionToken = null; + + /** + * The position in the stack where the class token was found. + * + * @var int + */ + private $_classToken = null; + + /** + * The function comment parser for the current method. + * + * @var PHP_CodeSniffer_Comment_Parser_FunctionCommentParser + */ + protected $commentParser = null; + + /** + * The current PHP_CodeSniffer_File object we are processing. + * + * @var PHP_CodeSniffer_File + */ + protected $currentFile = null; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $find = array( + T_COMMENT, + T_DOC_COMMENT, + T_CLASS, + T_FUNCTION, + T_OPEN_TAG, + ); + + $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1)); + + if ($commentEnd === false) { + return; + } + + $this->currentFile = $phpcsFile; + $tokens = $phpcsFile->getTokens(); + + // If the token that we found was a class or a function, then this + // function has no doc comment. + $code = $tokens[$commentEnd]['code']; + + if ($code === T_COMMENT) { + $error = 'You must use "/**" style comments for a function comment'; + $phpcsFile->addError($error, $stackPtr); + return; + } else if ($code !== T_DOC_COMMENT) { + $phpcsFile->addError('Missing function doc comment', $stackPtr); + return; + } + + // If there is any code between the function keyword and the doc block + // then the doc block is not for us. + $ignore = PHP_CodeSniffer_Tokens::$scopeModifiers; + $ignore[] = T_STATIC; + $ignore[] = T_WHITESPACE; + $ignore[] = T_ABSTRACT; + $ignore[] = T_FINAL; + $prevToken = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true); + if ($prevToken !== $commentEnd) { + $phpcsFile->addError('Missing function doc comment', $stackPtr); + return; + } + + $this->_functionToken = $stackPtr; + + foreach ($tokens[$stackPtr]['conditions'] as $condPtr => $condition) { + if ($condition === T_CLASS || $condition === T_INTERFACE) { + $this->_classToken = $condPtr; + break; + } + } + + // If the first T_OPEN_TAG is right before the comment, it is probably + // a file comment. + $commentStart = ($phpcsFile->findPrevious(T_DOC_COMMENT, ($commentEnd - 1), null, true) + 1); + $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($commentStart - 1), null, true); + if ($tokens[$prevToken]['code'] === T_OPEN_TAG) { + // Is this the first open tag? + if ($stackPtr === 0 || $phpcsFile->findPrevious(T_OPEN_TAG, ($prevToken - 1)) === false) { + $phpcsFile->addError('Missing function doc comment', $stackPtr); + return; + } + } + + $comment = $phpcsFile->getTokensAsString($commentStart, ($commentEnd - $commentStart + 1)); + $this->_methodName = $phpcsFile->getDeclarationName($stackPtr); + + try { + $this->commentParser = new PHP_CodeSniffer_CommentParser_FunctionCommentParser($comment, $phpcsFile); + $this->commentParser->parse(); + } catch (PHP_CodeSniffer_CommentParser_ParserException $e) { + $line = ($e->getLineWithinComment() + $commentStart); + $phpcsFile->addError($e->getMessage(), $line); + return; + } + + $comment = $this->commentParser->getComment(); + if (is_null($comment) === true) { + $error = 'Function doc comment is empty'; + $phpcsFile->addError($error, $commentStart); + return; + } + + $this->processParams($commentStart); + $this->processReturn($commentStart, $commentEnd); + $this->processThrows($commentStart); + + // No extra newline before short description. + $short = $comment->getShortComment(); + $newlineCount = 0; + $newlineSpan = strspn($short, $phpcsFile->eolChar); + if ($short !== '' && $newlineSpan > 0) { + $line = ($newlineSpan > 1) ? 'newlines' : 'newline'; + $error = "Extra $line found before function comment short description"; + $phpcsFile->addError($error, ($commentStart + 1)); + } + + $newlineCount = (substr_count($short, $phpcsFile->eolChar) + 1); + + // Exactly one blank line between short and long description. + $long = $comment->getLongComment(); + if (empty($long) === false) { + $between = $comment->getWhiteSpaceBetween(); + $newlineBetween = substr_count($between, $phpcsFile->eolChar); + if ($newlineBetween !== 2) { + $error = 'There must be exactly one blank line between descriptions in function comment'; + $phpcsFile->addError($error, ($commentStart + $newlineCount + 1)); + } + + $newlineCount += $newlineBetween; + } + + // Exactly one blank line before tags. + $params = $this->commentParser->getTagOrders(); + if (count($params) > 1) { + $newlineSpan = $comment->getNewlineAfter(); + if ($newlineSpan !== 2) { + $error = 'There must be exactly one blank line before the tags in function comment'; + if ($long !== '') { + $newlineCount += (substr_count($long, $phpcsFile->eolChar) - $newlineSpan + 1); + } + + $phpcsFile->addError($error, ($commentStart + $newlineCount)); + $short = rtrim($short, $phpcsFile->eolChar.' '); + } + } + + }//end process() + + + /** + * Process any throw tags that this function comment has. + * + * @param int $commentStart The position in the stack where the + * comment started. + * + * @return void + */ + protected function processThrows($commentStart) + { + if (count($this->commentParser->getThrows()) === 0) { + return; + } + + foreach ($this->commentParser->getThrows() as $throw) { + + $exception = $throw->getValue(); + $errorPos = ($commentStart + $throw->getLine()); + + if ($exception === '') { + $error = '@throws tag must contain the exception class name'; + $this->currentFile->addError($error, $errorPos); + } + } + + }//end processThrows() + + + /** + * Process the return comment of this function comment. + * + * @param int $commentStart The position in the stack where the comment started. + * @param int $commentEnd The position in the stack where the comment ended. + * + * @return void + */ + protected function processReturn($commentStart, $commentEnd) + { + // Skip constructor and destructor. + $className = ''; + if ($this->_classToken !== null) { + $className = $this->currentFile->getDeclarationName($this->_classToken); + $className = strtolower(ltrim($className, '_')); + } + + $methodName = strtolower(ltrim($this->_methodName, '_')); + $isSpecialMethod = ($this->_methodName === '__construct' || $this->_methodName === '__destruct'); + + if ($isSpecialMethod === false && $methodName !== $className) { + // Report missing return tag. + if ($this->commentParser->getReturn() === null) { + $error = 'Missing @return tag in function comment'; + $this->currentFile->addError($error, $commentEnd); + } else if (trim($this->commentParser->getReturn()->getRawContent()) === '') { + $error = '@return tag is empty in function comment'; + $errorPos = ($commentStart + $this->commentParser->getReturn()->getLine()); + $this->currentFile->addError($error, $errorPos); + } + } + + }//end processReturn() + + + /** + * Process the function parameter comments. + * + * @param int $commentStart The position in the stack where + * the comment started. + * + * @return void + */ + protected function processParams($commentStart) + { + $realParams = $this->currentFile->getMethodParameters($this->_functionToken); + + $params = $this->commentParser->getParams(); + $foundParams = array(); + + if (empty($params) === false) { + + $lastParm = (count($params) - 1); + if (substr_count($params[$lastParm]->getWhitespaceAfter(), $this->currentFile->eolChar) !== 2) { + $error = 'Last parameter comment requires a blank newline after it'; + $errorPos = ($params[$lastParm]->getLine() + $commentStart); + $this->currentFile->addError($error, $errorPos); + } + + // Parameters must appear immediately after the comment. + if ($params[0]->getOrder() !== 2) { + $error = 'Parameters must appear immediately after the comment'; + $errorPos = ($params[0]->getLine() + $commentStart); + $this->currentFile->addError($error, $errorPos); + } + + $previousParam = null; + $spaceBeforeVar = 10000; + $spaceBeforeComment = 10000; + $longestType = 0; + $longestVar = 0; + + foreach ($params as $param) { + + $paramComment = trim($param->getComment()); + $errorPos = ($param->getLine() + $commentStart); + + // Make sure that there is only one space before the var type. + if ($param->getWhitespaceBeforeType() !== ' ') { + $error = 'Expected 1 space before variable type'; + $this->currentFile->addError($error, $errorPos); + } + + $spaceCount = substr_count($param->getWhitespaceBeforeVarName(), ' '); + if ($spaceCount < $spaceBeforeVar) { + $spaceBeforeVar = $spaceCount; + $longestType = $errorPos; + } + + $spaceCount = substr_count($param->getWhitespaceBeforeComment(), ' '); + + if ($spaceCount < $spaceBeforeComment && $paramComment !== '') { + $spaceBeforeComment = $spaceCount; + $longestVar = $errorPos; + } + + // Make sure they are in the correct order, + // and have the correct name. + $pos = $param->getPosition(); + + $paramName = ($param->getVarName() !== '') ? $param->getVarName() : '[ UNKNOWN ]'; + + if ($previousParam !== null) { + $previousName = ($previousParam->getVarName() !== '') ? $previousParam->getVarName() : 'UNKNOWN'; + + // Check to see if the parameters align properly. + if ($param->alignsVariableWith($previousParam) === false) { + $error = 'The variable names for parameters '.$previousName.' ('.($pos - 1).') and '.$paramName.' ('.$pos.') do not align'; + $this->currentFile->addError($error, $errorPos); + } + + if ($param->alignsCommentWith($previousParam) === false) { + $error = 'The comments for parameters '.$previousName.' ('.($pos - 1).') and '.$paramName.' ('.$pos.') do not align'; + $this->currentFile->addError($error, $errorPos); + } + }//end if + + // Make sure the names of the parameter comment matches the + // actual parameter. + if (isset($realParams[($pos - 1)]) === true) { + $realName = $realParams[($pos - 1)]['name']; + $foundParams[] = $realName; + // Append ampersand to name if passing by reference. + if ($realParams[($pos - 1)]['pass_by_reference'] === true) { + $realName = '&'.$realName; + } + + if ($realName !== $param->getVarName()) { + $error = 'Doc comment var "'.$paramName; + $error .= '" does not match actual variable name "'.$realName; + $error .= '" at position '.$pos; + + $this->currentFile->addError($error, $errorPos); + } + } else { + // We must have an extra parameter comment. + $error = 'Superfluous doc comment at position '.$pos; + $this->currentFile->addError($error, $errorPos); + } + + if ($param->getVarName() === '') { + $error = 'Missing parameter name at position '.$pos; + $this->currentFile->addError($error, $errorPos); + } + + if ($param->getType() === '') { + $error = 'Missing type at position '.$pos; + $this->currentFile->addError($error, $errorPos); + } + + if ($paramComment === '') { + $error = 'Missing comment for param "'.$paramName.'" at position '.$pos; + $this->currentFile->addError($error, $errorPos); + } + + $previousParam = $param; + + }//end foreach + + if ($spaceBeforeVar !== 1 && $spaceBeforeVar !== 10000 && $spaceBeforeComment !== 10000) { + $error = 'Expected 1 space after the longest type'; + $this->currentFile->addError($error, $longestType); + } + + if ($spaceBeforeComment !== 1 && $spaceBeforeComment !== 10000) { + $error = 'Expected 1 space after the longest variable name'; + $this->currentFile->addError($error, $longestVar); + } + + }//end if + + $realNames = array(); + foreach ($realParams as $realParam) { + $realNames[] = $realParam['name']; + } + + // Report and missing comments. + $diff = array_diff($realNames, $foundParams); + foreach ($diff as $neededParam) { + if (count($params) !== 0) { + $errorPos = ($params[(count($params) - 1)]->getLine() + $commentStart); + } else { + $errorPos = $commentStart; + } + + $error = 'Doc comment for "'.$neededParam.'" missing'; + $this->currentFile->addError($error, $errorPos); + } + + }//end processParams() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Commenting/InlineCommentSniff.php b/test/codesniff/Reaktor/Sniffs/Commenting/InlineCommentSniff.php new file mode 100755 index 0000000..94cb5c3 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Commenting/InlineCommentSniff.php @@ -0,0 +1,71 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: InlineCommentSniff.php,v 1.4 2007/07/23 01:47:52 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * PHP_CodeSniffer_Sniffs_Reaktor_Commenting_InlineCommentSniff. + * + * Checks that no perl-style comments are used. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_COMMENT); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if ($tokens[$stackPtr]['content']{0} === '#') { + $error = 'Perl-style comments are not allowed. Use "// Comment."'; + $error .= ' or "/* comment */" instead.'; + $phpcsFile->addError($error, $stackPtr); + } + + }//end process() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/ControlStructures/ControlSignatureSniff.php b/test/codesniff/Reaktor/Sniffs/ControlStructures/ControlSignatureSniff.php new file mode 100755 index 0000000..7576c0d --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/ControlStructures/ControlSignatureSniff.php @@ -0,0 +1,75 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ControlSignatureSniff.php,v 1.7 2007/10/23 06:05:14 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractPatternSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractPatternSniff not found'); +} + +/** + * Verifies that control statements conform to their coding standards. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_ControlStructures_ControlSignatureSniff extends PHP_CodeSniffer_Standards_AbstractPatternSniff +{ + + + /** + * Constructs a Reaktor_Sniffs_ControlStructures_ControlSignatureSniff. + */ + public function __construct() + { + parent::__construct(true); + + }//end __construct() + + + /** + * Returns the patterns that this test wishes to verify. + * + * @return array(string) + */ + protected function getPatterns() + { + return array( + 'doEOL{...}EOLwhile (...);EOL', + 'while (...):', + 'while (...)EOL', + 'for (...):', + 'for (...)EOL', + 'if (...):', + 'if (...)EOL', + 'foreach (...):', + 'foreach (...)EOL', + '}EOLelse if (...)EOL', + '}EOLelseif (...)EOL', + '}EOLelseEOL', + 'doEOL', + ); + + }//end getPatterns() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Files/IncludingFileSniff.php b/test/codesniff/Reaktor/Sniffs/Files/IncludingFileSniff.php new file mode 100755 index 0000000..8036218 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Files/IncludingFileSniff.php @@ -0,0 +1,138 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: IncludingFileSniff.php,v 1.5 2007/10/22 23:11:56 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Reaktor_Sniffs_Files_IncludingFileSniff. + * + * Checks that the include_once is used in conditional situations, and + * require_once is used elsewhere. Also checks that brackets do not surround + * the file being included. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Files_IncludingFileSniff implements PHP_CodeSniffer_Sniff +{ + + /** + * Conditions that should use include_once + * + * @var array(int) + */ + private static $_conditions = array( + T_IF, + T_ELSE, + T_ELSEIF, + T_SWITCH, + ); + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_INCLUDE_ONCE, + T_REQUIRE_ONCE, + T_REQUIRE, + T_INCLUDE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($tokens[$nextToken]['code'] === T_OPEN_PARENTHESIS) { + $error = '"'.$tokens[$stackPtr]['content'].'"'; + $error .= ' is a statement, not a function; '; + $error .= 'no parentheses are required'; + $phpcsFile->addError($error, $stackPtr); + } + + $inCondition = (count($tokens[$stackPtr]['conditions']) !== 0) ? true : false; + + // Check to see if this including statement is within the parenthesis of a condition. + // If that's the case then we need to process it as being within a condition, as they + // are checking the return value. + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + foreach ($tokens[$stackPtr]['nested_parenthesis'] as $left => $right) { + if (isset($tokens[$left]['parenthesis_owner']) === true) { + $inCondition = true; + } + } + } + + // Check to see if they are assigning the return value of this including call. + // If they are then they are probably checking it, so its conditional. + $previous = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if (in_array($tokens[$previous]['code'], PHP_CodeSniffer_Tokens::$assignmentTokens) === true) { + // The have assigned the return value to it, so its conditional. + $inCondition = true; + } + + $tokenCode = $tokens[$stackPtr]['code']; + if ($inCondition === true) { + // We are inside a conditional statement. We need an include_once. + if ($tokenCode === T_REQUIRE_ONCE) { + $error = 'File is being conditionally included; '; + $error .= 'use "include_once" instead'; + $phpcsFile->addError($error, $stackPtr); + } else if ($tokenCode === T_REQUIRE) { + $error = 'File is being conditionally included; '; + $error .= 'use "include" instead'; + $phpcsFile->addError($error, $stackPtr); + } + } else { + // We are unconditionally including, we need a require_once. + if ($tokenCode === T_INCLUDE_ONCE) { + $error = 'File is being unconditionally included; '; + $error .= 'use "require_once" instead'; + $phpcsFile->addError($error, $stackPtr); + } else if ($tokenCode === T_INCLUDE) { + $error = 'File is being unconditionally included; '; + $error .= 'use "require" instead'; + $phpcsFile->addError($error, $stackPtr); + } + }//end if + + }//end process() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Files/LineEndingsSniff.php b/test/codesniff/Reaktor/Sniffs/Files/LineEndingsSniff.php new file mode 100755 index 0000000..11b5185 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Files/LineEndingsSniff.php @@ -0,0 +1,47 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: LineEndingsSniff.php,v 1.3 2007/07/27 05:36:23 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Generic_Sniffs_Files_LineEndingsSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_Files_LineEndingsSniff not found'); +} + +/** + * Reaktor_Sniffs_Files_LineEndingsSniff. + * + * Checks that end of line characters are "\n". + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Files_LineEndingsSniff extends Generic_Sniffs_Files_LineEndingsSniff +{ + + /** + * The valid EOL character. + * + * @var string + */ + protected $eolChar = "\n"; + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Files/LineLengthSniff.php b/test/codesniff/Reaktor/Sniffs/Files/LineLengthSniff.php new file mode 100755 index 0000000..0c61f60 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Files/LineLengthSniff.php @@ -0,0 +1,57 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: LineLengthSniff.php,v 1.6 2007/07/27 05:36:23 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Generic_Sniffs_Files_LineLengthSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_Files_LineLengthSniff not found'); +} + +/** + * Reaktor_Sniffs_Files_LineLengthSniff. + * + * Checks all lines in the file, and throws warnings if they are over 85 + * characters in length. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Files_LineLengthSniff extends Generic_Sniffs_Files_LineLengthSniff +{ + + /** + * The limit that the length of a line should not exceed. + * + * @var int + */ + protected $lineLimit = 1000; + + /** + * The limit that the length of a line must not exceed. + * + * Set to zero (0) to disable. + * + * @var int + */ + protected $absoluteLineLimit = 500; + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php b/test/codesniff/Reaktor/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php new file mode 100755 index 0000000..8c8daa4 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php @@ -0,0 +1,135 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: FunctionCallArgumentSpacingSniff.php,v 1.8 2007/07/23 01:47:53 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Reaktor_Sniffs_Functions_FunctionCallArgumentSpacingSniff. + * + * Checks that calls to methods and functions are spaced correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Functions_FunctionCallArgumentSpacingSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Skip tokens that are the names of functions or classes + // within their definitions. For example: + // function myFunction... + // "myFunction" is T_STRING but we should skip because it is not a + // function or method *call*. + $functionName = $stackPtr; + $functionKeyword = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$functionKeyword]['code'] === T_FUNCTION || $tokens[$functionKeyword]['code'] === T_CLASS) { + return; + } + + // If the next non-whitespace token after the function or method call + // is not an opening parenthesis then it cant really be a *call*. + $openBracket = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($functionName + 1), null, true); + if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { + return; + } + + $closeBracket = $tokens[$openBracket]['parenthesis_closer']; + + $nextSeperator = $openBracket; + while (($nextSeperator = $phpcsFile->findNext(array(T_COMMA, T_VARIABLE), ($nextSeperator + 1), $closeBracket)) !== false) { + // Make sure the comma or variable belongs directly to this function call, + // and is not inside a nested function call or array. + $brackets = $tokens[$nextSeperator]['nested_parenthesis']; + $lastBracket = array_pop($brackets); + if ($lastBracket !== $closeBracket) { + continue; + } + + if ($tokens[$nextSeperator]['code'] === T_COMMA) { + if ($tokens[($nextSeperator - 1)]['code'] === T_WHITESPACE) { + $error = 'Space found before comma in function call'; + $phpcsFile->addError($error, $stackPtr); + } + + if ($tokens[($nextSeperator + 1)]['code'] !== T_WHITESPACE) { + $error = 'No space found after comma in function call'; + $phpcsFile->addError($error, $stackPtr); + } else { + // If there is a newline in the space, then the must be formatting + // each argument on a newline, which is valid, so ignore it. + if (strpos($tokens[($nextSeperator + 1)]['content'], $phpcsFile->eolChar) === false) { + $space = strlen($tokens[($nextSeperator + 1)]['content']); + if ($space > 1) { + $error = 'Expected 1 space after comma in function call; '; + $error .= $space.' found'; + $phpcsFile->addError($error, $stackPtr); + } + } + } + } else { + // Token is a variable. + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($nextSeperator + 1), $closeBracket, true); + if ($nextToken !== false) { + if ($tokens[$nextToken]['code'] === T_EQUAL) { + if (($tokens[($nextToken - 1)]['code']) !== T_WHITESPACE) { + $error = 'Expected 1 space before = sign of default value'; + $phpcsFile->addError($error, $stackPtr); + } + + if ($tokens[($nextToken + 1)]['code'] !== T_WHITESPACE) { + $error = 'Expected 1 space after = sign of default value'; + $phpcsFile->addError($error, $stackPtr); + } + } + } + }//end if + }//end while + + }//end process() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/Functions/FunctionCallSignatureSniff.php b/test/codesniff/Reaktor/Sniffs/Functions/FunctionCallSignatureSniff.php new file mode 100755 index 0000000..c9565e7 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Functions/FunctionCallSignatureSniff.php @@ -0,0 +1,125 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: FunctionCallSignatureSniff.php,v 1.5 2007/07/23 01:47:53 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Reaktor_Sniffs_Functions_FunctionCallSignatureSniff. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Functions_FunctionCallSignatureSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_STRING); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // Find the next non-empty token. + $next = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true); + + if ($tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { + // Not a function call. + return; + } + + if (isset($tokens[$next]['parenthesis_closer']) === false) { + // Not a function call. + return; + } + + // Find the previous non-empty token. + $previous = $phpcsFile->findPrevious(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$previous]['code'] === T_FUNCTION) { + // It's a function definition, not a function call. + return; + } + + if ($tokens[$previous]['code'] === T_NEW) { + // We are creating an object, not calling a function. + return; + } + + if (($stackPtr + 1) !== $next) { + // Checking this: $value = my_function[*](...). + $error = 'Space before opening parenthesis of function call prohibited'; + $phpcsFile->addError($error, $stackPtr); + } + + if ($tokens[($next + 1)]['code'] === T_WHITESPACE) { + // Checking this: $value = my_function([*]...). + $error = 'Space after opening parenthesis of function call prohibited'; + $phpcsFile->addError($error, $stackPtr); + } + + $closer = $tokens[$next]['parenthesis_closer']; + + if ($tokens[($closer - 1)]['code'] === T_WHITESPACE) { + // Checking this: $value = my_function(...[*]). + $between = $phpcsFile->findNext(T_WHITESPACE, ($next + 1), null, true); + + // Only throw an error if there is some content between the parenthesis. + // IE. Checking for this: $value = my_function(). + // If there is no content, then we would have thrown an error in the + // previous IF statement because it would look like this: + // $value = my_function( ). + if ($between !== $closer) { + $error = 'Space before closing parenthesis of function call prohibited'; + $phpcsFile->addError($error, $closer); + } + } + + $next = $phpcsFile->findNext(T_WHITESPACE, ($closer + 1), null, true); + + if ($tokens[$next]['code'] === T_SEMICOLON) { + if (in_array($tokens[($closer + 1)]['code'], PHP_CodeSniffer_Tokens::$emptyTokens) === true) { + $error = 'Space after closing parenthesis of function call prohibited'; + $phpcsFile->addError($error, $closer); + } + } + + }//end process() + + +}//end class +?> diff --git a/test/codesniff/Reaktor/Sniffs/Functions/ValidDefaultValueSniff.php b/test/codesniff/Reaktor/Sniffs/Functions/ValidDefaultValueSniff.php new file mode 100755 index 0000000..3378e44 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/Functions/ValidDefaultValueSniff.php @@ -0,0 +1,110 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ValidDefaultValueSniff.php,v 1.5 2007/07/23 01:47:53 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Reaktor_Sniffs_Functions_ValidDefaultValueSniff. + * + * A Sniff to ensure that parameters defined for a function that have a default + * value come at the end of the function signature. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_Functions_ValidDefaultValueSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array(T_FUNCTION); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $argStart = $tokens[$stackPtr]['parenthesis_opener']; + $argEnd = $tokens[$stackPtr]['parenthesis_closer']; + + // Flag for when we have found a default in our arg list. + // If there is a value without a default after this, it is an error. + $defaultFound = false; + + $nextArg = $argStart; + while (($nextArg = $phpcsFile->findNext(T_VARIABLE, ($nextArg + 1), $argEnd)) !== false) { + $argHasDefault = self::_argHasDefault($phpcsFile, $nextArg); + if (($argHasDefault === false) && ($defaultFound === true)) { + $error = 'Arguments with default values must be at the end'; + $error .= ' of the argument list'; + $phpcsFile->addError($error, $nextArg); + return; + } + + if ($argHasDefault === true) { + $defaultFound = true; + } + } + + }//end process() + + + /** + * Returns true if the passed argument has a default value. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being scanned. + * @param int $argPtr The position of the argument + * in the stack. + * + * @return bool + */ + private static function _argHasDefault(PHP_CodeSniffer_File $phpcsFile, $argPtr) + { + $tokens = $phpcsFile->getTokens(); + $nextToken = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($argPtr + 1), null, true); + if ($tokens[$nextToken]['code'] !== T_EQUAL) { + return false; + } + + return true; + + }//end _argHasDefault() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/NamingConventions/ValidClassNameSniff.php b/test/codesniff/Reaktor/Sniffs/NamingConventions/ValidClassNameSniff.php new file mode 100755 index 0000000..843b979 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/NamingConventions/ValidClassNameSniff.php @@ -0,0 +1,107 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ValidClassNameSniff.php,v 1.8 2007/11/04 22:29:51 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Reaktor_Sniffs_NamingConventions_ValidClassNameSniff. + * + * Ensures class and interface names start with a capital letter + * and use _ separators. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_NamingConventions_ValidClassNameSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return array( + T_CLASS, + T_INTERFACE, + ); + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile The current file being processed. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $className = $phpcsFile->findNext(T_STRING, $stackPtr); + $name = trim($tokens[$className]['content']); + + // Make sure the first letter is a capital. + if (preg_match('|^[a-z]|', $name) === 0) { + $error = ucfirst($tokens[$stackPtr]['content']).' name must begin with a lower case letter'; + $phpcsFile->addError($error, $stackPtr); + } + + // Check that each new word starts with a capital as well, but don't + // check the first word, as it is checked above. + $validName = true; + $nameBits = explode('_', $name); + $firstBit = array_shift($nameBits); + foreach ($nameBits as $bit) { + if ($bit === '' || $bit{0} !== strtoupper($bit{0})) { + $validName = false; + break; + } + } + + if ($validName !== true) { + // Strip underscores because they cause the suggested name + // to be incorrect. + $nameBits = explode('_', trim($name, '_')); + $firstBit = array_shift($nameBits); + + $newName = strtoupper($firstBit{0}).substr($firstBit, 1).'_'; + foreach ($nameBits as $bit) { + $newName .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $newName = rtrim($newName, '_'); + $error = ucfirst($tokens[$stackPtr]['content'])." name is not valid; consider $newName instead"; + $phpcsFile->addError($error, $stackPtr); + } + + }//end process() + + +}//end class + + +?> diff --git a/test/codesniff/Reaktor/Sniffs/NamingConventions/ValidFunctionNameSniff.php b/test/codesniff/Reaktor/Sniffs/NamingConventions/ValidFunctionNameSniff.php new file mode 100755 index 0000000..61c49a4 --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/NamingConventions/ValidFunctionNameSniff.php @@ -0,0 +1,262 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ValidFunctionNameSniff.php,v 1.17 2007/11/19 03:39:07 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('PHP_CodeSniffer_Standards_AbstractScopeSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_AbstractScopeSniff not found'); +} + +/** + * Reaktor_Sniffs_NamingConventions_ValidFunctionNameSniff. + * + * Ensures method names are correct depending on whether they are public + * or private, and that functions are named correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_NamingConventions_ValidFunctionNameSniff extends PHP_CodeSniffer_Standards_AbstractScopeSniff +{ + + /** + * A list of all PHP magic methods. + * + * @var array + */ + private $_magicMethods = array( + 'construct', + 'destruct', + 'call', + 'get', + 'set', + 'isset', + 'unset', + 'sleep', + 'wakeup', + 'toString', + 'set_state', + 'clone', + ); + + /** + * A list of all PHP magic functions. + * + * @var array + */ + private $_magicFunctions = array( + 'autoload', + ); + + + /** + * Constructs a Reaktor_Sniffs_NamingConventions_ValidFunctionNameSniff. + */ + public function __construct() + { + parent::__construct(array(T_CLASS, T_INTERFACE), array(T_FUNCTION), true); + + }//end __construct() + + + /** + * Processes the tokens within the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * @param int $currScope The position of the current scope. + * + * @return void + */ + protected function processTokenWithinScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr, $currScope) + { + $className = $phpcsFile->getDeclarationName($currScope); + $methodName = $phpcsFile->getDeclarationName($stackPtr); + + // Is this a magic method. IE. is prefixed with "__". + if (preg_match('|^__|', $methodName) !== 0) { + $magicPart = substr($methodName, 2); + if (in_array($magicPart, $this->_magicMethods) === false) { + $error = "Method name \"$className::$methodName\" is invalid; only PHP magic methods should be prefixed with a double underscore"; + $phpcsFile->addError($error, $stackPtr); + } + + return; + } + + // PHP4 constructors are allowed to break our rules. + if ($methodName === $className) { + return; + } + + // PHP4 destructors are allowed to break our rules. + if ($methodName === '_'.$className) { + return; + } + + $methodProps = $phpcsFile->getMethodProperties($stackPtr); + $isPublic = ($methodProps['scope'] === 'private') ? false : true; + $scope = $methodProps['scope']; + $scopeSpecified = $methodProps['scope_specified']; + + // If it's a private method, it must have an underscore on the front. + if ($isPublic === false && $methodName{0} !== '_') { + $error = "Private method name \"$className::$methodName\" must be prefixed with an underscore"; + $phpcsFile->addError($error, $stackPtr); + return; + } + + // If it's not a private method, it must not have an underscore on the front. + if ($isPublic === true && $scopeSpecified === true && $methodName{0} === '_') { + $error = ucfirst($scope)." method name \"$className::$methodName\" must not be prefixed with an underscore"; + $phpcsFile->addError($error, $stackPtr); + return; + } + + // If the scope was specified on the method, then the method must be + // camel caps and an underscore should be checked for. If it wasn't + // specified, treat it like a public method and remove the underscore + // prefix if there is one because we cant determine if it is private or + // public. + $testMethodName = $methodName; + if ($scopeSpecified === false && $methodName{0} === '_') { + $testMethodName = substr($methodName, 1); + } + + if (PHP_CodeSniffer::isCamelCaps($testMethodName, false, $isPublic, false) === false) { + if ($scopeSpecified === true) { + $error = ucfirst($scope)." method name \"$className::$methodName\" is not in camel caps format"; + } else { + $error = "Method name \"$className::$methodName\" is not in camel caps format"; + } + + $phpcsFile->addError($error, $stackPtr); + return; + } + + }//end processTokenWithinScope() + + + /** + * Processes the tokens outside the scope. + * + * @param PHP_CodeSniffer_File $phpcsFile The file being processed. + * @param int $stackPtr The position where this token was + * found. + * + * @return void + */ + protected function processTokenOutsideScope(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $functionName = $phpcsFile->getDeclarationName($stackPtr); + + // Is this a magic function. IE. is prefixed with "__". + if (preg_match('|^__|', $functionName) !== 0) { + $magicPart = substr($functionName, 2); + if (in_array($magicPart, $this->_magicFunctions) === false) { + $error = "Function name \"$functionName\" is invalid; only PHP magic methods should be prefixed with a double underscore"; + $phpcsFile->addError($error, $stackPtr); + } + + return; + } + + // Function names can be in two parts; the package name and + // the function name. + $packagePart = ''; + $camelCapsPart = ''; + $underscorePos = strrpos($functionName, '_'); + if ($underscorePos === false) { + $camelCapsPart = $functionName; + } else { + $packagePart = substr($functionName, 0, $underscorePos); + $camelCapsPart = substr($functionName, ($underscorePos + 1)); + + // We don't care about _'s on the front. + $packagePart = ltrim($packagePart, '_'); + } + + // If it has a package part, make sure the first letter is a capital. + if ($packagePart !== '') { + if ($functionName{0} === '_') { + $error = "Function name \"$functionName\" is invalid; only private methods should be prefixed with an underscore"; + $phpcsFile->addError($error, $stackPtr); + return; + } + + if ($functionName{0} !== strtoupper($functionName{0})) { + $error = "Function name \"$functionName\" is prefixed with a package name but does not begin with a capital letter"; + $phpcsFile->addError($error, $stackPtr); + return; + } + } + + // If it doesn't have a camel caps part, it's not valid. + if (trim($camelCapsPart) === '') { + $error = "Function name \"$functionName\" is not valid; name appears incomplete"; + $phpcsFile->addError($error, $stackPtr); + return; + } + + $validName = true; + $newPackagePart = $packagePart; + $newCamelCapsPart = $camelCapsPart; + + // Every function must have a camel caps part, so check that first. + if (PHP_CodeSniffer::isCamelCaps($camelCapsPart, false, true, false) === false) { + $validName = false; + $newCamelCapsPart = strtolower($camelCapsPart{0}).substr($camelCapsPart, 1); + } + + if ($packagePart !== '') { + // Check that each new word starts with a capital. + $nameBits = explode('_', $packagePart); + foreach ($nameBits as $bit) { + if ($bit{0} !== strtoupper($bit{0})) { + $newPackagePart = ''; + foreach ($nameBits as $bit) { + $newPackagePart .= strtoupper($bit{0}).substr($bit, 1).'_'; + } + + $validName = false; + break; + } + } + } + + if ($validName === false) { + $newName = rtrim($newPackagePart, '_').'_'.$newCamelCapsPart; + if ($newPackagePart === '') { + $newName = $newCamelCapsPart; + } else { + $newName = rtrim($newPackagePart, '_').'_'.$newCamelCapsPart; + } + + $error = "Function name \"$functionName\" is invalid; consider \"$newName\" instead"; + $phpcsFile->addError($error, $stackPtr); + } + + }//end processTokenOutsideScope() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php b/test/codesniff/Reaktor/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php new file mode 100755 index 0000000..6ea538a --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php @@ -0,0 +1,115 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ScopeClosingBraceSniff.php,v 1.9 2007/07/23 01:47:53 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +/** + * Reaktor_Sniffs_Whitespace_ScopeClosingBraceSniff. + * + * Checks that the closing braces of scopes are aligned correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_WhiteSpace_ScopeClosingBraceSniff implements PHP_CodeSniffer_Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return PHP_CodeSniffer_Tokens::$scopeOpeners; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return void + */ + public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + // If this is an inline condition (ie. there is no scope opener), then + // return, as this is not a new scope. + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + return; + } + + // We need to actually find the first piece of content on this line, + // as if this is a method with tokens before it (public, static etc) + // or an if with an else before it, then we need to start the scope + // checking from there, rather than the current token. + $lineStart = ($stackPtr - 1); + for ($lineStart; $lineStart > 0; $lineStart--) { + if (strpos($tokens[$lineStart]['content'], $phpcsFile->eolChar) !== false) { + break; + } + } + + // We found a new line, now go forward and find the first non-whitespace + // token. + $lineStart = $phpcsFile->findNext(array(T_WHITESPACE), ($lineStart + 1), null, true); + + $startColumn = $tokens[$lineStart]['column']; + $scopeStart = $tokens[$stackPtr]['scope_opener']; + $scopeEnd = $tokens[$stackPtr]['scope_closer']; + + // Check that the closing brace is on it's own line. + $lastContent = $phpcsFile->findPrevious(array(T_WHITESPACE), ($scopeEnd - 1), $scopeStart, true); + if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) { + $error = 'Closing brace must be on a line by itself'; + $phpcsFile->addError($error, $scopeEnd); + return; + } + + // Check now that the closing brace is lined up correctly. + $braceIndent = $tokens[$scopeEnd]['column']; + $isBreakCloser = ($tokens[$scopeEnd]['code'] === T_BREAK); + if (in_array($tokens[$stackPtr]['code'], array(T_CASE, T_DEFAULT)) === true && $isBreakCloser === true) { + // BREAK statements should be indented 2 spaces from the + // CASE or DEFAULT statement. + if ($braceIndent !== ($startColumn + 2)) { + $error = 'Break statement indented incorrectly; expected '.($startColumn + 3).' spaces, found '.($braceIndent - 1); + $phpcsFile->addError($error, $scopeEnd); + } + } else { + if ($braceIndent !== $startColumn) { + $error = 'Closing brace indented incorrectly; expected '.($startColumn - 1).' spaces, found '.($braceIndent - 1); + $phpcsFile->addError($error, $scopeEnd); + } + } + + }//end process() + + +}//end class + +?> diff --git a/test/codesniff/Reaktor/Sniffs/WhiteSpace/ScopeIndentSniff.php b/test/codesniff/Reaktor/Sniffs/WhiteSpace/ScopeIndentSniff.php new file mode 100755 index 0000000..a33c63c --- /dev/null +++ b/test/codesniff/Reaktor/Sniffs/WhiteSpace/ScopeIndentSniff.php @@ -0,0 +1,48 @@ + + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version CVS: $Id: ScopeIndentSniff.php,v 1.11 2007/07/27 05:36:24 squiz Exp $ + * @link http://pear.php.net/package/PHP_CodeSniffer + */ + +if (class_exists('Generic_Sniffs_WhiteSpace_ScopeIndentSniff', true) === false) { + throw new PHP_CodeSniffer_Exception('Class Generic_Sniffs_WhiteSpace_ScopeIndentSniff not found'); +} + +/** + * Reaktor_Sniffs_Whitespace_ScopeIndentSniff. + * + * Checks that control structures are structured correctly, and their content + * is indented correctly. + * + * @category PHP + * @package PHP_CodeSniffer + * @author Greg Sherwood + * @author Marc McIntyre + * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600) + * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence + * @version Release: 1.0.0 + * @link http://pear.php.net/package/PHP_CodeSniffer + */ +class Reaktor_Sniffs_WhiteSpace_ScopeIndentSniff extends Generic_Sniffs_WhiteSpace_ScopeIndentSniff +{ + + /** + * Any scope openers that should not cause an indent. + * + * @var array(int) + */ + protected $nonIndentingScopes = array(); + protected $indent = 2; +}//end class + +?> diff --git a/test/data/audio-test-1.wav b/test/data/audio-test-1.wav new file mode 100644 index 0000000..ed97e88 Binary files /dev/null and b/test/data/audio-test-1.wav differ diff --git a/test/data/audio-test-2.ogg b/test/data/audio-test-2.ogg new file mode 100644 index 0000000..daa4515 Binary files /dev/null and b/test/data/audio-test-2.ogg differ diff --git a/test/data/audio-test-3.mp3 b/test/data/audio-test-3.mp3 new file mode 100644 index 0000000..9bf0a98 Binary files /dev/null and b/test/data/audio-test-3.mp3 differ diff --git a/test/data/audio-test-4.mid b/test/data/audio-test-4.mid new file mode 100644 index 0000000..8c7a614 Binary files /dev/null and b/test/data/audio-test-4.mid differ diff --git a/test/data/image-test-1.jpg b/test/data/image-test-1.jpg new file mode 100644 index 0000000..17c7175 Binary files /dev/null and b/test/data/image-test-1.jpg differ diff --git a/test/data/metadata/gong-ape-v2.mp3 b/test/data/metadata/gong-ape-v2.mp3 new file mode 100644 index 0000000..db740a4 Binary files /dev/null and b/test/data/metadata/gong-ape-v2.mp3 differ diff --git a/test/data/metadata/gong-id3-v1-and-ape-v2.mp3 b/test/data/metadata/gong-id3-v1-and-ape-v2.mp3 new file mode 100644 index 0000000..3067aa1 Binary files /dev/null and b/test/data/metadata/gong-id3-v1-and-ape-v2.mp3 differ diff --git a/test/data/metadata/gong-id3-v1-and-v2-and-ape-v2-with-image.mp3 b/test/data/metadata/gong-id3-v1-and-v2-and-ape-v2-with-image.mp3 new file mode 100644 index 0000000..e0da30d Binary files /dev/null and b/test/data/metadata/gong-id3-v1-and-v2-and-ape-v2-with-image.mp3 differ diff --git a/test/data/metadata/gong-id3-v1-and-v2-and-ape-v2.mp3 b/test/data/metadata/gong-id3-v1-and-v2-and-ape-v2.mp3 new file mode 100644 index 0000000..a25e953 Binary files /dev/null and b/test/data/metadata/gong-id3-v1-and-v2-and-ape-v2.mp3 differ diff --git a/test/data/metadata/gong-id3-v1-and-v2.mp3 b/test/data/metadata/gong-id3-v1-and-v2.mp3 new file mode 100644 index 0000000..36128a8 Binary files /dev/null and b/test/data/metadata/gong-id3-v1-and-v2.mp3 differ diff --git a/test/data/metadata/gong-id3-v1.mp3 b/test/data/metadata/gong-id3-v1.mp3 new file mode 100644 index 0000000..f5824d2 Binary files /dev/null and b/test/data/metadata/gong-id3-v1.mp3 differ diff --git a/test/data/metadata/gong-id3-v2-and-ape-v2.mp3 b/test/data/metadata/gong-id3-v2-and-ape-v2.mp3 new file mode 100644 index 0000000..547e531 Binary files /dev/null and b/test/data/metadata/gong-id3-v2-and-ape-v2.mp3 differ diff --git a/test/data/metadata/gong-id3-v2.mp3 b/test/data/metadata/gong-id3-v2.mp3 new file mode 100644 index 0000000..ae10f1d Binary files /dev/null and b/test/data/metadata/gong-id3-v2.mp3 differ diff --git a/test/data/metadata/gong-insane-metadata.ape b/test/data/metadata/gong-insane-metadata.ape new file mode 100644 index 0000000..a4a1086 Binary files /dev/null and b/test/data/metadata/gong-insane-metadata.ape differ diff --git a/test/data/metadata/gong-insane-no-metadata.ape b/test/data/metadata/gong-insane-no-metadata.ape new file mode 100644 index 0000000..7fa5151 Binary files /dev/null and b/test/data/metadata/gong-insane-no-metadata.ape differ diff --git a/test/data/metadata/gong-metadata.mp4 b/test/data/metadata/gong-metadata.mp4 new file mode 100644 index 0000000..a8a88ff Binary files /dev/null and b/test/data/metadata/gong-metadata.mp4 differ diff --git a/test/data/metadata/gong-metadata.wma b/test/data/metadata/gong-metadata.wma new file mode 100644 index 0000000..b14c163 Binary files /dev/null and b/test/data/metadata/gong-metadata.wma differ diff --git a/test/data/metadata/gong-no-metadata.flac b/test/data/metadata/gong-no-metadata.flac new file mode 100644 index 0000000..7e114e9 Binary files /dev/null and b/test/data/metadata/gong-no-metadata.flac differ diff --git a/test/data/metadata/gong-no-metadata.mp3 b/test/data/metadata/gong-no-metadata.mp3 new file mode 100644 index 0000000..049d4b2 Binary files /dev/null and b/test/data/metadata/gong-no-metadata.mp3 differ diff --git a/test/data/metadata/gong-no-metadata.mp4 b/test/data/metadata/gong-no-metadata.mp4 new file mode 100644 index 0000000..f9c8351 Binary files /dev/null and b/test/data/metadata/gong-no-metadata.mp4 differ diff --git a/test/data/metadata/gong-no-metadata.ogg b/test/data/metadata/gong-no-metadata.ogg new file mode 100644 index 0000000..4903a22 Binary files /dev/null and b/test/data/metadata/gong-no-metadata.ogg differ diff --git a/test/data/metadata/gong-no-metadata.wma b/test/data/metadata/gong-no-metadata.wma new file mode 100644 index 0000000..aa9c31c Binary files /dev/null and b/test/data/metadata/gong-no-metadata.wma differ diff --git a/test/data/metadata/gong-normal-metadata.ape b/test/data/metadata/gong-normal-metadata.ape new file mode 100644 index 0000000..58bf6f6 Binary files /dev/null and b/test/data/metadata/gong-normal-metadata.ape differ diff --git a/test/data/metadata/gong-normal-no-metadata.ape b/test/data/metadata/gong-normal-no-metadata.ape new file mode 100644 index 0000000..f02435e Binary files /dev/null and b/test/data/metadata/gong-normal-no-metadata.ape differ diff --git a/test/data/metadata/gong-vorbis-comment.flac b/test/data/metadata/gong-vorbis-comment.flac new file mode 100644 index 0000000..302d24d Binary files /dev/null and b/test/data/metadata/gong-vorbis-comment.flac differ diff --git a/test/data/metadata/gong-vorbis-comment.ogg b/test/data/metadata/gong-vorbis-comment.ogg new file mode 100644 index 0000000..a8f6a37 Binary files /dev/null and b/test/data/metadata/gong-vorbis-comment.ogg differ diff --git a/test/data/metadata/gong.wav b/test/data/metadata/gong.wav new file mode 100644 index 0000000..1303015 Binary files /dev/null and b/test/data/metadata/gong.wav differ diff --git a/test/data/metadata/image/255460-gong_super.jpg b/test/data/metadata/image/255460-gong_super.jpg new file mode 100644 index 0000000..3d5e160 Binary files /dev/null and b/test/data/metadata/image/255460-gong_super.jpg differ diff --git a/test/data/metadata/image/WS161.jpg b/test/data/metadata/image/WS161.jpg new file mode 100644 index 0000000..248d74b Binary files /dev/null and b/test/data/metadata/image/WS161.jpg differ diff --git a/test/data/small/dot.bmp b/test/data/small/dot.bmp new file mode 100644 index 0000000..8fe4bda Binary files /dev/null and b/test/data/small/dot.bmp differ diff --git a/test/data/small/dot.gif b/test/data/small/dot.gif new file mode 100644 index 0000000..2472b29 Binary files /dev/null and b/test/data/small/dot.gif differ diff --git a/test/data/small/dot.jpg b/test/data/small/dot.jpg new file mode 100644 index 0000000..4c0cba4 Binary files /dev/null and b/test/data/small/dot.jpg differ diff --git a/test/data/small/dot.png b/test/data/small/dot.png new file mode 100644 index 0000000..a22cf34 Binary files /dev/null and b/test/data/small/dot.png differ diff --git a/test/data/video-test-1.avi b/test/data/video-test-1.avi new file mode 100644 index 0000000..5977df9 Binary files /dev/null and b/test/data/video-test-1.avi differ diff --git a/test/data/video-test-2.ogg b/test/data/video-test-2.ogg new file mode 100644 index 0000000..7c4a601 Binary files /dev/null and b/test/data/video-test-2.ogg differ diff --git a/test/data/video-test-3.flv b/test/data/video-test-3.flv new file mode 100644 index 0000000..dce2496 Binary files /dev/null and b/test/data/video-test-3.flv differ diff --git a/test/data/video-test-4.wmv b/test/data/video-test-4.wmv new file mode 100644 index 0000000..04775d3 Binary files /dev/null and b/test/data/video-test-4.wmv differ diff --git a/test/functional/reaktor/000ProfileTest.php b/test/functional/reaktor/000ProfileTest.php new file mode 100644 index 0000000..7d63ae4 --- /dev/null +++ b/test/functional/reaktor/000ProfileTest.php @@ -0,0 +1,63 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick = 'monkeyboy'; + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); + +// first check that profile page is not viewable when not logged in +$b->get("/en/profile"); + +// should forward to register page +$b->isRedirected(); +$b->followRedirect(); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'profile'); +$b->isRequestParameter('action', 'register'); + +$b->get("/en"); +$b->isStatusCode(200); + +$b->setField('password', $nick); +$b->setField('username', $nick); +$b->click('Sign in'); +$b->followRedirect(); + +// click the edit profile link +$b->click('Edit profile'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'profile'); +$b->isRequestParameter('action', 'edit'); + +// check that we have arrived +$b->checkResponseElement('h1', '/Edit profile of monkeyboy/'); + +// do some basic editing +$b->setField('username_profile', 'userboy'); +$b->click('Save changes'); +$b->checkResponseElement('div#error_for_username_profile', '/already in use/'); + +$b->setField('residence_id', 1); +$b->setField('dob_day', 4); +$b->setField('dob_month', 5); +$b->setField('dob_year', 1983); +// (yes, this is my birthday) +$b->click('Save changes'); + +$b->checkResponseElement('div#error_for_dob', '!/not valid/'); +$b->checkResponseElement('div#error_for_dob', '!/complete date/'); +$b->checkResponseElement('div#error_for_residence', '!/must choose/'); + +?> \ No newline at end of file diff --git a/test/functional/reaktor/000homeActionsTest.php b/test/functional/reaktor/000homeActionsTest.php new file mode 100644 index 0000000..c0274bf --- /dev/null +++ b/test/functional/reaktor/000homeActionsTest.php @@ -0,0 +1,31 @@ +initialize(); + +// Insert bunch of bogus artworks to make the latest random artwork list happy +for ($i = 0; $i< 10; $i++) { + $artwork = new genericArtwork(); + $artwork->setUserId(2); + $artwork->changeStatus(1, 3); + $artwork->save(); + + $artworkFile = new artworkFile; + $artworkFile->setUserId(3); + $artworkFile->save(); + + $artwork->addFile($artworkFile); + $artwork->save(); +} + +$browser-> + get('/en')-> + isStatusCode(200)-> + isRequestParameter('module', 'home')-> + isRequestParameter('action', 'index')-> + checkResponseElement('div#recommend_block h1', '*We recommend*')-> + checkResponseElement('ul.my_page_image_list', true); + diff --git a/test/functional/reaktor/001AuthenticationTest.php b/test/functional/reaktor/001AuthenticationTest.php new file mode 100644 index 0000000..7fc6796 --- /dev/null +++ b/test/functional/reaktor/001AuthenticationTest.php @@ -0,0 +1,144 @@ + + * @author Daniel Andre Eikeland + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + + +$b->get("/no/profile"); + +$b->isStatusCode(302); +$b->isRequestParameter('module', 'profile'); +$b->isRequestParameter('action', 'edit'); + +$b->get("/no"); + +// Test clicking the login button with empty fields +$b->click('Sign in'); + +// Lets take a look at the resulting page so far +// It should be returning errors due to empty form fields +$b->responseContains("Username required"); +$b->responseContains("Password required"); + +// Now lets populate the username box and submit - this time it should not have the username error +$b->setField('username', 'random'); +$b->click('Sign in'); +$b->checkResponseElement("body", "!*Username required*"); +$b->checkResponseElement("div#sf_guard_auth_password", "*Password required*"); + +// We need to restart for the next test +$b->restart(); +$b->get('/no'); + +// Do the same with the password box +$b->setField('password', 'random'); +$b->click('Sign in'); +$b->checkResponseElement("div#sf_guard_auth_password", "!*Password required*"); +$b->checkResponseElement("div#sf_guard_auth_username", "*Username required*"); + +// We need to restart for the next test +$b->restart(); +$b->get('/no'); + +// Now popluate both fields to check for different error +$b->setField('password', 'random'); +$b->setField('username', 'random'); +$b->click('Sign in'); +$b->checkResponseElement("div#sf_guard_auth_password", "!*Password required*"); +$b->checkResponseElement("div#sf_guard_auth_username", "!*Username required*"); +$b->responseContains("Username or password is not valid"); + +// Now popluate both fields with all sorts of random characters +$b->setField('password', '!"#¤%&/()=?+90+\'".,<>*\'^~"'); +$b->setField('username', '!"#¤%&/()=?+90+\'".,<>*\'^~"'); +$b->click('Sign in'); +$b->checkResponseElement("div#sf_guard_auth_password", "!*Password required*"); +$b->checkResponseElement("div#sf_guard_auth_username", "!*Username required*"); +$b->responseContains("Username or password is not valid"); + +// Check that the form returns username but not password +$b->setField('password', 'randompassword'); +$b->setField('username', 'randomusername'); +$b->click('Sign in'); +$b->checkResponseElement("div#sf_guard_auth_password", "!*randompassword*"); +$b->responseContains("randomusername"); + +// Ok, so lets try with a user we know is in the database +// This test might fail at a later date when this user is removed from the db! +$b->setField('password', 'admin'); +$b->setField('username', 'nottherightpassword'); +$b->click('Sign in'); +$b->checkResponseElement("div#sf_guard_auth_password", "!*Password required*"); +$b->checkResponseElement("div#sf_guard_auth_username", "!*Username required*"); +$b->checkResponseElement("div#sf_guard_auth_username", "*Username or password is not valid*"); + +// try to log into an invalid account +$c = new Criteria(); +$c->add(sfGuardUserPeer::USERNAME,'admin'); +$c->addAscendingOrderByColumn('id'); + +$db_user = sfGuardUserPeer::doSelect($c); +$db_user[0]->setIsActive(0); +$db_user[0]->save(); + +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->checkResponseElement("body", "!*Password required*"); +$b->checkResponseElement("body", "!*Username required*"); +$b->checkResponseElement("div#sf_guard_auth_username", "!*Username or password is not valid*"); +$b->checkResponseElement("body", "*The account is not validated*"); + +// Finally, we test a correct login, we should be directed to the referred page +$db_user[0]->setIsActive(1); +$db_user[0]->save(); + +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->checkResponseElement("body", "!*password is required*"); +$b->checkResponseElement("body", "!*username is required*"); +$b->checkResponseElement("div#sf_guard_auth_username", "!*Username or password is not valid*"); + +// redirect the browser +$b->isRedirected()->followRedirect(); + +// check that the page loads correctly +$b->isStatusCode(200); +$b->checkResponseElement("body", "*my editorial center*"); + +// Finally we should check that the login state is maintained across the site +// I won't use click functionality here as the links may change + +$b->get("@register"); +$b->reload(); +$b->back(); +$b->get("/no"); + +$b->isStatusCode(200); + +//End of current test file diff --git a/test/functional/reaktor/002RegistrationTest.php b/test/functional/reaktor/002RegistrationTest.php new file mode 100644 index 0000000..e6d6ffb --- /dev/null +++ b/test/functional/reaktor/002RegistrationTest.php @@ -0,0 +1,155 @@ +initialize(); +$browser-> + get('/en/register')-> + isStatusCode(200)-> + isRequestParameter('module', 'profile')-> + isRequestParameter('action', 'register')-> + checkResponseElement('h1', '*Register as a user*')-> + //this checks that the config files are working + checkResponseElement('h2#information_msg', '/\*\*help-text when no field is selected\*\*/') +; + +//The fieldinformation we are going to test +$fields['username'] = array('username_profile', 'must enter a username', 'test'); +$fields['password'] = array('password_profile', 'choose a password', 'testdummy'); +$fields['password_repeat'] = array('password_repeat','must type the password twice', 'test'); +$fields['email'] = array('email', 'enter an email address', 'reaktor-functest@linpro.no'); +$fields['sex'] = array('sex','Please choose your sex','1'); +$fields['residence'] = array('residence_id', 'choose where your residence is', 1); +$fields['dob'] = array('dob', 'choose the date you were born', null); +$fields['terms_and_conditions'] = array('terms_and_conditions', 'must indicate that you have read and understood the terms', 1); + +//First we click the register button with empty fields and check that the validation works +$browser->click('Register me'); +foreach($fields as $field) +{ + $browser->checkResponseElement('div.profile_left', '*'.$field[1].'*'); +} + +//Now we enter all details but for one field to check that the fields we do fill in don't display validation messages +foreach($fields as $field) +{ + if($field[2]!= null) + { + $browser->setField($field[0], $field[2]); + } +} +$browser->click('Register me'); +foreach($fields as $field) +{ + if($field[2]!= null) + { + $browser->checkResponseElement('div.profile_left', '!/'.$field[1].'/'); + } +} + +//We do the same test but for the date of birth multi field, populate only date of birth fields +$browser-> + get('/en/register')-> + setField('dob[day]', 1)-> + setField('dob[month]', 1)-> + setField('dob[year]', 1999)-> + click('Register me'); +//check that all but dob field is validated +foreach($fields as $field) +{ + if($field[2]!= null) + { + $browser->checkResponseElement('div.profile_left', '*'.$field[1].'*'); + } + else + { + $browser->checkResponseElement('div.profile_left', '!/choose the date you were born/'); + } +} + +//Populate password and password_repeat field with different passwords +$browser-> + setField($fields['password'][0], $fields['password'][2])-> + setField($fields['password_repeat'][0], $fields['password_repeat'][2])-> + click('Register me')-> + checkResponseElement('div.profile_left', '*passwords do not match*'); + +//test #48 - do an actual registration +$fields['password_repeat'][2] = $fields['password'][2]; + +//populate all the fields +foreach($fields as $field) +{ + if($field[2]!= null) + { + $browser->setField($field[0], $field[2]); + } +} +$browser-> + setField('dob[day]', 1)-> + setField('dob[month]', 1)-> + setField('dob[year]', 1999)-> + setField('recaptcha_response_field', '1234567')-> # the CAPTCHA field is required, but not verified for tests + click('Register me'); + +//check the validation form hasn't kicked in again +foreach($fields as $field) +{ + $browser->checkResponseElement('div.profile_left', '!/'.$field[1].'/'); +} + +$browser->checkResponseElement('div#content_main h1', '*Registration successful*'); + +//register the same user twice +$browser->get('/en/register'); +//populate all the fields and check the user has been added +foreach($fields as $field) +{ + if($field[2]!= null) + { + $browser->setField($field[0], $field[2]); + } +} +$browser-> + setField('dob[day]', 1)-> + setField('dob[month]', 1)-> + setField('dob[year]', 1999)-> + setField('recaptcha_response_field', '1234567')-> # the CAPTCHA field is required, but not verified for tests + click('Register me')-> + checkResponseElement('div.profile_left','*This email is already in use*')-> + checkResponseElement('div.profile_left','*This username is already in use*'); + +// +//Activate account - here we need to cheat a little-. We're getting the activation code directly from the database +// +$con = Propel::getConnection(); + +$c = new Criteria(); +$c->add(sfGuardUserPeer::IS_VERIFIED, 0); +$c->addDescendingOrderByColumn('id'); + +$db_user = sfGuardUserPeer::doSelectOne($c); + +$browser-> + get('/en/profile/activate/key/'.$db_user->getSalt())-> + checkResponseElement('div#content_main h1', '*Activation successful*'); + diff --git a/test/functional/reaktor/004MypageTest.php b/test/functional/reaktor/004MypageTest.php new file mode 100644 index 0000000..95c854d --- /dev/null +++ b/test/functional/reaktor/004MypageTest.php @@ -0,0 +1,76 @@ + + * @author Russ + * + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick = "monkeyboy"; +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Try to be here without being logged in +$b->get("/no/mypage/". $nick); +$b->isStatusCode(404); + +$b->setField('password', $nick); +$b->setField('username', $nick); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$b->isRequestParameter('module', 'profile'); +$b->isRequestParameter('action', 'myPage'); + +//Now we are logged in, we should see our daddy in the latest commented list +$b->checkResponseElement("div#latestcommented", "/Fingers/"); + +$b->checkResponseElement("div#content_main", "/My artwork/"); + +$b->checkResponseElement("div#mypage_left", "/Recieved comments/"); +$b->checkResponseElement("div#mypage_left", "/Not me/"); + +$b->checkResponseElement("div#mypage_left", "/My latest commented artworks/"); +$b->checkResponseElement("div#mypage_left", "/Fingers/"); + +$b->checkResponseElement("div#content_main", "/a favourite with/"); +$b->checkResponseElement("div#content_main", "/dave/"); + +$b->checkResponseElement("div#content_main", "/My favourite users/"); +$b->checkResponseElement("div#content_main", "/admin/"); + +$b->checkResponseElement("body", "/My favourite artworks/"); +$b->checkResponseElement("body", "/The fancy gallery/"); + +$b->checkResponseElement("body", "/Users with shared interests/"); +$b->checkResponseElement("body", "/There are no users with matching interests\./"); + +$b->checkResponseElement("body", "/Written comments/"); +$b->checkResponseElement("body", "/Music to my ears/"); +$b->checkResponseElement("body", "/All comments/"); + +$b->checkResponseElement("div#mypage_right", "/Manage my artworks/"); +$b->checkResponseElement("div#mypage_right", "/manage and order artwork/"); + +$b->checkResponseElement("div#mypage_right", "/My resources /"); +$b->checkResponseElement("div#mypage_right", "/http:\/\/vg.no/"); +$b->checkResponseElement("div#mypage_right", "/Add a resource/"); + +$b->checkResponseElement("div#mypage_right", "/My favourite articles/"); +$b->checkResponseElement("div#mypage_right", "/There are no favourites in this list/"); +Favourite::ADDFavourite(3, "article", 2); +$b->reload(); +$b->checkResponseElement("div#mypage_right", "!/There are no favourites in this list/"); +$b->checkResponseElement("div#mypage_right", "/What is up in the tech world/"); + + +?> diff --git a/test/functional/reaktor/005AdminMessageTest.php b/test/functional/reaktor/005AdminMessageTest.php new file mode 100644 index 0000000..9393665 --- /dev/null +++ b/test/functional/reaktor/005AdminMessageTest.php @@ -0,0 +1,35 @@ +initialize(); +$b->get('/'); +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$b->get('/no/admin/message'); +$b->checkResponseElement("div#sidebar", "*System has been updated!*"); +$b->click('delete'); +$b->checkResponseElement("div#sidebar", "!/System has been updated!/"); + +$b->get('/no/admin/message/create'); +$b->setField('admin_message[message]', 'eat my monkeydust'); +$b->setField('admin_message[expires_at]', '23.05.2011 14.43'); +$b->setField('id', ''); + +$b->click('save'); + + +$b->get('/no/admin/message'); +$b->checkResponseElement("div#sidebar", "*eat my monkeydust*"); + +$b->click('edit'); +$b->setField('admin_message[message]', 'eat my new monkeydust'); +$b->click('save'); + +$b->get("/"); +$b->checkResponseElement("div#sidebar", "*eat my new monkeydust*"); \ No newline at end of file diff --git a/test/functional/reaktor/005MessageTest.php b/test/functional/reaktor/005MessageTest.php new file mode 100644 index 0000000..be78985 --- /dev/null +++ b/test/functional/reaktor/005MessageTest.php @@ -0,0 +1,85 @@ + + * + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick1 = "monkeyboy"; +$nick2 = "userboy"; +$user1 = sfGuardUserPeer::getByUsername($nick1); +$user2 = sfGuardUserPeer::getByUsername($nick2); + +$b = new sfTestBrowser(); +$b->initialize(); + +// Try to be here without being logged in +$b->get("/"); +$b->checkResponseElement('div#sidebar', '!/Messages:/'); + +//log in and check that messages box appears +$b->setField('password', $nick1); +$b->setField('username', $nick1); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$b->checkResponseElement('div#sidebar', '/Messages:/'); + +//send messages and check that they are received + +MessagesPeer::sendMessage($user1->getId(),$user2->getId(),"","Hello monkeyWorld!",0); + +$b->reload(); +$b->checkResponseElement('div#sidebar', '/Messages:/'); +$b->checkResponseElement('div#message_subject_holder', '*Hello monkeyWorld*'); +$b->checkResponseElement('div#message_summary', '*1 new*'); + +MessagesPeer::sendMessage($user2->getId(),$user1->getId(),"","Hello monkeyWorld boy!",0); + +$b->click('Log out'); +$b->isRedirected()->followRedirect(); + +$b->setField('password', $nick2); +$b->setField('username', $nick2); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$b->checkResponseElement('div#message_subject_holder', '*Hello monkeyWorld boy*'); +$b->checkResponseElement('div#message_summary', '*1 new*'); + +//Mark message as read and check that it appears right + +$messages = MessagesPeer::doselect(new Criteria()); + +foreach ($messages as $message) +{ + $message->setIsRead(1); + $message->save(); +} + +$b->reload(); + +$b->checkResponseElement('div#message_subject_holder', '!/Hello monkeyWorld boy/'); +$b->checkResponseElement('div#message_subject_holder_read', '*Hello monkeyWorld boy*'); + +//check that deleted message is deleted + +foreach ($messages as $message) +{ + $message->markAsDeletedByTo(); + $message->markAsDeletedByFrom(); + $message->save(); +} + +$b->reload(); +$b->checkResponseElement('div#message_subject_holder', '!/Hello monkeyWorld boy/'); +$b->checkResponseElement('div#message_subject_holder_read', '!/Hello monkeyWorld boy/'); + diff --git a/test/functional/reaktor/006ReportUnsuitableContentTest.php b/test/functional/reaktor/006ReportUnsuitableContentTest.php new file mode 100644 index 0000000..62f4720 --- /dev/null +++ b/test/functional/reaktor/006ReportUnsuitableContentTest.php @@ -0,0 +1,191 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//First we check that the security is up for viewing list of artworks under discussion +$b-> + get("/en/admin/list/file/reported")-> + isStatusCode(404)-> + isRequestParameter('module', 'artwork')-> + isRequestParameter('action', 'listReportedContent'); + +//Lets log in as a non admin user - this user should always exist in test db, page should generate 404 error +$user = sfGuardUserPeer::getByUsername('userboy'); +$b-> + setField('password', 'userboy')-> + setField('username', 'userboy')-> + click('Sign in')-> + isRedirected()-> + followRedirect()-> + isStatusCode(404); + +//Lets report a file in an artwork as unsuitable + +// Get an artwork from the database, that doesn't belong to userboy, and only has one file +$c = new Criteria(); +$c->addSelectColumn(ReaktorArtworkFilePeer::ARTWORK_ID); +$c->addSelectColumn('count('.ReaktorArtworkFilePeer::ARTWORK_ID.') as countfiles'); +$c->addJoin(ReaktorArtworkPeer::ID, ReaktorArtworkFilePeer::ARTWORK_ID, Criteria::LEFT_JOIN); +$c->add(ReaktorArtworkPeer::STATUS, 3); +$c->add(ReaktorArtworkPeer::USER_ID, $user->getId(), Criteria::NOT_EQUAL); +$c->addGroupByColumn(ReaktorArtworkFilePeer::ARTWORK_ID); +$c->setLimit(1); + +$c->addAscendingOrderByColumn(ReaktorArtworkPeer::ACTIONED_AT); +$rs = ReaktorArtworkPeer::doSelectRS($c); + +if($rs->next()&&$rs->getInt(2)==1) +{ + $artwork = ReaktorArtworkPeer::retrieveByPK($rs->getInt(1)); + $generic_artwork = new genericArtwork($artwork); +} +else +{ + echo 'There are no artworks with only one file, many of the following tests will fail'; +} + + +if(!$artwork) +{ + echo "Nothing to test! Following tests will fail. Check fixtures for at least one approved artwork"; +} + +//Check report unsuitable link is there +$b-> + get(url_for($artwork->getLink()))-> + checkResponseElement('div#unsuitable_content_msg', '*Report unsuitable content*'); +//Cheat by reporting file as unsuitable directly in the database (it's ajax), and updating cookie manually +//TODO: the cookies doesn't work.. + +$file = $generic_artwork->getFirstFile(); +$file->reportAsUnsuitable($user); +/* FIXME: The cookie +$b->getResponse()->setCookie('reported_file_'.$file->getId(), 1, time()+60*60*24*10); +$cookies = $b->getResponse()->getCookies(); +$b->test()->is($cookies['reported_file_'.$file->getId()]['value'], "1"); +*/ + + +$b-> + reload()-> +#checkResponseElement('span.admin_message', '*You have reported this file*')-> + click('Log out'); + +//We log in as an admin - this user should also always exist in the test db +//Test that admin has it's own message on the artwork page and that that file is in the +//files reported list +$b-> + get(url_for($artwork->getLink()))-> + setField('password', 'admin')-> + setField('username', 'admin')-> + click('Sign in')-> + isRedirected()-> + followRedirect()-> + isRequestParameter('module', 'artwork')-> + isRequestParameter('action', 'show')-> + checkResponseElement('div.admin_message', '/This content was reported by/')-> + checkResponseElement('div.moderator_block', '*Reject artwork*')-> + get("/en/admin/list/file/reported")-> + isStatusCode(200)-> + isRequestParameter('module', 'artwork')-> + isRequestParameter('action', 'listReportedContent')-> + checkResponseElement('h4.artwork_list_header', '*'.$file->getTitle().'*'); + +//Report file as OK, check it's removed from from the reported content list +$file->reportAsSuitable($user); + +$b-> + reload()-> + isRequestParameter('module', 'artwork')-> + isRequestParameter('action', 'listReportedContent')-> + checkResponseElement('h4.artwork_list_header', '!/'.$file->getTitle().'/')-> + get(url_for($artwork->getLink()))-> + checkResponseElement('div.admin_message', '*This content has not been reported*')-> + checkResponseElement('div.moderator_block', '*Reject artwork*'); + +//Report file again +$file->reportAsUnsuitable($user); + +//Report a file from an artwork with more than one file +$c2 = new Criteria(); +$c2->addSelectColumn(ReaktorArtworkFilePeer::ARTWORK_ID); +$c2->addSelectColumn('count('.ReaktorArtworkFilePeer::ARTWORK_ID.') as countfiles'); +$c2->addJoin(ReaktorArtworkPeer::ID, ReaktorArtworkFilePeer::ARTWORK_ID, Criteria::LEFT_JOIN); +$c2->add(ReaktorArtworkPeer::STATUS, 3); +$c2->addGroupByColumn(ReaktorArtworkFilePeer::ARTWORK_ID); +$c2->setLimit(1); + +$c2->addDescendingOrderByColumn('countfiles'); +$rs = ReaktorArtworkPeer::doSelectRS($c2); +if($rs->next()&&$rs->getInt(2)>1) +{ + $m_artwork = ReaktorArtworkPeer::retrieveByPK($rs->getInt(1)); + $m_generic_artwork = new genericArtwork($m_artwork); +} +else +{ + echo 'There are no approved artworks with more than one file, many of the following tests will fail'; +} + +$m_file = $m_generic_artwork->getFirstFile(); +$m_file->reportAsUnsuitable($user); + +//Clicking a button element is as of yet not supported by sftestbrowser, but we can check they're there.. +$b-> + get("/en/admin/list/file/reported")-> + checkResponseElement('div#admin_buttons_'.$m_file->getId(), '*Remove from artwork*')-> + responseContains('artwork/removefilemessage/'.$m_file->getId()); + +//Reject artwork with one file, this is thorougly tested with 040ArtworkRejectionTest, +//but we still check that it is removed from the reported files list after being rejected +$b-> + get('/en/artwork/reject/'.$generic_artwork->getId())-> + checkResponseElement('div#content_main h1' ,'/Reject artwork/')-> + checkResponseElement('div.warning' , '/Note! You are about to reject an artwork/')-> + setField('rejectionmsg','This artwork is not appropriate')-> + setField('rejectiontype','2')-> + click('Reject')-> + checkResponseElement('div#error_for_rejectionmsg',false)-> + isRedirected()-> + followRedirect(); +$artwork = ReaktorArtworkPeer::retrieveByPK($generic_artwork->getId()); + +$b-> + checkResponseElement('div#error_for_rejectionmsg',false)-> + responseContains('Show rejection message')-> + responseContains('This artwork is not appropriate')-> + checkResponseElement('div#content_main', '*Rejected on '.date("d/m/Y", strtotime($artwork->getActionedAt())).' at ' .date("H:i", strtotime($artwork->getActionedAt())).' by admin*')-> + get("/en/admin/list/file/reported"); + +//Remove file from artwork +$b-> + get('/en/admin/artwork/removefilemessage/'.$m_file->getId())-> + checkResponseElement('div#content_main h1' ,'/Remove file/')-> + checkResponseElement('div.warning' , '/Note! You are about to remove this file from the artwork and send an e-mail to/')-> + click('Remove')-> + responseContains('Please choose why this file is being removed')-> + responseContains('Please enter a rejection message')-> + setField('rejectionmsg','This file is not appropriate')-> + setField('rejectiontype','2')-> + click('Remove')-> + checkResponseElement('div#rejection_form','!/Please choose why this file is being removed/')-> + checkResponseElement('div#rejection_form','!/Please enter a rejection message/')-> + isRedirected()-> + followRedirect()-> + checkResponseElement('li#artwork_list_container_'.$m_file->getId().' h4', '/'.$m_file->getTitle().'/')-> + get("/en/admin/list/file/reported")-> + checkResponseElement('div#admin_buttons_'.$m_file->getId(), false); diff --git a/test/functional/reaktor/007RSSFeedsTest.php b/test/functional/reaktor/007RSSFeedsTest.php new file mode 100644 index 0000000..a234f8a --- /dev/null +++ b/test/functional/reaktor/007RSSFeedsTest.php @@ -0,0 +1,60 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Array of feeds +$feeds = array( + "/no/feed/latest_commented", + "/no/feed/latest_users", + "/no/feed/latest_artworks", + "/no/feed/popular_foto", + + "/no/foto/feed/most_popular", + "/no/foto/feed/latest_comments", + "/no/foto/feed/latest_users", + "/no/foto/feed/latest_artworks", + + "/no/groruddalen/feed/most_popular", + "/no/groruddalen/feed/latest_users", + "/no/groruddalen/feed/latest_artworks", + "/no/groruddalen/feed/latest_comments", + + "/no/groruddalen-foto/feed/most_popular", + "/no/groruddalen-foto/feed/latest_comments", + "/no/groruddalen-foto/feed/latest_users", + "/no/groruddalen-foto/feed/latest_artworks", +); + +$maxitems = sfConfig::get('app_rss_artwork_items', 5); +foreach($feeds as $URI) { + $b->get($URI); + $b->isStatusCode(200); + + // Retrieve the feed + $xml = $b->getResponse()->getContent(); + + $feed = sfFeedPeer::createFromXML($xml, $URI); + + $items = $feed->getItems(); + // And sanitycheck it + $b->test()->ok(count($items) <= $maxitems, "Checking for max number of items"); +} + + diff --git a/test/functional/reaktor/008tagsActionsTest.php b/test/functional/reaktor/008tagsActionsTest.php new file mode 100644 index 0000000..ca2ac86 --- /dev/null +++ b/test/functional/reaktor/008tagsActionsTest.php @@ -0,0 +1,30 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Check that the front page is loaded with test tags +$b->get('/no'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'home'); +$b->isRequestParameter('action', 'index'); +$b->checkResponseElement('div.tag_block', '/(.*)[animal|cute|silly](.*)/'); + +$b->get('/no/tags/tagAction?file=1'); +$b->isStatusCode(200); +#$b->checkResponse Element('div.tag_block', '/(.*)[animal|cute|silly](.*)/'); diff --git a/test/functional/reaktor/012ArtworkFavouritesTest.php b/test/functional/reaktor/012ArtworkFavouritesTest.php new file mode 100644 index 0000000..59caebd --- /dev/null +++ b/test/functional/reaktor/012ArtworkFavouritesTest.php @@ -0,0 +1,62 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Try to be here without specifying a file +$b->get("/no/artwork/show/2/The+fancy+gallery"); +$b->isStatusCode(); +$b->isRequestParameter('module', 'artwork'); +$b->isRequestParameter('action', 'show'); + +// Not logged in yet so we should see the list but not the links +$b->checkResponseElement("div#content_main", "* users like this artwork*"); + +# NOTE: If the "users like this artwork" test above failes this will most +# definetly fail to!! +$dom = $b->getResponseDom(); +$favs_count = $dom->getElementById("artwork_actions_and_favourites_js")->getElementsByTagName("ul")->item(0)->getElementsByTagName("li")->length; + + +// Make sure the count is correct +$b->checkResponseElement("div#content_main", "*$favs_count users like this artwork*"); + +$b->checkResponseElement("div#artwork_actions_and_favourites", "!*Add as favourite*"); +$b->checkResponseElement("div#artwork_actions_and_favourites", "!*Remove as favourite*"); + +// Lets clear the favourite for userboy if it exists, so we know where we are with the tests +//Lets log in and do the business +$b->setField('password', sfGuardUserPeer::retrieveByPK(2)->getUsername()); +$b->setField('username', sfGuardUserPeer::retrieveByPK(2)->getUsername()); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +// Now we should see an remove as favourite link + +$b->checkResponseElement("div#artwork_actions_and_favourites", "!*Mark artwork as favourite*"); +$b->checkResponseElement("div#artwork_actions_and_favourites", "*You like this artwork*"); + +// Now let's remove it as a favourite and check again... +// (manually since we can't do the ajax) +Favourite::deleteFavourite(2, "artwork", 2); +$b->get("/no/artwork/show/2/The+fancy+gallery"); +$b->checkResponseElement("div#artwork_actions_and_favourites", "!*Remove as favourite*"); +$b->checkResponseElement("div#artwork_actions_and_favourites", "*Mark this artwork as favourite*"); +// Final check really is to just see that favourite users are displayed correctly on the page... +Favourite::addFavourite(2, "artwork", 2); +$b->get("/no/artwork/show/2/The+fancy+gallery"); +$b->checkResponseElement("div#artwork_actions_and_favourites", "*".sfGuardUserPeer::retrieveByPK(2)->getUsername()."*"); + + diff --git a/test/functional/reaktor/017SearchTest.php b/test/functional/reaktor/017SearchTest.php new file mode 100644 index 0000000..5dd401a --- /dev/null +++ b/test/functional/reaktor/017SearchTest.php @@ -0,0 +1,65 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick = "admin"; +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// try to find artworks with 'car' +$b->get("/no/tags/find/tag/car"); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'tags'); +$b->isRequestParameter('action', 'find'); + +// check that it tries to display the results +$b->checkResponseElement("div#content_main", "/Work tagged with car/"); + +// check that it has a result in it +$b->checkResponseElement("div#content_main div.searchresult_row h4", '/My Pdf.*userboy/'); + +// click a tag in the results +$b->click('camping'); + +// check that it displays the new tag +$b->checkResponseElement("div#content_main", "/Work tagged with camping/"); + +// and that it displays more results +$b->checkResponseElement("div#content_main", '/The fancy gallery.*userboy/'); + +// try to combine more than one tag +$b->get("/no/tags/find/tag/car,lakes"); + +// check that it tries to display all tags +$b->checkResponseElement("div#content_main", "/Work tagged with car/"); +$b->checkResponseElement("div#content_main", "/Work tagged with lakes/"); + + +// check that it has a new artwork that will only be there if the new tag was displayed +$b->responseContains('Nice monkeys'); + +// try to find a user that doesn't exist +$b->get("/no/tags/find/tag/car/findtype/user"); +$b->responseContains('Sorry, could not find any users'); + +// try to find monkeyboy +$b->get("/no/tags/find/tag/monkeyboy/findtype/user"); + +// should end up on monkeyboys portfolio page +$b->followRedirect(); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'profile'); +$b->isRequestParameter('action', 'portfolio'); + +?> diff --git a/test/functional/reaktor/020OtherPeopleLikeTest.php b/test/functional/reaktor/020OtherPeopleLikeTest.php new file mode 100644 index 0000000..3121937 --- /dev/null +++ b/test/functional/reaktor/020OtherPeopleLikeTest.php @@ -0,0 +1,99 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$t = new reaktorTestBrowser(); +$t->initialize(); + + +// Approve the wonderful artwork +$aw = new genericArtwork(1); +$aw->changeStatus(1, 3, "hello world"); +$aw->save(); + +$urls = array( + 1 => "/no/artwork/show/1/The+wonderful+painting", + "/no/artwork/show/2/The+fancy+gallery", + 4 => "/no/artwork/show/4/Fingers", + 8 => "/no/artwork/show/8/Nice+monkeys", +); +foreach($urls as $id => $url) +{ + $c = new Criteria(); + $c->add(FavouritePeer::ARTWORK_ID, $id); + $favs = FavouritePeer::doSelect($c); + + $t->get($url); + $div = $t->getResponseDom()->getElementById("related_artwork_imagelist"); + + $thumbs = array(); + if (is_object($div)) + { + foreach($div->getElementsByTagName("a") as $thumb) + { + $tmp = trim($t->getResponseDom()->saveXML($thumb)); + $tmp = html_entity_decode($tmp); + if (preg_match("@

    (.*)

    @", $tmp, $match)) + { + $thumbs[] = $match[1]; + $t->test()->pass("Found {$match[1]}"); + } + else + { + $t->test()->fail("Was unable to find title from {$tmp}"); + } + } + } + + foreach($favs as $fav) + { + $user = sfGuardUserPeer::retrieveByPK($fav->getUserId()); + // Make sure all these users actually like this artwork + $t->checkResponseElement("div#artwork_actions_and_favourites", "*{$user->getUsername()}*"); + + // Then check if any of them like anything else + $c = new Criteria(); + $c->add(FavouritePeer::USER_ID, $fav->getUserId()); + $c->add(FavouritePeer::FAV_TYPE, "artwork"); + $otherfavs = FavouritePeer::doSelect($c); + if (count($otherfavs) == 1) + { + $t->test()->pass("User only had one favourite"); + } + else + { + $t->test()->pass("User has more favourites"); + foreach($otherfavs as $otherfav) + { + if ($otherfav->getArtworkId() != $fav->getArtworkId()) + { + $artwork = new genericArtwork($otherfav->getArtworkId()); + $text = $artwork->getTitle(); + if (false !== ($i = array_search($text, $thumbs))) + { + $t->test()->pass("Found artwork in other favourites"); + unset($thumbs[$i]); + } + else + { + # This is not neciserally a failure, but since we don't have so much test data + # the favs can never outgrow the actual artowkrs :] + $t->test()->fail("Didn't find artwork in other favs"); + var_dump($text, $thumbs); + } + } + } + } + } +} + diff --git a/test/functional/reaktor/020OtherUsersInterestsTest.php b/test/functional/reaktor/020OtherUsersInterestsTest.php new file mode 100644 index 0000000..8e77113 --- /dev/null +++ b/test/functional/reaktor/020OtherUsersInterestsTest.php @@ -0,0 +1,67 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +$users = array( + 2, # monkeyboy + 4, # leo + 7, # languageboy +); + +foreach($users as $userid) +{ + $username = sfGuardUserPeer::retrieveByPK($userid)->getUsername(); + $isthisguyreallyinterestedinphoto = false; + foreach(range(1, 2) as $i) + { + // Login + $b->login($username, $username); + + // Fetch his current interests + $interests = UserInterestPeer::retrieveByUser($userid); + foreach((array)$interests as $interestObj) { + $interest = $interestObj->getSubreaktorId(); + $userIds = UserInterestPeer::retrieveUsersIdLiking($interest); + + foreach($userIds as $matchingUser) { + $matchusername = sfGuardUserPeer::retrieveByPK($matchingUser->getUserId())->getUsername(); + // If another user likes the same stuff as I do, and he isn't me + if ($matchusername != $username) + { + $b->login($matchusername, $matchusername)->isStatusCode(200); + $b->get("/no/mypage/$matchusername")->isStatusCode(200); + // Then I should show up on his interests page + $b->checkResponseElement("div#matcing_interests_user_list ul", "*$username*"); + + // And he on mine + $b->login($username, $username)->get("/no/mypage/$username")->isStatusCode(200); + // Then I should show up on his interests page + $b->checkResponseElement("div#matcing_interests_user_list ul", "*$matchusername*"); + } + } + } + if (!$isthisguyreallyinterestedinphoto) { + $isthisguyreallyinterestedinphoto = true; + + $b->login($username, $username); + $b->get("/no/profile")->isStatusCode(200); + // he didn't like photos, but now he does! + $b->setField("Foto", 1); + $b->click("Save changes")->isRedirected()->followRedirect()->isStatusCode(200); + } + } +} + diff --git a/test/functional/reaktor/020RandomArtworkTest.php b/test/functional/reaktor/020RandomArtworkTest.php new file mode 100644 index 0000000..a2669c4 --- /dev/null +++ b/test/functional/reaktor/020RandomArtworkTest.php @@ -0,0 +1,78 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + + +# Run these checks few times as the minithumbs are randomly picked +foreach(range(1, 5) as $i) +{ + $b->test()->pass("Loop#$i"); + // Iterate over few reaktors + foreach(array("", "/foto", "/tegning", "/film", "/lyd", "/tegneserier") as $uri) + { + $b->get("/no$uri"); + $dom = $b->getResponseDom(); + $home = $dom->getElementById("home_content"); + + $thumbs = $hrefs = array(); + // Fetch all the bigthumbnails + foreach($home->getElementsByTagName("div") as $div) + { + if (strpos($div->getAttribute("class"), "big_artwork") !== false) + { + foreach($div->getElementsByTagName("div") as $subdiv) + { + if (strpos($subdiv->getAttribute("class"), "big_thumbnail") !== false) + { + $link = $subdiv->getElementsByTagName("a"); + // Skip missing bigthumbnails (nothing in the reaktor) + if (!$link->length) + { + $b->test()->pass("No bigthumbnail here"); + continue; + } + // Fetch the link + $hrefs[] = $link->item(0)->getAttribute("href"); + } + } + } + } + // Make sure we didn't get to many bigthumbnails + # To many means either fault in the logic above or changed frontpages + $b->test()->ok(count($hrefs) < 4, "At most three big thumbnails"); + + // Fetch the minithumbs id + $minithumbs = $dom->getElementById("minithumbs"); + if (!$minithumbs) { + $b->test()->pass("No thumbnails, probably because the reaktor has to little test data"); + continue; + } + // And iterate over all the minithumbs + foreach($minithumbs->getElementsByTagName("li") as $li) + { + $link = $li->getElementsByTagName("a")->item(0)->getAttribute("href"); + // Make sure thei aren't the same as the bigthumbs + $b->test()->ok(!in_array($link, $hrefs), "Check if the minithumblink is one of the bigthumbnails"); + // And make sure the same minithumb isn't twice + $b->test()->ok(!in_array($link, $thumbs), "Check if the minithumblink is only once"); + $thumbs[] = $link; + } + } +} + + diff --git a/test/functional/reaktor/020SortableTagsTest.php b/test/functional/reaktor/020SortableTagsTest.php new file mode 100644 index 0000000..56f744f --- /dev/null +++ b/test/functional/reaktor/020SortableTagsTest.php @@ -0,0 +1,107 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$t = new reaktorTestBrowser(); +$t->initialize(); + +$t->get("/no/"); +$tags = array("car", "cute", "abigail", "grass"); +$t->setField("tag", implode(", ", $tags)); +$t->click("Find"); + +// Tags are alphabetically sorted +sort($tags); + +foreach(array("title", "date", "rating", "username") as $sortby) +{ + foreach(array("asc", "desc") as $dir) + { + $t->click($sortby); + foreach($tags as $tag) + { + $dates = $users = $titles = array(); + $t->responseContains("Work tagged with $tag"); + $container = $t->getResponseDom()->getElementById("artwork_search_tag_" .$tag); + foreach($container->getElementsByTagName("div") as $div) + { + if ($div->getAttribute("class") != "searchresult_row") + { + continue; + } + + $titles[] = $div->getElementsByTagName("h4")->item(0)->getElementsByTagName("a")->item(0)->nodeValue; + $users[] = $div->getElementsByTagName("h4")->item(0)->getElementsByTagName("span")->item(0)->nodeValue; + foreach($div->getElementsByTagName("span") as $item) + { + if ($item->getAttribute("class") == "upload_time") + { + $dates[] = strtotime($item->nodeValue); + break; + } + } + } + + $t->test()->pass("Testing $tag - $sortby - $dir"); + switch($sortby) { + case "date": + $odates = $dates; + sort($dates); + if ($dir == "desc") + { + $dates = array_reverse($dates); + } + $t->test()->ok($odates === $dates, "Dates are correctly sorted"); + break; + + case "title": + $otitles = $titles; + natsort($titles); + + if ($dir == "desc") + { + $titles = array_reverse($titles); + } + $t->test()->ok($titles === $otitles, "Titles alphabetically sorted"); + break; + + case "rating": + $t->test()->todo("How the heck? Parse the image names or what?"); # TODO + break; + + case "username": + $users = array_unique($users); # Workaround annoying feature of the natural sorting algorithm, stupid quicksort based sorts algos!! + $ousers = $users; + natsort($users); + + if ($dir == "desc") + { + $users = array_reverse($users); + } + $t->test()->ok($users === $ousers, "Usernames alphabetically sorted"); + + break; + default: + $t->test()->fail("Unknown sort: $sortby"); + } + } + } +} + + diff --git a/test/functional/reaktor/020UserListTest.php b/test/functional/reaktor/020UserListTest.php new file mode 100644 index 0000000..a2b38af --- /dev/null +++ b/test/functional/reaktor/020UserListTest.php @@ -0,0 +1,81 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$t = new reaktorTestBrowser(); +$t->initialize(); + +$chars = array("a", "A", "e", "E", "l", "L", "u", "U"); +$users = array( + "a" => array( + ), + "e" => array( + ), + "l" => array( + "leo", + ), + "u" => array( + "userboy", + ), +); +$skip = array( + "a" => array( + "admin", + ), + "e" => array( + "editorialboy1", "editorialboy2", "editorialboy3", + ), + "l" => array( + "languageboy", + ), +); + +// Iterate over few chars +foreach($chars as $char) +{ + // Fetch a list of users startin with $char + $t->get("/no/list/users/startingwith/$char"); + if (strtolower($char) == 'a') + { + // Admin should not be displaed + $t->checkResponseElement("div#content_main ul", "!*admin*"); + } + if (empty($users[strtolower($char)])) + { + // Make sure this list is empty + $t->checkResponseElement("div#content_main", "*Sorry, could not find any users*"); + continue; + } + + foreach($users[strtolower($char)] as $user) + { + // And make sure all known users are there + $t->checkResponseElement("div#content_main ul", "*$user*"); + } + if ($char == 'u') + { + // Disable userboy + $t->login("admin", "admin", "/no/admin/edit/user/3") + ->setField("sf_guard_user[is_active]", "0") + #->setField("sf_guard_user[show_content]", "0") + ->click("Save") + ->isRedirected() + ->followRedirect(); + # And delete userboy from the array as he shouldn't show up disabled + $users["u"] = array(); + } +} + + diff --git a/test/functional/reaktor/021TagAdminTest.php b/test/functional/reaktor/021TagAdminTest.php new file mode 100644 index 0000000..dcf5960 --- /dev/null +++ b/test/functional/reaktor/021TagAdminTest.php @@ -0,0 +1,112 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//First we check that the security is up for viewing list of artworks under discussion +$b-> + get("/no/admin/tags/list/page/ALL")-> + isStatusCode(200)-> + isRequestParameter('module', 'tags')-> + isRequestParameter('action', 'listTags')-> + checkResponseElement('div#secure_notice p','*You need to log in*'); + +$b-> + setField('password', 'userboy')-> + setField('username', 'userboy')-> + click('Sign in')-> + isRedirected()-> + followRedirect()-> + isStatusCode(200)-> + checkResponseElement('div#content_main p','You don\'t have the requested permission to access this page.'); + +$b->click('Log out')-> + isRedirected()-> + followRedirect()-> + isStatusCode(200); + +$b-> + get("/no/admin/tags/list/page/ALL")-> + setField('password', 'admin')-> + setField('username', 'admin')-> + click('Sign in')-> + isRedirected()-> + followRedirect()-> + isStatusCode(200)-> + checkResponseElement('div#content_main p','!*You don\'t have the requested permission to access this page*'); + + //get all tags from DB + $c = new Criteria(); + $c->addAscendingOrderByColumn(TagPeer::NAME); + $tags = TagPeer::doSelect($c); + + //check that they are all displayed + $content = $b->getResponse()->getContent(); + $tag = current($tags); + $b->checkResponseElement("div#content_main", "/".$tag->getName()."/"); + + foreach ($tags as $tag) + { + $b->checkResponseElement("div#content_main", "/".$tag->getName()."/"); + } + + $b->get("/no/admin/tags/unapproved/page/ALL"); + foreach ($tags as $tag) + { + if ($tag->getApproved() == 0) + $b->responseContains($tag->getName()); + else + $b->checkResponseElement('div#content_main','!/ '.$tag->getName().' /'); + } + + //get unapproved tags from DB + $c = new Criteria(); + $c->addAscendingOrderByColumn(TagPeer::NAME); + $c->add(TagPeer::APPROVED,0); + $tags = TagPeer::doSelect($c); + + //test approval and so on for a few tags + $count = 0; + foreach ($tags as $tag) + { + if (++$count == 3) + break; + $b->get("/no/admin/tags/unapproved/page/ALL"); + $b->responseContains($tag->getName()); + /* + TagPeer::approveTagByName($tag->getName(),1); + $b->get("/no/admin/tags/unapproved/page/ALL"); + $b->checkResponseElement('body','!/ '.$tag->getName().' /'); + */ + + } + $fileId = 3; + $randomTag = "randomTag_".md5(time()); + $thisFile = new artworkFile($fileId); + $b->get("/no/upload/edit/".$fileId); + $b->checkResponseElement('body','!/'.$randomTag.'/'); + $thisFile->addTag($randomTag,true,true); + $b->get("/no/upload/edit/".$fileId); + $b->checkResponseElement('body','/'.$randomTag.'/'); + $b->get("/no/admin/tags/unapproved/page/ALL"); + $b->checkResponseElement('body','/'.$randomTag.'/'); + TagPeer::approveTagByName($randomTag,1); + $b->get("/no/admin/tags/unapproved/page/ALL"); + $b->checkResponseElement('body','!/'.$randomTag.'/'); + + $thisFile->removeTag($randomTag,true,true); + $b->get("/no/upload/edit/".$fileId); + $b->checkResponseElement('body','!/'.$randomTag.'/'); diff --git a/test/functional/reaktor/023SubreaktorsTest.php b/test/functional/reaktor/023SubreaktorsTest.php new file mode 100644 index 0000000..8f3a462 --- /dev/null +++ b/test/functional/reaktor/023SubreaktorsTest.php @@ -0,0 +1,250 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$b = new reaktorTestBrowser(); +$b->initialize(); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +$b->get("/no/admin/list/subreaktors"); + +/* #1-3 */ +$b->isStatusCode(200); +$b->isRequestParameter('module', 'subreaktors'); +$b->isRequestParameter('action', 'list'); + +/* #4 We should be presented with a login message, since this page is only ever for logged in users */ +$b->checkResponseElement("div#content_main", "*You need to log in*"); + +//Lets log in - this user should always exist in test db +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->followRedirect(); + +/* #5-6 Now we should be presented with the Subreaktor list page, if all went well */ +$b->checkResponseElement("div#content_main", "/Add a new subReaktor/"); +$b->checkResponseElement("div#content_main", "/Current subReaktors/"); + +/* #7-8 Lets check some of the standard subreaktors */ +$b->checkResponseElement("ul#subreaktor_list", "/Foto/"); +$b->checkResponseElement("ul#subreaktor_list", "/Film\/animasjon/"); + +/* #9-10 We can also check that the Foto Reaktor is first based on the ordering, + since this will only check the first instance of the class */ +$b->checkResponseElement("ul#subreaktor_list li.subreaktor_list", "/Foto/"); +$b->checkResponseElement("ul#subreaktor_list li.subreaktor_list", "!/Tegning\/graffikk/"); + +// Lets make the Foto reaktor "not live" and check it's status on this page +// We can also change the order of Foto and check that Tegning/graffikk has moved to the top + +$fotoReaktor = SubreaktorPeer::retrieveByPK(1); +echo "Foto reaktor order was ".$fotoReaktor->getSubreaktorOrder(); +$fotoReaktor->setLive(0); +$fotoReaktor->setSubreaktorOrder(2); +$fotoReaktor->save(); + +$tegningReaktor = SubreaktorPeer::retrieveByPK(2); +echo "Tegning reaktor order was ".$tegningReaktor->getSubreaktorOrder(); +$tegningReaktor->setSubreaktorOrder(1); +$tegningReaktor->save(); + +echo "Foto reaktor order is now ".$fotoReaktor->getSubreaktorOrder(); +echo "Tegning reaktor order is now ".$tegningReaktor->getSubreaktorOrder(); + +// The subreaktors most be repopulated when changed, or the old cached instance will be used +Subreaktor::_populateSubReaktors(); + +// Lets reload the page +$b->reload(); + +/* #11-12 Now photo should not be the first list element, Tegning should be */ +$b->checkResponseElement("ul#subreaktor_list li.subreaktor_list", "!/Foto/"); +$b->checkResponseElement("ul#subreaktor_list li.subreaktor_list", "/Tegning\/grafikk/"); + +/* #13 Foto should also be marked "not live" now, since we changed that above too */ +$b->checkResponseElement("li#subreaktor_1", "/not live/"); + +/* #14-15 Lets check the "not live" status by logging out and trying to access */ +$b->click("Log out"); +$b->isRedirected()->followRedirect(); +$b->get("/en/foto"); +$b->isStatusCode(404); + +/* #16 We should still be able to see it if we are admin though */ +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->followRedirect(); +$b->get("/en/foto"); +$b->isStatusCode(200); + +/* #17-18 Lets try to create a new subreaktor without entering any data */ +$b->get("/en/admin/list/subreaktors"); +$b->click("Create"); +$b->checkResponseElement("div#error_for_name", "/You must/"); +$b->checkResponseElement("div#error_for_reference", "/You must/"); + +/* #19-20 Lets fill only name field */ +$b->setField("name", "fred"); +$b->click("Create"); +$b->checkResponseElement("div#error_for_name", "!/You must/"); +$b->checkResponseElement("div#error_for_reference", "/You must/"); + +/* #21-22 Lets try to use weird characters in ref field */ +$b->setField("reference", "@£["); +$b->click("Create"); +$b->checkResponseElement("div#error_for_name", "!/You must/"); +$b->checkResponseElement("div#error_for_reference", "/Please use only alphanumeric characters /"); + +/* #23 lets use some real data */ +$b->setField("name", "Fred Reaktor"); +$b->setField("reference", "fred"); +$b->click("Create"); +$b->isRedirected()->followRedirect(); + +/* Possible problems here involve write access to folders which may throw up errors - if test fails after this point + Check the write permissions on /apps/reaktor/modules/subreaktors/templates and /web/images */ + +/* #24 Check we have a newly created subreaktor for editing */ +$b->checkResponseElement("body", "/Edit Fred Reaktor subReaktor/"); + +/* #25-28 Lets check the drop downs */ +$b->responseContains(''); +$b->setField("subreaktor_live", 1); +$b->setField("subreaktor_lokalreaktor", 0); //1 for lokalreaktor + +$b->click("Update subReaktor"); +$b->followRedirect(); +$b->responseContains(''); + +/* The rest is ajax so we should just put some data into the database and test the correct display + * First lets get the recently created subreaktor so we can modify it */ + +$c = new Criteria(); +$c->addDescendingOrderByColumn(SubreaktorPeer::ID); +$fredReaktor = SubreaktorPeer::doSelectOne($c); + +/* #29-30 Add some categories and check they appear correctly */ +$fredReaktor->addCategory(1); +$fredReaktor->addCategory(2); +$b->reload(); +$b->checkResponseElement("div#categoryList", "/architecture/"); +$b->checkResponseElement("div#categoryList", "/children/"); + +/* #31-32 Delete one of them and check it has gone */ +$fredReaktor->deleteCategory(1); +$fredReaktor->save(); + +$b->reload(); +$b->checkResponseElement("div#categoryList", "!/architecture/"); +$b->checkResponseElement("div#categoryList", "/children/"); + +/* #33-35 Same tests with file types */ +$fredReaktor->addFileType("image"); +$fredReaktor->addFileType("pdf"); +$b->reload(); +$b->checkResponseElement("div#subreaktorFiletypes", "/image/"); +$b->checkResponseElement("div#subreaktorFiletypes", "/pdf/"); + +$fredReaktor->deleteFileType("image"); +$b->reload(); +$b->checkResponseElement("div#subreaktorFiletypes", "!/image/"); +$b->checkResponseElement("div#subreaktorFiletypes", "/pdf/"); + +/** + * Would like to test the menu but can't get it working here, even though it's fine on the site + * +*/ + +// Perform cleanup +unlink(realpath(dirname(__FILE__).'/../../../apps/reaktor/modules/subreaktors/templates/fredReaktorSuccess.php')); +unlink(realpath(dirname(__FILE__).'/../../../web/images/logoFred.gif')); + +/* Lets load up some subreaktor pages, and check that the components are behaving */ +$b->get("/en/foto"); + +/* #36 ---> Check the category list */ +$fotoReaktor = Subreaktor::getByReference("foto"); +$categories = Subreaktor::listSubcategories($fotoReaktor); + +foreach ($categories as $category => $count) +{ + $b->checkResponseElement("div#top_block_right", "/".$category."/"); +} + +/* Check the tag cloud of a different subreaktor */ +Subreaktor::clear(); + +$b->get("/en/film"); + +$filmReaktor = Subreaktor::getByReference("film"); +$tags = TagPeer::getPopularTagsWithCount(sfConfig::get("app_home_max_tags", 5), sfConfig::get("app_home_max_tag_length", 500), $filmReaktor); + +foreach ($tags as $tag) +{ + $b->checkResponseElement("body", "/".$tag["displayName"]."/"); +} + +/* Lets do some basic tests for the most popular, latest comments and new users sections + Had enough of this test now, so will rely on the fixtures in some of the reaktors*/ + +Subreaktor::clear(); +$b->get("/en/foto"); + +// Most popular +$b->checkResponseElement("div.list_block_wrapper", "/The fancy gallery/"); + +// Latest comments +$b->checkResponseElement("div.list_block_wrapper", "/huh\?/"); +$b->checkResponseElement("div.list_block_wrapper", "/Sheesh/"); + +$user = sfGuardUserPeer::retrieveByUsername("userboy"); +$user->setLastActive(time()- 1000); +$user->save(); + +//New users +$b->reload(); +$b->checkResponseElement("div.list_block_wrapper", "/userboy/"); + +Subreaktor::clear(); +$b->get("/en/tekst"); + +// Spam test - SHOULD NOT show on page since it's unnapproved +$b->checkResponseElement("div.list_block_wrapper", "!/C1alis at net prices/"); + +// Latest comments +$b->checkResponseElement("div.list_block_wrapper", "/I hate Colin/"); +$b->checkResponseElement("div.list_block_wrapper", "/Huh\?/"); + +/* One last test - users that are not verified should not be on the new users list */ +Subreaktor::clear(); +$b->get("/en/foto"); +// Check that what we are testing below is valid +$b->checkResponseElement("div.list_block_wrapper", "/userboy/"); + + +$user->setIsActive(0); +$user->setIsVerified(0); + +$user->save(); +$b->reload(); + +// User should not appear now +$b->checkResponseElement("div.list_block_wrapper", "!/userboy/"); + diff --git a/test/functional/reaktor/025groupAdminActionsTest.php b/test/functional/reaktor/025groupAdminActionsTest.php new file mode 100644 index 0000000..e5f8158 --- /dev/null +++ b/test/functional/reaktor/025groupAdminActionsTest.php @@ -0,0 +1,83 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//Check if functionality is protected for users not logged in +$b->get('/no/admin/list/groups')->responseContains("You need to log in"); + +//Check if functionality is protected for logged in users without access +$b-> + setField('username', 'userboy')-> + setField('password', 'userboy')-> + click('Sign in'); + +$b->get('/no/admin/list/groups')->responseContains("You don't have the requested permission")->get('/no/logout'); + +// Log in as user with access +$b->get('/no')->setField('username', 'admin')->setField('password', 'admin')->click('Sign in'); + +// +//create group +// +$b->get('/no/sfGuardGroup/create') + ->isStatusCode(200) + ->isRequestParameter('module', 'sfGuardGroup') + ->isRequestParameter('action', 'create'); + +//$b->checkResponseElement('body [type="checkbox"]') //input[class="sf_admin_batch_checkbox"] +//input id="associated_permissions_1" type="checkbox" value="1" name="associated_permissions[] +$b->setField('sf_guard_group[name]', 'editor') + ->setField('sf_guard_group[description]', 'Editor description') + ->setField('associated_permissions[]', array(1,2,3)) + ->click('Save') + ->isRedirected() + ->followRedirect() + ->responseContains('Editor description') + ->responseContains('Editor'); + +// +//List groups, check new group is there +// +$b->get('/no/admin/list/groups') + ->isStatusCode(200) + ->isRequestParameter('module', 'sfGuardGroup') + ->isRequestParameter('action', 'list') + ->responseContains('Group list') + ->responseContains('Editor description') + ->responseContains('Editor'); + +// +//Delete group +// +/* There's a bug in propel that makes this test fail.. no workaround at this time.. +$b->click('publishers') + ->click('Delete group') + ->isRedirected() + ->followRedirect() + ->responseContains('Members') + ->responseContains('!/Editor description/') + ->responseContains('!/Editor/') + ->isRequestParameter('module', 'sfGuardGroup') + ->isRequestParameter('action', 'list'); +*/ + diff --git a/test/functional/reaktor/026AdminEditProfileInfoTest.php b/test/functional/reaktor/026AdminEditProfileInfoTest.php new file mode 100644 index 0000000..f06a6ed --- /dev/null +++ b/test/functional/reaktor/026AdminEditProfileInfoTest.php @@ -0,0 +1,122 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +define('NO_CLEAR', true); +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick = 'admin'; + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// first check that admin user edit page is not viewable when not logged in +$b->get("/en/admin/list/users"); + +// should not be accessible +$b->isStatusCode(200); +$b->responseContains('need to log in to view'); + +$b->get("/en"); +$b->isStatusCode(200); + +// log in as admin +$b->setField('password', $nick); +$b->setField('username', $nick); +$b->click('Sign in'); +$b->followRedirect(); + +// click the list users link in the admin portal +$b->click('List users'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'sfGuardUser'); +$b->isRequestParameter('action', 'list'); + +// check that we have arrived +$b->checkResponseElement('h1', '/List of users/'); + +// edit monkeyboy +$b->click('monkeyboy'); + +// check that we have the correct edit page +$b->checkResponseElement('div#content_main', '/Edit monkeyboy user/'); +$b->checkResponseElement('input[id="sf_guard_user_username"][value="monkeyboy"]'); +$b->checkResponseElement('input[id="sf_guard_user_email"][value="monkeyboy@linpro.no"]'); + +// try to change the password but not get it right +$b->setField('sf_guard_user[password]', 'fubar123'); +$b->setField('sf_guard_user[password_bis]', 'fubar124'); + +$b->click('Save'); + +// should give you an error +$b->checkResponseElement('div#content_main', '/Passwords do not match/'); + +// change the password +$b->setField('sf_guard_user[password]', 'fubar123'); +$b->setField('sf_guard_user[password_bis]', 'fubar123'); + +$b->click('Save'); + +// should save, then redirect (wouldn't redirect if the validation failed - save didn't happen) +$b->followRedirect(); + +// should not give you an error +$b->checkResponseElement('div#content_main', '!/Passwords do not match/'); + +// go to edit profile page for monkeyboy (id 2) +$b->get('/en/profile/edit/2'); + +// check that we are at the profile page for monkeyboy +$b->checkResponseElement('div#content_main', '/Edit profile of monkeyboy/'); +$b->checkResponseElement('input[id="username_profile"][value="monkeyboy"]'); +$b->checkResponseElement('input[id="email"][value="monkeyboy@linpro.no"]'); + +/* +//###Password changing has been moved to a seperate page + +// change passwords, but don't do it right +//$b->setField('password_profile', 'fubar123'); +//$b->setField('password_repeat', 'fubar12500000'); + +//$b->click('Save changes'); + +// should give you an error +//$b->checkResponseElement('div#error_for_password_repeat', '/passwords do not match/'); + +// change passwords properly +//$b->setField('password_profile', 'fubar123'); +//$b->setField('password_repeat', 'fubar123'); + +//$b->click('Save changes'); +//$b->followRedirect(); + +//$b->checkResponseElement('div#error_for_password_repeat', '!/passwords do not match/'); +*/ + +// edit some other information, like email and full name +$b->setField('email', 'fubar@fubar.com'); +$b->setField('name', 'Fubar Johnson'); + +$b->click('Save changes'); +$b->followRedirect(); + +// check that the information is updated +$b->checkResponseElement('input[id="email"][value="fubar@fubar.com"]'); +$b->checkResponseElement('input[id="name"][value="Fubar Johnson"]'); + +//change back e-mail address and name so we don't have to clear the database when this test runs next time +$b->setField('email', 'monkeyboy@linpro.no'); +$b->setField('name', 'monkey johns son'); +$b->click('Save changes'); +$b->isRedirected(); +$b->followRedirect(); + diff --git a/test/functional/reaktor/027viewDeactivatedUsersAndWorkTest.php b/test/functional/reaktor/027viewDeactivatedUsersAndWorkTest.php new file mode 100644 index 0000000..33966ca --- /dev/null +++ b/test/functional/reaktor/027viewDeactivatedUsersAndWorkTest.php @@ -0,0 +1,155 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$t = new reaktorTestBrowser(); +$t->initialize(); + +// Check if the functionality is protected for users not logged in +$t->get('/no/admin/list/users')->responseContains("You need to log in"); + +// Check if functionality is protected for logged in users without access +$t + ->setField('username', 'userboy') + ->setField('password', 'userboy') + ->click('Sign in'); + +$t + ->get('/no/admin/list/groups') + ->responseContains("You don't have the requested permission") + ->get('/no/logout'); + + +// Log in as user with access +$t + ->get('/no/admin/list/users') + ->setField('username', 'admin') + ->setField('password', 'admin') + ->click('Sign in'); + +// Open up userboys profile +$t + ->get('no/admin/edit/user/3') + ->responseContains("Edit userboy user") +// Make sure the "Activated" checkbox is checked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', true); + +$t +// Uncheck the "activated" checkbox + ->setField("sf_guard_user[is_active]", "0") + ->click("Save") + ->isRedirected() + ->followRedirect() +// Make sure the modifications have been saved + ->responseContains("Your modifications have been saved") +// ...and then make sure the checkbox is not cliked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', false); + + +// List all deactivated users +$t + ->get('/no/admin/list/users') + ->setField("filters[is_active]", 0) + ->click("filter") +// userboy should be deactivated + ->responseContains("userboy") +// But monkeyboy should not show up here + ->checkResponseElement("div#sf_admin_content", "!/monkeyboy/"); + +// List all activated users +$t + ->get('/no/admin/list/users') + ->setField("filters[is_active]", 1) + ->click("filter") +// userboy should not show up here + ->checkResponseElement("div#sf_admin_content", "!/userboy/") +// But monkeyboy should + ->checkResponseElement("div#sf_admin_content", "/monkeyboy/"); + + +// Check if I can still see userboys portfolio +$t + ->get("/no/portfolio/userboy") + ->responseContains("userboy's portfolio") + ->responseContains("The fancy gallery") # Name of a artwork he has in his portfolio +; + +// Open up monkeyboys profile +$t + ->get('no/admin/edit/user/2') + ->responseContains("Edit monkeyboy user") +// Make sure the "Activated" checkbox is checked and then uncheck it + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', true) + ->setField("sf_guard_user[is_active]", "0") + ->click("Save") + ->isRedirected() + ->followRedirect() +// Make sure the modifications have been saved + ->responseContains("Your modifications have been saved") +// ...and then make sure the checkbox is not cliked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', false); + + +// List all activated users +$t + ->get('/no/admin/list/users') + ->setField("filters[is_active]", 1) + ->click("filter") +// userboy should not show up here + ->checkResponseElement("div#sf_admin_content", "!/userboy/") +// and monkeyboy should neither + ->checkResponseElement("div#sf_admin_content", "!/monkeyboy/"); + +// List all deactivated users +$t + ->get('/no/admin/list/users') + ->setField("filters[is_active]", 0) + ->click("filter") +// userboy should show up here + ->checkResponseElement("div#sf_admin_content", "/userboy/") +// and monkeyboy should too + ->checkResponseElement("div#sf_admin_content", "/monkeyboy/"); + +// Open up monkeyboys profile +$t + ->get('no/admin/edit/user/2') + ->responseContains("Edit monkeyboy user") +// Make sure the "Activated" checkbox isn't checked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', false) + // check it (activate the user) + ->setField("sf_guard_user[is_active]", "1") + ->click("Save") + ->isRedirected() + ->followRedirect() +// Make sure the modifications have been saved + ->responseContains("Your modifications have been saved") +// ...and then make sure the checkbox is checked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', true); + +// Make sure monkeyboy is no longer in the deactivated list +$t + ->get('/no/admin/list/users') + ->setField("filters[is_active]", 0) + ->click("filter") +// userboy should still be there + ->checkResponseElement("div#sf_admin_content", "/userboy/") +// But monkeyboy not + ->checkResponseElement("div#sf_admin_content", "!/monkeyboy/"); + + diff --git a/test/functional/reaktor/028deactivatePermissionsTest.php b/test/functional/reaktor/028deactivatePermissionsTest.php new file mode 100644 index 0000000..47b8b96 --- /dev/null +++ b/test/functional/reaktor/028deactivatePermissionsTest.php @@ -0,0 +1,112 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +class localTestBrowser extends reaktorTestBrowser { + static $permissions = array( + 35, # Post new comments + 36, # Upload new content + 37, # Send messages to users + 38, # Rate artwork + 39, # Mark users/artwork as favourite + ); + + function enable($userid, $permission) { + is_integer($userid) or die("Expecting integer as userid , got " . gettype($userid)); + is_integer($permission) or die("Expecting integer, got " . gettype($permission)); + + // Login as admin + $this->login("admin", "admin", '/en/admin/edit/user/'.$userid) + ->responseContains("Edit userboy user"); + + // Enable it + return $this->setField("associated_permissions[]", array($permission)) + ->click("Save") + ->isRedirected() + ->followRedirect() + // Check if its really enabled + ->checkResponseElement('body div input[id="associated_permissions_' .$permission. '"][type="checkbox"][checked="checked"]', true); + } + +} + +$USERID = 3; +$USERNAME = "userboy"; +$PASSWORD = "userboy"; + + +$t = new localTestBrowser(); +$t->initialize(); + + +// Login as admin and open userboys profile +$t->login("admin", "admin", '/en/admin/edit/user/'. $USERID) + ->responseContains("Edit userboy user"); + +$t +// He currently has the "user" role + ->checkResponseElement('body div input[id="associated_groups_2"][type="checkbox"][checked="checked"]', true) +// Lets remove it + ->setField("associated_groups[]", null) + ->click("Save") + ->isRedirected() + ->followRedirect() +// Make sure the modifications have been saved + ->responseContains("Your modifications have been saved"); + +// Logout as admin +$t->logout(); + +// Login as userboy +$t->login($USERNAME, $PASSWORD, '/en/artwork/show/4/Fingers'); + +// Add a comment should fail +$t->checkResponseElement("body", "/You don't have permission to comment/"); + +// Enable it & test +$t->enable($USERID, 35) + ->login($USERNAME, $PASSWORD, '/en/artwork/show/4/Fingers') + ->setField("sf_comment", "This is my test comment :D") + ->setField("sf_comment_title", "Test comment title") + ->click("Post this comment") + ->responseContains("This is my test comment :D"); + +// He can't mark user as favourite +$t->checkResponseElement("body", "!/Mark this user as favourite/"); +$t->enable($USERID, 34); +$t->login($USERNAME, $PASSWORD, '/en/artwork/show/4/Fingers') + ->responseContains("Mark this user as favourite"); + +// He can't rate it +$t->checkResponseElement("body", "!/Rate it 5 stars/"); +$t->enable($USERID, 33); +$t->login($USERNAME, $PASSWORD, '/en/artwork/show/4/Fingers') +// But now he can + ->checkResponseElement("body", "/Rate it 5 stars/"); + +// He can't upload anything +$t->checkResponseElement("body", "!/Upload artwork now/"); +$t->enable($USERID, 31); +$t->login($USERNAME, $PASSWORD, '/en/artwork/show/4/Fingers') +// But now he can + ->checkResponseElement("body", "/Upload artwork now/"); + +// He can't send messages +$t->checkResponseElement("body", "!/Write new/"); +$t->enable($USERID, 32); +$t->login($USERNAME, $PASSWORD, '/en/artwork/show/4/Fingers') +// But now he can + ->checkResponseElement("body", "/Write new/"); + + diff --git a/test/functional/reaktor/028deactivateUserReActivateTest.php b/test/functional/reaktor/028deactivateUserReActivateTest.php new file mode 100644 index 0000000..82d4419 --- /dev/null +++ b/test/functional/reaktor/028deactivateUserReActivateTest.php @@ -0,0 +1,111 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$t = new reaktorTestBrowser(); +$t->initialize(); + +// Make sure userboy can log in +$t->login("userboy", "userboy") + ->checkResponseElement("div#user_summary .nickname", "userboy") +// And that he has artwork on the frontpage + ->checkResponseElement("div#popular_block", "/The fancy gallery/"); + +// Logout +$t->logout(); + +// Login as admin +$t->login("admin", "admin", "/no/admin/list/users"); + +// Open up userboys profile +$t + ->get('/en/admin/edit/user/3') + ->responseContains("Edit userboy user") +// Make sure the "Activated" checkbox is checked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', true) +// and the "show content" checkbox + ->checkResponseElement('body div input[id="sf_guard_user_show_content"][type="checkbox"][checked="checked"]', true) +// Then uncheck both of them + ->setField("sf_guard_user[is_active]", "0") + ->setField("sf_guard_user[show_content]", "0") + ->click("Save") + ->isRedirected() + ->followRedirect() +// Make sure the modifications have been saved + ->responseContains("Your modifications have been saved") +// ...and then make sure the checkbox is not cliked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', false) + ->checkResponseElement('body div input[id="sf_guard_user_show_content"][type="checkbox"][checked="checked"]', false); + +// Try to login as the deactivated user (userboy) +$t + ->login("userboy", "userboy", "/en", false) + ->responseContains("There was an error with your login, please check your details and try again.") + ->responseContains("The account is not validated"); + +// Make sure his portofilio has been blocked +$t + ->get("/en/portfolio/userboy") + ->responseContains("This users portfolio has been blocked"); + +// Login as admin +$t->login("admin", "admin", "/en/admin/list/users"); + +// Open up userboys profile +$t + ->get('/en/admin/edit/user/3') + ->responseContains("Edit userboy user") +// Make sure the "Activated" checkbox is unchecked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', false) +// and the "show content" checkbox + ->checkResponseElement('body div input[id="sf_guard_user_show_content"][type="checkbox"][checked="checked"]', false) +// Then activate his account - without enabling his content + ->setField("sf_guard_user[is_active]", "1") + ->click("Save") + ->isRedirected() + ->followRedirect() +// Make sure the modifications have been saved + ->responseContains("Your modifications have been saved") +// ...and then make sure the checkbox is not cliked + ->checkResponseElement('body div input[id="sf_guard_user_is_active"][type="checkbox"][checked="checked"]', true) + ->checkResponseElement('body div input[id="sf_guard_user_show_content"][type="checkbox"][checked="checked"]', false); + +// Logout +$t->logout(); + +// Make sure userboys portofolio is still blocked +$t + ->get("/en/portfolio/userboy") + ->responseContains("This users portfolio has been blocked"); + +// His portofolio is blocked, but userboy should be able to login +$t + ->login("userboy", "userboy") + ->checkResponseElement("div#user_summary .nickname", "userboy") +// Make sure his artwork is no longer on the frontpage + ->checkResponseElement("div#popular_block", "!/The fancy gallery/"); + +// He can see his own portofolio, even if its blocked +$t + ->get("/en/portfolio/userboy") +# FIXME: He should get some note about the fact his content is disabled + ->responseContains("userboy's portfolio"); + + diff --git a/test/functional/reaktor/030AssignEditorialTeamTest.php b/test/functional/reaktor/030AssignEditorialTeamTest.php new file mode 100644 index 0000000..fcd409e --- /dev/null +++ b/test/functional/reaktor/030AssignEditorialTeamTest.php @@ -0,0 +1,48 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//Navigate to an artwork without logging in, and check that we don't see which editorial team approved +$b->get("/no/artwork/show/2/The+fancy+gallery/") + ->checkResponseElement("div#artwork_editorialteam_tag", "!/Approved in Deichman by admin/"); + +//Log in as userboy and check that we still don't see which editorial team approved +$b->setField('password', 'userboy') + ->setField('username', 'userboy') + ->click('Sign in') + ->isRedirected() + ->followRedirect() + ->checkResponseElement("div#artwork_editorialteam_tag", "!/Approved in Deichman by admin/"); + +//Log in as staff and check that we do have access to see which editorial team approved +$b->click('Log out') + ->get("/no/artwork/show/2/The+fancy+gallery/") + ->setField('password', 'editorialboy1') + ->setField('username', 'editorialboy1') + ->click('Sign in') + ->isRedirected() + ->followRedirect() + ->checkResponseElement("div#artwork_editorialteam_tag", "*Approved in Deichman by admin*"); + +//This artwork is already approved, let's view an artwork that isn't and check it has a dropdown and different message +$b->get("no/artwork/show/6/Dolor+Sit") + ->checkResponseElement("div#artwork_editorialteam_tag", "*Awaiting approval by*") + ->checkResponseElement("#new_editorialteam", true); + +//Using the dropdown fires an ajax request which we cannot test here, so this is where it ends diff --git a/test/functional/reaktor/032CommentListTest.php b/test/functional/reaktor/032CommentListTest.php new file mode 100644 index 0000000..a2bb040 --- /dev/null +++ b/test/functional/reaktor/032CommentListTest.php @@ -0,0 +1,137 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Try to be here without specifying a file +$b->get("/no/admin/list/comments/user/3"); +$b->isStatusCode(404); +$b->isRequestParameter('module', 'sfComment'); +$b->isRequestParameter('action', 'listComments'); + +//We should be presented with a login message, since this page is only ever for logged in users +$b->checkResponseElement("div#content_main", "*the page or content that you have requested does not exist*"); + +//Lets log in as the wrong user - this user should always exist in test db, and is not admin +$b->setField('password', 'monkeyboy'); +$b->setField('username', 'monkeyboy'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$b->checkResponseElement("div#content_main", "*you do not have the required permissions to access this content*"); + +// Ok, so we need to log out and log in again as an admin user +$b->click('Log out'); +$b->isRedirected()->followRedirect(); +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$thisUser = sfGuardUserPeer::retrieveByPK(3); + +// Lets make sure we have enough comments for the test (to test pagination) +$testComments = array( + array("title" => "Random comment 1", "text" => "Random text 1\nsdvwevbewåvøæøå\ngmkls", "created" => "2007-03-01"), + array("title" => "Random comment 2", "text" => "Random text 2\n\nkvnsdkdåødsøvåøsdv", "created" => "2007-04-24"), + array("title" => "Random comment 3", "text" => "Random text 3\nvdvdsvdæv'æ'æåsdøvæ", "created" => "2007-04-24"), + array("title" => "Random comment 4", "text" => "Random text 4\n\n\nddsvæ'dvslpøøåøsdv2345678%&/(", "created" => "2007-01-01"), + array("title" => "Random comment 5", "text" => "Random text 5\nmoo moo moo moo moo moo moo", "created" => "2007-04-01") + ); + +foreach ($testComments as $commentArray) +{ + $myComment = new sfComment(); + $myComment->setTitle($commentArray["title"]); + $myComment->setText($commentArray["text"]); + $myComment->setAuthorId(3); + $myComment->setNamespace("frontend"); + $myComment->setCommentableModel("ReaktorArtwork"); + $myComment->setCommentableId(3); + $myComment->setCreatedAt($commentArray["created"]); + $myComment->save(); +} + +// Ok, let's get all this user's comments +$c = new Criteria(); +$c->add(sfCommentPeer::AUTHOR_ID, 3); +$c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT); +$c->addDescendingOrderByColumn(sfCommentPeer::ID); +$comments = sfCommentPeer::doSelect($c); + +// Lets force a low pagination so we know that it will paginate +sfConfig::set("app_admin_commentlistmax", 3); + +$b->get("/no/admin/list/comments/user/3"); +$b->checkResponseElement("div#content_main", "*Comments made by ".$thisUser->getUsername()."*"); + +// Check for pagination +$b->ResponseContains("/admin/list/comments/user/3/page/2"); + +// Check for latest comment on this page +$b->checkResponseElement("div#content_main", "*".$comments[0]->getTitle()."*"); + +// Check that the first comment is not on this page, since it should be paginated +$b->checkResponseElement("div#content_main", "!*".$comments[count($comments) - 1]->getTitle()."*"); + +// Now lets click the last page link and test for that comment again... +$b->click("Last"); +$b->checkResponseElement("div#content_main", "*".$comments[count($comments) - 1]->getTitle()."*"); + +// Right, all good so far - lets try the date functionality +$b->get("/no/admin/comments"); + +// Should show the current month since we didn't specify one +$b->checkResponseElement("div#content_main", "*Comments made in ".date("F")."*"); +#echo "This month: ".date("F"); + +$nextMonth = date("F", mktime(0, 0, 0, date("m")+1, date("d"), date("Y"))); + +// Click the next month and check it is being displayed +$b->click($nextMonth); +//echo "Next month: ".$nextMonth; + +$b->checkResponseElement("div#content_main", "*Comments made in ".$nextMonth."*"); + +// Ok we made some comments above, most were in April 2007 so lets go there +$b->get("/no/admin/comments/date/2007-04-01"); +$b->checkResponseElement("div#content_main", "*Comments made in April*"); + +// There should be a clickable number of comments on April 24th... might be some more in fixtures so best check +// We can't really click it, since it's a number and might be repeated elsewhere in the calendar +$c = new Criteria(); +$c->add(sfCommentPeer::CREATED_AT, "created_at LIKE '2007-04-24%'", Criteria::CUSTOM); +$countOn24 = sfCommentPeer::doCount($c); + +//echo "Comment count on 24th April: [ ".$countOn24." ]"; + +// We should be able to click a link which matches the above count, lets just check it exists +$b->responseContains('admin/list/comments/date/2007-04-24">'.$countOn24.''); + +// Now we know it's there, let's emulate the click - since we want to make sure we are going to the right place +$b->get("/no/admin/list/comments/date/2007-04-24"); +$b->isStatusCode(); +$b->isRequestParameter('module', 'admin'); +$b->isRequestParameter('action', 'listComments'); + +$b->checkResponseElement("div#content_main", "*Comments made on 24/04/2007*"); + +// We've already tested comment display and pagination which uses the same engine, +// so lets just check the change date link and be done with it + +$b->click("change date"); +$b->checkResponseElement("div#content_main", "*Comments made in ".date("F")."*"); diff --git a/test/functional/reaktor/034emailNotificationsTest.php b/test/functional/reaktor/034emailNotificationsTest.php new file mode 100644 index 0000000..468ddef --- /dev/null +++ b/test/functional/reaktor/034emailNotificationsTest.php @@ -0,0 +1,96 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// User +$u = new reaktorTestBrowser(); +$u->initialize(); + +$editors = array( + "admin" => "user_1", + "editorialboy1" => "user_8", + "editorialboy2" => "user_9", +); +$options = array( + "No email", + "Email on first incoming artwork", + "Email on all incoming artworks", +); + +/* This stuff has changed drastically */ +return; + +// Iterate over editorialboy1, 2 and 3 +foreach($editors as $username => $userid) { + // Login and open the notification page + $u->login($username, $username, "/en/admin/list/myteams"); + + // Iterate over the combobox and make sure they are there + foreach($options as $key => $value) { + $u->checkResponseElement('body div select[id="' .$userid. '"] option[value="' .$key. '"]', $value); + } + + // Iterate over all possible choices and click them + foreach($options as $key => $value) { + $u->setField($userid, $key)->click("Save"); + + // and make sure only the field we picked is selected + foreach($options as $k => $v) { + $u->checkResponseElement('body div select[id="' .$userid. '"] option[value="' .$k. '"][selected]', $k == $key); + } + } + +} + +foreach($editors as $username => $userid) { + // Now login as admin and bring up the notification page + $u->login("admin", "admin", "/en/admin/list/myteams"); + // Make sure we have these three editorialboys there + $u->responseContains($username); + + // Iterate over all possible choices and click them + foreach($options as $key => $value) { + $u->login("admin", "admin", "/en/admin/list/myteams"); + $u->setField($userid, $key)->click("Save"); + + // and make sure only the field we picked is selected + foreach($options as $k => $v) { + $u->checkResponseElement('body div select[id="' .$userid. '"] option[value="' .$k. '"][selected]', $k == $key); + } + + // Log in as the user and check if it really updated his settings + $u->login($username, $username, "/en/admin/list/myteams"); + foreach($options as $k => $v) { + $u->checkResponseElement('body div select[id="' .$userid. '"] option[value="' .$k. '"][selected]', $k == $key); + } + } + +} + + diff --git a/test/functional/reaktor/035UploadTest.php b/test/functional/reaktor/035UploadTest.php new file mode 100644 index 0000000..0a6e609 --- /dev/null +++ b/test/functional/reaktor/035UploadTest.php @@ -0,0 +1,108 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + + +$b->get("/en/upload"); + +$b->isStatusCode(200); +$b->isRequestParameter('module', 'upload'); +$b->isRequestParameter('action', 'upload'); + +//We should be presented with a login message, since this page is only ever for logged in users +$b->checkResponseElement("div#content_main", "*You need to log in*"); + + + +//Lets log in - this user should always exist in test db +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->followRedirect(); + +//Now we should be presented with the file dialogue, if login went well +$b->checkResponseElement("div#content_main", "*Step 1: File upload*"); + +// Lets try going here via a generated link for linking a file to artwork +// First we need to get a specific artwork, just in case primary keys are changing due to repeated fixtures loading +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, "image"); +$artworkObject = ReaktorArtworkPeer::doSelectOne($c); +$b->get("/en/upload/link/".$artworkObject->getId()); + +//We should now be expecting an image file to link +$b->checkResponseElement("div#content_main", "*Add file to artwork*"); +$b->checkResponseElement("div#content_main", "*Image*"); + +//Again with audio type +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, "audio"); +$artworkObject = ReaktorArtworkPeer::doSelectOne($c); +$b->get("/en/upload/link/".$artworkObject->getId()); + +//We should now be expecting an image file to link +$b->checkResponseElement("div#content_main", "*Add file to artwork*"); +$b->checkResponseElement("div#content_main", "*Audio*"); + +//Now with video type +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, "video"); +$artworkObject = ReaktorArtworkPeer::doSelectOne($c); +$b->get("/en/upload/link/".$artworkObject->getId()); + +//We should now be expecting an image file to link +$b->checkResponseElement("div#content_main", "*Add file to artwork*"); +$b->checkResponseElement("div#content_main", "*Video*"); + +//Now with text type +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, "text"); +$artworkObject = ReaktorArtworkPeer::doSelectOne($c); +$b->get("/en/upload/link/".$artworkObject->getId()); + +//We should now be expecting an image file to link +$b->checkResponseElement("div#content_main", "*Add file to artwork*"); +$b->checkResponseElement("div#content_main", "*Text*"); + +//Finally with pdf type +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, "pdf"); +$artworkObject = ReaktorArtworkPeer::doSelectOne($c); +$b->get("/en/upload/link/".$artworkObject->getId()); + +//We should now be expecting an image file to link +$b->checkResponseElement("div#content_main", "*Add file to artwork*"); +$b->checkResponseElement("div#content_main", "*Pdf*"); + +/* +// ZOID: File uploads not supported, however there is a patch, and they will be in 1.1 +// Now lets add a file of the wrong mime type for this link +//$b->setField("file", sfConfig::get("sf_test_dir")."/data/audio-test-1.wav"); +//echo "trying: ".sfConfig::get("sf_test_dir")."/data/audio-test-1.wav\n"; +//$b->click("Add"); +//$b->checkResponseElement("div#content_main", "*Wrong file type*"); +*/ + diff --git a/test/functional/reaktor/035userContentActionsTest.php b/test/functional/reaktor/035userContentActionsTest.php new file mode 100644 index 0000000..3784925 --- /dev/null +++ b/test/functional/reaktor/035userContentActionsTest.php @@ -0,0 +1,18 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$browser = new sfTestBrowser(); +$browser->initialize(); + +//ZOID: Test waiting to be written... \ No newline at end of file diff --git a/test/functional/reaktor/038ArtworkDiscussionTest.php b/test/functional/reaktor/038ArtworkDiscussionTest.php new file mode 100644 index 0000000..8145912 --- /dev/null +++ b/test/functional/reaktor/038ArtworkDiscussionTest.php @@ -0,0 +1,85 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// View the list of artworks under discussion +$b->get("/no/admin/listDiscussion"); +$b->isStatusCode(); +$b->isRequestParameter('module', 'admin'); +$b->isRequestParameter('action', 'listDiscussion'); + +//We should be presented with a login message, since this page is only ever for logged in users +$b->checkResponseElement("div#content_main", "*You need to log in*"); + +//Lets log in as a non admin user - this user should always exist in test db +$b->setField('password', 'userboy'); +$b->setField('username', 'userboy'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +// Userboy should not be trying to look at this page +$b->checkResponseElement("div#content_main", "*You don't have the requested*"); + +// Try with admin +$b->click('Log out'); +$b->get("/no/admin/listDiscussion"); + +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$b->isStatusCode(); +$b->isRequestParameter('module', 'admin'); +$b->isRequestParameter('action', 'listDiscussion'); + +// Now we should be looking at the edit page +$b->checkResponseElement("div#content_main", "*Under discussion*"); + +// Lets get something from the database that is under discussion +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::UNDER_DISCUSSION, 1); + +$underDiscussion = ReaktorArtworkPeer::doSelect($c); +if ($underDiscussion) +{ + $discussedObject = $underDiscussion[0]; +} +else +{ + echo "Nothing to test! Following tests will fail. Check fixtures for at least one object for discussion"; +} + +// We should see info about the object under discussion +$b->checkResponseElement("div#content_main", "*".$discussedObject->getTitle()."*"); +$b->responseContains(url_for("@show_discussion?type=artwork&id=".$discussedObject->getId()."&title=".$discussedObject->getTitle())); + +// Lets click the link and take a look then +$b->get(url_for("@show_discussion?type=artwork&id=".$discussedObject->getId()."&title=".$discussedObject->getTitle())); +// Check we can see the comments +$b->checkResponseElement("div#content_main", "/As a member of editorial staff, you can discuss this artwork/"); + +/* + * The comments use Ajax for processing, but also fall back to a standard page post if Javascript is disabled + * We can test that here, however the Ajax functionality should be tested manually also. + */ + +//Lets get a count of comments for this artwork, in case some have been added to fixtures +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ID, $discussedObject->getId()); +$c->add(sfCommentPeer::COMMENTABLE_MODEL, "ReaktorArtwork"); +$commentCount = sfCommentPeer::doCount($c); +echo "Comment count for this artwork in fixtures is: ".$commentCount."\n"; diff --git a/test/functional/reaktor/039TagEditTest.php b/test/functional/reaktor/039TagEditTest.php new file mode 100644 index 0000000..e77fb7c --- /dev/null +++ b/test/functional/reaktor/039TagEditTest.php @@ -0,0 +1,72 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//We can't test a lot, but lets at least test that the tags are appearing correctly + +$b->get("/no/upload/edit/1"); +$b->isStatusCode(); +$b->isRequestParameter('module', 'upload'); +$b->isRequestParameter('action', 'edit'); + +//We should be presented with a login message, since this page is only ever for logged in users +$b->checkResponseElement("div#content_main", "*You need to log in*"); + +//Lets log in - this user should always exist in test db +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); +$b->followRedirect(); + +//Now we should be presented with the file dialogue, if login went well +$b->checkResponseElement("div#content_main", "*Modify upload details*"); + +// Lets get all the tags for this object +// so we can check if they are appearing on the page +// hopefully file 1 will always have some tags! but we'll +// add some later just in case + +$thisFile = new artworkFile(1); +$tags = $thisFile->getTags(); + +// Lets check they are all displayed in the tag box +foreach($tags as $tag) +{ + $b->checkResponseElement("div#thumbnail_editpage", "*".$tag."*"); +} + +// And just to be on the safe side to make sure the test is executing correctly +$badTags = array("notatag", "1234567", "1d1d1d1d", "looney looney"); +foreach($badTags as $tag) +{ + $b->checkResponseElement("div#thumbnail_editpage", "!*".$tag."*"); +} + +// Lets add a tag and check for that, just in case there were none +// in the first place +// Since it's an Ajax call we need to do it manually +$thisFile->addTag("randomtag"); +$thisFile->save(); +$b->get("/no/upload/edit/1"); +$b->isStatusCode(); +$b->isRequestParameter('module', 'upload'); +$b->isRequestParameter('action', 'edit'); +$b->checkResponseElement("div#thumbnail_editpage", "*randomtag*"); + +// We could now test the various functions for deleting/approving but +// Since they are also Ajax calls, they will simply mimic the unit tests +// for these functions - there's really not a lot more I can test. diff --git a/test/functional/reaktor/040ArtworkRejectionTest.php b/test/functional/reaktor/040ArtworkRejectionTest.php new file mode 100644 index 0000000..b115c07 --- /dev/null +++ b/test/functional/reaktor/040ArtworkRejectionTest.php @@ -0,0 +1,89 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//check that page doesnt show when not logged in +$b->get('/en/admin/list/rejected')->isStatusCode(200); +$b->checkResponseElement('div#content_main', '*You need to log in to view this page, please use the login form to the right*'); + +$b->get('/en'); + +$b->setField('username', 'monkeyboy'); +$b->setField('password','monkeyboy'); +$b->click('Sign in'); + +$b->isRedirected()->followRedirect(); + +$b->checkResponseElement("div#user_summary .nickname", "monkeyboy"); + +// open approveartwork +$b->restart(); +$b->get('/en/admin/list/rejected')->isStatusCode(200); +$b->checkResponseElement('div#content_main', "*You need to log in to view this page, please use the login form to the right.*"); + +$b->restart(); +$b->get('/en/logout'); + +$b->get('/en'); +$b->setField('username', 'admin'); +$b->setField('password','admin'); +$b->click('Sign in'); + +$b->isRedirected()->followRedirect(); + +$b->responseContains('my editorial center'); +//Reject an artwork +$b->restart(); +$b->login("admin", "admin"); +$b->get('/en/admin/listUnapproved'); +$b->checkResponseElement('li', '!/No artworks/'); + +//lets get rejected artworks +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::STATUS,2); +$artworks = ReaktorArtworkPeer::doSelect($c); + +$first_artwork = array_shift($artworks); + +$b->get('/en/artwork/reject/'.$first_artwork->getId()); +$b->responseContains('Reject artwork'); +$b->responseContains('Note! You are about to reject an artwork'); +$b->click('Reject'); + +$b->setField('rejectionmsg','This artwork is not approriate'); +$b->click('Reject'); +$b->responseContains('Please choose why this artwork is rejected'); +$b->checkResponseElement('body','!/Please enter a rejection message/'); + +$b->setField('rejectionmsg',''); +$b->setField('rejectiontype','1'); +$b->click('Reject'); +$b->checkResponseElement('body','!/Please choose why this artwork is rejected/'); +$b->checkResponseElement('body','/Please enter a rejection message/'); + +$b->setField('rejectiontype','1'); +$b->setField('rejectionmsg','This artwork is not approriate'); +$b->click('Reject'); +$b->isRedirected()->followRedirect(); +$b->responseContains('Show rejection message'); +$b->responseContains('This artwork is not approriate'); + +$artwork = ReaktorArtworkPeer::retrieveByPK($first_artwork->getId()); + +$b->checkResponseElement('div#content_main', '*Rejected on '.date("d/m/Y", strtotime($artwork->getActionedAt())).' at ' .date("H:i", strtotime($artwork->getActionedAt())).' by admin*'); + diff --git a/test/functional/reaktor/041ArtworkReconsiderTest.php b/test/functional/reaktor/041ArtworkReconsiderTest.php new file mode 100644 index 0000000..910dade --- /dev/null +++ b/test/functional/reaktor/041ArtworkReconsiderTest.php @@ -0,0 +1,99 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//check that page doesnt show when not logged in +$b->get('no/admin/list/rejected'); +$b->responseContains('You need to log in to view this page'); + +// Ok, lets log in as a user that does not have admin priveledges +$b->setField('username', 'monkeyboy'); +$b->setField('password','monkeyboy'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +// open approveartwork +$b->get('no/admin/list/rejected'); +$b->responseContains("You don't have the requested permission to access this page"); + +//Ok so we should log out and back in again as admin +$b->click('Log out'); + +$b->get('no/admin/list/rejected'); +$b->setField('username', 'admin'); +$b->setField('password','admin'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$b->checkResponseElement('div#content_main', '/No artworks/'); + +//lets get rejected artworks +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::STATUS,2); +$artworks = ReaktorArtworkPeer::doSelect($c); + +$first_artwork = array_shift($artworks); + +$b->get('/no/artwork/reject/'.$first_artwork->getId()); + +$b->setField('rejectiontype','1'); +$b->setField('rejectionmsg','This artwork is not approriate'); +$b->click('Reject'); +$b->isRedirected()->followRedirect(); + +$b->checkResponseElement('div#content_main', '!/No artworks/'); + +$artwork = ReaktorArtworkPeer::retrieveByPK($first_artwork->getId()); + +$b->checkResponseElement('div#content_main', '*Rejected on '.date("d/m/Y", strtotime($artwork->getActionedAt())).' at ' .date("H:i", strtotime($artwork->getActionedAt())).' by admin*'); + + +/* +This part here has become Ajax... Todo: Make test cover this as well +$b->restart(); +$b->get(url_for('@listrejected')); +$b->checkResponseElement('li', '/No artworks/'); + +$b->restart(); +$b->get('/no/artwork/changeStatus/status/4/id/6'); +$b->checkResponseElement('body', '/Reject artwork/'); +$b->setField('rejectiontype','1'); +$b->setField('rejectionmsg','This artwork is not approriate'); +$b->click('Reject'); +$b->isRedirected()->followRedirect(); + +$b->restart(); +$b->get('@listRejected'); +$b->checkResponseElement('li', '!/No artworks/'); +$b->responseContains("Status 'Rejected' set by admin at"); +$b->click('Flag for discussion'); +$b->isRedirected()->followRedirect(); + +$b->restart(); +$b->get('@listRejected'); +$b->checkResponseElement('li', '/No artworks/'); + +$b->restart(); +$b->get('@listdiscussion'); +$b->checkResponseElement('li', '!/No artworks/'); +$b->responseContains("Status 'Discussion' set by admin"); +*/ + + + +?> diff --git a/test/functional/reaktor/042ArtworkVotingTest.php b/test/functional/reaktor/042ArtworkVotingTest.php new file mode 100644 index 0000000..10eb142 --- /dev/null +++ b/test/functional/reaktor/042ArtworkVotingTest.php @@ -0,0 +1,37 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//check that we can't vote when not logged in (looking for the html snippet that should show when not able to vote +$b->get('/no/artwork/show/2/The+fancy+gallery'); +$b->responseContains('
    • Reaktor_full_blue'); +$b->responseContains("Please login to vote"); + +$b->get('/no'); +//check that we can vote when logged in (it's ajax, so we're justlooking for a snipet of the java code +$b->setField('username', 'monkeyboy'); +$b->setField('password','monkeyboy'); +$b->click('Sign in'); + + +$b->isRedirected()->followRedirect(); + +$b->checkResponseElement("div#user_summary .nickname", "monkeyboy"); +$b->get('/no/artwork/show/2/The+fancy+gallery'); +$b->responseContains('{asynchronous:true, evalScripts:true, onComplete:function(request, json){new Effect.Appear(\'rating_message_'); + +?> diff --git a/test/functional/reaktor/044ArtworkOrderingTest.php b/test/functional/reaktor/044ArtworkOrderingTest.php new file mode 100644 index 0000000..f10f9af --- /dev/null +++ b/test/functional/reaktor/044ArtworkOrderingTest.php @@ -0,0 +1,47 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//log in + +$b->get('/en'); + +$b->setField('username', 'monkeyboy'); +$b->setField('password','monkeyboy'); +$b->click('Sign in'); + +$b->isRedirected()->followRedirect(); + +$b->checkResponseElement("div#user_summary .nickname", "monkeyboy"); + +//check for javascript code and page title +$b->get('/en/mypage/content/manage/allartwork'); +$b->responseContains('My Artworks'); +$b->responseContains('Sortable.create'); + + +//check that we have all artworks in list +$c = new Criteria(); +$c->addJoin(SfGuardUserPeer::ID,ReaktorArtworkPeer::USER_ID); +$c->add(SfGuardUserPeer::USERNAME,'monkeyboy'); +$artworks = ReaktorArtworkPeer::doSelect($c); +foreach ($artworks as $artwork) +{ + $b->responseContains($artwork->getTitle()); +} + +?> diff --git a/test/functional/reaktor/045ArtworkCommentTest.php b/test/functional/reaktor/045ArtworkCommentTest.php new file mode 100644 index 0000000..c41db93 --- /dev/null +++ b/test/functional/reaktor/045ArtworkCommentTest.php @@ -0,0 +1,34 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// View an artworks comments +$b->get("/no/artwork/show/2/The+fancy+gallery"); +$b->isStatusCode(200); +$b->checkResponseElement('div#commentlist','!/Write a comment/'); +$b->setField('password', 'monkeyboy'); +$b->setField('username', 'monkeyboy'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); +$b->checkResponseElement('div#commentlist','/Write a comment/'); + +//post a comment +$b->setField('sf_comment_title','A comment to the artwork'); +$b->setField('sf_comment','Testing comments 123...'); + +// Ajax functionality cannot be tested here + +?> \ No newline at end of file diff --git a/test/functional/reaktor/046embedArtworkTest.php b/test/functional/reaktor/046embedArtworkTest.php new file mode 100644 index 0000000..172ae3b --- /dev/null +++ b/test/functional/reaktor/046embedArtworkTest.php @@ -0,0 +1,112 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$t = new reaktorTestBrowser(); +$t->initialize(); + +// Approve a graphic +$foo = new genericArtwork(10); +$foo->changeStatus(1, 3); + +define("IMAGE", 1); +define("PDF", 0); +define("GRAPHIC", 1); + +// URLs we are going to test +$urls = array( + "/no/artwork/show/2/The+fancy+gallery" => IMAGE, + "/no/artwork/show/3/My+Pdf" => PDF, + "/no/artwork/show/10/Magic+roundabout+-+Swindon" => GRAPHIC, +); + +foreach($urls as $URL => $item) { + // Open up an artwork page + $t->get($URL); + + $pageDom = $t->getResponseDom(); + $artwork = $pageDom->getElementById("artwork_div")->getElementsByTagName("a")->item(0); + $artimg = $pageDom->getElementById("artwork_div")->getElementsByTagName("img")->item($item); + + // Check if "Embed this artwork on another website" works + $embed = $pageDom->getElementById("embed_link")->getAttribute("value"); + $text = html_entity_decode($embed); # All the HTML is escaped + $tmp = new DomDocument('1.0', sfConfig::get('sf_charset')); + $tmp->validateOnParse = true; + $tmp->loadHTML($text); # Load the content of into dom + + $a = $tmp->getElementsByTagName("a")->item(0); + // Match the embedded link title to the artwork title + $alt = $a->getAttribute("alt"); + $t->test()->is($alt, $artwork->getAttribute("title"), "Check if the embedded link title matches the artwork title"); + + // Match the embedded link url + $href = $a->getAttribute("href"); + $path = parse_url($href, PHP_URL_PATH); + $t->test()->ok(strpos($path, $URL)!==false, "Check if the embedded link matches the actual artwork uri"); + + $img = $tmp->getElementsByTagName("img")->item(0); + // Match the embedded image title to the artwork title + $alt = $img->getAttribute("title"); + $t->test()->ok(strpos($alt, $artwork->getAttribute("title"))!==false, "Check if the embedded image title matches the artwork title"); + + // Match the embedded image src to the artwork src + $src = $img->getAttribute("src"); + $path = parse_url($src, PHP_URL_PATH); + # Note: pdf files add ".jpg" to the url (to workaround bbcode issues) so we + # have to just strpos() check it + $t->test()->ok(strpos($path, $artimg->getAttribute("src"))!==false, "Check if the embedded image src matches the artwork src"); + + + // Check if the "Direct path to this artwork" is correct + $embed = $pageDom->getElementById("file_path")->getAttribute("value"); + $path = parse_url($embed, PHP_URL_PATH); + $t->test()->is($path, $artwork->getAttribute("href"), "Check the 'direct path'"); + + $bb = $pageDom->getElementById("embed_link_bb")->getAttribute("value"); + $t->test()->ok(strpos($bb, "$URL]") !== false, "Match the BB url against the artwork url"); + $t->test()->ok(strpos($bb, $artimg->getAttribute("src"))!==false, "Match the BB image against the artwork image"); + # Note: BBCode doesn't support titles + + + // Social bookmarks + + $social = $pageDom->getElementById("socialBookmarks"); + $bookmarks = $social->getElementsByTagName("li"); + $req = $t->getRequest(); + $HOST = $req->getHost() . $req->getScriptName(); + + # These use the actual artwork title for some reason + $title = $pageDom->getElementById("artwork_info_header")->getElementsByTagName("h2")->item(0)->nodeValue; + foreach($bookmarks as $li) { + $service = $li->getAttribute("class"); + $onclick = $li->getElementsByTagName("a")->item(0)->getAttribute("onclick"); + if ($service == "print") { + $js = "window.print(); return false;"; + } else { + $js = "share" . ucfirst($service) . "('http://" .$HOST. $URL. "', '" . $title. "'); return false;"; + } + $t->test()->is($onclick, $js, "Check if {$service} link is OK"); + } +} + + diff --git a/test/functional/reaktor/051ArtworkReportsTest.php b/test/functional/reaktor/051ArtworkReportsTest.php new file mode 100644 index 0000000..942dc94 --- /dev/null +++ b/test/functional/reaktor/051ArtworkReportsTest.php @@ -0,0 +1,168 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//We start by confirming that the page doesnt show when not logged in +$b->get('/en/admin/reports/artwork')->isStatusCode(200) + ->checkResponseElement('div#secure_notice', '/You need to log in to view this page, please use the login form to the right/'); + + +//Log in as a non-admin user, and confirm the page doesn't show +$b->setField('username', 'monkeyboy') + ->setField('password','monkeyboy') + ->click('Sign in') + ->isRedirected() + ->followRedirect() + ->checkResponseElement("div#user_summary .nickname", "monkeyboy") + ->get('/en/admin/reports/artwork')->isStatusCode(200) + ->checkResponseElement('div#content_main', "/You don't have the requested permission to access this page./"); + +//Log out and log in as a staff member +$b->click('Log out') + ->isRedirected() + ->followRedirect() + ->setField('username', 'editorialboy1') + ->setField('password','editorialboy1') + ->click('Sign in') + ->followRedirect() + ->checkResponseElement('div#user_summary .nickname', 'editorialboy1'); + +//Confirm that page shows when logged in with correct credentials +$b->get('/en/admin/reports/artwork') + ->responseContains("Generate new artwork report"); +//->checkResponseElement('div#query_generator h1', '/Generate new artwork report/'); + +//Find all artworks in foto subreaktor +$b->setField('subreaktor_check', 1) + ->setField('subreaktor_id', 1) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/Number of artworks/'); + +//Find all artworks tagged with animal and display as artwork list +$b->get('/en/admin/reports/artwork') + ->setField('category_check', 1) + ->setField('category_id', 3) + ->setField('report_type', 2) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/Artwork matching your query/') + ->checkResponseElement('div#query_results', '/Cute monkeys/'); + +//Find all artworks tagged with 'fluffy' display as artwork list +$b->get('/en/admin/reports/artwork') + ->setField('tags_check', 1) + ->setField('tags', 'fluffy') + ->setField('report_type', 2) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/Artwork matching your query/') + ->checkResponseElement('div#query_results', '/Nice monkeys/') + ->checkResponseElement('div#query_results', '/The fancy gallery/'); + +//Find all artworks approved by Groruddalen editorial team, display as list +$b->get('/en/admin/reports/artwork') + ->setField('editorial_team_check', 1) + ->setField('editorial_team_id', 9) + ->setField('report_type', 2) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/The wonderful painting/') + ->checkResponseElement('div#query_results', '/My Pdf/'); + +//Find all artworks approved by editorialboy1, display statistics +$b->get('/en/admin/reports/artwork') + ->setField('editorial_team_member_check', 1) + ->setField('editorial_team_member_id', 8) + ->setField('report_type', 1) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/Number of artworks/') + ->checkResponseElement('div#query_results', '/0 unique artworks matching your query/'); + +//Find all unapproved artworks, display statistics +$b->get('/en/admin/reports/artwork') + ->setField('status_check', 1) + ->setField('status_value', 2) + ->setField('report_type', 1) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/Number of artworks/') + ->checkResponseElement('div#query_results', '/4 unique artworks matching your query/'); + +//Find all artworks under discussion +$b->get('/en/admin/reports/artwork') + ->setField('under_discussion_check', 1) + ->setField('report_type', 1) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/Number of artworks/') + ->checkResponseElement('div#query_results', '/1 unique artworks matching your query/'); + +//Find all artworks approved in march 2008 +$b->get('/en/admin/reports/artwork') + ->setField('from_date_check', 1) + ->setField('from_date[day]', 1) + ->setField('from_date[month]', 3) + ->setField('from_date[year]', 2008) + ->setField('to_date_check', 1) + ->setField('to_date[day]', 31) + ->setField('to_date[month]', 3) + ->setField('to_date[year]', 2008) + ->setField('report_type', 1) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/Number of artworks/') + ->checkResponseElement('div#query_results', '/Average waiting time before approval/') + ->checkResponseElement('div#query_results', '/3 unique artworks matching your query/'); + +//Try a combination: all approved artworks in march, in category travel, approved by photo editorial team, by staff user admin +$b->get('/en/admin/reports/artwork') + ->setField('subreaktor_check', 1) + ->setField('subreaktor_id', 1) + ->setField('category_check', 1) + ->setField('category_id', 12) + ->setField('editorial_team_check', 1) + ->setField('editorial_team_id', 5) + ->setField('editorial_team_member_check', 1) + ->setField('editorial_team_member_id', 1) + ->setField('status_check', 1) + ->setField('status_value', 3) + ->setField('from_date_check', 1) + ->setField('from_date[day]', 1) + ->setField('from_date[month]', 3) + ->setField('from_date[year]', 2008) + ->setField('to_date_check', 1) + ->setField('to_date[day]', 31) + ->setField('to_date[month]', 3) + ->setField('to_date[year]', 2008) + ->setField('report_type', 1) + ->click('Generate report') + ->checkResponseElement('div#query_results', '/Number of artworks/') + ->checkResponseElement('div#query_results', '/1 unique artworks matching your query/'); + +//Check out links to top saved artwork reports +$b->get('/en/admin/reports/artwork') + ->checkResponseElement('div#savedReportsBox', '/Top saved artwork reports/') + ->click('Stats', 'All approved stats') + ->checkResponseElement('div#query_results', '/Number of artworks/') + ->click('List', 'All rejected list') + ->checkResponseElement('div#query_results', '/Artwork matching your query/'); + +//Check the list link in the this report +$b->click('List', 'This report - All rejected list') + ->checkResponseElement('div#query_results', '/Artwork matching your query/'); + +?> diff --git a/test/functional/reaktor/051UserReportsTest.php b/test/functional/reaktor/051UserReportsTest.php new file mode 100644 index 0000000..f11efa5 --- /dev/null +++ b/test/functional/reaktor/051UserReportsTest.php @@ -0,0 +1,155 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +function selectAndPick(sfTestBrowser $t, array $options) +{ + # Loop over the options as select the options, and their _check options + foreach($options as $check => $value) + { + $t->setField($check . "_check", 1); + $t->setField($check, $value); + } + + return $t; +} +function deSelect(sfTestBrowser $t) +{ + $args = func_get_args(); + array_shift($args); + foreach($args as $option) + { + $t->setField($option. "_check", 0); + } + return $t; +} +function select(sfTestBrowser $t) +{ + $args = func_get_args(); + array_shift($args); + foreach($args as $k => $v) + { + if (is_array($v)) + { + $t->setField(key($v), current($v)); + } + else + { + $t->setField($v, 1); + } + } +} + +define("STATS", 1); +define("USERLIST", 2); + +function generate(sfTestBrowser $t, $what) +{ + $t->setField("report_type", $what); + $t->click("Generate report"); + return $t; +} +function checkResults(sfTestBrowser $t, array $users) +{ + generate($t, STATS)->checkResponseElement("div#result_div", "/Number of hits: ". count($users) . "/"); + generate($t, USERLIST); + + foreach($users as $username) { + $t->checkResponseElement("div#result_div", "/$username/"); + } +} + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +$BASE = "/en/admin/reports/user"; +//We start by confirming that the page doesnt show when not logged in +$b->get($BASE)->isStatusCode(200) + ->checkResponseElement('div#secure_notice', '/You need to log in to view this page, please use the login form to the right/'); + + +//Log in as a non-admin user, and confirm the page doesn't show +$b->login("monkeyboy", "monkeyboy", $BASE) + ->checkResponseElement('div#content_main', "/You don't have the requested permission to access this page./"); + +//Confirm that page shows when logged in with correct credentials +$b->login("editorialboy1", "editorialboy1", $BASE) + ->checkResponseElement('div#query_generator h1', '/Generate custom user report/'); + +// Males from Finnmark +selectAndPick($b, array( + "residence" => 4, # Finnmark + "sex" => 1, # Male +)); +// Only monkeyboy +checkResults($b, array("monkeyboy")); + +// Females from Finnmark +selectAndPick($b, array( + "sex" => 2, # Female +)); +// Only leo +checkResults($b, array("leo")); + +// Pick whichever sex +deSelect($b, "sex"); + +// Only users who have published artwork +select($b, "publishedArtwork"); +// Which is only monkeyboy +checkResults($b, array("monkeyboy")); + +// And +select($b, "commentAndOr"); + +// Has not commented +select($b, "notCommentedArtwork"); + +// Which is noone +checkResults($b, array()); + +// Reset the form +$b->get($BASE); + + +selectAndPick($b, array( + "sex" => 1, # Male +)); +// All males +checkResults($b, array("monkeyboy", "userboy", "languageboy", "editorialboy1", "editorialboy2", "editorialboy3", "articleboy", "veteran")); +// That have published artworks +select($b, "publishedArtwork"); +checkResults($b, array("monkeyboy", "userboy")); + +// Sexchange +selectAndPick($b, array( + "sex" => 2, # Female +)); +checkResults($b, array("admin", "Kerry", "dave")); # Yes, dave and admin are chicks + + +$b->get($BASE); +// Get all users registered from 5mars to 6th mars +select($b, "startDateArr_check", array("startDateArr[day]" => 5), array("startDateArr[month]" => 3), array("startDateArr[year]" => 2008)); +select($b, "endDateArr_check", array("endDateArr[day]" => 6), array("endDateArr[month]" => 3), array("endDateArr[year]" => 2008)); +checkResults($b, array("admin", "monkeyboy", "userboy", "leo")); + +// Which are females +selectAndPick($b, array( + "sex" => 2, # Female +)); +checkResults($b, array("admin", "leo")); + + diff --git a/test/functional/reaktor/052TaggingArticlesTest.php b/test/functional/reaktor/052TaggingArticlesTest.php new file mode 100644 index 0000000..85781f7 --- /dev/null +++ b/test/functional/reaktor/052TaggingArticlesTest.php @@ -0,0 +1,106 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); +function disable($ids) +{ + foreach((array)$ids as $id) + { + $article = ArticlePeer::retrieveByPK($id); + $article->setDraft(); + $article->save(); + } +} + +// Disable the theme article, internal article and mypage article in the fixtures +disable(array(4, 7, 9)); + + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Access articles without logging in +$b->get("/no/admin/article/edit/browse/artworks/1") + ->isStatusCode(404) + ->isRequestParameter("module", "artwork") + ->responseContains("or you do not have the required permissions"); + +// Normal users shouldn't be able either +$b->login("monkeyboy", "monkeyboy", "/no/admin/article/edit/browse/artworks/1") + ->isStatusCode(404) + ->isRequestParameter("module", "artwork") + ->responseContains("you do not have the required permissions to access this content"); + +// But admin can +$b->login("admin", "admin", "/no/admin/article/create") + ->isStatusCode(200) + ->isRequestParameter("module", "articles") + ->isRequestParameter("action", "edit") + ->responseContains("Create new article"); + +// Write an article +$article = array( + "article_type" => ArticlePeer::HELP_ARTICLE, + "article_title" => "Article1", + "article_ingress" => "", + "article_content" => "This is my article", +); +foreach($article as $opt => $val) +{ + $b->setField($opt, $val); +} + +// Save as draft so we can associate artworks to it +$b->click("Save and continue"); +$b->isStatusCode(302)->followRedirect(); + +// We have to associate a subreatkor to the help article +$b->post("/no/artwork/categoryAction", array("articleId" => 12, "subreaktorClick" => 1, "subreaktorChecked" => array(1)))->isStatusCode(200); +$b->get("/no/admin/article/edit/12"); + +// Publish it +$b->setField("status", ArticlePeer::PUBLISHED); +$b->click("Save changes"); +$b->isStatusCode(302)->followRedirect(); + +// Check for the subreaktor / formats checkboxes +$b->checkResponseElement('div#subreaktor_list input[value="7"]', false); # Groruddals +$b->checkResponseElement('div#subreaktor_list input[value="1"]', true); # Foto +$b->checkResponseElement('div#subreaktor_list input[value="2"]', true); # Tegning/grafikk +$b->checkResponseElement('div#subreaktor_list input[value="3"]', true); # Film/Animasjon + +// Add a tag to the article +$b->setField("tags", "russ"); +$b->click("Add"); + +// Retrieve a known help article +$b->get("/no/admin/article/edit/1"); + +// Check for the subreaktor / formats checkboxes +$b->checkResponseElement('div#subreaktor_list input[value="7"]', false); # Groruddals +$b->checkResponseElement('div#subreaktor_list input[value="1"][checked]', true); # Foto +$b->checkResponseElement('div#subreaktor_list input[value="2"]', true); # Tegning/grafikk +$b->checkResponseElement('div#subreaktor_list input[value="3"]', true); # Film/Animasjon + + +// Couple of fixtures articles have the 'latin' tag +$b->get("/no/tags/find/tag/latin"); +$b->checkResponseElement("div#article_search_tag_latin", "*Lorem Ipsum*"); +$b->checkResponseElement("div#article_search_tag_latin", "*What is Lorem Ipsum?*"); + +// Check for our new article +$b->get("/no/tags/find/tag/russ"); +$b->checkResponseElement("div#article_search_tag_russ", "*Article1*"); + + diff --git a/test/functional/reaktor/054ArtworkEmbeddingTest.php b/test/functional/reaktor/054ArtworkEmbeddingTest.php new file mode 100644 index 0000000..bfb09d7 --- /dev/null +++ b/test/functional/reaktor/054ArtworkEmbeddingTest.php @@ -0,0 +1,71 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Access articles without logging in +$b->get("/no/admin/article/edit/browse/artworks/1") + ->isStatusCode(404) + ->isRequestParameter("module", "artwork") + ->responseContains("or you do not have the required permissions"); + +// Normal users shouldn't be able either +$b->login("monkeyboy", "monkeyboy", "/no/admin/article/edit/browse/artworks/1") + ->isStatusCode(404) + ->isRequestParameter("module", "artwork") + ->responseContains("you do not have the required permissions to access this content"); + +// But admin can +$b->login("admin", "admin", "/no/admin/article/create") + ->isStatusCode(200) + ->isRequestParameter("module", "articles") + ->isRequestParameter("action", "edit") + ->responseContains("Create new article"); + +// Write an article +$article = array( + "article_type" => 1, + "article_title" => "Article1", + "article_ingress" => "", + "article_content" => "This is my article", +); +foreach($article as $opt => $val) +{ + $b->setField($opt, $val); +} + +// Save as draft so we can associate artworks to it +$b->click("Save and continue");#->isStatusCode(302)->isRedirected()->followRedirect(); + +// Since this is all javascript we cannot really test it, except checking if the +// functionality exists there +$b->get("/no/admin/article/edit/browse/artworks/1"); + $b->responseContains("The fancy gallery") + ->responseContains("My Pdf") + ->responseContains("Fingers") + ->responseContains("Embed this artwork") + ->responseContains("Relate this artwork"); + +// Only show artworks tagged with russ +$b->setField("filter", "russ"); +$b->click("Filter by tag") + ->responseContains("The fancy gallery") + ->responseContains("My Pdf") + ->checkResponseElement("artworkslist", "!/Fingers/") + ->checkResponseElement("artworkslist", "!/Nice monkeys/"); + + + diff --git a/test/functional/reaktor/058ArticlePublilshingTest.php b/test/functional/reaktor/058ArticlePublilshingTest.php new file mode 100644 index 0000000..62e2af1 --- /dev/null +++ b/test/functional/reaktor/058ArticlePublilshingTest.php @@ -0,0 +1,180 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +function change($b, $article) +{ + foreach($article as $id => $value) + { + $b->setField($id, $value); + } + return $b; +} + +function verify($b, $article, $saved = false) +{ + // Check and see if all our fields are still there + foreach($article as $id => $value) + { + switch($id) + { + case "article_type": + $b->checkResponseElement('body select[id="'.$id.'"] option[value="'.$value.'"][selected]', true); + break; + + case "article_title": + if ($article["article_type"] == ArticlePeer::FOOTER_ARTICLE) + { + // Translations default to the norwegian title, if no other specified on + // save + if ($saved) + { + $langs = array("no" => $value, "nn" => $value, "en" => $value); + } + else + { + $langs = array("no" => $value, "nn" => "", "en" => ""); + } + foreach ($langs as $lang => $title) + { + $b->checkResponseElement('body input[id="'.$id.'_i18n_'.$lang.'"][type="text"][value="'.$title.'"]'); + } + break; + } + // break omitted intentionally + case "article_ingress": + $b->checkResponseElement('body input[id="'.$id.'"][type="text"][value="'.$value.'"]'); + break; + + case "article_content": + $b->checkResponseElement('body textarea#'.$id, $value); + break; + } + } + return $b; +} + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Access articles without logging in +$b->get("/no/admin/article/create") + ->isStatusCode(404) + ->isRequestParameter('module', 'articles') + ->isRequestParameter('action', 'edit') + ->responseContains("do not have the required permissions to access this content"); + +// Normal users can't create articles +$b->login("monkeyboy", "monkeyboy", "/no/admin/article/create") + ->isStatusCode(404) + ->isRequestParameter('module', 'articles') + ->isRequestParameter('action', 'edit') + ->responseContains("do not have the required permissions to access this content"); + +// Only articleboy can +$b->login("articleboy", "articleboy", "/no/admin/article/create") + ->isStatusCode(200) + ->isRequestParameter('module', 'articles') + ->isRequestParameter('action', 'edit') + ->responseContains("Create new article"); + + +// Write an article +$articles = array( + array( + "article_type" => ArticlePeer::HELP_ARTICLE, + "article_title" => "Article1", + "article_ingress" => "", + "article_content" => "This is my article", + ), + array( + "article_type" => ArticlePeer::THEME_ARTICLE, + "article_title" => "Article2", + "article_ingress" => "This is an ingress which I am writing now", + "article_content" => "This is not really my article, honestly", + ), + array( + "article_type" => ArticlePeer::INTERNAL_ARTICLE, + "article_title" => "Article3", + "article_ingress" => "I don't know if I need to specify this", + "article_content" => "asdfkljalkdf asdlkfj asdflkj", + ), + array( + "article_type" => ArticlePeer::FOOTER_ARTICLE, + "article_title" => "Article4", + "article_ingress" => "", + "article_content" => "But This should be the one is not really my article, honestly", + ), + array( + "article_type" => ArticlePeer::MY_PAGE_ARTICLE, + "article_title" => "Article5", + "article_ingress" => "ritney to the B", + "article_content" => "I'm not a girl. Not yet a woman. All I need is time.", + ), + array( + "article_type" => ArticlePeer::REGULAR_ARTICLE, + "article_title" => "Article6", + "article_ingress" => "", + "article_content" => "Bored of writing content.", + ), + array( + "article_type" => ArticlePeer::SPECIAL_ARTICLE, + "article_title" => "Article7", + "article_ingress" => "", + "article_content" => "Handycapped article?", + ), +); + + +foreach($articles as $article) +{ + + $b->get("/no/admin/article/create"); + // Save the article as draft + change($b, $article)->click("Save and continue")->isRedirected()->followRedirect(); + + // Make sure we are now editing the article + $b->responseContains("Editing article") + ->checkResponseElement("div.createdby_block", "*articleboy*") + ->checkResponseElement("div.updatedby_block", "!*articleboy*"); + + verify($b, $article); + + // Change the content + $article["article_content"] .= "*CHANGED*"; + change($b, $article)->click("Save changes")->isRedirected()->followRedirect()->checkResponseElement("div.updatedby_block", "*articleboy*"); + verify($b, $article, true); + + // Change + do { + $article["article_type"] = rand(1, 6); + } while($article["article_type"] == ArticlePeer::FOOTER_ARTICLE); + change($b, $article)->click("Save changes")->isRedirected()->followRedirect(); + verify($b, $article, true); +} +/* +Fleh... This is all AJAX (which XHMLHttpRequest checks) so we cannot test it :( +// OK. Now we have 5 draft articles. Lets try to relate few of them +// to published articles (from the fixtures) + +// We only have two articles in the fixtures so our first inserted article is nr3 +$b->get("/no/admin/article/edit/3"); +// Relate Lorem Ipsum to article#3 +$b->setField("relate_article_select", array(2)); +$b->click("Relate article"); +# Since its an AJAX request we need to reload the page +$b->get("/no/admin/article/edit/3"); +// Did it work? +$b->checkResponseElement("ul#related_articles ul", "*Lorem Ipsum*"); +*/ + diff --git a/test/functional/reaktor/058FavouriteUsersTest.php b/test/functional/reaktor/058FavouriteUsersTest.php new file mode 100644 index 0000000..1633829 --- /dev/null +++ b/test/functional/reaktor/058FavouriteUsersTest.php @@ -0,0 +1,47 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Access the portofolio without specifying a file +$b->get("/no/portfolio/monkeyboy")->isStatusCode(200); +$b->isRequestParameter('module', 'profile'); +$b->isRequestParameter('action', 'portfolio'); + +// Not logged in yet so we should see the list but not the links +$b->checkResponseElement("div#favourite_with_block", "*Users who have marked monkeyboy as favourite*"); +$b->checkResponseElement("div#favourite_with_block", "!*Add as favourite*"); +$b->checkResponseElement("div#favourite_with_block", "!*Remove as favourite*"); + +// Lets clear monkeyboy's favourites (artwork and user favourites) +$c = new Criteria(); +$c->add(favouritePeer::USER_ID, 3); +FavouritePeer::doDelete($c); + +//Lets log in as monkeyboy and do the business +$b->setField('password', sfGuardUserPeer::retrieveByPK(3)->getUsername()); +$b->setField('username', sfGuardUserPeer::retrieveByPK(3)->getUsername()); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +// Now let's add monkeyboy as a favourite and check again... +Favourite::addFavourite(2, "user", 3); + +// Final check is to see that monkeyboy is displayed in userboy's favourite users list on his portfolio +$b->get("/no/portfolio/userboy"); +$b->checkResponseElement("div#my_favourite_users_block", "*monkeyboy*"); + + + diff --git a/test/functional/reaktor/061ApproveTest.php b/test/functional/reaktor/061ApproveTest.php new file mode 100644 index 0000000..2dc2a25 --- /dev/null +++ b/test/functional/reaktor/061ApproveTest.php @@ -0,0 +1,76 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//check that page doesnt show when not logged in +$b->get('/no/admin/list/unapprovedmyteams'); +$b->checkResponseElement('div#content_main', '*You need to log in*'); + +$b->get('/no/admin/list/unapprovedmyteams'); + +//Try to log in as a user without the proper credentials +$b->setField('username', 'monkeyboy'); +$b->setField('password','monkeyboy'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); +$b->checkResponseElement('div#content_main', "*You don't have the requested permission to access this page*"); + +// Log in as admin +$b->click('Log out'); +$b->get('/no/admin/list/unapprovedmyteams'); +$b->setField('username', 'admin'); +$b->setField('password','admin'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +//Check it has the correct header +$b->checkResponseElement('div#content_main h1', '/Artworks pending queue/'); + +// We can't test the functionality of the page because all the buttons are ajax, but we can +// Simulate the effects, first lets check that some of the unapproved artworks are showing + +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::STATUS, 2); +$c->setLimit(2); // Just get a couple to play with +$c->addAscendingOrderByColumn(ReaktorArtworkPeer::SUBMITTED_AT); + +$unapprovedArtworks = ReaktorArtworkPeer::doselect($c); +if (count($unapprovedArtworks) < 2) +{ + throw new exception ("Need 2 or more unapproved artworks for this test to be useful"); +} + +foreach($unapprovedArtworks as $artwork) +{ + $b->checkResponseElement('div#content_main', '*'.$artwork->getTitle().'*'); + $displayedArtworks[$artwork->getId()] = $artwork->getTitle(); +} + +// Ok, lets approve the first one +reset($displayedArtworks); +$thisArtwork = new genericArtwork(key($displayedArtworks)); +$thisArtwork->changeStatus(1, 3, "something"); +$thisArtwork->save(); + +// Now we should not see it on the page, since we just approved it +$b->get('/no/admin/list/unapprovedmyteams'); +$b->checkResponseElement('div#content_main', '!*'.$thisArtwork->getTitle().'*'); + +// But we should still see the other one +$b->checkResponseElement('div#content_main', '*'.next($displayedArtworks).'*'); + +?> diff --git a/test/functional/reaktor/062ArtworkViewTest.php b/test/functional/reaktor/062ArtworkViewTest.php new file mode 100644 index 0000000..aa618bc --- /dev/null +++ b/test/functional/reaktor/062ArtworkViewTest.php @@ -0,0 +1,249 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//Get an approved artwork from the database +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::STATUS, 3, Criteria::EQUAL); +$approved_artwork = ReaktorArtworkPeer::doSelectOne($c); +$approved = new genericArtwork($approved_artwork); + +//Get a different approved artwork, that's not owned by previous retrieved approved artwork +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::STATUS, 3, Criteria::EQUAL); +$c->add(ReaktorArtworkPeer::USER_ID, $approved->getUserId(), Criteria::NOT_EQUAL); +$diff_approved_artwork = ReaktorArtworkPeer::doSelectOne($c); +$diff_approved = new genericArtwork($diff_approved_artwork); + +//Get an unapproved artwork from the database +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::STATUS, 2, Criteria::EQUAL); +$c->add(ReaktorArtworkPeer::USER_ID, $approved->getUserId(), Criteria::EQUAL); +$unapproved_artwork = ReaktorArtworkPeer::doSelectOne($c); +$unapproved = new genericArtwork($unapproved_artwork); + +//Get a different unapproved artwork from the database, no owned by the previous unapproved artwork +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::STATUS, 2, Criteria::EQUAL); +$c->add(ReaktorArtworkPeer::USER_ID, $approved->getUserId(), Criteria::NOT_EQUAL); +$diff_unapproved_artwork = ReaktorArtworkPeer::doSelectOne($c); +$diff_unapproved = new genericArtwork($diff_unapproved_artwork); + +//Get a image artwork from the database +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, 'image', Criteria::EQUAL); +$image_artwork = ReaktorArtworkPeer::doSelectOne($c); +$image = new genericArtwork($image_artwork); + +//Get a pdf artwork from the database +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, 'pdf', Criteria::EQUAL); +$pdf_artwork = ReaktorArtworkPeer::doSelectOne($c); +$pdf = new genericArtwork($pdf_artwork); + +//Get a video artwork from the database +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, 'video', Criteria::EQUAL); +$video_artwork = ReaktorArtworkPeer::doSelectOne($c); +$video = new genericArtwork($video_artwork); + +//Get a text artwork from the database +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, 'text', Criteria::EQUAL); +$text_artwork = ReaktorArtworkPeer::doSelectOne($c); +$text = new genericArtwork($text_artwork); + +//Get a audio artwork from the database +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, 'audio', Criteria::EQUAL); +$audio_artwork = ReaktorArtworkPeer::doSelectOne($c); +$audio = new genericArtwork($audio_artwork); + +if(!$approved) +{ + echo "Nothing to test! Following tests will fail. Check fixtures for at least one approved artwork"; +} +if(!$unapproved) +{ + echo "Nothing to test! Following tests will fail. Check fixtures for at least one unapproved artwork"; +} + +// Show the approved artwork based on just id should fail +$b->get('/en/artwork/show/id/'.$approved->getId()); +$b->isStatusCode(404); + +/********** FIXME: Disabled as passing only the ID has to work for now **********/ +// Showing the approved artwork using just the file id should also fail +/* +$b->get('/en/artwork/show/'.$approved->getId()) + ->isStatusCode(404); +*/ + +// Trying to access unapproved content when not logged in should fail, trying with and without the file id set +$b->get($unapproved->getLink('show', $unapproved->getFirstFile()->getId(), true)) + ->isStatusCode(404) + ->get($unapproved->getLink('show', null, true)) + ->isStatusCode(404); + +// Trying to access the content with just title and file should fail +$b->get('/en/artwork/show/title/'.$approved->getTitle().'/file/'.$approved->getFirstFile()->getId()) + ->isStatusCode(404); + +// Trying to access the content with specific file id should work even if not logged in +$b->get($approved->getLink('show', $approved->getFirstFile()->getId(), true)) + ->isStatusCode(200); +echo $approved->getLink('show', $approved->getFirstFile()->getId(), true); +// Check that it displays the artwork when not logged in, and that the username is displayed and not the name +$b->get($approved->getLink('show', null, true)) + ->isStatusCode(200) + ->checkResponseElement('div#artwork_info_header h2', '/'.$approved->getTitle().'/') + ->checkResponseElement('div#artwork_description h4', '/Artwork description/') + ->checkResponseElement('div#artwork_tags h4', '/Tags/') + ->checkResponseElement('div#artwork_copyright h4', '/Copyright/') + ->checkResponseElement('div#artwork_info_header', '/'.$approved->getUser()->getUsername().'/') + ->checkResponseElement('div#embed_links a', '/Embed this artwork/') + ->checkResponseElement('div#socialBookmarks h3', '/Share this artwork/'); + +// Log in as owner of approved artwork and check that the page content is still valid +$b->setField('username', $approved->getUser()->getUsername()) + ->setField('password', $approved->getUser()->getUsername()) + ->click('Sign in') + ->isRedirected() + ->followRedirect() + ->isStatusCode(200) + ->checkResponseElement("div#user_summary .nickname", $approved->getUser()->getUsername()) + ->checkResponseElement('div#artwork_info_header h2', '/'.$approved->getTitle().'/') + ->checkResponseElement('div#artwork_description h4', '/Artwork description/') + ->checkResponseElement('div#artwork_tags h4', '/Tags/') + ->checkResponseElement('div#artwork_copyright h4', '/Copyright/') + ->checkResponseElement('div#artwork_info_header', '/'.$approved->getUser()->getUsername().'/'); + +// Trying to show the artwork based on just id should fail +$b->get('/en/artwork/show/id/'.$approved->getId()) + ->isStatusCode(404); + +// Trying to just show a file should fail +$b->get('/en/artwork/show/file/'.$approved->getFirstFile()->getId()) + ->isStatusCode(404); + +// Trying to access an artwork with a wrong title should not fail if you are the owner +$b->get('/en/artwork/show/title/'.str_shuffle($approved->getTitle()).'/id/'.$approved->getId()) + ->isStatusCode(200); +//Check out artwork by another user +$name = $diff_approved->getUser()->getNamePrivate() ? $diff_approved->getUser()->getUsername() : $diff_approved->getUser()->getUsername(); +$b->get($diff_approved->getLink('show', null, true))//'/en/artwork/show/9/Nice cartoon') + ->checkResponseElement('div#artwork_info_header', '/'.$name.'/'); + +// Trying to access artwork with a wrong title should fail if you are not the owner +$b->get('/en/artwork/show/title/'.str_shuffle($diff_approved->getTitle()).'/id/'.$diff_approved->getId()) +// FIXME: For the moment this should work. However, this behaviour will be +// reverted after the test-release +// ->isStatusCode(404); + ->isStatusCode(200); + +// Trying to access an artwork with a wrong title should fail if you are not the owner, also when file i specified +$b->get('/en/artwork/show/title/'.str_shuffle($diff_approved->getTitle()).'/id/'.$diff_approved->getId(). + '/file/'.$diff_approved->getFirstFile()->getId()) +//'title/'wrong title/id/9/file/11') + //->isStatusCode(404); + ->isStatusCode(200); // FIXME: See FIXME above + +// Trying to access the content with just title and file should fail also if you are not the owner +$b->get('/en/artwork/show/title/'.$diff_approved->getTitle().'/file/'.$diff_approved->getFirstFile()->getId()) + //'/en/artwork/show/title/My Pdf/file/2') + ->isStatusCode(404); + +// Trying to access the content with specific file id as well should not fail when logged in +$b->get($diff_approved->getLink('show', $diff_approved->getFirstFile()->getId(), true)) +//'/en/artwork/show/3/2/My Pdf') + ->isStatusCode(200); + +// Check that we can access unapproved artwork when logged in as owner of it, with and without file set +$b->get($unapproved->getLink('show', $unapproved->getFirstFile()->getId(), true)) + ->isStatusCode(200) + ->get($unapproved->getLink('show', null, true)) + ->isStatusCode(200); + +// Check that we can't access unapproved artwork when logged in as normal users, and we aren't the owner with and without file set +$b->get($diff_unapproved->getLink('show', $diff_unapproved->getFirstFile()->getId(), true)) + ->isStatusCode(404) + ->get($diff_unapproved->getLink('show', null, true)) + ->isStatusCode(404); + +// Log out +$b->click('Log out'); + +// Log in as admin +$b->get('/en') + ->setField('username', 'admin') + ->setField('password','admin') + ->click('Sign in') + ->isRedirected() + ->followRedirect(); + +// Check that we are logged in +$b->checkResponseElement('div#user_summary .nickname', 'admin'); + +// Check that we can access unapproved artwork when logged in as admin, both with and without file set +$b->get($unapproved->getLink('show', $unapproved->getFirstFile()->getId(), true)) + ->isStatusCode(200) + ->get($unapproved->getLink('show', null, true)) + ->isStatusCode(200); + + +// Check multi file image artwork, it is exactly the same, except it has a link to view a slideshow +$b->get('/en/artwork/show/2/The fancy gallery') + ->isStatusCode(200) + ->checkResponseElement('div#magnify_div a', '/View slideshow/'); + + +$format_artworks = array ($image, $pdf, $video, $text, $audio); + +//Finally we check that each of the different formats have roughly the same content +foreach($format_artworks as $format_artwork) +{ + $b->get($format_artwork->getLink('show', null, true)) + ->isStatusCode(200) + ->checkResponseElement('div#artwork_info_header h2', '/'.$format_artwork->getTitle().'/') + ->checkResponseElement('div#artwork_tags h4', '/Tags/') + ->checkResponseElement('div#artwork_copyright h4', '/Copyright/') + ->checkResponseElement('div#artwork_info_header', '/by '.$format_artwork->getUser()->getUsername().'/') + ->checkResponseElement('div#embed_links a', '/Embed this artwork/') + ->checkResponseElement('div#socialBookmarks h3', '/Share this artwork/') + ->checkResponseElement('div.artwork_tag_block ul', true) + ->checkResponseElement('div#artwork_actions_and_favourites', true) + ->checkResponseElement('div#artwork_rating ul', true) + ->checkResponseElement('div#commentlist', true) + ->checkResponseElement('div#artwork_time_and_report', true) + ->checkResponseElement('div.moderator_block h2', 'Moderator'); +if ($format_artwork->getArtworkType() != 'text') +{ + $b->checkResponseElement('div#artwork_description h4', '/Artwork description/'); +} + +} + +//->checkResponseElement('div#artwork_div','/FlowPlayerLight.swf/' );// '/VM_EmbedFlash/'); +//->responseContains('/FlowPlayerLight.swf/');//'VM_EmbedFlash'); +//->responseContains('application/x-shockwave-flash'); +//->checkResponseElement("div#content_main script[type='text/javascript']", '/xspf_player/'); + + +?> diff --git a/test/functional/reaktor/063FrontpageTemplateTest.php b/test/functional/reaktor/063FrontpageTemplateTest.php new file mode 100644 index 0000000..e67a8a2 --- /dev/null +++ b/test/functional/reaktor/063FrontpageTemplateTest.php @@ -0,0 +1,37 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + + +// create a new test browser +$browser = new reaktorTestBrowser(); +$browser->initialize(); + +//Check page exist and that the headers are correct +$browser-> + get('/en')-> + isStatusCode(200)-> + isRequestParameter('module', 'home')-> + isRequestParameter('action', 'index')-> + checkResponseElement('h1#recommend', '/We recommend/')-> + checkResponseElement('h1#toprated', '/Most popular/')-> + checkResponseElement('h1#latest', '/Latest/') + +; + diff --git a/test/functional/reaktor/064RelatedArtworksTest.php b/test/functional/reaktor/064RelatedArtworksTest.php new file mode 100644 index 0000000..d6709f5 --- /dev/null +++ b/test/functional/reaktor/064RelatedArtworksTest.php @@ -0,0 +1,84 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// Create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//Check page exist and that the content is correct +$b->get('/no/artwork/show/2/3/The+fancy+gallery'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'artwork'); +$b->isRequestParameter('action', 'show'); + +// Check to see that we have a "See also" block +//$b->checkResponseElement('div#relate_artwork_see_also', '*More work by*'); + +// Check that it contains a link to another artwork +$b->responseContains('"UnTip()" href="/index.php/no/artwork/show/3/My+Pdf"'); + +// Add another related artwork +$r = new RelatedArtwork(); +$r->setFirstArtwork(2); +$r->setSecondArtwork(4); +$r->save(); + +// Get the page again and see if the second artwork is added +$b->get('/no/artwork/show/2/3/The+fancy+gallery'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'artwork'); +$b->isRequestParameter('action', 'show'); + +// Check to see that we have a "See also" block +$b->checkResponseElement('div#relate_artwork_see_also', '*See also*'); + +// Check that it contains the link to artwork +$b->responseContains('"UnTip()" href="/index.php/no/artwork/show/3/My+Pdf"'); + +// Delete all related artwork for artwork 2 +$c = new Criteria(); +$c->add(RelatedArtworkPeer::FIRST_ARTWORK, 2); +RelatedArtworkPeer::doDelete($c); + +// Get the page again +$b->get('/no/artwork/show/2/3/The+fancy+gallery'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'artwork'); +$b->isRequestParameter('action', 'show'); + +// Check that the "See also" block now contains "More work by" +$b->checkResponseElement('div#relate_artwork_see_also', '/More work by/'); + +// Check that it also displays links to other artwork by this user +$b->responseContains('UnTip()" href="/index.php/no/artwork/show/3/My+Pdf">add(ReaktorArtworkPeer::ID, 1); +$art = ReaktorArtworkPeer::doSelectOne($c); + +$art->setStatus(3); +$art->save(); + +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('Sign in'); + +//switch to edit page +$b->get('/no/artwork/edit/2'); +$b->responseContains("Other artworks related to this one"); + + diff --git a/test/functional/reaktor/065PrinterFriendlyFormatTest.php b/test/functional/reaktor/065PrinterFriendlyFormatTest.php new file mode 100644 index 0000000..bc7ff51 --- /dev/null +++ b/test/functional/reaktor/065PrinterFriendlyFormatTest.php @@ -0,0 +1,32 @@ +getContext()->getResponse()->addStylesheet('css/print'); + * + * These functional tests cover: + * + * - Check for print button on the artwork page. + * + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); +$b->get('/no/artwork/show/2/The+fancy+gallery') + ->isStatusCode(200) + ->checkResponseElement('div#socialBookmarks', '/Print/'); + +?> \ No newline at end of file diff --git a/test/functional/reaktor/067ArtworkOnlineEditTest.php b/test/functional/reaktor/067ArtworkOnlineEditTest.php new file mode 100644 index 0000000..8cb8d10 --- /dev/null +++ b/test/functional/reaktor/067ArtworkOnlineEditTest.php @@ -0,0 +1,66 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); + +//first check that admin module is not viewable when not logged in +$b->get("/en/admin"); + +$b->isStatusCode(200); +$b->checkResponseElement('div#content_main' , '*You need to log in to view this page*'); + +$b->get("/en"); +$b->setField('username', 'admin'); +$b->setField('password', 'admin'); + +// Log in and check that we are redirected to admin page +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); +$b->isRequestParameter('module', 'admin'); +$b->isRequestParameter('action', 'index'); + +$b->get('/no/artwork/edit/2'); + +// check that we're editing the correct artwork +$b->checkResponseElement('div#artwork_main_container', '/Editing: The fancy gallery/'); + +// check that it contains the author information +$b->checkResponseElement('div#artwork_main_container', '/userboy/'); + +// check that the artwork image is displayed +$b->checkResponseElement('div#artwork_div a[href="/index.php/content/3/lovely.jpg"]'); + +// check that it contains the description +$b->checkResponseElement('textarea#description_value', 'This is an awesome gallery'); + +// check that it contains the drag and drop file list +$b->checkResponseElement('ul#artwork_files'); +$b->checkResponseElement('li#file_3'); +$b->checkResponseElement('li#file_4'); +$b->checkResponseElement('li#file_8'); + +$b->checkResponseElement('div[id="relate_artwork_see_also"]'); + +$b->checkResponseElement('div[id="categorySelect"]'); +$b->checkResponseElement('div[id="subreaktor_list"]'); +$b->checkResponseElement('div[id="category_list"]'); + +//$b->checkResponseElement('div[id="artwork_edit_link"]', '/Switch to view mode/'); +$b->checkResponseElement('div#artwork_main_container', '/View mode/'); + +$b->responseContains('Add tag(s)'); + +$b->responseContains('Current tags'); diff --git a/test/functional/reaktor/071CreateCompositeArtworkTest.php b/test/functional/reaktor/071CreateCompositeArtworkTest.php new file mode 100644 index 0000000..a4cae93 --- /dev/null +++ b/test/functional/reaktor/071CreateCompositeArtworkTest.php @@ -0,0 +1,129 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Make sure this page is not accessible by regular joes +$b + ->get("/en/admin/artwork/createcomposite") + ->responseContains("You need to log in to view this page, please use the login form to the right.") + ->login("userboy", "userboy", "/en/admin/artwork/createcomposite") + ->responseContains("You don't have the requested permission to access this page.") +; + +// Admin can +$b + ->login("admin", "admin", "/en/admin/artwork/createcomposite") + ->isStatusCode(200) + ->isRequestParameter("module", "admin") + ->checkResponseElement("h1", "*Create a new composite artwork*") +; + +// Get all images tagged with car, russ or abigail +$b + ->setField("tags_check", 1) + ->setField("tags", "car, russ, abigail") + ->click("Find files") + ->isStatusCode(200) +; + +// Two of those, one russ and one abigail +$b + ->checkResponseElement("ul#composite_artwork_filelist", true) + ->checkResponseElement("ul#composite_artwork_filelist li", "*Filming in Saudi*") + ->checkResponseElement("ul#composite_artwork_filelist li#file_8", "*Abigail at Frogner*") +; + +// russ images from January 1st to 2nd 2007 +$b + ->setField("tags", "russ, abigail") + ->setField("date_check", 1) + ->setField("from_date", array( + "day" => 01, + "month" => 01, + "year" => 2007, + ) + ) + ->setField("to_date", array( + "day" => 02, + "month" => 01, + "year" => 2007, + ) + ) + ->click("Find files") +; + +// And that is Russ filming ing saudi arabia, not abigail +$b + ->checkResponseElement("ul#composite_artwork_filelist", true) + ->checkResponseElement("ul#composite_artwork_filelist li", "*Filming in Saudi*") + ->checkResponseElement("ul#composite_artwork_filelist li#file_8", false) +; + + +// Using the same search elements, changing images not whatever else should fail +$b + ->setField("filetype", "audio") + ->click("Find files") + ->checkResponseElement("ul#composite_artwork_filelist", false) + ->checkResponseElement("div#composite_file_list", "*Could not find any files based on your criteria*") +; + +$b + ->setField("filetype", "pdf") + ->click("Find files") + ->checkResponseElement("ul#composite_artwork_filelist", false) + ->checkResponseElement("div#composite_file_list", "*Could not find any files based on your criteria*") +; + +$b + ->setField("filetype", "text") + ->click("Find files") + ->checkResponseElement("ul#composite_artwork_filelist", false) + ->checkResponseElement("div#composite_file_list", "*Could not find any files based on your criteria*") +; + + +// Clear the page +$b->get("/en/admin/artwork/createcomposite"); + +// Make sure the text search works too :) +$b + ->setField("date_check", 1) + ->setField("from_date", array( + "day" => 01, + "month" => 01, + "year" => 2007, + ) + ) + ->setField("to_date", array( + "day" => 01, + "month" => 12, + "year" => 2008, + ) + ) + ->setField("filetype", "text") + ->click("Find files") +; + +// That should find "Random plain text" +$b + ->checkResponseElement("ul#composite_artwork_filelist", true) + ->checkResponseElement("ul#composite_artwork_filelist li", "*Random plain text*") +; + + + diff --git a/test/functional/reaktor/074PortfoliopageTest.php b/test/functional/reaktor/074PortfoliopageTest.php new file mode 100644 index 0000000..6f3796b --- /dev/null +++ b/test/functional/reaktor/074PortfoliopageTest.php @@ -0,0 +1,38 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick = "userboy"; +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Try to be here without specifying a file +$b->get("/en/portfolio/". $nick); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'profile'); +$b->isRequestParameter('action', 'portfolio'); + +//We should be presented with a login message, since this page is only ever for logged in users +$b->checkResponseElement("div.portfolio_header_wrapper", "*userboy's portfolio*"); +$b->checkResponseElement("div#content_main", "*The fancy gallery*"); +$b->responseContains("default.gif"); +$b->checkResponseElement("div#content_main", "!/Logged in/"); +$b->setField('password', $nick); +$b->setField('username', $nick); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); +$b->checkResponseElement("div#content_main", "*This user is currently online*"); + +?> diff --git a/test/functional/reaktor/075TranslationTest.php b/test/functional/reaktor/075TranslationTest.php new file mode 100644 index 0000000..145d493 --- /dev/null +++ b/test/functional/reaktor/075TranslationTest.php @@ -0,0 +1,100 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +//$crit = new Criteria(); +$trans_en = new TransUnit(); +$trans_en->setSource('LokalReaktor'); +$trans_en->setTranslated(true); +$trans_en->setTarget('English lokalreaktor'); +$trans_en->setId(15); +$trans_en->setDateAdded(time()); +$trans_en->setCatId(3); +$trans_en->save(); + +$trans_no = new TransUnit(); +$trans_no->setSource('LokalReaktor'); +$trans_no->setTranslated(true); +$trans_no->setTarget('Bokmål lokalreaktor'); +$trans_no->setId(15); +$trans_no->setDateAdded(time()); +$trans_no->setCatId(1); +$trans_no->save(); + +$trans_nn = new TransUnit(); +$trans_nn->setSource('LokalReaktor'); +$trans_nn->setTranslated(true); +$trans_nn->setTarget('Nynorsk lokalreaktor'); +$trans_nn->setId(15); +$trans_nn->setDateAdded(time()); +$trans_nn->setCatId(2); +$trans_nn->save(); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Only admin/transadmin can get translation list +$b->get('/en/admin/translation/list') + ->isStatusCode(200) + ->checkResponseElement('h1', '!*Translation list*') +; + +// Log in as a translator +$b->setField('password', 'languageboy') + ->setField('username', 'languageboy') + ->click('Sign in') + ->isStatusCode(302) + ->isRedirected()->followRedirect() + ->checkResponseElement('h1', '*Translation list*') +; + + +// Search for a specific "source string" +// filters[source]=LokalReaktor&filters[translated]=&filters[cat_id]=3&filter=filter +$b->call('/en/admin/translation/list', 'get', array( + "filters" => array( + "source" => "Lokalreaktor", + "translated" => "", + "cat_id" => 3, // English + ), + "filter" => "filter" +)); + +$b->responseContains("1 result") + ->checkResponseElement("tr.sf_admin_row_0 td", "/en/") + ->checkResponseElement("tr.sf_admin_row_0 td a", "/LokalReaktor/") +; + +// Edit The "Lokalreaktor" string +$b->get('en/sfTransUnit/edit/msg_id/1') + ->isStatusCode(200) + ->checkResponseElement('h1', '*Edit Translation*') + ->responseContains('English lokalreaktor') + ->responseContains('Bokmål lokalreaktor') + ->responseContains('Nynorsk lokalreaktor') +; + +// Translate to english +$b->setField("trans_unit_1[target]", "Bokmål lokalgåseby") + ->setField("rans_unit_1[translated]", "1") + ->setField("trans_unit_2[target]", "Nynorsk lokalgåseby") + ->setField("rans_unit_2[translated]", "1") + ->setField("trans_unit_3[target]", "English lokalgåseby") + ->setField("rans_unit_3[translated]", "1") + ->click("save") + ->isRedirected() + ->followRedirect() + ->isStatusCode(200) + ->checkResponseElement("h2", "/Your modifications have been saved/") +; \ No newline at end of file diff --git a/test/functional/reaktor/076MetadataTest.php b/test/functional/reaktor/076MetadataTest.php new file mode 100644 index 0000000..e8a7616 --- /dev/null +++ b/test/functional/reaktor/076MetadataTest.php @@ -0,0 +1,47 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick = "admin"; +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Try to go to edit metadata page without being logged in +$b->get("/no/artwork/showmetadata/2/The+fancy+gallery"); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'artwork'); +$b->isRequestParameter('action', 'showMetadata'); + +// Check that we don't get the metadata edit page +$b->checkResponseElement("div#content_main", "!/Metadata for/"); + +// Log in as admin +$b->setField('password', $nick); +$b->setField('username', $nick); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); +$b->checkResponseElement("div#content_main", "/Metadata for The fancy gallery/"); + +// Go to edit metadata page +$b->isRequestParameter('module', 'artwork'); +$b->isRequestParameter('action', 'showMetadata'); + +// check that we are on the edit metadata page +$b->checkResponseElement("div#content_main", "/Metadata for/"); + +// Check that the metadata is correctly displayed +$b->responseContains('Saudi Arabia, Bahrain, Squash, boat, water, psalive'); + +?> \ No newline at end of file diff --git a/test/functional/reaktor/078TranslationTest.php b/test/functional/reaktor/078TranslationTest.php new file mode 100644 index 0000000..7d740c4 --- /dev/null +++ b/test/functional/reaktor/078TranslationTest.php @@ -0,0 +1,40 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick = "userboy"; +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +// Go to english frontpage +$b->get("/en"); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'home'); +$b->isRequestParameter('action', 'index'); + +$b->checkResponseElement("div#menu_bar", '/Photo/'); + +// The subreaktor class is caching some stuff, and since symfony test doesn't really reload or +// refresh, we need to clear the cached stuff +Subreaktor::clear(); + +// Go to norwegian frontpage, should have different subreaktor headers +$b->get("/no"); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'home'); +$b->isRequestParameter('action', 'index'); + +$b->checkResponseElement("div#menu_bar", '/Foto/'); + +?> \ No newline at end of file diff --git a/test/functional/reaktor/079AdminFrontpageTest.php b/test/functional/reaktor/079AdminFrontpageTest.php new file mode 100644 index 0000000..d363685 --- /dev/null +++ b/test/functional/reaktor/079AdminFrontpageTest.php @@ -0,0 +1,68 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +//first check that admin module is not viewable when not logged in +$b->get("/en/admin"); + +$b->isStatusCode(200); +$b->checkResponseElement('div#content_main' , '*You need to log in to view this page*'); + +$b->get("/en"); +$b->setField('username', 'admin'); +$b->setField('password', 'admin'); + +// Log in and check that we are redirected to admin page +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); +$b->isRequestParameter('module', 'admin'); +$b->isRequestParameter('action', 'index'); +//check that admin logo is shown +$b->responseContains('logoAdmin.gif'); + +//get unapproved tags from DB and check the num in template +$c = new Criteria(); +$c->addAscendingOrderByColumn(TagPeer::NAME); +$c->add(TagPeer::APPROVED, 0); +$tags = TagPeer::doSelect($c); +$num_tags = count($tags); + +$b->checkResponseElement('div#content_main','*('.$num_tags.')*'); + +//count reported files and check if this is ok +$c = new Criteria(); + +$c->add(ReaktorFilePeer::REPORTED, 0, Criteria::GREATER_THAN); +$c->add(ReaktorFilePeer::MARKED_UNSUITABLE, 0, Criteria::EQUAL); +$reported = ReaktorFilePeer::doSelect($c); +$num_reported = count($reported); + +$b->checkResponseElement('div#content_main','*('.$num_reported.')*'); + +//count artworks under discussion +$discussion = ReaktorArtworkPeer::getArtworksUnderDiscussion(); +$num_discussion = count($discussion); + +$b->checkResponseElement('div#content_main','*('.$num_discussion.')*'); + +//get all comments marked as unsuitable +$c = new Criteria(); +$c->add(sfCommentPeer::UNSUITABLE,2); +$comments = sfCommentPeer::doSelect($c); +$num_comments = count($comments); + +$b->checkResponseElement('div#content_main','*('.$num_comments.')*'); \ No newline at end of file diff --git a/test/functional/reaktor/080ViewArticlesTest.php b/test/functional/reaktor/080ViewArticlesTest.php new file mode 100644 index 0000000..841d198 --- /dev/null +++ b/test/functional/reaktor/080ViewArticlesTest.php @@ -0,0 +1,144 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new reaktorTestBrowser(); +$b->initialize(); + +function disable($ids) +{ + foreach((array)$ids as $id) + { + $article = ArticlePeer::retrieveByPK($id); + $article->setDraft(); + $article->save(); + } +} + +// Disable the theme article, internal article and mypage article in the fixtures +disable(array(4, 7, 9)); + +function publish($b, $type, $title = null, $intro = null, $content = null) +{ + return $b + ->setField("article_type", $type) + ->setField("article_title", $title) + ->setField("article_ingress", $intro) + ->setField("article_content", $content) + ->click("Save and continue") + ->isStatusCode(302) + ->isRedirected()->followRedirect() + ->setField("status", ArticlePeer::PUBLISHED) + ->setField("frontpage", 1) + ->click("Save changes") + ->isStatusCode(302) + ->isRedirected()->followRedirect(); +} +$b + ->login("articleboy", "articleboy", "/no/admin/article/create") + ->isStatusCode(200) + ->isRequestParameter('module', 'articles') + ->checkResponseElement('div#article_main_container h2', '*Create new article*'); + +$title = "This is a test article"; +$permlink = "This_is_a_test_article"; +$intro = "This article has no content so only the ingress should show up"; + +// Write a regular article +publish($b, ArticlePeer::REGULAR_ARTICLE, $title, $intro)->logout(); + +$b->get("/"); + +// Make sure it shows up on the frontpage +$b + ->checkResponseElement("div#navigation_block_wrapper .article_summary_block", "*$title*") + ->checkResponseElement("div#navigation_block_wrapper .article_summary_block", "*$intro*"); + +// Userboy should not see any articles in "my page articles" +$b->login("userboy", "userboy", "/no/mypage/userboy"); +$b->checkResponseElement("div#mypage_articles ul", false); + +// Make sure we can access the list of articles +$b + ->login("articleboy", "articleboy", "/no/admin/articles/list") + ->isStatusCode(200); + +// Retrieve the recently submitted article +$b->get("/no/admin/article/edit/12") + ->isStatusCode(200); +// And change the article to mypage article +$b->setField("article_type", ArticlePeer::MY_PAGE_ARTICLE); +$b->click("Save changes") + ->isStatusCode(302) + ->isRedirected()->followRedirect(); + +// Now userboy should see the article on mypage +$b->login("userboy", "userboy", "/no/mypage/userboy"); +$b->checkResponseElement("div#mypage_articles ul", true); +$b->checkResponseElement("div#mypage_articles ul li", "*$title*"); + +// Log in as articleboy +$b->login("articleboy", "articleboy", "/no/admin"); +// He shouldn't see any internal articles now +$b->checkResponseElement("div#internal_articles ul", false); + +// But if we change the article to internal one.. +$b->get("/no/admin/article/edit/12") + ->isStatusCode(200); +$b->setField("article_type", ArticlePeer::INTERNAL_ARTICLE); +$b->click("Save changes") + ->isStatusCode(302) + ->isRedirected()->followRedirect(); + +// Admin should see the article now +$b->checkResponseElement("div#internal_articles ul", true); +$b->checkResponseElement("div#internal_articles ul li", "*$title*"); + +// And be able to view it +$b->get("/no/article/$permlink")->isStatusCode(200)->responseContains($intro); + + +// But monkeyboy, or unlogged in user, on the other hand can't +$b->login("monkeyboy", "monkeyboy", "/no/article/$permlink")->isStatusCode(404); +$b->logout(); +$b->get("/no/article/$permlink")->isStatusCode(404); + +// Log in as articleboy +$b->login("articleboy", "articleboy", "/no/admin"); +// Associate an subreaktor with the article +$b->post("/no/artwork/categoryAction", array("articleId" => 12, "subreaktorClick" => 1, "subreaktorChecked" => array(1)))->isStatusCode(200); + +// Reclassify the article as help article +$b->get("/no/admin/article/edit/12") + ->isStatusCode(200) + ->setField("article_type", ArticlePeer::HELP_ARTICLE) + ->click("Save changes") + ->isStatusCode(302) + ->isRedirected()->followRedirect() + ->setField("tags", "upload") + ->click("Add"); + +// H4X0R it to be in the foto subreaktor +$b->post("/no/artwork/categoryAction", array("articleId" => 12, "subreaktorClick" => 1, "subreaktorChecked" => array(1)))->isStatusCode(200); +// H4X0R the category 'mannesker' +$b->post("/no/artwork/categoryAction", array("articleId" => 12, "add" => 8))->isStatusCode(200); + + +// We should now see the help article on the fancy gallery page +$b->logout(); +$b->get("/no/artwork/show/2/The+fancy+gallery") + ->checkResponseElement("div.colored_article_container", true) + ->checkResponseElement("div.colored_article_container ul li", "*$title*"); + + diff --git a/test/functional/reaktor/081IntelliCloudTest.php b/test/functional/reaktor/081IntelliCloudTest.php new file mode 100644 index 0000000..3743194 --- /dev/null +++ b/test/functional/reaktor/081IntelliCloudTest.php @@ -0,0 +1,62 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +define("NO_CLEAR", true); +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$b = new reaktorTestBrowser(); +$b->initialize(); + +$b->get("/no/artwork/show/2/The+fancy+gallery"); + +// #1-3 +$b->isStatusCode(); +$b->isRequestParameter('module', 'artwork'); +$b->isRequestParameter('action', 'show'); + +// #4 Check the tag cloud block exists - good for debugging when/if the following tests fail +$b->checkResponseElement('div#artwork_right_container .tag-cloud-right'); + +// #5-14 Check the cloud at least contains the tags that this artwork is tagged with +// Includes file objects that are attached to the artwork +// We should set a limit so we don't exceed the tag cloud capacity + +$artwork = new genericArtwork(2); +$tags = $artwork->getTags(true); +$i = 1; + +foreach ($tags as $tag) +{ + $b->checkResponseElement('div#artwork_right_container .tag-cloud-right', '/'.$tag.'/'); + if (++$i > 10) + { + break; + } +} + +// #15-18 Now we should check that some related tags are showing +// The logic behind the returned tags should be dealt with in unit tests and QA - there is no point +// testing them, other that the results of the logic display on the page + +// The following have been manually taken from the results based on the fixtures, to save time +// If these tests fail it is because the tag fixtures have changed, and this test needs to be updated + +$b->checkResponseElement('div#artwork_right_container .tag-cloud-right', '/wildlife/'); +$b->checkResponseElement('div#artwork_right_container .tag-cloud-right', '/gardening/'); +$b->checkResponseElement('div#artwork_right_container .tag-cloud-right', '/car/'); +$b->checkResponseElement('div#artwork_right_container .tag-cloud-right', '/park/'); + +// #19-22 Lets check a link to see if they are being generated correctly +$b->click("wildlife"); +$b->isStatusCode(); +$b->isRequestParameter('module', 'tags'); +$b->isRequestParameter('action', 'find'); +$b->checkResponseElement('div#content_main h2', '*Work tagged with wildlife*'); diff --git a/test/functional/reaktor/083LocalSubReaktorsTest.php b/test/functional/reaktor/083LocalSubReaktorsTest.php new file mode 100644 index 0000000..5382bb8 --- /dev/null +++ b/test/functional/reaktor/083LocalSubReaktorsTest.php @@ -0,0 +1,84 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$t = new reaktorTestBrowser(); +$t->initialize(); + + +// Login as admin and open the subreaktor listing +$t->login("admin", "admin", "/no/admin/list/subreaktors") + ->responseContains("Add a new subReaktor") + // Create new reaktor + ->setField("name", "NewLokalSubReaktor") + ->setField("reference", "tlokalreaktor") + ->click("Create") +# If it doesn't redirect here then a common error is your +# "apps/reaktor/modules/subreaktors/templates/" folder isn't writable + ->isRedirected() + ->followRedirect() + // Make sure the URI is correct +// ->checkResponseElement("form#sf_admin_edit_form a", "http://reaktor/tlokalreaktor"); + ->checkResponseElement('a[href$="/no/tlokalreaktor"]', "http://reaktor/tlokalreaktor"); + +$uri = $t->getResponseDom()->getElementById("sf_admin_edit_form")->getAttribute("action"); + +// Set the reaktor as live & as lokalreaktor +$t->checkResponseElement('form#sf_admin_edit_form', true); +$t-> +post($uri, + array( + "subreaktor_live" => "1", + "subreaktor_reference" => "tlokalreaktor", + "subreaktor_lokalreaktor" => "1", + "commit" => "Update subReaktor", + )) +->isRedirected() +->followRedirect(); + + +// Associate "Finnmark" (4) with it (monkeyboy is from finnmark) +$t->post($uri, + array( + "subreaktor_live" => "1", + "subreaktor_lokalreaktor" => "1", + "associated_lokalreaktor_residence[]" => "4", + "commit" => "Update subReaktor", + )) +->isRedirected() +->followRedirect(); + + + +$t->logout(); + +$t +// Open the newly created lokalcityreaktor and check if monkeyboy has the latest artwork + ->get("/no/tlokalreaktor-film") + ->responseContains("dokumentar") # Tag cloud + ->checkResponseElement('div#top_block_center div.artwork_link', "*Magic animations*") + ->checkResponseElement('div#top_block_center div.artwork_link', "*monkeyboy*"); + +# Cleanup +unlink(dirname(__FILE__).'/../../../apps/reaktor/modules/subreaktors/templates/tlokalreaktorReaktorSuccess.php'); +unlink(dirname(__FILE__).'/../../../web/images/logoTlokalreaktor.gif'); + diff --git a/test/functional/reaktor/086IntegrationOfRSSTest.php b/test/functional/reaktor/086IntegrationOfRSSTest.php new file mode 100644 index 0000000..0add6f0 --- /dev/null +++ b/test/functional/reaktor/086IntegrationOfRSSTest.php @@ -0,0 +1,36 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +// Apparently this functionality is not wanted +return; +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +$nick = "admin"; +$t = new reaktorTestBrowser(); +$t->initialize(); + +$t->get("/"); +$t->isStatusCode(200); + +// Make sure there is a feed there displaying +$t->checkResponseElement("div#sidebar_articles div.foreignfeed_normal ul li", true); +// With a headline +$t->checkResponseElement("div#sidebar_articles div.foreignfeed_normal ul li h4", "News from Deichman"); +// And that there is a link to the original location +$t->checkResponseElement('div#sidebar_articles div.foreignfeed_normal ul a', "*Read more*"); + + diff --git a/test/functional/reaktor/foobar.php b/test/functional/reaktor/foobar.php new file mode 100644 index 0000000..4280c33 --- /dev/null +++ b/test/functional/reaktor/foobar.php @@ -0,0 +1,12 @@ +initialize(); + + +$browser->login("admin", "admin")-> + get('/no/admin/article/edit/1/'); + diff --git a/test/jmeter/300-000-files.jmx b/test/jmeter/300-000-files.jmx new file mode 100644 index 0000000..658cec2 --- /dev/null +++ b/test/jmeter/300-000-files.jmx @@ -0,0 +1,207 @@ + + + + + + false + false + + + + + + + + false + + + + + false + + + + + + User-Agent + Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US) + + + + + + + + User-Agent + Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/2008111317 Ubuntu/8.04 (hardy) Firefox/3.0.4 + + + + + + + + User-Agent + Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; en) AppleWebKit/528.5+ (KHTML, like Gecko) Version/4.0 Safari/528.1 + + + + + + + + User-Agent + Opera/9.62 (X11; Linux i686; U; en) Presto/2.1.1 + + + + + + + + + reaktor.lab.linpro.no + + + utf-8 + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + 300-000-Summary.jtl + + + + + false + 1 + + 1 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + + + + false + monkeyboy + = + true + username + + + false + monkeyboy + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + true + -1 + + + + + + + + + + + /no/upload + POST + true + false + true + true + /crypt/home/chrisw/oppdrag/reaktor/svn/test/jmeter/dot.png + file + image/png + true + false + + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + diff --git a/test/jmeter/investigations.jmx b/test/jmeter/investigations.jmx new file mode 100644 index 0000000..b2d96b1 --- /dev/null +++ b/test/jmeter/investigations.jmx @@ -0,0 +1,46865 @@ + + + + + + false + false + + + + + + + + + false + 2 + + 10 + 0 + 1222939128000 + 1222939128000 + false + stoptest + + + Num/Ramp=Per second + + + + + + + reaktor.lab.linpro.no + + + + + + + + + + + test.minreaktor.no + + + + + + + + + + + test.reaktor.lab.linpro.no + + + + + + + + + + + 171.23.133.229 + + + + + + + + + + + + + + + + 80 + http + + / + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/grass/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegning/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegning/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegning/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-film/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-foto/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen-tegneserier/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-film/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegning/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-film/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen-tegneserier7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier7/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier7/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-film/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen-lyd/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/users_by_W + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/W/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen-tekst/tags/find/tag/focus7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegning/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/natur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/natur/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/category/essays + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/saudi+arabia + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/saudi+arabia/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/saudi+arabia/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/filming + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/foto/tags/find/tag/filming + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/users_by_R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/F/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/V/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/users_by_X + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/X/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/C/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/Z/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/users_by_Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/J/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/feed/tagged_with_focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/field/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/register + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tekst7/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/Z7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/T7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/tegning/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/lyd/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/focus/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/fingers7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/red + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/robin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/robin/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/abigail + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/abigail7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/register + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/lyd/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/lyd/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/lyd/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/lyd/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/en7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegneserier/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/en77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/car/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/car/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/car/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/wildlife/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/date/sortdirection/asc/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/wildlife/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/article/Fotoeditering_i_GIMP + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/article/Lorem_Ipsum + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/eden+project + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/field/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/E7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/I7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/I7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_I7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/J7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/F7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/F7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_F7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/no7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/no77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/no77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/norefjell + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/norefjell/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/film/tags/find/sortby/date/sortdirection/asc/tag/norefjell7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/nn7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/nn77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/nn77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dokumentar + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dokumentar/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dokumentar/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dokumentar/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/fingers/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/fingers/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/feed/tagged_with_fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/fingers/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/boat + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/boat7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/abigail + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/abigail7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/red + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/baby/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/username/sortdirection/asc/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/baby/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/baby/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/car/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/latin/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/latin/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/latin/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/article/Lorem_Ipsum + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/article/Fotoeditering_i_GIMP + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en7/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/en7/article + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no7/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/no7/article + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn7/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/nn7/article + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/9/Nice+cartoon + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/artwork/show/9/Nice+cartoon7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/artwork/show/9/Nice+cartoon7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/artwork/show/9/Nice+cartoon7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/cute7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camera + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camera/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camera/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/date/sortdirection/desc/tag/camera7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bike/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/rating/sortdirection/desc/tag/bike7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/fingers7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/water/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/eden+project + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/camping7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/abigail + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/abigail/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_camping + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/camping7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/camping7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lemur/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lemur/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lemur/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fluffy/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fluffy/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/username/sortdirection/desc/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/username/sortdirection/desc/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fluffy/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/car/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/feed/tagged_with_car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/latin/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen/tags/find/sortby/title/sortdirection/asc/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegneserier/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/article/Lorem_Ipsum + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/foto7/article/Lorem_Ipsum + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fred/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fred/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fred/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/date/sortdirection/desc/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fred/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fred/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/date/sortdirection/desc/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/articles_tagged_with_fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/article/Lorem_Ipsum + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegneserier + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /lyd/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/latin/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/latin/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/articles_tagged_with_latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/article/Fotoeditering_i_GIMP + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fred/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/date/sortdirection/desc/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fred/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fred/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/artwork/show/9/Nice+cartoon + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/portfolio/dave + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fred/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fred/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/articles_tagged_with_fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/portfolio/dave + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fred/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/title/sortdirection/asc/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/title/sortdirection/asc/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/title/sortdirection/asc/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fred/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/rating/sortdirection/desc/tag/fred7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/rating/sortdirection/desc/tag/fred7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/rating/sortdirection/desc/tag/fred7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/fred7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/fred7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/fred7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/foto7/article/Lorem_Ipsum + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/foto7/article/Lorem_Ipsum + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/article/Fotoeditering_i_GIMP + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/articles_tagged_with_latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/latin/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/latin/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/abigail + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/category/nature + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/category/travel + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/category/vehicles + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/category/animals + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/bird + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/red + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/boat + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/camera + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/gardening + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/saudi+arabia + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/robin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/category/people + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/eden+project + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/lyd/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegneserier/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegneserier/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegning/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegning/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/latin/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/latin/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen/tags/find/sortby/title/sortdirection/asc/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/feed/articles_tagged_with_latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/article/Lorem_Ipsum + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/sortby/title/sortdirection/asc/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen/tags/find/tag/latin7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/latin/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/latin7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen/tags/find/tag/latin7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/camping/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/camping/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/camping/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/camping/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-film + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/feed/tagged_with_camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-lyd + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/car/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen/tags/find/sortby/date/sortdirection/asc/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen/tags/find/sortby/date/sortdirection/asc/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/car/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/car/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/sortby/date/sortdirection/asc/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/car/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/essays + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/noveller + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/dyr + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/bird + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/norefjell + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/saudi+arabia + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/boat + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/saudi+arabia + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bird + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/gardening + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/boat + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/eden+project + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fluffy/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/camera + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fluffy/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/filming + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/robin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fluffy/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fluffy/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/username/sortdirection/desc/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/filming + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fluffy/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fluffy/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fluffy/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/gardening + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/username/sortdirection/asc/tag/fluffy7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/username/sortdirection/asc/tag/fluffy7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/username/sortdirection/asc/tag/fluffy7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/fluffy/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_lemur + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/username/sortdirection/desc/tag/lemur7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lemur/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/username/sortdirection/desc/tag/lemur7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/username/sortdirection/desc/tag/lemur7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lemur/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lemur/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/date/sortdirection/asc/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/date/sortdirection/asc/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/date/sortdirection/asc/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lemur/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lemur/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lemur/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lemur/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/norefjell + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/bird + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/robin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/red + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/camera + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/norefjell + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/saudi+arabia + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/bil/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/bil/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/bil/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/bil/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/camping/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/camping/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/filming + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/camping/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/gardening + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/camping/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/abigail/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/rating/sortdirection/desc/tag/abigail7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/abigail/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/rating/sortdirection/desc/tag/abigail7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_abigail + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/rating/sortdirection/desc/tag/abigail7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/abigail/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/abigail/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/abigail7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/abigail/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camping/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camping/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camping/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camping/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/eden+project/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/eden+project/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/eden+project/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/eden+project/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_eden+project + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/water/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/water/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_water + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/rating/sortdirection/desc/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/water/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/rating/sortdirection/desc/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/water/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/rating/sortdirection/desc/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/water/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/statue/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/statue/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/statue/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/statue/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/statue/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/statue/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/statue/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/statue/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/fingers7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fingers/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fingers/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/4/Fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/portfolio/monkeyboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fingers/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/fingers/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_fingers + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/rating/sortdirection/desc/tag/bike7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/rating/sortdirection/desc/tag/bike7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bike/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bike/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bike/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bike/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/bike7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/bike7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/bike/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/bike7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/date/sortdirection/desc/tag/camera7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/date/sortdirection/desc/tag/camera7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camera/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_camera + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camera/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/camera/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/cute7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/cute7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/cute/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/cute/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/cute/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/cute/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/lakes/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/lakes/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/lakes/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/lakes/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lakes/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lakes/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lakes/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/lakes/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/portfolio/dave + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/articles_tagged_with_latin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/date/sortdirection/asc/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/date/sortdirection/asc/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/date/sortdirection/asc/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/latin/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/articles_tagged_with_latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/latin/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/latin/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/car/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/car/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/car/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/car/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/baby/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/baby/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/baby/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_baby + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/rating/sortdirection/desc/tag/baby7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/rating/sortdirection/desc/tag/baby7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/rating/sortdirection/desc/tag/baby7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/username/sortdirection/asc/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/username/sortdirection/asc/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/baby/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/baby/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/baby/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/baby/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/baby/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/baby7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/baby7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/baby7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/baby/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_red + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/red/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/red/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/red/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/red/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/abigail/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/abigail/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_abigail + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/abigail/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/abigail/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/filler/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/filler/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/articles_tagged_with_filler + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/boat7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/boat7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/boat/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/boat/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_boat + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/boat/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/boat/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lake+district/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lake+district/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lake+district/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/lake+district/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/popular_foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/artwork/show/4/Fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/portfolio/monkeyboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/artwork/show/11/Magic+animations + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/article/Talenter_i_tusj + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /film/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/fingers/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/fingers/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/artwork/show/4/Fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/fingers/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/portfolio/monkeyboy + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/film/tags/find/sortby/rating/sortdirection/desc/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/film/tags/find/sortby/rating/sortdirection/desc/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/film/tags/find/sortby/rating/sortdirection/desc/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/fingers/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/film/tags/find/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/fingers/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/lady + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/fingers/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/fingers/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/portfolio/monkeyboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/fingers/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/artwork/show/4/Fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /film/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/fingers/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/feed/tagged_with_fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/fingers/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/feed/in_category_dokumentar + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dokumentar/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dokumentar/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dokumentar/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dokumentar/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/lady + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/animasjonsfilm + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/kortfilm + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/artwork/show/11/Magic+animations + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/tags/find/tag/norefjell + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/film/category/dataanimasjon + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/nn77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/feed/users_by_A + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/A/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/A/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/A/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/en/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegning/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/film/tags/find/sortby/date/sortdirection/asc/tag/norefjell7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/film/tags/find/sortby/date/sortdirection/asc/tag/norefjell7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/norefjell/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/feed/tagged_with_norefjell + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/norefjell/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/norefjell/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/tags/find/tag/norefjell/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/film/tags/find/tag/norefjell7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/film/tags/find/tag/norefjell7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/film/tags/find/tag/norefjell7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/category/animasjonsfilm + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/category/kortfilm + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/category/dataanimasjon + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/film/category/dokumentar + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/no77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/F7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_F7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_F + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn7/list/users + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/nn7/list + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en7/list/users + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/en7/list + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no7/list/users + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/no7/list + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/J7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_J7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/J7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_J + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/I7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_I7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_I + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/E7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/E7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_E7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/users_by_E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/users_by_Y + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/Y7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/Y7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/Y7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn7/list/users + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no7/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en7/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/field/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/field/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/field/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/field/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/field/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/grass/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/grass/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/grass/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/grass/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_eden+project + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/eden+project/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/eden+project/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/eden+project/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/eden+project/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/water/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/water/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/water/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/water/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/articles_tagged_with_filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/filler/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/filler/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn7/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en7/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no7/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/artwork/show/8/Nice+monkeys7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/artwork/show/8/Nice+monkeys7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/artwork/show/8/Nice+monkeys7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/wildlife/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/wildlife/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/wildlife/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/wildlife/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/date/sortdirection/asc/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/date/sortdirection/asc/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/wildlife/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/wildlife/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/wildlife/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/wildlife/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/wildlife/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/wildlife/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/wildlife/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/wildlife/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/park/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/tag/park7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/park7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/park/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/tag/park7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/park/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/park/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/car/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/car/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/car/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/title/sortdirection/desc/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/title/sortdirection/desc/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/title/sortdirection/desc/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tags/find/sortby/title/sortdirection/asc/tag/car7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/sortby/title/sortdirection/asc/tag/car7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tags/find/sortby/title/sortdirection/asc/tag/car7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/car/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/artwork/show/4/Fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/article/Talenter_i_tusj + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/artwork/show/11/Magic+animations + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/popular_foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/en77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/en77/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /lyd/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/lyd/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /lyd/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/lyd/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/articles_tagged_with_filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/filler/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/filler/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/abigail/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/abigail/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_abigail + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/abigail/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/abigail/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/robin/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/robin/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/robin/sortby/username/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_robin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/robin/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/robin/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/red/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/red/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/red/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/tagged_with_red + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tags/find/tag/red/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fingers/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fingers/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fingers/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fingers/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/focus/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/focus/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/focus/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/focus/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/focus/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/portfolio/admin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/2/"/nn/artwork/show/2/3/The+fancy+gallery">Go + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/2/"/nn/artwork/show/2/8/The+fancy+gallery">Go + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/2/"/nn/artwork/show/2/4/The+fancy+gallery">Go + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/portfolio/leo + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/artwork/2/files + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/portfolio/ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/foto/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/tegneserier/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/film/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/artwork/show/4/Fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/userboy_favourite_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/tekst/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/userboy_latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/users_by_U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/U/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/U/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/nn/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/U/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/C/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/users_by_C + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/C/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/C/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/users_by_T + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/T/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/T/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/T/subreaktor/tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/users_by_A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegning/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tegneserier/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/monkey/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/monkey/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/monkey/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/monkey/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/artwork/show/11/Magic+animations + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/article/Talenter_i_tusj + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/popular_foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegning/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tegning/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_Y + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/T7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/users_by_T7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/T7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_T + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/Z7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_Z7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/Z7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_Q + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/Q7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/Q7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/Q7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/W7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_W + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/W7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/W7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/A7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_A + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/A7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/A7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/O7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_O + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/O7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/O7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/N7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/N7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_N + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/N7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/M7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/M7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_M + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/M7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/portfolio/monkeyboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/feed/users_by_S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/portfolio/superadmin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/S7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/S7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/S7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/users_by_Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tegneserier/en/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/users_by_N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/users_by_K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tegneserier/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tegneserier7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tegneserier7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tegneserier7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tegneserier7/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tegneserier7/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tegneserier7/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tegneserier7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tegneserier7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tegneserier7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tekst7/register + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tekst7/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tekst/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tekst7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tekst7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tekst7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/field/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/feed/tagged_with_field + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tekst/tags/find/sortby/rating/sortdirection/desc/tag/field7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/field/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tekst/tags/find/sortby/rating/sortdirection/desc/tag/field7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tekst/tags/find/sortby/rating/sortdirection/desc/tag/field7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/field/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/field/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tekst/tags/find/tag/field7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tekst/tags/find/tag/field7 + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tekst/tags/find/tag/field7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/field/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/tekst/tags/find/tag/focus7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/focus/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/focus/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tekst/tags/find/tag/focus7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/focus/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/tekst/tags/find/tag/focus7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/tags/find/tag/focus/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/category/noveller + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tekst/category/essays + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/nn/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/register + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/J/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/J/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/users_by_J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/users_by_J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/no/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/Z/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/Z/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/users_by_Z + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/C/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/users_by_C + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/C/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/users_by_C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /foto/en/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/users_by_X + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/X/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/X/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/V/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/V/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/users_by_V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/portfolio/veteran + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/users_by_V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/portfolio/veteran + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/F/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/users_by_F + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/F/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/users_by_F + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/R/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/R/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/R/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/users_by_L + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/L/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/portfolio/leo + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/L/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/L/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/users_by_I + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/I/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/I/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/I/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/Q/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/Q/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/Q/subreaktor/foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/users_by_Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/feed/tagged_with_filming + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/filming/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/filming/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/filming/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/foto/tags/find/tag/filming/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/foto/tags/find/tag/filming + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/filming/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/abigail + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/bird + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/filming/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/camera + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/filming/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/gardening + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/robin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/boat + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/tagged_with_filming + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/eden+project + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/red + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/filming/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/tagged_with_statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/statue/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/foto/tags/find/tag/statue7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/statue/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/foto/tags/find/tag/statue7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/statue/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/foto/tags/find/tag/statue7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/statue/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/saudi+arabia/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/saudi+arabia/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/tagged_with_saudi+arabia + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/saudi+arabia/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/saudi+arabia/sortby/rating/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/category/natur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/category/mennesker + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/category/reise + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/category/dyr + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/foto/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tekst/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/focus/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/tagged_with_focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/focus/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/focus/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/focus/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/camping/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/camping/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/camping/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/tagged_with_camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/tags/find/tag/camping/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/category/essays/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/in_category_essays + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/category/essays/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/category/essays/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/category/essays/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/tekst/category/novels + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /film/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/category/short+film + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/category/computer+animation + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/artwork/show/4/Fingers + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/category/documentary + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/tags/find/tag/norefjell + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/category/animation + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/film/tags/find/tag/lady + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegning + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-film + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/natur/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/feed/in_category_natur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/natur/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/natur/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/natur/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/category/natur/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegning/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-lyd/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-film/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-lyd/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-foto/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-lyd/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegning/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-film/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-foto/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-film/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-lyd/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-foto/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegning/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegning/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-film/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/feed/latest_commented + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegning/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/feed/latest_artworks + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen-tekst/tags/find/tag/focus7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-tekst/tags/find/tag/focus7 + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tekst/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/focus/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/feed/tagged_with_focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/focus/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/focus/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/tags/find/tag/focus/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/category/essays + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tekst/category/noveller + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/feed/users_by_T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/T/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/T/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/T/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/no/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/W/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-foto/feed/users_by_W + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/W/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-foto/nn/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/startingwith/Y/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/users_by_Y + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/startingwith/Y/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/startingwith/Y/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/list/users/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/list/users/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/list/users/subreaktor/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/category/natur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/category/dyr + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-foto/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen-lyd/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-lyd/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-lyd/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen-lyd7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen-lyd7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-lyd7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/groruddalen-lyd/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-lyd/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-lyd/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier7/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tegneserier7/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier7/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier7/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-tegneserier7/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen-tegneserier7/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-tegneserier7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/groruddalen-tegneserier7/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tegneserier/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen-tegneserier/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-film/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-film/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tegneserier/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tegneserier/nn/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tegneserier/en/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /en/groruddalen-tegneserier/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/L + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/W + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/B + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/V + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/X + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/D + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/H + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/C + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/M + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/R + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/A + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/F + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/I + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/P + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/E + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/O + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/G + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/Y + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/Q + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/U + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/S + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/K + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/J + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /groruddalen-tekst/nn/list/users/startingwith/N + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/users_by_Z + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/users_by_T + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/users_by_ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/category/essays + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/category/noveller + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen-tekst/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/groruddalen/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/feed/recommended_artwork + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/groruddalen/feed/most_popular + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/red + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/gardening + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/article/Fotoeditering_i_GIMP + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /nn/foto/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/eden+project + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /en/foto/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/bird + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/statue + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/robin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/article/Hvordan_ta_dyrebilder + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/camera + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/abigail + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/artwork/show/2/The+fancy+gallery + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/category/reise + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/category/mennesker + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/category/natur + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/category/dyr + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/saudi+arabia + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/boat + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/foto/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/field/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/field/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/tagged_with_field + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/field/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/register + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/field/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /tekst/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/car/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/tagged_with_car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/car/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/car/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/car/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/tagged_with_focus + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/focus/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/focus/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/focus/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/tags/find/tag/focus/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/category/noveller + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/category/essays + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/latest_users + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tekst/feed/latest_comments + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/articles_tagged_with_fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fred/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fred/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_fred + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/artwork/show/9/Nice+cartoon + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fred/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/fred/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/car/sortby/title/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/car/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/car/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/feed/tagged_with_car + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /nn/tags/find/tag/car/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/grass/sortby/rating/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/grass/sortby/date/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/feed/tagged_with_grass + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/grass/sortby/title/sortdirection/desc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/grass/sortby/username/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + + + + 80 + http + + /no/tags/find/tag/grass/sortby/date/sortdirection/asc + GET + true + false + true + false + + + + false + + + + + + 8080 + + .*\/images\/.* + .*%.* + .*\/uploads\/.* + .*\/content\/.* + .*\/lang\/.* + .*\/js\/.* + .*txt + + + false + 0 + false + 0 + false + true + true + false + false + false + + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Aggregate-Graph.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Aggregate-Report.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Graph-full.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Graph.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Monitor.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Spline.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Summary.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Table.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Tree.jtl + + + + 1000 + + + + 3000 + 1000 + + + + 1000 + 10000 + + + + + + + + + + + + + / + GET + false + true + true + false + + + + false + + + + + + + .* + returnVar + true + + + + + + + reaktor.lab.linpro.no + + + + ${returnVar} + GET + true + false + true + false + + + + false + + + + + + true + -1 + + + + + + + reaktor.lab.linpro.no + + + + .* + GET + true + true + true + false + + + + false + + + + + + + + + + + + + 1 + + + + + + + + + + + / + GET + false + true + true + false + + + + false + + + + + 1 + + + + + + + + + + + /no/artwork/show/8/Nice+monkeys + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/artwork/show/2/The+fancy+gallery + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/artwork/show/11/Magic+animations + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/artwork/show/3/My+Pdf + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/artwork/show/4/Fingers + GET + false + true + true + false + + + + false + + + + + + 1 + + + + + + + + + + + /no/article/login_help + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/article/Talenter_i_tusj + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/article/Om_Reaktor + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/article/terms_and_conditions + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + false + true + true + false + + + + false + + + + + + 1 + + + + + + + + + + + /no/foto + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/tegning + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/film + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/lyd + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/tegneserier + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/tekst + GET + false + true + true + false + + + + false + + + + + + 1 + + + + + + + + + + + /no/register + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/list/users + GET + false + true + true + false + + + + false + + + + + + 1 + + + + + + + + + + + /no/tags/find + GET + false + true + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/abigail + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/baby + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/bird + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/camera + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/boat + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/fingers + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/norefjell + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/red + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/robin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/saudi+arabia + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/statue + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/water + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + 1 + + + + + + + + + + + /no/portfolio/Kerry + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/portfolio/userboy + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/portfolio/monkeyboy + GET + false + true + true + false + + + + false + + + + + + 1 + + + + + + + + + + + /no/rssfeeds + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/feed/recommended_artwork + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/feed/most_popular + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/feed/latest_artworks + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/feed/latest_commented + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/feed/latest_users + GET + false + true + true + false + + + + false + + + + + + + + + + + + /no/feed/popular_foto + GET + false + true + true + false + + + + false + + + + + + 1 + + + + + + + + + + + /no/groruddalen + GET + false + true + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-film + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-lyd + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-foto + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-tegning + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-tegneserier + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen-tekst + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/artwork/show/3/My+Pdf + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/portfolio/userboy + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/artwork/show/8/Nice+monkeys + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/portfolio/Kerry + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/category/natur + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/category/dyr + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/lake+district + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/frogner + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/wildlife + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/russ + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/lakes + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/park + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/field + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/camping + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/bil + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/fluffy + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/fred + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/grass + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/car + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/focus + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/monkey + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/lemur + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/bike + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/latin + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/cute + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/tags/find/tag/filler + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/article/login_help + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/register + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/article/Om_Reaktor + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/article/terms_and_conditions + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/article/Kontakt_oss_hvis_du_har_spoersmaal + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /no/groruddalen/rssfeeds + GET + true + false + true + false + + + + false + + + + + + + + + + http + + /groruddalen/no/list/users + GET + true + false + true + false + + + + false + + + + + + + + 0 + false + continue + 1076438592000 + + false + 1 + + 1 + + + 1076438592000 + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + + + + + + + + reaktor.lab.linpro.no + + + + + + + + + + + + + + + / + GET + true + false + true + false + + + + false + + + + + inputVar1 + <a href="\/([^"]+)" + -1 + fout + $1$ + false + + + + inputVar + src="\/([^"]+)" + -1 + fout + $1$ + false + + + + inputVar + href="\/([^"]+)" + -1 + fout + $1$ + false + + + + + returnVar1 + inputVar1 + true + + + + + + + + + + + ${returnVar1} + GET + true + false + true + false + + + + false + + + + + inputVar2 + <a href="\/([^"]+)" + -1 + fout + $1$ + false + + + + + + returnVar2 + inputVar2 + true + + + + + + + + + + + ${returnVar2} + GET + true + false + true + false + + + + false + + + + + + + 0 + false + continue + 1076438592000 + + false + 1 + + 1 + + + 1076438592000 + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + + + + + + + + reaktor.lab.linpro.no + + + + + + + + + + + + + + + / + GET + true + false + true + false + + + + false + + + + + inputVar1 + <a href="\/([^"]+)" + -1 + fout + $1$ + false + + + + + returnVar1 + inputVar1 + true + + + + + + + + + + + ${returnVar1} + GET + true + false + true + false + + + + false + + + + + inputVar2 + <a href="\/([^"]+)" + -1 + fout + $1$ + false + + + + + returnVar2 + inputVar2 + true + + + + + + + + + + + ${returnVar2} + GET + true + false + true + false + + + + false + + + + + + + + + false + 1 + + 7 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + false + + + + + + User-Agent + Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US) + + + + + + + + User-Agent + Opera/9.62 (X11; Linux i686; U; en) Presto/2.1.1 + + + + + + + + User-Agent + Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/2008111317 Ubuntu/8.04 (hardy) Firefox/3.0.4 + + + + + + + + User-Agent + Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; en) AppleWebKit/528.5+ (KHTML, like Gecko) Version/4.0 Safari/528.1 + + + + + + + + + reaktor.lab.linpro.no + + + utf-8 + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + true + true + true + true + true + true + true + true + true + false + true + 0 + true + true + true + true + true + true + + + investigations/Tree.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Table.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + investigations/Summary.jtl + + + + + + + + + + + / + GET + false + true + true + false + + + + true + false + + + + + + + + false + + + + + + + false + userboy + = + true + username + + + false + userboy + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/message/inbox + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/userboy + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/content/manage/menu + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/content/manage/allartwork + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/content/manage/allapproved + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/content/manage/submittedartwork + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/content/manage/draftartwork + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/content/manage/allrejected + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/content/manage/allfiles + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/mypage/content/manage/orphanedfiles + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/portfolio/userboy + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/profile + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/profile/changepassword/userboy/0 + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/upload + GET + false + true + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/audio-test-1.wav + file + audio/wav + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-metadata.wma + file + audio/x-ms-wma + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-no-metadata.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-id3-v1.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-id3-v2.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-id3-v1-and-v2.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-ape-v2.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-id3-v1-and-v2-and-ape-v2.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-id3-v1-and-ape-v2.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-id3-v2-and-ape-v2.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/metadata/gong-id3-v1-and-v2-and-ape-v2-with-image.mp3 + file + audio/mpeg + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/large/grid1920.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + + diff --git a/test/jmeter/upload.jmx b/test/jmeter/upload.jmx new file mode 100644 index 0000000..d3bd4e8 --- /dev/null +++ b/test/jmeter/upload.jmx @@ -0,0 +1,1735 @@ + + + + + + false + false + + + + + + + + false + + + + + + User-Agent + Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US) + + + + + + + + User-Agent + Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.4) Gecko/2008111317 Ubuntu/8.04 (hardy) Firefox/3.0.4 + + + + + + + + User-Agent + Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_4_11; en) AppleWebKit/528.5+ (KHTML, like Gecko) Version/4.0 Safari/528.1 + + + + + + + + User-Agent + Opera/9.62 (X11; Linux i686; U; en) Presto/2.1.1 + + + + + + + + + reaktor.lab.linpro.no + + + utf-8 + + + + + + + + prod.minreaktor.no + + + utf-8 + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + upload/GraphResults.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + upload/SplineVisualizer.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + upload/AggregateGraph.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + upload/AggregateReport.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + upload/Summary.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + false + false + false + 0 + true + + + upload/Table.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + true + true + true + true + true + true + true + true + true + false + true + 0 + true + true + true + true + true + true + + + upload/Tree.jtl + + + + + false + 1 + + 1 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + userboy + = + true + username + + + false + userboy + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + monkeyboy + = + true + username + + + false + monkeyboy + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + languageboy + = + true + username + + + false + languageboy + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + admin + = + true + username + + + false + admin + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + editorialboy1 + = + true + username + + + false + editorialboy1 + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + editorialboy2 + = + true + username + + + false + editorialboy2 + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 1 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + editorialboy3 + = + true + username + + + false + editorialboy3 + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 0 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + testupload1 + = + true + username + + + false + test + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 0 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + testupload2 + = + true + username + + + false + test + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 0 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + testupload3 + = + true + username + + + false + test + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 0 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + testupload4 + = + true + username + + + false + test + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 0 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + testupload5 + = + true + username + + + false + test + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 0 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + testupload6 + = + true + username + + + false + test + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + false + 1 + + 1 + 0 + 1227780386000 + 1227780386000 + false + continue + + + + + + + false + + + + + + + false + testupload7 + = + true + username + + + false + test + = + true + password + + + + + + + + /no/login + POST + true + false + true + false + + + + true + false + + + + + + + + + + + + /no/upload + POST + true + false + true + true + /home/chrisw/oppdrag/reaktor/svn/test/data/image-test-1.jpg + file + image/jpeg + true + false + + + + + + + + + + + + /no/logout + GET + false + true + true + false + + + + true + false + + + + + + + diff --git a/test/siege/config-default.txt b/test/siege/config-default.txt new file mode 100644 index 0000000..7a6fe89 --- /dev/null +++ b/test/siege/config-default.txt @@ -0,0 +1,12 @@ +accept-encoding = gzip +benchmark = false +cache = false +chunked = true +connection = close +failures = 50 +internet = false +logging = false +protocol = HTTP/1.1 +show-logfile = false +spinner = false +verbose = false diff --git a/test/siege/many-users.bash b/test/siege/many-users.bash new file mode 100755 index 0000000..4afe4f9 --- /dev/null +++ b/test/siege/many-users.bash @@ -0,0 +1,87 @@ +#!/bin/bash +# wget ftp://ftp.joedog.org/pub/siege/siege-2.67.tar.gz && tar zxf siege-2.67.tar.gz && cd siege-2.67 && ./configure && make +# make install +# +# siege --help +# +# -C, --config CONFIGURATION, show the current configuration. +# -v, --verbose VERBOSE, prints notification to screen. +# -c, --concurrent=NUM CONCURRENT users, default is 10 +# -i, --internet INTERNET user simulation, hits the URLs randomly. +# +# -t, --time=NUMm TIME based testing where "m" is the modifier S, M, or H +# no space between NUM and "m", ex: --time=1H, one hour test. +# +# -r, --reps=NUM REPS, number of times to run the test, default is 25 +# -f, --file=FILE FILE, change the configuration file to file. +# -R, --rc=FILE RC, change the siegerc file to file. Overrides +# the SIEGERC environmental variable. +# -l, --log LOG, logs the transaction to PREFIX/var/siege.log +# +# -d, --delay=NUM Time DELAY, random delay between 1 and num designed +# to simulate human activity. Default value is 3 + +#config=config-default.txt +config=config-nologin.txt + +# www.minreaktor.no = 171.23.133.229 +#host='171.23.133.229' +#host='www.minreaktor.no' +host='localhost' + +#url="http://$host" +url="-i -f urls-no-login.txt" + +dir="$host-$(date '+%Y-%m-%d_%H.%M.%S')" + +#log="$PWD/$dir-c${num_users}t${time}-reaktor.log" +log="$PWD/$dir-reaktor.log" + +#cmd_siege=siege +cmd_siege='/home/linpro/siege/siege-2.67/src/siege' +cmd_ps='ps -o pid,user=USERNAME -o nlwp=THR -o pri,nice=NICE -o vsz=SIZE -o rss=RES -o s=STATE -o time,pcpu=CPU -o args' + +#$cmd_siege -R $config -C 2>&1|tee -a $log +$cmd_siege -R $config -C 1>>$log 2>&1 + +# Increasing users ------------------------------------------------------------- +delay=5 +Users[1]=10;Time[1]=1M;Delay[1]=$delay +Users[2]=20;Time[2]=1M;Delay[2]=$delay +Users[3]=30;Time[3]=1M;Delay[3]=$delay +Users[4]=40;Time[4]=1M;Delay[4]=$delay +Users[5]=50;Time[5]=1M;Delay[5]=$delay +Users[6]=60;Time[6]=1M;Delay[6]=$delay +Users[7]=70;Time[7]=1M;Delay[7]=$delay +Users[8]=80;Time[8]=1M;Delay[8]=$delay +Users[9]=90;Time[9]=1M;Delay[9]=$delay +Users[10]=100;Time[10]=1M;Delay[10]=$delay +Users[11]=110;Time[11]=1M;Delay[11]=$delay + + +# Different delays ------------------------------------------------------------- +#users=20 +#Users[1]=$users;Time[1]=1M;Delay[1]=7 +#Users[2]=$users;Time[2]=1M;Delay[2]=5 +#Users[3]=$users;Time[3]=1M;Delay[3]=3 +#Users[4]=$users;Time[4]=1M;Delay[4]=5 +#Users[5]=$users;Time[5]=1M;Delay[5]=4 +#Users[6]=$users;Time[6]=1M;Delay[6]=3 + + +pid="$$" +(while ps -p $pid >/dev/null 2>/dev/null; do echo && $cmd_ps -p $pid && uptime && free -o && sleep 10; done) 2>&1|tee -a $log & + +#free -o -s 10 -c 37& +for index in 1 2 3 4 5 6 7; do + echo '--------------------------------------------------------------------------------' 2>&1|tee -a $log + #uptime 2>&1|tee -a $log + #command="$cmd_siege -R $config -c ${Users[index]} -t ${Time[index]} -d ${Delay[index]} -l $log $url" + command="$cmd_siege -R $config -c ${Users[index]} -t ${Time[index]} -d ${Delay[index]} -v -i -f urls-no-login.txt" + #echo $command 2>&1|tee -a $log + echo $command 1>>$log 2>&1 + #$command 2>&1|tee -a $log + $command 1>>$log 2>&1 + #uptime 2>&1|tee -a $log +done + diff --git a/test/siege/urls-no-login.txt b/test/siege/urls-no-login.txt new file mode 100644 index 0000000..456b5a9 --- /dev/null +++ b/test/siege/urls-no-login.txt @@ -0,0 +1,74 @@ +http://localhost/ +http://localhost/no/foto +http://localhost/no/tegning +http://localhost/no/film +http://localhost/no/lyd +http://localhost/no/tegneserier +http://localhost/no/tekst +http://localhost/no/register +http://localhost/no/rssfeeds +http://localhost/no/feed/latest_artworks +http://localhost/no/feed/latest_commented +http://localhost/no/feed/latest_users +http://localhost/no/feed/most_popular +http://localhost/no/feed/popular_foto +http://localhost/no/feed/recommended_artwork +http://localhost/no/list/users +http://localhost/no/list/users/startingwith/A +http://localhost/no/list/users/startingwith/B +http://localhost/no/list/users/startingwith/C +http://localhost/no/list/users/startingwith/D +http://localhost/no/list/users/startingwith/E +http://localhost/no/list/users/startingwith/F +http://localhost/no/list/users/startingwith/G +http://localhost/no/list/users/startingwith/H +http://localhost/no/list/users/startingwith/I +http://localhost/no/list/users/startingwith/J +http://localhost/no/list/users/startingwith/K +http://localhost/no/list/users/startingwith/L +http://localhost/no/list/users/startingwith/M +http://localhost/no/list/users/startingwith/N +http://localhost/no/list/users/startingwith/O +http://localhost/no/list/users/startingwith/P +http://localhost/no/list/users/startingwith/Q +http://localhost/no/list/users/startingwith/R +http://localhost/no/list/users/startingwith/S +http://localhost/no/list/users/startingwith/T +http://localhost/no/list/users/startingwith/U +http://localhost/no/list/users/startingwith/V +http://localhost/no/list/users/startingwith/W +http://localhost/no/list/users/startingwith/X +http://localhost/no/list/users/startingwith/Y +http://localhost/no/list/users/startingwith/Z +http://localhost/no/list/users/startingwith/Æ +http://localhost/no/list/users/startingwith/Ø +http://localhost/no/list/users/startingwith/Å +http://localhost/no/feed/users_by_A +http://localhost/no/feed/users_by_B +http://localhost/no/feed/users_by_C +http://localhost/no/feed/users_by_D +http://localhost/no/feed/users_by_E +http://localhost/no/feed/users_by_F +http://localhost/no/feed/users_by_G +http://localhost/no/feed/users_by_H +http://localhost/no/feed/users_by_I +http://localhost/no/feed/users_by_J +http://localhost/no/feed/users_by_K +http://localhost/no/feed/users_by_L +http://localhost/no/feed/users_by_M +http://localhost/no/feed/users_by_N +http://localhost/no/feed/users_by_O +http://localhost/no/feed/users_by_P +http://localhost/no/feed/users_by_Q +http://localhost/no/feed/users_by_R +http://localhost/no/feed/users_by_S +http://localhost/no/feed/users_by_T +http://localhost/no/feed/users_by_U +http://localhost/no/feed/users_by_V +http://localhost/no/feed/users_by_W +http://localhost/no/feed/users_by_X +http://localhost/no/feed/users_by_Y +http://localhost/no/feed/users_by_Z +http://localhost/no/feed/users_by_Æ +http://localhost/no/feed/users_by_Ø +http://localhost/no/feed/users_by_Å diff --git a/test/unit/ReaktorArtworkPeerTest.php b/test/unit/ReaktorArtworkPeerTest.php new file mode 100644 index 0000000..c55e76c --- /dev/null +++ b/test/unit/ReaktorArtworkPeerTest.php @@ -0,0 +1,63 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: ReaktorArtworkPeerTest.php 1138 2008-05-29 10:24:17Z dae $ + */ + +define('SF_APP', 'reaktor'); +$base_dir = realpath(dirname(__FILE__).'/../..'); +include($base_dir.'/plugins/sfModelTestPlugin/bootstrap/model-unit.php'); + +class ReaktorArtworkPeerTest extends sfPropelTest +{ + public function test_getArtworkByStatus() + { + $stat = array('Draft' => 0, + 'Ready for approval' => 2, + 'Approved' => 3, + 'Rejected' => 0, + 'Discussion' => 1, + ); + foreach ($stat as $s => $c) + { + $this->is(count(ReaktorArtworkPeer::getArtworkByStatus($c)), + $c, + "Counting status for: $s"); + } + } + + public function test_getUnapprovedArtworks() + { + $this->pass('Dummy test'); + + } + + public function test_getStatusIdByDescription() + { + $as = ArtworkStatusPeer::doSelect(new Criteria()); + $this->diag("getStatusIdByDescription()"); + foreach ($as as $i) + { + $this->is(ReaktorArtworkPeer::getStatusIdByDescription($i->getDescription()), + $i->getId(), + "Checking description: ". $i->getDescription()); + } + + // FIX isn't it bether to throw an exception instead of returning 0? + $this->is(ReaktorArtworkPeer::getStatusIdByDescription('This would probably not exist ...'), + 0, + "Nonexistent description"); + } + +} + +$test = new ReaktorArtworkPeerTest($base_dir.'/data/fixtures/fixtures.yml'); +$test->execute(); + diff --git a/test/unit/UserInterestPeerTest.php b/test/unit/UserInterestPeerTest.php new file mode 100644 index 0000000..2014eb7 --- /dev/null +++ b/test/unit/UserInterestPeerTest.php @@ -0,0 +1,55 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: UserInterestPeerTest.php 1148 2008-05-29 16:09:28Z dae $ + */ + +define('SF_APP', 'reaktor'); +$base_dir = realpath(dirname(__FILE__).'/../..'); +//include($base_dir.'/plugins/sfModelTestPlugin/bootstrap/model-unit.php'); +include(dirname(__FILE__).'/../bootstrap/unit.php'); + +class UserInterestPeerTest extends sfPropelTest +{ + public function test_retrieveByUser() + { + $c = new Criteria(); + $c->add(sfGuardUserPeer::USERNAME, 'userboy'); + $user = sfGuardUserPeer::doSelectOne($c); + + $this->is(count(UserInterestPeer::retrieveByUser($user->getId())), + 3, + 'Userboy has three interests'); + + + $c = new Criteria(); + $c->add(sfGuardUserPeer::USERNAME, 'monkeyboy'); + $user = sfGuardUserPeer::doSelectOne($c); + $this->is(count(UserInterestPeer::retrieveByUser($user->getId())), + 1, + 'Monkeyboy has one interest'); + } + + + public function test_deleteByUser() + { + $c = new Criteria(); + $c->add(sfGuardUserPeer::USERNAME, 'monkeyboy'); + $user = sfGuardUserPeer::doSelectOne($c); + UserInterestPeer::deleteByUser($user->getId()); + $this->is(UserInterestPeer::retrieveByUser($user->getId()), + null, + 'Deleted monkeyboys interests'); + } +} + +$test = new UserInterestPeerTest($base_dir.'/data/fixtures/'); +$test->execute(); + diff --git a/test/unit/cloudHelperTest.php b/test/unit/cloudHelperTest.php new file mode 100644 index 0000000..d7f708a --- /dev/null +++ b/test/unit/cloudHelperTest.php @@ -0,0 +1,31 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +$test_dir = dirname(__FILE__).'/..'; + +require $test_dir.'/bootstrap/unit.php'; +require_once $test_dir.'/../apps/reaktor/lib/helper/cloudHelper.php'; + +//////////////////////////////////////////////////////////////////////////////// +// MOCKS + +function link_to() { + return ''; +} + +// +//////////////////////////////////////////////////////////////////////////////// + +$t = new lime_test(1, new lime_output_color()); + +$tags = array('a' => array('count' => 2), + 'b' => array('count' => 3)); +$t->is(substr_count(tag_cloud_with_count($tags, 'foo'), ''), 2, 'Correct num anchors returned'); diff --git a/test/unit/contentHelperTest.php b/test/unit/contentHelperTest.php new file mode 100644 index 0000000..8c1aab9 --- /dev/null +++ b/test/unit/contentHelperTest.php @@ -0,0 +1,20 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: contentHelperTest.php 524 2008-03-28 00:58:49Z kjellm $ + */ + + +require dirname(__FILE__).'/../bootstrap/unit.php'; +require_once dirname(__FILE__).'/../../apps/reaktor/lib/helper/contentHelper.php'; + +$t = new lime_test(1, new lime_output_color()); + +$t->pass("Replace me!"); \ No newline at end of file diff --git a/test/unit/flashHelperTest.php b/test/unit/flashHelperTest.php new file mode 100644 index 0000000..11f5c04 --- /dev/null +++ b/test/unit/flashHelperTest.php @@ -0,0 +1,45 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: flashHelperTest.php 524 2008-03-28 00:58:49Z kjellm $ + */ + + +require dirname(__FILE__).'/../bootstrap/unit.php'; +require_once dirname(__FILE__).'/../../apps/reaktor/lib/helper/flashHelper.php'; + +$t = new lime_test(2, new lime_output_color()); + + + +$t->diag('flash_movie_player()'); +$expected = << + + + + +HERE; +$t->is($expected, flash_movie_player('foo'), "HTML object tag ok. Contains flowplayer"); + + + +$t->diag('flash_audio_player()'); +$expected = << + + + +HERE; + $t->is($expected, flash_audio_player('foo', 'Space+door'), "HTML object tag ok. Contains xspf_playerr"); + diff --git a/test/unit/genericArtworkTest.php b/test/unit/genericArtworkTest.php new file mode 100644 index 0000000..8e6a7df --- /dev/null +++ b/test/unit/genericArtworkTest.php @@ -0,0 +1,103 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: UserInterestPeerTest.php 524 2008-03-28 00:58:49Z kjellm $ + */ + +define('SF_APP', 'reaktor'); +$base_dir = realpath(dirname(__FILE__).'/../..'); +include(dirname(__FILE__).'/../bootstrap/unit.php'); + +include(dirname(__FILE__).'/../../apps/reaktor/lib/genericArtwork.class.php'); + +class genericArtworkTest extends genericArtwork +{ + + /** + * constructs a genericArtwork object + * + * @param integer $id + * + * @return genericArtworkTest + */ + function __construct($id) + { + parent::__construct($id); + } + + /** + * Test the getEditorialTeam function + * + * @param newLimeTest $test + * + * @return sfGuardGroup + */ + function testGetEditorialTeam($test) + { + $test->diag('Testing genericArtwork::getEditorialTeam()'); + $test->ok($retval = parent::getEditorialTeam(), 'Getting editorial team'); + $test->ok($retval instanceof sfGuardGroup && $retval->getIsEditorialTeam(), 'New editorial team is a group and is an editorial team'); + return $retval; + } + + /** + * Test the setEditorialTeam function + * + * @param integer $val + * @param newLimeTest $test + */ + function testSetEditorialTeam($val, $test) + { + $test->diag('Testing genericArtwork::setEditorialTeam()'); + $test->ok(parent::setEditorialTeam($val), 'Setting editorial team to ' . $val); + $test->diag('New editorial team set'); + } + + /** + * Test the reset editorial team function + * + * @param newLimeTest $test + */ + function testResetEditorialTeam($test) + { + $test->diag('Testing genericArtwork::resetEditorialTeam()'); + $test->ok(parent::resetEditorialTeam() instanceof sfGuardGroup, 'Resetting editorial team'); + $test->diag('New editorial team saved'); + } + +} + +$test = new newLimeTest($base_dir.'/data/fixtures/'); + +$c = new Criteria(); +$c->add(ReaktorArtworkPeer::TEAM_ID, 0, Criteria::GREATER_THAN); +//$c->setLimit(1); + +$artworks = ReaktorArtworkPeer::doSelect($c); + +foreach ($artworks as $artwork) +{ + try + { + $artwork = new genericArtworkTest($artwork->getId()); + $test->ok($artwork instanceof genericArtwork, 'Instantiated genericArtwork object with id ' . $artwork->getId()); + } + catch (Exception $e) + { + $test->fail('genericArtwork did not instantiate properly: ' . $e->getMessage()); + break; + } + + $prev_id = $artwork->getEditorialTeam()->getId(); + $artwork->testSetEditorialTeam(0, $test); + $artwork->testResetEditorialTeam($test); + $artwork->testGetEditorialTeam($test); + $test->ok($prev_id == $artwork->getEditorialTeam()->getId(), 'New editorial team ' . $artwork->getEditorialTeam()->getName() . '(' . $artwork->getEditorialTeam()->getId() . ') is correct for artwork with id ' . $artwork->getTitle()); +} \ No newline at end of file diff --git a/test/unit/homeHelperTest.php b/test/unit/homeHelperTest.php new file mode 100644 index 0000000..72d7992 --- /dev/null +++ b/test/unit/homeHelperTest.php @@ -0,0 +1,39 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: homeHelperTest.php 524 2008-03-28 00:58:49Z kjellm $ + */ + +$test_dir = dirname(__FILE__).'/..'; +require $test_dir.'/bootstrap/unit.php'; +require_once $test_dir.'/../apps/reaktor/lib/helper/homeHelper.php'; + +//////////////////////////////////////////////////////////////////////////////// +// MOCK + + +function image_tag() { + return ''; +} + +if (!class_exists('sfConfig')) { + class sfConfig { + function get() { + return 6; + } + } +} + + +//////////////////////////////////////////////////////////////////////////////// + +$t = new lime_test(1, new lime_output_color()); + +$t->is(substr_count(showScore(4), ''), 4, 'Correct num images returned'); diff --git a/test/unit/id3v1Test.php b/test/unit/id3v1Test.php new file mode 100644 index 0000000..42c0bd8 --- /dev/null +++ b/test/unit/id3v1Test.php @@ -0,0 +1,29 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: transcoderTest.php 437 2008-03-05 22:30:27Z kjellm $ + */ + +$test_dir = dirname(__FILE__).'/..'; +require $test_dir.'/bootstrap/unit.php'; +require_once $test_dir.'/../apps/reaktor/lib/id3v1.class.php'; + +$t = new lime_test(8, new lime_output_color()); + +$id3 = new id3v1('test/data/audio-test-3.mp3', true); + +$t->is($id3->getTitle(), "Test 3", "Title"); +$t->is($id3->getArtist(), "NA", "Title"); +$t->is($id3->getAlbum(), "Test album", "Title"); +$t->is($id3->getComment(), "Just an aaaaaaaaaaaaaaaaaaa", "Title"); +$t->is($id3->getGenre(), "R&B", "Title"); +$t->is($id3->getGenreId(), 14, "Title"); +$t->is($id3->getYear(), "2008", "Title"); +$t->is($id3->getTrack(), "1", "Title"); \ No newline at end of file diff --git a/test/unit/imageResizeTest.php b/test/unit/imageResizeTest.php new file mode 100644 index 0000000..df76bbb --- /dev/null +++ b/test/unit/imageResizeTest.php @@ -0,0 +1,34 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: imageResizeTest.php 524 2008-03-28 00:58:49Z kjellm $ + */ + +$test_dir = dirname(__FILE__).'/..'; +require $test_dir.'/bootstrap/unit.php'; +require_once $test_dir.'/../apps/reaktor/lib/imageResize.class.php'; + +$tmp_dir = $test_dir.'/tmp-imageresize'; +exec("rm -rf $tmp_dir"); +mkdir($tmp_dir); + + +$t = new lime_test(2, new lime_output_color()); + +$ir = new imageResize('test/data/image-test-1.jpg', $tmp_dir.'/resized.jpg', 100, 100); +$ir->imageWrite(); +$t->is(md5($tmp_dir.'/resized.jpg'), '7f3438458c50196c4489f1022cca0011', 'Resized md5 matches'); + +try { + $ir = new imageResize(__FILE__, $tmp_dir.'/resized.jpg', 100, 100); + $t->fail('Trying to resize a text file'); +} catch (Exception $e) { + $t->pass('Trying to resize a text file'); +} diff --git a/test/unit/sfGuardUserPeerTest.php b/test/unit/sfGuardUserPeerTest.php new file mode 100644 index 0000000..727fc8f --- /dev/null +++ b/test/unit/sfGuardUserPeerTest.php @@ -0,0 +1,33 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: sfGuardUserPeerTest.php 764 2008-04-28 14:09:35Z dae $ + */ + +define('SF_APP', 'reaktor'); +$base_dir = realpath(dirname(__FILE__).'/../..'); +include($base_dir.'/plugins/sfModelTestPlugin/bootstrap/model-unit.php'); + +class sfGuardUserPeerTest extends sfPropelTest +{ + public function test_retrieveByEmail() + { + $u = sfGuardUserPeer::retrieveByEmail('userboy@linpro.no'); + + $this->is($u->getName(), 'User Boy', "getName()"); + $this->is($u->getSex(), '1', "getSex()"); + + $this->is(sfGuardUserPeer::retrieveByEmail('nonexistent'), null, "Nonexistent email"); + } +} + +$test = new sfGuardUserPeerTest($base_dir.'/data/fixtures/fixtures.yml'); +$test->execute(); + diff --git a/test/unit/stringMagickTest.php b/test/unit/stringMagickTest.php new file mode 100644 index 0000000..6d6d9df --- /dev/null +++ b/test/unit/stringMagickTest.php @@ -0,0 +1,35 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: stringMagickTest.php 524 2008-03-28 00:58:49Z kjellm $ + */ + +$test_dir = dirname(__FILE__).'/..'; +require $test_dir.'/bootstrap/unit.php'; +require_once $test_dir.'/../apps/reaktor/lib/stringMagick.class.php'; + +$t = new lime_test(4, new lime_output_color()); + +$t->is(strlen(stringMagick::randomString()), 5, "Default length of random string"); +$t->is(strlen(stringMagick::randomString(10)), 10, "Return a string with proper length"); + +try { + stringMagick::randomString(-1); + $t->fail("Exception thrown for negative length"); +} catch (Exception $e) { + $t->pass("Exception thrown for negative length"); +} + +try { + stringMagick::randomString("asdfs"); + $t->fail("Exception thrown for non-numeric length"); +} catch (Exception $e) { + $t->pass("Exception thrown for non-numeric length"); +} diff --git a/test/unit/transcoderTest.php b/test/unit/transcoderTest.php new file mode 100644 index 0000000..badc389 --- /dev/null +++ b/test/unit/transcoderTest.php @@ -0,0 +1,112 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: transcoderTest.php 558 2008-04-03 01:18:56Z kjellm $ + */ + +/* We seem to be running inside a function, so I need to register + * these as globals (Hope that doesn't brake anything ...)) */ +global $tmp_dir, $test_dir, $t, $tc; + +$test_dir = dirname(__FILE__).'/..'; +$tmp_dir = $test_dir.'/tmp-transcoder'; + +require $test_dir.'/bootstrap/unit.php'; +require_once $test_dir.'/../apps/reaktor/lib/transcoder.class.php'; + +$t = new lime_test(27, new lime_output_color()); + +exec("rm -rf $tmp_dir"); +mkdir($tmp_dir); +mkdir($tmp_dir.'/audio'); +mkdir($tmp_dir.'/video'); + +$tc = new transcoder($tmp_dir.'/'); + +//////////////////////////////////////////////////////////////////////////////// + +$t->diag('transcode() error handling'); +try +{ + $tc->transcode('this file should not exist!', '/tmp'); + $t->fail('File not found throws exception'); +} +catch (Exception $e) +{ + $t->pass('File not found throws exception'); +} + +try +{ + touch($tmp_dir .'/empty'); + $tc->transcode($tmp_dir .'/empty', '/tmp'); + $t->fail('Empty file throws exception'); +} +catch (Exception $e) +{ + $t->pass('Empty file throws exception'); +} + +try +{ + $tc->transcode(__FILE__, '/tmp'); + $t->fail('Trying to transcode a text file'); +} +catch (Exception $e) +{ + $t->pass('Trying to transcode a text file'); +} + + + +//////////////////////////////////////////////////////////////////////////////// + +function test_video($comment, $filename, $expected_filesize) { + global $tmp_dir, $test_dir, $t, $tc; + + $basename = substr($filename, 0, strrpos($filename, '.')); + + $t->diag($comment); + /* The MD5 approach does not work in this case, since a timestamp gets + * embeded in the flv. Testing on filesize instead. */ + $ret = $tc->transcode($test_dir.'/data/'.$filename, $filename); + $t->is(filesize($tmp_dir.'/video/'.$basename.'.flv'), + $expected_filesize, + 'flv filesize matches'); + $t->is($ret['newFileName'], $basename.'.flv', 'Returned filename'); + $t->is($ret['convertedMime'], 'video/flv', 'Returned mime type'); +} + + +test_video('Video - AVI', 'video-test-1.avi', 144989); +test_video('Video - OGG/Theora', 'video-test-2.ogg', 152358); +test_video('Video - FLV', 'video-test-3.flv', 144989); +test_video('Video - WMV', 'video-test-4.wmv', 143608); + + +function test_audio($comment, $filename, $expected_md5sum) { + global $tmp_dir, $test_dir, $t, $tc; + + $basename = substr($filename, 0, strrpos($filename, '.')); + + $t->diag($comment); + $ret = $tc->transcode($test_dir.'/data/'.$filename, $filename); + $t->is(md5_file($tmp_dir.'/audio/'.$basename.'.mp3'), $expected_md5sum, + 'Conversion to mp3, MD5 matches'); + $t->is($ret['newFileName'], $basename.'.mp3', 'Returned filename'); + $t->is($ret['convertedMime'], 'audio/mpeg', 'Returned mime type'); + +} + +test_audio('Audio - WAV', 'audio-test-1.wav', '1eec95a85007dfb0d9529de9dc3a5d58'); +test_audio('Audio - OGG/Vorbis', 'audio-test-2.ogg', '991f8cceeff61b44cee5b687bd70d494'); +test_audio('Audio - MP3', 'audio-test-3.mp3', '6d97d184bfba72e0a18e117ff62e1641'); +test_audio('Audio - MIDI', 'audio-test-4.mid', '0778b9c3b16871354ada59b983def3ff'); + diff --git a/test/unit/videoFrameTest.php b/test/unit/videoFrameTest.php new file mode 100644 index 0000000..44e82a0 --- /dev/null +++ b/test/unit/videoFrameTest.php @@ -0,0 +1,34 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: videoFrameTest.php 675 2008-04-16 20:07:25Z kjellm $ + */ + +$test_dir = dirname(__FILE__).'/..'; + +require_once $test_dir.'/../apps/reaktor/lib/videoFrame.class.php'; +require $test_dir.'/bootstrap/unit.php'; + +$t = new lime_test(3, new lime_output_color()); + +try +{ + $vf = videoFrame::fromVideoFile('/this/file/does/really_unlikely/exist'); + $t->fail("File not found should result in an Exception"); +} +catch (Exception $e) +{ + $t->pass("File not found should result in an Exception"); +} + +$vf = videoFrame::fromVideoFile($test_dir.'/data/video-test-1.avi'); +$t->is(strlen($vf->getContent()), 32498); +$t->is(md5($vf->getContent()), '0cdd2f777e6207e3ad2c23a1cac2c1e0'); +$t->is($vf->getMime(), 'image/jpeg'); diff --git a/test/unit/videoInfoTest.php b/test/unit/videoInfoTest.php new file mode 100644 index 0000000..a8f2d68 --- /dev/null +++ b/test/unit/videoInfoTest.php @@ -0,0 +1,34 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: videoFrameTest.php 524 2008-03-28 00:58:49Z kjellm $ + */ + +$test_dir = dirname(__FILE__).'/..'; + +require_once $test_dir.'/../apps/reaktor/lib/videoInfo.class.php'; +require $test_dir.'/bootstrap/unit.php'; + +$t = new lime_test(2, new lime_output_color()); + +try +{ + $vf = videoInfo::videoLength('/this/file/does/really_unlikely/exist'); + $t->fail("File not found should result in an Exception"); +} +catch (Exception $e) +{ + $t->pass("File not found should result in an Exception"); +} + +$len = videoInfo::videoLength($test_dir.'/data/video-test-1.avi'); + +//FIX Allow for floating point roundinng errors? +$t->is($len, 2.8, "Checking correct length returned"); diff --git a/utils/rebuild b/utils/rebuild new file mode 100755 index 0000000..30296ba --- /dev/null +++ b/utils/rebuild @@ -0,0 +1,13 @@ +#! /bin/bash + +mysqladmin -uroot -f drop reaktor +mysqladmin -uroot create reaktor +symfony clear-cache +symfony propel-build-model +symfony propel-build-sql +symfony propel-insert-sql +symfony propel-load-data reaktor + +mysqladmin -uroot -f drop reaktor_test +mysqladmin -uroot create reaktor_test +cat data/sql/*.sql | mysql -u root reaktor_test diff --git a/web/.htaccess b/web/.htaccess new file mode 100644 index 0000000..827bc58 --- /dev/null +++ b/web/.htaccess @@ -0,0 +1,28 @@ +Options +FollowSymLinks +ExecCGI + + + RewriteEngine On + + # uncomment the following line, if you are having trouble + # getting no_script_name to work + #RewriteBase / + + # we skip all files with .something, and content served files + RewriteCond %{REQUEST_URI} ^\..+$ + RewriteCond %{REQUEST_URI} !\.html$ + RewriteCond %{REQUEST_URI} !/content/* + RewriteRule .* - [L] + + # we check if the .html version is here (caching) + RewriteRule ^$ index.html [QSA] + RewriteRule ^([^.]+)$ $1.html [QSA] + RewriteCond %{REQUEST_FILENAME} !-f + + # no, so we redirect to our front web controller + RewriteRule ^(.*)$ index.php [QSA,L] + + +# big crash from our front web controller +ErrorDocument 500 "

      Application error

      symfony application failed to start properly" +AddType application/octet-stream .pdf + diff --git a/web/css/cropper.css b/web/css/cropper.css new file mode 100644 index 0000000..0099851 --- /dev/null +++ b/web/css/cropper.css @@ -0,0 +1,217 @@ +.imgCrop_wrap { + /* width: 500px; @done_in_js */ + /* height: 375px; @done_in_js */ + position: relative; + cursor: crosshair; +} + +/* an extra classname is applied for Opera < 9.0 to fix it's lack of opacity support */ +.imgCrop_wrap.opera8 .imgCrop_overlay, +.imgCrop_wrap.opera8 .imgCrop_clickArea { + background-color: transparent; +} + +/* fix for IE displaying all boxes at line-height by default, although they are still 1 pixel high until we combine them with the pointless span */ +.imgCrop_wrap, +.imgCrop_wrap * { + font-size: 0; +} + +.imgCrop_overlay { + background-color: #000; + opacity: 0.5; + filter:alpha(opacity=50); + position: absolute; + width: 100%; + height: 100%; +} + +.imgCrop_selArea { + position: absolute; + /* @done_in_js + top: 20px; + left: 20px; + width: 200px; + height: 200px; + background: transparent url(castle.jpg) no-repeat -210px -110px; + */ + cursor: move; + z-index: 2; +} + +/* clickArea is all a fix for IE 5.5 & 6 to allow the user to click on the given area */ +.imgCrop_clickArea { + width: 100%; + height: 100%; + background-color: #FFF; + opacity: 0.01; + filter:alpha(opacity=01); +} + +.imgCrop_marqueeHoriz { + position: absolute; + width: 100%; + height: 1px; + background: transparent url(../images/marqueeHoriz.gif) repeat-x 0 0; + z-index: 3; +} + +.imgCrop_marqueeVert { + position: absolute; + height: 100%; + width: 1px; + background: transparent url(../images/marqueeVert.gif) repeat-y 0 0; + z-index: 3; +} + +/* + * FIX MARCHING ANTS IN IE + * As IE <6 tries to load background images we can uncomment the follwoing hack + * to remove that issue, not as pretty - but is anything in IE? + * And yes I do know that 'filter' is evil, but it will make it look semi decent in IE + * +* html .imgCrop_marqueeHoriz, +* html .imgCrop_marqueeVert { + background: transparent; + filter: Invert; +} +* html .imgCrop_marqueeNorth { border-top: 1px dashed #000; } +* html .imgCrop_marqueeEast { border-right: 1px dashed #000; } +* html .imgCrop_marqueeSouth { border-bottom: 1px dashed #000; } +* html .imgCrop_marqueeWest { border-left: 1px dashed #000; } +*/ + +.imgCrop_marqueeNorth { top: 0; left: 0; } +.imgCrop_marqueeEast { top: 0; right: 0; } +.imgCrop_marqueeSouth { bottom: 0px; left: 0; } +.imgCrop_marqueeWest { top: 0; left: 0; } + + +.imgCrop_handle { + position: absolute; + border: 1px solid #333; + width: 6px; + height: 6px; + background: #FFF; + opacity: 0.5; + filter:alpha(opacity=50); + z-index: 4; +} + +/* fix IE 5 box model */ +* html .imgCrop_handle { + width: 8px; + height: 8px; + wid\th: 6px; + hei\ght: 6px; +} + +.imgCrop_handleN { + top: -3px; + left: 0; + /* margin-left: 49%; @done_in_js */ + cursor: n-resize; +} + +.imgCrop_handleNE { + top: -3px; + right: -3px; + cursor: ne-resize; +} + +.imgCrop_handleE { + top: 0; + right: -3px; + /* margin-top: 49%; @done_in_js */ + cursor: e-resize; +} + +.imgCrop_handleSE { + right: -3px; + bottom: -3px; + cursor: se-resize; +} + +.imgCrop_handleS { + right: 0; + bottom: -3px; + /* margin-right: 49%; @done_in_js */ + cursor: s-resize; +} + +.imgCrop_handleSW { + left: -3px; + bottom: -3px; + cursor: sw-resize; +} + +.imgCrop_handleW { + top: 0; + left: -3px; + /* margin-top: 49%; @done_in_js */ + cursor: w-resize; +} + +.imgCrop_handleNW { + top: -3px; + left: -3px; + cursor: nw-resize; +} + +/** + * Create an area to click & drag around on as the default browser behaviour is to let you drag the image + */ +.imgCrop_dragArea { + width: 100%; + height: 100%; + z-index: 200; + position: absolute; + top: 0; + left: 0; +} + +.imgCrop_previewWrap { + /* width: 200px; @done_in_js */ + /* height: 200px; @done_in_js */ + overflow: hidden; + position: relative; +} + +.imgCrop_previewWrap img { + position: absolute; +} + +#testWrap { + clear: both; + position: relative; + width: 720px; + text-align: left; +} + + +#testWrap span { float: left; } + +div#help_text { + float: right; + width: 430px; + padding-top: 10px; +} + +div#help_text form input[type="submit"] { float: right; } + +#previewOuterWrap { + border: 1px solid #DDD; + padding: 10px; + float: left; + width: 240px; +} + +#previewOuterWrap p { + text-align: center; + padding: 5px; +} + +#previewOuterWrap h4 { + margin-bottom: 5px; + text-align: center; +} \ No newline at end of file diff --git a/web/css/genericajax.css b/web/css/genericajax.css new file mode 100644 index 0000000..752160b --- /dev/null +++ b/web/css/genericajax.css @@ -0,0 +1,82 @@ +@CHARSET "UTF-8"; +form.inplaceeditor-form +{ /* The form */ +} + +#artwork_title-inplaceeditor .editor_field +{ /* Input box */ + width: 300px; + font-size: 13px; +} + +h1 form +{ + display: inline; +} + +#artwork_title-inplaceeditor .editor_ok_button +{ /* ok button */ + font-size: 1.0em; + text-transform: uppercase; +} + +#artwork_title-inplaceeditor .editor_cancel_link +{ /* cancel link */ + font-size: 1.0em; + /* text-transform: capitalize; */ +} + +#artwork_description-inplaceeditor .editor_field +{ /* Input box */ + width: 450px; +} + +#artwork_description-inplaceeditor .editor_ok_button +{ /* ok button */ +} + +#artwork_description-inplaceeditor .editor_cancel_link +{ /* cancel link */ +} + +form.inplaceeditor-form textarea +{ /* Textarea, if multiple columns */ + font-size: 12px; + color: #0E8293; + border: 1px solid #a5acb2; +} + +form.inplaceeditor-form input[type="submit"] +{ /* The submit button */ + font-size: 12px; + color: #0E8293; + margin-left:1em; + border: 1px solid #a5acb2; +} + +form.inplaceeditor-form a +{ /* The cancel link */ + text-decoration: none; + color: #282b64; + margin-left:1em; +} + +.sortable-list { + list-style-type : none; + margin : 0; +} +.sortable-list li { + border : 1px solid #000; + cursor : move; + margin : 2px 0 2px 0; + padding : 3px; + background : #f7f7f7; + border : #ccc; + width : 515px; + min-height: 65px; +} + +* html .sortable-list li { + height: 65px; +} + diff --git a/web/css/hidefooterimages.css b/web/css/hidefooterimages.css new file mode 100644 index 0000000..5cf3e9b --- /dev/null +++ b/web/css/hidefooterimages.css @@ -0,0 +1,6 @@ +@CHARSET "UTF-8"; + +#footer_images +{ + display: none; +} \ No newline at end of file diff --git a/web/css/lightwindow.css b/web/css/lightwindow.css new file mode 100644 index 0000000..20e03bf --- /dev/null +++ b/web/css/lightwindow.css @@ -0,0 +1,386 @@ +#lightwindow_overlay { + /* REQUIRED */ + display: none; + visibility: hidden; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100px; + z-index: 500; + /* REQUIRED */ +} + +#lightwindow { + /* REQUIRED */ + /* Of Note - The height and width of this element are set to 0px */ + display: none; + visibility: hidden; + position: absolute; + z-index: 999; + line-height: 0px; + /* REQUIRED */ +} + + #lightwindow_container { + /* REQUIRED */ + display: none; + visibility: hidden; + position: absolute; + /* REQUIRED */ + padding: 0 0 0 0; + margin: 0 0 0 0; + } + + /* IE6 needs this or it messes with our positioning */ + * html #lightwindow_container { + overflow: hidden; + } + + #lightwindow_contents { + overflow: hidden; + z-index: 0; + position: relative; + border: 10px solid #ffffff; + background-color: #ffffff; + } + +#lightwindow_loading { + /* REQUIRED */ + height: 100%; + width: 100%; + top: 0px; + left: 0px; + z-index: 9999; + position: absolute; + /* REQUIRED */ + background-color: #f0f0f0; + padding: 10px; +} + + #lightwindow_loading_shim { + display: none; + left: 0px; + position: absolute; + top: 0px; + width: 100%; + height: 100%; + } + + #lightwindow_loading span { + font-size: 12px; + line-height: 32px; + color: #444444; + float: left; + padding: 0 10px 0 0; + } + + #lightwindow_loading span a, + #lightwindow_loading span a:link, + #lightwindow_loading span a:visited { + color: #09F; + text-decoration: none; + cursor: pointer; + } + + #lightwindow_loading span a:hover, + #lightwindow_loading span a:active { + text-decoration: underline; + } + + + #lightwindow_loading img { + float: left; + margin: 0 10px 0 0; + } + + +/*----------------------------------------------------------------------------------------------- + I liked the Navigation so much from http://www.huddletogether.com/projects/lightbox2/ + I mean let's face it, it works really well and is very easy to figure out. +-----------------------------------------------------------------------------------------------*/ + +#lightwindow_navigation { + /* REQUIRED */ + position: absolute; + top: 0px; + left: 0px; + display: none; + /* REQUIRED */ +} + /* We need to shim the navigation for IE, though its more of a sub-floor */ + #lightwindow_navigation_shim { + /* REQUIRED */ + display: none; + left: 0px; + position: absolute; + top: 0px; + width: 100%; + height: 100%; + /* REQUIRED */ + } + + #lightwindow_navigation a, + #lightwindow_navigation a:link, + #lightwindow_navigation a:visited, + #lightwindow_navigation a:hover, + #lightwindow_navigation a:active { + /* REQUIRED */ + outline: none; + /* REQUIRED */ + } + + #lightwindow_previous, + #lightwindow_next { + width: 49%; + height: 100%; + background: transparent url(../images/blank.gif) no-repeat; /* Trick IE into showing hover */ + display: block; + } + + #lightwindow_previous { + float: left; + left: 0px; + } + + #lightwindow_next { + float: right; + right: 0px; + } + + #lightwindow_previous:hover, + #lightwindow_previous:active { + background: url(../images/prevlabel.gif) left 15% no-repeat; + } + + #lightwindow_next:hover, + #lightwindow_next:active { + background: url(../images/nextlabel.gif) right 15% no-repeat; + } + + #lightwindow_previous_title, + #lightwindow_next_title { + display: none; + } + +#lightwindow_galleries { + width: 100%; + position: absolute; + z-index: 50; + display: none; + overflow: hidden; + margin: 0 0 0 10px; + bottom: 0px; + left: 0px; +} + + #lightwindow_galleries_tab_container { + width: 100%; + height: 0px; + overflow: hidden; + } + + a#lightwindow_galleries_tab, + a:link#lightwindow_galleries_tab, + a:visited#lightwindow_galleries_tab { + display: block; + height: 20px; + width: 77px; + float: right; + line-height: 22px; + color: #ffffff; + text-decoration: none; + font-weight: bold; + cursor: pointer; + font-size: 11px; + color: #ffffbe; + background: url(../images/black-70.png) repeat 0 0 transparent; + } + + * html a#lightwindow_galleries_tab, + * html a:link#lightwindow_galleries_tab, + * html a:visited#lightwindow_galleries_tab { + background: none; + background-color: #000000; + opacity: .70; + filter: alpha(opacity=70); + } + + a:hover#lightwindow_galleries_tab, + a:active#lightwindow_galleries_tab { + color: #ffffbe; + + } + + #lightwindow_galleries_tab_span { + display: block; + height: 20px; + width: 63px; + padding: 0 7px 0 7px; + } + + #lightwindow_galleries_tab .up { + background: url(../images/arrow-up.gif) no-repeat 60px 5px transparent; + } + + #lightwindow_galleries_tab .down { + background: url(../images/arrow-down.gif) no-repeat 60px 6px transparent; + } + + #lightwindow_galleries_list { + background: url(../images/black-70.png) repeat 0 0 transparent; + overflow: hidden; + height: 0px; + } + + * html #lightwindow_galleries_list { + background: none; + background-color: #000000; + opacity: .70; + filter: alpha(opacity=70); + } + + .lightwindow_galleries_list { + width: 200px; + float: left; + margin: 0 0 10px 0; + padding: 10px; + } + + .lightwindow_galleries_list h1 { + color: #09F; + text-decoration: none; + font-weight: bold; + cursor: pointer; + padding: 10px 0 5px 0; + font-size: 16px; + } + + .lightwindow_galleries_list li { + margin: 5px 0 5px 0; + list-style-type: none; + } + + .lightwindow_galleries_list a, + .lightwindow_galleries_list a:link, + .lightwindow_galleries_list a:visited { + display: block; + line-height: 22px; + color: #ffffff; + text-decoration: none; + font-weight: bold; + cursor: pointer; + padding: 0 0 0 10px; + font-size: 11px; + } + + .lightwindow_galleries_list a:hover, + .lightwindow_galleries_list a:active { + background: #000000; + color: #ffffbe; + border-left: 3px solid #ffffbe; + padding: 0 0 0 7px; + } + +#lightwindow_data { + /* REQUIRED */ + position: absolute; + /* REQUIRED */ +} + + #lightwindow_data_slide { + /* REQUIRED */ + position: relative; + /* REQUIRED */ + } + + #lightwindow_data_slide_inner { + background-color: #ffffff; + padding: 0 10px 10px 10px; + } + + #lightwindow_data_caption { + padding: 10px 0 0 0; + color: #666666; + line-height: 25px; + background-color: #ffffff; + clear: both; + } + + #lightwindow_navigation_text { + clear: both; + display: block; + line-height: 14px; + color: #666666; + padding: 0 0 0 10px; + background-color: #f0f0f0; + } + + #lightwindow_data_details { + background-color: #f0f0f0; + padding: 0 10px 0 10px; + height: 22px; + } + + #lightwindow_data_author_container { + text-align: right; + color: #666666; + font-style: italic; + font-size: 10px; + line-height: 12px; + float: right; + overflow: hidden; + } + + #lightwindow_data_gallery_container { + font-size: 10px; + width: 40%; + text-align: left; + color: #666666; + line-height: 20px; + float: left; + overflow: hidden; + } + +#lightwindow_title_bar { + height: 25px; + overflow: hidden; +} + + #lightwindow_title_bar_title { + color: #ffffbe; + font-size: 14px; + line-height: 25px; + text-align: left; + float: left; + } + + a#lightwindow_title_bar_close_link, + a:link#lightwindow_title_bar_close_link, + a:visited#lightwindow_title_bar_close_link { + float: right; + text-align: right; + cursor: pointer; + color: #ffffbe; + line-height: 25px; + padding: 0; + margin: 0; + } + + a:hover#lightwindow_title_bar_close_link, + a:active#lightwindow_title_bar_close_link { + color: #ffffff; + } + + a.lightwindow:hover { text-decoration: none; color: #282B64; } + +/*----------------------------------------------------------------------------------------------- + Theme styling stuff +-----------------------------------------------------------------------------------------------*/ + +#lightwindow p { + color: #000000; + padding-right: 10px; +} + + diff --git a/web/css/main.css b/web/css/main.css new file mode 100644 index 0000000..9a7e583 --- /dev/null +++ b/web/css/main.css @@ -0,0 +1,1485 @@ +@CHARSET "UTF-8"; + +ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, body, html, blockquote, fieldset, input, td, dl { + font-family: Verdana, "Lucida sans", sans-serif; + border: none; + margin: 0px; + padding: 0px; + font-size: 8pt; +} + +ul { list-style-type: none; } +li { clear: both; } +img { border: none; } +hr { height: 1px; color: #CCCCCC; } +dd { margin-left: 0px; padding-bottom: 5px; } +big { font-size: 1.3em; } +label { color: #000000; font-weight: bold; } +p { font-size: 8pt; } + +#tag_search_box label { + font-weight: normal; +} + +dl.publicated dt{ + float: left; + padding-right: 5px; +} +dl.publicated dd { + float: left; + padding-right: 20px; +} + +h1 { + font-size:1.3em; + color: #0E8293; + font-weight: bold; + padding: 7px 2px 2px 0px; +} + +h2 { + font-size:1.2em; + color: #0E8293; + padding-top: 5px; +} + +h2.entry-title { + margin-left: 0px; +} + +h3 { + font-size:1.1em; + padding: 10px 0; +} + +h4 { + font-size:1.00em; + color: #0E8293; + margin-top: 2px; + margin-bottom: 0px; +} + +h5 { + font-size:1.00em; + font-weight: bold; +} + +a:link, a:visited { + text-decoration: none; + color: #282b64; + padding: 0px; +} + +a:hover { text-decoration: underline; color: #F58426; } + +p.position_right { margin-top: 5px; width: 100%; text-align: right; } + +.differ, a.differ { color: #F58426; margin-left: 5px; } + +.capitalize { text-transform: capitalize} + +select { + border-width: 1px; + border-color: #A5ACB2; + color: #0E8293; + font-weight: bold; + padding: 2px; +} + +textarea { + border: 1px solid #a5acb2; + color: #0E8293; + font-weight: bold; + width: 375px; + height: 100px; + overflow: auto; +} + +.rightaligned +{ + text-align: right; +} + +h2, select, .inform_msg, #embed_slider, input#message_to, .warning_box li { margin-bottom: 5px; } + +li.bulletlist {list-style-type: disc; } +.entry-content li { + margin-left: 15px; + list-style-type: disc; +} +.grey_text { color: #ccc} +label.normal_text { font-weight: normal; padding: 0px 5px 0px 5px; } + +/* Would rather not do the following but it saved around 500 lines of code so is worth it */ + +.right_buttons, .footer_right_links, .float_right, #newpass_form input[type="submit"], #sidebar, .editmode, +div#format_selection, #tag_indicator, #artwork_right_container, #artwork_rating, ul.star-rating, +#textartwork_rating_and_thumb, .message_header_right, #upload_right_box, +#upload_error, #artwork_magnifier { float: right; } + +.float_left, #artwork_info_header, #navigation_block_wrapper, .artwork_list_image, .list_block_top, .list_block_wrapper, +.artwork_link, .list_block, .list_medium, .list_small, .my_page_block, .list_block_big, .portfolio_block, +.portfolio_header, .image_single_score, .image_list_item, .artwork_lis, div.warning, +.single_list_artwork, #rejection_form, #mypage_left, .mypage_list li, #artwork_main_container, +#artwork_time_and_report, .mediatypebutton, .message_to_row input, .message_to_row span, +#new_lang_item label, .message_header_left, div.admin_linkbar, .searchresult_row img, +#approved_calendar, #content_main, .floatleft, .big_artwork, +.profile_left, .profile_right, .contact_info, #mypage_right, .subreaktor_list_image, +#menu_bar .dropdown_menu_link, #article_editing_container { float: left; } + +.floatright +{ + float: right; +} + +#menu_bar { z-index: 1; } + +#tagresultsortlinks { position: absolute; top: 5px; right: 5px; z-index: 100;} + +#top_block_right li, #avatar_label, .currentTags, #upload_error, .list_block, .relative, +#content_main, #header_block, #menu_bar, #menu_bar .dropdown_menu_link, +#save_file_draft, #artwork_submit, .big_artwork, #latest_block, #popular_block, #recommend_block, .block, +.list_row, .list_block_medium, .list_block_small, .artwork_list, .subreaktor_list, .artwork_list_info, .subreaktor_list_info, +#artwork_main_container, #artwork_actions_and_favourites, #artwork_edit_link, .message_menu, .portfolio_block, +.view_link, .tag_container, #subreaktor_list, .tool_tip_internal, #user_report_block { position: relative; } + +#top_block_right { width: 240px; } +.tag_cloud_header h2 { border-bottom: 1px solid #FFF; padding-bottom: 3px; margin-bottom: 3px; } + +.form_error { color: #d8732f; margin-bottom: 3px; font-weight: bold; font-size: 0.9em; } +.clearleft { clear: left; } +.clearright { clear: right; } +.clearboth { clear: both; } +.clearnone, ul.clearnone li { clear: none; } +.tag-cloud { width: 300px; } +.tag-cloud li { display: inline; } +.short { width: 60%; } +.full_width { width: 100%; } +.overflow { height: 7em; overflow: auto; } +span.navigation, .emphasis { font-weight: bold; } +.profile_left { width: 380px; } +.profile_interest { padding: 2px; } +.contact_info { padding: 5px 10px 0px 0px; } +.extra_padding { padding: 5px 0 5px 15px; } +.indented { margin-top: 5px; margin-left: 100px; } +.admin_link { color: red; } +.box_shape { width: 240px; text-align: center; } +.spacer { width: 10px; } +.mediumindent { margin-left: 14px; } +.smallishindent { margin-left: 10px; } +.category_selected a { color: green; font-weight: bold; } +.smallrightpad { padding-right: 2px; } +.mediumrightpad { padding-right: 9px; } +.goodleftpad { padding-left: 25px; } +.no_heading { margin-top: 25px; } +.pad_for_mini { padding-left: 86px; } +.largeleftpad { padding-left: 15px; } +.sidebar_text { width: 143px; } +.message_header_left { width: 50%; } +.message_menu { padding: 3px; } +.message_header { margin: 3px; } +.message_body { padding: 3px; border: 0px solid #CCCCCC; } +.mypage_list li { width: 171px; } +.message { color: #FF0000; } +.image_single_score { padding-right: 2px; } +.image_list_item { padding-right: 0px; } +.bottom_right { bottom: 2px; } +.top_right { top: 2px; position: absolute; right: 5px; } +.bottom_right_outside{ bottom: -5px; } +.inline { display: inline; } +.bumpup { position: relative; bottom: 10px; } +ul.inline li { display: inline; } +.grey_background { background-color: #F2F2F3 } +.nomargin { margin: 0; } +.hentry { margin-top: 25px; width: 560px; float: left; } +.entry-summary { clear: left; } +.entry-content { clear: both; } +.grey_boarder { border: 1px solid #CCCCCC; padding: 5px; } +.meta_label { color: #0E8293; font-weight: bold; } + +#errormsg { color: #D8732F; font-weight: bold; } +#transcodershell { text-align: left; } + +#exif_block, #footer_block, .clear_fix, #artwork_description, #artwork_tags, + #artwork_copyright, #artwork_info_footer, #artwork_comments, #embed_link, #see_also_block, + .tool_tip_internal, #popular_artworks_block li, .message_menu { clear: both; } + +#article_editing_container { width: 550px; margin-top: 10px; } +.article_edit_area { width: 540px; height: 250px; } +#article_editing_container p.margin_for_mcebox { margin-right: 18px; width: auto;} + +.artwork_list_info { min-height: 65px; margin-left: 85px;} +div.indent_artwork_list { margin-left: 85px; } + +ul.star-rating li, .star-rating-non-interactive li { display: inline; clear: none;} + +/* The following will be ignored by browsers except IE6 */ +* html .artwork_list_draggable_info { + height: 65px; /* Behaves like min-height in IE6 */ +} + +#exif_block { + border: 1px solid blue; + background: #FFFFCC; + padding: 5px; +} + +input[type="submit"], input[type="button"] { + background-color: #FFFFFF; + color: #0E8293; + padding: 0.2em; + font-weight: 400; + border: 0.1em solid #A5ACB2; + font-size: 1em; + margin: 0.2em 0.2em 0em 0em; + width: auto; + cursor: pointer; + z-index: 10; +} + +input[type="file"], input[type="text"], input[type="password"], input#message_to { + height: 22px; + border: 1px solid #A5ACB2; + color: #0E8293; + font-weight: bold; +} + +input#message_to { width: 100px; } +input.cancel, input.draft { font-weight: bold; margin: 2px; } +input.cancel { background-color: red; color: #CCF; } +input.draft { background-color: #CCF; } +input.approve { background-color: #6F6; } +input.alternate { background-color: #FF9; } +input[type="text"], input[type="password"] { width: 375px; margin-bottom: 5px; } + +input[type="text"].medium, div.medium { width: 220px; } +input[type="text"].short { width: 150px; } +input[type="text"].width_shorter { width: 130px; } +input[type="text"].short_input, div.large { width: 250px; } + + +textarea#mce_data { height: 400px; } +textarea#rejectionmsg { width: 700px; height: 250px; } +#upload_right_box { width: 320px; } +#upload_right_box h2 { margin-top: 0px; } + +#upload_error { + border: 1px solid red; + padding: 5px; + width: 98%; +} + +#upload_box { + border: 1px solid #DDDDDD; + padding: 5px; + max-width: 330px; + float: left; +} + +#upload_box ul { + width: 100%; + margin-top: 3px; + text-align: right; +} + +#upload_wrapper { + margin-top: 20px; +} + +#upload_status_box { + margin-top: 15%; + margin-left: 25%; + border: 1px solid #DDDDDD; + padding: 5px; + max-width: 330px; +} + +.currentTags { + font-size: 1.2em; + font-weight: bold; + max-height: 140px; + overflow: auto; +} + +.tags_in_file_list li { display: inline; } +.tags_in_file_list { overflow: hidden; max-height: none; } +.approved_tag, .approved_tag a { color: green; } +.unapproved_tag, .unapproved_tag a, li.orange, a.orange { color: #DC143C; } +.all_tag_actions { position: absolute; bottom: 0px; right: 5px; z-index: 100; font-size: 0.8em; } +img.indent { margin-left: 14px; } + +.tageditor { border: 1px solid #C0C0C0; width: 160px; padding: 10px; margin: 10px 5px 10px 30px; } +.tageditor input[type=text] { width: 140px; margin-top: 10px; } +.tageditor p { font-weight: normal; } + +span.required_star { color: #F55; position: relative; bottom: 3px; padding-left: 5px; } + +.warning_box { + border: 1px solid blue; + padding: 4px; + font-weight: normal; +} + +#artwork_header_block { + display: block; + padding-top: 7px; + padding-bottom: 3px; + border-bottom: 1px solid #DDDDDD; + margin-bottom: 3px; +} + +.comment_header { font-weight: bold; } +.sf_comment { padding-left: 5px; } +.comment_buttons { padding-top: 15px; padding-left: 5px; padding-bottom: 15px; } +.inform_msg { background-color: #FFFFCC; padding: 2px; margin-right: 5px; } + +#interests_box { + background: #F2F2F3; + margin: 200px 5px 5px 20px; + width: 280px; + padding: 0px 0px 5px 10px; +} + +#avatar_edit, #avatar_edit_new, .edit_user_editorialteam { position: absolute; } + +#avatar_edit { margin: 5px 5px 5px 20px; top: 280px; left: 380px; background-color: #FFF; padding: 10px; border: 1px solid #DDD; } +#avatar_edit_new { top: 400px; right: 30px; background-color: #FFF; padding: 10px; border: 1px solid #DDD; } + +.edit_user_editorialteam { margin: 5px 5px 5px 20px; top: 350px; left: 380px; background-color: #FFF; padding: 0px; } + +#information_msg { + margin: 5px 5px 5px 20px; + height: 180px; + padding-top: 15px; + width: 280px; +} + +#footer_menu { + padding: 2px 0px 2px 0px; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; +} + +.footer_left_links { width: 50%; float: left; } + +.footer_left_links a { margin-right: 10px; } + +#my_artwork_link { text-align: right; margin-bottom: 10px; } + +.selected_category, .selected_category a, .selected_category a:visited { color: green; font-weight: bold; } + +.user_image_list { padding-bottom: 40px; height: 183px; } + +#category_tag_list li { + display: inline; + margin-right: 0.5em; + font-size: 1.1em; +} + +.subcategorylist { + background: #F2F2F3 none repeat scroll 0%; + border-bottom: 1px solid #CCCCCC; + margin-bottom: 2px; + padding: 5px 0px 2px 10px; + /*width: 210px;*/ + border-top: 1px solid #CCCCCC; +} + +.rss_hover .subcategorylist { + background-color: #E2E2E3; + border-top: 1px solid #D2D2D3; + border-bottom: 1px solid #D2D2D3; +} + +.subcategorydiv { max-width: 255px; } +.subcategorydiv ul { margin-left: 3px; } +.subcategorylink { text-transform: capitalize; font-size: 1.2em; } + +.related_artwork_tip h3 { + padding: 0px; + margin-left: 3px; + color: #0E8293; +} + +small small, small, big, big big { font-weight: normal; } + +small { font-size: 1.0em; } +big { font-size: 1.3em; } +big big { font-size: 1.4em; } +small small { font-size: 0.9em; } + +#wrapper { + width: 886px; + text-align: left; + margin-left:auto; + margin-right:auto; + padding:0px; + text-align:left; +} + +#sidebar { width: 155px; z-index: 0; } +div.message_wrapper { width: 153px; } +#sidebar input { max-width: 145px; } + +#tag, #sf_admin_container, #sf_admin_content, #uploadanothercheck, +.artwork_list, .subreaktor_list, #message_subject_holder, div.auto_complete ul, .metadata_table textarea { width: 100%; } + +#tag_search_box { width: auto; padding: 5px; margin-top: 5px; } +#tag_search_box span { font-size: 0.8em; color: #999; } +#sidebar h3 { padding: 0px; margin-bottom: 5px; } +#user_summary { width: auto; background-color: #D0E2E4; padding: 5px; } +#user_summary.admin_summary ul li { padding-bottom: 2px; } +#user_summary.admin_summary h2 { margin: 0px; margin-bottom: 8px; } +#send_in a:hover, #internal_articles a:hover { color: #282B64; text-decoration: underline; } +#send_in h3 { margin-bottom: 5px; margin-top: 5px; padding: 2px 0px 0px 0px; } +#header_image { position: absolute; bottom: 5px; } +div#font_selector_block a:hover { text-decoration: none; } +#upload_loading_room { margin: 50px; } +#avatar_loading_room { margin: 15px; } +#newimage, #newimagebutton { margin-top: 3px; } + + +#send_in, #internal_articles { background-color: #F58426; padding: 5px; } +#internal_articles a { font-weight: bold; } + +#send_in { + color: #FFFFFF; + /*min-height: 120px;*/ + margin-top: 5px; + padding-bottom: 10px; +} + +#content_main { + width: 726px; + background-color: white; + z-index: 0; +} + +#header_block { + height: 80px; + background-image: url("/images/bgheading.gif"); + background-repeat: no-repeat; +} + +#font_selector_block { + position:absolute; + bottom: 5px; + right: 0px; + width: 50px; + vertical-align: bottom; +} + +#font_selector_block li { display: inline; } + +li.font_size_normal a { font-size: 10pt; } +li.font_size_large a { font-size: 12pt; } +li.font_size_largest a { font-size: 14pt; } + +#font_selector_block a { + display: block; + position: absolute; + width: 15px; + height: 20px; + background: transparent url(/images/fontselector_all.gif) no-repeat; +} + +a#font_size_normal { left: 0px; bottom: 0px;} +a#font_size_larger { left: 10px; bottom: 0px; background-position: -10px 0px; } +a#font_size_largest { left: 20px; bottom: 0px; background-position: -20px 0px;} + +a#font_size_normal:hover { background-position: 0px -19px;} +a#font_size_larger:hover { background-position: -10px -19px; } +a#font_size_largest:hover { background-position: -20px -19px;} + +#footer_block, .padding_top { padding-top: 10px; } + +#menu_bar { + background-color: #F2F2F3; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; + height: 20px; + padding-left: 5px; +} + +#menu_bar .selected { color: #F58426; } + +#menu_bar #lokalreaktor_link { + position: absolute; + top: 0px; + left: 730px; +} + +#menu_bar .dropdown_menu_link { margin-right: 16px; } + +#menu_bar .dropdown_menu { + position: absolute; + z-index: 10; + background-color: #F2F2F3; + border-bottom: 1px solid #CCCCCC; + border-top: 3px solid #F2F2F3; + font-size: 1.2em; + margin: 0px 0px 0px -5px; + padding-top: 3px; +} + +.dropdown_menu li { + border-left: 1px solid #CCC; + border-right: 1px solid #CCC; +} + +a.dropdown_menu_link_container#first { padding: 5px; } +#menu_bar .dropdown_menu_link { padding-bottom: 0px; } + +.dropdown_menu_link .wide { width: 250px; } +.dropdown_menu_link .normal { width: 150px; } +.dropdown_menu_link .narrow { width: 120px; } +.dropdown_menu ul li { padding: 5px; } + +#menu_bar a { font-size: 12px; border-bottom: 4px solid #F2F2F3; } +#menu_bar a:hover { font-size: 12px; text-decoration: none; } + +#sf_guard_auth_title { + text-transform: capitalize; + font-size: 13px; + font-weight: bold; +} + +#error404 { + font-size: 12pt; + border: 1px solid red; + text-align: center; + padding: 40px; + margin-top: 30px; +} + +.sf_admin_filters { width: 500px; } +.sf_admin_actions { width: auto; text-align: left; } + +#thumbnail_editpage { + width: 250px; + float: right; + margin: 10px 20px 10px 5px; +} + +#thumbnail_editpage.leaveagap { margin: 250px 20px 10px 5px; /* Placeholder for inline upload */ } + +#inline_upload { + position: absolute; + top: 10px; + right: 29px; +} + +#editpage_form textarea { height: 130px; } +#editpage_form select { font-size: 8pt; } + +#new_file_save { + border: 1px solid #C0C0C0; + padding: 5px 5px 0px 5px; + margin-bottom: 1px; + clear: both; + width: 720px; +} + +#save_file_draft { + border: 1px solid #C0C0C0; + padding: 10px 5px; + margin-bottom: 1px; + clear: both; + width: 720px; +} + +#save_file_edit { + border: 1px solid #C0C0C0; + padding: 10px 5px; + margin-bottom: 1px; + clear: both; + width: 720px; +} + +#artwork_submit { + margin-top: 7px; + padding: 5px; + border: 1px solid #C0C0C0; +} + +#link_file_save { + border: 1px solid #C0C0C0; + padding: 10px 5px; + width: 720px; + margin-bottom: 2px; +} + +.artwork_select { + text-align: right; + margin-bottom: 0px; + margin-top: 5px; +} + +.tag-cloud-right { width: auto; } +.tag-cloud-right li { display: inline; } + + +#uploadanothercheck { + text-align: right; + margin-bottom: 5px; + margin-right: 2px; +} + +.editmode { padding-right: 5px; font-weight: bold; } + +.bottom_line { + height: 1px; + background-color: #CCCCCC; + border: 0px; + margin: 0px; +} + +.big_artwork { padding: 0px 1px 15px; max-width: 240px; min-height: 130px; } +.artwork_link { padding: 0px 0px 0px 2px; max-width: 238px; } +.artwork_link a { color: #282B64; text-decoration: underline; } + +#latest_block, #popular_block, #recommend_block, +.block, .list_row, .list_block_medium, .list_block_small { min-height: 66px; } + +#latest_block, #popular_block, #recommend_block {width: 240px; } + +#home_top_row { min-height: 66px; width: 100%; } + +.score { + position:absolute; + right: 2px; + top: 12px; +} + +#lang_bar a.selected { font-weight: bold; } + +.list_block_wrapper { + width: 484px; +} + +.month_link { list-style-type: none; } +.month_links li, .month_links h2 { display: inline; } +.artwork_list_image { margin-bottom: 3px; } +.subreaktor_list_image { margin-bottom: 3px; margin-right: 10px; height: 60px; padding-top: 20px; } + +.list_block_top { + width: 240px; + height: 120px; + margin: 20px 0px -20px 0px; +} + +.list_block, .list_block_medium, .list_block_small, .my_page_block, .list_block_big, .portfolio_block { padding: 5px 0px 5px 0px; float: left; } + +.my_page_image_list, .my_page_image_listing { height: 65px; } +ul.my_page_image_list li, ul.my_page_image_listing li { display: inline; } +.my_page_image_listing .mediumrightpad { padding: 0px; } +ul.my_page_image_listing li { padding: 0px; margin: -1px; } + +#artwork_rating_print { display: none; } + +.list_block, .my_page_block, .list_block_big { width: 240px; position: relative; } +.list_block_medium, .portfolio_block { width: 180px; } +.list_block_small { width: 120px; } + +#showuserlist { padding-right: 5px; text-align: right; } + +#user_info_portfolio { + width: auto; + background-color: #D0E2E4; + padding: 5px; +} + +.portfolio_header { + width: 675px; + background-color: #D0E2E4; + font-size: 14px; + margin: 26px 0px 5px 0px; + font-weight: bold; + padding: 3px; +} + +.portfolio_header_wrapper { + width: 731px; + margin: 0px; + padding: 0px; + height: 105px; +} + +div#format_selection { padding: 3px; } + +.status_in { + font-size: 10px; + color: red; + font-weight: normal; + } + +.status_out { + font-size: 10px; + color: red; + font-weight: normal; + } + +.element_header { + width: 240px; + height: 25px; + padding-bottom: 0px; + } + +.tag_block { + width: 220px; + background-color: #F2F2F3; + border-bottom: solid 1px #FFFFFF; + margin-top: 1px; + padding: 10px; + padding-top: 3px; + min-height: 125px; + font-size: 0.95em; +} + +.colored_article_container, .colored_article_container ul { margin-top: 5px; } +.colored_article_container { background-color: #F2F2F3; padding: 5px; position: relative; } + + +/* The following will be ignored by browsers except IE6 */ +* html .tag_block { + height: 125px; /* Behaves like min-height in IE6 */ +} + +.article_summary_block { + background-color: #F2F2F3; + width: 220px; +/* height: 145px;*/ + padding: 10px; +} + +.big_thumbnail, h2.cal_comm_hdr { padding-bottom: 4px; } + +ul.artwork_list, ul.subreaktor_list { border-bottom: 1px solid #CCCCCC; padding-top: 5px; height: 110px; } +li.artwork_list, li.subreaktor_list { clear: both;} + +ul#artwork_list li, ul#subreaktor_list li { position: relative; padding: 5px 0px; margin: 0px; } +ul#artwork_list li.evenrow, ul#subreaktor_list li.evenrow { background-color: #F2F2F3; } + +ul.artwork_list_info, ul.subreaktor_list_info { padding-left: 10px; width:600px; } + +.artwork_list_info li, .subreaktor_list_info li { clear: none; padding: 1px 0px; margin: 0px; } +/*.artwork_list_info ul { margin: 4px 0px 0px 83px; max-width: 480px; }*/ +.subreaktor_list_info span { margin-left: 5px; } +.artwork_list_info span strong { font-size: 1.2em; } +.file_list strong { font-size: 1.2em; } +.filerow { border-bottom: 1px solid #DDD; } + +.artwork_list_links, .subreaktor_list_buttons { width: 100%; text-align: right; } +.subreaktor_list_buttons { border-bottom: 1px solid #DDD; padding-bottom: 5px; } + +.artwork_tag_block { + background-color: #F2F2F3; + padding: 6px; + padding-top: 3px; + min-height: 125px; + font-size: 0.95em; +} + +.moderator_block, .admin_message, .user_warning { + border: 1px solid #EE0000; + margin-top: 10px; + padding: 6px; +} + +.moderator_block h2, .moderator_block a, .moderator_block h4, .moderator_block li, .admin_message, +.admin_message h4, .user_warning h3 { color: #EE0000; } + +.moderator_block form { + background-color: #F2F2F3; + padding: 2px; + margin-top: 1em; +} + + +/* The following will be ignored by browesers except IE6 */ +* html .artwork_tag_block { + width: 200px; + height: 125px; /* Behaves like min-height in IE6 */ +} + +.comment0 { padding-top: 5px; background-color: #FFFFFF; } +.comment1 { padding-top: 5px; background-color: #F2F2F3; } + +.comment1 a, .comment a, .adminbutton a, .green { color: #0E8293; } + +.commentbutton { + background-color: #FFFFFF; + border: 1px solid #AAAAAA; + padding: 3px; + display: inline; +} + +.commentbutton:hover { text-decoration: none; } + +.adminbutton { + background-color: #FFFFFF; + border: 1px solid #AAAAAA; + padding: 3px; + display: inline; + margin-right: 2px; + color: #0E8293; +} + +.adminbutton:hover a { + color: #0E8293; + text-decoration: none; + cursor: default; +} + +#calendar { + border-left: 1px solid #A2ADBC; + text-align: center; + line-height:20px; +} + +caption { + height: 20px; + background: #D0E2E4; + color: #0E8293; + text-align: center; + font-weight: bold; +} + +.cal_hdr { + color: #0E8293; + background: #F2F2F3; + border-right: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; + border-top: 1px solid #CCCCCC; +} + +.today, td.today a, td.today a:link, td.today a:visited { + color: #282B64; + font-weight: bold; + background: #F58426; +} + +td.day a:link { font-weight:bold; } + +.day { + border-right: 1px solid #A2ADBC; + border-bottom: 1px solid #A2ADBC; + width: 40px; + height: 20px; + text-align: center; +} + +td.day a:hover, td.day a:active { text-decoration: underline; } + +div.auto_complete { + width: 350px; + background: #C0C0C0; + z-index: 100; +} + +div.auto_complete ul { + margin: 0px; + padding: 0px; + list-style-type: none; + border: 1px solid #BBBBBB; +} + +div.auto_complete ul li { + margin: 0px; + padding: 3px; + border-bottom: 1px solid #EEEEEE; + list-style-type: none; +} + +div.auto_complete ul li.selected { background-color: #FFFFBB; } + +div.auto_complete ul strong.highlight { + margin: 0px; + padding: 0px; + color: #880000; +} + +div.warning { border: 1px solid #EE0000; width: 720px; } + + +.single_list_artwork { + width: 720px; + padding-top: 20px; + padding-bottom: 20px; +} + +div#rejection_form { padding-top: 20px; } +#email_indicator { padding: 25px; } +#mypage_left { width: 483px; } +#mypage_right { width: 225px; padding-left: 10px; } + +.top_box_grey { background-color: #F2F2F3; height: 11em; } + +.new_comment_header { + background-color: #F2F2F3; + border-top: 1px solid #CCC; + border-bottom: 1px solid #CCC; + padding-bottom: 2px; + margin-bottom: 5px; +} + +#artwork_main_container { width: 520px; margin-top: 1em; } +#artwork_main_container.short_top_margin { margin-top: 1em; } +#artwork_right_container { width: 200px; margin-top: 2.5em; } +#artwork_right_container.short_top_margin { margin-top: 1em; } +#artwork_right_container input { max-width: 150px; } +#artwork_time_and_report { padding: 5px; } +#artwork_description, #artwork_tags { margin-top: 5px; padding-left: 5px; } +#artwork_copyright { margin-top: 10px; padding-left: 5px; } +#artwork_info_footer { min-height: 4.0em; } +#artwork_div, #artwork_div img { max-width: 520px; clear: both; } +#artwork_magnifier, #magnify_div { margin-top: 0.2em; } + +.short_top_margin { margin-top: 1em; } + +#magnify_div p { margin: 0px; text-align: right; } + +#artwork_rating { + padding-top: 2px; + margin-left: 5px; + width: 172px; +} + +#artwork_magnifier, #artwork_info_header { font-size: 1.2em; } + +#artwork_info_header h2 { + display: inline; + margin: 0px; + padding: 0px; +} + +#artwork_actions_and_favourites { + margin-top: 10px; + background-color: #F2F2F3; + padding: 6px; +} + +#artwork_edit_link { + margin-top: 10px; + background-color: #F2F2F3; + padding: 6px; +} + +#artwork_actions_and_favourites #fav_loading { + position: absolute; + right: 0px; + bottom: 0px; +} + +.message_summary #msg_loading { + position: absolute; + right: 0px; + bottom: 0px; +} + +#artwork_actions_and_favourites .list_bottom { margin-bottom: 10px; } + +#artwork_comments { margin-top: 10px; } +#embed_link { padding-left: 5px; } +div#embed_link input { width: 510px; margin-top: 5px; } +#artwork_comments h4 { background-color: #F2F2F3; padding: 5px; } + +.comment_header_total { + background-color: #F2F2F3; + padding: 5px; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; +} + +#ignored_users_list ul { + margin: 0px; + padding: 0px; + list-style-type: none; +} + +#min_count { + width: 50px; + margin-left: 10px; + margin-right: 10px; +} + +.messages_grey { color: #AAAAAA; display: inline; } +.view_link { top: 12px; right: 60px; } + +#file_list h2 { margin-top: 15px; } +#portifoliopage { width: 715px; } +.tag_container { display: inline; } +.currentTags li { margin: 3px 5px; } +.tags_in_file_list li { display: inline; } +.tags_in_file_list ul { margin-left: 10px; } +.tags_in_file_list { margin-top: 0px; } + +.longer { + overflow: hidden; + max-height: none; + max-width: 400px; +} +div.longer .all_tag_actions { top: 0px; } + +#artwork_files p { margin: 5px 0px; } + + #tag_key { + position: absolute; + right: 40px; + top: 20px; + border: solid 1px #C0C0C0; + max-width: 300px; + padding: 10px; + font-weight: normal; +} + +#tag_key li { margin-bottom: 5px; } + +.list_bottom a { font-weight: bold; } + +#cat_indicator { + position: absolute; + top: 2px; + right: 5px; +} + +#textartwork_wrapper h3, #textartwork_wrapper h3, #textartwork_wrapper h2, #textartwork_wrapper ol li +div#textartwork_wrapper h1, #textartwork_wrapper h4, #textartwork_wrapper ul li { color: #000000; } + +div#textartwork_wrapper h1 { font-size: 16px; } +#textartwork_wrapper h2 { font-size: 14px; } +#textartwork_wrapper h3 { font-size: 12px; } +#textartwork_wrapper h4 { font-size: 10px; } +#textartwork_wrapper ul li { list-style: circle inside; } +#textartwork_wrapper ol li { list-style: decimal inside; } + +div#textartwork_wrapper { margin-left: 5px; } + +#artwork_thumbnail_text, #textartwork_rating_and_thumb { width: 250px; } + +.mediatypebutton { + background-color: #FFFFFF; + border: 1px solid #CCCCCC; + padding: 3px; +} + +.text_audio_subreaktor_rating_list, .artwork_list_with_tags { + width: 230px; + background-color: #F2F2F3; + border-top: 1px solid #CCCCCC; + border-bottom: 1px solid #CCCCCC; + margin-bottom: 3px; + margin-right: 10px; +} + +#see_also_block { padding-bottom: 5px; } +#relate_artwork_see_also { margin-top: 15px; padding-left: 5px; } +#related_artwork_imagelist { margin-top: 3px; } +#relate_artwork_select { margin-bottom: 0px; } +#revision_info { width: 400px; } +#lang_bar { position: absolute; right: 0px; top: 5px; } +#message_subject_holder { padding-top: 15px; } +#new_lang_item label { width: 17%; } +#new_lang_item .form_error { margin-left: 17%; } + +.tool_tip_internal { padding: 7px; } +.message_wrapper { margin: 5px 0px 5px 0px; border: 1px solid #CCCCCC;} +.send_message { padding: 5px; } +.send_message textarea { width: 143px; } +.message_to_row input { margin-top: 5px; width: 103px; } +.message_to_row span { margin: 5px 5px 0px 0px; width: 35px; } +.messages_info { color: #808080; font-size: 0.8em; } + +.admin_linkbar { + background-color: #F58426; + color: #FFFFFF; + min-height: 1.5em; + font-size: 1.1em; + margin-bottom: 2px; +} + +div.admin_linkbar { padding: 5px; width: 350px; } +.admin_linkbar div a { font-size: 1.05em; font-weight: bold; } +.admin_linkbar a:hover { color: #282B64; text-decoration: underline; } + +.metadata_table thead td { + font-weight: bold; + background-color: #F58426; + color: #FFFFFF; + border: 1px solid #F58426; +} + +.metadata_table td { border: 1px solid #DDDDDD; padding: 1px; } +.metadata_table td.actions { text-align: center; } +.searchresult_row img { margin-right: 5px; } +.searchresult_row .taglist { margin-top: 10px; } +.editorialteamlist li { font-size: 1em; } + +h4.artwork_list_header, h4.subreaktor_list_header { margin-bottom: 5px; } +ul.months, ul.months ul { margin-left: 10px; font-weight: normal; } +.selected { font-weight: bold; } + +.metadata_table textarea { + font-size: 1.1em; + font-family: "Courier new", monospace; + font-weight: normal; + height: 40px; + color: #000000; +} + +.searchresult_row { + border-bottom: 1px solid #DDDDDD; + height: 70px; + margin-bottom: 5px; +} + +#lightwindow_contents { line-height: 1.45em; text-align: left; } + +#approved_calendar, #article_calendar_container, #editorial_team_container, #content_manager_sidebar { + background-color: #F2F2F3; + padding: 5px; + margin-top: 10px; + width: 150px; + height: 600px; +} + +#approved_calendar { border-left: 1px solid #CCC; } +.withstripe { border-right: 1px solid #CCC; } +#content_manager_sidebar h1 { padding: 0px; padding-bottom: 5px;} +#my_content { margin-top: 10px; } +#content_manager_sidebar h2 { font-size: 8pt; margin: 0px; } + +.approved_main { + float: right; + margin-top: 10px; + margin-right: 10px; + width: 545px; +} + +.bottom_right, .bottom_right_outside { position: absolute; right: 5px; text-align: right; bottom: -5px; } + +.rss_link_top_left, .rss_link_top_right { top: 5px; position: absolute; z-index: 10; } +.rss_link_top_right { right: 5px; } +.rss_link_top_left { left: -20px; } +.rss_hover { background-color: #FFFFAA; } + +.rss_list { margin-top: 10px; } +.rss_list a { padding-left: 22px; } + +.rss_list li { + color: red; + padding: 0pt 4px 6px 0px; + background: transparent url("/images/RSSfeed.png") no-repeat scroll 0pt 0pt; + font-size: 1.2em; +} + +#socialBookmarks { border: 1px solid #C0C0C0; padding: 0px 5px 10px 5px; margin-top: 10px; min-height: 5.0em; } +#socialBookmarks li { display: inline; padding: 0pt 10px 6px 2px; text-align: center; } +#socialBookmarks li.delicious { background: transparent url(/images/delicious.gif) no-repeat scroll 0pt 0pt; } +#socialBookmarks li.digg { background: transparent url(/images/digg.gif) no-repeat scroll 0pt 0pt; } +#socialBookmarks li.reddit { background: transparent url(/images/reddit.gif) no-repeat scroll 0pt 0pt; } +#socialBookmarks li.facebook { background: transparent url(/images/facebook.gif) no-repeat scroll 0pt 0pt; } +#socialBookmarks li.stumbleupon { background: transparent url(/images/stumbleupon.gif) no-repeat scroll 0pt 0pt; } +#socialBookmarks li.nettby { background: transparent url(/images/nettby.png) no-repeat scroll 0pt 0pt; } +#socialBookmarks li.print { background: transparent url(/images/print_printer.png) no-repeat scroll 0pt 0pt; } +#socialBookmarks ul { padding: 15px 0px 0px 10px; } +#socialBookmarks a { padding-left: 18px; } + +div.report_graph { + width:420px; + height:220px; + position: relative; + vertical-align: bottom; + clear: both; +} + +li.report_bar { + width:65px; + border: 1px solid black; + background: #808080; + vertical-align:bottom; + text-align: center; + float: left; + position:absolute; + bottom:0pt; +} + +.results_block { min-height: 450px; } + +.favourite_user_portfolio { float: left; margin-left: 30px; } + +#startDate_day, #startDate_month, #startDate_year, + #endDate_day, #endDate_month, #endDate_year { display: inline } + +#savedReportsBox { + width: 250px; + background-color: #F2F2F3; + border: 1px solid #CCC; + padding: 5px; + margin-top: 10px; +} + +#query_show_hide { margin-right: 10px; float: right; position: absolute; right: 0px; top:0px;} +#savedReportsBox { margin-right: 10px; float: right; position: absolute; right: 0px; top: 15px;} + +#query_generator { padding-bottom: 5px; width: 450px;} +#query_generator form div { float: left; width: 210px; } +#query_generator form div.full_width { width: 100%; } +#query_generator label { margin-right: 10px; width: 150px; } +#query_generator input { margin-right: 5px; max-width: 255px;} +#query_show_hide { clear: right; margin-top: 5px; } +#query_results li { font-size: 1.2em; margin-bottom: 3px; } +#report_save_box input { max-width: 250px; } +#report_save_box textarea { width: 248px; height: auto; } +#report_save_box label { display: block; } +#show_bookmarks ul { width: 90%; margin-left: 15px; } +#show_bookmarks li { padding: 5px; min-height: 80px; height: 80px; } +#show_bookmarks h3 { margin: 0px 0px 0px -7px; padding: 0px 0px 2px 0px; font-size: 1.1em; font-weight: normal; color: #444; } +#show_bookmarks p { width: 75%; } + +.article_container, .article_type_list_selected { margin-bottom: 10px; margin-top: 10px; } +.article_result_row { border-bottom: 1px solid #DDD; padding: 5px 0px 10px 20px; } +ul.article_list_full li { margin-bottom: 10px; } +ul.article_list_footer { list-style-type: none; } +ul.article_list_footer li { display: inline; margin-right: 10px; } +.foreignfeed_normal { margin-bottom: 10px; margin-top: 10px; } +.foreignfeed_article { margin-bottom: 10px; margin-top: 10px; } +ul.foreignfeed_list li { margin-top: 7px; margin-bottom: 7px; } + +.draft {color: orange; } +.approved {color: green; } +.rejected {color: red; } + +.message h2, .message h3, .message h4 { margin: 0px; padding: 0px; color: #222; display: inline; } +.message p { margin-bottom: 5px; margin-top: 5px; } +div.status_draft { border: 1px solid #BBB; padding: 4px; } +.status_draft, h2.status_draft { background-color: #F1F1F1; color: #555; } +div.status_submitted { border: 1px solid orange; padding: 4px; } +.status_submitted, h2.status_submitted { background-color: #FFF9D1; color: #888541; } +div.status_approved { border: 1px solid green; padding: 4px; } +.status_approved, h2.status_approved { background-color: #CEC; color: green; } +div.status_rejected { border: 1px solid red; padding: 4px; } +.status_rejected, h2.status_rejected { background-color: #FDD; color: red; } + +div.status_approved {border: 1px solid green; } +div.status_rejected {border: 1px solid red; } + +#user_artwork_list h1, #user_artwork_list h2 { display: inline; } +#user_artwork_list { margin-top: 5px; } +#user_artwork_list li { position: relative; cursor: move; } +#artwork_collection_files { + border: 1px solid #DDD; + height: 100%; + padding: 5px; + background: #FFC; +} + +#artwork_eligible_files { + border: 1px solid #999; + height: 100%; + padding: 5px; + background: #DDD; + margin-top: 5px; +} + +#composite_file_list { margin-top: 20px; } +#composite_file_list ul { margin-top: 10px; margin-bottom: 10px; padding-bottom: 5px; padding-top: 5px; border-top: 1px solid #DDD; } +#composite_file_list ul li { position: relative; border-bottom: 1px solid #DDD; padding-bottom: 7px; } + +#editarticlecontents label { display: block; margin-bottom: 3px;} + +#my_content li { } +.inline_tag_list, .inline_tag_list ul { display: inline; } + +ul.indentli li { margin-left: 15px; } + +#my_content { width: 550px; float: right; } + +#artworkslist div.artwork_list_item { + margin: 5px; + padding: 5px; +} +#artworkslist li { + float: left; + clear: none; +} + +.transcoder_panel { + width:500px; + max-height: 500px; + overflow: auto; + background: #FFF; + padding: 5px 0px; +} + +/* The following will be ignored by browsers except IE6 */ +* html .transcoder_panel { + max-height: 500px; /* Behaves like min-height in IE6 */ +} + +ul.group_permissions_list_tip li.check { list-style: url('/images/tick.png') circle inside; } + +.attachment_message { + border: 1px solid #DDD; + width: 70%; + margin-bottom: 5px; + padding: 5px; +} + +li.tip_item label { cursor: pointer; } + +select#new_editorialteam { max-width: 182px; } + +form.composite_add_form { display: inline; } + +#sidebar_no_artworks { margin-top: 30px; border: 1px solid #CCC; padding: 3px; text-align: center; } + +.menu_separator { border-top: 1px solid #BBBBBB; height: 1px; } + +#meta_list p { margin-top: 2px; padding-left: 8px; padding-bottom: 5px; padding-right: 5px; } +#meta_list h4 { margin: 3px; } +#meta_list h2 { margin-bottom: 8px; } +#meta_list br { margin-bottom: 5px; } +#meta_list p br { margin-bottom: 0px; } +#meta_list { padding-left: 5px; padding-bottom: 5px; } + +.message_box { background-color: #FFFACD; color: #4B0082; border: 1px solid #C0C0C0; padding: 2px 5px 5px 10px; margin-top: 5px; } +.language_label { float:left; margin-left: 20px; font-weight:normal; width: 15%; } + +#sidebar_articles { + margin: 2px; + color: #282B64; +} +#sidebar_articles ul.article_list_full li { + padding: 5px; + margin-top: 1px; + margin-bottom: 1px; + background-color: #F2F2F3; +} + +.page_box { + border: 1px solid #CCC; + margin: 30px 0px 0px 30px; + width: 70%; + padding: 5px 5px 5px 10px; + background: #D0E2E4; +} + +#unsupportedbrowserbanner { margin-bottom: 10px; padding: 5px; background-color: #EEE; color: #555; border: 1px solid #CCC; border-top: 0px; } + + +.adminbuttons { + padding: 10px 0; + clear:both; +} + +.fakebutton_disabled { + background-color: #DDDDDD; + border: 1px solid #AAAAAA; + padding: 3px; + display: inline; + margin-right: 2px; + color: #AAAAAA; +} + +.fakebutton_disabled a:link, .fakebutton_disabled a:visited, .fakebutton_disabled a:hover { + cursor: default; + color: #999999; + text-decoration: none; +} + +.fakebutton { + background-color: #FFFFFF; + border: 1px solid #AAAAAA; + padding: 3px; + display: inline; + margin-right: 2px; + color: #0E8293; +} + +.fakebutton a:link, .fakebutton a:visited, .fakebutton a:hover { + cursor: pointer; + color: #0E8293; + text-decoration: none; +} + +.small_text { font-size: 0.8em; } +.faded_text, #footer_images p a { color: #CCC; } +.updated, .published { text-transform: lowercase; } +.nostripe { border-right: 0px; } + +.portfolio_header #artwork_actions_and_favourites_js { + font-size: 0.8em; + font-weight: normal; +} + +#recommend_artwork_form { background-color: #FFF; } + +.linkpointer { cursor: pointer; } +.topborder { border-top: 1px solid #DDD; } +.bottomborder { border-bottom: 1px solid #DDD; } +.smallborder { border: 1px solid #DDD; } +.padbottom { margin-bottom: 10px; padding-bottom: 5px; } + +#recaptca_text { + position: absolute; + top: 585px; + left: 387px; + width: 300px; +} + +#relate_artwork_tag input[type=text] { width: 430px; } + +#artwork_description { display: block; width: 400px; } + +.editor_field { width: 400px; height: 60px; } + +.artwork_nav_links { position: relative; height: 20px; } +.artwork_nav_links div { position: absolute; bottom: 5px; } +.artwork_nav_links div.left { left: 2px; } +.artwork_nav_links div.right { right: 2px; } + +#artwork_list div.admin_message { border: none; padding: 0px; margin: 0px; } +div.history_list { min-width: 220px; } +div#artwork_editorialteam_tag h4 { margin-bottom: 5px; } + + +ul#moderator_main_links {border: 1px solid #C0C0C0; margin: 7px 0px 10px 0px; padding-top: 0px;} +ul#moderator_main_links li {padding: 3px 0px 5px 25px; font-weight: bold;} +ul#moderator_main_links li.approve_artwork {background: transparent url(/images/accept.png) no-repeat scroll 0.2em;} +ul#moderator_main_links li.reject {background: transparent url(/images/cancel.png) no-repeat scroll 0.2em;} +ul#moderator_main_links li.mark_discussion {background: transparent url(/images/user_comment.png) no-repeat scroll 0.2em;} + +#portfolio_image_list { position: relative; } + +.editablearticle { margin-left: 5px; } + +.file_warning { + font-size: 8pt; +} + +.upload_box_text_wrapper{ + margin-top: 50px; +} + +.upload_box_text { + float: left; + border: 1px solid #ddd; + width: 340px; + padding-left: 3px; + height: 100px; + margin-right: 5px; +} + +.big_gray_upload { +float:left; +font-size:4em; +color: #aaa; +width: 50px; +} + +#artwork_reportunsuitable { margin-top: 15px; } + +.admin_message_tiny { + border: 1px solid red; +} diff --git a/web/css/print.css b/web/css/print.css new file mode 100644 index 0000000..d7cc204 --- /dev/null +++ b/web/css/print.css @@ -0,0 +1,96 @@ +@CHARSET "UTF-8"; + +#content_main +{ + width: 880px; +} + +#artwork_main_container +{ + width: 670px; +} + +#artwork_div, #artwork_div img +{ + max-width: 670px; + +} + +#menu_bar, #lang_bar, #font_selector_block, #sidebar, #artwork_actions_and_favourites, +#embed_links, #socialBookmarks, #lightwindow, #lightwindow_overlay, +#artwork_favourite_links_container, #artwork_reportunsuitable, #artwork_rating, #footer_menu +{ + display: none; +} + +#footer_images +{ + border-bottom: 0px solid #000; +} + +#artwork_rating_print +{ + display: block; + padding-top: 5px; + width: 90px; + float: right; +} + +#header_block +{ + border-bottom: 1px dotted #ccc; + padding-bottom: 0px; + height: 80px; + margin-bottom: 5px; + width: 720px; + +} + +#artwork_comments +{ + page-break-before: always; + width: 880px; +} + +.comment_buttons +{ + border-bottom: 1px dotted #CCCCCC; + height: 1px; + padding: 0px; +} + + +.comment_buttons input, .commentbutton +{ + display: none; +} + +.comment_header_total +{ + border-bottom: 2px dotted #CCCCCC; + border-top: 2px dotted #CCCCCC; +} + +h4 +{ + margin-top: 8px; +} + +#header_image +{ + bottom: 10px; +} + +#artwork_info_header h2 +{ + font-size: 1.5em; +} + +body +{ + font-size: 10pt; +} + +.portfolio_image_list { + width: 720px; + } diff --git a/web/css/sf_comment.css b/web/css/sf_comment.css new file mode 100644 index 0000000..f7e065f --- /dev/null +++ b/web/css/sf_comment.css @@ -0,0 +1,73 @@ +.sf_comment_form div { +margin: 0 0 10px 0; +} + +.sf_comment_form fieldset { +padding: 0; +} + +.sf_comment_form label { +margin: 0; +padding: 0; +display: block; +} + +/* +.sf_comment_form input, .sf_comment_form textarea { +padding: 1px 0 1px 10px; +min-width: 30em; +}*/ + +.sf_comment_form textarea { +height: 10em; +} + +.sf_comment_form .form_error { +color: red; +font-weight: bold; +} + +/* +.sf_comment_form input.submit { +color: #666; +width: auto; +border: 1px #666 solid; +height: 2.2em; +margin: 0 0 2em 0; +padding: 0 5px; +font-size: 1em; +min-width: 0; +background: none; +background-color: #ececec; +} + + +.sf_comment_form input.submit:hover { +color: #ececec; +border: 1px #ececec solid; +background-color: #666; +} +*/ + +.sf_comment_form_error { +color: red; +font-weight: bold; +} + +#sf_comment_ajax_indicator { +width: 20px; +height: 20px; +margin: 0; +padding: 0; +background: transparent url(../images/indicator.gif) top left no-repeat; +} + +#all_sf_comments_list +{ + clear: both; +} + +.sf_comment_list ul{ +margin-left: 0; +} + diff --git a/web/css/sf_rating.css b/web/css/sf_rating.css new file mode 100644 index 0000000..2d7ee30 --- /dev/null +++ b/web/css/sf_rating.css @@ -0,0 +1,150 @@ +/** + * Based on http://komodomedia.com/blog/samples/star_rating/example2.htm + * Styles for the star rater + */ +table.rating_details_table td.sf_rating_bar_bg { + background: #ADD8E6; +} + +table.rating_details_table div { + background: blue; +} + +.star-rating, .star-rating-non-interactive { + list-style: none; + margin: 0; + padding: 0; + height: 25px; + position:relative; + overflow:hidden; +} + +.star-rating { + background: url(../images/alt_star.gif) top left repeat-x; + float: left; + width: 20px; +} +.star-rating-non-interactive { + float: right; + width: 120px; +} +.star-rating, .star-rating-non-interactive { + padding: 0; + margin: 0; + height: 20px; +} +.star-rating-non-interactive li { + padding: 1px; +} +.star-rating li a{ + display: block; + width: 20px; + height: 25px; + line-height: 25px; + text-decoration: none; + text-indent: -9000px; + z-index: 20; + position: absolute; + padding: 0; + overflow: hidden; +} +.star-rating li a:hover{ + background: url(../images/alt_star.gif) left bottom; + z-index: 2; + left: 0; + border:none; +} +.star-rating a.r1star{ + left: 0; +} +.star-rating a.r1star:hover{ + width:20px; +} +.star-rating a.r2stars{ + left:20px; +} +.star-rating a.r2stars:hover{ + width: 40px; +} +.star-rating a.r3stars{ + left: 40px; +} +.star-rating a.r3stars:hover{ + width: 60px; +} +.star-rating a.r4stars{ + left: 60px; +} +.star-rating a.r4stars:hover{ + width: 80px; +} +.star-rating a.r5stars{ + left: 80px; +} +.star-rating a.r5stars:hover{ + width: 100px; +} +.star-rating a.r6stars{ + left: 100px; +} +.star-rating a.r6stars:hover{ + width: 120px; +} +.star-rating a.r7stars{ + left: 120px; +} +.star-rating a.r7stars:hover{ + width: 140px; +} +.star-rating a.r8stars{ + left: 140px; +} +.star-rating a.r8stars:hover{ + width: 160px; +} +.star-rating a.r9stars{ + left: 160px; +} +.star-rating a.r9stars:hover{ + width: 180px; +} +.star-rating a.r10stars{ + left: 180px; +} +.star-rating a.r10stars:hover{ + width: 200px; +} +.star-rating li.current-rating{ + background: url(/images/alt_star.gif) left center; + position: absolute; + height: 25px; + display: block; + text-indent: -9000px; + z-index: 1; + left:0px; +} + +.star-rating li.current-rating-1{ + background: url(/images/reaktor_rating1.gif) left center; + position: absolute; + height: 25px; + display: block; + text-indent: -9000px; + z-index: 0; + left:0px; +} + +.star-rating li.current-rating-2{ + background: url(/images/reaktor_rating2.gif) left center; + position: absolute; + height: 25px; + display: block; + text-indent: -9000px; + z-index: 0; + left:0px; +} + +/* remove halo effect in firefox */ +a:active{ + outline: none; +} diff --git a/web/errors/error500.php b/web/errors/error500.php new file mode 100644 index 0000000..eb1dd80 --- /dev/null +++ b/web/errors/error500.php @@ -0,0 +1,89 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + * + * Internal Error 500 + * + * The server encountered an unexpected condition which prevented it from + * fulfilling the request. + * + * Note the "prevented it from fulfilling the request" part. We cannot use stuff + * from synfony here as it may or may not have managed to initialize anything. + * + */ +?> + + + + + + + + + Reaktor: Internal error + + + + + + + + +
      +
      + LogoForside + + Home + FotoReaktor + TegningReaktor + + FilmReaktor + LydReaktor + TegneserieReaktor + TekstReaktor + +
      +
      +
      +
      +
      +
      +

      We are sorry, but there was an error trying to show the page you have requested.

      +

      Please try again later.

      +

      If the problem persists, please contact deichman@minreaktor.no

      +

      (Go back)

      +
      +
      +
      +

      Beklager, det oppstod en feil ved visning av siden.

      +

      Vennligst prøv igjen senere.

      +

      Hvis problemet fortsetter, vennligst kontakt deichman@minreaktor.no

      +

      (Gå tilbake)

      +
      +
      +
      +
      +
      +





      + +

      + Deichmanske bibliotek + Trondheim folkebibliotek + Norsk digitalt bibliotek + Kulturnett.no +

      + +

      +
      + + + + + diff --git a/web/flowplayer/FlowPlayerClassic.swf b/web/flowplayer/FlowPlayerClassic.swf new file mode 100644 index 0000000..5990d7d Binary files /dev/null and b/web/flowplayer/FlowPlayerClassic.swf differ diff --git a/web/flowplayer/FlowPlayerDark.swf b/web/flowplayer/FlowPlayerDark.swf new file mode 100644 index 0000000..55a3990 Binary files /dev/null and b/web/flowplayer/FlowPlayerDark.swf differ diff --git a/web/flowplayer/FlowPlayerLP.swf b/web/flowplayer/FlowPlayerLP.swf new file mode 100644 index 0000000..33d3c8e Binary files /dev/null and b/web/flowplayer/FlowPlayerLP.swf differ diff --git a/web/flowplayer/FlowPlayerLight.swf b/web/flowplayer/FlowPlayerLight.swf new file mode 100644 index 0000000..aef4585 Binary files /dev/null and b/web/flowplayer/FlowPlayerLight.swf differ diff --git a/web/flowplayer/LICENSE.txt b/web/flowplayer/LICENSE.txt new file mode 100644 index 0000000..caa5c96 --- /dev/null +++ b/web/flowplayer/LICENSE.txt @@ -0,0 +1,680 @@ +FlowPlayer is released under GNU GENERAL PUBLIC LICENSE Version 3. + +Included flashembed Flash Embedding script is eleased under the MIT License: +http://www.opensource.org/licenses/mit-license.php + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state 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) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/web/flowplayer/README.txt b/web/flowplayer/README.txt new file mode 100644 index 0000000..fa377f8 --- /dev/null +++ b/web/flowplayer/README.txt @@ -0,0 +1,443 @@ + +The players are located in the root flowplayer directory in the distribution package. +* The player flash components are: FlowPlayer.swf, FlowPlayerWhite.swf, FlowPlayerBlack.swf and FlowPlayerLP.swf +* Sample HTML files + JavaScript for embedding the players are in the html directory. +* Extra example files for special cases in the extras folder + (example suggestion.js, example external configuration file). + +Installation +============ + +To install the player copy html/flashembed.min.js and one of the player SWF files into +your Web server. Only the SWF and flashembed.min.js is required! For further info please +see the installation instruction in our Web site http://flowplayer.org + +See html/FlowPlayer.html for a simple example! + +FlowPlayer Version history (latest release on top) +================================================= + +2.1.2 + - New example.html included, old example files were dropped from the distribution package + - New version of flashembed.min.js, it has some bugs fixed + Fixes: + - Sometimes the buffering animation was left running in the beginning of videos. + - Scaling problems fixed. You can use showOnLoadBegin: false in the clips to prevent them from showing before + they have been scaled properly. + +2.1.1 + Fixes: + - Buffering animation was left visible when pausing and resuming using the control-bar's + pause/resume button + +2.1 + - Hardware Scaled video in full-screen mode + - New buffering rotation animation + - New option controlBarGloss + Fixes: + - The control bar hiding is now based on mouse move delay, works much better that way + - Calls onFlowPlayerReady() also when you use the configInject option. + - Does not show NaN's in the time display when playing MP3 clips with autoPlay: false + - The stop button behaves correctly for MP3 clips + - Replay button in the suggestions view fixed + - Does not produce sound in the beginning of clip when autoPlay: false and autoBuffering: true + - Now shows the first frame of video when autoPlay: false and autoBuffering: true + - Fixed: was not possible to set the clip's duration just using the 'end' parameter + - Does not show the buffering rotation animation at the end of playList + +2.0.1 + - Arranges the buttons to the left if the scrubber is not shown (when using showScrubber: false) + - Does not show the video link in the Embed popup unless videoLink is specified in config + Fixes: + - Email sending works now by default, it sends the data to flowplayer.org's email sender + - Menu bar is now always correctly opened above the control bar + + +2.0 + - Now uses the "native full screen" by default, no need to specify useNativeFullScreen: true to enable it + - Shows the big play button overlay image by default, new config option 'usePlayOverlay' that can be + used to disable it. + - New button to mute and unmute the sound volume + - Possibility to show/hide every button and widget in the control bar + - New overlay play button graphic + - New rotating buffer animation + - Added a new callback onFlowPlayerReady() to the JavaScript API. + - New default skin 'air' + * New controlsOverVideo config setting + * new config setting controlBarBackgroundColor (controlAreaBorderColor setting was removed) + - Removed the loop button (unnecessary) + - The initial volume level is now 50% + - The popup menu automatically hides after 10 seconds if not closed by the user. + - Added new "onPlaybackTime" callback to the JavaScript API. Reports the current time + in the video timeline. + - setting autoPlay: true now starts playing when the 'play' button overlay is used as the first clip + in the playList. Setting autoPlay: false will make the player pause on and show the splash. + - Embed view shows a direct link to the current video file + * added videoLink config option that can be used to override the default + that is taken from the playList or the videoFile option + - Email-a-link functionality: + * added emailPostUrl config option + * added emailVideoLink config option + * added emailDefaultMessage config option (all occurrences of [video_link] tag in the message + are replaced with the value of emailVideoLink) + - AdServer functionality: + * added following clip specific configuration options: id, keywords + * added enableAds, publisherId, adServerUrl, adServerAuth, countryCode config options + Fixes: + - autoRewind now rewinds to start and stops if loop is false + - The initialScale config option works correctly when the controls are hidden using hideControls: true + - playList support with RTMP streaming servers was broken + +1.21.1 + Fixes: + - FlowPlayer prevented page elements from loading properly when the page was refreshed in IE. Now fixed! + - setConfig() JavaScript API function is initialized as early as possible to + fix some timing issues on IE. + - does not load the fullscreen.js from flowplayer.org when using the native full screen mode + - volume level was reset back to 100% when scrubbing + + +1.21 + - MP3 playback (following are not supported yet: Protection codes (a.k.a. anti-leeching)) + - Google Analytics support + - Extensions to the JavaScript API + - Added the possibility to play a clip via JavaScript + - Added possibility to set programmatic cue points using JavaScript + - Added possibility to play a clip having a RTMP url + - Player initializes without specifying any config. After that you can use the JavaScript API + to configure it and play clips. + - Embed code does not include child configs any more. Only the configuration set by + flashVars or injected is included in the embed code configuration. + - Possibility to supply the embed code in config + - Possibility to load a page for suggestions instead of just playing them in the same + player instance. Done with the linkURL and linkWindow clip specific fields. + Fixes: + - Seeking is more accurate so that it seeks exactly where the scrub bar is released + - You can now seek to the beginning or the end of a video using the scrubber + - Setting a new config using JavaScript via setConfig() now re-creates the UI so that it properly + reflects the new config + - baseURL was not used if it was specified in a parent config and the playlist was specified in it's child config. + - does not load the fullscreen.js from flowplayer.org when using the native full screen mode + - doubleclickin on the "play" overlay at the beginning of a playlist caused the player to pause. Now doubleclicks + work the same as single clicks. + - Fixes to suggestions: + - Does not unnecessarily load the suggestion URL several times. + - Suggestions loading did not work when using an external config file. Caused the player to initialize over and over. + +1.20 + - Suggestions a.k.a. related videos + - Loading of configuration using RTMP from a streaming server + - The native full screen ads were removed and replaced by a flowplayer.org logo + - Added a new clip type 'video' that ensures correct playback for h.264 videos supported + by the latest Flash player 3 update codenamed "Moviestar" + Fixes: + - RTMP recorded streams were not played to the end + - Fixed the sample HTML files + +1.19 + - Skinning kit + - Added all dependencies to the source distribution package + Fixes: + - videoHeight does not have any effect in full screen mode any more, now resizes to fit the full area + - configured progress bar, buffering bar etc. colors were ignored + +1.18 + - Smoothing of FLV videos (antialiasing of scaled video) + - Native Flash full screen mode added. + - The Long Play version (FlowPlayerLP.swf) now resizes to full screen + - Addes mouse over states to buttons. + - Added 'overlay' to image clips. Can be used to overlay a play button image on top of another image clip. + - Addes a built-in Big Play Button overlay. + - Added new clip specific configuration variable 'liveStream' to specify that the clip is a live stream + played from a media server. + - Changed the background of the video area to be black. Now the player does not show the video (shows the black + background instead) before the buffer is filled an the playback starts. + - Added new clip specific setting 'showOnLoadBegin'. Turn this to false and the video will not be shown + before the buffer has been filled and the playback starts. + - All methods of the JavaScript API are now available in LocalConnection API as well. You can now + control FlowPlayer from another Flash movie. + - By default the loop button is no longer shown. You have to specify showLoopButton: true to make it visible. + - New maximum play count for clips in the playlist. Controlled with a clip specific 'maxPlayCount' setting. + Fixes: + - Progress bar now better seeks to the end of videos. + - The embed area is centered horizontally also in full screen mode. + - The time display was corrupted with videos longer than 60 minutes. Now uses a smaller font so that + the time values fit properly. + - JS full screen works with external config file + - Setting showFullScreenButton to False Shortens Progress Bar - now fixed + - The Long Play version does not redraw the thumbs strip unnecessarily + +Older releases in in version number order: + +0.9 Initial public release. All basic features are in place. + +0.9.1 Added 'autoPlay' variable that can be used to specify whether the + playback should begin immediately when the player has been loaded into + the Web browser. + +0.9.2 Bug fixes. + +0.9.3 Added new 'bufferLength' variable that can be used in the HTML page to + specify the length of the buffer in seconds when streaming FLV. Fixed a + bug that prevented playback after an FLV was completely played. + +0.9.4 Added a 'baseURL' variable that can be used to specify the location of + the video file to be loaded by Player.swf. See Player.html for an + example. + + If the 'videoFile' variable's value contains a '.flv' or '.swf' + extension, the standalone player (Player.swf) will NOT append this based + on the detected flash version. If a prefix is not present, the player + always appends either one of these prefixes. + +1.0 + - Displays a "BUFFERING..." text when filling the video buffer. + - Fixed playback of the start and the end of the video where the player + was errorneously cutting off some of the video. + - Added a new start() function to the FlowPlayer class. + - Fixed Sample.fla + +1.1 + - Added ability to loop; Contains a new toggle button to control looping. + Default looping state is defined in 'loop' parameter. Thanks Jeff Wagner + for contributing the initial looping support. + - Now resizes according to the size defined in the HTML page + - Fixed some flaws in the graphics + - The color of the progress bar is now gray by default (more neutral). The + color can be customized by parameters. + - Removed support to play videos in SWF format. + +1.2 + - Added a 'autoBuffering' option and welcome image support. + - Added a 'hideContols' option to hide all buttons and other widgets and + leaving only the video display showing. + - Added support for welcome images + - Most of the UI is now built dynamically with ActionScript instead of using + pre-drawn images. This results in 50% smaller download size. + +1.2.b2 + - Fixed binary build that contained an old buggy FlowPlayer.swf + +1.3 + - Fixed resizing problem that occurred with Internet Explorer: The video was + not resized when the page was refreshed. + +1.4 + - Removed the blue the background color of the player. The light blue color + became visible when using only the obect-tag to embed the player into a page. + By using only the object tag it's possible to author valid XHTML. The sample + FlowPlayer.html now shows this kind of markup. + +1.5 + - Support for playlists + - Extenal configuration file that enables configuring all the existing + settings. All settings defined in this configuration file can be + overridden using flashvars in the HTML object tag. + - Basic skinning support: Images for all buttons (play, pause, looping + toggle, and dragger) can be loaded from external JPG files. Smaller + versions of the default buttons are provided as an example. + FlowPlayerLiht.swf is meant to be used with skinning: it does not contain + any button images in itself and therefore is slightly smaller in download + size. + - 'hideBorder' option + - visual improvement of control buttons + - dragging can be now done by clicking anywhere in the progress bar area + - clicking on the video area pauses and resumes playback + - scaling the splash image is now optional. Alternatively it can be centered + into the video area. + - removed the border surrounding the video area + - plus some more minor changes + Bug fixes: + - Seeking using the dragger button is more accurate. Now it is possible to + seek to the very beginning of a clip. + - Stops playing in the launching player when the full screen player is opened. This + way the full screen player can begin buffering the video immediately. Previously + the launching player was paused and continued buffering and it prevented the full + screen player from buffering. + +1.6 + Bug fixes: + - Does not buffer unnessessarily if looping through one clip again and again + - Playback can be started normally again when the clip is done and looping + is off. There was a bug that prevented this. + - Clicking on the video area did not start playing if splash not used and + when autoPlay=false + - The seeker button aligned to the right from the mouse position when it was + grabbed using the mouse button. Now it stays on the same position it was in + when the mouse button was pressed down. + - It was not possible to use characters 'y' and 'Y' in the names inside + the playList. Now following characters are available: + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?!/-:,. 1234567890" + +1.7 + Fixes: + - baseURLs are not appended to file name values that are complete URLs + - minor visual enhancements + New features: + - Support for long videos: Initial support for streaming servers (tested with red5) + + thumbnails corresponding to cue points. + - Video duration and time indicator + - Resizing of the video area through a menu + +1.7.1 + - Now the original FLV video dimensions are detected from the FLV metadata. The different resizing options are based on those. Initially the size is maximized according to the 'videoHeight' setting and preserving the aspect ratio. + Fixes: + - progress bar now goes to the start position (left) even when autoPlay=false and autoBuffering=false [1574640] + - resizing menu does not toggle pause/resume anymore [1581085] + - fixed missing audio on some FLV files [1568612] + - Flash Media Servers seems to send the FLV metadata again and again when seeking. This caused unnessessary rearranging of the thumbnails. + - Thumnail list's scrollbar is now hidden if all thumbnails fit the available visible space. + +1.8 + - Initial JavaScript API (Requires FlashPlayer 8 or above): + * Possibility to configure the player using JavaScript and a configuration object + similar to the external config file (using JavaScript Object Notation, JSON) + * Possibility to move the playback to different clips in the playlist using JavaScript + - Changed the format how thumbnails are specified in the config object + - The numbers from the playlist's clips were removed + - Unnamed clips are hidden from the playlist + - Possibility to have images in the playlist. Now the splash image is internally handled + as being the first clip in the playlist. + - Adjacent clips are played as one stream when using a streaming server + +1.9 - More complete JavaScript API + - Hierarchical configuration + - New config variable "initialScale" to control the initial scaling of the video + - New resizing option "fill window" that will fill all available space (does not care about preserving the aspect ratios) + - Changed the default buffer to 10 seconds + - noVideoClip config setting that can be used to specify a video clip or an image to be played when + the primary clip is not found + Fixes: + - Fixed buffering indicator, did not show the buffer lenght correctly when not using a streaming server + - It was not possible to pass an empty string in baseURL when using setConfig() in the JavaScript API + - loop config setting was broken + - Clip is now better recognized as completely played + +1.10 + Changed to use the same configuration syntax with flashVars as with external configuration files. Now + the same configuration style is used consistently everywhere. + Fixes: + - It was impossible to disable autoPlay and autoBuffering + +1.10.1 + - Fix for the message on IE: "Object doesn't support this property or method' Line 48, Char 3". This + was caused by two method names in the new JavaScript API. As a result, these methods are now renamed + in the JavaScript API. + - Inlcuded javascript.txt (documentation for the JavaScript API) in the distribution packages. + +1.11 + - Finally added a volume control slider + - Made all progress bar and volume slider colors customizable + - Added a possibility to hide the playlist control buttons (next clip and previous clip buttons) + - Fixed the sample html files to work in Internet Explorer. The pages now use SWFObject + (http://blog.deconcept.com/swfobject/) to embed the player. + +1.11.1 + - Changed volume slider to change the volume while the slider is being moved. The previous version changed + it only after the mouse button was released. + Fixes: + - Now resets the play/pause button correctly when the clip ends and looping is not used + - Looping does not go to the splash after the last clip in the playlist is finished. Instead the playback loops + to the first clip after the splash. This is valid also when only one video is configured to be played using + the 'videoFile' config option. + +1.12 + - Protection scheme to prevent inline linking (http://en.wikipedia.org/wiki/Inline_linking) + of video and image files. + - Images in playlist are resized according to the menu options. Images also respect the 'initialScale' + config option. + Fixes: + - If loop is off the player stops on the last frame of the clip + +1.13 + - New config options to hide the loop button and the size options menu. + - Possibility to disable transport control buttons using a clip specific option. + - Possibility to have hyperlinks for clips. Will open the linked URL into the browser when the clip is clicked. + - Possibility to disable pause/resume behavior associated to clicking the video area. This is done + by specifying an empty hyperlink URL to a click. + - New animation that plays on the progress bar area when the video is buffering + - The setConfig() method in the JavaScript API can be used over and over again to replace the configuration + +1.14 + - Two new skins included (black & white) + - Initial support for lighttpd + - Ability to include Flash movies (swf files) in playlist + - Added a type property to playlist clips so that the URLs don't need to have an extension (swf, flv or jpg) + any more. + Fixes: + - playlist control buttons (next & prev) did not fade out when disabling them for a clip + +1.14.1 + - dragger (scrubber) now causes immediate seeking when it is moved + Fixes: + - JavaScript API's setConfig() did not work correctly + - allows seeking to unbuffered areas when streaming with lighttpd + - removed unnecessary error logging + - volume slider goes all the way to the right edge + - fixed regressions in LP version: Thumbnail scrollbar was not shown, + duration labels did not have the grey background + +1.15 + - Added several event callbacks to the JavaScript API. See javascript.txt for details. + - Added a new "thermometer" skin, ends up in FlowPlayerThermo.swf (does not include the playlist + control and loop buttons yet) + - Andrew Rice: Faster seeking with lighttpd by using a binary search to find the keyframes. + A fix to the Seek() method in the JavaScript API now works correctly with lighttpd. + +1.16 + - Added full screen support. Opens a new browser window that occupies all screen estate. + - Added a new view that shows the HTML code for embedding the video in blogs etc. + - Changed the looks of the menu. The menu is now shown when the user hovers over the area + where it is displayed. + - Added more event callbacks to the JavaScript API. See javascript.txt for details. + - Changed the splash image to use the 'baseURL' variable that is used with all other types of clips. + 'skinImagesBaseURL' is only used for external skin images + - Removed the playlist view (the list that showed the playlist contents under the control buttons) + Fixes: + - Volume slider sometimes was errorneusly placed on top of the video area + - a SWF in a playlist is not loaded on top of the control button area (new the control area + border stays on top of it). + - initialScale parameter did not work when the controls were hidden + - pause/resume by clicking the video (or the linkUrl behavior) did not work in the upper left + corner of the video area + - The player now dynamically resizes itself if the size is changed in the embedding HTML. This + is utilized by the fullscreen feature. + +1.16.1 + Fixes a bug in the new full screen feature, it was not able to dynamically add the required + JavaScript to the opening page's DOM on Internet Explorer. + +1.16.2 + Fixed the embedding feature so that the displayed code works in MySpace. + +1.17 + - Added a button to open the full screen page. + - Removed the menu auto-popup. + - Added a 'autoRewind' option that is used to rewind to the first clip in the playlist. The old + 'loop' option keeps the playback looping without returning back to the first splash image + (if there is a splash). + - Added ability to include png files in playlists. Especially useful for creating transparent splash images + that have a big play button image. + - Added a per clip parameter 'allowResize' that can be used to override the scaling setting. + - Changed the font used in FlowPlayer to be non italics + - Added possibility to fix the control buttons area width. Now the controls do not fill the whole + width in the full screen mode. + Fixes: + - Embed provided hardcoded width and height values. Now it takes those from the parent player. + +1.17.1 + Fixes: + - Fixed user interface problems introduced in 1.17 + (see: http://sourceforge.net/forum/forum.php?thread_id=1733937&forum_id=453550) + + + +How to use it +============= + +Please see http://flowplayer.org/documentation + +Support, comments, bug reports and feedback: +-------------------------------------------- +Please post support requests and feedback to the forums at http://flowplayer.org +You can also contact the author directly: api@iki.fi diff --git a/web/flowplayer/extras/FlowPlayerClassic.swf b/web/flowplayer/extras/FlowPlayerClassic.swf new file mode 100644 index 0000000..1a7c741 Binary files /dev/null and b/web/flowplayer/extras/FlowPlayerClassic.swf differ diff --git a/web/flowplayer/extras/FlowPlayerDark.swf b/web/flowplayer/extras/FlowPlayerDark.swf new file mode 100644 index 0000000..65d6bae Binary files /dev/null and b/web/flowplayer/extras/FlowPlayerDark.swf differ diff --git a/web/flowplayer/extras/FlowPlayerLP.swf b/web/flowplayer/extras/FlowPlayerLP.swf new file mode 100644 index 0000000..8897330 Binary files /dev/null and b/web/flowplayer/extras/FlowPlayerLP.swf differ diff --git a/web/flowplayer/extras/FlowPlayerLight.swf b/web/flowplayer/extras/FlowPlayerLight.swf new file mode 100644 index 0000000..504c122 Binary files /dev/null and b/web/flowplayer/extras/FlowPlayerLight.swf differ diff --git a/web/flowplayer/extras/LICENSE.txt b/web/flowplayer/extras/LICENSE.txt new file mode 100644 index 0000000..caa5c96 --- /dev/null +++ b/web/flowplayer/extras/LICENSE.txt @@ -0,0 +1,680 @@ +FlowPlayer is released under GNU GENERAL PUBLIC LICENSE Version 3. + +Included flashembed Flash Embedding script is eleased under the MIT License: +http://www.opensource.org/licenses/mit-license.php + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + 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 +state 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) + + 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 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/web/flowplayer/extras/README.txt b/web/flowplayer/extras/README.txt new file mode 100644 index 0000000..2ae34ba --- /dev/null +++ b/web/flowplayer/extras/README.txt @@ -0,0 +1,485 @@ + +The players are located in the root flowplayer directory in the distribution package. +* The player flash components are: FlowPlayer.swf, FlowPlayerWhite.swf, FlowPlayerBlack.swf and FlowPlayerLP.swf +* Sample HTML files + JavaScript for embedding the players are in the examples directory. Open the examples/index.html + with your browser! +* Extra example files for special cases in the extras folder + (example suggestion.js, example external configuration file). + +Installation +============ + +To install the player copy html/flashembed.min.js and one of the player SWF files into +your Web server. Only the SWF and flashembed.min.js is required! For further info please +see the installation instruction in our Web site http://flowplayer.org + +See html/FlowPlayer.html for a simple example! + +FlowPlayer Version history (latest release on top) +================================================= + +2.2.1 + Fixes: + - initialVolumePercentage did not affect the volume level before the slider was touched + - non-HW full-screen did not scale the video up when the menu was hidden + - pauses the player before opening the page linked with the clip specific linkUrl variable + - Fixed SWF viewing + - The controlBar's playbutton did not work after pressing stop or after rewinding to beginning + - controlsOverVideo: 'no' was fixed + +2.2 + - Added possibility to pause/resume using the space bar + - Added initialVolumePercentage configuration variable + - Added getVersion() to the JavaScript API + - Explicitly returning false from following JavaScript API callback methods will disable + the default behavior related to the event: + onClipChanged, onClipDone, onLoadBegin, onStartBuffering, onStreamNotFound + - The clips' "start" property is now supported with lighttpd + - Added new showEmailView() and showEmbedView() to the JavaScript API + - Added new onSeek(targetSeconds) to the JavaScript API + - Changed to use the new Google Analytics pageTracker._trackPageview function to send the stats. + To continue using urchinTracker (the deprecated old function) you can configure this using the new + googleAnalyticsFunction configuration option. + Fixes: + - The play button is now enabled at the end of the clip when loop: false, autoRewin: false + - JavaScript API method getIsPlaying() now returns false if the player is paused + - Looping through adjacent streams now works properly when using a RTMP server. You will need to provide + duration information for the clips though. The loop parameter works also as expected. + - Suggestion thumbnails fell out of alignment if they were of differing widths. + - There was no sound when video clips don't contain metadata or when using RTMP live streams. + To fix this, the sound is now muted only when autoPlay: false, autoBuffering: true + - Volume slider now mutes the volume completely when dragged to the left end. + +2.1.3 + New version 0.27 of flashembed.js + Commercial versions: + Added the possibility have a custom Overlay Play Button image. New config option playButtonImageUrl to achieve this. + Fixes: + - noVideoClip was not working with playOverlay + - progress bar was not visible in IE after page refresh + - Now really stops at first frame when setting autoPlay:false, autoBuffering: false + +2.1.2 + - New example.html included, old example files were dropped from the distribution package + - New version of flashembed.min.js, it has some bugs fixed + Fixes: + - Sometimes the buffering animation was left running in the beginning of videos. + - Scaling problems fixed. You can use showOnLoadBegin: false in the clips to prevent them from showing before + they have been scaled properly. + +2.1.1 + Fixes: + - Buffering animation was left visible when pausing and resuming using the control-bar's + pause/resume button + +2.1 + - Hardware Scaled video in full-screen mode + - New buffering rotation animation + - New option controlBarGloss + Fixes: + - The control bar hiding is now based on mouse move delay, works much better that way + - Calls onFlowPlayerReady() also when you use the configInject option. + - Does not show NaN's in the time display when playing MP3 clips with autoPlay: false + - The stop button behaves correctly for MP3 clips + - Replay button in the suggestions view fixed + - Does not produce sound in the beginning of clip when autoPlay: false and autoBuffering: true + - Now shows the first frame of video when autoPlay: false and autoBuffering: true + - Fixed: was not possible to set the clip's duration just using the 'end' parameter + - Does not show the buffering rotation animation at the end of playList + +2.0.1 + - Arranges the buttons to the left if the scrubber is not shown (when using showScrubber: false) + - Does not show the video link in the Embed popup unless videoLink is specified in config + Fixes: + - Email sending works now by default, it sends the data to flowplayer.org's email sender + - Menu bar is now always correctly opened above the control bar + + +2.0 + - Now uses the "native full screen" by default, no need to specify useNativeFullScreen: true to enable it + - Shows the big play button overlay image by default, new config option 'usePlayOverlay' that can be + used to disable it. + - New button to mute and unmute the sound volume + - Possibility to show/hide every button and widget in the control bar + - New overlay play button graphic + - New rotating buffer animation + - Added a new callback onFlowPlayerReady() to the JavaScript API. + - New default skin 'air' + * New controlsOverVideo config setting + * new config setting controlBarBackgroundColor (controlAreaBorderColor setting was removed) + - Removed the loop button (unnecessary) + - The initial volume level is now 50% + - The popup menu automatically hides after 10 seconds if not closed by the user. + - Added new "onPlaybackTime" callback to the JavaScript API. Reports the current time + in the video timeline. + - setting autoPlay: true now starts playing when the 'play' button overlay is used as the first clip + in the playList. Setting autoPlay: false will make the player pause on and show the splash. + - Embed view shows a direct link to the current video file + * added videoLink config option that can be used to override the default + that is taken from the playList or the videoFile option + - Email-a-link functionality: + * added emailPostUrl config option + * added emailVideoLink config option + * added emailDefaultMessage config option (all occurrences of [video_link] tag in the message + are replaced with the value of emailVideoLink) + - AdServer functionality: + * added following clip specific configuration options: id, keywords + * added enableAds, publisherId, adServerUrl, adServerAuth, countryCode config options + Fixes: + - autoRewind now rewinds to start and stops if loop is false + - The initialScale config option works correctly when the controls are hidden using hideControls: true + - playList support with RTMP streaming servers was broken + +1.21.1 + Fixes: + - FlowPlayer prevented page elements from loading properly when the page was refreshed in IE. Now fixed! + - setConfig() JavaScript API function is initialized as early as possible to + fix some timing issues on IE. + - does not load the fullscreen.js from flowplayer.org when using the native full screen mode + - volume level was reset back to 100% when scrubbing + + +1.21 + - MP3 playback (following are not supported yet: Protection codes (a.k.a. anti-leeching)) + - Google Analytics support + - Extensions to the JavaScript API + - Added the possibility to play a clip via JavaScript + - Added possibility to set programmatic cue points using JavaScript + - Added possibility to play a clip having a RTMP url + - Player initializes without specifying any config. After that you can use the JavaScript API + to configure it and play clips. + - Embed code does not include child configs any more. Only the configuration set by + flashVars or injected is included in the embed code configuration. + - Possibility to supply the embed code in config + - Possibility to load a page for suggestions instead of just playing them in the same + player instance. Done with the linkURL and linkWindow clip specific fields. + Fixes: + - Seeking is more accurate so that it seeks exactly where the scrub bar is released + - You can now seek to the beginning or the end of a video using the scrubber + - Setting a new config using JavaScript via setConfig() now re-creates the UI so that it properly + reflects the new config + - baseURL was not used if it was specified in a parent config and the playlist was specified in it's child config. + - does not load the fullscreen.js from flowplayer.org when using the native full screen mode + - doubleclickin on the "play" overlay at the beginning of a playlist caused the player to pause. Now doubleclicks + work the same as single clicks. + - Fixes to suggestions: + - Does not unnecessarily load the suggestion URL several times. + - Suggestions loading did not work when using an external config file. Caused the player to initialize over and over. + +1.20 + - Suggestions a.k.a. related videos + - Loading of configuration using RTMP from a streaming server + - The native full screen ads were removed and replaced by a flowplayer.org logo + - Added a new clip type 'video' that ensures correct playback for h.264 videos supported + by the latest Flash player 3 update codenamed "Moviestar" + Fixes: + - RTMP recorded streams were not played to the end + - Fixed the sample HTML files + +1.19 + - Skinning kit + - Added all dependencies to the source distribution package + Fixes: + - videoHeight does not have any effect in full screen mode any more, now resizes to fit the full area + - configured progress bar, buffering bar etc. colors were ignored + +1.18 + - Smoothing of FLV videos (antialiasing of scaled video) + - Native Flash full screen mode added. + - The Long Play version (FlowPlayerLP.swf) now resizes to full screen + - Addes mouse over states to buttons. + - Added 'overlay' to image clips. Can be used to overlay a play button image on top of another image clip. + - Addes a built-in Big Play Button overlay. + - Added new clip specific configuration variable 'liveStream' to specify that the clip is a live stream + played from a media server. + - Changed the background of the video area to be black. Now the player does not show the video (shows the black + background instead) before the buffer is filled an the playback starts. + - Added new clip specific setting 'showOnLoadBegin'. Turn this to false and the video will not be shown + before the buffer has been filled and the playback starts. + - All methods of the JavaScript API are now available in LocalConnection API as well. You can now + control FlowPlayer from another Flash movie. + - By default the loop button is no longer shown. You have to specify showLoopButton: true to make it visible. + - New maximum play count for clips in the playlist. Controlled with a clip specific 'maxPlayCount' setting. + Fixes: + - Progress bar now better seeks to the end of videos. + - The embed area is centered horizontally also in full screen mode. + - The time display was corrupted with videos longer than 60 minutes. Now uses a smaller font so that + the time values fit properly. + - JS full screen works with external config file + - Setting showFullScreenButton to False Shortens Progress Bar - now fixed + - The Long Play version does not redraw the thumbs strip unnecessarily + +Older releases in in version number order: + +0.9 Initial public release. All basic features are in place. + +0.9.1 Added 'autoPlay' variable that can be used to specify whether the + playback should begin immediately when the player has been loaded into + the Web browser. + +0.9.2 Bug fixes. + +0.9.3 Added new 'bufferLength' variable that can be used in the HTML page to + specify the length of the buffer in seconds when streaming FLV. Fixed a + bug that prevented playback after an FLV was completely played. + +0.9.4 Added a 'baseURL' variable that can be used to specify the location of + the video file to be loaded by Player.swf. See Player.html for an + example. + + If the 'videoFile' variable's value contains a '.flv' or '.swf' + extension, the standalone player (Player.swf) will NOT append this based + on the detected flash version. If a prefix is not present, the player + always appends either one of these prefixes. + +1.0 + - Displays a "BUFFERING..." text when filling the video buffer. + - Fixed playback of the start and the end of the video where the player + was errorneously cutting off some of the video. + - Added a new start() function to the FlowPlayer class. + - Fixed Sample.fla + +1.1 + - Added ability to loop; Contains a new toggle button to control looping. + Default looping state is defined in 'loop' parameter. Thanks Jeff Wagner + for contributing the initial looping support. + - Now resizes according to the size defined in the HTML page + - Fixed some flaws in the graphics + - The color of the progress bar is now gray by default (more neutral). The + color can be customized by parameters. + - Removed support to play videos in SWF format. + +1.2 + - Added a 'autoBuffering' option and welcome image support. + - Added a 'hideContols' option to hide all buttons and other widgets and + leaving only the video display showing. + - Added support for welcome images + - Most of the UI is now built dynamically with ActionScript instead of using + pre-drawn images. This results in 50% smaller download size. + +1.2.b2 + - Fixed binary build that contained an old buggy FlowPlayer.swf + +1.3 + - Fixed resizing problem that occurred with Internet Explorer: The video was + not resized when the page was refreshed. + +1.4 + - Removed the blue the background color of the player. The light blue color + became visible when using only the obect-tag to embed the player into a page. + By using only the object tag it's possible to author valid XHTML. The sample + FlowPlayer.html now shows this kind of markup. + +1.5 + - Support for playlists + - Extenal configuration file that enables configuring all the existing + settings. All settings defined in this configuration file can be + overridden using flashvars in the HTML object tag. + - Basic skinning support: Images for all buttons (play, pause, looping + toggle, and dragger) can be loaded from external JPG files. Smaller + versions of the default buttons are provided as an example. + FlowPlayerLiht.swf is meant to be used with skinning: it does not contain + any button images in itself and therefore is slightly smaller in download + size. + - 'hideBorder' option + - visual improvement of control buttons + - dragging can be now done by clicking anywhere in the progress bar area + - clicking on the video area pauses and resumes playback + - scaling the splash image is now optional. Alternatively it can be centered + into the video area. + - removed the border surrounding the video area + - plus some more minor changes + Bug fixes: + - Seeking using the dragger button is more accurate. Now it is possible to + seek to the very beginning of a clip. + - Stops playing in the launching player when the full screen player is opened. This + way the full screen player can begin buffering the video immediately. Previously + the launching player was paused and continued buffering and it prevented the full + screen player from buffering. + +1.6 + Bug fixes: + - Does not buffer unnessessarily if looping through one clip again and again + - Playback can be started normally again when the clip is done and looping + is off. There was a bug that prevented this. + - Clicking on the video area did not start playing if splash not used and + when autoPlay=false + - The seeker button aligned to the right from the mouse position when it was + grabbed using the mouse button. Now it stays on the same position it was in + when the mouse button was pressed down. + - It was not possible to use characters 'y' and 'Y' in the names inside + the playList. Now following characters are available: + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz?!/-:,. 1234567890" + +1.7 + Fixes: + - baseURLs are not appended to file name values that are complete URLs + - minor visual enhancements + New features: + - Support for long videos: Initial support for streaming servers (tested with red5) + + thumbnails corresponding to cue points. + - Video duration and time indicator + - Resizing of the video area through a menu + +1.7.1 + - Now the original FLV video dimensions are detected from the FLV metadata. The different resizing options are based on those. Initially the size is maximized according to the 'videoHeight' setting and preserving the aspect ratio. + Fixes: + - progress bar now goes to the start position (left) even when autoPlay=false and autoBuffering=false [1574640] + - resizing menu does not toggle pause/resume anymore [1581085] + - fixed missing audio on some FLV files [1568612] + - Flash Media Servers seems to send the FLV metadata again and again when seeking. This caused unnessessary rearranging of the thumbnails. + - Thumnail list's scrollbar is now hidden if all thumbnails fit the available visible space. + +1.8 + - Initial JavaScript API (Requires FlashPlayer 8 or above): + * Possibility to configure the player using JavaScript and a configuration object + similar to the external config file (using JavaScript Object Notation, JSON) + * Possibility to move the playback to different clips in the playlist using JavaScript + - Changed the format how thumbnails are specified in the config object + - The numbers from the playlist's clips were removed + - Unnamed clips are hidden from the playlist + - Possibility to have images in the playlist. Now the splash image is internally handled + as being the first clip in the playlist. + - Adjacent clips are played as one stream when using a streaming server + +1.9 - More complete JavaScript API + - Hierarchical configuration + - New config variable "initialScale" to control the initial scaling of the video + - New resizing option "fill window" that will fill all available space (does not care about preserving the aspect ratios) + - Changed the default buffer to 10 seconds + - noVideoClip config setting that can be used to specify a video clip or an image to be played when + the primary clip is not found + Fixes: + - Fixed buffering indicator, did not show the buffer lenght correctly when not using a streaming server + - It was not possible to pass an empty string in baseURL when using setConfig() in the JavaScript API + - loop config setting was broken + - Clip is now better recognized as completely played + +1.10 + Changed to use the same configuration syntax with flashVars as with external configuration files. Now + the same configuration style is used consistently everywhere. + Fixes: + - It was impossible to disable autoPlay and autoBuffering + +1.10.1 + - Fix for the message on IE: "Object doesn't support this property or method' Line 48, Char 3". This + was caused by two method names in the new JavaScript API. As a result, these methods are now renamed + in the JavaScript API. + - Inlcuded javascript.txt (documentation for the JavaScript API) in the distribution packages. + +1.11 + - Finally added a volume control slider + - Made all progress bar and volume slider colors customizable + - Added a possibility to hide the playlist control buttons (next clip and previous clip buttons) + - Fixed the sample html files to work in Internet Explorer. The pages now use SWFObject + (http://blog.deconcept.com/swfobject/) to embed the player. + +1.11.1 + - Changed volume slider to change the volume while the slider is being moved. The previous version changed + it only after the mouse button was released. + Fixes: + - Now resets the play/pause button correctly when the clip ends and looping is not used + - Looping does not go to the splash after the last clip in the playlist is finished. Instead the playback loops + to the first clip after the splash. This is valid also when only one video is configured to be played using + the 'videoFile' config option. + +1.12 + - Protection scheme to prevent inline linking (http://en.wikipedia.org/wiki/Inline_linking) + of video and image files. + - Images in playlist are resized according to the menu options. Images also respect the 'initialScale' + config option. + Fixes: + - If loop is off the player stops on the last frame of the clip + +1.13 + - New config options to hide the loop button and the size options menu. + - Possibility to disable transport control buttons using a clip specific option. + - Possibility to have hyperlinks for clips. Will open the linked URL into the browser when the clip is clicked. + - Possibility to disable pause/resume behavior associated to clicking the video area. This is done + by specifying an empty hyperlink URL to a click. + - New animation that plays on the progress bar area when the video is buffering + - The setConfig() method in the JavaScript API can be used over and over again to replace the configuration + +1.14 + - Two new skins included (black & white) + - Initial support for lighttpd + - Ability to include Flash movies (swf files) in playlist + - Added a type property to playlist clips so that the URLs don't need to have an extension (swf, flv or jpg) + any more. + Fixes: + - playlist control buttons (next & prev) did not fade out when disabling them for a clip + +1.14.1 + - dragger (scrubber) now causes immediate seeking when it is moved + Fixes: + - JavaScript API's setConfig() did not work correctly + - allows seeking to unbuffered areas when streaming with lighttpd + - removed unnecessary error logging + - volume slider goes all the way to the right edge + - fixed regressions in LP version: Thumbnail scrollbar was not shown, + duration labels did not have the grey background + +1.15 + - Added several event callbacks to the JavaScript API. See javascript.txt for details. + - Added a new "thermometer" skin, ends up in FlowPlayerThermo.swf (does not include the playlist + control and loop buttons yet) + - Andrew Rice: Faster seeking with lighttpd by using a binary search to find the keyframes. + A fix to the Seek() method in the JavaScript API now works correctly with lighttpd. + +1.16 + - Added full screen support. Opens a new browser window that occupies all screen estate. + - Added a new view that shows the HTML code for embedding the video in blogs etc. + - Changed the looks of the menu. The menu is now shown when the user hovers over the area + where it is displayed. + - Added more event callbacks to the JavaScript API. See javascript.txt for details. + - Changed the splash image to use the 'baseURL' variable that is used with all other types of clips. + 'skinImagesBaseURL' is only used for external skin images + - Removed the playlist view (the list that showed the playlist contents under the control buttons) + Fixes: + - Volume slider sometimes was errorneusly placed on top of the video area + - a SWF in a playlist is not loaded on top of the control button area (new the control area + border stays on top of it). + - initialScale parameter did not work when the controls were hidden + - pause/resume by clicking the video (or the linkUrl behavior) did not work in the upper left + corner of the video area + - The player now dynamically resizes itself if the size is changed in the embedding HTML. This + is utilized by the fullscreen feature. + +1.16.1 + Fixes a bug in the new full screen feature, it was not able to dynamically add the required + JavaScript to the opening page's DOM on Internet Explorer. + +1.16.2 + Fixed the embedding feature so that the displayed code works in MySpace. + +1.17 + - Added a button to open the full screen page. + - Removed the menu auto-popup. + - Added a 'autoRewind' option that is used to rewind to the first clip in the playlist. The old + 'loop' option keeps the playback looping without returning back to the first splash image + (if there is a splash). + - Added ability to include png files in playlists. Especially useful for creating transparent splash images + that have a big play button image. + - Added a per clip parameter 'allowResize' that can be used to override the scaling setting. + - Changed the font used in FlowPlayer to be non italics + - Added possibility to fix the control buttons area width. Now the controls do not fill the whole + width in the full screen mode. + Fixes: + - Embed provided hardcoded width and height values. Now it takes those from the parent player. + +1.17.1 + Fixes: + - Fixed user interface problems introduced in 1.17 + (see: http://sourceforge.net/forum/forum.php?thread_id=1733937&forum_id=453550) + + + +How to use it +============= + +Please see http://flowplayer.org/documentation + +Support, comments, bug reports and feedback: +-------------------------------------------- +Please post support requests and feedback to the forums at http://flowplayer.org +You can also contact the author directly: api@iki.fi diff --git a/web/flowplayer/extras/examples/css/common.css b/web/flowplayer/extras/examples/css/common.css new file mode 100644 index 0000000..f6a3586 --- /dev/null +++ b/web/flowplayer/extras/examples/css/common.css @@ -0,0 +1,44 @@ + +body { + background-color:#777; + font-family:"trebuchet ms", verdana, "bitstream vera sans"; + padding:0; + margin:0; + text-align:center; +} + +#page { + width:600px; + background-color:#fff; + margin:0px auto; + padding:20px 150px 20px 50px; + min-height:600px; + border:1px solid #000; + border-width:0 1px 1px 1px; + text-align:left; +} + +h1 { + font-size:22px; + letter-spacing:-1px; + color:#0d7b7a; + font-weight:normal; +} + +h1 em { + font-style:normal; + color:darkorange; +} + + +h2 { + font-size:18px; + font-weight:normal; +} + + +.less { + color:#999; + font-size:12px; +} + diff --git a/web/flowplayer/extras/examples/css/multiple-instances.css b/web/flowplayer/extras/examples/css/multiple-instances.css new file mode 100644 index 0000000..e78b782 --- /dev/null +++ b/web/flowplayer/extras/examples/css/multiple-instances.css @@ -0,0 +1,26 @@ + +/* dimensios for both splash image and the player wrapper */ +a.flowplayer, a.flowplayer img { + display:block; + width:300px; + height:240px; + border:0px; +} + +/* play button on top of splash screenn */ +div.playButton { + background:url(../img/play.png) no-repeat; + width:50px; + height:50px; + position:relative; + top:-140px; + left:125px; + opacity:0.9; + margin-bottom:-50px; +} + +/* play button upon mouseover */ +div.playButton:hover { + opacity:1.0; +} + diff --git a/web/flowplayer/extras/examples/css/scrollable-playlist.css b/web/flowplayer/extras/examples/css/scrollable-playlist.css new file mode 100644 index 0000000..024254c --- /dev/null +++ b/web/flowplayer/extras/examples/css/scrollable-playlist.css @@ -0,0 +1,103 @@ + +/* player and playlist go side by side */ +#player, div.playlist { + float:left; + margin-right:20px; +} + +div.playlist { + width:150px; +} + +/* player dimensions */ +#player, #player img { + display:block; + width:300px; + height:240px; + border:0px; +} + +/* play button on top of splash image */ +div.play { + background:url(../img/play.png) no-repeat; + width:50px; + height:50px; + position:relative; + top:-140px; + left:125px; + opacity:0.9; + margin-bottom:-50px; +} + +div.play:hover { + opacity:1.0; +} + + +/* single playlist item */ +div.items a { + background:url(../img/block.jpg) no-repeat; + width:150px; + height:68px; + display:block; + text-decoration:none; + color:#444; +} + +div.items p { + font-size:11px; + width:130px; + padding:8px 0 0 12px; + margin:0px; +} + +div.items p.time { + padding-top:0px; + color:#777; + margin-top:5px; +} + +/* item stages: normal, hover, playing, paused */ +div.items a:hover { + background-position:0 -68px; +} + +div.items a.playing, div.items a.paused { + color:#000; +} + +div.items a.playing { + background-position:0 -136px; +} + +div.items a.paused { + background-position:0 -68px; +} + + +/* small navigational dots */ +div.navi { + width:60px; + float:left; + margin:10px 0 0 50px; + height:11px; + overflow:hidden; +} + +div.navi span { + width:8px; + height:8px; + float:left; + margin:3px; + background:url(../img/dots.png) 0px 0px no-repeat; + cursor:pointer; +} + +div.navi span:hover { + background-position:0 -8px; +} + +div.navi span.active { + background-position:0 -16px; + cursor:default; +} diff --git a/web/flowplayer/extras/examples/css/scrollable-view.css b/web/flowplayer/extras/examples/css/scrollable-view.css new file mode 100644 index 0000000..9b9a8df --- /dev/null +++ b/web/flowplayer/extras/examples/css/scrollable-view.css @@ -0,0 +1,125 @@ + +/* player dimensions */ +a.flowplayer, a.flowplayer img { + display:block; + border:0; + width:250px; + height:180px; + margin-right:15px; + float:left; +} + +/* play button on top of splash image */ +div.playButton { + background:url(../img/play.png) no-repeat; + width:45px !important; + height:45px; + position:relative; + top:-115px; + left:105px; + margin-bottom:-50px; + opacity:0.9; +} + +div.playButton:hover { + opacity:1.0; +} + +/* items */ +div.scrollable { + margin-left:-30px; +} + +div.items { + height:180px; + float:left; + width:470px; + background-color:#efefef; + border:1px solid #ddd; +} + +div.items div { + width:470px; +} + +div.scrollable div { + float:left; +} + +div.scrollable h2 { + margin-top:15px; +} + +div.scrollable p { + color:#444; + font-size:11px; + margin-right:15px; +} + +/* next / prev buttons */ +a.prev, a.next { + display:block; + width:30px; + height:30px; + float:left; + background-repeat:no-repeat; + margin-top:70px; +} + +a.prev { + background:url(../img/button-left.gif); + margin-right:10px; +} + +a.prev:hover { + background:url(../img/button-left-over.gif); +} + +a.next { + background:url(../img/button-right.gif); + margin-left:10px; +} + +a.next:hover { + background:url(../img/button-right-over.gif); +} + + +/* tabs */ +ul.navi { + margin:20px 0 0 0 ; + padding:0px; + height:1.45em; + position:relative; + top:10px; + left:39px; + width:470px; +} + +ul.navi li { + background:url(../img/tab-left.gif) left top no-repeat; + padding-left:4px; + float:left; + margin:0; + list-style-type:none; +} + +ul.navi a { + background:url(../img/tab-right.gif) right top no-repeat; + padding:3px 12px; + border-bottom:1px solid #D2D2D2; + text-decoration:none; + display:block; + color:#333; + font-size:13px; +} + +ul.navi li.active a, ul.navi a:hover { + background-position:100% -150px; + border-bottom:1px solid #fff; +} + +ul.navi li.active { + background-position:0 -150px; +} + diff --git a/web/flowplayer/extras/examples/css/simple-playlist.css b/web/flowplayer/extras/examples/css/simple-playlist.css new file mode 100644 index 0000000..747de67 --- /dev/null +++ b/web/flowplayer/extras/examples/css/simple-playlist.css @@ -0,0 +1,80 @@ + + +/* player and playlist go side by side */ +#player, #playlist { + float:left; + margin-right:20px; +} + +/* player dimensions */ +#player, #player img { + display:block; + width:300px; + height:240px; + border:0px; +} + +#playlist { + width:150px; +} + + +/* overlay play button */ +div.play { + background:url(../img/play.png) no-repeat; + width:50px; + height:50px; + position:relative; + top:-140px; + left:125px; + opacity:0.9; + margin-bottom:-50px; +} + +div.play:hover { + opacity:1.0; +} + + +/* playlist entry */ +#playlist a { + background:url(../img/block.jpg) no-repeat; + width:150px; + height:68px; + display:block; + text-decoration:none; + color:#333; +} + +#playlist p { + font-size:11px; + width:130px; + padding:8px 0 0 12px; + margin:0px; +} + +#playlist p.time { + padding-top:0px; + color:#777; + margin-top:5px; +} + + +/* entry stages: normal, hover, playing, paused */ +#playlist a:hover { + background-position:0 -68px; +} + +#playlist a.playing, #playlist a.paused { + color:#000; +} + +#playlist a.playing { + background-position:0 -136px; +} + +#playlist a.paused { + background-position:0 -68px; +} + + diff --git a/web/flowplayer/extras/examples/img/1m.jpg b/web/flowplayer/extras/examples/img/1m.jpg new file mode 100644 index 0000000..d6d2359 Binary files /dev/null and b/web/flowplayer/extras/examples/img/1m.jpg differ diff --git a/web/flowplayer/extras/examples/img/2m.jpg b/web/flowplayer/extras/examples/img/2m.jpg new file mode 100644 index 0000000..7bd1fd5 Binary files /dev/null and b/web/flowplayer/extras/examples/img/2m.jpg differ diff --git a/web/flowplayer/extras/examples/img/3m.jpg b/web/flowplayer/extras/examples/img/3m.jpg new file mode 100644 index 0000000..ff7bab1 Binary files /dev/null and b/web/flowplayer/extras/examples/img/3m.jpg differ diff --git a/web/flowplayer/extras/examples/img/block.jpg b/web/flowplayer/extras/examples/img/block.jpg new file mode 100644 index 0000000..ad0d70b Binary files /dev/null and b/web/flowplayer/extras/examples/img/block.jpg differ diff --git a/web/flowplayer/extras/examples/img/button-left-over.gif b/web/flowplayer/extras/examples/img/button-left-over.gif new file mode 100644 index 0000000..3554e4b Binary files /dev/null and b/web/flowplayer/extras/examples/img/button-left-over.gif differ diff --git a/web/flowplayer/extras/examples/img/button-left.gif b/web/flowplayer/extras/examples/img/button-left.gif new file mode 100644 index 0000000..6c5def0 Binary files /dev/null and b/web/flowplayer/extras/examples/img/button-left.gif differ diff --git a/web/flowplayer/extras/examples/img/button-right-over.gif b/web/flowplayer/extras/examples/img/button-right-over.gif new file mode 100644 index 0000000..23c7777 Binary files /dev/null and b/web/flowplayer/extras/examples/img/button-right-over.gif differ diff --git a/web/flowplayer/extras/examples/img/button-right.gif b/web/flowplayer/extras/examples/img/button-right.gif new file mode 100644 index 0000000..97db05b Binary files /dev/null and b/web/flowplayer/extras/examples/img/button-right.gif differ diff --git a/web/flowplayer/extras/examples/img/dots.png b/web/flowplayer/extras/examples/img/dots.png new file mode 100644 index 0000000..2731a9d Binary files /dev/null and b/web/flowplayer/extras/examples/img/dots.png differ diff --git a/web/flowplayer/extras/examples/img/item.gif b/web/flowplayer/extras/examples/img/item.gif new file mode 100644 index 0000000..b09f397 Binary files /dev/null and b/web/flowplayer/extras/examples/img/item.gif differ diff --git a/web/flowplayer/extras/examples/img/play.png b/web/flowplayer/extras/examples/img/play.png new file mode 100644 index 0000000..8118915 Binary files /dev/null and b/web/flowplayer/extras/examples/img/play.png differ diff --git a/web/flowplayer/extras/examples/img/tab-left.gif b/web/flowplayer/extras/examples/img/tab-left.gif new file mode 100644 index 0000000..42a138a Binary files /dev/null and b/web/flowplayer/extras/examples/img/tab-left.gif differ diff --git a/web/flowplayer/extras/examples/img/tab-right.gif b/web/flowplayer/extras/examples/img/tab-right.gif new file mode 100644 index 0000000..9326b9a Binary files /dev/null and b/web/flowplayer/extras/examples/img/tab-right.gif differ diff --git a/web/flowplayer/extras/examples/index.html b/web/flowplayer/extras/examples/index.html new file mode 100644 index 0000000..77bc631 --- /dev/null +++ b/web/flowplayer/extras/examples/index.html @@ -0,0 +1,50 @@ + + + Flowplayer examples + + + +
      + +

      Flowplayer examples

      + +

      + We recommend you to study each pages' source code to see how things work. We tried to write them as cleanly as possible so that you can actually understand them. +

      + +

      + Simple example +

      + +

      + Multiple Flowplayer instances +

      + +

      + Simple HTML Playlist +

      + +

      + Scrollable HTML Playlist +

      + +

      + Multiple player instances is tabbed pane +

      + +
      +
      + +

      + If you are running these examples locally and cannot see any video you need to edit your + + Flash security settings. +

      + +

      + Select "Edit locations" > "Add location" > "Browse for files" and select + FlowPlayerDark.swf you just downloaded. +

      + + +
      diff --git a/web/flowplayer/extras/examples/js/flashembed.min.js b/web/flowplayer/extras/examples/js/flashembed.min.js new file mode 100644 index 0000000..ca2f6d6 --- /dev/null +++ b/web/flowplayer/extras/examples/js/flashembed.min.js @@ -0,0 +1,17 @@ + +/** + * flashembed 0.28. Adobe Flash embedding script + * + * http://flowplayer.org/tools/flash-embed.html + * + * Copyright (c) 2008 Tero Piirainen (tero@flowplayer.org) + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * >> Basically you can do anything you want but leave this header as is << + * + * Since: 03/11/2008 + * Version: 0.28 05/26/2008 + */ +function flashembed(g,h,j){if(typeof g=='string')g=document.getElementById(g);var k={src:'#',width:'100%',height:'100%',version:null,loadEvent:null,onFail:null,expressInstall:null,allowfullscreen:true,allowscriptaccess:'always',quality:'high',bgcolor:'#ffffff',type:'application/x-shockwave-flash',pluginspage:'http://www.adobe.com/go/getflashplayer'};extend(k,h);var l=k.loadEvent;k.loadEvent=null;if(l){if(!g)return;g['on'+l]=function(){return load()}}else{return load()}function extend(a,b){if(b){for(key in b){a[key]=b[key]}}}function load(){var a=getVersion();var b=k.version;var c=k.expressInstall;if(!g)return;if(!b||isSupported(b)){k.onFail=k.version=k.expressInstall=null;g.innerHTML=getHTML();return g.firstChild}else if(k.onFail){var d=k.onFail.call(k,getVersion(),j);if(d)g.innerHTML=d}else if(b&&c&&isSupported([6,65])){extend(k,{src:c});j={MMredirectURL:location.href,MMplayerType:'PlugIn',MMdoctitle:document.title};g.innerHTML=getHTML()}else{if(g.innerHTML.replace(/\s/g,'')!=''){}else{g.innerHTML="

      Flash version "+b+" or greater is required

      "+"

      "+(a[0]>0?"Your version is "+a:"You have no flash plugin installed")+"

      "+"

      Download latest version from here

      "}}g['on'+l]=null}function isSupported(a){var b=getVersion();var c=(b[0]>a[0])||(b[0]==a[0]&&b[1]>=a[1]);return c}function getHTML(){var a="";if(typeof j=='function')j=j();if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){a=''}else{a='';k.id=k.src=k.width=k.height=null;for(var b in k){if(k[b]!=null)a+='\n\t'}if(j){a+='\n\t'}a+=""}return a}function getVersion(){var a=[0,0];if(navigator.plugins&&typeof navigator.plugins["Shockwave Flash"]=="object"){var b=navigator.plugins["Shockwave Flash"].description;if(typeof b!="undefined"){b=b.replace(/^.*\s+(\S+\s+\S+$)/,"$1");var c=parseInt(b.replace(/^(.*)\..*$/,"$1"),10);var d=/r/.test(b)?parseInt(b.replace(/^.*r(.*)$/,"$1"),10):0;a=[c,d]}}else if(window.ActiveXObject){try{var f=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7")}catch(e){try{var f=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");a=[6,0];f.AllowScriptAccess="always"}catch(e){if(a[0]==6)return}try{var f=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")}catch(e){}}if(typeof f=="object"){var b=f.GetVariable("$version");if(typeof b!="undefined"){b=b.replace(/^\S+\s+(.*)$/,"$1").split(",");a=[parseInt(b[0],10),parseInt(b[2],10)]}}}return a}function asString(b){switch(typeOf(b)){case'string':return'"'+b.replace(new RegExp('(["\\\\])','g'),'\\$1')+'"';case'array':return'['+map(b,function(a){return asString(a)}).join(',')+']';case'object':var c=[];for(var d in b){c.push('"'+d+'":'+asString(b[d]))}return'{'+c.join(',')+'}'}return String(b).replace(/\s/g," ").replace(/\'/g,"\"")}function typeOf(a){if(a===null||a===undefined)return false;var b=typeof a;return(b=='object'&&a.push)?'array':b}if(window.attachEvent){window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}})}function map(a,b){var c=[];for(var i in a){c[i]=b(a[i])}return c}flashembed.getVersion=getVersion;flashembed.isSupported=isSupported;return g}if(typeof jQuery=='function'){(function($){$.fn.extend({flashembed:function(a,b){return this.each(function(){new flashembed(this,a,b)})}})})(jQuery)} diff --git a/web/flowplayer/extras/examples/js/flow.embed.js b/web/flowplayer/extras/examples/js/flow.embed.js new file mode 100644 index 0000000..2904bdf --- /dev/null +++ b/web/flowplayer/extras/examples/js/flow.embed.js @@ -0,0 +1,79 @@ + +/** + * flowembed 0.10. Flowplayer embedding script + * + * http://flowplayer.org/tools/flow-embed.html + * + * Copyright (c) 2008 Tero Piirainen (tero@flowplayer.org) + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * >> Basically you can do anything you want but leave this header as is << + * + * Version: 0.10 - 05/19/2008 + */ + +(function($) { + + // jQuery plugin initialization + $.fn.extend({ + flowembed: function(params, config, opts) { + return this.each(function() { + new flowembed($(this), params, config, opts); + }); + } + }); + + + function flowembed(root, params, config, embedOpts) { + + var opts = { + oneInstance: true, + activeClass: 'playing', + overlayClass: 'playButton' + }; + + $.extend(opts, embedOpts); + var player = null; + config = config || {}; + if (typeof params == 'string') params = {src:params}; + + root.click(function(event) { + + // oneInstance previously playing video + if (opts.oneInstance) onClipDone(); + + // save nested HTML content for resuming purposes + root.addClass(opts.activeClass).data("html", root.html()); + + // build flowplayer with videoFile supplied in href- attribute + config.videoFile = root.attr("href"); + + player = flashembed(this, params, {config:config}); + + // disable default behaviour + return false; + + }); + + // create play button on top of splash image + root.append($("
      ").addClass(opts.overlayClass)); + + + /* + this function is called by Flowplayer when playback finishes. + it makes currently playing video to oneInstance it's original + HTML stage. + */ + if (opts.oneInstance && !$.isFunction("onClipDone")) { + window.onClipDone = function() { + $("." + opts.activeClass).each(function() { + $(this).html($(this).data("html")).removeClass(opts.activeClass); + }); + }; + } + } + +})(jQuery); + diff --git a/web/flowplayer/extras/examples/js/flow.playlist.js b/web/flowplayer/extras/examples/js/flow.playlist.js new file mode 100644 index 0000000..36a14e6 --- /dev/null +++ b/web/flowplayer/extras/examples/js/flow.playlist.js @@ -0,0 +1,126 @@ + +/** + * flowembed 0.10. Flowplayer playlist script + * + * http://flowplayer.org/tools/flow-playlist.html + * + * Copyright (c) 2008 Tero Piirainen (tero@flowplayer.org) + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * >> Basically you can do anything you want but leave this header as is << + * + * Version: 0.10 - 05/19/2008 + */ +(function($) { + + // plugin initialization + $.fn.extend({ + playlist: function(params, config, opts) { + return this.each(function() { + new playlist($(this), params, config, opts); + }); + } + }); + + + function playlist(root, params, config, playlistOpts) { + + var player = null; + + var opts = { + playingClass: 'playing', + pausedClass: 'paused', + player: '#player', + loop:false + } + + opts = $.extend(opts, playlistOpts); + + config = config || {}; + if (typeof params == 'string') params = {src:params}; + + if (!$(opts.player).length) { + alert("flow.playlist not configured properly\nnonexisting element " + opts.player); + return; + } + + var items = root.children(); + if (items.is(".__scrollable")) items = root.children().children(); + + items.click(function(event) { + + var el = $(this); + + // toggle play pause action + if (player && el.hasClass(opts.playingClass)) { + if (player.getIsPaused()) player.DoPlay(); + else player.Pause(); + return false; + } + + // toggle playing state + el.parent().find("." + opts.playingClass) + .removeClass(opts.playingClass) + .removeClass(opts.pausedClass) + ; + + el.addClass(opts.playingClass); + + config.videoFile = el.attr("href"); + + if (player == null) { + player = flashembed($(opts.player)[0], params, {config:config}); + + } else { + player.setConfig(config); + } + + // setup callback methods + window.onClipDone = function() { + el.removeClass(opts.playingClass).removeClass(opts.pausedClass); + + // move to next entry if it exists + if (el.next().length) el.next().click(); + + // else reset player + else { + if (opts.loop) { + items.eq(0).click(); + + } else { + player.DoStop(); + player.Seek(0); + } + } + + + // omit player's default behaviour (since version 2.2) + return false; + } + + window.onPause = function() { + if (el.hasClass(opts.playingClass)) el.addClass(opts.pausedClass); + } + + window.onResume = function() { + el.removeClass(opts.pausedClass); + } + + // disable default behaviour + return false; + + }); + + // clicking on the player clicks on the first playlist entry + $(opts.player).click(function(event) { + event.preventDefault(); + items.eq(0).click(); + }); + + } + + +})(jQuery); + diff --git a/web/flowplayer/extras/examples/js/jquery.mousewheel.js b/web/flowplayer/extras/examples/js/jquery.mousewheel.js new file mode 100644 index 0000000..6a73c3c --- /dev/null +++ b/web/flowplayer/extras/examples/js/jquery.mousewheel.js @@ -0,0 +1,85 @@ +/* Copyright (c) 2006 Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * + * $LastChangedDate: 2007-12-20 09:02:08 -0600 (Thu, 20 Dec 2007) $ + * $Rev: 4265 $ + * + * Version: 3.0 + * + * Requires: $ 1.2.2+ + */ + +(function($) { + +$.event.special.mousewheel = { + setup: function() { + var handler = $.event.special.mousewheel.handler; + + // Fix pageX, pageY, clientX and clientY for mozilla + if ( $.browser.mozilla ) + $(this).bind('mousemove.mousewheel', function(event) { + $.data(this, 'mwcursorposdata', { + pageX: event.pageX, + pageY: event.pageY, + clientX: event.clientX, + clientY: event.clientY + }); + }); + + if ( this.addEventListener ) + this.addEventListener( ($.browser.mozilla ? 'DOMMouseScroll' : 'mousewheel'), handler, false); + else + this.onmousewheel = handler; + }, + + teardown: function() { + var handler = $.event.special.mousewheel.handler; + + $(this).unbind('mousemove.mousewheel'); + + if ( this.removeEventListener ) + this.removeEventListener( ($.browser.mozilla ? 'DOMMouseScroll' : 'mousewheel'), handler, false); + else + this.onmousewheel = function(){}; + + $.removeData(this, 'mwcursorposdata'); + }, + + handler: function(event) { + var args = Array.prototype.slice.call( arguments, 1 ); + + event = $.event.fix(event || window.event); + // Get correct pageX, pageY, clientX and clientY for mozilla + $.extend( event, $.data(this, 'mwcursorposdata') || {} ); + var delta = 0, returnValue = true; + + if ( event.wheelDelta ) delta = event.wheelDelta/120; + if ( event.detail ) delta = -event.detail/3; + if ( $.browser.opera ) delta = -event.wheelDelta; + + event.data = event.data || {}; + event.type = "mousewheel"; + + // Add delta to the front of the arguments + args.unshift(delta); + // Add event to the front of the arguments + args.unshift(event); + + return $.event.handle.apply(this, args); + } +}; + +$.fn.extend({ + mousewheel: function(fn) { + return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); + }, + + unmousewheel: function(fn) { + return this.unbind("mousewheel", fn); + } +}); + +})(jQuery); \ No newline at end of file diff --git a/web/flowplayer/extras/examples/js/jquery.pack.js b/web/flowplayer/extras/examples/js/jquery.pack.js new file mode 100644 index 0000000..72dc44b --- /dev/null +++ b/web/flowplayer/extras/examples/js/jquery.pack.js @@ -0,0 +1,11 @@ +/* + * jQuery 1.2.6 - New Wave Javascript + * + * Copyright (c) 2008 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2008/05/28 07:31:05 $ + * $Rev: 5685 $ + */ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(H(){J w=1b.4M,3m$=1b.$;J D=1b.4M=1b.$=H(a,b){I 2B D.17.5j(a,b)};J u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/,62=/^.[^:#\\[\\.]*$/,12;D.17=D.44={5j:H(d,b){d=d||S;G(d.16){7[0]=d;7.K=1;I 7}G(1j d=="23"){J c=u.2D(d);G(c&&(c[1]||!b)){G(c[1])d=D.4h([c[1]],b);N{J a=S.61(c[3]);G(a){G(a.2v!=c[3])I D().2q(d);I D(a)}d=[]}}N I D(b).2q(d)}N G(D.1D(d))I D(S)[D.17.27?"27":"43"](d);I 7.6Y(D.2d(d))},5w:"1.2.6",8G:H(){I 7.K},K:0,3p:H(a){I a==12?D.2d(7):7[a]},2I:H(b){J a=D(b);a.5n=7;I a},6Y:H(a){7.K=0;2p.44.1p.1w(7,a);I 7},P:H(a,b){I D.P(7,a,b)},5i:H(b){J a=-1;I D.2L(b&&b.5w?b[0]:b,7)},1K:H(c,a,b){J d=c;G(c.1q==56)G(a===12)I 7[0]&&D[b||"1K"](7[0],c);N{d={};d[c]=a}I 7.P(H(i){R(c 1n d)D.1K(b?7.V:7,c,D.1i(7,d[c],b,i,c))})},1g:H(b,a){G((b==\'2h\'||b==\'1Z\')&&3d(a)<0)a=12;I 7.1K(b,a,"2a")},1r:H(b){G(1j b!="49"&&b!=U)I 7.4E().3v((7[0]&&7[0].2z||S).5F(b));J a="";D.P(b||7,H(){D.P(7.3t,H(){G(7.16!=8)a+=7.16!=1?7.76:D.17.1r([7])})});I a},5z:H(b){G(7[0])D(b,7[0].2z).5y().39(7[0]).2l(H(){J a=7;1B(a.1x)a=a.1x;I a}).3v(7);I 7},8Y:H(a){I 7.P(H(){D(7).6Q().5z(a)})},8R:H(a){I 7.P(H(){D(7).5z(a)})},3v:H(){I 7.3W(19,M,Q,H(a){G(7.16==1)7.3U(a)})},6F:H(){I 7.3W(19,M,M,H(a){G(7.16==1)7.39(a,7.1x)})},6E:H(){I 7.3W(19,Q,Q,H(a){7.1d.39(a,7)})},5q:H(){I 7.3W(19,Q,M,H(a){7.1d.39(a,7.2H)})},3l:H(){I 7.5n||D([])},2q:H(b){J c=D.2l(7,H(a){I D.2q(b,a)});I 7.2I(/[^+>] [^+>]/.11(b)||b.1h("..")>-1?D.4r(c):c)},5y:H(e){J f=7.2l(H(){G(D.14.1f&&!D.4n(7)){J a=7.6o(M),5h=S.3h("1v");5h.3U(a);I D.4h([5h.4H])[0]}N I 7.6o(M)});J d=f.2q("*").5c().P(H(){G(7[E]!=12)7[E]=U});G(e===M)7.2q("*").5c().P(H(i){G(7.16==3)I;J c=D.L(7,"3w");R(J a 1n c)R(J b 1n c[a])D.W.1e(d[i],a,c[a][b],c[a][b].L)});I f},1E:H(b){I 7.2I(D.1D(b)&&D.3C(7,H(a,i){I b.1k(a,i)})||D.3g(b,7))},4Y:H(b){G(b.1q==56)G(62.11(b))I 7.2I(D.3g(b,7,M));N b=D.3g(b,7);J a=b.K&&b[b.K-1]!==12&&!b.16;I 7.1E(H(){I a?D.2L(7,b)<0:7!=b})},1e:H(a){I 7.2I(D.4r(D.2R(7.3p(),1j a==\'23\'?D(a):D.2d(a))))},3F:H(a){I!!a&&D.3g(a,7).K>0},7T:H(a){I 7.3F("."+a)},6e:H(b){G(b==12){G(7.K){J c=7[0];G(D.Y(c,"2A")){J e=c.64,63=[],15=c.15,2V=c.O=="2A-2V";G(e<0)I U;R(J i=2V?e:0,2f=2V?e+1:15.K;i<2f;i++){J d=15[i];G(d.2W){b=D.14.1f&&!d.at.2x.an?d.1r:d.2x;G(2V)I b;63.1p(b)}}I 63}N I(7[0].2x||"").1o(/\\r/g,"")}I 12}G(b.1q==4L)b+=\'\';I 7.P(H(){G(7.16!=1)I;G(b.1q==2p&&/5O|5L/.11(7.O))7.4J=(D.2L(7.2x,b)>=0||D.2L(7.34,b)>=0);N G(D.Y(7,"2A")){J a=D.2d(b);D("9R",7).P(H(){7.2W=(D.2L(7.2x,a)>=0||D.2L(7.1r,a)>=0)});G(!a.K)7.64=-1}N 7.2x=b})},2K:H(a){I a==12?(7[0]?7[0].4H:U):7.4E().3v(a)},7b:H(a){I 7.5q(a).21()},79:H(i){I 7.3s(i,i+1)},3s:H(){I 7.2I(2p.44.3s.1w(7,19))},2l:H(b){I 7.2I(D.2l(7,H(a,i){I b.1k(a,i,a)}))},5c:H(){I 7.1e(7.5n)},L:H(d,b){J a=d.1R(".");a[1]=a[1]?"."+a[1]:"";G(b===12){J c=7.5C("9z"+a[1]+"!",[a[0]]);G(c===12&&7.K)c=D.L(7[0],d);I c===12&&a[1]?7.L(a[0]):c}N I 7.1P("9u"+a[1]+"!",[a[0],b]).P(H(){D.L(7,d,b)})},3b:H(a){I 7.P(H(){D.3b(7,a)})},3W:H(g,f,h,d){J e=7.K>1,3x;I 7.P(H(){G(!3x){3x=D.4h(g,7.2z);G(h)3x.9o()}J b=7;G(f&&D.Y(7,"1T")&&D.Y(3x[0],"4F"))b=7.3H("22")[0]||7.3U(7.2z.3h("22"));J c=D([]);D.P(3x,H(){J a=e?D(7).5y(M)[0]:7;G(D.Y(a,"1m"))c=c.1e(a);N{G(a.16==1)c=c.1e(D("1m",a).21());d.1k(b,a)}});c.P(6T)})}};D.17.5j.44=D.17;H 6T(i,a){G(a.4d)D.3Y({1a:a.4d,31:Q,1O:"1m"});N D.5u(a.1r||a.6O||a.4H||"");G(a.1d)a.1d.37(a)}H 1z(){I+2B 8J}D.1l=D.17.1l=H(){J b=19[0]||{},i=1,K=19.K,4x=Q,15;G(b.1q==8I){4x=b;b=19[1]||{};i=2}G(1j b!="49"&&1j b!="H")b={};G(K==i){b=7;--i}R(;i-1}},6q:H(b,c,a){J e={};R(J d 1n c){e[d]=b.V[d];b.V[d]=c[d]}a.1k(b);R(J d 1n c)b.V[d]=e[d]},1g:H(d,e,c){G(e=="2h"||e=="1Z"){J b,3X={30:"5x",5g:"1G",18:"3I"},35=e=="2h"?["5e","6k"]:["5G","6i"];H 5b(){b=e=="2h"?d.8f:d.8c;J a=0,2C=0;D.P(35,H(){a+=3d(D.2a(d,"57"+7,M))||0;2C+=3d(D.2a(d,"2C"+7+"4b",M))||0});b-=29.83(a+2C)}G(D(d).3F(":4j"))5b();N D.6q(d,3X,5b);I 29.2f(0,b)}I D.2a(d,e,c)},2a:H(f,l,k){J e,V=f.V;H 3E(b){G(!D.14.2k)I Q;J a=3P.54(b,U);I!a||a.52("3E")==""}G(l=="1y"&&D.14.1f){e=D.1K(V,"1y");I e==""?"1":e}G(D.14.2G&&l=="18"){J d=V.50;V.50="0 7Y 7W";V.50=d}G(l.1I(/4i/i))l=y;G(!k&&V&&V[l])e=V[l];N G(3P.54){G(l.1I(/4i/i))l="4i";l=l.1o(/([A-Z])/g,"-$1").3y();J c=3P.54(f,U);G(c&&!3E(f))e=c.52(l);N{J g=[],2E=[],a=f,i=0;R(;a&&3E(a);a=a.1d)2E.6h(a);R(;i<2E.K;i++)G(3E(2E[i])){g[i]=2E[i].V.18;2E[i].V.18="3I"}e=l=="18"&&g[2E.K-1]!=U?"2F":(c&&c.52(l))||"";R(i=0;i]*?)\\/>/g,H(b,a,c){I c.1I(/^(aK|4f|7E|aG|4T|7A|aB|3n|az|ay|av)$/i)?b:a+">"});J f=D.3k(d).3y(),1v=h.3h("1v");J e=!f.1h("",""]||!f.1h("",""]||f.1I(/^<(aq|22|am|ak|ai)/)&&[1,"<1T>",""]||!f.1h("<4F")&&[2,"<1T><22>",""]||(!f.1h("<22><4F>",""]||!f.1h("<7E")&&[2,"<1T><22><7q>",""]||D.14.1f&&[1,"1v<1v>",""]||[0,"",""];1v.4H=e[1]+d+e[2];1B(e[0]--)1v=1v.5T;G(D.14.1f){J g=!f.1h("<1T")&&f.1h("<22")<0?1v.1x&&1v.1x.3t:e[1]=="<1T>"&&f.1h("<22")<0?1v.3t:[];R(J j=g.K-1;j>=0;--j)G(D.Y(g[j],"22")&&!g[j].3t.K)g[j].1d.37(g[j]);G(/^\\s/.11(d))1v.39(h.5F(d.1I(/^\\s*/)[0]),1v.1x)}d=D.2d(1v.3t)}G(d.K===0&&(!D.Y(d,"3V")&&!D.Y(d,"2A")))I;G(d[0]==12||D.Y(d,"3V")||d.15)k.1p(d);N k=D.2R(k,d)});I k},1K:H(d,f,c){G(!d||d.16==3||d.16==8)I 12;J e=!D.4n(d),40=c!==12,1f=D.14.1f;f=e&&D.3X[f]||f;G(d.2j){J g=/5Q|4d|V/.11(f);G(f=="2W"&&D.14.2k)d.1d.64;G(f 1n d&&e&&!g){G(40){G(f=="O"&&D.Y(d,"4T")&&d.1d)7p"O a3 a1\'t 9V 9U";d[f]=c}G(D.Y(d,"3V")&&d.7i(f))I d.7i(f).76;I d[f]}G(1f&&e&&f=="V")I D.1K(d.V,"9T",c);G(40)d.9Q(f,""+c);J h=1f&&e&&g?d.4G(f,2):d.4G(f);I h===U?12:h}G(1f&&f=="1y"){G(40){d.6B=1;d.1E=(d.1E||"").1o(/7f\\([^)]*\\)/,"")+(3r(c)+\'\'=="9L"?"":"7f(1y="+c*7a+")")}I d.1E&&d.1E.1h("1y=")>=0?(3d(d.1E.1I(/1y=([^)]*)/)[1])/7a)+\'\':""}f=f.1o(/-([a-z])/9H,H(a,b){I b.2r()});G(40)d[f]=c;I d[f]},3k:H(a){I(a||"").1o(/^\\s+|\\s+$/g,"")},2d:H(b){J a=[];G(b!=U){J i=b.K;G(i==U||b.1R||b.4I||b.1k)a[0]=b;N 1B(i)a[--i]=b[i]}I a},2L:H(b,a){R(J i=0,K=a.K;i*",7).21();1B(7.1x)7.37(7.1x)}},H(a,b){D.17[a]=H(){I 7.P(b,19)}});D.P(["6N","4b"],H(i,c){J b=c.3y();D.17[b]=H(a){I 7[0]==1b?D.14.2G&&S.1c["5t"+c]||D.14.2k&&1b["5s"+c]||S.70=="6Z"&&S.1C["5t"+c]||S.1c["5t"+c]:7[0]==S?29.2f(29.2f(S.1c["4y"+c],S.1C["4y"+c]),29.2f(S.1c["2i"+c],S.1C["2i"+c])):a==12?(7.K?D.1g(7[0],b):U):7.1g(b,a.1q==56?a:a+"2X")}});H 25(a,b){I a[0]&&3r(D.2a(a[0],b,M),10)||0}J C=D.14.2k&&3r(D.14.5B)<8H?"(?:[\\\\w*3m-]|\\\\\\\\.)":"(?:[\\\\w\\8F-\\8E*3m-]|\\\\\\\\.)",6L=2B 4v("^>\\\\s*("+C+"+)"),6J=2B 4v("^("+C+"+)(#)("+C+"+)"),6I=2B 4v("^([#.]?)("+C+"*)");D.1l({6H:{"":H(a,i,m){I m[2]=="*"||D.Y(a,m[2])},"#":H(a,i,m){I a.4G("2v")==m[2]},":":{8D:H(a,i,m){I im[3]-0},3a:H(a,i,m){I m[3]-0==i},79:H(a,i,m){I m[3]-0==i},3o:H(a,i){I i==0},3S:H(a,i,m,r){I i==r.K-1},6D:H(a,i){I i%2==0},6C:H(a,i){I i%2},"3o-4u":H(a){I a.1d.3H("*")[0]==a},"3S-4u":H(a){I D.3a(a.1d.5T,1,"4l")==a},"8z-4u":H(a){I!D.3a(a.1d.5T,2,"4l")},6W:H(a){I a.1x},4E:H(a){I!a.1x},8y:H(a,i,m){I(a.6O||a.8x||D(a).1r()||"").1h(m[3])>=0},4j:H(a){I"1G"!=a.O&&D.1g(a,"18")!="2F"&&D.1g(a,"5g")!="1G"},1G:H(a){I"1G"==a.O||D.1g(a,"18")=="2F"||D.1g(a,"5g")=="1G"},8w:H(a){I!a.3R},3R:H(a){I a.3R},4J:H(a){I a.4J},2W:H(a){I a.2W||D.1K(a,"2W")},1r:H(a){I"1r"==a.O},5O:H(a){I"5O"==a.O},5L:H(a){I"5L"==a.O},5p:H(a){I"5p"==a.O},3Q:H(a){I"3Q"==a.O},5o:H(a){I"5o"==a.O},6A:H(a){I"6A"==a.O},6z:H(a){I"6z"==a.O},2s:H(a){I"2s"==a.O||D.Y(a,"2s")},4T:H(a){I/4T|2A|6y|2s/i.11(a.Y)},3T:H(a,i,m){I D.2q(m[3],a).K},8t:H(a){I/h\\d/i.11(a.Y)},8s:H(a){I D.3C(D.3O,H(b){I a==b.T}).K}}},6x:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,2B 4v("^([:.#]*)("+C+"+)")],3g:H(a,c,b){J d,1t=[];1B(a&&a!=d){d=a;J f=D.1E(a,c,b);a=f.t.1o(/^\\s*,\\s*/,"");1t=b?c=f.r:D.2R(1t,f.r)}I 1t},2q:H(t,o){G(1j t!="23")I[t];G(o&&o.16!=1&&o.16!=9)I[];o=o||S;J d=[o],2o=[],3S,Y;1B(t&&3S!=t){J r=[];3S=t;t=D.3k(t);J l=Q,3j=6L,m=3j.2D(t);G(m){Y=m[1].2r();R(J i=0;d[i];i++)R(J c=d[i].1x;c;c=c.2H)G(c.16==1&&(Y=="*"||c.Y.2r()==Y))r.1p(c);d=r;t=t.1o(3j,"");G(t.1h(" ")==0)6M;l=M}N{3j=/^([>+~])\\s*(\\w*)/i;G((m=3j.2D(t))!=U){r=[];J k={};Y=m[2].2r();m=m[1];R(J j=0,3i=d.K;j<3i;j++){J n=m=="~"||m=="+"?d[j].2H:d[j].1x;R(;n;n=n.2H)G(n.16==1){J g=D.L(n);G(m=="~"&&k[g])1X;G(!Y||n.Y.2r()==Y){G(m=="~")k[g]=M;r.1p(n)}G(m=="+")1X}}d=r;t=D.3k(t.1o(3j,""));l=M}}G(t&&!l){G(!t.1h(",")){G(o==d[0])d.4s();2o=D.2R(2o,d);r=d=[o];t=" "+t.6v(1,t.K)}N{J h=6J;J m=h.2D(t);G(m){m=[0,m[2],m[3],m[1]]}N{h=6I;m=h.2D(t)}m[2]=m[2].1o(/\\\\/g,"");J f=d[d.K-1];G(m[1]=="#"&&f&&f.61&&!D.4n(f)){J p=f.61(m[2]);G((D.14.1f||D.14.2G)&&p&&1j p.2v=="23"&&p.2v!=m[2])p=D(\'[@2v="\'+m[2]+\'"]\',f)[0];d=r=p&&(!m[3]||D.Y(p,m[3]))?[p]:[]}N{R(J i=0;d[i];i++){J a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];G(a=="*"&&d[i].Y.3y()=="49")a="3n";r=D.2R(r,d[i].3H(a))}G(m[1]==".")r=D.5m(r,m[2]);G(m[1]=="#"){J e=[];R(J i=0;r[i];i++)G(r[i].4G("2v")==m[2]){e=[r[i]];1X}r=e}d=r}t=t.1o(h,"")}}G(t){J b=D.1E(t,r);d=r=b.r;t=D.3k(b.t)}}G(t)d=[];G(d&&o==d[0])d.4s();2o=D.2R(2o,d);I 2o},5m:H(r,m,a){m=" "+m+" ";J c=[];R(J i=0;r[i];i++){J b=(" "+r[i].1F+" ").1h(m)>=0;G(!a&&b||a&&!b)c.1p(r[i])}I c},1E:H(t,r,h){J d;1B(t&&t!=d){d=t;J p=D.6x,m;R(J i=0;p[i];i++){m=p[i].2D(t);G(m){t=t.8r(m[0].K);m[2]=m[2].1o(/\\\\/g,"");1X}}G(!m)1X;G(m[1]==":"&&m[2]=="4Y")r=62.11(m[3])?D.1E(m[3],r,M).r:D(r).4Y(m[3]);N G(m[1]==".")r=D.5m(r,m[2],h);N G(m[1]=="["){J g=[],O=m[3];R(J i=0,3i=r.K;i<3i;i++){J a=r[i],z=a[D.3X[m[2]]||m[2]];G(z==U||/5Q|4d|2W/.11(m[2]))z=D.1K(a,m[2])||\'\';G((O==""&&!!z||O=="="&&z==m[5]||O=="!="&&z!=m[5]||O=="^="&&z&&!z.1h(m[5])||O=="$="&&z.6v(z.K-m[5].K)==m[5]||(O=="*="||O=="~=")&&z.1h(m[5])>=0)^h)g.1p(a)}r=g}N G(m[1]==":"&&m[2]=="3a-4u"){J e={},g=[],11=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.2D(m[3]=="6D"&&"2n"||m[3]=="6C"&&"2n+1"||!/\\D/.11(m[3])&&"8q+"+m[3]||m[3]),3o=(11[1]+(11[2]||1))-0,d=11[3]-0;R(J i=0,3i=r.K;i<3i;i++){J j=r[i],1d=j.1d,2v=D.L(1d);G(!e[2v]){J c=1;R(J n=1d.1x;n;n=n.2H)G(n.16==1)n.4q=c++;e[2v]=M}J b=Q;G(3o==0){G(j.4q==d)b=M}N G((j.4q-d)%3o==0&&(j.4q-d)/3o>=0)b=M;G(b^h)g.1p(j)}r=g}N{J f=D.6H[m[1]];G(1j f=="49")f=f[m[2]];G(1j f=="23")f=6u("Q||H(a,i){I "+f+";}");r=D.3C(r,H(a,i){I f(a,i,m,r)},h)}}I{r:r,t:t}},4S:H(b,c){J a=[],1t=b[c];1B(1t&&1t!=S){G(1t.16==1)a.1p(1t);1t=1t[c]}I a},3a:H(a,e,c,b){e=e||1;J d=0;R(;a;a=a[c])G(a.16==1&&++d==e)1X;I a},5v:H(n,a){J r=[];R(;n;n=n.2H){G(n.16==1&&n!=a)r.1p(n)}I r}});D.W={1e:H(f,i,g,e){G(f.16==3||f.16==8)I;G(D.14.1f&&f.4I)f=1b;G(!g.24)g.24=7.24++;G(e!=12){J h=g;g=7.3M(h,H(){I h.1w(7,19)});g.L=e}J j=D.L(f,"3w")||D.L(f,"3w",{}),1H=D.L(f,"1H")||D.L(f,"1H",H(){G(1j D!="12"&&!D.W.5k)I D.W.1H.1w(19.3L.T,19)});1H.T=f;D.P(i.1R(/\\s+/),H(c,b){J a=b.1R(".");b=a[0];g.O=a[1];J d=j[b];G(!d){d=j[b]={};G(!D.W.2t[b]||D.W.2t[b].4p.1k(f)===Q){G(f.3K)f.3K(b,1H,Q);N G(f.6t)f.6t("4o"+b,1H)}}d[g.24]=g;D.W.26[b]=M});f=U},24:1,26:{},21:H(e,h,f){G(e.16==3||e.16==8)I;J i=D.L(e,"3w"),1L,5i;G(i){G(h==12||(1j h=="23"&&h.8p(0)=="."))R(J g 1n i)7.21(e,g+(h||""));N{G(h.O){f=h.2y;h=h.O}D.P(h.1R(/\\s+/),H(b,a){J c=a.1R(".");a=c[0];G(i[a]){G(f)2U i[a][f.24];N R(f 1n i[a])G(!c[1]||i[a][f].O==c[1])2U i[a][f];R(1L 1n i[a])1X;G(!1L){G(!D.W.2t[a]||D.W.2t[a].4A.1k(e)===Q){G(e.6p)e.6p(a,D.L(e,"1H"),Q);N G(e.6n)e.6n("4o"+a,D.L(e,"1H"))}1L=U;2U i[a]}}})}R(1L 1n i)1X;G(!1L){J d=D.L(e,"1H");G(d)d.T=U;D.3b(e,"3w");D.3b(e,"1H")}}},1P:H(h,c,f,g,i){c=D.2d(c);G(h.1h("!")>=0){h=h.3s(0,-1);J a=M}G(!f){G(7.26[h])D("*").1e([1b,S]).1P(h,c)}N{G(f.16==3||f.16==8)I 12;J b,1L,17=D.1D(f[h]||U),W=!c[0]||!c[0].32;G(W){c.6h({O:h,2J:f,32:H(){},3J:H(){},4C:1z()});c[0][E]=M}c[0].O=h;G(a)c[0].6m=M;J d=D.L(f,"1H");G(d)b=d.1w(f,c);G((!17||(D.Y(f,\'a\')&&h=="4V"))&&f["4o"+h]&&f["4o"+h].1w(f,c)===Q)b=Q;G(W)c.4s();G(i&&D.1D(i)){1L=i.1w(f,b==U?c:c.7d(b));G(1L!==12)b=1L}G(17&&g!==Q&&b!==Q&&!(D.Y(f,\'a\')&&h=="4V")){7.5k=M;1U{f[h]()}1V(e){}}7.5k=Q}I b},1H:H(b){J a,1L,38,5f,4m;b=19[0]=D.W.6l(b||1b.W);38=b.O.1R(".");b.O=38[0];38=38[1];5f=!38&&!b.6m;4m=(D.L(7,"3w")||{})[b.O];R(J j 1n 4m){J c=4m[j];G(5f||c.O==38){b.2y=c;b.L=c.L;1L=c.1w(7,19);G(a!==Q)a=1L;G(1L===Q){b.32();b.3J()}}}I a},6l:H(b){G(b[E]==M)I b;J d=b;b={8o:d};J c="8n 8m 8l 8k 2s 8j 47 5d 6j 5E 8i L 8h 8g 4K 2y 5a 59 8e 8b 58 6f 8a 88 4k 87 86 84 6d 2J 4C 6c O 82 81 35".1R(" ");R(J i=c.K;i;i--)b[c[i]]=d[c[i]];b[E]=M;b.32=H(){G(d.32)d.32();d.80=Q};b.3J=H(){G(d.3J)d.3J();d.7Z=M};b.4C=b.4C||1z();G(!b.2J)b.2J=b.6d||S;G(b.2J.16==3)b.2J=b.2J.1d;G(!b.4k&&b.4K)b.4k=b.4K==b.2J?b.6c:b.4K;G(b.58==U&&b.5d!=U){J a=S.1C,1c=S.1c;b.58=b.5d+(a&&a.2e||1c&&1c.2e||0)-(a.6b||0);b.6f=b.6j+(a&&a.2c||1c&&1c.2c||0)-(a.6a||0)}G(!b.35&&((b.47||b.47===0)?b.47:b.5a))b.35=b.47||b.5a;G(!b.59&&b.5E)b.59=b.5E;G(!b.35&&b.2s)b.35=(b.2s&1?1:(b.2s&2?3:(b.2s&4?2:0)));I b},3M:H(a,b){b.24=a.24=a.24||b.24||7.24++;I b},2t:{27:{4p:H(){55();I},4A:H(){I}},3D:{4p:H(){G(D.14.1f)I Q;D(7).2O("53",D.W.2t.3D.2y);I M},4A:H(){G(D.14.1f)I Q;D(7).4e("53",D.W.2t.3D.2y);I M},2y:H(a){G(F(a,7))I M;a.O="3D";I D.W.1H.1w(7,19)}},3N:{4p:H(){G(D.14.1f)I Q;D(7).2O("51",D.W.2t.3N.2y);I M},4A:H(){G(D.14.1f)I Q;D(7).4e("51",D.W.2t.3N.2y);I M},2y:H(a){G(F(a,7))I M;a.O="3N";I D.W.1H.1w(7,19)}}}};D.17.1l({2O:H(c,a,b){I c=="4X"?7.2V(c,a,b):7.P(H(){D.W.1e(7,c,b||a,b&&a)})},2V:H(d,b,c){J e=D.W.3M(c||b,H(a){D(7).4e(a,e);I(c||b).1w(7,19)});I 7.P(H(){D.W.1e(7,d,e,c&&b)})},4e:H(a,b){I 7.P(H(){D.W.21(7,a,b)})},1P:H(c,a,b){I 7.P(H(){D.W.1P(c,a,7,M,b)})},5C:H(c,a,b){I 7[0]&&D.W.1P(c,a,7[0],Q,b)},2m:H(b){J c=19,i=1;1B(i=0){J i=g.3s(e,g.K);g=g.3s(0,e)}c=c||H(){};J f="2P";G(d)G(D.1D(d)){c=d;d=U}N{d=D.3n(d);f="6g"}J h=7;D.3Y({1a:g,O:f,1O:"2K",L:d,1J:H(a,b){G(b=="1W"||b=="7J")h.2K(i?D("<1v/>").3v(a.4U.1o(/<1m(.|\\s)*?\\/1m>/g,"")).2q(i):a.4U);h.P(c,[a.4U,b,a])}});I 7},aL:H(){I D.3n(7.7I())},7I:H(){I 7.2l(H(){I D.Y(7,"3V")?D.2d(7.aH):7}).1E(H(){I 7.34&&!7.3R&&(7.4J||/2A|6y/i.11(7.Y)||/1r|1G|3Q/i.11(7.O))}).2l(H(i,c){J b=D(7).6e();I b==U?U:b.1q==2p?D.2l(b,H(a,i){I{34:c.34,2x:a}}):{34:c.34,2x:b}}).3p()}});D.P("7H,7G,7F,7D,7C,7B".1R(","),H(i,o){D.17[o]=H(f){I 7.2O(o,f)}});J B=1z();D.1l({3p:H(d,b,a,c){G(D.1D(b)){a=b;b=U}I D.3Y({O:"2P",1a:d,L:b,1W:a,1O:c})},aE:H(b,a){I D.3p(b,U,a,"1m")},aD:H(c,b,a){I D.3p(c,b,a,"3z")},aC:H(d,b,a,c){G(D.1D(b)){a=b;b={}}I D.3Y({O:"6g",1a:d,L:b,1W:a,1O:c})},aA:H(a){D.1l(D.60,a)},60:{1a:5Z.5Q,26:M,O:"2P",2T:0,7z:"4R/x-ax-3V-aw",7x:M,31:M,L:U,5Y:U,3Q:U,4Q:{2N:"4R/2N, 1r/2N",2K:"1r/2K",1m:"1r/4t, 4R/4t",3z:"4R/3z, 1r/4t",1r:"1r/as",4w:"*/*"}},4z:{},3Y:H(s){s=D.1l(M,s,D.1l(M,{},D.60,s));J g,2Z=/=\\?(&|$)/g,1u,L,O=s.O.2r();G(s.L&&s.7x&&1j s.L!="23")s.L=D.3n(s.L);G(s.1O=="4P"){G(O=="2P"){G(!s.1a.1I(2Z))s.1a+=(s.1a.1I(/\\?/)?"&":"?")+(s.4P||"7u")+"=?"}N G(!s.L||!s.L.1I(2Z))s.L=(s.L?s.L+"&":"")+(s.4P||"7u")+"=?";s.1O="3z"}G(s.1O=="3z"&&(s.L&&s.L.1I(2Z)||s.1a.1I(2Z))){g="4P"+B++;G(s.L)s.L=(s.L+"").1o(2Z,"="+g+"$1");s.1a=s.1a.1o(2Z,"="+g+"$1");s.1O="1m";1b[g]=H(a){L=a;1W();1J();1b[g]=12;1U{2U 1b[g]}1V(e){}G(i)i.37(h)}}G(s.1O=="1m"&&s.1Y==U)s.1Y=Q;G(s.1Y===Q&&O=="2P"){J j=1z();J k=s.1a.1o(/(\\?|&)3m=.*?(&|$)/,"$ap="+j+"$2");s.1a=k+((k==s.1a)?(s.1a.1I(/\\?/)?"&":"?")+"3m="+j:"")}G(s.L&&O=="2P"){s.1a+=(s.1a.1I(/\\?/)?"&":"?")+s.L;s.L=U}G(s.26&&!D.4O++)D.W.1P("7H");J n=/^(?:\\w+:)?\\/\\/([^\\/?#]+)/;G(s.1O=="1m"&&O=="2P"&&n.11(s.1a)&&n.2D(s.1a)[1]!=5Z.al){J i=S.3H("6w")[0];J h=S.3h("1m");h.4d=s.1a;G(s.7t)h.aj=s.7t;G(!g){J l=Q;h.ah=h.ag=H(){G(!l&&(!7.3f||7.3f=="68"||7.3f=="1J")){l=M;1W();1J();i.37(h)}}}i.3U(h);I 12}J m=Q;J c=1b.7s?2B 7s("ae.ac"):2B 7r();G(s.5Y)c.6R(O,s.1a,s.31,s.5Y,s.3Q);N c.6R(O,s.1a,s.31);1U{G(s.L)c.4B("ab-aa",s.7z);G(s.5S)c.4B("a9-5R-a8",D.4z[s.1a]||"a7, a6 a5 a4 5N:5N:5N a2");c.4B("X-9Z-9Y","7r");c.4B("9W",s.1O&&s.4Q[s.1O]?s.4Q[s.1O]+", */*":s.4Q.4w)}1V(e){}G(s.7m&&s.7m(c,s)===Q){s.26&&D.4O--;c.7l();I Q}G(s.26)D.W.1P("7B",[c,s]);J d=H(a){G(!m&&c&&(c.3f==4||a=="2T")){m=M;G(f){7k(f);f=U}1u=a=="2T"&&"2T"||!D.7j(c)&&"3e"||s.5S&&D.7h(c,s.1a)&&"7J"||"1W";G(1u=="1W"){1U{L=D.6X(c,s.1O,s.9S)}1V(e){1u="5J"}}G(1u=="1W"){J b;1U{b=c.5I("7g-5R")}1V(e){}G(s.5S&&b)D.4z[s.1a]=b;G(!g)1W()}N D.5H(s,c,1u);1J();G(s.31)c=U}};G(s.31){J f=4I(d,13);G(s.2T>0)3B(H(){G(c){c.7l();G(!m)d("2T")}},s.2T)}1U{c.9P(s.L)}1V(e){D.5H(s,c,U,e)}G(!s.31)d();H 1W(){G(s.1W)s.1W(L,1u);G(s.26)D.W.1P("7C",[c,s])}H 1J(){G(s.1J)s.1J(c,1u);G(s.26)D.W.1P("7F",[c,s]);G(s.26&&!--D.4O)D.W.1P("7G")}I c},5H:H(s,a,b,e){G(s.3e)s.3e(a,b,e);G(s.26)D.W.1P("7D",[a,s,e])},4O:0,7j:H(a){1U{I!a.1u&&5Z.9O=="5p:"||(a.1u>=7e&&a.1u<9N)||a.1u==7c||a.1u==9K||D.14.2k&&a.1u==12}1V(e){}I Q},7h:H(a,c){1U{J b=a.5I("7g-5R");I a.1u==7c||b==D.4z[c]||D.14.2k&&a.1u==12}1V(e){}I Q},6X:H(a,c,b){J d=a.5I("9J-O"),2N=c=="2N"||!c&&d&&d.1h("2N")>=0,L=2N?a.9I:a.4U;G(2N&&L.1C.2j=="5J")7p"5J";G(b)L=b(L,c);G(c=="1m")D.5u(L);G(c=="3z")L=6u("("+L+")");I L},3n:H(a){J s=[];G(a.1q==2p||a.5w)D.P(a,H(){s.1p(3u(7.34)+"="+3u(7.2x))});N R(J j 1n a)G(a[j]&&a[j].1q==2p)D.P(a[j],H(){s.1p(3u(j)+"="+3u(7))});N s.1p(3u(j)+"="+3u(D.1D(a[j])?a[j]():a[j]));I s.6s("&").1o(/%20/g,"+")}});D.17.1l({1N:H(c,b){I c?7.2g({1Z:"1N",2h:"1N",1y:"1N"},c,b):7.1E(":1G").P(H(){7.V.18=7.5D||"";G(D.1g(7,"18")=="2F"){J a=D("<"+7.2j+" />").6P("1c");7.V.18=a.1g("18");G(7.V.18=="2F")7.V.18="3I";a.21()}}).3l()},1M:H(b,a){I b?7.2g({1Z:"1M",2h:"1M",1y:"1M"},b,a):7.1E(":4j").P(H(){7.5D=7.5D||D.1g(7,"18");7.V.18="2F"}).3l()},78:D.17.2m,2m:H(a,b){I D.1D(a)&&D.1D(b)?7.78.1w(7,19):a?7.2g({1Z:"2m",2h:"2m",1y:"2m"},a,b):7.P(H(){D(7)[D(7).3F(":1G")?"1N":"1M"]()})},9G:H(b,a){I 7.2g({1Z:"1N"},b,a)},9F:H(b,a){I 7.2g({1Z:"1M"},b,a)},9E:H(b,a){I 7.2g({1Z:"2m"},b,a)},9D:H(b,a){I 7.2g({1y:"1N"},b,a)},9M:H(b,a){I 7.2g({1y:"1M"},b,a)},9C:H(c,a,b){I 7.2g({1y:a},c,b)},2g:H(k,j,i,g){J h=D.77(j,i,g);I 7[h.36===Q?"P":"36"](H(){G(7.16!=1)I Q;J f=D.1l({},h),p,1G=D(7).3F(":1G"),46=7;R(p 1n k){G(k[p]=="1M"&&1G||k[p]=="1N"&&!1G)I f.1J.1k(7);G(p=="1Z"||p=="2h"){f.18=D.1g(7,"18");f.33=7.V.33}}G(f.33!=U)7.V.33="1G";f.45=D.1l({},k);D.P(k,H(c,a){J e=2B D.28(46,f,c);G(/2m|1N|1M/.11(a))e[a=="2m"?1G?"1N":"1M":a](k);N{J b=a.6r().1I(/^([+-]=)?([\\d+-.]+)(.*)$/),2b=e.1t(M)||0;G(b){J d=3d(b[2]),2M=b[3]||"2X";G(2M!="2X"){46.V[c]=(d||1)+2M;2b=((d||1)/e.1t(M))*2b;46.V[c]=2b+2M}G(b[1])d=((b[1]=="-="?-1:1)*d)+2b;e.3G(2b,d,2M)}N e.3G(2b,a,"")}});I M})},36:H(a,b){G(D.1D(a)||(a&&a.1q==2p)){b=a;a="28"}G(!a||(1j a=="23"&&!b))I A(7[0],a);I 7.P(H(){G(b.1q==2p)A(7,a,b);N{A(7,a).1p(b);G(A(7,a).K==1)b.1k(7)}})},9X:H(b,c){J a=D.3O;G(b)7.36([]);7.P(H(){R(J i=a.K-1;i>=0;i--)G(a[i].T==7){G(c)a[i](M);a.7n(i,1)}});G(!c)7.5A();I 7}});J A=H(b,c,a){G(b){c=c||"28";J q=D.L(b,c+"36");G(!q||a)q=D.L(b,c+"36",D.2d(a))}I q};D.17.5A=H(a){a=a||"28";I 7.P(H(){J q=A(7,a);q.4s();G(q.K)q[0].1k(7)})};D.1l({77:H(b,a,c){J d=b&&b.1q==a0?b:{1J:c||!c&&a||D.1D(b)&&b,2u:b,41:c&&a||a&&a.1q!=9t&&a};d.2u=(d.2u&&d.2u.1q==4L?d.2u:D.28.5K[d.2u])||D.28.5K.74;d.5M=d.1J;d.1J=H(){G(d.36!==Q)D(7).5A();G(D.1D(d.5M))d.5M.1k(7)};I d},41:{73:H(p,n,b,a){I b+a*p},5P:H(p,n,b,a){I((-29.9r(p*29.9q)/2)+0.5)*a+b}},3O:[],48:U,28:H(b,c,a){7.15=c;7.T=b;7.1i=a;G(!c.3Z)c.3Z={}}});D.28.44={4D:H(){G(7.15.2Y)7.15.2Y.1k(7.T,7.1z,7);(D.28.2Y[7.1i]||D.28.2Y.4w)(7);G(7.1i=="1Z"||7.1i=="2h")7.T.V.18="3I"},1t:H(a){G(7.T[7.1i]!=U&&7.T.V[7.1i]==U)I 7.T[7.1i];J r=3d(D.1g(7.T,7.1i,a));I r&&r>-9p?r:3d(D.2a(7.T,7.1i))||0},3G:H(c,b,d){7.5V=1z();7.2b=c;7.3l=b;7.2M=d||7.2M||"2X";7.1z=7.2b;7.2S=7.4N=0;7.4D();J e=7;H t(a){I e.2Y(a)}t.T=7.T;D.3O.1p(t);G(D.48==U){D.48=4I(H(){J a=D.3O;R(J i=0;i7.15.2u+7.5V){7.1z=7.3l;7.2S=7.4N=1;7.4D();7.15.45[7.1i]=M;J b=M;R(J i 1n 7.15.45)G(7.15.45[i]!==M)b=Q;G(b){G(7.15.18!=U){7.T.V.33=7.15.33;7.T.V.18=7.15.18;G(D.1g(7.T,"18")=="2F")7.T.V.18="3I"}G(7.15.1M)7.T.V.18="2F";G(7.15.1M||7.15.1N)R(J p 1n 7.15.45)D.1K(7.T.V,p,7.15.3Z[p])}G(b)7.15.1J.1k(7.T);I Q}N{J n=t-7.5V;7.4N=n/7.15.2u;7.2S=D.41[7.15.41||(D.41.5P?"5P":"73")](7.4N,n,0,1,7.15.2u);7.1z=7.2b+((7.3l-7.2b)*7.2S);7.4D()}I M}};D.1l(D.28,{5K:{9l:9j,9i:7e,74:9g},2Y:{2e:H(a){a.T.2e=a.1z},2c:H(a){a.T.2c=a.1z},1y:H(a){D.1K(a.T.V,"1y",a.1z)},4w:H(a){a.T.V[a.1i]=a.1z+a.2M}}});D.17.2i=H(){J b=0,1S=0,T=7[0],3q;G(T)ao(D.14){J d=T.1d,4a=T,1s=T.1s,1Q=T.2z,5U=2k&&3r(5B)<9c&&!/9a/i.11(v),1g=D.2a,3c=1g(T,"30")=="3c";G(T.7y){J c=T.7y();1e(c.1A+29.2f(1Q.1C.2e,1Q.1c.2e),c.1S+29.2f(1Q.1C.2c,1Q.1c.2c));1e(-1Q.1C.6b,-1Q.1C.6a)}N{1e(T.5X,T.5W);1B(1s){1e(1s.5X,1s.5W);G(42&&!/^t(98|d|h)$/i.11(1s.2j)||2k&&!5U)2C(1s);G(!3c&&1g(1s,"30")=="3c")3c=M;4a=/^1c$/i.11(1s.2j)?4a:1s;1s=1s.1s}1B(d&&d.2j&&!/^1c|2K$/i.11(d.2j)){G(!/^96|1T.*$/i.11(1g(d,"18")))1e(-d.2e,-d.2c);G(42&&1g(d,"33")!="4j")2C(d);d=d.1d}G((5U&&(3c||1g(4a,"30")=="5x"))||(42&&1g(4a,"30")!="5x"))1e(-1Q.1c.5X,-1Q.1c.5W);G(3c)1e(29.2f(1Q.1C.2e,1Q.1c.2e),29.2f(1Q.1C.2c,1Q.1c.2c))}3q={1S:1S,1A:b}}H 2C(a){1e(D.2a(a,"6V",M),D.2a(a,"6U",M))}H 1e(l,t){b+=3r(l,10)||0;1S+=3r(t,10)||0}I 3q};D.17.1l({30:H(){J a=0,1S=0,3q;G(7[0]){J b=7.1s(),2i=7.2i(),4c=/^1c|2K$/i.11(b[0].2j)?{1S:0,1A:0}:b.2i();2i.1S-=25(7,\'94\');2i.1A-=25(7,\'aF\');4c.1S+=25(b,\'6U\');4c.1A+=25(b,\'6V\');3q={1S:2i.1S-4c.1S,1A:2i.1A-4c.1A}}I 3q},1s:H(){J a=7[0].1s;1B(a&&(!/^1c|2K$/i.11(a.2j)&&D.1g(a,\'30\')==\'93\'))a=a.1s;I D(a)}});D.P([\'5e\',\'5G\'],H(i,b){J c=\'4y\'+b;D.17[c]=H(a){G(!7[0])I;I a!=12?7.P(H(){7==1b||7==S?1b.92(!i?a:D(1b).2e(),i?a:D(1b).2c()):7[c]=a}):7[0]==1b||7[0]==S?46[i?\'aI\':\'aJ\']||D.71&&S.1C[c]||S.1c[c]:7[0][c]}});D.P(["6N","4b"],H(i,b){J c=i?"5e":"5G",4f=i?"6k":"6i";D.17["5s"+b]=H(){I 7[b.3y()]()+25(7,"57"+c)+25(7,"57"+4f)};D.17["90"+b]=H(a){I 7["5s"+b]()+25(7,"2C"+c+"4b")+25(7,"2C"+4f+"4b")+(a?25(7,"6S"+c)+25(7,"6S"+4f):0)}})})();',62,669,'|||||||this|||||||||||||||||||||||||||||||||||if|function|return|var|length|data|true|else|type|each|false|for|document|elem|null|style|event||nodeName|||test|undefined||browser|options|nodeType|fn|display|arguments|url|window|body|parentNode|add|msie|css|indexOf|prop|typeof|call|extend|script|in|replace|push|constructor|text|offsetParent|cur|status|div|apply|firstChild|opacity|now|left|while|documentElement|isFunction|filter|className|hidden|handle|match|complete|attr|ret|hide|show|dataType|trigger|doc|split|top|table|try|catch|success|break|cache|height||remove|tbody|string|guid|num|global|ready|fx|Math|curCSS|start|scrollTop|makeArray|scrollLeft|max|animate|width|offset|tagName|safari|map|toggle||done|Array|find|toUpperCase|button|special|duration|id|copy|value|handler|ownerDocument|select|new|border|exec|stack|none|opera|nextSibling|pushStack|target|html|inArray|unit|xml|bind|GET|isReady|merge|pos|timeout|delete|one|selected|px|step|jsre|position|async|preventDefault|overflow|name|which|queue|removeChild|namespace|insertBefore|nth|removeData|fixed|parseFloat|error|readyState|multiFilter|createElement|rl|re|trim|end|_|param|first|get|results|parseInt|slice|childNodes|encodeURIComponent|append|events|elems|toLowerCase|json|readyList|setTimeout|grep|mouseenter|color|is|custom|getElementsByTagName|block|stopPropagation|addEventListener|callee|proxy|mouseleave|timers|defaultView|password|disabled|last|has|appendChild|form|domManip|props|ajax|orig|set|easing|mozilla|load|prototype|curAnim|self|charCode|timerId|object|offsetChild|Width|parentOffset|src|unbind|br|currentStyle|clean|float|visible|relatedTarget|previousSibling|handlers|isXMLDoc|on|setup|nodeIndex|unique|shift|javascript|child|RegExp|_default|deep|scroll|lastModified|teardown|setRequestHeader|timeStamp|update|empty|tr|getAttribute|innerHTML|setInterval|checked|fromElement|Number|jQuery|state|active|jsonp|accepts|application|dir|input|responseText|click|styleSheets|unload|not|lastToggle|outline|mouseout|getPropertyValue|mouseover|getComputedStyle|bindReady|String|padding|pageX|metaKey|keyCode|getWH|andSelf|clientX|Left|all|visibility|container|index|init|triggered|removeAttribute|classFilter|prevObject|submit|file|after|windowData|inner|client|globalEval|sibling|jquery|absolute|clone|wrapAll|dequeue|version|triggerHandler|oldblock|ctrlKey|createTextNode|Top|handleError|getResponseHeader|parsererror|speeds|checkbox|old|00|radio|swing|href|Modified|ifModified|lastChild|safari2|startTime|offsetTop|offsetLeft|username|location|ajaxSettings|getElementById|isSimple|values|selectedIndex|runtimeStyle|rsLeft|_load|loaded|DOMContentLoaded|clientTop|clientLeft|toElement|srcElement|val|pageY|POST|unshift|Bottom|clientY|Right|fix|exclusive|detachEvent|cloneNode|removeEventListener|swap|toString|join|attachEvent|eval|substr|head|parse|textarea|reset|image|zoom|odd|even|before|prepend|exclude|expr|quickClass|quickID|uuid|quickChild|continue|Height|textContent|appendTo|contents|open|margin|evalScript|borderTopWidth|borderLeftWidth|parent|httpData|setArray|CSS1Compat|compatMode|boxModel|cssFloat|linear|def|webkit|nodeValue|speed|_toggle|eq|100|replaceWith|304|concat|200|alpha|Last|httpNotModified|getAttributeNode|httpSuccess|clearInterval|abort|beforeSend|splice|styleFloat|throw|colgroup|XMLHttpRequest|ActiveXObject|scriptCharset|callback|fieldset|multiple|processData|getBoundingClientRect|contentType|link|ajaxSend|ajaxSuccess|ajaxError|col|ajaxComplete|ajaxStop|ajaxStart|serializeArray|notmodified|keypress|keydown|change|mouseup|mousedown|dblclick|focus|blur|stylesheet|hasClass|rel|doScroll|black|hover|solid|cancelBubble|returnValue|wheelDelta|view|round|shiftKey|resize|screenY|screenX|relatedNode|mousemove|prevValue|originalTarget|offsetHeight|keyup|newValue|offsetWidth|eventPhase|detail|currentTarget|cancelable|bubbles|attrName|attrChange|altKey|originalEvent|charAt|0n|substring|animated|header|noConflict|line|enabled|innerText|contains|only|weight|font|gt|lt|uFFFF|u0128|size|417|Boolean|Date|toggleClass|removeClass|addClass|removeAttr|replaceAll|insertAfter|prependTo|wrap|contentWindow|contentDocument|iframe|children|siblings|prevAll|wrapInner|nextAll|outer|prev|scrollTo|static|marginTop|next|inline|parents|able|cellSpacing|adobeair|cellspacing|522|maxLength|maxlength|readOnly|400|readonly|fast|600|class|slow|1px|htmlFor|reverse|10000|PI|cos|compatible|Function|setData|ie|ra|it|rv|getData|userAgent|navigator|fadeTo|fadeIn|slideToggle|slideUp|slideDown|ig|responseXML|content|1223|NaN|fadeOut|300|protocol|send|setAttribute|option|dataFilter|cssText|changed|be|Accept|stop|With|Requested|Object|can|GMT|property|1970|Jan|01|Thu|Since|If|Type|Content|XMLHTTP|th|Microsoft|td|onreadystatechange|onload|cap|charset|colg|host|tfoot|specified|with|1_|thead|leg|plain|attributes|opt|embed|urlencoded|www|area|hr|ajaxSetup|meta|post|getJSON|getScript|marginLeft|img|elements|pageYOffset|pageXOffset|abbr|serialize|pixelLeft'.split('|'),0,{})) \ No newline at end of file diff --git a/web/flowplayer/extras/examples/js/jquery.scrollable.min.js b/web/flowplayer/extras/examples/js/jquery.scrollable.min.js new file mode 100644 index 0000000..be94c0f --- /dev/null +++ b/web/flowplayer/extras/examples/js/jquery.scrollable.min.js @@ -0,0 +1,23 @@ +/** + * jquery.scrollable 0.11. Making HTML elements scroll. + * + * http://flowplayer.org/tools/scrollable.html + * + * Copyright (c) 2008 Tero Piirainen (tero@flowplayer.org) + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * >> Basically you can do anything you want but leave this header as is << + * + * Since : 0.01 - 03/01/2008 + * Version: 0.11 - 05/20/2008 + */ +(function($){$.fn.extend({scrollable:function(arg1,arg2,arg3){return this.each(function(){if(typeof arg1=="string"){var el=$.data(this,"scrollable");el[arg1].apply(el,[arg2,arg3]);}else{new $.scrollable(this,arg1,arg2);}});}});$.scrollable=function(el,opts){$.data(el,"scrollable",this);this.init(el,opts);};$.extend($.scrollable.prototype,{init:function(el,config){var self=this;var opts={size:5,horizontal:false,activeClass:'active',speed:300,onSeek:null,items:'.items',prev:'.prev',next:'.next',navi:'.navi',naviItem:'span'};this.opts=$.extend(opts,config);var root=this.root=$(el);var itemRoot=$(opts.items,root);if(!itemRoot.length)itemRoot=root;itemRoot.css({position:'relative',overflow:'hidden',visibility:'visible'});itemRoot.children().wrapAll('
      ');this.wrap=itemRoot.children(":first");this.wrap.css(opts.horizontal?"width":"height","200000em").after('
      ');this.items=this.wrap.children();this.index=0;if(opts.horizontal){itemRoot.width(opts.size*(this.items.eq(1).offset().left-this.items.eq(0).offset().left)-2);}else{itemRoot.height(opts.size*(this.items.eq(1).offset().top-this.items.eq(0).offset().top)-2);} +if($.isFunction($.fn.mousewheel)){root.bind("mousewheel.scrollable",function(event,delta){self.move(-delta,50);return false;});} +$(window).bind("keypress.scrollable",function(evt){if($(evt.target).parents(".__scrollable").length){if(opts.horizontal&&(evt.keyCode==37||evt.keyCode==39)){self.move(evt.keyCode==37?-1:1);return false;} +if(!opts.horizontal&&(evt.keyCode==38||evt.keyCode==40)){self.move(evt.keyCode==38?-1:1);return false;}} +return true;});this.items.each(function(index,arg){$(this).bind("click.scrollable",function(){self.click(index);});});this.activeIndex=0;$(opts.prev,root).click(function(){self.prev()});$(opts.next,root).click(function(){self.next()});$(opts.navi,root).each(function(){var navi=$(this);var status=self.getStatus();if(navi.is(":empty")){for(var i=0;i").attr("page",i).click(function(){var el=$(this);el.parent().children().removeClass(opts.activeClass);el.addClass(opts.activeClass);self.setPage(el.attr("page"));});if(i==0)item.addClass(opts.activeClass);navi.append(item);}}else{navi.children().each(function(i){var item=$(this);item.attr("page",i);if(i==0)item.addClass(opts.activeClass);item.click(function(){item.parent().children().removeClass(opts.activeClass);item.addClass(opts.activeClass);self.setPage(item.attr("page"));});});}});},click:function(index){var item=this.items.eq(index);var klass=this.opts.activeClass;if(!item.hasClass(klass)&&(index>=0||index + + Multiple Flowplayer instances + + + + + + + + + + +
      + +

      Multiple Flowplayer instances

      + +

      + This page uses flow.embed + to include multiple player instances smoothly. +

      + +

      + + + +

      + + +

      + + + +

      + +

      + + + +

      + +

      + +

      + +
      diff --git a/web/flowplayer/extras/examples/scrollable-playlist.html b/web/flowplayer/extras/examples/scrollable-playlist.html new file mode 100644 index 0000000..a732764 --- /dev/null +++ b/web/flowplayer/extras/examples/scrollable-playlist.html @@ -0,0 +1,127 @@ + + + + Scrollable HTML playlist + + + + + + + + + + + + + + + +
      + +

      Scrollable HTML playlist

      + +

      + Following playlist is implemented with flow.playlist and jquery.scrollable. +

      + + + + + +
      +
      + + + + + + +
      +
      + +

      + Try scrolling with mousewheel and arrow keys. Notice that play/pause buttons are "in sync" between player and playlist. Spacebar toggles the play/pause state. +

      + +

      + +

      + +
      + diff --git a/web/flowplayer/extras/examples/scrollable-view.html b/web/flowplayer/extras/examples/scrollable-view.html new file mode 100644 index 0000000..406c496 --- /dev/null +++ b/web/flowplayer/extras/examples/scrollable-view.html @@ -0,0 +1,131 @@ + + + + Scrollable view + + + + + + + + + + + + + + +
      + +

      Multiple player instances is tabbed pane

      + +

      + This kind of navigational system is easy to do with flow.embed and + + jquery.scrollable. +

      + +
      + + + +
      + + + +
      +
      + + + + +

      First video

      + +

      + Sed ut magna. Duis condimentum purus non nisi. Praesent justo. + Suspendisse urna mi, malesuada vitae, molestie ut, sodales eu, sem. +

      +
      + +
      + + + + +

      Second video

      + +

      + Vivamus vulputate. Vestibulum eget eros sit amet ligula + vestibulum tincidunt. Vivamus id orci nec metus pretium rhoncus. + Donec tortor nisi, viverra id, fringilla sed, euismod feugiat, pede. +

      +
      + +
      + + + + +

      Third video

      + +

      + Nullam dui. Vestibulum diam neque, vehicula non, dapibus non, lacinia in, neque. +

      + +

      + Tellus mi aliquet diam, eu semper tellus ante a massa. Cras leo massa, blandit vitae, pharetra ve. +

      +
      + +
      + + + + +

      Fourth video

      + +

      + Nullam sit amet arcu vel mi commodo sodales. Donec a augue. In semper magna sit amet tortor. Aenean id ligula. Nulla facilisi. +

      +
      +
      + + + +
      + +
      +
      + +

      + You can also use mousewheel to switch between tabs. +

      + +

      + +

      + +
      + + diff --git a/web/flowplayer/extras/examples/simple-example.html b/web/flowplayer/extras/examples/simple-example.html new file mode 100644 index 0000000..0e60dff --- /dev/null +++ b/web/flowplayer/extras/examples/simple-example.html @@ -0,0 +1,77 @@ + + + + + + Simple Flowplayer example + + + + + + + + + + + + +
      + +

      Simple Flowplayer example

      + +

      + View the page source code to familiarize yourself with flowplayer basics. +

      + + +
      + +

      + +

      + +
      diff --git a/web/flowplayer/extras/examples/simple-playlist.html b/web/flowplayer/extras/examples/simple-playlist.html new file mode 100644 index 0000000..e88f6fa --- /dev/null +++ b/web/flowplayer/extras/examples/simple-playlist.html @@ -0,0 +1,68 @@ + + + + Simple playlist example + + + + + + + + + + + + +
      + +

      Simple playlist example using flow.playlist

      + +

      + Following playlist is implemented with flow.playlist. +

      + + + + + +
      +
      + + + + + +
      + +

      + +

      + +
      + + diff --git a/web/flowplayer/extras/extras/flowPlayer.js b/web/flowplayer/extras/extras/flowPlayer.js new file mode 100644 index 0000000..f4e8097 --- /dev/null +++ b/web/flowplayer/extras/extras/flowPlayer.js @@ -0,0 +1,449 @@ +/* + * FlowPlayer external configuration file. + * + * NOTE! This file is only needed if you don't want to include all configuration + * in the embedding HTML file. Please see the installation instructions at + * http://flowpalyer.org + * + * Copyright 2005-2008 Anssi Piirainen + * + * All settings defined in this file can be alternatively defined in the + * embedding HTML object tag (as flashvars variables). Values defined in the + * object tag override values defined in this file. You could use this + * config file to provide defaults for multiple player instances that + * are used in a Web site. Individual instances can be then customized + * with their embedding HTML. + * + * Note that you should probably remove all the comments from this file + * before using it. That way the file will be smaller and will load faster. + */ +{ + /* + * Instructs the player to load the configuration from an external config file. + * This can be a abosulte URL or a relative url (relative to the HTML page + * where the player is embedded). + */ +// configFileName: 'flowPlayer.js', + + /* + * Instructs the player to load the configuration from a RTMP server. + * The player connects to the server listening in the address specified + * by this URL and calls a method 'getStreamPlayerConfig' that should return a + * valid FP configuration object. + */ +// rtmpConfigUrl: 'rtmp://localhost/myapp', + + /* + * A param value to be passed to getStreamPlayerConfig(). A value 'foobar' + * will make the player to call getStreamPlayerConfig('foobsr') + */ +// rtmpConfigParam: 'anssi', + + /* + * Name of the video file. Used if only one video is shown. + * + * Note for testing locally: Specify an empty baseURL '', if you want to load + * the video from your local disk from the directory that contains + * FlowPlayer.swf. In this case the videoFile parameter value should start + * with a slash, for example '/video.flv'. + * + * See also: 'baseURL' that affects this variable + */ +// videoFile: 'honda_accord.flv', + + /* + * Clip to be used if the file specified with 'videoFile' or any of the clips in the playlist + * was not found. The missing video clips are replaced by this clip. This can be + * an image or a FLV clip. Typically this will contain an image/video saying + * "the video you requested cannot be found.....". + * + * The syntax for the value is the same is with the clips in a playlist + * including the possibility to have start/end and duration properties. + * + * See also: 'baseURL' that affects this variable + */ + noVideoClip: { url: 'main_clickToPlay.jpg', duration: 10 }, + //noVideoClip: { url: 'MiltonFriedmanonLimi.flv' }, + + /* + * Playlist is used to publish several videos using one player instance. + * You can also have images in the playlist. The playback pauses in the + * image unless a 'duration' property is given for the image: + + * * The clips in the playlist may have following properties: + * + * name: Name for the clip to be shown in the playlist view. If this is + * not given, the clip will be hidden from the view. + * + * url: The URL used to load the clip. + * + * type: One of 'video', 'flv', 'swf', 'jpg'. Optional, determined from the URL's filename extension + * if that is present. 'video' means a video file in any format supported by Flash. + * 'flv' is present here for backward compatibility, use 'video' in new FlowPlayer installations + * now. Defaults to 'video' if the extension is not present in the URL. + * + * start: The start time (seconds) from where to start the playback. A nonzero + * value can only be used when using a streaming server!! + * end: The end time (seconds) where to stop the playback. + * + * duration: The duration the image is to be shown. If not given the playback + * pauses when the image is reached in the list. + * + * protected: (true/false) Apply inlinine linking protection for this clip? + * Optional, defaults to false. + * + * linkUrl: Associates a hyperlink pointing to the specified URL. The linked + * document will be opened to the browser when the clip area is clicked. + * Specifying this parameter will replace the normal pause/resume behavior + * that is associated to clicking the display area. If you specify an empty + * linkUrl '' the pause/resume behavior is disabled but no hyperlink + * is created. + * linkWindow: Specifies the name of the browser window or frame into which to load + * the linked document. Can be a custom name or one of presets: '_blank', + * '_parent', '_self', '_top'. (optional, defaults to '_blank') + * + * controlEnabled: (true/false) Enable transport control buttons for this clip? + * Optional, defaults to true. + * + * allowResize: (true/false) Allow resizing this clip according to the menu selection. + * Optional, defaults to true. + * + * overlay: A filename pointing to an image that will be placed on top of this image clip. This + * is only applicable to image clips (jpg or png files). Essentially this layers two images + * on top of each other. Typically the image on top is a big play button that is used on + * top of an image taken from the main movie. + * + * overlayId: ID that specifies a built-in overlay to be used. Currently the player supports + * one built-in overlay with ID 'play'. It renders a large play button with mouse hover color change. + * You can use this on top of image clips (one clip with both the 'url' property and + * 'overlayId' property). + * You can also specify a clip that only has this ID. In that + * case you should place it immediately before or after a FLV clip. This overlay-only + * clip is then rendered on top of the first or the last frame of the FLV video. + * + * live: (true/false) Is this a live stream (played from a media server)? + * + * showOnLoadBegin: (true/false) If true, make this clip visible when the fist bits have been loaded. + * If false, do not show this clip (show the background instead) before the buffer is filled + * and the playback starts. Optional, defaults to true. + * + * maxPlayCount: The maximum play count for this clip. The clip is removed from the playlist when + * the playcount reaches this amount. + * + * suggestedClipsInfoUrl: URL used to fetch suggestions (related videos) information from the server + * + * See also: 'baseURL' is prefixed with each URL + */ + playList: [ + { url: 'main_clickToPlay.jpg' }, + { name: 'Honda Accord', url: '!honda_accord.flv' }, + { name: 'River', url: 'river.flv' }, + { name: 'Ounasvaara', url: 'ounasvaara.flv' } + ], + + /* + * Specifies wether the playlist control buttons should be shown in the player SWF component or not. + * Optional, defaults to the value of showPlayList. + */ + showPlayListButtons: true, + + /* + * Streaming server connection URL. + * You don't need this with lighttpd, just use the streamingServer setting (see below) with it. + */ +// streamingServerURL: 'rtmp://localahost:oflaDemo', + + /* + * baseURL specifies the URL that is appended in front of different file names + * given in this file. + * + * You don't need to specify this at all if you place the video next to + * the player SWF file on the Web server (to be available under the same URL path). + */ +// baseURL: 'http://flowplayer.sourceforge.net/video', + + + /* + * What kind of streaming server? Available options: 'fms', 'red5', 'lighttpd' + */ +// streamingServer: 'fms', + + /* + * Specifies whether thumbnail information is contained in the FLV's cue point + * metadata. Cue points can be injected into the FLV file using + * for example Flvtool2. See the FlowPlayer web site for more info. + * (optional, defaults to false) + * + * See also: cuePoints below for an alternative way of specifying thumb metadata + */ +// thumbsOnFLV: true, + + /* + * Thumbnails specific to cue points. Use this if you don't want to + * embed thumbnail metadata into the FLV's cue points. + * If you have thumbNails defined here you should have thumbsOnFLV: false ! + * thumb times are given in seconds + */ +// thumbs: [ +// { thumbNail: 'Thumb1.jpg', time: 10 }, +// { thumbNail: 'Thumb2.jpg', time: 24 }, +// { thumbNail: 'Thumb3.jpg', time: 54 }, +// { thumbNail: 'Thumb4.jpg', time: 74 }, +// { thumbNail: 'Thumb5.jpg', time: 94 }, +// { thumbNail: 'Thumb6.jpg', time: 110 } +// ], + // Location of the thumbnail files +// thumbLocation: 'http://www.kolumbus.fi/apiirain/video', + + /* + * 'autoPlay' variable defines whether playback begins immediately or not. + * + * Note that currently with red5 you should not have false in autoPlay + * when you specify a nonzero starting position for the video clip. This is because red5 + * does not send FLV metadata when the playback starts from a nonzero value. + * + * (optional, defaults to true) + */ + autoPlay: true, + + /* + * 'autoBuffering' specifies wheter to start loading the video stream into + * buffer memory immediately. Only meaningful if 'autoPlay' is set to + * false. (optional, defaults to true) + */ + autoBuffering: true, + + /* + * 'startingBufferLength' specifies the video buffer length to be used to kick + * off the playback. This is used in the beginning of the playback and every time + * after the player has ran out of buffer memory. + * More info at: http://www.progettosinergia.com/flashvideo/flashvideoblog.htm#031205 + * (optional, defaults to the value of 'bufferLength' setting) + * + * see also: bufferLength + */ +// startingBufferLength: 5, + + /* + * 'bufferLength' specifies the video buffer length in seconds. This is used + * after the playback has started with the initial buffer length. You should + * use an arbitrary large value here to ensure stable playback. + * (optional, defaults to 10 seconds) + * + * see also: startingBufferLength + */ + bufferLength: 20, + + /* + * 'loop' defines whether the playback should loop to the first clip after + * all clips in the playlist have been shown. It is used as the + * default state of the toggle button that controls looping. (optional, + * defaults to true) + */ + loop: true, + + /* + * Rewind back to the fist clip in the playlist when end of the list has been reached? + * This option only has effect if loop is false (please see loop variable above). + * (optional, defaults to false) + */ + autoRewind: true, + + /* + * Specifies wether the loop toggle button should be shown in the player SWF component or not. + * Optional, defaults to false. + */ +// showLoopButton: true, + + /* + * Specifies the height to be allocated for the video display. This is the + * maximum height available for the different resizing options. + */ + videoHeight: 320, + + /* + * Specifies the width for the control buttons area. Optiona, defaults to the + * width setting used in the embedding code. + */ +// controlsWidth: 480, + + /* + * Specifies how the video is scaled initially. This can be then changed by + * the user through the menu. (optional, defaults to 'fit') + * Possible values: + * 'fit' Fit to window by preserving the aspect ratios encoded in the FLV metadata. + * This is the default behavior. + * 'half' Half size (preserves aspect ratios) + * 'orig' Use the dimensions encoded in FLV. If the video is too big for the + * available space the video is scaled as if using the 'fit' option. + * 'scale' Scale the video to fill all available space for the video. Ignores + * the dimensions in metadata. + * + */ + initialScale: 'fit', + + /* + * Specifies if the menu containing the size options should be shown or not. + * (optional, defaults to true) +// showMenu: false, + + /* + * 'hideControls' if set to true, hides all buttons and the progress bar + * leaving only the video showing (optional, defaults to false) + */ + hideControls: false, + + /* + * URL that specifies a base URL that points to a folder containing + * images used to skin the player. You must specify this if you intend + * to load external button images (see 'loadButtonImages' below). + */ + skinImagesBaseURL: 'http://flowplayer.sourceforge.net/resources' + + /* + * Will button images be loaded from external files, or will images embedded + * in the player SWF component be used? Set this to false if you want to "skin" + * the buttons. Optional, defaults to true. + * + * NOTE: If you set this to false, you need to have the skin images available + * on the server! Otherwise the player will not show up at all or will show + * up corrupted. + * + * See also: 'skinImagesBaseURL' that affects this variable + */ +// useEmbeddedButtonImages: false, + + /* + * 'splashImageFile' specifies an image file to be used as a splash image. + * This is useful if 'autoPlay' is set to false and you want to show a + * welcome image before the video is played. Should be in JPG format. The + * value of 'baseURL' is used similarily as with the video file name and + * therefore the video and the image files should be placed in the Web + * server next to each other. + * + * NOTE: If you set a value for this, you need to have the splash image available + * on the server! Otherwise the player will not show up at all or will show + * up corrupted. + * + * NOTE2: You can also specify the splash in a playlist. This is just + * an alternative way of doing it. It was preserved for backward compatibility. + * + * See also: 'baseURL' that affects this variable + */ +// splashImageFile: 'main_clickToPlay.jpg', + + /* + * Should the splash image be scaled to fit the entire video area? If false, + * the image will be centered. Optional, defaults to false. + */ +// scaleSplash: false, + + /* + * 'progressBarColor1' defines the color of the progress bar at the bottom + * and top edges. Specified in hexadecimal triplet form indicating the RGB + * color component values. (optional) + */ +// progressBarColor1: 0xFFFFFF, + + + /* + * 'progressBarColor2' defines the color in the middle of the progress bar. + * The value of this and 'progressBarColor1' variables define the gradient + * color fill of the progress bar. (optional) + */ +// progressBarColor2: 0xDDFFDD, + + /* + * 'bufferBarColor1' defines the color of the buffer size indicator bar at the bottom + * and top edges. (optional) + */ +// bufferBarColor1: 0xFFFFFF, + + + /* + * 'bufferBarColor2' defines the color of the buffer size indicator bar in the middle + * of the bar. (optional) + */ +// bufferBarColor2: 0xDDFFDD, + + /* + * 'progressBarBorderColor1' defines the color of the progress bar's border at the bottom + * and top edges. (optional) + */ +// progressBarBorderColor1: 0xDDDDDD, + + + /* + * 'progressBarBorderColor2' defines the color of the progress bar's border in the middle + * of the bar. (optional) + */ +// progressBarBorderColor2: 0xEEEEEE, + + /* + * 'bufferingAnimationColor' defines the color of the moving bars used in the buffering + * animation. (optional) + */ +// bufferingAnimationColor: 0x0000FF, + + /* + * 'controlsAreaBorderColor' defines the color of the border behind buttons and progress bar + * (optional) + */ +// controlsAreaBorderColor: 0x1234, + + /* + * 'timeDisplayFontColor' defines the color of the progress/duration time display + * (optional) + */ +// timeDisplayFontColor: 0xAABBCC, + + /* + * Height of the progress bar. (optional) + */ +// progressBarHeight: 10, + + /* + * Height of the progress bar area. (optional) + */ +// progressBarAreaHeight: 10, + + /* + * Name of the authentication code file name that is used to prevent inline linking + * of video and image files. This can be a complete URL or just a file name relative + * to the location from where the player is loaded. (optional, defaults to flowplayer_auth.txt) + */ +// authFileName: 'http://www.mytube.org/authCode.txt', + + /* + * The URL pointing to a sctipt that opens the player full screen. + * If this is not configured explicitly, the default script, + * http://flowplayer.sourceforge.net/fullscreen.js, is used. + */ +// fullScreenScriptURL: 'http://mysite.org/fullscreen.js' + + /** + * Specifies which menu items will be show. This is an array that contains a boolean + * value for each of the items. By default shows them all except "full screen". + */ +// menuItems[ +// true, // show 'Fit to window' +// true, // show 'Half size' +// true, // show 'Original size' +// true, // show 'Fill window' +// true, // show 'Full screen' +// false // hide 'Embed...' +// ], + + + /* + * Specifies wether the full screen button should be shown in the player SWF component or not. + * Optional, defaults to true. + */ +// showFullScreenButton: false, + + /* + * Use the Flash 9 native full screen mode. + */ +// useNativeFullScreen: true, +} + diff --git a/web/flowplayer/extras/extras/suggestions.js b/web/flowplayer/extras/extras/suggestions.js new file mode 100644 index 0000000..c6f9eeb --- /dev/null +++ b/web/flowplayer/extras/extras/suggestions.js @@ -0,0 +1,10 @@ +{ + clips: [ + { url: 'honda_accord.flv', name: 'Honda commercial', suggestedClipsInfoUrl: 'suggestions.js', + duration: 180, thumbnailUrl: 'Thumb1.jpg', + info: { viewed: 631, category: 'ads' } }, + { url: 'river.flv', name: 'Skiing in Rovaniemi', suggestedClipsInfoUrl: 'suggestions.js', + duration: 180, thumbnailUrl: 'Thumb2.jpg', + info: { viewed: 2, category: 'sports' } } + ] +} \ No newline at end of file diff --git a/web/flowplayer/extras/flowPlayer.js b/web/flowplayer/extras/flowPlayer.js new file mode 100644 index 0000000..f4e8097 --- /dev/null +++ b/web/flowplayer/extras/flowPlayer.js @@ -0,0 +1,449 @@ +/* + * FlowPlayer external configuration file. + * + * NOTE! This file is only needed if you don't want to include all configuration + * in the embedding HTML file. Please see the installation instructions at + * http://flowpalyer.org + * + * Copyright 2005-2008 Anssi Piirainen + * + * All settings defined in this file can be alternatively defined in the + * embedding HTML object tag (as flashvars variables). Values defined in the + * object tag override values defined in this file. You could use this + * config file to provide defaults for multiple player instances that + * are used in a Web site. Individual instances can be then customized + * with their embedding HTML. + * + * Note that you should probably remove all the comments from this file + * before using it. That way the file will be smaller and will load faster. + */ +{ + /* + * Instructs the player to load the configuration from an external config file. + * This can be a abosulte URL or a relative url (relative to the HTML page + * where the player is embedded). + */ +// configFileName: 'flowPlayer.js', + + /* + * Instructs the player to load the configuration from a RTMP server. + * The player connects to the server listening in the address specified + * by this URL and calls a method 'getStreamPlayerConfig' that should return a + * valid FP configuration object. + */ +// rtmpConfigUrl: 'rtmp://localhost/myapp', + + /* + * A param value to be passed to getStreamPlayerConfig(). A value 'foobar' + * will make the player to call getStreamPlayerConfig('foobsr') + */ +// rtmpConfigParam: 'anssi', + + /* + * Name of the video file. Used if only one video is shown. + * + * Note for testing locally: Specify an empty baseURL '', if you want to load + * the video from your local disk from the directory that contains + * FlowPlayer.swf. In this case the videoFile parameter value should start + * with a slash, for example '/video.flv'. + * + * See also: 'baseURL' that affects this variable + */ +// videoFile: 'honda_accord.flv', + + /* + * Clip to be used if the file specified with 'videoFile' or any of the clips in the playlist + * was not found. The missing video clips are replaced by this clip. This can be + * an image or a FLV clip. Typically this will contain an image/video saying + * "the video you requested cannot be found.....". + * + * The syntax for the value is the same is with the clips in a playlist + * including the possibility to have start/end and duration properties. + * + * See also: 'baseURL' that affects this variable + */ + noVideoClip: { url: 'main_clickToPlay.jpg', duration: 10 }, + //noVideoClip: { url: 'MiltonFriedmanonLimi.flv' }, + + /* + * Playlist is used to publish several videos using one player instance. + * You can also have images in the playlist. The playback pauses in the + * image unless a 'duration' property is given for the image: + + * * The clips in the playlist may have following properties: + * + * name: Name for the clip to be shown in the playlist view. If this is + * not given, the clip will be hidden from the view. + * + * url: The URL used to load the clip. + * + * type: One of 'video', 'flv', 'swf', 'jpg'. Optional, determined from the URL's filename extension + * if that is present. 'video' means a video file in any format supported by Flash. + * 'flv' is present here for backward compatibility, use 'video' in new FlowPlayer installations + * now. Defaults to 'video' if the extension is not present in the URL. + * + * start: The start time (seconds) from where to start the playback. A nonzero + * value can only be used when using a streaming server!! + * end: The end time (seconds) where to stop the playback. + * + * duration: The duration the image is to be shown. If not given the playback + * pauses when the image is reached in the list. + * + * protected: (true/false) Apply inlinine linking protection for this clip? + * Optional, defaults to false. + * + * linkUrl: Associates a hyperlink pointing to the specified URL. The linked + * document will be opened to the browser when the clip area is clicked. + * Specifying this parameter will replace the normal pause/resume behavior + * that is associated to clicking the display area. If you specify an empty + * linkUrl '' the pause/resume behavior is disabled but no hyperlink + * is created. + * linkWindow: Specifies the name of the browser window or frame into which to load + * the linked document. Can be a custom name or one of presets: '_blank', + * '_parent', '_self', '_top'. (optional, defaults to '_blank') + * + * controlEnabled: (true/false) Enable transport control buttons for this clip? + * Optional, defaults to true. + * + * allowResize: (true/false) Allow resizing this clip according to the menu selection. + * Optional, defaults to true. + * + * overlay: A filename pointing to an image that will be placed on top of this image clip. This + * is only applicable to image clips (jpg or png files). Essentially this layers two images + * on top of each other. Typically the image on top is a big play button that is used on + * top of an image taken from the main movie. + * + * overlayId: ID that specifies a built-in overlay to be used. Currently the player supports + * one built-in overlay with ID 'play'. It renders a large play button with mouse hover color change. + * You can use this on top of image clips (one clip with both the 'url' property and + * 'overlayId' property). + * You can also specify a clip that only has this ID. In that + * case you should place it immediately before or after a FLV clip. This overlay-only + * clip is then rendered on top of the first or the last frame of the FLV video. + * + * live: (true/false) Is this a live stream (played from a media server)? + * + * showOnLoadBegin: (true/false) If true, make this clip visible when the fist bits have been loaded. + * If false, do not show this clip (show the background instead) before the buffer is filled + * and the playback starts. Optional, defaults to true. + * + * maxPlayCount: The maximum play count for this clip. The clip is removed from the playlist when + * the playcount reaches this amount. + * + * suggestedClipsInfoUrl: URL used to fetch suggestions (related videos) information from the server + * + * See also: 'baseURL' is prefixed with each URL + */ + playList: [ + { url: 'main_clickToPlay.jpg' }, + { name: 'Honda Accord', url: '!honda_accord.flv' }, + { name: 'River', url: 'river.flv' }, + { name: 'Ounasvaara', url: 'ounasvaara.flv' } + ], + + /* + * Specifies wether the playlist control buttons should be shown in the player SWF component or not. + * Optional, defaults to the value of showPlayList. + */ + showPlayListButtons: true, + + /* + * Streaming server connection URL. + * You don't need this with lighttpd, just use the streamingServer setting (see below) with it. + */ +// streamingServerURL: 'rtmp://localahost:oflaDemo', + + /* + * baseURL specifies the URL that is appended in front of different file names + * given in this file. + * + * You don't need to specify this at all if you place the video next to + * the player SWF file on the Web server (to be available under the same URL path). + */ +// baseURL: 'http://flowplayer.sourceforge.net/video', + + + /* + * What kind of streaming server? Available options: 'fms', 'red5', 'lighttpd' + */ +// streamingServer: 'fms', + + /* + * Specifies whether thumbnail information is contained in the FLV's cue point + * metadata. Cue points can be injected into the FLV file using + * for example Flvtool2. See the FlowPlayer web site for more info. + * (optional, defaults to false) + * + * See also: cuePoints below for an alternative way of specifying thumb metadata + */ +// thumbsOnFLV: true, + + /* + * Thumbnails specific to cue points. Use this if you don't want to + * embed thumbnail metadata into the FLV's cue points. + * If you have thumbNails defined here you should have thumbsOnFLV: false ! + * thumb times are given in seconds + */ +// thumbs: [ +// { thumbNail: 'Thumb1.jpg', time: 10 }, +// { thumbNail: 'Thumb2.jpg', time: 24 }, +// { thumbNail: 'Thumb3.jpg', time: 54 }, +// { thumbNail: 'Thumb4.jpg', time: 74 }, +// { thumbNail: 'Thumb5.jpg', time: 94 }, +// { thumbNail: 'Thumb6.jpg', time: 110 } +// ], + // Location of the thumbnail files +// thumbLocation: 'http://www.kolumbus.fi/apiirain/video', + + /* + * 'autoPlay' variable defines whether playback begins immediately or not. + * + * Note that currently with red5 you should not have false in autoPlay + * when you specify a nonzero starting position for the video clip. This is because red5 + * does not send FLV metadata when the playback starts from a nonzero value. + * + * (optional, defaults to true) + */ + autoPlay: true, + + /* + * 'autoBuffering' specifies wheter to start loading the video stream into + * buffer memory immediately. Only meaningful if 'autoPlay' is set to + * false. (optional, defaults to true) + */ + autoBuffering: true, + + /* + * 'startingBufferLength' specifies the video buffer length to be used to kick + * off the playback. This is used in the beginning of the playback and every time + * after the player has ran out of buffer memory. + * More info at: http://www.progettosinergia.com/flashvideo/flashvideoblog.htm#031205 + * (optional, defaults to the value of 'bufferLength' setting) + * + * see also: bufferLength + */ +// startingBufferLength: 5, + + /* + * 'bufferLength' specifies the video buffer length in seconds. This is used + * after the playback has started with the initial buffer length. You should + * use an arbitrary large value here to ensure stable playback. + * (optional, defaults to 10 seconds) + * + * see also: startingBufferLength + */ + bufferLength: 20, + + /* + * 'loop' defines whether the playback should loop to the first clip after + * all clips in the playlist have been shown. It is used as the + * default state of the toggle button that controls looping. (optional, + * defaults to true) + */ + loop: true, + + /* + * Rewind back to the fist clip in the playlist when end of the list has been reached? + * This option only has effect if loop is false (please see loop variable above). + * (optional, defaults to false) + */ + autoRewind: true, + + /* + * Specifies wether the loop toggle button should be shown in the player SWF component or not. + * Optional, defaults to false. + */ +// showLoopButton: true, + + /* + * Specifies the height to be allocated for the video display. This is the + * maximum height available for the different resizing options. + */ + videoHeight: 320, + + /* + * Specifies the width for the control buttons area. Optiona, defaults to the + * width setting used in the embedding code. + */ +// controlsWidth: 480, + + /* + * Specifies how the video is scaled initially. This can be then changed by + * the user through the menu. (optional, defaults to 'fit') + * Possible values: + * 'fit' Fit to window by preserving the aspect ratios encoded in the FLV metadata. + * This is the default behavior. + * 'half' Half size (preserves aspect ratios) + * 'orig' Use the dimensions encoded in FLV. If the video is too big for the + * available space the video is scaled as if using the 'fit' option. + * 'scale' Scale the video to fill all available space for the video. Ignores + * the dimensions in metadata. + * + */ + initialScale: 'fit', + + /* + * Specifies if the menu containing the size options should be shown or not. + * (optional, defaults to true) +// showMenu: false, + + /* + * 'hideControls' if set to true, hides all buttons and the progress bar + * leaving only the video showing (optional, defaults to false) + */ + hideControls: false, + + /* + * URL that specifies a base URL that points to a folder containing + * images used to skin the player. You must specify this if you intend + * to load external button images (see 'loadButtonImages' below). + */ + skinImagesBaseURL: 'http://flowplayer.sourceforge.net/resources' + + /* + * Will button images be loaded from external files, or will images embedded + * in the player SWF component be used? Set this to false if you want to "skin" + * the buttons. Optional, defaults to true. + * + * NOTE: If you set this to false, you need to have the skin images available + * on the server! Otherwise the player will not show up at all or will show + * up corrupted. + * + * See also: 'skinImagesBaseURL' that affects this variable + */ +// useEmbeddedButtonImages: false, + + /* + * 'splashImageFile' specifies an image file to be used as a splash image. + * This is useful if 'autoPlay' is set to false and you want to show a + * welcome image before the video is played. Should be in JPG format. The + * value of 'baseURL' is used similarily as with the video file name and + * therefore the video and the image files should be placed in the Web + * server next to each other. + * + * NOTE: If you set a value for this, you need to have the splash image available + * on the server! Otherwise the player will not show up at all or will show + * up corrupted. + * + * NOTE2: You can also specify the splash in a playlist. This is just + * an alternative way of doing it. It was preserved for backward compatibility. + * + * See also: 'baseURL' that affects this variable + */ +// splashImageFile: 'main_clickToPlay.jpg', + + /* + * Should the splash image be scaled to fit the entire video area? If false, + * the image will be centered. Optional, defaults to false. + */ +// scaleSplash: false, + + /* + * 'progressBarColor1' defines the color of the progress bar at the bottom + * and top edges. Specified in hexadecimal triplet form indicating the RGB + * color component values. (optional) + */ +// progressBarColor1: 0xFFFFFF, + + + /* + * 'progressBarColor2' defines the color in the middle of the progress bar. + * The value of this and 'progressBarColor1' variables define the gradient + * color fill of the progress bar. (optional) + */ +// progressBarColor2: 0xDDFFDD, + + /* + * 'bufferBarColor1' defines the color of the buffer size indicator bar at the bottom + * and top edges. (optional) + */ +// bufferBarColor1: 0xFFFFFF, + + + /* + * 'bufferBarColor2' defines the color of the buffer size indicator bar in the middle + * of the bar. (optional) + */ +// bufferBarColor2: 0xDDFFDD, + + /* + * 'progressBarBorderColor1' defines the color of the progress bar's border at the bottom + * and top edges. (optional) + */ +// progressBarBorderColor1: 0xDDDDDD, + + + /* + * 'progressBarBorderColor2' defines the color of the progress bar's border in the middle + * of the bar. (optional) + */ +// progressBarBorderColor2: 0xEEEEEE, + + /* + * 'bufferingAnimationColor' defines the color of the moving bars used in the buffering + * animation. (optional) + */ +// bufferingAnimationColor: 0x0000FF, + + /* + * 'controlsAreaBorderColor' defines the color of the border behind buttons and progress bar + * (optional) + */ +// controlsAreaBorderColor: 0x1234, + + /* + * 'timeDisplayFontColor' defines the color of the progress/duration time display + * (optional) + */ +// timeDisplayFontColor: 0xAABBCC, + + /* + * Height of the progress bar. (optional) + */ +// progressBarHeight: 10, + + /* + * Height of the progress bar area. (optional) + */ +// progressBarAreaHeight: 10, + + /* + * Name of the authentication code file name that is used to prevent inline linking + * of video and image files. This can be a complete URL or just a file name relative + * to the location from where the player is loaded. (optional, defaults to flowplayer_auth.txt) + */ +// authFileName: 'http://www.mytube.org/authCode.txt', + + /* + * The URL pointing to a sctipt that opens the player full screen. + * If this is not configured explicitly, the default script, + * http://flowplayer.sourceforge.net/fullscreen.js, is used. + */ +// fullScreenScriptURL: 'http://mysite.org/fullscreen.js' + + /** + * Specifies which menu items will be show. This is an array that contains a boolean + * value for each of the items. By default shows them all except "full screen". + */ +// menuItems[ +// true, // show 'Fit to window' +// true, // show 'Half size' +// true, // show 'Original size' +// true, // show 'Fill window' +// true, // show 'Full screen' +// false // hide 'Embed...' +// ], + + + /* + * Specifies wether the full screen button should be shown in the player SWF component or not. + * Optional, defaults to true. + */ +// showFullScreenButton: false, + + /* + * Use the Flash 9 native full screen mode. + */ +// useNativeFullScreen: true, +} + diff --git a/web/flowplayer/extras/javascript.txt b/web/flowplayer/extras/javascript.txt new file mode 100644 index 0000000..3b0eeb3 --- /dev/null +++ b/web/flowplayer/extras/javascript.txt @@ -0,0 +1,233 @@ +FlowPlayer API supports a subset of the JavaScript API +available in mplayer browser plug-in (http://mplayerplug-in.sourceforge.net/). +Additionally it defines some methods that are not available in mplayer +plug-in. mplayer plug-in's API is documented in javascript.txt that can be found +in the plugin's source distribution package. + +FlowPlayer supports the following methods. These are available to JavaScript and +to other Flash movies via Flash's LocalConnection. + +NOTE! + +It takes some time before the Flash plugin and the player has been initialized +and the functions in this API are ready to be used. You should wait until you +receive the onFlowPlayerReady() callback from the player. After the player has +called this function the API is guaranteed to be ready for use. + +methods (same as in mplayer plug-in): + + DoPlay():Void; + + Plays the current clip. + + DoStop():Void; + + Stops playback and returns to the first clip in the playlist. + + Reset():Void; + + Resets the player to the initial state. + + Pause():Void; + + Pauses playback. + + Seek(seconds:Number):Void; + + Seeks to the specified time during the clip's timeline. + + getTime():Void; + + Get's the current time (seconds advanced). + + getDuration():Void; + + Get's the clip's duration. + +FlowPlayer specific, not in mplayer plug-in API: + + setConfig(flowPlayerConfig:Object):Void; + + Configure the player using a FlowPlayer configuration object. + This is a JavaScript object that is documented in flowPlayer.js + (http://flowplayer.sourceforge.net/flowPlayer.js). + + NOTE: The visible playList will not behave currently if you replace + an existing playlist by calling this method with an object that + has a different playList! + + StartBuffering()Void; + + Starts loading the clip into the buffer memory. Does not start + playback. + + ToggleLoop()Void; + + Toggless looping on/off. + + getPercentLoaded():Number; + + Gets the percentage of buffer memory currently filled with data. + + getIsPlaying():Boolean; + + Is the player currently playing? + + getIsPaused():Boolean; + + Is the player currently paused? + + getIsLooping():Boolean; + + Is the player looping? + + addCuePoint(timeSeconds, name, parameters):Void; + + Adds a new programmatic cue point. When the cue point's time is reached + the onCuePoint callback is called. The onCuePoint callback receives the name and + parameters values. You can pass a JSON style object in the 'parameters' + parameter. + + addCuePoints(Array):Void; + + Adds a several cue points. Syntax: + addCuePoints([ { name: 'cue1', time: 5, parameters: { foo: 1, bar: 'x' } }, + { name: 'cue2', time: 45, parameters: { foo: 2, bar: 'xy' } } ]) + + +PlayList control (FlowPlayer specific, not in mplayer plug-in API): + + hasNext():Boolean; + + Does the playlist have more clips after the current clipP? + + NextClip():Void; + + Moves to next clip. + + PrevClip():Void; + + Moves to previous clip. + + getPlayListSize():Number; + + Gets the number of clips in the playlist. + + getCurrentClip():Number; + + Gets the index of the current clip. First clip is at index zero. + + ToClip(index:Number):Void; + + Moves to clip at the specified index. + + playClip(clipObj):Void; + + Plays the specified clip. Existing playList is discarded + and replaced with a a playList containing the specified clip. + The clip should be a valid flowplayer clip object that are + also used in playLists. + + setClipURL(clipObj):Void; + + Creates a new playList that has the specified clip. + Existing playList is discarded. + The clip should be a valid flowplayer clip object that are + also used in playLists. + + showEmailView():Void; + + Shows the e-mail to a friend view. + + showEmbedView():Void; + + Shows the embedding view. + +Callbacks from the player (FlowPlayer specific, not in mplayer plug-in API): + + + onFlowPlayerReady():Void + + Called when the player has been initialized and the JavaScript API is ready to be used. + + function onClipDone(clip); + + Called when a clip has been played to the end. The clip parameter object + has following properties: name, baseUrl, fileName, start (start time in seconds), + end (end time in seconds), protected (is hotlink protection applied for this clip?), + linkUrl, linkWindow, controlEnabled (enable playback control buttons?) + + If you return false from this callback the player's default behavior associated with + this event is disabled. The default is to move to the next clip in playList, or rewind + the current clip and loop (if only one clip in playlist) after this event occurs. + + function onClipChanged(clip); + + Called when the user manually changes to another clip in the playlist or + when the playback moves from one clip to the next. + + If you return false from this callback the player's default behavior associated with + this event is disabled. The default is to play the clip. + + function onLoadBegin(clip); + + Called when the loading of a clip begins. + + If you return false from this callback the player's default behavior associated with + this event is disabled. The default is to show the clip's display, resize and center + the display. + + function onStreamNotFound(clip); + + Called when a clip is not found using it's URL. If you return false from this callback + the player's default behavior associated with this event is disabled. The default + behavior is to play the configured "noVideoClip", if it's configured. + + function onPlay(clip); + + Called when playback starts for a playlist. + + function onStop(clip); + + Called when playback of the playlist stops. + + function onPause(clip); + + Called when the player is paused. + + function onResume(clip); + + Called when the player is resumed. + + function onCuePoint(cuePoint); + + Called when a cue point is reached. + + function onStartBuffering(clip); + + Called when a clip starts buffering. If you return false from this callback + the player's default behavior associated with this event is disabled. The default + behavior is to hide the display of the previous clip. + + function onBufferFull(clip); + + Called when the buffer is full and the playback for the specified clip can start. + + function onBufferFlush(clip); + + Called when the buffer is flushed for a clip. + + function onMetaData(metadataObj); + + Called when metadata for the currently playing clip has been received. + The metadata object contains following properties: duration (seconds), + videodatarate (kbit/s), audiodatarate (kbit/s) and creationdate. + + function onPlaybackTime(time); + + Called every time the playhead moves in the media's timeline. The value + of time tells the current time. + + function onSeek(targetTime); + + Called when seek occurs. The parameter values gives the seek's target time in seconds. \ No newline at end of file diff --git a/web/flowplayer/extras/suggestions.js b/web/flowplayer/extras/suggestions.js new file mode 100644 index 0000000..c6f9eeb --- /dev/null +++ b/web/flowplayer/extras/suggestions.js @@ -0,0 +1,10 @@ +{ + clips: [ + { url: 'honda_accord.flv', name: 'Honda commercial', suggestedClipsInfoUrl: 'suggestions.js', + duration: 180, thumbnailUrl: 'Thumb1.jpg', + info: { viewed: 631, category: 'ads' } }, + { url: 'river.flv', name: 'Skiing in Rovaniemi', suggestedClipsInfoUrl: 'suggestions.js', + duration: 180, thumbnailUrl: 'Thumb2.jpg', + info: { viewed: 2, category: 'sports' } } + ] +} \ No newline at end of file diff --git a/web/flowplayer/html/FlowPlayer.html b/web/flowplayer/html/FlowPlayer.html new file mode 100644 index 0000000..e610ffc --- /dev/null +++ b/web/flowplayer/html/FlowPlayer.html @@ -0,0 +1,24 @@ + + + + +FlowPlayer + + + + +
      + This will be replaced by the player. +
      + + + + diff --git a/web/flowplayer/html/FlowPlayerJs.html b/web/flowplayer/html/FlowPlayerJs.html new file mode 100644 index 0000000..2876308 --- /dev/null +++ b/web/flowplayer/html/FlowPlayerJs.html @@ -0,0 +1,99 @@ + + + + +FlowPlayer + + + + + +
      + You need to have the Flash Player installed and + a browser with JavaScript support. +
      + + + +
    ")); + $theartwork->setDescription($description); + $returntext = sfContext::getInstance()->getI18N()->__("Description updated!"); + + $modifiedField = "Description field modified"; + $translateMe = sfContext::getInstance()->getI18N()->__("Description field modified"); + + break; + case 'files': + $theorder = 1; + foreach ($this->getRequestParameter('artwork_files', array()) as $afile) + { + $this->renderText("setting order of ".$afile." to ".$theorder); + ReaktorArtworkFilePeer::setFileOrderPlacement($theorder, $afile, $theartwork); + $theorder++; + + } + $returntext = "File order saved!"; + $modifiedField = "File order changed"; + $translateMe = sfContext::getInstance()->getI18N()->__("File order changed"); + break; + } + try + { + $theartwork->flagChanged($this->getUser(), $modifiedField); + $theartwork->save(); + } + catch (Exception $e) + { + return $this->renderText("*".$returntext."* - Not saved [Error]"); + } + return $this->renderText($returntext); + } + else + { + return $this->renderText('Please don\'t mess with the system'); + } + } + + /** + * List all unapproved artwork in my editorial teams + * + * @return void + */ + public function executeListUnapprovedMyTeams() + { + $editorialteams = array(); + foreach ($this->getUser()->getGuardUser()->getEditorialTeams() as $aTeam) + { + $editorialteams[] = $aTeam->getId(); + } + $this->setFlash('editorialteams', $editorialteams, false); + $this->forward('artwork', 'listUnapproved'); + } + + /** + * List all unapproved artwork in other editorial teams (not mine) + * + * @return null + */ + public function executeListUnapprovedOtherTeams() + { + $editorialteams = array(); + foreach ($this->getUser()->getGuardUser()->getEditorialTeams() as $aTeam) + { + $editorialteams[$aTeam->getId()] = $aTeam; + } + + $othereditorialteams = array(); + if ($this->getRequestParameter('team')) + { + $othereditorialteams[$this->getRequestParameter('team')] = $this->getRequestParameter('team'); + $this->setFlash('oneteam', $this->getRequestParameter('team'), false); + } + else + { + foreach (sfGuardGroupPeer::getEditorialTeams(false) as $aTeam) + { + if (!isset($editorialteams[$aTeam->getId()])) + { + $othereditorialteams[$aTeam->getId()] = $aTeam->getId(); + } + } + } + foreach (sfGuardGroupPeer::getEditorialTeams(false) as $aTeam) + { + if (!isset($editorialteams[$aTeam->getId()])) + { + $othereditorialteamoptionslist[$aTeam->getId()] = $aTeam->getDescription() . ' (' . ReaktorArtworkPeer::getNumberofArtworksByEditorialTeam($aTeam->getId(), 2, true) . ')'; + } + } + + $this->setFlash('othereditorialteams', $othereditorialteams, false); + $this->setFlash('othereditorialteamoptionslist', $othereditorialteamoptionslist, false); + $this->forward('artwork', 'listUnapproved'); + } + + /** + * List unapproved artwork + * + * @return null + */ + public function executeListUnapproved() + { + //$this->artworks = ReaktorArtworkPeer::getUnapprovedArtworksByUser($this->getuser()); + if ($this->getFlash('editorialteams')) + { + $this->editorialteams = $this->getFlash('editorialteams'); + } + + if ($this->getFlash('othereditorialteams') !== null) + { + $this->editorialteams = $this->getFlash('othereditorialteams'); + $this->othereditorialteams = $this->getFlash('othereditorialteams'); + $this->othereditorialteamoptionslist = $this->getFlash('othereditorialteamoptionslist'); + } + + if ($this->getUser()->hasCredential('approveartwork') && $this->editorialteams) + { + $this->pager = ReaktorArtworkPeer::getArtworkByStatusAndCredentialsPaginated( + 2, $this->getUser()->listCredentials(), null, $this->editorialteams, false, true); + } + + else + { + $this->pager = ReaktorArtworkPeer::getArtworkByStatusAndCredentialsPaginated( + 2, $this->getUser()->listCredentials(), $this->getUser()->getGuardUser()->getId(), null, false, true); + } + + if ($this->getFlash('oneteam') !== null) + { + $this->team = sfGuardGroupPeer::retrieveByPK($this->editorialteams[$this->getFlash('oneteam')]); + } + else + { + $this->team = null; + } + $this->artworks = array(); + $this->pager->setPage($this->getRequestParameter('page', 1)); + $this->pager->init(); + foreach ($this->pager->getResults() as $artwork) + { + $this->artworks[] = new genericArtwork($artwork->getId()); + } + } + + /** + * Show list of artwork files flagged for discussion + * + * @return void + */ + public function executeListDiscussion() + { + $this->forward404Unless($this->getUser()->hasCredential('discussartwork')); + $this->files = ReaktorFilePeer::getFilesUnderDiscussion(); + $this->artworks = ReaktorArtworkPeer::getArtworksUnderDiscussion(); + } + + /** + * Reject an artwork + * + * @return void + */ + public function executeRejectArtwork() + { + $this->forward404Unless($this->getUser()->hasCredential('approveartwork')); + $id = $this->getRequestParameter('id'); + $this->forward404Unless($id); + + $this->artwork = new genericArtwork($id); + $this->rejectiontypes = RejectionTypePeer::doSelect(new Criteria()); + } + + /** + * Ajax call to change artwork status + * + * @return unknown + */ + public function executeChangeArtworkStatus() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + + $id = $this->getRequestParameter('id'); + $status = $this->getRequestParameter('status'); + + $artwork = new genericArtwork($id); + $userAllowed = array(ReaktorArtwork::REMOVED, ReaktorArtwork::APPROVED_HIDDEN); + $quiet = false; // Whether to avoid setting the actioned_by flags + + // If a user has hidden an artwork then they are allowed to make it "live" again + if ($artwork->getStatus() == ReaktorArtwork::APPROVED_HIDDEN) + { + $userAllowed[] = ReaktorArtwork::APPROVED; + $quiet = true; + } + + // Users can set their own artwork to removed or deleted, but only admin can do the rest + $this->forward404Unless($this->getUser()->hasCredential('approveartwork') || + ($this->getUser()->getId() == $artwork->getUserId() && in_array($status, $userAllowed))); + + $artwork->changeStatus($this->getUser()->getGuardUser()->getId(), $status, null, $quiet); + + if ($this->getRequestParameter("returndetails") && (!$artwork->isRemoved() || $this->getUser()->hasCredential("viewallcontent"))) + { + sfLoader::loadHelpers("Partial"); + return $this->renderText(get_partial("artwork/userArtworkListElement", array("artwork" => $artwork, "thisUser" => $artwork->getUser()))); + } + + else + { + return $this->renderText(''); + } + } + + /** + * Change the discussion status of an artwork or file + * + */ + public function executeChangeDiscussionStatus() + { + $this->forward404Unless($this->getUser()->hasCredential('approveartwork')); + $id = $this->getRequestParameter('id'); + $object = $this->getRequestParameter('type')=='artwork' ? new genericArtwork($id) : new artworkFile($id); + + if ($this->getRequestParameter('status') == 1) + { + $object->markUnderDiscussion(); + } + else + { + $object->markNotUnderDiscussion(); + } + + if($this->getRequest()->isXmlHttpRequest()) + { + return $this->renderText(''); + } + + $this->redirect('@listdiscussion'); + } + + /** + * Ajax call to accept artwork modifications + * + * @return true + */ + public function executeAcceptArtworkModifications() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && $this->getUser()->hasCredential('approveartwork')); + + $id = $this->getRequestParameter('id'); + $artwork = new genericArtwork($id); + $artwork->flagCleared(); + $artwork->save(); + + return $this->renderText(' '); + } + + /** + * Change the status of an artwork file (Ajax request) + * + * @return void + */ + public function executeChangeFileStatus() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && $this->getUser()->hasCredential('approveartwork')); + + try + { + $file = new artworkFile($this->getRequestParameter('id')); + } + catch (Exception $e) + { + throw new exception ('Could not create file object'); + } + + /*if ($this->getRequestParameter('discussion')) + { + if ($this->getRequestParameter('status') == 1) + { + $file->markUnderDiscussion(); + } + else + { + $file->markNotUnderDiscussion(); + } + }*/ + + // Left scope for other status changes + + return $this->renderText(' '); + } + + /** + * Display rejection form again with error messages + * + * @return void + */ + public function handleErrorReject() + { + $this->forward('artwork', 'rejectArtwork'); + } + + /** + * Reject artwork: send email, and set status + * + * @return void + */ + public function executeReject() + { + $raw_mail = $this->sendEmail('mail', 'sendRejectArtworkOrFile'); + $this->logMessage($raw_mail, 'debug'); + + $artwork = new genericArtwork($this->getRequestParameter('id')); + $artwork->changeStatus($this->getUser()->getGuardUser()->getId(), 4, + $this->getRequestParameter('rejectionmsg')); + + $this->redirect('@listrejected'); + } + + /** + * Show list of rejected artworks + * + * @return void + */ + public function executeListRejected() + { + $this->selected_year = ($this->getRequestParameter('year') != '') ? $this->getRequestParameter('year') : date('Y'); + if ($this->getRequestParameter('month') != '') + { + $this->selected_month = $this->getRequestParameter('month'); + } + elseif ($this->getRequestParameter('year') == '') + { + $this->selected_month = date('n'); + } + else + { + $this->selected_month = null; + } + $this->months = array(); + for ($cc = 1; $cc <= 12; $cc++) + { + $count = 0; + $this->months[] = array('month' => $cc, 'artworkcount' => ReaktorArtworkPeer::countArtworksByDateAndStatus(4, $this->selected_year, $cc)); + } + $this->artworks = array(); + $this->page = $this->getRequestParameter('page', 1); + $this->pager = ReaktorArtworkPeer::getArtworksByDateAndStatus(4, $this->selected_year, $this->selected_month); + $this->pager->setPage($this->page); + $this->pager->init(); + foreach ($this->pager->getResults() as $reaktor_artwork) + { + $this->artworks[] = new genericArtwork($reaktor_artwork, null, null); + } + $this->route = '@rejectedartwork_month?year='.$this->selected_year.'&month='.$this->selected_month; + } + + + /** + * Ajax function to remove a file from an artwork + * + * @return null + */ + public function executeRemoveFileFromArtwork() + { + try + { + $artwork = new genericArtwork($this->getRequestParameter('artwork')); + + $this->forward404Unless($this->getRequest()->isXMLHttpRequest() && $this->getUser()->isAuthenticated() + && $artwork->getFilesCount() > 1 + && ($artwork->getUserId() == $this->getUser()->getId() || $this->getUser()->hasCredential("editusercontent")));; + $artwork->removeFile($this->getRequestParameter('file')); + } + catch (Exception $e) + { + $this->forward404(); + } + + return $this->renderText("ok"); + } + + /** + * Show list of rejected artworks + * + * @return void + */ + public function executeListModified() + { + $this->forward404Unless($this->getUser()->hasCredential('approveartwork')); + $this->pager = ReaktorArtworkPeer::getArtworkByStatusAndCredentialsPaginated(3, $this->getUser()->listCredentials(), null, null, true); + $this->arts = array(); + $this->pager->setPage($this->getRequestParameter('page', 1)); + $this->pager->init(); + + foreach ($this->pager->getResults() as $artwork) + { + $this->arts[] = new genericArtwork($artwork); + } + } + + /** + * Show list of rejected artworks + * + * @return void + */ + public function executeListRejectedFiles() + { + $this->forward404Unless($this->getUser()->isAuthenticated()&&$this->getUser()->hasCredential('approveartwork')); + $this->pager = ReaktorFilePeer::getMarkedUnsuitableFilesPaginated(); + + $this->pager->setPage($this->getRequestParameter('page', 1)); + $this->pager->init(); + $this->files = array(); + + foreach ($this->pager->getResults() as $file) //Get artwork file object and rejection message + { + $artwork_file = new artworkFile($file); + $artwork_file->setRejectedMessage(ReaktorArtworkHistoryPeer::getLatestRejectionMessage($artwork_file->getId(), true, true)); + + $this->files[] = $artwork_file; + } + } + + /** + * Update artwork order when dragging and dropping + * + * @return null + */ + public function executeUpdateArtworkOrder() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + try + { + $artworkList = $this->getRequestParameter('artwork_list'); + + foreach ($artworkList as $key => $artworkId) + { + $artwork = ReaktorArtworkPeer::retrieveByPK($artworkId); + $artwork->setArtworkOrder($key); + $artwork->save(); + } + return $this->renderText("ok"); + + } + catch (Exception $e) + { + return $this->renderText($this->getContext()->getI18N()->__("An error occured, your list was not updated")); + } + } + + /** + * Discuss an artwork + * + * @return void + */ + public function executeDiscuss() + { + $id = $this->getRequestParameter('id'); + + $this->forward404Unless($id && $this->getUser()->hasCredential('discussartwork')); + + try + { + switch ($this->getRequestParameter('type')) + { + case "artwork": + $this->object = new genericArtwork($id); + $this->type = "artwork"; + break; + case "file": + $this->object = new artworkFile($id); + $this->type = "file"; + break; + default: + throw new Exception(); + break; + } + } + catch (Exception $e) + { + $this->forward404(); + } + } + + /** + * List artwork files with reported flag set + * + * @return void + */ + public function executeListReportedContent() + { + $this->forward404Unless($this->getUser()->hasCredential('approveartwork')); + $this->pager = ReaktorFilePeer::getReportedFilesPaginated(); + $this->pager->setPage($this->getRequestParameter('page', 1)); + $this->pager->init(); + $this->reported_files = array(); + + $artwork_files = $this->pager->getResults(); + + $this->counter = array(); + + foreach ($artwork_files as $artwork_file) + { + $this->reported_files[] = new artworkFile($artwork_file->getId()); + } + } + + /** + * update portfolio artwork list + * + * @return void + */ + public function executeLastArtworksFromUserAction() + { + $this->orderBy = $this->getRequestParameter('orderBy'); + $this->userid = $this->getRequestParameter('userid'); + $this->user = sfGuardUserPeer::retrieveByPk($this->userid); + } + + /** + * Relate an artwork to another, so they + * + * @return void + */ + public function executeRelateArtwork() + { + //Security: display if ajax, and the logged in user is admin or owns the artwork + if (!$this->getRequest()->isXmlHttpRequest()) + { + //User shouldn't be here + die(); + } + + $this->forward404Unless($this->getRequestParameter('id') && $this->getRequestParameter('relate_artwork_select')); + + $user = $this->getUser(); + $artwork = new genericArtwork($this->getRequestParameter('id')); + $artwork2 = new genericArtwork($this->getRequestParameter('relate_artwork_select')); + + //We need to check and pass on the usercanedit variable + $usercanedit = ($user->isAuthenticated() && + ($user->getGuardUser()->getId() == $artwork->getUserId() || + $user->hasCredential('createcompositeartwork') || + $user->hasCredential('editusercontent'))) ? true : false; + $this->forward404Unless($usercanedit); + + //check the artworks are owned by the same user, or this is an admin user creating composite relationships + $this->forward404Unless($artwork->getUserId() == $artwork2->getUserId() || $this->getUser()->hasCredential("createcompositeartwork")); + + //Make sure we don't add a relation that already exists + if (!$artwork->isRelated($artwork2->getId())) + { + //Add relation + RelatedArtworkPeer::addRelatedArtwork($artwork->getId(), $artwork2->getId(), $artwork->getUserId()); + } + + sfLoader::loadHelpers(array('Partial')); + + return $this->renderText( + get_component('artwork', 'linkRelated', array( + 'artwork' => $artwork, + 'usercanedit' => $usercanedit, + 'editmode' => 1 + ))); + + } + + public function executeCrossRelateArtwork() + { + $this->forward404Unless($this->getUser()->isAuthenticated()); + $this->forward404Unless($this->getUser()->hasCredential("createcompositeartwork")); + $this->forward404Unless($this->getRequestParameter('id')); + $userid = $this->getUser()->getId(); + $artwork = new genericArtwork($this->getRequestParameter('id')); + $relatedArtworksClone = $relatedArtworks = $artwork->getRelatedArtworks(0, 0); + foreach($relatedArtworks as $related) + { + foreach($relatedArtworksClone as $current) + { + $this->relate($related, $current, $userid); + } + } + return $this->renderText("OK"); + } + protected function relate($a, $b, $userid) + { + if (!$a->isRelated($b->getId())) + { + RelatedArtworkPeer::addRelatedArtwork($a->getId(), $b->getId(), $userid); + } + if (!$b->isRelated($a->getId())) + { + RelatedArtworkPeer::addRelatedArtwork($b->getId(), $a->getId(), $userid); + } + + } + + public function executeRemoveArtworkRelation() + { + $this->forward404Unless($this->getUser()->isAuthenticated()); + //Security: display if ajax, and the logged in user is admin or own the mypage + if (!$this->getRequest()->isXmlHttpRequest()) + { + //User shouldn't be here + die(); + } + + $user = $this->getUser(); + $id1 = $this->getRequestParameter('viewartwork'); + $id2 = $this->getRequestParameter('relatedartwork'); + + $this->forward404Unless($id1&&$id2); + + $artwork1 = new genericArtwork($id1); + $artwork2 = new genericArtwork($id2); + + //Check if owner of artworks are the same user + $this->forward404Unless($artwork1->getUserId()==$artwork2->getUserId()); + + //Check if user can edit + $usercanedit = ($user->isAuthenticated() && + ($user->getGuardUser()->getId() == $artwork1->getUserId() || + $user->hasCredential('editusercontent'))); + + $this->forward404Unless($usercanedit); + + RelatedArtworkPeer::deleteRelation($id1, $id2); + + sfLoader::loadHelpers(array('Partial')); + + return $this->renderText( + get_component('artwork', 'linkRelated', array( + 'artwork' => $artwork1, + 'usercanedit' => $usercanedit, + 'editmode' => 1 + ))); + + } + + /** + * Validation adding categories and subreaktors to articles. + * + * If trying to remove a subreaktor from an already published article validation must fail. + * + * @return boolean true if validation succeeds, false if not + */ + public function validateCategoryAction() + { + if ($this->getRequestParameter('articleId') && $this->getRequestParameter("subreaktorClick")) + { + $article = ArticlePeer::retrieveByPK($this->getRequestParameter('articleId')); + + //Article is published and last subreaktor tried to be removed + if ($article->isPublished() && !$this->getRequestParameter("subreaktorChecked")) + { + return false; + } + } + return true; + } + + /** + * Handle error with adding subreaktors to articles + * + * User tried to remove a subreaktor from an already published article, thus validation failed. + * + * @return string Rendered html of component for subreaktor/format and categories selection (with error message set) + */ + public function handleErrorCategoryAction() + { + $article = ArticlePeer::retrieveByPK($this->getRequestParameter('articleId')); + sfLoader::loadHelpers(array('Partial')); + + return $this->renderText(get_component("artwork", "categorySelect", array( + "article" => $article, + "ajaxCall" => true, + "error_msg" => 1, + ))); + } + + /** + * Ajax function for handling category and subreaktor selections + * + * @return Ajax output + * + */ + public function executeCategoryAction() + { + $this->forward404Unless($this->getUser()->isAuthenticated() && + $this->getRequest()->getMethod() == sfRequest::POST); + + //Subreaktor and categories can be added to artworks or articles + $isArtwork = false; + $isArticle = false; + $object = null; + + if ($this->getRequestParameter('artworkId')) //Create object and test for correct credentials + { + $isArtwork = true; + $object = new genericArtwork($this->getRequestParameter("artworkId")); + + $this->forward404Unless($this->getUser()->getGuardUser()->getId() == $object->getUserId() || + $this->getUser()->hasCredential("editcategories")); + } + elseif ($this->getRequestParameter('articleId')) + { + $isArticle = true; + $object = ArticlePeer::retrieveByPK($this->getRequestParameter('articleId')); + } + + // Are we working with subreaktors or categories? + if ($this->getRequestParameter("subreaktorClick")) //Add/remove subreakors + { + $subreaktors = $this->getRequestParameter("subreaktorChecked", array()); + $previousArray = $this->getRequestParameter("current", array()); + $object->updateSubreaktors($subreaktors, $previousArray); + + if ($isArtwork) + { + // We should now reassign this to a new editorial team based on the click - but only if this artwork + // has not been submitted already + if (!$object->isSubmitted()) + { + $object->resetEditorialTeam(); + } + + if ($object->getStatus() == 3 && !$this->getUser()->hasCredential("editcategories")) + { + //This makes sure the extract script will find it for translation + $translateMe = sfContext::getInstance()->geti18n()->__("Subreaktors modified"); + $object->flagChanged($this->getUser(), "Subreaktors modified"); + } + $object->save(); + } + + sfLoader::loadHelpers(array('Partial')); + $params = $isArtwork ? array("artwork" => $object, "ajaxCall" => true) : array("article" => $object, "ajaxCall" => true); + return $this->renderText(get_component("artwork", "categorySelect", $params)); + + } + else //Adding/removing categories + { + if ($this->getRequestParameter("add")) + { + if ($isArtwork) + { + $object->addCategory($this->getRequestParameter("add"), $this->getUser()); + } + elseif ($isArticle) + { + $object->addCategory($this->getRequestParameter("add")); + } + } + elseif ($this->getRequestParameter("remove")) + { + $object->removeCategory($this->getRequestParameter("remove")); + } + + if ($isArtwork) + { + if ($object->getStatus() == 3 && !$this->getUser()->hasCredential("editcategories")) + { + //This makes sure the extract script will find it for translation + $translateMe = sfContext::getInstance()->getI18N()->__("Categories changed"); + $object->flagChanged($this->getUser(), "Categories changed"); + $object->save(); + } + // We should now reassign this to a new editorial team based on the click, + // since category changes may affect competition assignment. Onyl applies if has not been submitted already + if (!$object->isSubmitted()) + { + $object->resetEditorialTeam(); + $object->save(); + } + } + + sfLoader::loadHelpers(array('Partial')); + $params = $isArtwork ? array("artwork" => $object) : array("article" => $object); + return $this->renderText(get_component("artwork", "categoryList", $params)); + } + } + + public function executeRecommendations() + { + $this->forward404Unless($this->getUser()->isAuthenticated()&&$this->getUser()->hasCredential('recommendartwork')); + + $this->artwork = new genericArtwork($this->getRequestParameter('id')); + } + + /** + * Handle validation errors when adding a recommendations + * + * @return void + */ + public function handleErrorAddRecommendation() + { + $params = $this->getContext()->getController()->convertUrlStringToParameters($this->getRequestParameter('sf_comment_referer')); + + foreach ($params[1] as $param => $value) + { + $this->getRequest()->setParameter($param, $value); + } + $this->getResponse()->setStatusCode(500); + + $this->forward('artwork', 'recommendations'); + } + + /** + * Recommend an artwork in a subreaktor + * + * @return void + */ + public function executeAddRecommendation() + { + $this->forward404Unless($this->getUser()->isAuthenticated()); + + //Security: display if ajax, and the logged in user is admin or owns the artwork + if (!$this->getRequest()->isXmlHttpRequest()) + { + //User shouldn't be here + die(); + } + //Get the subreaktor or subreaktor:localreaktor the artwork is to be added + $subreaktor = $this->getRequestParameter('recommend_in_subreaktor'); + + //Check credentials + $this->forward404Unless($this->getUser()->hasCredential('recommendartwork') && $subreaktor); + + //Get artwork to be recommended and check that its approved + $artwork = new genericArtwork($this->getRequestParameter('id')); + + //Should never happen + $this->forward404Unless($artwork->getStatus(true)==3); + + //Subraktors and subreaktor:localreaktor needs to be treated differently + $subreaktor_array = explode(':', $subreaktor); + if(count($subreaktor_array)>1) + { + $subreaktor = $subreaktor_array[0]; + $lokalreaktor = $subreaktor_array[1]; + $recommended_in = $subreaktor.':'.$lokalreaktor; + RecommendedArtworkPeer::addRecommendation($this->getUser()->getGuardUser()->getId(), $artwork->getId(), $subreaktor, $lokalreaktor); + } + else + { + RecommendedArtworkPeer::addRecommendation($this->getUser()->getGuardUser()->getId(), $artwork->getId(), $subreaktor); + $recommended_in = $subreaktor; + } + + sfLoader::loadHelpers(array('Partial')); + + // Not nice solution but no other choice - Ticket 23736 + apc_clear_cache('user'); + + //Render component and return it + return $this->renderText( get_component('artwork', 'recommendArtwork', array( + 'artwork' => $artwork, + ))); + } + + function executeUpdateEditorialTeam() + { + $this->forward404Unless($this->getUser()->isAuthenticated()); + + //Security: display if ajax, and the logged in user is admin or owns the artwork + if (!$this->getRequest()->isXmlHttpRequest()) + { + //User shouldn't be here + die(); + } + + $artwork = new genericArtwork($this->getRequestParameter('id')); + $this->forward404Unless($artwork); + + $neweditorialteam = $this->getRequestParameter('new_editorialteam'); + + $artwork->setEditorialTeam($neweditorialteam); + $artwork->save(); + + sfLoader::loadHelpers(array('Partial')); + + //Render component and return it + return $this->renderText( get_component('artwork', 'editorialTeamArtwork', array( + 'artwork' => $artwork, + ))); + } + + /** + * Trigger a transcode process + * + * @return null + */ + function executeReTranscode() + { + $this->forward404Unless($this->getUser()->hasCredential('reruntranscoding')); + $this->id = $this->getRequestParameter('id'); + $file = ReaktorFilePeer::retrieveByPK($this->id, null, true); + + if (file_exists($file->getFullFilePath("original"))) + { + $transcoder = new transcoder(); + $transcodingInfo = $transcoder->transcode($file->getFullFilePath("original"), $file->getRealPath()); + return $this->renderText(sfContext::getInstance()->getI18n()->__("Transcoding has started")); + } + else + { + return $this->renderText(sfContext::getInstance()->getI18n()->__("Original file not found - transcoding could not start")); + } + } + + /** + * Show the transcoder log for a specified file + * + * @return null Render the template + */ + function executeTranscoderLog() + { + $this->forward404Unless($this->getUser()->hasCredential('reruntranscoding')); + $this->file = ReaktorFilePeer::retrieveByPK($this->getRequestParameter('id'), null, true); + $path = $this->file->getFullFilePath().".log"; + if (file_exists($path)) + { + $this->data = file_get_contents($path); + } + else + { + $this->data = false; + } + } + + public function executeListArtworksPopup() + { + $this->forward404Unless($this->getUser()->hasCredential('staff')); + $article = ArticlePeer::retrieveByPK($this->getRequestParameter('article_id')); + $this->forward404Unless($article); + + $artworks = $this->processFilter("filter"); + if (!$artworks) + { + $artworks = ReaktorArtworkPeer::mostPopularArtworks(); + } + $this->artworks = $artworks; + $this->article = $article; + if ($this->getRequest()->isXmlHttpRequest()) + { + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_partial("artwork/listArtworksPopupChoices", array("artworks" => $artworks, "article" => $article))); + } + } + + protected function processFilter($varname,$approved_only = true) + { + $artworks = array(); + if ($tag = $this->getRequestParameter($varname)) + { + if ($approved_only) + { + $matching = TagPeer::getObjectsTaggedWith(array($tag), array("approved" => 1, "parent_approved" => 1), true); + } + else + { + $matching = TagPeer::getObjectsTaggedWith(array($tag), array(), true); + } + foreach ($matching as $match) + { + if (!($match instanceof genericArtwork)) + { + foreach ($match->getParentArtworks() as $artwork) + { + $artworks[] = $artwork; + } + } + else + { + $artworks[] = $match; + } + } + } + return $artworks; + } + + public function executeRelatedFilter() + { + if ($this->getRequest()->isXmlHttpRequest()) + { + $current_artwork = new genericArtwork($this->getRequestParameter("id")); + $artworks = $this->processFilter("filter",false); + + sfLoader::loadHelpers(array('Partial')); + if ($artworks) { + $allArtworks = $artworks; + if ($this->getUser()->hasCredential("createcompositeartwork")) + { + foreach($allArtworks as $key => $thisArtwork) + { + // Don't show already related artworks + if ($current_artwork->isRelated($thisArtwork->getId())) + { + unset($artworks[$key]); + } + } + } + // If he asn't karma for composite artworks, only show his own + else + { + foreach($allArtworks as $key => $thisArtwork) + { + if (!($thisArtwork->getUserId() == $this->getUser()->getId())) + { + unset($artworks[$key]); + } + elseif ($current_artwork->isRelated($thisArtwork->getId())) + { + unset($artworks[$key]); + } + } + } + if ($this->getRequestParameter('autocompleter')=='false') + { + if ($artworks) + { + return $this->renderText(get_partial("artwork/linkRelatedChoices", array("artworks" => $artworks, "thisArtwork" => $current_artwork))); + } else + { + return $this->renderText("
    • " . sfContext::getInstance()->geti18n()->__("Can't find any unrelated artworks tagged with %tagname%", array("%tagname%" => $this->getRequestParameter("filter"))) . "
    " ); + } + } + } + $hasNoTags = true; + if ($this->getRequestParameter('autocompleter')=='true') + { + + $output = "
      "; + foreach(TagPeer::getTagsStartingWithString($this->getRequestParameter("filter"),0,$this->getUser()) as $tag) + { + $output .= "
    • ".$tag->getName()."
    • "; + $hasNoTags = false; + } + $output .= "
    "; + } else + { + return $this->renderText("
    • " . sfContext::getInstance()->geti18n()->__("Can't find any unrelated artworks tagged with %tagname%", array("%tagname%" => $this->getRequestParameter("filter"))) . "
    " ); + } + + return $this->renderText($output); + } + $this->forward404(); + } + + public function executeResolveArtworkId() + { + $this->forward404Unless($this->getUser()->hasCredential('staff')); + $artwork = ReaktorArtworkPeer::retrieveByPK($this->getRequestParameter("id")); + + sfLoader::loadHelpers(array('content')); + $retval = showMiniThumb(new genericArtwork($artwork), true); + $output = json_encode(array($retval)); + + //return $this->renderText($retval); + $this->getResponse()->setHttpHeader("X-JSON", '('.$output.')'); + + return sfView::HEADER_ONLY; + } + + /** + * Ajax action for refreshing the file list on an artwork edit page, once something has changed elsewhere + * (such as tags) + * + * @return null + */ + public function executeUpdateFileList() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && $this->getUser()->isAuthenticated()); + + try + { + $artwork = new genericArtwork($this->getRequestParameter("artworkId", 0)); + } + catch (Exception $e) + { + $this->forward404(); + } + + $this->forward404Unless($this->getUser()->getId() == $artwork->getUserId() || $this->getUser()->hasCredential("viewallcontent")); + $completeFuncs = "updateArtworkTagList(0, ".$artwork->getId().");"; + + sfLoader::loadHelpers("Partial"); + return $this->renderText(get_partial("artwork/draganddroplist", array("artwork" => $artwork, "options" => array("completeFuncs" => $completeFuncs, "artworkList" => $artwork->getId())))); + } + + /** + * Ajax action for refreshing the tag list on an artwork edit page, once something has changed elsewhere + * (such as tags on the file list) This only applies if the artwork has one file, in which case the artwork tag list + * is the same as the list next to the file + * + * @return null + */ + public function executeUpdateArtworkTagList() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && $this->getUser()->isAuthenticated()); + + try + { + $artwork = new genericArtwork($this->getRequestParameter("artworkId")); + + if ($this->getRequestParameter("fileId")) + { + $file = new artworkFile($this->getRequestParameter("fileId", 0)); + } + else + { + $file = $artwork->getFirstFile(); + } + } + catch (Exception $e) + { + $this->forward404(); + } + + $this->forward404Unless($this->getUser()->getId() == $file->getUserId() || $this->getUser()->hasCredential("viewallcontent")); + $completeFuncs = "updateFileList(".$artwork->getId().");"; + + sfLoader::loadHelpers("Partial"); + return $this->renderText(get_component("tags", "tagEditList", array("taggableObject" => $artwork, "options" => array("completeFuncs" => $completeFuncs, "artworkList" => $this->getRequestParameter("artworkId"))))); + } +} + diff --git a/apps/reaktor/modules/artwork/actions/components.class.php b/apps/reaktor/modules/artwork/actions/components.class.php new file mode 100644 index 0000000..f7c221e --- /dev/null +++ b/apps/reaktor/modules/artwork/actions/components.class.php @@ -0,0 +1,526 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class artworkComponents extends sfComponents +{ + /** + * Display the last created artworks + * + * @return void + */ + function executeLastArtworks() + { + + $cache = reaktorCache::singleton($this->genExcludeKey()); + +// Ticket 25288 + if ($this->last ) + { + $list = (array)$cache->get(); + foreach($this->last as $art) + { + if ($art instanceof genericArtwork) + { + $list[] = $art->getId(); + } + } + $list = array_unique($list); + $cache->update($list); + } + else + + { + if(!$this->limit)//If limit isn't set, use configuration instead + { + $this->limit = sfConfig::get('app_home_list_length', 5); + } + $exclude = $cache->get(); + + //The first artwork could be displayed another place on the site, and should be excluded in the list, + //thus to keep the limit we add one more to the list + $count = ($this->exclude_first) ? ($this->limit+$this->exclude_first) : $this->limit; + + + if (!$this->last ) + $this->last = ReaktorArtworkPeer::getLatestSubmittedApproved($count+count($exclude), null, $this->random, $this->subreaktor, $this->lokalreaktor); + + //Remove first if parameter is set + if($this->exclude_first) + { + array_shift($this->last); + } + + if ($exclude) + { + $last = $this->last; + foreach($last as $key => $artwork) + { + if (in_array($artwork->getId(), $exclude)) + { + unset($this->last[$key]); + } + } + } + + // Make sure we don't return more then requested + if (count($this->last) > $this->limit) + { + $this->last = array_slice($this->last, 0, $this->limit); + } + } + + $this->image = (isset($this->image)) ? $this->image : ''; + $this->tags = (isset($this->tags)) ? $this->tags : ''; + $this->subreaktor = (isset($this->subreaktor)) ? $this->subreaktor : ''; + $this->lokalreaktor = (isset($this->lokalreaktor)) ? $this->lokalreaktor : ''; + $this->feed_description = sfContext::getInstance()->getI18N()->__('Latest artworks'); + $this->feed_slug = 'latest_artworks'; + } + + function executeListPresentation() + { + + } + + /** + * Display the latest commented artwork + * + * @return void + */ + function executeLatestCommented() + { + $this->latestCommented = ReaktorArtworkPeer::getLatestCommented(sfConfig::get('app_home_list_length', 5)); + } + + /** + * Display images of last artworks from user + * + * @return void + */ + function executeLastArtworksFromUser() + { + if (isset($this->portfolio)) + { + if (!$this->orderBy) + { + $this->orderBy = $this->getRequestParameter('orderBy'); + } + $artworks = ReaktorArtworkPeer::getLatestSubmittedApprovedPaginated(SfConfig::get('app_profile_portfolio_pagination', 21), $this->id, $this->orderBy); + $artworks->setPage($this->getRequestParameter('page', 1)); + $artworks->init(); + $this->last = $artworks->getResults(); + $this->artworks = $artworks; + + } else { + $this->last = ReaktorArtworkPeer::getLatestSubmittedApproved(6, $this->id, null, null, null, true, false); + $this->mypage = true; + } + $this->viewingMyOwnPage = $this->getUser()->getId() == $this->id; + } + + /** + * List a users most popular artworks + * + * @return void + */ + function executeListUsersPopularArtworks() + { + $count = $this->limit ? $this->limit : sfConfig::get('app_home_list_length', 5); + $this->artworks = ReaktorArtworkPeer::mostPopularArtworks($this->subreaktor, $count, $this->lokalreaktor, $this->user); + } + + /** + * List a users most popular artworks + * + * @return void + */ + function executeListReaktorsLatestArtworks() + { + $this->artworks = ReaktorArtworkPeer::getLatestSubmittedApproved(6, null, null, $this->subreaktor); + array_shift($this->artworks); + } + + /** + * List a subreaktors most popular artworks + * + * @return void + */ + function executeListReaktorsPopularArtworks() + { + //If limit isn't set, use configuration instead + $count = $this->limit ? $this->limit : sfConfig::get('app_home_list_length', 6); + $this->subreaktor = (isset($this->subreaktor)) ? $this->subreaktor : ''; + $this->lokalreaktor = (isset($this->lokalreaktor)) ? $this->lokalreaktor : ''; + $this->artworks = ReaktorArtworkPeer::mostPopularArtworks($this->subreaktor, $count, $this->lokalreaktor); + + // Throw these artworks into a "don't show these artworks again on this page" list + $cache = reaktorCache::singleton($this->genExcludeKey()); + $list = (array)$cache->get(); + foreach((array)$this->artworks as $artwork) + { + $list[] = $artwork->getId(); + } + $list = array_unique($list); + $cache->update($list); + + $this->text_or_artwork = (isset($this->text_or_artwork)) ? $this->text_or_artwork : ''; + $this->image = (isset($this->image)) ? $this->image : ''; + $this->feed_description = (isset($this->feed_description)) ? $this->feed_description : sfContext::getInstance()->getI18N()->__('Most popular'); + $this->feed_slug = (isset($this->feed_slug)) ? $this->feed_slug : 'most_popular'; + } + + private function genExcludeKey() + { + static $key = null; + + if ($key === null) + { + $key = "exclude_artwork_ids"; + $sub = Subreaktor::getProvidedSubreaktorReference(); + $lok = Subreaktor::getProvidedLokalReference(); + $key = "{$key}_sub{$sub}_lok{$lok}"; + } + return $key; + } + + /** + * Lists related artworks + * + * @return void Renders the seeAlso component template + */ + function executeSeeAlso() + { + $onlyApproved = !$this->editmode; + $this->relatedArtworks = $this->artwork->getRelatedArtworks(0, $onlyApproved); + $this->otherpeoplelike = array(); + $this->otherArtworks = array(); + $this->otherpeoplelike = RelatedArtworkPeer::getOtherRelatedArtworkObjects($this->artwork->getId(), sfConfig::get("app_artwork_other_usrs_also_like", 6)); + + if (count($this->relatedArtworks) == 0) + { + $this->otherArtworks = ReaktorArtworkPeer::getArtworksByUser($this->artwork->getUser(), sfConfig::get("app_artwork_other_by_user", 6), true, array($this->artwork)); + } + } + + /** + * Display the link to artworks dropdown, and the see also list. When an artwork is + * linked to another artwork, this adds to the see also list. + * + * @return void + */ + function executeLinkRelated() + { + if ($this->editmode) + { + $onlyApproved = false; + } + else + { + $onlyApproved = true; + } + + //Find the related artworks + $related_artworks = $this->artwork->getRelatedArtworks(null, $onlyApproved); + + //Get the id's of the related artworks + $related = array(); + foreach($related_artworks as $related_artwork) + { + $related[] = $related_artwork->getId(); + } + //Include the artwork itself + $related[] = $this->artwork->getId(); + + + //Find all artworks that aren't related + if ($this->getUser()->hasCredential("createcompositeartwork")) + { + $this->artworks = ReaktorArtworkPeer::getUnrelatedArtworks(null, null, $related, $onlyApproved, 5); + } + else + { + $this->artworks = ReaktorArtworkPeer::getUnrelatedArtworks($this->artwork->getUser()->getId(), $this->artwork->getId(), $related, $onlyApproved, 5); + } + + } + + /** + * Display recommended artwork given a subreaktor + * + * @return void + */ + function executeRecommended() + { + static $cache = null; + if ($cache === null && $cache = reaktorCache::singleton($this->genExcludeKey())); + + $recommended_artwork = RecommendedArtworkPeer::getRecommendedArtwork($this->subreaktor, $this->lokalreaktor, true); + $this->artwork = $recommended_artwork ? new genericArtwork($recommended_artwork->getArtwork()) : null ; + + if ($recommended_artwork) + { + // Throw these artworks into a "don't show these artworks again on this page" list + $list = (array)$cache->get(); + $list[] = $this->artwork->getId(); + $list = array_unique($list); + $cache->update($list); + } + } + + /** + * Show the category and subreaktor/format selections + * + * @return void + */ + function executeCategorySelect() + { + $eligibleLokalReaktors = array(); + if(!($this->article && $this->article->getArticleType() == ArticlePeer::HELP_ARTICLE)) //Don't display lokalreaktor on help articles + { + if ($this->getUser()->hasCredential("editusercontent")) //Allow admin users to add additional lokalreaktors to artwork + { + $eligibleLokalReaktors = SubreaktorPeer::getLokalReaktors(); + } + elseif ($this->artwork) + { + $eligibleLokalReaktors = $this->artwork->getLokalreaktors(); + } + } + + // First we need a list of eligible subreaktors and categories for this file + if ($this->artwork) + { + $eligibleSubreaktors = SubreaktorIdentifierPeer::getEligibleSubreaktors($this->artwork); + } + else + { + $eligibleSubreaktors = SubreaktorPeer::getSubReaktors(false,true); + } + + // The first result should never be empty, but if admin are being silly, we should return something + // for the user if there are no linked subreaktors - we'll give them the whole list to choose from. + if (empty($eligibleSubreaktors)) + { + $eligibleSubreaktors = SubreaktorPeer::doSelectWithI18n(new Criteria()); + } + elseif(count($eligibleSubreaktors) == 1) + { + $subreaktor = current($eligibleSubreaktors); + $this->artwork->addSubreaktor($subreaktor->getId()); + + // If there is only one eligible subreaktor, the checkboxes will never be checked, so we should set the editorial team now + if ($this->artwork->isDraft()) + { + $this->artwork->resetEditorialTeam(); + $this->artwork->save(); + } + } + + // Get the subreaktors already associated with this file/artwork + // This function returns references (film, lyd, etc) from subreaktor table + if ($this->artwork) + { + $artworkSubreaktors = $this->artwork->getSubreaktors(true); + } + elseif ($this->article) + { + $artworkSubreaktors = $this->article->getSubreaktors(true); + } + + // Ok, lets pass the arrays to the template for parsing + $this->eligibleSubreaktors = $eligibleSubreaktors; + $this->eligibleLokalReaktors = $eligibleLokalReaktors; + $this->artworkSubreaktors = array_keys($artworkSubreaktors); + + } + + /** + * Show the list of currently selected categories + * + * @return void + */ + function executeCategoryList() + { + if ($this->artwork) + { + $artworkSubreaktors = $this->artwork->getSubreaktors(); + $artworkCategories = $this->artwork->getCategories(); // Returns array of cats with id as key + } + elseif ($this->article) + { + $artworkSubreaktors = $this->article->getSubreaktors(); + $artworkCategories = $this->article->getCategories(); // Returns array of cats with id as key + } + $eligibleCategories = CategorySubreaktorPeer::getCategoriesUsedBySubreaktor($artworkSubreaktors, false); + $otherCategories = array_diff($artworkCategories, $eligibleCategories); + + $this->eligibleCategories = $eligibleCategories; + $this->artworkCategories = array_keys($artworkCategories); + + $this->otherCategories = $otherCategories; + } + + /** + * Display artwork recommendation information, i.e which subreaktors an artwork + * is recommended in, and where it can be recommended + * + * @return void + */ + function executeRecommendArtwork() + { + //First we find all the recommendations an artwork has + $this->recommendations = RecommendedArtworkPeer::getArtworkRecommendations($this->artwork->getId()); + + //We now check which subreaktors the artwork belongs to, both in subreaktors and lokalreaktor:subreaktor + //because we want to display the possible subreaktors an artwork can be recommended in + + $subreaktors = SubreaktorArtworkPeer::getSubreaktorsByArtwork($this->artwork->getId()); + $subreaktor_array = array(); + + if (sfContext::getInstance()->getUser()->hasCredential('viewothereditorialteams')) + foreach ($subreaktors as $subreaktor) + { + $subreaktor_array[$subreaktor->getSubreaktor()->getId()] = $subreaktor->getSubreaktor()->getReference(); + } + + $lokalreaktors = LokalreaktorArtworkPeer::getLokalreaktorsByArtwork($this->artwork->getId()); + foreach ($lokalreaktors as $lokalreaktor) + { + + $canRecommend=false; + foreach (sfContext::getInstance()->getUser()->getGuardUser()->getEditorialTeams() as $aTeam) + if($this->artwork->getEditorialTeam()->getId()==$aTeam->getId()) $canRecommend=true; + +if (sfContext::getInstance()->getUser()->hasCredential('viewothereditorialteams') || $canRecommend) + foreach ($subreaktors as $subreaktor) + { + $subreaktor_array[$lokalreaktor->getSubreaktor()->getId().':'.$subreaktor->getSubreaktor()->getId()] = + $lokalreaktor->getSubreaktor()->getReference().':'.$subreaktor->getSubreaktor()->getReference(); + } + } + + //We don't want the user to recommend an artwork in a subreaktor where it's already recommended, so + //we remove those reaktors from the dropdown + foreach ($this->recommendations as $recommendation) + { + if ($recommendation->getLocalsubreaktor()->getId()) + { + unset($subreaktor_array[$recommendation->getSubreaktor()->getId().':'.$recommendation->getLocalsubreaktor()->getId()]); + } + else + { + unset($subreaktor_array[$recommendation->getSubreaktor()->getId()]); + } + } + + $this->subreaktor_array = $subreaktor_array; + } + + function executeEditorialTeamArtwork() + { + $crit = new Criteria(); + $crit->add(sfGuardGroupPeer::IS_ENABLED, true); + $crit->add(sfGuardGroupPeer::IS_EDITORIAL_TEAM, true); + $available_teams = SfGuardGroupPeer::doSelect($crit); + $this->available_teams = array(); + foreach ($available_teams as $aTeam) + { + $this->available_teams[$aTeam->getId()] = $aTeam->getDescription(); + } + } + + /** + * Embed link component for correctly displaying links to embed artwork in another site + * + * @return void the component is rendered + */ + function executeEmbedLink() + { + $options = array(); + + if (isset($this->options)) $options = $this->options; + + //sfLoader::loadHelpers('Javascript'); + + switch ($this->file->getIdentifier()) + { + case 'image': + $img_title = $this->getRequest()->getHost() . ' - ' . $this->file->getTitle(); + $this->link = link_to(image_tag('http://' . $this->getRequest()->getHost() . contentPath($this->file), + array('title' => $img_title, + 'alt' => $this->img_title)), + 'http://' . $this->getRequest()->getHost() . url_for($this->artwork->getLink()), + array('title' => $this->file->getTitle(), + 'alt' => $this->file->getTitle())); + $this->bb_link = '[url=' . 'http://' . $this->getRequest()->getHost() . url_for($this->artwork->getLink()) . '][img]' . 'http://' . $this->getRequest()->getHost() . contentPath($this->file) . '[/img][/url]'; + $this->file_path = 'http://'.$this->getRequest()->getHost().contentPath($this->file); + break; + case 'pdf': + $img_title = $this->getRequest()->getHost().' - '.$this->file->getTitle(); + //Added .jpg to the end of this as forums and some sites don't like image extensions they don't recognise! Updated content server to allow it. + $this->link = link_to(image_tag('http://'.$this->getRequest()->getHost() . contentPath($this->file, 'thumb').'.jpg', + array('title' => $img_title, + 'alt' => $this->img_title)), + 'http://' . $this->getRequest()->getHost().url_for($this->artwork->getLink()), + array('title' => $this->file->getTitle(), + 'alt' => $this->file->getTitle())); + $this->bb_link = '[url=' . 'http://' . $this->getRequest()->getHost().url_for($this->artwork->getLink()).'][img]'.'http://' . $this->getRequest()->getHost() . contentPath($this->file, 'thumb') . '.jpg[/img][/url]'; + $this->file_path = 'http://'.$this->getRequest()->getHost().contentPath($this->file); + break; + case 'video': + $this->link = "getRequest()->getHost()."/flowplayer/FlowPlayerLight.swf?config={embedded:true,"; + $this->link .= "autoRewind:true, loop:false, videoFile:'".contentPath($this->file)."', "; + $this->link .= "baseURL:'http://".$this->getRequest()->getHost()."/'} \" "; + $this->link .= "width=\"480\" height=\"360\" >"; + $this->link .= '
    '.link_to('http://'.$this->getRequest()->getHost().' - '.$this->artwork->getTitle().' '.sfContext::getInstance()->getI18N()->__('by').' '.$this->artwork->getUser()->getUsername(), + 'http://' . $this->getRequest()->getHost() . url_for($this->artwork->getLink()), + array('title' => $this->file->getTitle(), + 'alt' => $this->file->getTitle())); + break; + case 'text': + $img_title = $this->getRequest()->getHost().' - '.$this->file->getTitle(); + $this->link = link_to(image_tag('http://' . $this->getRequest()->getHost().contentPath($this->file), + array('title' => $img_title, + 'alt' => $this->img_title)), + 'http://' . $this->getRequest()->getHost().url_for($this->artwork->getLink()), + array('title' => $this->file->getTitle(), + 'alt' => $this->file->getTitle())); + $this->bb_link = '[url=' . 'http://' . $this->getRequest()->getHost() . url_for($this->artwork->getLink()) . '][img]' . 'http://' . $this->getRequest()->getHost() . contentPath($this->file, 'thumb') . '.jpg[/img][/url]'; + $this->file_path = 'http://'.$this->getRequest()->getHost().contentPath($this->file); + break; + case 'audio': + $this->link = 'link .= 'codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" '; + $this->link .= 'width="400" height="168">'; + $this->link .= ''; + $this->link .= ''; + $this->link .= ''; + $this->link .= 'link .= 'quality="high" bgcolor="#E6E6E6" '; + $this->link .= 'name="xspf_player" allowscriptaccess="sameDomain" '; + $this->link .= 'type="application/x-shockwave-flash" '; + $this->link .= 'pluginspage="http://www.macromedia.com/go/getflashplayer" '; + $this->link .= 'align="center" height="168" width="400">'; + $this->link .= ''; + $this->link .= '
    '.link_to('http://'.$this->getRequest()->getHost().' - '.$this->artwork->getTitle().' '.sfContext::getInstance()->getI18N()->__('by').' '.$this->artwork->getUser()->getUsername(), + 'http://' . $this->getRequest()->getHost() . url_for($this->artwork->getLink()), + array('title' => $this->file->getTitle(), + 'alt' => $this->file->getTitle())); + break; + } + + } + + public function executeUserArtworkListElement() + { + } + +} + diff --git a/apps/reaktor/modules/artwork/config/cache.yml b/apps/reaktor/modules/artwork/config/cache.yml new file mode 100644 index 0000000..5cf8a11 --- /dev/null +++ b/apps/reaktor/modules/artwork/config/cache.yml @@ -0,0 +1,4 @@ +_lastArtworks: + enabled: off + + diff --git a/apps/reaktor/modules/artwork/config/security.yml b/apps/reaktor/modules/artwork/config/security.yml new file mode 100644 index 0000000..2fa599a --- /dev/null +++ b/apps/reaktor/modules/artwork/config/security.yml @@ -0,0 +1,11 @@ +#All users should be able to view tags +all: + is_secure: off + +listUnapprovedMyTeams: + is_secure: on + credentials: staff + +listUnapprovedOtherTeams: + is_secure: on + credentials: viewothereditorialteams \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/config/view.yml b/apps/reaktor/modules/artwork/config/view.yml new file mode 100644 index 0000000..5fd2e6e --- /dev/null +++ b/apps/reaktor/modules/artwork/config/view.yml @@ -0,0 +1,27 @@ +all: + javascripts: [lightwindow, effects, socialBookmarks] + stylesheets: [/css/genericajax: {media: all}, /css/lightwindow, /css/sf_rating, /css/hidefooterimages: {media: print}] + +editNodecor: + has_layout: false + +listDiscussionSuccess: + http_metas: + Pragma: no-cache + Cache-Control: no-cache + +listUnapprovedSuccess: + http_metas: + Pragma: no-cache + Cache-Control: no-cache + +rejectArtworkSuccess: + http_metas: + Pragma: no-cache + Cache-Control: no-cache + + +listRejectedSuccess: + http_metas: + Pragma: no-cache + Cache-Control: no-cache diff --git a/apps/reaktor/modules/artwork/templates/_adminButtons.php b/apps/reaktor/modules/artwork/templates/_adminButtons.php new file mode 100644 index 0000000..5d4b6e4 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_adminButtons.php @@ -0,0 +1,115 @@ + $artwork)) + * + * The parameters passed are: + * $artwork - A reaktorArtwork object + * + * PHP Version 5 + * + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript", "button"); + +$this_id = $object->getId(); + +?> + + diff --git a/apps/reaktor/modules/artwork/templates/_artworkDisplay.php b/apps/reaktor/modules/artwork/templates/_artworkDisplay.php new file mode 100644 index 0000000..d88a52a --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_artworkDisplay.php @@ -0,0 +1,63 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +switch($thefile->getFiletype()) +{ + case('image'): + include_partial("slideshow", array("thefile" => $thefile, "artwork" => $artwork)); + break; + case('video'): + include_partial("displayPlayer", array("mode" => "video", "file" => $thefile)); + break; + case('flash_animation'): + echo '"; + } + echo '" caption="' . $thefile->getMetadata('description', 'abstract') . + '" title="' . $thefile->getTitle() . '">'; + echo image_tag(contentPath($thefile, 'thumb')); + echo '

    '; + echo '

    '; + echo __('This is an interactive Flash animation, which needs to be started manually. +
    Click here to start this interactive Flash animation: %link_to_launch%', + array('%link_to_launch%' => '" : '') . + '" params="lightwindow_width=850,lightwindow_height=600" closetext="'.__("close").'" caption="' . + $thefile->getMetadata('description', 'abstract') . '" title="' . $thefile->getTitle() . '">' . + __('Launch this animation') . '')); + echo '

    '; + break; + case('audio'): + include_partial("displayPlayer", array("mode" => "audio", "file" => $thefile, 'artwork' => $artwork)); + break; + case('pdf'): + echo link_to(image_tag(contentPath($thefile->getId(), 'thumb')), contentPath($thefile->getId(), '', true), + array("title" => $thefile->getTitle())); + break; + case('text'): + echo "
    "; + echo nl2br(file_get_contents(sfConfig::get('app_artwork_content_path', '../content/') . 'text/'.$thefile->getRealpath())) ; + echo "
    "; + break; + default: + echo 'MIMETYPE NOT HANDLED!!! ' . $thefile->getMimetype() . ' ' . $thefile->getFiletype(); + break; +} + + +?> diff --git a/apps/reaktor/modules/artwork/templates/_artworkNavLinks.php b/apps/reaktor/modules/artwork/templates/_artworkNavLinks.php new file mode 100644 index 0000000..cf34539 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_artworkNavLinks.php @@ -0,0 +1,51 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + +
    > +
    + getPreviousFile($thefile->getId())): ?> + ("Tip('".__("Go to first file: %title%", array("%title%" => $artwork->getFirstFile()->getTitle()."');"))), + "onMouseOut" => "UnTip();")), + $artwork->getLink('show', $artwork->getFirstFile()->getId())); ?> + ("Tip('".__("Go to previous file: %title%", array("%title%" => $prevfile->getTitle()."');"))), + "onMouseOut" => "UnTip();")), + $artwork->getLink('show', $prevfile->getId())); ?> + + + + + +
    +
    + getNextFile($thefile->getId())): ?> + ("Tip('".__("Go to next file: %title%", array("%title%" => $nextfile->getTitle()."');"))), + "onMouseOut" => "UnTip();")), + $artwork->getLink('show', $nextfile->getId())); ?> + ("Tip('".__("Go to last file: %title%", array("%title%" => $artwork->getLastFile()->getTitle()."');"))), + "onMouseOut" => "UnTip();")), + $artwork->getLink('show', $artwork->getLastFile()->getId())); ?> + + + + +
    +
    \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_artworkRating.php b/apps/reaktor/modules/artwork/templates/_artworkRating.php new file mode 100644 index 0000000..6d5eff0 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_artworkRating.php @@ -0,0 +1,37 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?> +'.__("Rating:").''; + +if ($sf_user->isAuthenticated() && $sf_user->getGuardUser()->getId() != $artwork->getUserId() && $noedit && $sf_user->hasCredential('rateartwork')): + echo sf_rater($artwork->getBaseObject()); +else: + echo showScorePadded($artwork->getAverageRating()); +endif; + diff --git a/apps/reaktor/modules/artwork/templates/_categoryList.php b/apps/reaktor/modules/artwork/templates/_categoryList.php new file mode 100644 index 0000000..3a293be --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_categoryList.php @@ -0,0 +1,109 @@ + $artwork)); + * + * Takes an $artwork as a parameter, and that's all it needs. + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper("Javascript"); +?> +hasCredential('editcategories') || + (isset($artwork) && $sf_user->getId() == $artwork->getUser()->getId()) || + (isset($article))): ?> + + + + +

    + + +

    + +

    + + +

    + + +
      + $category):?> + + +
    • + + +
    • + + + + 'category_list', + 'url' => '@category_action', + 'with' => "'artworkId=".$artwork->getId()."&".$toggle."=".$categoryId."'", + 'loading' => "Element.show('cat_indicator')", + 'complete' => "setTimeout('Element.hide(\'cat_indicator\')', 500)" + )); ?> + + 'category_list', + 'url' => '@category_action', + 'with' => "'articleId=".$article->getId()."&".$toggle."=".$categoryId."'", + 'loading' => "Element.show('cat_indicator')", + 'complete' => "setTimeout('Element.hide(\'cat_indicator\')', 500)" + )); ?> + + +
    • + +
    + + $category):?> + + + + + + + + + + 'category_list', + 'url' => '@category_action', + 'with' => "'artworkId=".$artwork->getId()."&".$toggle."=".$categoryId."'", + 'loading' => "Element.show('cat_indicator')", + 'complete' => "setTimeout('Element.hide(\'cat_indicator\')', 500)" + )); ?> + + 'category_list', + 'url' => '@category_action', + 'with' => "'articleId=".$article->getId()."&".$toggle."=".$categoryId."'", + 'loading' => "Element.show('cat_indicator')", + 'complete' => "setTimeout('Element.hide(\'cat_indicator\')', 500)" + )); ?> + + + + + $category):?> + +
    + + + diff --git a/apps/reaktor/modules/artwork/templates/_categorySelect.php b/apps/reaktor/modules/artwork/templates/_categorySelect.php new file mode 100644 index 0000000..6fbf4a0 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_categorySelect.php @@ -0,0 +1,127 @@ + $artwork)); + * + * Where $artwork is the artwork you want to edit. + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper("Javascript"); +$warning = __("Are you sure you wish to remove this selection? All categories associated with this subReaktor will be removed automatically."); +// The javascript function and form on this page has been written manually because the Symfony form +// Handlers could not allow ajax submit via checkbox click which was needed. + +?> +hasCredential('editcategories') || + (isset($artwork) && $sf_user->getId() == $artwork->getUser()->getId())|| + (isset($article))): //Subreaktors?> + + +
    +
    + + +

    + + +
    + + + 0): ?> + hasCredential("editusercontent") && (isset($article) ? $article->getArticleType() != ArticlePeer::HELP_ARTICLE : true)): ?> + + getLive() != 1) continue; ?> + getId(), + in_array($lokalReaktorObject->getId(), + $artworkSubreaktors), + array("onclick" => "if(this.checked == false) {if(confirm('".$warning."')) { doSubmit(); } + else this.checked=true; } else { doSubmit();}")) ?> + getName(); ?>
    + + + + getId()); ?> + + + + + + + + getName(); ?> + getId()); ?> + + + getId(), + in_array($subreaktorObject->getId(), + $artworkSubreaktors), + array("onclick" => "if(this.checked == false) {if(confirm('".$warning."')) { doSubmit(); } + else this.checked=true; } else { doSubmit();}")) ?> + getName(); ?>
    + + +
    +

    (click to select/deselect)"); ?>

    +
    + +
    + + $artwork)); ?> + + $article)); ?> + +
    + + + getId()) ?> + + getId()) ?> + + + + + + + +
    + +

    + +
    + +


    + hasCredential('editcategories') || (isset($artwork) && $sf_user->getId() == $artwork->getUser()->getId())): ?> + + +

    +
    + + $artwork)); ?> + + $article)); ?> + +
    + diff --git a/apps/reaktor/modules/artwork/templates/_displayArtworkInList.php b/apps/reaktor/modules/artwork/templates/_displayArtworkInList.php new file mode 100644 index 0000000..a42d79e --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_displayArtworkInList.php @@ -0,0 +1,104 @@ + $artwork, + * 'buttonPartial' => 'admin/discussButtons')) + * + * The possible buttonPartials are + * - admin/discussButtons + * - artwork/adminButtons + * + * + * PHP version 5 + * + * @author juneih + * @author Daniel Andre Eikeland + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('content') +?> + +
    + getFirstFile(), 'mini'), array( + 'title' => $artwork->getTitle(), + 'alt' => $artwork->getTitle(), + 'height' => 65, + 'width' => 78, + )); ?> +
    +
    +

    + link_to($artwork->getTitle(), $artwork->getLink()), + '%user%' => link_to($artwork->getUser()->getUsername(), '@portfolio?user='.$artwork->getUser()->getUsername()) + )); ?> + + $show_recommended_at)); ?> + + getId())." ]"; ?> + isTranscoded()): ?> + ** + +

    +
      +
    • + $artwork)); ?> +
    • + getStatus() == 2): //Assigned to editorial team ?> +
    • $artwork->getEditorialTeam()->getDescription(), + )); ?>
    • + + isUnderDiscussion()): ?> +
    • $artwork->getDiscussionInfo()->getsfGuardUser()->getNameOrUsername(), + '%date%' => date('d/m/Y', strtotime($artwork->getDiscussionInfo()->getCreatedAt())), + '%time%' => date('H.i', strtotime($artwork->getDiscussionInfo()->getCreatedAt())) + )); ?>
    • + + getModifiedDate()): ?> +
    • date('d/m/Y', strtotime($artwork->getModifiedDate())), + '%time%' => date('H.i', strtotime($artwork->getModifiedDate())) + )); ?> + + getId()."').toggle();")." ]"; ?> + + +
      > + +

      +

      getModifiedNote()); ?>

      +
      +
    • + +
    • $artwork)); ?>
    • + getFilesCount() > 1): //Artwork with more than one file?> +
    • $artwork->getFilesCount() + )); ?>
    • + + +
    +
    + + +
    + + $artwork, + "type" => "artwork", + "update_div" => $update_div, + )); ?> +
    + diff --git a/apps/reaktor/modules/artwork/templates/_displayComments.php b/apps/reaktor/modules/artwork/templates/_displayComments.php new file mode 100644 index 0000000..345703e --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_displayComments.php @@ -0,0 +1,35 @@ + $artwork->getBaseObject(), 'namespace' => 'frontend') + * + * Parameters passed: + * $object - The object to attach comments to + * $namespace - Which namespace the comments belong to (administrator|frontend) + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + ?> + +
    + $object, + 'namespace' => $namespace, + 'adminlist' => $adminlist))?> + hasCredential('postnewcomments')): ?> + +
    + $object, + 'namespace' => $namespace, + 'adminlist' => $adminlist)) ?> +
    + +
    \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_displayFileInList.php b/apps/reaktor/modules/artwork/templates/_displayFileInList.php new file mode 100644 index 0000000..e11ab65 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_displayFileInList.php @@ -0,0 +1,97 @@ + $file, + * 'buttonPartial' => 'admin/discussButtons')) + * + * The possible buttonPartials are + * - admin/discussButtons + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + ?> + + + +
    + + getParentArtworks()) > 0): //File belongs to one or more artwork ?> +

    + reaktor_link_to($file->getTitle(), '@show_artwork_file?id='.$file->getParentArtwork()->getId(). + '&file='.$file->getId().'&title='.$file->getParentArtwork()->getTitle()), + '%user%' => reaktor_link_to($file->getUser()->getUsername(), '@portfolio?user='.$file->getUser()->getUsername()) + )) ?> +

    + $file->getUser()->getUsername(), + '%date%' => $file->getUploadedAt() + ))?>
    + + + getParentArtworks() as $anArtwork): ?> + getTitle(), $anArtwork->getLink()) ?> + + + + +

    + reaktor_link_to($file->getTitle(), + '@edit_upload?fileId='.$file->getId()), + '%user%' => reaktor_link_to($file->getUser()->getUsername(), '@portfolio?user='.$file->getUser()->getUsername()))); ?> +

    + + + $file)); ?> + isUnderDiscussion()): ?> +
    + getDiscussionInfo()): ?> + getDiscussionInfo() ?> + getsfGuardUser()->getName() ?> + getDiscussionInfo()->getCreatedAt())).', '. + date('H.i', strtotime($file->getDiscussionInfo()->getCreatedAt())) ?> + + + + + $username, + '%date%' => $date + ))?> + + +
    +
    + + + + $file, + "type" => "file", + "update_div" => $update_div, + )) ?> + \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_displayPlayer.php b/apps/reaktor/modules/artwork/templates/_displayPlayer.php new file mode 100644 index 0000000..f2f1712 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_displayPlayer.php @@ -0,0 +1,90 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript", "content"); +?> + + + + + getMimeType()=='image/gif' && file_exists($file->getFullFilePath('original'))): ?> + +getId()."/".$file->getFilename(); ?>" > + + getFullFilePath())): ?> + getId()."/".$file->getFilename()."', loop: false, autoRewind: true, autoPlay: false, videoLink:'http://".$sf_request->getHost().contentPath($file)."'}\");"); ?> + + getFullFilePath().".temp.flv")): ?> +
    +

    + + hasCredential('reruntranscoding') || $sf_user->hasCredential("staff")): ?> + $file)); ?> + +
    + + + +
    +

    + $file->getTitle())); ?>
    + hasCredential('reruntranscoding') || $sf_user->hasCredential("staff")): ?> + $file)); ?> + + +
    + + + + + + + + getFullFilePath())): ?> + getLink('xml').'&format=xspf'); + if ($artwork->getFilesCount() == 1 || true) + { + $height = 153; + } + else + { + $height = 15; + } + echo javascript_tag(" + VM_EmbedFlash ( 'width', '100%', 'height', $height, + 'src', '$url', 'bgcolor', '#e6e6e6'); + + "); // bgcolor = c6c6c6 will make it same color as rest of player ?> + getFullFilePath().".temp.mp3") ): ?> +
    +

    + +
    + hasCredential('reruntranscoding') || $sf_user->hasCredential("staff")): ?> + $file)); ?> + + + $file->getrealPath())); ?> + hasCredential('reruntranscoding') || $sf_user->hasCredential("staff")): ?> + $file)); ?> + + + + + + + + + diff --git a/apps/reaktor/modules/artwork/templates/_draganddropartworklist.php b/apps/reaktor/modules/artwork/templates/_draganddropartworklist.php new file mode 100644 index 0000000..66a69df --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_draganddropartworklist.php @@ -0,0 +1,42 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript'); + +?> + + 0): ?> +
      + +
    • getId() ?>' class="bottomborder"> + + +
    • + +
    + + 'artwork/updateArtworkOrder', + 'update' => 'feedback', + 'loading' => "", + 'success' => visual_effect('highlight', 'artwork_list'), + )); ?> + + + + diff --git a/apps/reaktor/modules/artwork/templates/_draganddroplist.php b/apps/reaktor/modules/artwork/templates/_draganddroplist.php new file mode 100644 index 0000000..c8c85b4 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_draganddroplist.php @@ -0,0 +1,105 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper ("content", "Javascript"); + +?> +getId()."&field=files")."', options); + }" +);?> + +

    +getFilesCount() == 1): ?> + collectionType($artwork))). + " [ ".reaktor_link_to(__("new file"), "@artwork_link?link_artwork_id=".$artwork->getId())." / ". + link_to(__("existing file"), "@".($sf_user->hasCredential("createcompositeartwork") ? "admin_" : "")."link_existing_file?user=".$artwork->getUser()->getUsername()."&artworkId=".$artwork->getId())." ]"; ?> + + collectionType($artwork))). + " [ ".reaktor_link_to(__("new file"), "@artwork_link?link_artwork_id=".$artwork->getId())." / ". + link_to(__("existing file"), "@".($sf_user->hasCredential("createcompositeartwork") ? "admin_" : "")."link_existing_file?user=".$artwork->getUser()->getUsername()."&artworkId=".$artwork->getId())." ]"; ?> + +

    +
    +getFilesCount() > 1): ?> + +
    + +
    + + + + +
      + getFiles() as $afile): ?> + +
    • +
      + +
      +
      +

      + getTitle() ?> + [ + '')), "@edit_upload?fileId=".$afile->getId())." / "; ?> + '')), "@show_artwork_file?id=".$artwork->getId()."&file=".$afile->getId()."&title=".$artwork->getTitle()); ?> + hasCredential("staff")): ?> + getIdentifier()!='text' && $afile->getIdentifier()!='pdf'): ?> + + + + + getFilesCount() > 1): ?> + '')), array( + 'confirm' => __('Are you sure you wish to remove this file from the artwork?'), + 'url' => '@removefilefromartwork?artwork='.$artwork->getId().'&file='.$afile->getId(), + 'success' => "location.reload();" + )); ?> + + ] +

      +

      +  [  '')), "@edit_upload?fileId=".$afile->getId()); ?> ] + hasCredential("editusercontent") || $sf_user->getId() == $afile->getUserId()): ?> +

      + $afile, "options" => + array("rowLimit" => 4, + "completeFuncs" => $artwork->getFilesCount() > 1 ? "" : "updateArtworkTagList(".$afile->getId().",".$artwork->getId().")"))); ?> +
      + + getTags()); ?> + +

      +
      +
    • + +
    + +getFilesCount() > 1): ?> + + diff --git a/apps/reaktor/modules/artwork/templates/_editmetadata.php b/apps/reaktor/modules/artwork/templates/_editmetadata.php new file mode 100644 index 0000000..7be1736 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_editmetadata.php @@ -0,0 +1,65 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('wai'); + +$theFile = ''; + +try +{ + // print 'fu' . $file_id; + $theFile = new artworkFile($file_id); +} +catch (Exception $e) +{ + print $e->getMessage(); + print '
    Try adding a number to the url.'; +} + +if ($theFile instanceof artworkFile) +{ + ?> +

    Editing metadata for getTitle(); ?>

    + + getId()) ?> +
    +
    +
    + getMetadata('contributor', 'author'), + array ('size' => 60)) ?>
    +
    +
    +
    +
    + getMetadata('description', 'abstract'), + array ('size' => 60)) ?>
    +
    +
    +
    +
    + 'Creative Commons - Attribution (by)', + 'by-sa' => 'Creative Commons - Attribution Share Alike (by-sa)', + 'by-nd' => 'Creative Commons - Attribution No Derivatives (by-nd)', + 'by-nc' => 'Creative Commons - Attribution Non-commercial (by-nc)', + 'by-nc-sa' => 'Creative Commons - Attribution Non-commercial Share Alike (by-nc-sa)', + 'by-nc-nd' => 'Creative Commons - Attribution Non-commercial No Derivatives (by-nc-nd)'), + $theFile->getMetadata('rights', 'license'))) ?>
    +
    +
    + + '; +} +?> +
    +I am the editmetadata partial. Find me in module/artwork/templates/_editmetadata.php diff --git a/apps/reaktor/modules/artwork/templates/_editorialTeamArtwork.php b/apps/reaktor/modules/artwork/templates/_editorialTeamArtwork.php new file mode 100644 index 0000000..175bd4a --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_editorialTeamArtwork.php @@ -0,0 +1,61 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper('Javascript'); +//print_r($recommendations); +?> +
    + getStatus() != 3): ?> + getId(), array( + 'class' => 'artwork_editorialteam_form', + 'id' => 'artwork_editorialteam_form', + 'name' => 'artwork_editorialteam_form' + ))?> + +

    +

    + getEditorialTeam()->getDescription(); + $hasteam = true; + } catch(Exception $e) + { + $editorial_desc = "No team"; + } + echo $editorial_desc; + ?> +

    +

    + getEditorialTeam()->getId() : -1)) ?> + + + + + 'artwork_editorialteam_tag', + 'url' => '@updateartworkeditorialteam?id='.$artwork->getId(), + 'loading' => "Element.show('editorialteam_artwork_ajax_indicator')", + 'complete' => "Element.hide('editorialteam_artwork_ajax_indicator')", + 'script' => true), array( + 'class' => 'submit' + )) ?> + '; ?> + +
    + date("d/m/Y", strtotime($artwork->getActionedAt())), "%at_time%" => date("H:i", strtotime($artwork->getActionedAt())), '%editorial_team%' => $artwork->getEditorialTeam()->getDescription(), '%user%' => $artwork->getActionedBy(false))) ?> +
    +
    + +
    diff --git a/apps/reaktor/modules/artwork/templates/_embedLink.php b/apps/reaktor/modules/artwork/templates/_embedLink.php new file mode 100644 index 0000000..7784bdd --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_embedLink.php @@ -0,0 +1,33 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + + + + diff --git a/apps/reaktor/modules/artwork/templates/_fileAdminButtons.php b/apps/reaktor/modules/artwork/templates/_fileAdminButtons.php new file mode 100644 index 0000000..b50cd70 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_fileAdminButtons.php @@ -0,0 +1,25 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript"); + +?> +
    + + '@flag_suitable_file?id='.$artwork_file->getId(), + 'complete'=> "Effect.BlindUp('artwork_list_container_".$artwork_file->getId()."');", + 'confirm' => __("Flag this file as OK?"), + ), array("id" => "flag_ok_button_".$artwork_file->getId())); ?> + + getId()."').toggle()"); ?> +
    \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_lastArtworks.php b/apps/reaktor/modules/artwork/templates/_lastArtworks.php new file mode 100644 index 0000000..1a1b832 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_lastArtworks.php @@ -0,0 +1,55 @@ + 'mini', + * 'limit' => 6, + * 'subreaktor' => $subreaktor, + * 'lokalreaktor' => $lokalreaktor, + * 'random' => true, + * 'exclude_first' => 1)) + * + * None of these parameters are required. The default limit is retrieved from configuration, + * exclude_first will exclude the n latest artworks from the list (say you've displayed the + * latest artwork as a thumbnail on top of the page, and you want a list of smaller thumbnails + * on a different part of the page, you don't want the latest artwork to be displayed again, so + * exclude_first = 1). If $image (thumb|subreaktorthumb|mini) isn't passed then text is + * used. $subreaktor and $lokalreaktor are only needed if they should display something + * from a different reaktor than the site belongs to. For instance, on the frontpage of + * groruddalenreaktor, you might want to show a list of the most popular reaktors in foto: + * + * include_component('artwork', 'lastArtworks', array('subreaktor' => 'foto') + * + * The information passed from the controller are the following: + * - $last : If not passed from a lokalreaktor: An array of artwork objects + * - $last : If passed from a lokalreaktor: An array with: + * 'last' => an array of artworks, + * 'subreaktor' = the subreaktor object for the subreaktor it was passed from + * + * The image type "subreaktorthumb" and "subreaktorlist" can only be called from a lokalreaktor + * frontpage. This is used when this list is called more than once on the same page, to make sure + * the same image doesn't appear more than once. + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + + +include_partial ('artwork/listPresentation', array('image' => $image, + 'artworks' => $last, + 'tags' => $tags, + 'lokalreaktor' => $lokalreaktor, + 'subreaktor' => $subreaktor, + 'feed_description' => $feed_description, + 'feed_slug' => $feed_slug, + 'show_username' => isset($show_username) ? $show_username : false, + )); + ?> diff --git a/apps/reaktor/modules/artwork/templates/_lastArtworksFromUser.php b/apps/reaktor/modules/artwork/templates/_lastArtworksFromUser.php new file mode 100644 index 0000000..86c1638 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_lastArtworksFromUser.php @@ -0,0 +1,106 @@ + $userid, + * 'portfolio' => true, + * 'user' => $user, + * 'orderBy' => $orderBy, + * )) + * + * Component can pass: + * $id : The id of the user who owns the portfolio page + * $user : sfGuardUser object, (used to set title of page) + * $portfolio : If set then this template is used in portfolio + * $mypage : If set then this template is used in mypage + * $orderby : What to order/filter by (title, date, rating or format) + * + * + * PHP version 5 + * + * @author June Henriksen + * @author Hannes Magnusson + * @author Daniel Andre Eikeland + * @author Russell Flynn + * + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper('PagerNavigation','home', 'content'); +$artwork_count = count($last); +$counter = 0; + +?> + + + + + + + getFirstFile(); ?> + +
    +

    getShortTitle(sfConfig::get('app_artwork_teaser_len', 20)-15) ?>

    +
    + getReaktorFile()->getId().'&filename='.$file[0]->getReaktorFile()->getFilename()), array('size' => '240x160','alt' =>$artwork->getTitle())), + $artwork->getLink()) ?> +
    +
    + getAverageRating()) ?> +
    +
    + + + + + 0): //No artworks either in this filter, or at all..?> + + 0): ?> + +
      + +
        + + + + getFirstFile(); ?> + + + +
      • + + +
      • + + + +
      • > + +
      • + + + + + 0): ?> +
      + + + +

      +
      + + + +

      + + + + + ".pager_navigation($artworks, '@portfolio?user='.$user->getUsername() . $order) ?> + + + diff --git a/apps/reaktor/modules/artwork/templates/_latestCommented.php b/apps/reaktor/modules/artwork/templates/_latestCommented.php new file mode 100644 index 0000000..768e27d --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_latestCommented.php @@ -0,0 +1,29 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include_partial ('artwork/listPresentation', array('artworks' => $latestCommented, + 'lokalreaktor' => ((isset($lokalreaktor) ? $lokalreaktor : '')), + 'subreaktor' => ((isset($subreaktor) ? $subreaktor : '')), + 'feed_description' => __('latest commented'), + 'feed_slug' => 'latest_commented')); + +?> \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_licenseinfo.php b/apps/reaktor/modules/artwork/templates/_licenseinfo.php new file mode 100644 index 0000000..e3033a0 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_licenseinfo.php @@ -0,0 +1,52 @@ + $thefile)) + * + * $file : ReaktorFile object. + * + * PHP version 5 + * + * @author Daniel Andre Eikeland + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +getLicense(); ?> + +

      + link_to(__('the author'), '@portfolio?user=' . $thefile->getUser()->getUsername()))); + break; + case "no_allow": + echo __("The author of this artwork does not allow any use of this artwork outside private use"); + break; + default: + ?> +

      + + Creative Commons License + +
      + "")) ?> + Creative Commons 3.0 Norway lisens. +

      + \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_linkRelated.php b/apps/reaktor/modules/artwork/templates/_linkRelated.php new file mode 100644 index 0000000..fcbd655 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_linkRelated.php @@ -0,0 +1,73 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript'); +?> + + + + +
      + + + + + +
      +

      + hasCredential("staff")): ?> +
      + : +

      + 'listArtwork', + 'url' => '@AJAX_browse_unrelated_artworks?id='.$artwork->getId().'&autocompleter=false', + 'complete' => "Element.show('listArtworkMaster');", + 'script' => true, + ), + array("name" => "relate_form", "id" => "relate_form")) ?> + + getId().'&autocompleter=true', + array("class" => "mediumindent",'onkeypress'=>'if(event.keyCode!=9) listartworkClose();' ), + array("frequency" => 0.2 ) + );?> "search_related" )); ?> +
      + + + + + +
      +

      +
      + + + +
      + $artwork, + 'update' => 'relate_artwork_tag', + 'editmode' => $editmode, + 'usercanedit' => $usercanedit)); ?> +
      + +
      + diff --git a/apps/reaktor/modules/artwork/templates/_linkRelatedChoices.php b/apps/reaktor/modules/artwork/templates/_linkRelatedChoices.php new file mode 100644 index 0000000..87d6f39 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_linkRelatedChoices.php @@ -0,0 +1,23 @@ + + +
        + +
      • +
        +
        + $artwork->getCreatedAt())) ?> + getTitle() . '
        ' .$timestring) ?>
        + 'relate_artwork_tag', + 'url' => '@relateartwork?id='.$thisArtwork->getId(). '&relate_artwork_select=' .$artwork->getId(), + 'loading' => "Element.show('relate_artwork_ajax_indicator')", + 'complete' => "Element.hide('relate_artwork_ajax_indicator')", + 'script' => true), array( + 'class' => 'submit' + )); ?> +
        +
      • + +
      +
      + diff --git a/apps/reaktor/modules/artwork/templates/_listArtworksPopupChoices.php b/apps/reaktor/modules/artwork/templates/_listArtworksPopupChoices.php new file mode 100644 index 0000000..daab55c --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_listArtworksPopupChoices.php @@ -0,0 +1,19 @@ + + +
        + +
      • +
        +
        + getTitle()) ?>
        + "ArtworklistDialog.insert('".$artwork->getId()."')", "href" => "")) ?>
        + '@relateartworktoarticle?article_id='.$article->getId().'&artwork_id='.$artwork->getId(), + 'complete' => 'tinyMCEPopup.getWin().updateArtworks();setTimeout("tinyMCEPopup.close()", 1000);')); + ?> +
        +
      • + +
      +

      + diff --git a/apps/reaktor/modules/artwork/templates/_listPresentation.php b/apps/reaktor/modules/artwork/templates/_listPresentation.php new file mode 100644 index 0000000..2de3acc --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_listPresentation.php @@ -0,0 +1,202 @@ + 'mini', + * 'limit' => 6, + * 'subreaktor' => $subreaktor, + * 'lokalreaktor' => $lokalreaktor, + * 'random' => true, + * 'exclude_first' => 1)) + * + * None of these parameters are required. The default limit is retrieved from configuration, + * exclude_first will exclude the n latest artworks from the list (say you've displayed the + * latest artwork as a thumbnail on top of the page, and you want a list of smaller thumbnails + * on a different part of the page, you don't want the latest artwork to be displayed again, so + * exclude_first = 1). If $image (thumb|subreaktorthumb|mini) isn't passed then text is + * used(??). $subreaktor and $lokalreaktor are only needed if they should display something + * from a different reaktor than the site belongs to. For instance, on the frontpage of + * groruddalenreaktor, you might want to show a list of the most popular reaktors in foto: + * + * include_component('artwork', 'lastArtworks', array('subreaktor' => 'foto') + * + * The information passed from the controller are the following: + * - $artworks : If not passed from a lokalreaktor: An array of artwork objects + * - $artworks : If passed from a lokalreaktor: An array with: + * 'last' => an array of artworks, + * 'subreaktor' = the subreaktor object for the subreaktor it was passed from + * + * The image type "subreaktorthumb" and "subreaktorlist" can only be called from a lokalreaktor + * frontpage. This is used when this list is called more than once on the same page, to make sure + * the same image doesn't appear more than once. + * + * PHP version 5 + * + * @author Daniel Andre Eikeland + * @author Hannes Magnusson + * @author June Henriksen + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper('content'); + +// Generate the RSS links for everything except for subreaktlists, those are +// dealt with later in this file +if (!isset($image) || (isset($image) && $image != "subreaktorlist")) +{ + include_partial('feed/rssLink', array('description' => $feed_description, 'slug' => $feed_slug)); +} +?> + + + 0): ?> + + + getFirstFile(); ?> +
      + getId().'&filename='.$file->getFilename()), + 'size=240x160 alt="'.$artwork->getTitle().'" title="'.$artwork->getTitle().'"'), + $artwork->getLink()); ?> +
      + +
      getAverageRating()); ?>
      + + + +
      + +
      +
      + +
      + +
      + + + 0): ?> + + +
      + getFirstFile(); ?> +
      + getId(). + '&filename='.$file->getFilename()), + 'size=240x160 alt="'.$artwork->getTitle().'" title="'.$artwork->getTitle().'"'), + $artwork->getLink()); ?> +
      + +
      + + + +
      + +
      +
      + +
      + +
      + + +
      +

      $artworks['subreaktor']->getName())); ?>

      + __($artworks['subreaktor']->getName()), + 'slug' => $feed_slug, + 'url' => '/' . (($lokalreaktor) ? $lokalreaktor->getReference() . '-' : '') . $subreaktor->getReference() . '/feed/' . $feed_slug) //latest_artworks") + ); ?> +
        + 0): ?> + + +
      • + getShortTitle(), $artwork->getLink()) ?> + getUser()->getUsername(), '@portfolio?user='.$artwork->getUser()->getUsername()) ?> + $tmp_artwork_title, + '%username%' => $tmp_username)) ?> +
        + getCategories()) > 0): ?> + + getCategories() as $category): ?> + + + + + + +
      • + + + +
      • + +
      +
      + + 0): ?> +
        + +
      • + +
      + + + +
        + 0): // There are artworks?> + + + +
      • + getShortTitle(), $artwork->getLink()); ?> + + + getUser()->getUsername(), + '@portfolio?user='.$artwork->getUser()->getUsername()); ?> + $tmp_artwork_title, + '%username%' => $tmp_username)); ?> + +
        + + +
        + + + getCategories() as $category):?> + + + + +
      • + + + +
      • + +
      + diff --git a/apps/reaktor/modules/artwork/templates/_listReaktorsLatestArtworks.php b/apps/reaktor/modules/artwork/templates/_listReaktorsLatestArtworks.php new file mode 100644 index 0000000..fadff75 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_listReaktorsLatestArtworks.php @@ -0,0 +1,41 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('home'); +?> + + __('latest published'), 'slug' => 'latest_artworks')); ?> + 1 && !isset($text_or_artwork)): ?> +
        + +
      • + getTitle(), $artwork->getLink()) ?> +
      • + +
      + + + = 1 && isset($text_or_artwork)): ?> +
        + +
      • + getTitle(), $artwork->getLink()) ?>
        + getTags() as $category): ?> + + +
      • + +
      + + + + + diff --git a/apps/reaktor/modules/artwork/templates/_listReaktorsPopularArtworks.php b/apps/reaktor/modules/artwork/templates/_listReaktorsPopularArtworks.php new file mode 100644 index 0000000..aeabcba --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_listReaktorsPopularArtworks.php @@ -0,0 +1,45 @@ + 'thumb', + * 'limit' => 1, + * 'subreaktor' => $subreaktor, + * 'lokalreaktor' => $lokalreaktor)) + * + * None of these parameters are needed. The default limit is retrived from configuration, + * if $image isn't passed then text is used. $subreaktor and lokal reaktor are only needed if they should display something + * from a different reaktor than the site belongs to. For instance, on the frontpage of groruddalenreaktor, you might want to show + * a list of the most popular reaktors in foto: + * + * include_component('artwork', 'listReaktorsPopularArtworks', array('subreaktor' => 'foto') + * + * The information passed from the controller are the following: + * - $artworks : An array of artwork objects + * + */ + +/** + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('home'); + +include_partial ('artwork/listPresentation', array('artworks' => $artworks, + 'image' => $image, + 'tags' => $text_or_artwork, + 'lokalreaktor' => ((isset($lokalreaktor) ? $lokalreaktor : '')), + 'subreaktor' => ((isset($subreaktor) ? $subreaktor : '')), + 'feed_description' => $feed_description, + 'feed_slug' => $feed_slug, + 'show_username' => isset($show_username) ? $show_username : false, + )); +?> diff --git a/apps/reaktor/modules/artwork/templates/_listUsersPopularArtworks.php b/apps/reaktor/modules/artwork/templates/_listUsersPopularArtworks.php new file mode 100644 index 0000000..3312bc4 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_listUsersPopularArtworks.php @@ -0,0 +1,45 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('home'); +?> + +1): ?> + +

      +
        + + + + getFirstFile(); ?> + + +
      • + getId().'&filename='.$file->getFilename()), + 'size=70x60'), + $artwork->getLink())?>
        + getTitle(), $artwork->getLink()) ?> + getAverageRating()) ?> +
      • + + +
      • + getTitle(), $artwork->getLink()).showScore($artwork->getAverageRating()); ?> +
      • + + + + + +
      + + \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_metadataList.php b/apps/reaktor/modules/artwork/templates/_metadataList.php new file mode 100644 index 0000000..ea527fe --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_metadataList.php @@ -0,0 +1,146 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +// Image files +/** +$metaArray["image"][__("Width")]["element"] = "format"; +$metaArray["image"][__("Width")]["qualifier"] = "width"; +$metaArray["image"][__("Width")]["suffix"] = "px"; + +$metaArray["image"][__("Height")]["element"] = "format"; +$metaArray["image"][__("Height")]["qualifier"] = "height"; +$metaArray["image"][__("Height")]["suffix"] = "px"; +*/ + +$metaArray["image"][__("Created by")]["element"] = "creator"; +$metaArray["image"][__("Created by")]["qualifier"] = ""; + +$metaArray["image"][__("Created at")]["element"] = "date"; +$metaArray["image"][__("Created at")]["qualifier"] = "creation"; +$metaArray["image"][__("Created at")]["date"] = "d/m/Y h:i"; // See http://php.net/date for formatting options + +$metaArray["image"][__("Camera")]["element"] = "description"; +$metaArray["image"][__("Camera")]["qualifier"] = "camera"; + +$metaArray["image"][__("Aperture")]["element"] = "format"; +$metaArray["image"][__("Aperture")]["qualifier"] = "aperture"; + +$metaArray["image"][__("Shutter")]["element"] = "format"; +$metaArray["image"][__("Shutter")]["qualifier"] = "shutter"; + +$metaArray["image"][__("Focal Length")]["element"] = "format"; +$metaArray["image"][__("Focal Length")]["qualifier"] = "focalLength"; + +$metaArray["image"][__("Software")]["element"] = "description"; +$metaArray["image"][__("Software")]["qualifier"] = "software"; + +$metaArray["image"][__("Production")]["element"] = "description"; +$metaArray["image"][__("Production")]["qualifier"] = "creation"; +$metaArray["image"][__("Production")]["newline"] = true; // Uses a block of text under the header instead of alongside + +/* +$metaArray["image"][__("Description")]["element"] = "description"; +$metaArray["image"][__("Description")]["qualifier"] = "abstract"; +$metaArray["image"][__("Description")]["newline"] = true; +*/ + + +//Audio files +$metaArray["audio"][__("Track title")]["element"] = "title"; + +$metaArray["audio"][__("Description")]["element"] = "description"; +$metaArray["audio"][__("Description")]["qualifier"] = "abstract"; + +$metaArray["audio"][__("Created by")]["element"] = "creator"; +$metaArray["audio"][__("Created by")]["qualifier"] = ""; + +$metaArray["audio"][__("Created at")]["element"] = "date"; +$metaArray["audio"][__("Created at")]["qualifier"] = "creation"; +$metaArray["audio"][__("Created at")]["date"] = "d/m/Y h:i"; // See http://php.net/date for formatting options + +$metaArray["audio"][__("Production method")]["element"] = "description"; +$metaArray["audio"][__("Production method")]["qualifier"] = "creation"; +$metaArray["audio"][__("Production method")]["newline"] = true; // Uses a block of text under the header instead of alongside + +//Video files +$metaArray["video"][__("Created by")]["element"] = "creator"; +$metaArray["video"][__("Created by")]["qualifier"] = ""; + +$metaArray["video"][__("Created at")]["element"] = "date"; +$metaArray["video"][__("Created at")]["qualifier"] = "creation"; +$metaArray["video"][__("Created at")]["date"] = "d/m/Y h:i"; // See http://php.net/date for formatting options + +//PDFs +$metaArray["pdf"][__("Created by")]["element"] = "creator"; +$metaArray["pdf"][__("Created by")]["qualifier"] = ""; + +$metaArray["pdf"][__("Created at")]["element"] = "date"; +$metaArray["pdf"][__("Created at")]["qualifier"] = "creation"; +$metaArray["pdf"][__("Created at")]["date"] = "d/m/Y h:i"; // See http://php.net/date for formatting options + +//Text files +$metaArray["text"][__("Created by")]["element"] = "creator"; +$metaArray["text"][__("Created by")]["qualifier"] = ""; + +$metaArray["text"][__("Created at")]["element"] = "date"; +$metaArray["text"][__("Created at")]["qualifier"] = "creation"; +$metaArray["text"][__("Created at")]["date"] = "d/m/Y h:i"; // See http://php.net/date for formatting options + +//Flash animation +$metaArray["flash_animation"][__("Created by")]["element"] = "creator"; +$metaArray["flash_animation"][__("Created by")]["qualifier"] = ""; + +$metaArray["flash_animation"][__("Created at")]["element"] = "date"; +$metaArray["flash_animation"][__("Created at")]["qualifier"] = "creation"; +$metaArray["flash_animation"][__("Created at")]["date"] = "d/m/Y h:i"; // See http://php.net/date for formatting options + +$hasmetainfo = false; + +?> + +getIdentifier()]) && !empty($metaArray[$file->getIdentifier()])): ?> +
      +

      getTitle(); ?>

      + getIdentifier()] as $name => $valuesArray): ?> + + getMetaData($valuesArray["element"], $valuesArray["qualifier"])): ?> + + + +

      > +

      + +

      + +

      + + + + + +
      +
      + + + + + +

      + +
      + + diff --git a/apps/reaktor/modules/artwork/templates/_moderatorlinks.php b/apps/reaktor/modules/artwork/templates/_moderatorlinks.php new file mode 100644 index 0000000..a080cc6 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_moderatorlinks.php @@ -0,0 +1,53 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> +

      +hasCredential('approveartwork')): ?> + + +
        +
      • + getUser()->getUsername()); ?> +
      • + hasCredential('viewmetadata')): ?> +
      • + getId().'&title='.$artwork->getTitle()) ?> +
      • + +
      +
        + hasCredential('approvetags')): ?> +
      • getId()); ?>
      • + + hasCredential('downloadoriginalfile')): ?> +
      • + +
      diff --git a/apps/reaktor/modules/artwork/templates/_recommendArtwork.php b/apps/reaktor/modules/artwork/templates/_recommendArtwork.php new file mode 100644 index 0000000..2127674 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_recommendArtwork.php @@ -0,0 +1,75 @@ + $artwork)) + * + * Parameters passed: + * + * $artwork - Object of an artwork + * + * From the controller the following information is passed: + * $recommendations - Array of recommendation objects + * $subreaktor_array - An array of the subreaktors the artwork can be recommended in + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript'); +?> +
      + 0): //Display if the artwork is recommended already ?> + +

      +
        + +
      • + getSubreaktor()->getReference() ?> + getLocalsubreaktor()->getReference()): ?> + getLocalsubreaktor()->getReference() ?> + + + +
      • + +
      + + + 0 && $sf_user->hasCredential('recommendartwork')): ?> +

      + 'recommend_artwork_form', + 'id' => 'recommend_artwork_form', + 'name' => 'recommend_artwork_form' + ))?> + + + __('--- Recommend in ---') + ))) ?> + + + + + + 'recommend_artwork_tag', + 'url' => '@addartworkrecommendation?id='.$artwork->getId(), + 'loading' => "Element.show('recommend_artwork_ajax_indicator')", + 'complete' => "Element.hide('recommend_artwork_ajax_indicator')", + 'script' => true), array( + 'class' => 'submit' + )) ?> + + + +
      diff --git a/apps/reaktor/modules/artwork/templates/_recommended.php b/apps/reaktor/modules/artwork/templates/_recommended.php new file mode 100644 index 0000000..b25b118 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_recommended.php @@ -0,0 +1,79 @@ + 'ignore', 'subreaktor' => Subreaktor::getByReference('foto')); + * + * To display only the latest recommended photo artwork in groruddalen, use the above code, but leave out the lokalreaktor parameter. + * + * To get an instance of a reaktor you use the following piece of code: Subreaktor::getByReference('foto'), where foto is the name + * of the subreaktor. Other alteratives to foto are: tegning, film, lyd, tegneserier and tekst. To get an instance + * of a lokalreaktor the same piece of code is used, but the name of the lokalreaktor is used instead (groruddalen etc.). + * + * The component's controller passes the following information: + * + * $artwork - An artwork object + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('home'); +?> + __('recommended artwork'), 'slug' => 'recommended_artwork')); ?> + + +
      + get())): + $retval = reaktor_link_to(image_tag(contentPath($artwork, "thumb"), + "alt='".$artwork->getTitle()."' title='".$artwork->getTitle()."'"." size=240x160"), + "@show_artwork?id=".$artwork->getId()."&title=".$artwork->getTitle()); + $cache->set($retval); + endif; + echo $retval; + ?> +
      + + +
      getAverageRating()); ?>
      + + +
      + +
      +
      + +
      + +
      + + diff --git a/apps/reaktor/modules/artwork/templates/_removeFileButtons.php b/apps/reaktor/modules/artwork/templates/_removeFileButtons.php new file mode 100644 index 0000000..9badd55 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_removeFileButtons.php @@ -0,0 +1,40 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper("Javascript"); +?> +
      + \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_reportunsuitable.php b/apps/reaktor/modules/artwork/templates/_reportunsuitable.php new file mode 100644 index 0000000..275dda4 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_reportunsuitable.php @@ -0,0 +1,75 @@ + + * @author June Henriksen + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +//Logged in users +if($sf_user->isAuthenticated()): +use_helper("reportHistory"); + + //Admin user + if($sf_user->hasCredential("editusercontent")): +?> + +
      + getReportHistory(); ?> + getSfGuardUser() : null; ?> + getCreatedAt())) : ""; ?> + is_object($reportUser) ? $reportUser->getUsername() : "", + "%reportdate%" => $reportDate, + "%mouseoveruserlist%" => link_to(__("%reportedcount% users", array("%reportedcount%" => count($reportHistory))), "#", + array("onmouseover" => "Tip('".displayReportHistory($reportHistory)."');", + "onmouseout" => "UnTip();"))), + count($reportHistory)); ?> + isUnderDiscussion()): ?> +
      reaktor_link_to(__('view'), '@show_discussion?id='.$thefile->getId().'&type=file'))) ?> + + isUnderDiscussion()): ?> +
      reaktor_link_to(__('view'), '@show_discussion?id='.$artwork->getId().'&type=artwork'))) ?> + +
      +
      +
      + + getGuardUser()->getId() != $thefile->getUserId()): + + //User has not reported the artwork before + if (!$sf_request->getCookie('reported_'.md5($sf_user->getGuardUser()->getUsername().$thefile->getId()))):?> +
      + '@report_file?id=' . $artwork->getId() . '&title=' . $artwork->getTitle() . '&file=' . $thefile->getId(), + 'update'=>'unsuitable_content_msg')) ?> +
      + +
      + +
      + diff --git a/apps/reaktor/modules/artwork/templates/_seeAlso.php b/apps/reaktor/modules/artwork/templates/_seeAlso.php new file mode 100644 index 0000000..45ef692 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_seeAlso.php @@ -0,0 +1,82 @@ + + $artwork, + * 'update' => 'relate_artwork_tag', + * 'editmode' => $editmode, + * 'usercanedit' => $usercanedit)); + * + * $artwork: genericArtwork object, the artwork currently viewed + * $update: the div that should be updated + * $editmode: the artwork view mode (show|edit) + * $usercanedit: the user has proper credentials? (true|false) + * + * The controller passes the following information: + * $relatedArtworks: array of genericArtwork objects + * $otherpeoplelike: array of genericArtwork objects + * otherArtworks: array of genericArtwork objects + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("content"); + +?> + +

      + + hasCredential("createcompositeartwork")): ?> + + + +isMultiUser()): ?> +

      getUser()->getUsername();?>

      + + + +

      + + + diff --git a/apps/reaktor/modules/artwork/templates/_slideshow.php b/apps/reaktor/modules/artwork/templates/_slideshow.php new file mode 100644 index 0000000..38e24cc --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_slideshow.php @@ -0,0 +1,141 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + if (isset($related) && $related) + { + $slidetitle = __('See also'); + } + else + { + $slidetitle = __('This artwork'); + } +use_helper("content"); + +reaktor::addJsToFooter("setTimeout(\"resizeArtworkImage('artwork_image')\", 200);"); +$MAGNIFIER_ICON = image_tag('forstorre.gif', array('class' => 'magnifier_icon', 'width' => 13, 'height' => 13)); + +$relatedArtworks = $artwork->getRelatedArtworks(0, true); +$otherArtworks = ReaktorArtworkPeer::getArtworksByUser($artwork->getUser(), sfConfig::get("app_artwork_other_by_user", 6), true, array($artwork)); + +$artworks = array(); +$artworks[$artwork->getId()] = $artwork; +foreach ($relatedArtworks as $anArtwork) +{ + $artworks[$anArtwork->getId()] = $anArtwork; +} +foreach ($otherArtworks as $anArtwork) +{ + $artworks[$anArtwork->getId()] = $anArtwork; +} + +$theartwork = $artwork; + +?> +
      +getFiletype() == 'image'): + foreach ($artworks as $artwork): + if ($artwork->isSlideshow()): + foreach ($artwork->getFiles() as $slidefile): + if ($artwork->getId() == $theartwork->getId()): + $rel = $slidetitle.'[' . __('Watch slideshow') . ']'; + else: + $rel = __('Other artworks').'[' . $artwork->getTitle() . ']'; + endif; + $metadata = str_replace("'", '‘', $slidefile->getMetadata('description', 'abstract')); + $linkto = reaktor_link_to(__('Go to this file'), '@show_artwork_file?id=' . $artwork->getId() . '&file=' . $slidefile->getId() . '&title=' . $artwork->getTitle()); + $caption = $metadata . "
      " . $linkto; + $username = $slidefile->getUser()->getUsername(); + + $license = ""; + if (!in_array($slidefile->getLicense(), array('no_allow', 'contact', 'free_use', 'non_commercial', ''))): + $license_img = 'http://i.creativecommons.org/l/' . $slidefile->getLicense() . '/3.0/no/80x15.png'; + $license = " Creative Commons License"; + endif; + + // This is the artwork image (first image) + if ($slidefile->getId() == $thefile->getId() && $theartwork->getId() == $artwork->getId()): + echo '\n"; + /* + * And these are the rest of the images in the artwork. + * Note that we don't print out any content of the link. + * The solo purpose of this stuff is so lightwindow can pick it up + */ + else: + echo link_to(" ", contentPath($slidefile, "", true), array( + "style" => "display: none;", + "rel" => $rel, + "class" => "lightwindow", + "author" => $username . $license, + "caption" => $caption, + "helptext" => __("(if you are watching a slideshow, use the 'left' / 'right' arrow keys on your keyboard to navigate)"), + "author_by_text" => __("by"), + "closetext" => __("close"), + "title" => $slidefile->getTitle(), + )); + endif; + endforeach; + else: + $license = ""; + switch($thefile->getLicense()): + case "free_use": + $license = __("The author of this artwork allows all other Reactor users to freely copy this artwork"); + break; + case "non_commercial": + $license = __("The author of this artwork allows all other Reactor users to freely copy this artwork for educational or non-commercial use"); + break; + case "contact": + case "": + case NULL: + $license = __("Please contact %the_author% if you want to use or copy this artwork in any way", array("%the_author%" => link_to(__('the author'), '@portfolio?user=' . $thefile->getUser()->getUsername()))); + break; + case "no_allow": + $license = __("The author of this artwork does not allow any use of this artwork outside private use"); + break; + default: + $license_img = 'http://i.creativecommons.org/l/' . $thefile->getLicense() . '/3.0/no/80x15.png'; + $license = "Creative Commons License"; + endswitch; + + if ($theartwork->getId() == $artwork->getId()): + echo '\n"; + endif; + endif; + endforeach; + endif; +?> +
      + diff --git a/apps/reaktor/modules/artwork/templates/_socialBookmarks.php b/apps/reaktor/modules/artwork/templates/_socialBookmarks.php new file mode 100644 index 0000000..157c638 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_socialBookmarks.php @@ -0,0 +1,53 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("content"); + +$linkUrl = 'http://'.$sf_request->getHost().url_for($artwork->getLink()); +$title = $artwork->getTitle(); +?> + +
      +

      +
        +
      • + __("Post this to Delicious"))); ?> +
      • +
      • + __("Post this to Digg"))); ?> +
      • +
      • + __("Post this to Reddit"))); ?> +
      • + +
      +
        +
      • + __("Post this to Stumbleupon"))); ?> +
      • +
      • + __("Post this to Nettby"))); ?> +
      • +
      • + __("Show this artwork in print preview"))); ?> +
      • +
      + canEmbed()): ?> + + + +
      + diff --git a/apps/reaktor/modules/artwork/templates/_statusButtons.php b/apps/reaktor/modules/artwork/templates/_statusButtons.php new file mode 100644 index 0000000..de6cfe9 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_statusButtons.php @@ -0,0 +1,63 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + +

      +

      $artwork)); ?>

      + isDraft()): ?> +

      + + +
      + +
      + isDraft() || $artwork->isRejected()): ?> + getId(), array('class' => 'clearnone inline')); ?> + "submit_artwork")); ?> + '; ?> + + isRemoved()): ?> + "artwork_".$artwork->getId(), + 'complete' => $sf_user->hasCredential("editusercontent") ? "location.reload();" : "window.location='".url_for("@my_content?mode=menu")."'", + 'url' => '@artwork_status?status=5&id='.$artwork->getId(), + 'confirm' => __("You are about to completely remove this artwork, are you sure?"), + ), array("id" => "remove_button_".$artwork->getId())); ?> + hasCredential("editusercontent")): ?> + "artwork_".$artwork->getId(), + 'complete' => "location.reload();", + 'url' => '@artwork_status?status=1&id='.$artwork->getId(), + 'confirm' => __("You are about to restore this artwork to draft status, ". + "this will also restore any files in this artwork that were hidden. ". + "the user may be under the impression that these files were deleted. Are you sure?"), + ), array("id" => "restore_button_".$artwork->getId())); ?> + + isApproved()): ?> + "artwork_".$artwork->getId(), + 'complete' => "location.reload();", + 'url' => '@artwork_status?status=6&id='.$artwork->getId(), + 'confirm' => __("Hide this artwork temporarily?"), + ), array("id" => "disable_button_".$artwork->getId())); ?> + isApprovedHidden()): ?> + "artwork_".$artwork->getId(), + 'complete' => "location.reload();", + 'url' => '@artwork_status?status=3&id='.$artwork->getId(), + 'confirm' => __("Restore this artwork for public viewing?"), + ), array("id" => "enable_button_".$artwork->getId())); ?> + +
      \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_statusRow.php b/apps/reaktor/modules/artwork/templates/_statusRow.php new file mode 100644 index 0000000..6f2a716 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_statusRow.php @@ -0,0 +1,65 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> +hasCredential('staff') && isset($show_id)): ?> + getId()) ?>
      + + + date("d/m/Y", $t = strtotime($artwork->getCreatedAt(), $_SERVER["REQUEST_TIME"])), + "%at_time%" => date("H:i", $t), + "%action%" => __("Created"))); ?> + +
      + + + + +isSubmitted()): ?> + date("d/m/Y", $t = strtotime($artwork->getSubmittedAt(), $_SERVER["REQUEST_TIME"])), + "%at_time%" => date("H:i", $t), + "%action%" => "".__("Awaiting approval")."")); ?> +isRejected()): ?> + hasCredential('staff')?" by %username%":""), + array("%on_date%" => date("d/m/Y", $t = strtotime($artwork->getActionedAt(), $_SERVER["REQUEST_TIME"])), + "%at_time%" => date("H:i", $t), + "%action%" => "".__("Rejected")."", + "%username%" => $artwork->getActionedBy(false), + )); ?> +isDraft()): ?> + ".__("Not submitted").''; ?> +isApproved()): ?> + hasCredential('staff')?" by %username%":""), + array("%on_date%" => date("d/m/Y", $t = strtotime($artwork->getActionedAt(), $_SERVER["REQUEST_TIME"])), + "%at_time%" => date("H:i", $t), + "%username%" => $artwork->getActionedBy(false), + "%action%" => "".__("Approved")."")); ?> +isRemoved()): ?> + date("d/m/Y", $t = strtotime($artwork->getActionedAt(), $_SERVER["REQUEST_TIME"])), + "%at_time%" => date("H:i", $t), + "%username%" => $artwork->getActionedBy(false), + "%action%" => "".__("Removed by %staff_or_user% %username%", + array("%staff_or_user%" => ($artwork->getActionedBy() == $artwork->getUserId() ? __("user") : __("staff")), + "%username%" => $sf_user->hasCredential('staff') ? "(".$artwork->getActionedBy(false).")" : ""))."")); ?> +isApprovedHidden()): ?> + date("d/m/Y", $t = strtotime($artwork->getActionedAt(), $_SERVER["REQUEST_TIME"])), + "%at_time%" => date("H:i", $t), + "%username%" => $artwork->getActionedBy(false), + "%action%" => "".__("Approved but was hidden by %staff_or_user% %username%", + array("%staff_or_user%" => ($artwork->getActionedBy() == $artwork->getUserId() ? __("user") : __("staff")), + "%username%" => $sf_user->hasCredential('staff') ? "(".$artwork->getActionedBy(false).")" : ""))."")); ?> + + diff --git a/apps/reaktor/modules/artwork/templates/_submit_box.php b/apps/reaktor/modules/artwork/templates/_submit_box.php new file mode 100644 index 0000000..e8bc4df --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_submit_box.php @@ -0,0 +1,51 @@ +isDraft(): + ?> +
      +

      :

        +

      +
      +

      +

      .

      + $artwork, 'nostatus' => true)); ?> +
      + isSubmitted(): + ?> + + isApproved(): + ?> +
      +

      :

        +

      +
      +

      .

      + $artwork, 'nostatus' => true)); ?> +
      + isRejected(): + ?> +
      +

      :

        +

      +
      +

      :

      +

      getRejectionMsg(); ?> 

      + $artwork, 'nostatus' => true)); ?> +
      + \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/_transcoderOptions.php b/apps/reaktor/modules/artwork/templates/_transcoderOptions.php new file mode 100644 index 0000000..9a10907 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_transcoderOptions.php @@ -0,0 +1,31 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + +
      + '@re_transcode_file?id='.$file->getId(), + 'update' => 'transcodershell', + 'script' => 'true', + 'complete' => "$('player_warning').style.width='500px'; $('player_warning').style.height='500px';" + +)); ?> + '@transcoderlog?id='.$file->getId(), + 'update' => 'transcodershell', + 'script' => 'true', + 'complete' => "$('player_warning').style.width='500px'; $('player_warning').style.height='500px';" + +)); ?> diff --git a/apps/reaktor/modules/artwork/templates/_userArtworkListElement.php b/apps/reaktor/modules/artwork/templates/_userArtworkListElement.php new file mode 100644 index 0000000..e8f1493 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/_userArtworkListElement.php @@ -0,0 +1,126 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper("content", "Javascript"); + +?> + +
      + getFirstFile(), 'mini'), array( + 'title' => $artwork->getTitle(), + 'alt' => $artwork->getTitle(), + 'height' => 65, + 'width' => 78, + )); ?> +
      + +
      + + getTitle(), "@show_artwork?id=".$artwork->getId()."&title=".$artwork->getTitle()); ?>  + [ getId()); ?> + isRemoved()): ?> / + "artwork_".$artwork->getId(), + 'complete' => "updateContentSidebar('".$thisUser->getUsername()."');".visual_effect('highlight', 'user_artwork_list'), + 'url' => '@artwork_status_returndetails?status=5&id='.$artwork->getId(), + 'confirm' => __("You are about to completely remove this artwork, are you sure?"), + ), array("id" => "remove_button_".$artwork->getId())); ?> + / + "artwork_".$artwork->getId(), + 'complete' => "updateContentSidebar('".$thisUser->getUsername()."');".visual_effect('highlight', 'artwork_'.$artwork->getId()), + 'url' => '@artwork_status_returndetails?status=1&id='.$artwork->getId(), + 'confirm' => __("You are about to restore this artwork to draft status, ". + "this will also restore any files in this artwork that were hidden. ". + "the user may be under the impression that these files were deleted. Are you sure?"), + ), array("id" => "restore_button_".$artwork->getId())); ?> + + isApproved()): ?> + "artwork_".$artwork->getId(), + 'complete' => "updateContentSidebar('".$thisUser->getUsername()."');".visual_effect('highlight', 'artwork_'.$artwork->getId()), + 'url' => '@artwork_status_returndetails?status=6&id='.$artwork->getId(), + 'confirm' => __("Hide this artwork temporarily?"), + ), array("id" => "disable_button_".$artwork->getId())); ?> + isApprovedHidden()): ?> + "artwork_".$artwork->getId(), + 'complete' => "updateContentSidebar('".$thisUser->getUsername()."');".visual_effect('highlight', 'artwork_'.$artwork->getId()), + 'url' => '@artwork_status_returndetails?status=3&id='.$artwork->getId(), + 'confirm' => __("Restore this artwork for public viewing?"), + ), array("id" => "enable_button_".$artwork->getId())); ?> + + + ] + +
        +
      • + + isRemoved()): ?> +
        + getId() != $sf_user->getId() && $sf_user->hascredential("editusercontent")): ?> + + + + + getFilesCount() == 1): ?> + collectionType($artwork))). + " ".reaktor_link_to(__("new file"), "@artwork_link?link_artwork_id=".$artwork->getId()). + " / ".reaktor_link_to(__("existing file"), "@".$extra_route."link_existing_file?user=".$thisUser->getUsername()."&artworkId=".$artwork->getId()); ?> + + collectionType($artwork))). + " ".reaktor_link_to(__("new file"), "@artwork_link?link_artwork_id=".$artwork->getId()). + " / ".reaktor_link_to(__("existing file"), "@".$extra_route."link_existing_file?user=".$thisUser->getUsername()."&artworkId=".$artwork->getId()); ?> + + +
        + +
        + getTags(); + include sfConfig::get("sf_root_dir"). '/apps/reaktor/modules/tags/templates/_viewTagsWithLinks.php'; */ + if (count($artwork->getTags(false, true)) > 0) + { + include_component("tags","tagEditList", + array("taggableObject" => $artwork, "options" => array('noicons' => true, "nomargin" => true))); + } + else + { + if (count($artwork->getTags(false, true)) > 0) + { + echo '' . __('This artwork has no approved tags. Tags makes your artworks easier to find.') . ''; + } + else + { + echo '' . __('This artwork has no tags. Tags makes your artworks easier to find.') . ''; + } + } + + ?> +
        +
      • +
      • + getRelatedArtworks(6, false)): ?> + + + + +  [getId()); ?>] +
      • +
      +
      + diff --git a/apps/reaktor/modules/artwork/templates/discussSuccess.php b/apps/reaktor/modules/artwork/templates/discussSuccess.php new file mode 100644 index 0000000..4cd09a7 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/discussSuccess.php @@ -0,0 +1,62 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript'); +reaktor::setReaktorTitle(__('Artwork discussion')); + +?> +
      +
        +
      • +
      • +
      • +
      + +
       
      + + +

      + +

      + + +
      + + $object, + 'buttonPartial' => 'admin/discussButtons' + )) ?> + + $object, + 'buttonPartial' => 'admin/discussButtons')); ?> + +
      + +
      +

      +

      +

       

      +
      +
      + $object->getBaseObject(), + 'namespace' => 'administrator', + 'adminlist' => true))?> +
      \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/editSuccess.php b/apps/reaktor/modules/artwork/templates/editSuccess.php new file mode 100644 index 0000000..78661d2 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/editSuccess.php @@ -0,0 +1,137 @@ + + * @author Daniel Andre Eikeland + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('content', 'Javascript', 'Object'); +reaktor::setReaktorTitle(__('Artwork edit')); + +include_partial('submit_box',array('artwork' => $artwork)); + ?> +hasErrors()): ?> +

       .

      + +
      +

      + $artwork->getTitle())) ?> +

      + '@artworkupdatefield?id='.$artwork->getId().'&field=title', + 'update' => 'title_message', + 'loading' => "$('title_waiting').show();", + 'success' => "$('title_message').show();$('title_waiting').hide();", + )); ?> +   +
      + getTitle(), array('id' => 'title_value')); ?> + 'margin: 0px; margin-bottom: 5px;')); ?> +
      + sfConfig::get("app_artwork_min_title_length"), + "%max%" => sfConfig::get("app_artwork_max_title_length"), + ' (' => '
      (')); ?> +
      +
      + '; ?> + isMultiUser()): //Print username only if artwork has single author/owner?> + + getUser()->getUsername(); + + echo __('Author: %username%', array( + '%username%' => ''.reaktor_link_to($displayname, '@portfolio?user='.$artwork->getUser()->getUsername()).'' + ))?> + + +  [getLink('show', null, false, true)); ?>]
      +
      + getArtworkType() == "text"): ?> +
      + +
      + + $artwork, 'thefile' => $artwork->getFirstFile())) ?> +
      + getArtworkType() != "image"): ?> + getId()); ?> + hasStaticThumbnail()): ?> + getId()); ?> + +
      + +
      + + getFilesCount() > 1): ?> +

      + '@artworkupdatefield?id='.$artwork->getId().'&field=description', + 'update' => 'description_message', + 'loading' => "$('description_waiting').show();", + 'success' => "$('description_message').show();$('description_waiting').hide();", + )); ?> +   +
      + getDescription(), array('id' => 'description_value', 'style' => 'width: 520px;')); ?>
      + 'margin: 0px; margin-bottom: 5px; float: right;')); ?> +
      + '; ?> + + +
      + $artwork)) ?> +
      + +
      + getUser()->getArtworkCount() > 1): ?> +

      + +
      + $artwork, 'usercanedit' => true, 'editmode' => true)); ?> +
      + + +
      + + +
      +
      + $artwork)); ?> +
      +
      +

      + getId().");" : ""; ?> + $objectToTag, "artworkList" => $artwork->getId(), "completeFuncs" => $completeFuncs)); ?> + hasCredential('staff')): ?> +
      + $artwork)) ?> + + $artwork)) ?> + isApproved()): ?> + $artwork)) ?> + +
      + + +
      +
      + $artwork)); ?> +
      + diff --git a/apps/reaktor/modules/artwork/templates/lastArtworksFromUserActionSuccess.php b/apps/reaktor/modules/artwork/templates/lastArtworksFromUserActionSuccess.php new file mode 100644 index 0000000..22959c2 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/lastArtworksFromUserActionSuccess.php @@ -0,0 +1,27 @@ + + * @author June Henriksen + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__('Latest artwork from %username%', array("%username%" => $user))); + +?> + + $userid, + 'portfolio' => true, + 'user' => $user, + 'orderBy' => $orderBy, +)) ?> diff --git a/apps/reaktor/modules/artwork/templates/listArtworksPopupSuccess.php b/apps/reaktor/modules/artwork/templates/listArtworksPopupSuccess.php new file mode 100644 index 0000000..c1987c0 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/listArtworksPopupSuccess.php @@ -0,0 +1,40 @@ + + + + + Browse artworks + + + + + + + + + + + + + + +getId(), array( + 'id' => 'listartform', + 'name' => 'listartform'));?> + $artworks, 'article' => $article)); ?> + + getId(), null, array('frequency' => 0.2,))?> + array('success' => 'artworkslist', 'failure' => 'artworkslist'), + 'url' => '@browsearticleartworks?article_id='. $article->getId(), + 'script' => true), + array('class' => 'submit'))?> + " onclick="tinyMCEPopup.close();" /> + + + + + + diff --git a/apps/reaktor/modules/artwork/templates/listDiscussionSuccess.php b/apps/reaktor/modules/artwork/templates/listDiscussionSuccess.php new file mode 100644 index 0000000..70a3c1b --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/listDiscussionSuccess.php @@ -0,0 +1,59 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'content'); +reaktor::setReaktorTitle(__('Artwork discussion')); + +?> + +

      +
      +
      + + 0): //artworks or files found?> + +
        + +
      • + $artwork, + 'update_div' => 'artwork_list_container_'.$artwork->getId(), + 'buttonPartial' => 'admin/discussButtons')); ?> +
      • + + +
      • + $file, + 'update_div' => 'artwork_list_container_f_'.$file->getId(), + "buttonPartial" => "admin/discussButtons")); ?> +
      • +
      + + + + + +

      + +

      + \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/listModifiedSuccess.php b/apps/reaktor/modules/artwork/templates/listModifiedSuccess.php new file mode 100644 index 0000000..dc26d42 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/listModifiedSuccess.php @@ -0,0 +1,23 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * TODO: Slide the rejection comments + */ + +reaktor::setReaktorTitle(__('Modified artwork')); + +?> + + + +

      +
      + $arts)); ?> + \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/listRejectedFilesSuccess.php b/apps/reaktor/modules/artwork/templates/listRejectedFilesSuccess.php new file mode 100644 index 0000000..9504ae3 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/listRejectedFilesSuccess.php @@ -0,0 +1,30 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'PagerNavigation'); +reaktor::setReaktorTitle('Rejected files'); + +?> + +

      +
      + $files))?> + diff --git a/apps/reaktor/modules/artwork/templates/listRejectedSuccess.php b/apps/reaktor/modules/artwork/templates/listRejectedSuccess.php new file mode 100644 index 0000000..156936d --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/listRejectedSuccess.php @@ -0,0 +1,57 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * TODO: Slide the rejection comments + */ + +reaktor::setReaktorTitle(__('Rejected files')); +reaktor::addJsToFooter("$('approved_calendar').setStyle({height: $('sidebar').offsetHeight + 'px'});"); +use_helper('content', 'Javascript', 'PagerNavigation', 'Date'); + +?> + +hasCredential('approveartwork')): ?> +
      +
      +

      +
      +
        + = 2004; $ccY--): ?> +
      • + +
          + +
        • + +
        + +
      • + +
      +
      +
      + +

      format_date(date('Y-m-d', mktime(null, null, null, $selected_month, 1, $selected_year)), 'MMMM'), '%year%' => $selected_year)) ?>

      + $artworks)); ?> + + + + +
      +
      + diff --git a/apps/reaktor/modules/artwork/templates/listReportedContentSuccess.php b/apps/reaktor/modules/artwork/templates/listReportedContentSuccess.php new file mode 100644 index 0000000..560502c --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/listReportedContentSuccess.php @@ -0,0 +1,22 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'PagerNavigation'); +reaktor::setReaktorTitle(__('Reported content')); + +?> + +

      +
      + $reported_files)); ?> + diff --git a/apps/reaktor/modules/artwork/templates/listUnapprovedSuccess.php b/apps/reaktor/modules/artwork/templates/listUnapprovedSuccess.php new file mode 100644 index 0000000..0805f47 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/listUnapprovedSuccess.php @@ -0,0 +1,38 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper('Javascript', 'content', 'PagerNavigation', 'Url'); +reaktor::setReaktorTitle(__('Unapproved artworks')); + +$selectedteam = ($team instanceof sfGuardGroup) ? $team->getId() : 0; + +?> + +hasCredential('approveartwork')): ?> + +

      $team->getDescription())) ?>

      + +

      + +

      + + +

      getUsername() ?>

      + +
      + + 'float: right;')) ?> + __('All other teams') . ' (' . ReaktorArtworkPeer::getNumberofArtworksByEditorialTeam($othereditorialteams, 2, true) . ')')), array('onchange' => 'form.submit();')); ?> + '; ?> + + $artworks)); ?> + + diff --git a/apps/reaktor/modules/artwork/templates/metadataSuccess.php b/apps/reaktor/modules/artwork/templates/metadataSuccess.php new file mode 100644 index 0000000..3b03604 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/metadataSuccess.php @@ -0,0 +1,61 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +reaktor::setReaktorTitle(__('Artwork metadata for %artwork_title%', array("%artwork_title%" => $artwork->getTitle()))); + +?> + +

      $artwork->getTitle())) ?>

      + + + + + + + + + + + + + + + +
      :getId() ?>
      :getTitle() ?>
      :getLink()), $artwork->getLink()) ?>
      :getCreatedAt() ?>
      +

      + +getFiles() as $aFile): ?> +

      getTitle() ?>

      + + + + + + + + + + + + getMetadatas(false) as $aMetadata): ?> + + + + + + + + + + + diff --git a/apps/reaktor/modules/artwork/templates/recommendationsSuccess.php b/apps/reaktor/modules/artwork/templates/recommendationsSuccess.php new file mode 100644 index 0000000..f70e08e --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/recommendationsSuccess.php @@ -0,0 +1,28 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?> + + + + $artwork)) + +?> \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/rejectArtworkSuccess.php b/apps/reaktor/modules/artwork/templates/rejectArtworkSuccess.php new file mode 100644 index 0000000..ce68dc7 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/rejectArtworkSuccess.php @@ -0,0 +1,106 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__('Reject artwork (%artwork_title%)', array("%artwork_title%" => $artwork->getTitle()))); +use_helper('content', 'Validation', 'Object', 'Javascript', 'wai'); ?> +

      + +

      +
      + $artwork)); ?> +
      +
      +getUser()->getUsername()?> +
      + +
      + +
      +
      + getId()) ?> +
      +
      + getRequest()->getParameter('status')) ?> +
      + +
      + +
      +
      + +
      +
      + + +
      + +
      + +
      +
      + +
      +
      + getUser()->getEmail()) ?> +
      + +
      + +
      +
      + +
      +
      + +
      + +
      + +
      +
      + +
      +
      + $artwork->getTitle()))) ?> +
      + +
      + +
      +
      + +
      +
      + '--'.__('Choose rejectiontype').'--')))?> +
      + +
      + +
      +
      + +
      +
      + 'rejectionmsg')) ?> +
      +
      + + __('Are you sure?'))) ?> +'history.go(-1)')) ?> +'rejectionmsg', + 'url'=>'@rejection_type_chosen', + 'with' => "'rejectiontype='+value" +))?> +
      diff --git a/apps/reaktor/modules/artwork/templates/removeFileMessageSuccess.php b/apps/reaktor/modules/artwork/templates/removeFileMessageSuccess.php new file mode 100644 index 0000000..a254832 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/removeFileMessageSuccess.php @@ -0,0 +1,128 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper('Javascript', 'Object', 'wai'); +reaktor::setReaktorTitle(__('Remove %file_title% from artworks', array("%file_title%" => $artwork_file->getTitle()))); + +?> +

      + +
      + +
      + getId().'&filename='.$artwork_file->getFilename())) ?> +
      + + + + $artwork)); ?> +
      + +
      +getUser()->getUsername()?> +
      + +
      + +
      +
      + getId()) ?> +
      +
      + getRequest()->getParameter('status')) ?> +
      + +
      + +
      +
      + +
      +
      + + +
      + +
      + +
      +
      + +
      +
      + getUser()->getEmail()) ?> +
      + +
      + +
      +
      + +
      +
      + +
      + +
      + +
      +
      + +
      +
      + $artwork_file->getFilename()))) ?> +
      + +
      + +
      +
      + +
      +
      + '--'.__('Choose removetemplate').'--')))?> +
      + +
      + +
      +
      + +
      +
      + 'rejectionmsg')) ?> +
      +
      + + __('Are you sure?'))) ?> + __('Are you sure?'))) ?> +'rejectionmsg', + 'url'=>'@rejection_type_chosen', + 'with' => "'rejectiontype='+value" +))?> +
      diff --git a/apps/reaktor/modules/artwork/templates/showSuccess.php b/apps/reaktor/modules/artwork/templates/showSuccess.php new file mode 100644 index 0000000..92ba10f --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/showSuccess.php @@ -0,0 +1,221 @@ + + * @author Russ Flynn + * @author Daniel Andre Eikeland + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle($artwork->getTitle()); +use_helper('content', 'Javascript'); + +?> + +
      +
      + + getUser()->getUsername() ?> + isMultiUser()): //Display title and username?> + '

      ' . $artwork->getTitle() . '

      ', + '%username%' => '' . reaktor_link_to($displayname, + '@portfolio?user=' . $artwork->getUser()->getUsername()) . '' + ))?> + + ' . $artwork->getTitle() . ''; ?> + + hasCredential("editusercontent") || $sf_user->getId() == $artwork->getUserId()): ?> +  [getId()); ?>] + +
      + hasCredential('staff')): ?> +
      +

      $artwork, + "break" => true, + "show_id" => true)); ?>

      + getArtworkType() == genericArtwork::TEXT): ?> +
      +
      + + + getFilesCount() > 1): ?> +
      + $artwork->getTitle(), 'slug' => "artwork", "route" => "showfilefeed?id=".$artwork->getId())); ?> +
      + + +
      + getArtworkType() == genericArtwork::TEXT): //Big thumbnail and rating for ?> + +
      + getThumbpath() != '' && is_file(sfConfig::get('sf_root_dir') . "/content/" . $thefile->getIdentifier() . "/thumbnail/" .$thefile->getThumbPath())): ?> +
      + +
      + +
      isAuthenticated()): ?> title="" > + $artwork, 'usercanedit' => $usercanedit)); ?> +
      +
      + + + + $artwork, 'thefile' => $thefile)) ?> +
      + + + +
      + getArtworkType() != 'text'): ?> +
      +

      + getFilesCount() > 1): ?> + getDescription()) != "" ? nl2br($artwork->getDescription()) : __("No description"); ?> + + getMetadata('description', 'abstract')): ?> + getMetadata('description', 'abstract')) ?> + + getDescription()) != "" ? nl2br($artwork->getDescription()) : __("No description"); ?> + + +
      + + + + + + + + getFilesCount() == 1 && $thefile->getMetadata('relation', 'references') && !stristr($thefile->getMetadata('relation', 'references'), 'http')===FALSE): ?> + +getMetadata('relation', 'references')); ?> + + + +
      +

      + getMetadata('relation', 'references')); + + foreach($links as $link) if(!stristr($link, 'http')===FALSE) + echo link_to($link, $link).'
      '; + + + ?> +
      + + + + + + +
      +

      + getTags(); ?> + + $tags, 'subreaktor' => $artwork->getSubreaktors(true))) ?> + + getTags(false, true)) > 0): ?> + + + + + +
      + + + +
      + $artwork, 'usercanedit' =>$usercanedit, 'editmode' => $editmode)) ?> + $artwork, + 'update' => 'relate_artwork_tag', + 'editmode' => $editmode, + 'usercanedit' => $usercanedit)); ?> +
      + + + $artwork, 'thefile' => $thefile)); ?> +
      +
      + $artwork->getBaseObject(), 'namespace' => 'frontend', 'adminlist' => false)) ?> +
      +
      + + +
      + + +
      +
      + $artwork->getTags())) ?> +
      +
      + $artwork->getId(), 'user_id' => $artwork->getUser()->getId(), "checkAndDeleteNode" => "artwork_actions_and_favourites")); ?> +
      $artwork, 'thefile' => $thefile, 'partial' => true)); ?>
      +
      + + showNavigationOnDisplay() && $artwork->getFilesCount() > 1): ?> +
      +

      +
      + $thefile->getTitle())); ?> +

      + "artwork_nav_links", "artwork" => $artwork, "thefile" => $thefile)); ?> +
      + + + $artwork, 'file' => $thefile)); ?> + + +
      +

      + $articles))?> +
      + + + + hasCredential('staff')): ?> +
      + $artwork, + 'thefile' => $thefile)) ?> + + $artwork)) ?> + getStatus() == 3): ?> + $artwork)) ?> + + +
      + + +
      diff --git a/apps/reaktor/modules/artwork/templates/transcoderLogSuccess.php b/apps/reaktor/modules/artwork/templates/transcoderLogSuccess.php new file mode 100644 index 0000000..4feae5d --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/transcoderLogSuccess.php @@ -0,0 +1,22 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> +
      +

      + + + + + +

      +

      \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/updateSuccess.php b/apps/reaktor/modules/artwork/templates/updateSuccess.php new file mode 100644 index 0000000..4bb57ab --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/updateSuccess.php @@ -0,0 +1,11 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/templates/xspfOutputSuccess.php b/apps/reaktor/modules/artwork/templates/xspfOutputSuccess.php new file mode 100644 index 0000000..e7351d9 --- /dev/null +++ b/apps/reaktor/modules/artwork/templates/xspfOutputSuccess.php @@ -0,0 +1,52 @@ + +' . "\n"; ?> +getHost() . '/' . sfConfig::get('app_image_path') . '/'; ?> +getCategories()) > 1): ?> + + + getCategories(); ?> + + + +getTitle(); + $search = array('æ', 'Æ', 'ø', 'Ø', 'å', 'Å'); + $replace = array('ae', 'AE', 'oe', 'OE', 'aa', 'AA'); + $title = str_replace($search, $replace, $title); +/*$title = str_replace('Æ', 'AE', $title); + $title = str_replace('ø', 'oe', $title); + $title = str_replace('Ø', 'OE', $title); + $title = str_replace('å', 'aa', $title); + $title = str_replace('Å', 'AA', $title);*/ + + ?> + + <?php echo $title ?> + http:// + getUser()->getName(); ?> + getHost() .url_for($artwork->getLink('xml').'&format=xspf'); ?> + + +getFiles() as $aFile): ?> + + getMetadata('title'); + $trackCreator = $aFile->getMetadata('creator'); + $search = array('æ', 'Æ', 'ø', 'Ø', 'å', 'Å'); + $replace = array('ae', 'AE', 'oe', 'OE', 'aa', 'AA'); + $trackTitle = str_replace($search, $replace, $trackTitle); + $trackCreator = str_replace($search, $replace, $trackCreator); + ?> + + <?php echo $trackTitle; ?> + getThumbPath()): ?> + http://getHost() . contentPath($aFile, "thumb"); ?> + + http:// + + http://getHost() . contentPath($aFile); ?> + getMetadata('description', 'abstract') ?> + + + + + diff --git a/apps/reaktor/modules/artwork/validate/addRecommendation.yml b/apps/reaktor/modules/artwork/validate/addRecommendation.yml new file mode 100644 index 0000000..f7d6130 --- /dev/null +++ b/apps/reaktor/modules/artwork/validate/addRecommendation.yml @@ -0,0 +1,7 @@ +fillin: + enabled: true + +fields: + recommend_in_subreaktor: + required: + msg: Please choose the subReaktor you want this artwork to be recommended in diff --git a/apps/reaktor/modules/artwork/validate/reject.yml b/apps/reaktor/modules/artwork/validate/reject.yml new file mode 100644 index 0000000..afcb9ff --- /dev/null +++ b/apps/reaktor/modules/artwork/validate/reject.yml @@ -0,0 +1,26 @@ +fillin: + enabled: true + +fields: + subject: + required: + msg: Please enter a title + rejectionmsg: + required: + msg: Please enter a rejection message + to: + required: + msg: Please enter an email address + sfEmailValidator: + email_error: This email address is invalid + cc: + sfEmailValidator: + email_error: This email address is invalid + from: + required: + msg: Please enter an e-mail address + sfEmailValidator: + email_error: This email address is invalid + rejectiontype: + required: + msg: Please choose why this artwork is rejected \ No newline at end of file diff --git a/apps/reaktor/modules/artwork/validate/removeFile.yml b/apps/reaktor/modules/artwork/validate/removeFile.yml new file mode 100644 index 0000000..58941ff --- /dev/null +++ b/apps/reaktor/modules/artwork/validate/removeFile.yml @@ -0,0 +1,40 @@ +fillin: + enabled: true + +validators: + doubleCheckEmailValidator: + class: sfEmailValidator + param: + strict: true + email_error: This email address has an incorrect format + + myEmailValidator: + class: sfEmailValidator + param: + email_error: This email address contains non-acceptable values + strict: false + + +fields: + subject: + required: + msg: Please enter a title + rejectionmsg: + required: + msg: Please enter a rejection message + to: + required: + msg: Please enter an email address + myEmailValidator: + doubleCheckEmailValidator: + cc: + myEmailValidator: + doubleCheckEmailValidator: + from: + required: + msg: Please enter an e-mail address + myEmailValidator: + doubleCheckEmailValidator: + rejectiontype: + required: + msg: Please choose why this file is being removed \ No newline at end of file diff --git a/apps/reaktor/modules/contentServer/actions/actions.class.php b/apps/reaktor/modules/contentServer/actions/actions.class.php new file mode 100644 index 0000000..3ee2e6c --- /dev/null +++ b/apps/reaktor/modules/contentServer/actions/actions.class.php @@ -0,0 +1,324 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Serve content to the web from a hidden location + * + * This is required so content which is not yet public cannot be directly accessed + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class contentServerActions extends sfActions +{ + /** + * The file identifier, (image, pdf) + * + * @var string + */ + protected $_identifier; + + /** + * The original name (the name to use when serving the file) + * For example myimage.jpg + * + * @var string + */ + protected $_originalName; + + /** + * The content type (mime type) of the file + * + * @var string + */ + protected $_contentType; + + /** + * The actual name of the file on the server + * + * @var string + */ + protected $_realname; + + /** + * The full path to the file on the server + * + * @var string + */ + protected $_filePath; + + /** + * The Return type of the file (thumbnail/mini etc) + * + * @var unknown_type + */ + protected $_returnType; + + /** + * From routing /content/:id/:filename + * Serve the normal file that will be shown on the artwork view + * + * @return null + * + */ + public function executeContentServer() + { + $this->_getFile("converted"); + } + + /** + * From routing /content/:id/thumb/:filename + * Serve the thumbnail image associated with a file + * + * @return null + */ + public function executeContentThumb() + { + $this->_getFile("thumbnail"); + } + + /** + * From routing /content/:id/mini/:filename + * Serve the mini thumbnail image associated with a file + * + * @return null + */ + public function executeContentMini() + { + $this->_getFile("thumbnail", "/mini"); + } + + /** + * From routing /content/:id/original/:filename + * Serve the original (non resized) version of a file + * If one exists + * + * @return null + * + */ + public function executeContentOriginal() + { + $this->_getfile("original"); + } + + /** + * Look up the file from the DB and gather the required information + * + * @param string $returnType The mode based on the route to this script + * @param string $subsubdir The sub-sub directory (for example when using mini) + * + * @return nothing - calls the page renderer if all ok + */ + protected function _getFile($returnType, $subsubdir = "") + { + $contentDir = sfConfig::get('upload_dir', 'content'); + $fileId = $this->getRequestParameter('id'); + $authSql = ""; + $subdir = ""; + $this->_returnType = $returnType; + $c = new Criteria(); + + $c->add(ReaktorFilePeer::ID, $fileId); + $c->setLimit(1); + if (!$this->getUser()->hasCredential("viewallcontent")) + { + $crit = $c->getNewCriterion(ReaktorArtworkPeer::STATUS, 3); + $crit->addOr($c->getNewCriterion(ReaktorFilePeer::USER_ID, $this->getUser()->getId())); + $c->add($crit); + } + + $resultset = ReaktorArtworkFilePeer::doSelectJoinAll($c); + $resultset = array_shift($resultset); + if (!$resultset) + { + $c = new Criteria(); + + if (!$this->getUser()->hasCredential("viewallcontent")) + $c->add(ReaktorFilePeer::USER_ID, $this->getUser()->getId()); + $c->add(ReaktorFilePeer::ID, $fileId); + + $fileObj = ReaktorFilePeer::doSelectOne($c); + } else + { + + $fileObj = $resultset->getReaktorFile(); + } + // If we didn't get a hit then we should use a "file not found" image or similar + // Most likely is that the parent artwork/user has been removed/disabled + if (!$fileObj) + { + $this->_sendFileNotFound(); + } + + $this->_realname = $fileObj->getRealPath(); + $this->_originalName = $fileObj->getFilename(); + $this->_identifier = $fileObj->getIdentifier(); + $this->_originalpath = $fileObj->getOriginalpath(); + $location = "/content/".$this->_identifier; + $mimeFunc = 'get'.ucfirst($returnType).'MimetypeId'; + $mimeTypeId = $fileObj->$mimeFunc(); + + + + +// to avoid wrong mimetype of movie thumbnail + if (($returnType == "thumbnail" || $returnType == "mini") && $this->_identifier != "image") { + $this->_contentType = "image/jpeg"; + }else { + $this->_contentType = FileMimetypePeer::retrieveByPK($mimeTypeId)->getMimeType(); + } + + + if ($returnType != "converted") + { + $subdir = "/".$returnType; + if ($returnType == "thumbnail" && $this->_identifier != "image") + { + $this->_realname .= ".jpg"; + } + } + if ($returnType != 'original') + { + + $this->_filePath = sfConfig::get('sf_root_dir').$location.$subdir.$subsubdir."/".$this->_realname; + } + else + { + $this->_contentType = "application/octet-stream"; + $this->_filePath = sfConfig::get('sf_root_dir').$location.$subdir.$subsubdir."/".$this->_originalpath; + } + + + if (!$this->_fileOk() && $returnType == "thumbnail") + { + if (!$this->_getPostGeneratedFile($fileObj,$location)) + { + $this->_contentType = "image/gif"; + $this->_filePath = sfConfig::get('sf_root_dir').$location.$subdir.$subsubdir."/default.gif"; + + } + } + else + { + if (!$this->_fileOk()) + { + + $this->_sendFileNotFound(); + } + } + $this->_sendpage(); + } + + /** + * Render the page + * + * @return formatted html page + * + */ + protected function _sendpage() + { + if (ini_get('zlib.output_compression')) + { + ini_set('zlib.output_compression', 'Off'); + } + + header("Pragma: public"); + header("Expires: 0"); + header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); + header("Cache-Control: private", false); + header("Content-Type: ".$this->_contentType); + + set_time_limit(0); + + @readfile($this->_filePath); + + exit(); // Brutal but we should make sure there is no further output once this function is perfomed + } + + /** + * Checks to see if a file matches the required criteria to be served + * + * @return boolean (true if file exists and is ok) + */ + protected function _fileOk() + { +sfLoader::loadHelpers('string'); + $path_parts = pathinfo($this->getRequestParameter("filename") ); + $extension = $path_parts['extension']; + return (file_exists($this->_filePath) && ($this->_originalName == $this->getRequestParameter("filename") + || $this->getRequestParameter("filename") == $this->_originalName.".".$extension + || $this->getRequestParameter("filename") == $this->_originalName.".jpg" + || getThumbNameFromFile($this->getRequestParameter("filename")) == getThumbNameFromFile($this->_originalName) +) + ); + } + + /** + * Send a file not found image in case of errors + * Used instead of 404 because it covers artworks that have been removed etc + * + * @return void triggers the send page function + */ + protected function _sendFileNotFound() + { + if ($this->_returnType == "mini") + { + $this->_contentType = "image/gif"; + $this->_filePath = sfConfig::get('sf_web_dir').'/images/filenotfound78x65.gif'; + } + else + { + $this->_contentType = "image/gif"; + $this->_filePath = sfConfig::get('sf_web_dir').'/images/filenotfound240x160.gif'; + } + $this->_sendpage(); + } + + protected function _getPostGeneratedFile($fileObj, $location) + { + $thumbLocation = sfConfig::get('sf_root_dir').$location."/".$fileObj->getRealPath().".thumb.jpg"; + $newThumb = sfConfig::get('sf_root_dir').$location."/thumbnail/".$fileObj->getRealPath().".jpg"; + $newMini = sfConfig::get('sf_root_dir').$location."/thumbnail/mini/".$fileObj->getRealPath().".jpg"; + + if (file_exists($thumbLocation) && (!file_exists($newThumb) || !file_exists($newMini))) + { + + $image = new imageResize($thumbLocation, + $newThumb, + 240, + 160, + true); + $image->imageWrite(); + + $image = new imageResize($thumbLocation, + $newMini, + 78, + 65, + true); + $image->imageWrite(); + unlink($thumbLocation); + + $fileObj->setThumbnailMimetypeId(2); + $fileObj->save(); + + header("Location: ".$this->getRequest()->getUri()); + } + return false; + } +} + diff --git a/apps/reaktor/modules/contentServer/config/security.yml b/apps/reaktor/modules/contentServer/config/security.yml new file mode 100644 index 0000000..d81bd18 --- /dev/null +++ b/apps/reaktor/modules/contentServer/config/security.yml @@ -0,0 +1,2 @@ +all: + is_secure: off \ No newline at end of file diff --git a/apps/reaktor/modules/contentServer/config/view.yml b/apps/reaktor/modules/contentServer/config/view.yml new file mode 100644 index 0000000..e69de29 diff --git a/apps/reaktor/modules/contentServer/templates/_showMini.php b/apps/reaktor/modules/contentServer/templates/_showMini.php new file mode 100644 index 0000000..c33737a --- /dev/null +++ b/apps/reaktor/modules/contentServer/templates/_showMini.php @@ -0,0 +1,46 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +// Generate the mouseover tooltip if any +if (!isset($nomouseover) || !$nomouseover): + $thisMouseover = "Tip('

      ".addslashes($artwork->getTitle())."

      "; + if (!$artwork->isMultiUser()) + { + $thisMouseover .= __("by")." ".$artwork->getUser()->getUsername()."
      "; + } + $thisMouseover .= __('Created on: %creation_date%', array('%creation_date%' => date("d/m/Y", strtotime($artwork->getCreatedAt()))))."

      "; + $thisMouseover .= get_partial('artwork/artworkRating', array('artwork' => $artwork, 'noedit' => false, 'login' => false))."
      ', FADEIN, 300, BGCOLOR, '#FFFFFF')"; + $thisMouseout = "UnTip()"; +else: + $thisMouseover = ""; + $thisMouseout = ""; +endif; +$relative = isset($relative) ? $relative : false; + +// Display the thumbnail on the page +if (!isset($nolink) || $nolink == false): +echo reaktor_link_to(image_tag(contentPath($artwork, "mini"), array('size' => '78x65', 'alt' => $artwork->getTitle(), 'title' => $artwork->getTitle(), 'absolute' => !$relative)), + $artwork->getLink(), array( + 'onmouseover' => $thisMouseover, + 'onmouseout' => $thisMouseout, + 'absolute' => !$relative, +)); +else: + echo image_tag(contentPath($artwork, "mini"), array('size' => '78x65', 'alt' => $artwork->getTitle(), 'title' => $artwork->getTitle())); +endif; + diff --git a/apps/reaktor/modules/contentServer/templates/contentServerSuccess.php b/apps/reaktor/modules/contentServer/templates/contentServerSuccess.php new file mode 100644 index 0000000..b81e37f --- /dev/null +++ b/apps/reaktor/modules/contentServer/templates/contentServerSuccess.php @@ -0,0 +1,18 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> \ No newline at end of file diff --git a/apps/reaktor/modules/favourite/actions/actions.class.php b/apps/reaktor/modules/favourite/actions/actions.class.php new file mode 100644 index 0000000..2fca7a4 --- /dev/null +++ b/apps/reaktor/modules/favourite/actions/actions.class.php @@ -0,0 +1,178 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +class favouriteActions extends sfActions +{ + + function executeAdd() + { + if (!$this->getRequest()->isXmlHttpRequest() || !$this->getUser()->hasCredential('markfavourite')) + { + $this->forward404(); + } + $this->article_id = 0; + $this->artwork_or_user_id = $this->getRequestParameter('id'); + Favourite::ADDFavourite($this->getRequestParameter('id'),$this->getRequestParameter('type'),$this->getUser()->getGuardUser()->getId()); + + $this->type = $this->getRequestParameter('type'); + $this->both = $this->getRequestParameter('both'); + if ($this->both) + { + $this->artwork_id = $this->getRequestParameter('artwork_id'); + $this->user_id = $this->getRequestParameter('user_id'); + } + else + { + $this->artwork_id = $this->user_id = 0; + } + if ($this->type == "article") + { + $this->article_id = $this->getRequestParameter('id'); + } + } + + function executeRemove() + { + + if (!$this->getRequest()->isXmlHttpRequest() || !$this->getUser()->hasCredential('markfavourite')) + { + $this->forward404(); + } + $this->both = $this->getRequestParameter('both'); + if ($this->both) + { + $this->artwork_id = $this->getRequestParameter('artwork_id'); + $this->user_id = $this->getRequestParameter('user_id'); + } + if (!$this->getRequestParameter('who')) + { + $this->artwork_or_user_id = $this->getRequestParameter('id'); + } + else + { + $this->artwork_or_user_id = $this->getUser()->getGuardUser()->getId(); + } + Favourite::deleteFavourite($this->getRequestParameter('id'),$this->getRequestParameter('type'),$this->getUser()->getGuardUser()->getId()); + + $this->who = $this->getRequestParameter('who'); + $this->type = $this->getRequestParameter('type'); + $fav_obj = new Favourite(); + + if (!$this->who) + { + $this->favourites = null;//$fav_obj->getLastFavs($this->getRequestParameter('type'),$this->getRequestParameter('id')); + } + else + { + $this->favourites = $fav_obj->getMyLastFavs($this->getRequestParameter('type'),$this->getUser()->getGuardUser()->getId()); + } + if ($this->type == "article") + { + $this->article_id = $this->getRequestParameter('id'); + $this->list = $this->type; + } + else { + $this->article_id = 0; + } + } + + function executeListAll() + { + if (!$this->getRequest()->isXmlHttpRequest()) + { + $this->forward404(); + } + $this->who = $this->getRequestParameter('who'); + $fav_obj = new Favourite(); + if (!$this->who) + { + $this->favourites = $fav_obj->getLastFavs($this->getRequestParameter('type'),$this->getRequestParameter('id')); + } + else + { + $this->favourites = $fav_obj->getMyLastFavs($this->getRequestParameter('type'),$this->getRequestParameter('id')); + } + $this->type = $this->getRequestParameter('type'); + + $this->artwork_or_user_id = $this->getRequestParameter('id'); + if ($this->getUser()->isAuthenticated()) + { + $this->isFavourite = $fav_obj->getIsFavourite($this->getUser()->getGuardUser()->getId(),$this->artwork_or_user_id,$this->type); + $username = sfGuardUserPeer::retrieveByPK($this->getRequestParameter('id')); + } else + { + $user = sfGuardUserPeer::retrieveByPK($this->artwork_or_user_id); + $username = $user->getUserName(); + } + $this->header = $this->getRequestParameter("header", null); + //$this->favouriteCount = count($this->favourites); + $this->listOwner = $username; + if ($this->type == 'artwork') + { + if (!$this->who) + { + $this->artwork = new genericArtwork($this->artwork_or_user_id); + } + } + } + + function executeListLast() + { + $this->hasMoreFavorites = true; + if (!$this->getRequest()->isXmlHttpRequest()) + { + $this->forward404(); + } + $this->who = $this->getRequestParameter('who'); + $fav_obj = new Favourite(); + if (!$this->who) + $this->favourites = $fav_obj->getLastFavs($this->getRequestParameter('type'),$this->getRequestParameter('id'),6); + else + $this->favourites = $fav_obj->getMyLastFavs($this->getRequestParameter('type'),$this->getRequestParameter('id'),6); + + + $this->type = $this->getRequestParameter('type'); + $this->artwork_or_user_id = $this->getRequestParameter('id'); + + if ($this->getUser()->isAuthenticated()) + { + $this->isFavourite = $fav_obj->getIsFavourite($this->getUser()->getGuardUser()->getId(),$this->artwork_or_user_id,$this->type); + $username = sfGuardUserPeer::retrieveByPK($this->getRequestParameter('id')); + } else + { + $this->isFavourite = false; + $user = sfGuardUserPeer::retrieveByPK($this->artwork_or_user_id); + $username = $user->getUserName(); + } + $this->listOwner = $username; + $this->header = $this->getRequestParameter("header", null); + //$this->favouriteCount = $this->getRequestParameter("favouriteCount", 0); + if (count($this->favourites) > 5) + { + array_pop($this->favourites); + $this->hasMoreFavorites = true; + } + if ($this->type == 'artwork') + { + if (!$this->who) + { + $this->artwork = new genericArtwork($this->artwork_or_user_id); + } else + { + //$this->artwork = new genericArtwork($this->artwork_or_user_id); + } + + } + } +} +?> diff --git a/apps/reaktor/modules/favourite/actions/components.class.php b/apps/reaktor/modules/favourite/actions/components.class.php new file mode 100644 index 0000000..ab0909f --- /dev/null +++ b/apps/reaktor/modules/favourite/actions/components.class.php @@ -0,0 +1,335 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +class favouriteComponents extends sfComponents +{ + /** + * Function for listing favourites, independent of types + * + * @return void + */ + function executeListFavourites() + { + $MAX = 5; // Max favorites we should fetch + $this->hasMoreFavorites = isset($this->hasMoreFavorites)?$this->hasMoreFavorites:false; // Used in the template to print "show all" + $hadNoFav = !isset($this->favourites); + + switch($this->type) + { + case 'artwork': + $fav_type = 'artwork'; + $artwork = ReaktorArtworkPeer::getArtworkById($this->artwork_or_user_id); + $artwork = array_shift($artwork); + if(count($artwork) > 0) + { + $user = sfGuardUserPeer::retrieveByPk($artwork->getUserId()); + $username = $user->getUsername(); + $this->listOwner = $username; + } + break; + case 'user': + case 'article': + $fav_type = $this->type; + + if($this->getUser()->isAuthenticated()) + { + //User is logged in, get owner from requestparameter + $username = !isset($this->listOwner)?$this->getRequestParameter('user'):$this->listOwner; + } + else + { + //User is not logged in, we get id from artwork_or_user_id, which will always be the user we're watching, except + //when deleting, but user is not logged in, and thus should never be able to delete + $user = sfGuardUserPeer::retrieveByPK($this->artwork_or_user_id); + $username = $user->getUserName(); + } + $this->listOwner = $username; + + break; + default: + if (!isset($this->listOwner)) + { + $this->listOwner = ""; + } + break; + } + + if (!isset($fav_type)) + { + throw new Exception ('Unknown favourite type'); + } + + $fav_obj = new Favourite(); + + + if (isset($this->who) && $this->who == 'Me') + { + if (!(isset($this->favourites) && $this->favourites)) + $this->favourites = $fav_obj->getMyLastFavs($fav_type,$this->artwork_or_user_id, $MAX+1); + + } + else + { + if (!(isset($this->favourites) && $this->favourites)) + { + $this->favourites = $fav_obj->getLastFavs($fav_type,$this->artwork_or_user_id, $MAX+1); + } + + } + + $this->isMyPage = false; + if ($this->getUser()->isAuthenticated()) + { + if ( isset($username) && $this->getUser()->getUsername() == $username) + { + $this->isMyPage = true; + } + $this->isFavourite = $fav_obj->getIsFavourite($this->getUser()->getGuardUser()->getId(),$this->artwork_or_user_id,$fav_type); + } + else + { + $this->isFavourite = false; + } + if ($hadNoFav && count($this->favourites) > $MAX) + { + array_pop($this->favourites); + $this->hasMoreFavorites = true; + } + } + + function executeFavouriteActions() + { + switch($this->type) + { + case 'artwork': + $fav_type = 'artwork'; + $artwork = ReaktorArtworkPeer::getArtworkById($this->artwork_or_user_id); + $artwork = array_shift($artwork); + $user = sfGuardUserPeer::retrieveByPk($artwork->getUserId()); + $username = $user->getUsername(); + + //$username = $artwork->getUser()->getUsername(); + break; + case 'user': + $fav_type = 'user'; + + if($this->getUser()->isAuthenticated()) + { + //User is logged in, get owner from requestparameter + $username = $this->getRequestParameter('user'); + } + else + { + //User is not logged in, we get id from artwork_or_user_id, which will always be the user we're watching, except + //when deleting, but user is not logged in, and thus should never be able to delete + $user = sfGuardUserPeer::retrieveByPK($this->artwork_or_user_id); + $username = $user->getUserName(); + } + $this->listOwner = $username; + + break; + default: + break; + } + + if (!isset($fav_type)) + { + throw new Exception ('Unknown favourite type'); + } + + $fav_obj = new Favourite(); + + + if (isset($this->who) && $this->who == 'Me') + { + if (!(isset($this->favourites) && $this->favourites)) + $this->favourites = $fav_obj->getMyLastFavs($fav_type,$this->artwork_or_user_id,5); + + } else + { + if (!(isset($this->favourites) && $this->favourites)) + $this->favourites = $fav_obj->getLastFavs($fav_type,$this->artwork_or_user_id,5); + + } + + + $this->isMyPage = false; + if ($this->getUser()->isAuthenticated()) + { + if ( $this->getUser()->getUsername() == $username) + { + + $this->isMyPage = true; + } + $this->isFavourite = $fav_obj->getIsFavourite($this->getUser()->getGuardUser()->getId(),$this->artwork_or_user_id,$fav_type); + + } else + { + $this->isFavourite = false; + } + } + + /** + * List users who have the artwork as a favourite, and users who have the + * owner of the artwork as a favourite + * + * @return void + */ + function executeArtworkListFavourites() + { + $this->hasMoreFavourites = false; + $orglist = isset($this->list) ? $this->list : null; + if (!isset($this->user_id)) + { + $this->user_id = 0; + } + if (!isset($this->artwork_id)) + { + $this->artwork_id = 0; + } + if (!isset($this->article_id)) + { + $this->article_id = 0; + } + + if ( + $this->getRequestParameter("module") == "profile" + && $this->getRequestParameter("action") == "portfolio" + ) + { + $this->list = 'user'; + $this->types = array('user'); + $this->showUsers = false; + $this->artwork_id = 0; + } + else + { + $this->types = array('user', 'artwork', ); + $this->showUsers = true; + } + + if ($orglist != 'article') + { + $fav_obj = array('user' => null, 'artwork' => null, 'article' => null); + $user = array('user' => null, 'artwork' => null, 'article' => null); + $username = array('user' => null, 'artwork' => null, 'article' => null); + $this->favourites = array('user' => null, 'artwork' => null, 'article' => null); + $this->isFavourite = array('user' => null, 'artwork' => null, 'article' => null); + } + else + { + $this->types = array('article'); + $fav_obj = $user = $username = $this->favourites = $this->isFavourite = array('article' => null); + } + + foreach ($this->types as $type) + { + + switch($type) + { + case 'artwork': + $artwork = ReaktorArtworkPeer::getArtworkById($this->artwork_id); + $artwork = array_shift($artwork); + if (!$artwork) { + $this->list = 'user'; + continue; + } + $user[$type] = sfGuardUserPeer::retrieveByPk($artwork->getUserId()); + $username[$type] = $user[$type]->getUsername(); + break; + case 'user': + + if($this->getUser()->isAuthenticated()) + { + //User is logged in, get owner from requestparameter + $username[$type] = $this->getRequestParameter('user'); + + } + else + { + //User is not logged in, we get id from artwork_or_user_id, which will always be the user we're watching, except + //when deleting, but user is not logged in, and thus should never be able to delete + $user[$type] = sfGuardUserPeer::retrieveByPK($this->user_id); + $username[$type] = $user[$type]->getUserName(); + } + + + break; + case 'article': + break; + default: + break; + } + $this->listOwner = $username[$type]; + $fav_obj[$type] = new Favourite(); + + + if (!(isset($this->favourites[$type]) && $this->favourites[$type])) + { + if ($type == 'artwork') + { + if ($this->all) + { + $this->favourites[$type] = $fav_obj[$type]->getLastFavs($type,$this->artwork_id,6); + } else + { + $this->favourites[$type] = $fav_obj[$type]->getLastFavs($type,$this->artwork_id,6); + if (count($this->favourites[$type]) > 5) + { + + $this->hasMoreFavourites = true; + array_pop($this->favourites[$type]); + } + } + } + elseif ($type == 'user') + { + $this->favourites[$type] = $fav_obj[$type]->getLastFavs($type,$this->user_id,5); + } + elseif ($type == 'article') + { + $this->favourites[$type] = $fav_obj[$type]->getLastFavs($type,$this->article_id, 5); + } + } + + if ($this->getUser()->isAuthenticated()) + { + if ( $this->getUser()->getUsername() != $username[$type]) + { + if ($type == 'artwork') + { + $this->isFavourite[$type] = $fav_obj[$type]->getIsFavourite($this->getUser()->getGuardUser()->getId(),$this->artwork_id,$type); + } + elseif ($type == 'user') + { + $this->isFavourite[$type] = $fav_obj[$type]->getIsFavourite($this->getUser()->getGuardUser()->getId(),$this->user_id,$type); + } + elseif ($type == 'article') + { + $this->isFavourite[$type] = $fav_obj[$type]->getIsFavourite($this->getUser()->getGuardUser()->getId(),$this->article_id,$type); + } + } + } + else + { + $this->isFavourite[$type] = false; + } + } + if ($orglist != $this->list && $orglist == 'article') + { + $this->list = $orglist; + } + + } + +} + +?> diff --git a/apps/reaktor/modules/favourite/config/security.yml b/apps/reaktor/modules/favourite/config/security.yml new file mode 100644 index 0000000..d81bd18 --- /dev/null +++ b/apps/reaktor/modules/favourite/config/security.yml @@ -0,0 +1,2 @@ +all: + is_secure: off \ No newline at end of file diff --git a/apps/reaktor/modules/favourite/templates/_artworkListFavourites.php b/apps/reaktor/modules/favourite/templates/_artworkListFavourites.php new file mode 100644 index 0000000..d7345de --- /dev/null +++ b/apps/reaktor/modules/favourite/templates/_artworkListFavourites.php @@ -0,0 +1,155 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript'); + +if (!isset($types)): + $types = array('user', 'artwork',); +endif; + +if (isset($list) && in_array($list, $types)): + $types = array($list); +endif; + +?> + +
      + + + + + +

      + + count($favourites[$type]), '%users%' => $user_string)) ?>

      +
        + + + getFavType() == 'artwork'): ?> + + getSfGuardUserRelatedByUserId()->getUsername() ?> +
      • + + getFavType() == 'article'): ?> + FIXME + getFavType() == 'user'): ?> + + getSfGuardUserRelatedByFriendId()->getUsername() ?> +
      • + + + isAuthenticated()): ?> + getSfGuardUserRelatedByFriendId()->getId() ?> + getUsername() === $listOwner): ?> + '/favourite/remove?id='.$userId.'&who=Me&both=true&artwork_id='.$artwork_id.'&user_id='.$user_id.'&type='.$type.'&user='.$listOwner, + 'update' => 'artwork_actions_and_favourites_js', + 'confirm' => __('Are you sure you want to remove this user from your list of favourite users?'), + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('highlight', 'myfavourites')));?> + + +
      • + + + + + +
      • + isAuthenticated() && !isset($who)): ?> + 'artwork_actions_and_favourites_js', + 'url' => '/favourite/listAll?id='.$artwork_or_user_id.'&both=true&artwork_id='.$artwork_id.'&user_id='.$user_id.'&type='.$type, + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('fade', 'fav_loading').visual_effect('highlight', 'favourites') + )); ?> + +
      • + + +
      • + isAuthenticated() && !isset($who)): ?> + 'artwork_actions_and_favourites_js', + 'url' => '/favourite/listLast?id='.$artwork_or_user_id.'&both=true&artwork_id='.$artwork_id.'&user_id='.$user_id.'&type='.$type, + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('fade', 'fav_loading').visual_effect('highlight', 'favourites') + )); ?> + +
      • + + +
      + + + + + + +
      + + + + + diff --git a/apps/reaktor/modules/favourite/templates/_favouriteActions.php b/apps/reaktor/modules/favourite/templates/_favouriteActions.php new file mode 100644 index 0000000..5f2afbd --- /dev/null +++ b/apps/reaktor/modules/favourite/templates/_favouriteActions.php @@ -0,0 +1,38 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +isAuthenticated() && !isset($who)): ?> +
      + + + + $type)), array( 'update' => $type.'favourites', + 'url' => '/favourite/remove?id='.$artwork_or_user_id.'&type='.$type, + 'confirm' => __('Are you sure you want to remove this from your list of favourites?'), + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('fade', 'fav_loading'). + visual_effect('highlight', 'favourites') + + )) ?>
      + + + + $type)) . "  ", array( 'update' => $type.'favourites', + 'url' => '/favourite/add?id='.$artwork_or_user_id.'&type='.$type, + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('fade', 'fav_loading'). + visual_effect('highlight', 'favourites') + )) ?>
      + + +
      + + \ No newline at end of file diff --git a/apps/reaktor/modules/favourite/templates/_listFavourites.php b/apps/reaktor/modules/favourite/templates/_listFavourites.php new file mode 100644 index 0000000..3ca4f4d --- /dev/null +++ b/apps/reaktor/modules/favourite/templates/_listFavourites.php @@ -0,0 +1,152 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?> + + +

      + + getSfGuardUserRelatedByUserId()->getUsername(); + $slug = $user. '_favourite_' . current($favourites)->getFavType(); + else: + if ($type == 'user'): + $user = current($favourites)->getSfGuardUserRelatedByFriendId()->getUsername(); + else: + $userObj = sfGuardUserPeer::retrieveByPK(current($favourites)->getUserId()); + $user = $userObj->getUsername(); + endif; + $slug = 'favourite_' . current($favourites)->getFavType(). '_' . $user; + endif; + include_partial('feed/rssLink', array('description' => isset($header) ? $header : __('Favourites'), 'slug' => $slug)); + $header = isset($header) ? $header : null; + + + ?> +
        + + + getFavType() == 'artwork' || !isset($who)): ?> + + + getReaktorArtwork()->getTitle() ?> + getReaktorArtwork()->getId() ?> + +
      • + isAuthenticated() && $sf_user->getUsername() === $favourite->getSfGuardUserRelatedByUserId()->getUsername()): ?> + '/favourite/remove?id=' .$artId. '&who=Me&type='.$type.'&user='.@$listOwner, + 'update' => $type.'myfavourites', + 'confirm' => __('Are you sure you want to remove this artwork from your list of favourite artworks?'), + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('highlight', 'myfavourites')));?> + +
      • + + + getSfGuardUserRelatedByUserId()->getUsername() ?> +
      • + + + getFavType() == "article"): ?> +
      • + getArticle()->getTitle(), $favourite->getArticle()->getLink()) ?> + + isAuthenticated() && $sf_user->getUsername() === $listOwner): ?> + '/favourite/remove?id='.$favourite->getArticleId().'&who=Me&type='.$type.'&user='.$listOwner, + 'update' => $type.'myfavourites', + 'confirm' => __('Are you sure you want to remove this article from your list af favourite articles?'), + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('highlight', 'myfavourites')));?> + +
      • + + getSfGuardUserRelatedByFriendId() ?> +
      • + getUsername(),'@portfolio?user='.$user->getUsername()); ?> + getId())): ?> + + + + isAuthenticated()): ?> + + getSfGuardUserRelatedByFriendId()->getId() ?> + + + getUsername() == $listOwner): ?> + '/favourite/remove?id='.$userId.'&who=Me&type='.$type.'&user='.$listOwner, + 'update' => $type.'myfavourites', + 'confirm' => __('Are you sure you want to remove this user from your list of favourite users?'), + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('highlight', 'myfavourites')));?> + + +
      • + + + + +
      • + + $type.'favourites', + 'url' => '/favourite/listAll?id='.$artwork_or_user_id.'&type='.$type."&header=$header", + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('fade', 'fav_loading'). + visual_effect('highlight', 'favourites') + ) + ); ?> + + $type.'myfavourites', + 'url' => '/favourite/listAll?id='.$artwork_or_user_id.'&who=Me&type='.$type."&header=$header", + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('fade', 'fav_loading'). + visual_effect('highlight', 'myfavourites') + ) + ); ?> + +
      • + + +
      • + + $type.'favourites', + 'url' => '/favourite/listLast?id='.$artwork_or_user_id.'&type='.$type."&header=$header", + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('fade', 'fav_loading'). + visual_effect('highlight', 'favourites') + ) + ); ?> + + $type.'myfavourites', + 'url' => '/favourite/listLast?id='.$artwork_or_user_id.'&who=Me&type='.$type."&header=$header", + 'loading' => visual_effect('appear', 'fav_loading'), + 'complete' => visual_effect('fade', 'fav_loading'). + visual_effect('highlight', 'myfavourites') + ) + ); ?> + +
      • + + +
      + + + + + + diff --git a/apps/reaktor/modules/favourite/templates/addSuccess.php b/apps/reaktor/modules/favourite/templates/addSuccess.php new file mode 100644 index 0000000..01136fb --- /dev/null +++ b/apps/reaktor/modules/favourite/templates/addSuccess.php @@ -0,0 +1,17 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?> + + $artwork_id, 'user_id' => $user_id, 'article_id' => $article_id, 'list' => $article_id ? "article" : null)); ?> + + $type, 'artwork_or_user_id' => $artwork_or_user_id)); ?> + diff --git a/apps/reaktor/modules/favourite/templates/listAllSuccess.php b/apps/reaktor/modules/favourite/templates/listAllSuccess.php new file mode 100644 index 0000000..a4ed2e8 --- /dev/null +++ b/apps/reaktor/modules/favourite/templates/listAllSuccess.php @@ -0,0 +1,27 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?> + + + $type, 'artwork_or_user_id' => $artwork_or_user_id,'favourites' => $favourites, 'who' => 'Me', 'header' => $header, 'listOwner' => $listOwner)); ?> + + $type, 'artwork_or_user_id' => $artwork_or_user_id,'favourites' => $favourites, 'header' => $header, 'listOwner' => $listOwner)); ?> + + + + $artwork->getId() , 'user_id' => $artwork->getUser()->getId(), 'all' => true)); ?> + + $type, 'artwork_or_user_id' => $artwork_or_user_id,'favourites' => $favourites, 'who' => 'Me', 'header' => $header, 'listOwner' => $listOwner)); ?> + + + + diff --git a/apps/reaktor/modules/favourite/templates/listLastSuccess.php b/apps/reaktor/modules/favourite/templates/listLastSuccess.php new file mode 100644 index 0000000..7d2c8d1 --- /dev/null +++ b/apps/reaktor/modules/favourite/templates/listLastSuccess.php @@ -0,0 +1,27 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?> + + + $type, 'artwork_or_user_id' => $artwork_or_user_id,'favourites' => $favourites, 'who' => 'Me', 'header' => $header, 'hasMoreFavorites' => $hasMoreFavorites, 'listOwner' => $listOwner)?> + + $type, 'artwork_or_user_id' => $artwork_or_user_id,'favourites' => $favourites, 'header' => $header, 'hasMoreFavorites' => $hasMoreFavorites, 'listOwner' => $listOwner)?> + + + + + $artwork->getId() , 'user_id' => $artwork->getUser()->getId(), 'all' => false)); ?> + + $type, 'artwork_or_user_id' => $artwork_or_user_id,'favourites' => $favourites, 'who' => 'Me', 'header' => $header, 'hasMoreFavorites' => $hasMoreFavorites, 'listOwner' => $listOwner)?> + + + diff --git a/apps/reaktor/modules/favourite/templates/removeSuccess.php b/apps/reaktor/modules/favourite/templates/removeSuccess.php new file mode 100644 index 0000000..09d3547 --- /dev/null +++ b/apps/reaktor/modules/favourite/templates/removeSuccess.php @@ -0,0 +1,23 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?> + + + $type, 'artwork_or_user_id' => $artwork_or_user_id,'favourites' => $favourites, 'who' => 'Me')?> + + $type, 'artwork_or_user_id' => $artwork_or_user_id,'favourites' => $favourites)?> + + + + $artwork_id, 'user_id' => $user_id, 'article_id' => $article_id, 'list' => $article_id ? "article" : null)); ?> + + diff --git a/apps/reaktor/modules/feed/actions/actions.class.php b/apps/reaktor/modules/feed/actions/actions.class.php new file mode 100644 index 0000000..d1af10a --- /dev/null +++ b/apps/reaktor/modules/feed/actions/actions.class.php @@ -0,0 +1,509 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * RSS feed actions class + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class feedActions extends sfActions +{ + + /** + * @var sfAtom1Feed + */ + protected $_atomFeed; + + /** + * Subreaktor object if found + * + * @var subreaktor + */ + protected $_subreaktor = null; + + /** + * LokalReaktor (subreaktor) object if found + * + * @var subreaktor + */ + protected $_lokalReaktor = null; + + /** + * Extra title information for subreaktors + * + * @var string + */ + protected $_subreaktorTitle = ''; + + /** + * Pre execute tasks - using this to make sure all the following actions use + * the same template unless specified otherwise. + * + * @return null executes tasks before actions + */ + public function preExecute() + { + sfConfig::set('sf_web_debug', false); + + $this->setTemplate('feed'); + $this->_atomFeed = new sfAtom1Feed(); + + $this->_atomFeed->initialize(array( + 'authorEmail' => sfConfig::get('app_rss_email'), + 'authorName' => sfConfig::get('app_rss_authorname'), + 'feedUrl' => $this->getContext()->getRequest()->getUri(), + )); + + // These should be null if none provided, which works for the following queries + $this->_lokalReaktor = Subreaktor::getProvidedLokalReference(); + $this->_subreaktor = Subreaktor::getProvidedSubreaktorReference(); + + // Add subreaktor info to title + if ($this->_lokalReaktor && $this->_subreaktor) + { + $this->_subreaktorTitle = ' in '.$this->_lokalReaktor.' ('.$this->_subreaktor.')'; + } + elseif ($this->_lokalReaktor) + { + $this->_subreaktorTitle = ' in '.$this->_lokalReaktor; + } + elseif ($this->_subreaktor) + { + $this->_subreaktorTitle = ' in '.$this->_subreaktor; + } + + } + + /** + * Executes main feed action for artwork feeds + * + * @return void Renders the feedsuccess template + */ + public function executeArtworkFeed() + { + $custom = array(); + + $c = new Criteria(); + $limit = sfConfig::get('app_rss_artwork_items', 5); + $c->setLimit($limit); + + $route = '@show_artwork'; // Use the show_artwork route by default + $link = ''; //Use home URL by default + $slug = $this->getRequestParameter('slug'); + + // Check for special feeds (like tags) + if (strpos($slug, 'tagged_with') !== false || strpos($slug, 'in_category') !== false || strpos($slug, 'users_by') !== false) + { + $slugArray = explode("_", $slug); + if ($slugArray[0] == 'articles') + { + $article = true; + array_shift($slugArray); + } + else + { + $article = false; + } + $slug = array_shift($slugArray).'_'.array_shift($slugArray); + $params = $slugArray; + } + + switch($slug) + { + case 'latest_artworks': + + $title = 'latest artworks'; + //Should use the exact same query as the original list + $entries = ReaktorArtworkPeer::getLatestSubmittedApproved($limit, null, null, $this->_subreaktor, $this->_lokalReaktor); + break; + + case 'latest_comments': + + $title = sfContext::getInstance()->getI18N()->__('latest comments'); + $entries = sfComment::getReaktorsLatestComments($this->_subreaktor, $limit, $this->_lokalReaktor); + break; + + case 'latest_commented': + + $title = sfContext::getInstance()->getI18N()->__('latest commented'); + $entries = ReaktorArtworkPeer::getLatestCommented($limit); + break; + + case 'latest_users': + + $route = '@portfolio'; + $title = sfContext::getInstance()->getI18N()->__('latest users'); + $entries = sfGuardUserPeer::getLastUsers($limit, false, $this->_subreaktor, $this->_lokalReaktor); + break; + + case 'most_popular': + $title = sfContext::getInstance()->getI18N()->__('most popular'); + $entries = ReaktorArtworkPeer::mostPopularArtworks($this->_subreaktor, $limit, $this->_lokalReaktor); + break; + + case 'tagged_with': + $entries = array(); + $result = TagPeer::getObjectsTaggedWith($params, array('parent_approved' => true, 'approved' => true)); + if ($article) + { + $route = '@article'; + foreach($result as $entry) + { + // Filter out not-articles and internals articles + if (!($entry instanceof Article) || $entry->getArticleType() == ArticlePeer::INTERNAL_ARTICLE) + { + continue; + } + $entries[] = $entry; + } + } + // Not article.. + else + { + $route = '@show_artwork'; + // If it is an reaktorFile then we want the artworks it belongs to, + // not the file it self + foreach($result as $entry) + { + if ($entry instanceof reaktorFile) + { + foreach($entry->getParentArtworks() as $artwork) + { + $entries[] = $artwork; + } + } + else + { + $entries[] = $entry; + } + } + } + $title = sfContext::getInstance()->getI18N()->__('Tagged with %tags%', array('%tags%' => implode(', ', $params))); + break; + + case 'in_category': + $entries = CategoryArtworkPeer::getArtworksInCategory($params[0]); + $title = sfContext::getInstance()->getI18N()->__('Tagged with %tags%', array('%tags%' => implode(', ', $params))); + $route = '@show_artwork'; + break; + + case 'users_by': + $entries = sfGuardUserPeer::getUsernamesStartingWith($params[0]); + $title = sfContext::getInstance()->getI18N()->__('users starting with %char%', array('%char%' => $params[0])); + $route = '@portfolio'; + break; + + case 'recommended_artwork': + $title = sfContext::getInstance()->getI18N()->__('Recommended'); + $entries = array(); + $lid = $this->_lokalReaktor ? Subreaktor::getProvidedLokalreaktor()->getId() : null; + $sid = $this->_subreaktor ? Subreaktor::getProvidedSubreaktor()->getId() : null; + + if ($this->_lokalReaktor) + { + $tentries = RecommendedArtworkPeer::getRecommendedArtwork($lid, $sid, true, $limit); + } + elseif ($this->_subreaktor) + { + $tentries = RecommendedArtworkPeer::getRecommendedArtwork($sid, null, true, $limit); + } + else + { + $tentries = RecommendedArtworkPeer::getRecommendedArtwork(null, null, true, $limit); + } + + foreach($tentries as $entry) + { + $entries[] = new genericArtwork($entry->getArtwork()); + } + break; + + } + + /* Unable to create static link names, have to parse the type from the url */ + switch(substr_count($slug, "_")) { + // popular_subreaktor, i.e popular_foto + case 1: + list ($popular, $ssubreaktor) = explode("_", $slug, 2); + try { + $subreaktor = Subreaktor::getByReference($ssubreaktor); + $title = sfContext::getInstance()->getI18N()->__($slug); + $entries = ReaktorArtworkPeer::mostPopularArtworks($subreaktor, $limit, $this->_lokalReaktor); + } catch(Exception $e) { + } + break; + + /* [username_][favourite/latest][_module][_username], examples: + * monkeyboy_favourite_user // monkeyboys favourite users + * monkeyboy_favourite_artworks // monkeyboys favourite artworks + * favorite_user_monkeyboy // users who are favourite with monkeyboy + * + * monkeyboy_latest_commented // Last commented monkeyboys artworks + */ + case 2: + list ($username, $str, $module) = explode("_", $slug, 3); + $fav_obj = new Favourite(); + + switch($module) + { + case "comments": + switch($str) + { + case "written": + $title = sprintf("%ss latest comments", $username); + $entries = sfComment::getLatestWrittenComments(sfGuardUserPeer::getByUsername($username)->getId()); + break; + case "received": + $title = sprintf("%ss recently received comments", $username); + $entries = sfComment::getLatestReceivedComments(sfGuardUserPeer::getByUsername($username)->getId()); + break; + } + break; + + case "commented": + $title = sprintf("%ss latest commented artworks", $username); + $entries = sfComment::getLatestCommented(sfGuardUserPeer::getByUsername($username)->getId()); + break; + + case "artwork": + case "article": + case "user": + $user = sfGuardUserPeer::getByUsername($username); + + $title = sprintf("%ss favourite %ss", $user->getUsername(), $module); + $entries = $fav_obj->getMyLastFavs($module, $user->getId(), $limit); + + if ($module == "artwork") + { + $route = '@show_artwork'; + $custom["link"] = "getArtworkLink"; + } + elseif ($module == "user") + { + $route = '@portfolio'; + } + elseif ($module == 'article') + { + $route = '@article'; + } + break; + + default: + // Twisted logic. Users who have marked "monkeyboy" as favourite + if ($username != "favourite") + { + break; + } + + $username = $module; + $module = $str; + $route = '@portfolio'; + $user = sfGuardUserPeer::getByUsername($username); + $title = sprintf("%s favourite with", $user->getUsername()); + $entries = $fav_obj->getLastFavs($module, $user->getId(), $limit); + break; + } + break; + + } + + if (!isset($entries)) + { + $this->redirect404(); + } + + if (($route == '@show_artwork' || $route == '@article' || $route == '@show_artwork_file') && strpos($slug, "comment") === false) + { + $custom["title"] = 'getCustomFeedTitle'; + if ($route == "@article") { + $custom["link"] = "getFeedPermalink"; + } + } + + if (Subreaktor::isProvided()) + { + $route = str_replace('@', '@subreaktor', $route); + } + + $this->_atomFeed->setLink($link); + $this->_atomFeed->setTitle(sfConfig::get('app_rss_title').' - '.$title.$this->_subreaktorTitle); + $resultItems = sfFeedPeer::convertObjectsToItems($entries, array('routeName' => $route, 'methods' => $custom)); + + $this->_atomFeed->addItems($resultItems); + + $this->feed = $this->_atomFeed; + } + + public function executeFileFeed() + { + $artwork = new genericArtwork($this->getRequestParameter('id')); + $title = $artwork->getTitle(); + $entries = $artwork->getFiles(); + $this->_atomFeed->setTitle(sfConfig::get('app_rss_title').' - '.$title.$this->_subreaktorTitle); + $resultItems = sfFeedPeer::convertObjectsToItems($entries); + + $this->_atomFeed->addItems($resultItems); + + $this->feed = $this->_atomFeed; + + } + /** + * Template for displaying a list of RSS feeds which are available around the site + * + * @return null Just process the template + */ + public function executeList() + { + $this->setTemplate('list'); + } + + public function executeUserFeed() + { + $limit = sfConfig::get('app_rss_artwork_items', 5); + $slug = $this->getRequestParameter('slug'); + $username = $this->getRequestParameter('username'); + $route = '@portfolio'; + + switch($slug) + { + case 'shared_interest': + $title = sfContext::getInstance()->getI18N()->__('shared interest'); + $user = sfGuardUserPeer::getByUsername($username); + if (!$user) { + break; + } + $entries = sfGuardUserPeer::getUsersByMatchingInterests($user->getId(), $limit); + break; + case 'all': + $max = $this->getRequestParameter("max", 5); + if ($max == 0) + { + $max = PHP_INT_MAX; + } + + $title = sfContext::getInstance()->getI18N()->__('All artworks'); + $user = sfGuardUserPeer::getByUsername($username); + $route = '@show_artwork'; + $entries = ReaktorArtworkPeer::getLatestSubmittedApprovedNotPaginated($max, $user->getId()); + + break; + /* $slug === subreaktor-reference */ + default: + $sub = SubreaktorPeer::retrieveByReference($slug); + if (!$sub) + { + break; + } + + $user = sfGuardUserPeer::getByUsername($username); + if (!$user) + { + break; + } + + $max = $this->getRequestParameter("max", 5); + if ($max == 0) + { + $max = PHP_INT_MAX; + } + + $entries = ReaktorArtworkPeer::getLatestSubmittedApprovedNotPaginated($max, $user->getId(), $sub->getId()); + $route = '@show_artwork'; + $title = $sub->getName(); + break; + } + + $c = new Criteria(); + $c->setLimit($limit); + + if (!isset($entries)) + { + $this->redirect404(); + } + + $this->_atomFeed->setTitle(sfConfig::get('app_rss_title').' - ' . $username. ' ' .$title); + $resultItems = sfFeedPeer::convertObjectsToItems($entries, array('routeName' => $route)); + + $this->_atomFeed->addItems($resultItems); + + $this->feed = $this->_atomFeed; + } + + public function executeAdminFeed() + { + $slug = $this->getRequestParameter('slug'); + $limit = $this->getRequestParameter('limit'); + + if ($limit < 1) + { + if ($limit == -1) + { + $limit = PHP_INT_MAX; + } + else + { + $limit = 5; + } + } + if ($limit > 10 && !($this->getUser()->isAuthenticated() && $this->getUser()->hasCredential('staff'))) + { + $limit = 5; + } + + switch($slug) + { + case "users": + $route = '@portfolio'; + $title = sfContext::getInstance()->getI18N()->__('latest users'); + $entries = sfGuardUserPeer::getLastUsers($limit, false, null, null); + break; + + case "random_artwork": + $random = true; + $title = sfContext::getInstance()->getI18N()->__('random artworks'); + case "artworks": + $route = '@show_artwork'; + if (!isset($random)) + { + $random = false; + $title = sfContext::getInstance()->getI18N()->__('latest artworks'); + } + $entries = ReaktorArtworkPeer::getLatestSubmittedApproved($limit, null, $random, $this->_subreaktor, $this->_lokalReaktor); + break; + + default: + $this->forward404(); + break; + } + + $this->_atomFeed->setTitle(sfConfig::get('app_rss_title').' - '.$title.$this->_subreaktorTitle); + $result = sfFeedPeer::convertObjectsToItems($entries, array('routeName' => $route)); + $this->_atomFeed->addItems($result); + $this->feed = $this->_atomFeed; + } + + /** + * This module has no index, forward all /index requests to 404 + * + * @return void + */ + public function executeIndex() + { + $this->forward404(); + } +} + diff --git a/apps/reaktor/modules/feed/actions/components.class.php b/apps/reaktor/modules/feed/actions/components.class.php new file mode 100644 index 0000000..89a9bda --- /dev/null +++ b/apps/reaktor/modules/feed/actions/components.class.php @@ -0,0 +1,53 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * RSS feed components class + * + * PHP Version 5 + * + * @author Daniel Andre Eikeland + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class feedComponents extends sfComponents +{ + + public function executeForeignReader() + { + $this->feederror = null; + if ($this->feedurl) + { + $timeout = $this->timeout?$this->timeout:1; + + try + { + $feed = sfFeedPeer::createFromWeb($this->feedurl,array('adapter' => 'sfFopenAdapter', 'adapter_options' => array('timeout' => $timeout))); + $this->items = (isset($this->items)) ? $this->items : 5; + $this->feedtitle = (isset($this->title)) ? $this->title : ''; + $this->feedstyle = (isset($this->source)) ? $this->source : 'normal'; + $this->ingresslength = (isset($this->ingresslength)) ? $this->ingresslength : 80; + $this->showreadmore = (isset($this->showreadmore)) ? $this->showreadmore : true; + $this->headerlink = (isset($this->headerlink)) ? $this->headerlink : false; + $this->feed = $feed; + $this->feedcount = 0; + } + catch (Exception $e) + { + $this->feederror = $e->getMessage(); + return sfView::NONE; + } + } + } + +} diff --git a/apps/reaktor/modules/feed/config/security.yml b/apps/reaktor/modules/feed/config/security.yml new file mode 100644 index 0000000..19e03c5 --- /dev/null +++ b/apps/reaktor/modules/feed/config/security.yml @@ -0,0 +1,2 @@ +all: + is_secure: no \ No newline at end of file diff --git a/apps/reaktor/modules/feed/templates/_foreignReader.php b/apps/reaktor/modules/feed/templates/_foreignReader.php new file mode 100644 index 0000000..d975071 --- /dev/null +++ b/apps/reaktor/modules/feed/templates/_foreignReader.php @@ -0,0 +1,53 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + +
      +
        + +
      • + +
      • + + +
      • + + getItems() as $item): ?> + +
      • + +
        getTitle(); ?>
        + + getTitle() ?>
        + + getDescription()) > $ingresslength) ? substr($item->getDescription(), 0, ($ingresslength - 3)) . '[...] ' : $item->getDescription() . ' '; ?> + + + +
      • + = $items): ?> + + + + +
      +
      \ No newline at end of file diff --git a/apps/reaktor/modules/feed/templates/_rssLink.php b/apps/reaktor/modules/feed/templates/_rssLink.php new file mode 100644 index 0000000..418f4aa --- /dev/null +++ b/apps/reaktor/modules/feed/templates/_rssLink.php @@ -0,0 +1,70 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +$class = isset($class) ? $class : 'rss_link_top_right'; +$route = isset($route) ? $route : 'artworkfeed'; +$description = isset($description) ? $description : __('this list'); +$url = isset($url) ? $url : null; +$caption = isset($caption) ? $caption : ''; +$route .= strpos($route, "?") !== false ? "&slug=$slug" : "?slug=$slug"; + +$tip = '
      '.__('Subscribe to %rss_description%', array('%rss_description%' => $description)).'
      '; + +$rss_headers = $sf_request->getAttribute('rss_head_meta', array()); +$rss_headers[$slug]['title'] = $description; +$newId = md5(microtime().$class.$route); + +use_helper("Javascript"); + +?> + + +setAttribute('rss_head_meta', $rss_headers); ?> + + \ No newline at end of file diff --git a/apps/reaktor/modules/feed/templates/feedSuccess.php b/apps/reaktor/modules/feed/templates/feedSuccess.php new file mode 100644 index 0000000..5b608b4 --- /dev/null +++ b/apps/reaktor/modules/feed/templates/feedSuccess.php @@ -0,0 +1,19 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +decorate_with(false); +echo $feed->asXml(); diff --git a/apps/reaktor/modules/feed/templates/listSuccess.php b/apps/reaktor/modules/feed/templates/listSuccess.php new file mode 100644 index 0000000..42c05c8 --- /dev/null +++ b/apps/reaktor/modules/feed/templates/listSuccess.php @@ -0,0 +1,60 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +$feeds = array( + array("route" => "artworkfeed", "slug" => "latest_artworks" , "description" => __("Recently approved artwork")), + array("route" => "artworkfeed", "slug" => "most_popular" , "description" => __("Most popular")), + //array("route" => "artworkfeed", "slug" => "latest_users" , "description" => __("Latest registered users")), + array("route" => "artworkfeed", "slug" => "latest_commented", "description" => __("Latest commented artwork")), + array("route" => "artworkfeed", "slug" => "recommended_artwork" , "description" => __("Recommended artwork")) +); +?> +

      +getReference() . "-"; + echo __("Subscribe to Reaktor RSS feeds in %LokalReaktor%", array("%LokalReaktor%" => Subreaktor::getProvidedLokalreaktor()->getName())); +} +else +{ + echo __("Subscribe to Reaktor RSS feeds"); +} +?> +

      + +
      + + isLokalReaktor()) continue; ?> + getLive()) continue; ?> +

      +
        + + getReference(); ?> +
      • + + + +
      + + +setAttribute('rss_head_meta', $rss_headers); ?> + diff --git a/apps/reaktor/modules/filelist/actions/actions.class.php b/apps/reaktor/modules/filelist/actions/actions.class.php new file mode 100644 index 0000000..26792aa --- /dev/null +++ b/apps/reaktor/modules/filelist/actions/actions.class.php @@ -0,0 +1,44 @@ + + * @version SVN: $Id: actions.class.php 2692 2006-11-15 21:03:55Z fabien $ + */ +class filelistActions extends sfActions +{ + /** + * Executes index action + * + */ + public function executeIndex() + { + $this->forward('default', 'module'); + } + + public function executeBrowseFiles() + { + $article = ArticlePeer::retrieveByPK($this->getRequestParameter("article_id")); + $this->forward404Unless($article); + + $tfiles = ArticleFilePeer::getAll(); + $files = array(); + foreach($tfiles as $file) + { + $fn = $file->getFilename(); + if (!$fn) + { + continue; + } + + $files[$file->getId()] = $file; + } + $this->files = $files; + $this->article = $article; + } + +} + diff --git a/apps/reaktor/modules/filelist/actions/components.class.php b/apps/reaktor/modules/filelist/actions/components.class.php new file mode 100644 index 0000000..e69de29 diff --git a/apps/reaktor/modules/filelist/templates/browseFilesSuccess.php b/apps/reaktor/modules/filelist/templates/browseFilesSuccess.php new file mode 100644 index 0000000..77dfd44 --- /dev/null +++ b/apps/reaktor/modules/filelist/templates/browseFilesSuccess.php @@ -0,0 +1,119 @@ + + + + + + Browse/upload attachments + + + + + + + + + + + + + + +

      + +
      +

      +
        + + $file): ?> + getArticletype()==2){ + $attach = "[".link_to_remote(__("Attach"), array("url" => "@article_attach?article_id=" .$article->getId(). "&file_id=" . $id, "complete" => "UploadDialog.close()"))."]"; +// }else { +// $attach= ""; +// } +?> + getDirectLink().'\'));UploadDialog.close()">'.__("Insert into the article").''; ?> +
      • []
      • + +
      + + +
      + +

      +getId(), array( + "multipart" => "true", + "name" => "image_upload_form", +# "onsubmit" => "return AIM.submit(this, {'onStart' : UploadDialog.startcb, 'onComplete' : UploadDialog.completecb })" +) +); ?> + +
      + + + "newfilebutton", + "onclick" => "if($('file').value=='') + { alert('".__('Please choose a file first')."');return false; }" )) + ?> +
      + + +
      + + + + diff --git a/apps/reaktor/modules/filelist/templates/indexSuccess.php b/apps/reaktor/modules/filelist/templates/indexSuccess.php new file mode 100644 index 0000000..d37b238 --- /dev/null +++ b/apps/reaktor/modules/filelist/templates/indexSuccess.php @@ -0,0 +1 @@ +This is a browsing plugin diff --git a/apps/reaktor/modules/home/actions/actions.class.php b/apps/reaktor/modules/home/actions/actions.class.php new file mode 100644 index 0000000..41309a4 --- /dev/null +++ b/apps/reaktor/modules/home/actions/actions.class.php @@ -0,0 +1,68 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * The main class for the home module + * + * This is currently the default class that is loaded when a user + * navigates to the site root as defined in the routing.yml file + * + * PHP version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class homeActions extends sfActions +{ + /** + * Executes index action, since there is nothing here at the moment + * templates/indexSuccess.php would be processed + * + * @return void + * + */ + public function executeIndex() + { + $this->setFlash('subreaktor', '', true); + $limit = sfConfig::get('app_home_list_length', 5); + $this->last = ReaktorArtworkPeer::getLatestSubmittedApproved($limit+1); + } + + /** + * Execute phpinfo template + * + * @return void + * + */ + public function executePhpinfo() + { + $this->forward404Unless($this->getUser()->hasCredential("mustbeasuperadmin")); + } + + /** + * Execute error404 template + * + * @return void + * + */ + public function executeError404() + { + // Lets check if a user is trying to access a i18n page without the correct URL + if (!$this->getRequestParameter("sf_culture") && isset($_SERVER['REDIRECT_URL'])) + { + $this->redirect($_SERVER['REDIRECT_URL']); + } + } +} diff --git a/apps/reaktor/modules/home/config/security.yml b/apps/reaktor/modules/home/config/security.yml new file mode 100644 index 0000000..36c471e --- /dev/null +++ b/apps/reaktor/modules/home/config/security.yml @@ -0,0 +1,7 @@ +#All users should be able to view front page +all: + is_secure: off + +adminfunctions: + is_secure: on + credentials: adminfunctions \ No newline at end of file diff --git a/apps/reaktor/modules/home/config/view.yml b/apps/reaktor/modules/home/config/view.yml new file mode 100644 index 0000000..f3b2189 --- /dev/null +++ b/apps/reaktor/modules/home/config/view.yml @@ -0,0 +1,2 @@ +phpinfoSuccess: + layout: emptyLayout \ No newline at end of file diff --git a/apps/reaktor/modules/home/templates/error404Success.php b/apps/reaktor/modules/home/templates/error404Success.php new file mode 100644 index 0000000..9deb0a6 --- /dev/null +++ b/apps/reaktor/modules/home/templates/error404Success.php @@ -0,0 +1,21 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('Not found')); + +?> + +
      +

      +

      +

      +
      \ No newline at end of file diff --git a/apps/reaktor/modules/home/templates/indexSuccess.php b/apps/reaktor/modules/home/templates/indexSuccess.php new file mode 100644 index 0000000..9a6bff0 --- /dev/null +++ b/apps/reaktor/modules/home/templates/indexSuccess.php @@ -0,0 +1,109 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__('Homepage')); +use_helper('home', 'content'); + +?> + +
      +
      +
      +

      + +
      + + + +
      + +

      + 'thumb', + 'limit' => 1, + 'cache' => 'sub' .Subreaktor::getProvidedSubreaktorReference() . 'lok' .Subreaktor::getProvidedLokalReference(), +// Ticket 25288 ? +'last' => array(array_shift($last)), +// 'last' => $last, + )); ?> +
      +
      +
      + +
      +
      +

      + +
      +
      +

      + $sf_user->getCulture(), + 'last' => $last, + )) ?> +
      +
      +
      + + +
      +
      +

      + Subreaktor::getByReference('foto'), + 'feed_slug' => 'popular_foto', + 'feed_description' => "top photos" + )); ?> + +
      + +
      +

      + +
      +
      +
      + +
      + getViewCacheManager()->addCache( + "artwork", '_lastArtworks', array('withLayout' => false, 'lifeTime' => -1, 'clientLifeTime' => 86400, 'contextual' => false, 'vary' => array ()) + ); + } + include_component('artwork', 'lastArtworks', array( + 'image' => 'mini', + 'limit' => 6, + 'random'=> true, + )) ?> +
      +
      + + +
      + diff --git a/apps/reaktor/modules/home/templates/phpinfoSuccess.php b/apps/reaktor/modules/home/templates/phpinfoSuccess.php new file mode 100644 index 0000000..52ceb34 --- /dev/null +++ b/apps/reaktor/modules/home/templates/phpinfoSuccess.php @@ -0,0 +1,13 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +phpinfo(); \ No newline at end of file diff --git a/apps/reaktor/modules/mail/actions/actions.class.php b/apps/reaktor/modules/mail/actions/actions.class.php new file mode 100644 index 0000000..d9fc612 --- /dev/null +++ b/apps/reaktor/modules/mail/actions/actions.class.php @@ -0,0 +1,152 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version SVN: $Id: actions.class.php 2561 2008-09-18 09:47:23Z bjori $ + */ + +/** + * Mail actions. + * + * PHP Version 5 + * + * @author Kjell-Magne Oierud + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class mailActions extends sfActions +{ + public function preExecute() + { + $this->mail = new sfMail(); + $this->mail->setCharset('utf-8'); + + $this->fromMail = sfConfig::get('app_artwork_sender_email'); + $this->fromName = sfConfig::get('app_artwork_sender'); + + $this->mail->setSender($this->fromMail, $this->fromName); + $this->mail->setFrom($this->fromMail, $this->fromName); + $this->mail->addReplyTo(sfConfig::get('app_artwork_sender_email')); + + } + + /** + * Sends an email notifiying the artwork creator that a comment to + * one of her artworks has been posted. + * + * Assumes that the global variable mail_data is set and contains + * artwork and comment objects. + * + * @return void + */ + public function executeSendCommentNotification() + { + global $mail_data; + + $this->comment = $mail_data['comment']; + $this->artwork = $mail_data['artwork']; + $this->parent = $mail_data['parent']; + + + // FIX why doesn't $this->artwork->getUser() work? + $au = sfGuardUserPeer::retrieveByPk($this->parent->getAuthorId()); + $this->mail->addAddress($au->getEmail()); + + + } + + /** + * Sends an email notifiication to new users + * @return void + */ + public function executeSendActivationEmail() + { + global $mail_data; + + $this->user = $mail_data['user']; + $this->url = '@activate?key='.$this->user->getSalt(); + + $this->mail->addAddress($mail_data['user']->getEmail()); + + } + + public function executeSendProfileRegisteredByAdmin() + { + global $mail_data; + + $this->user = $mail_data['user']; + $this->password = $mail_data['password']; + $this->mail->addAddress($mail_data['user']->getEmail()); + + + } + + public function executeSendNewEmailActivation() + { + global $mail_data; + + $this->mail->addAddress($mail_data['user']->getNewEmail()); + $this->url = '@changeemail?key='.$mail_data['salt'].'&new_email_key='.$mail_data['newEmailKey']; + $this->oldemail = $mail_data['user']->getEmail(); + $this->newemail = $mail_data['user']->getNewEmail(); + + } + + public function executeSendNewEmailActivationNotification() + { + global $mail_data; + + $this->mail->addAddress($mail_data['user']->getEmail()); + $this->url = '@changeemail?key='.$mail_data['salt'].'&new_email_key='.$mail_data['newEmailKey']; + $this->oldemail = $mail_data['user']->getEmail(); + $this->newemail = $mail_data['user']->getNewEmail(); + + } + + public function executeEditorialTeamNotification() + { + global $mail_data; + + foreach ($mail_data['users'] as $user) + { + + $this->mail->addAddress($user->getsfGuardUser()->getEmail()); + } + //$this->mail->addAddress($mail_data['user']->getEmail()); + //$this->mail->addAddress($mail_data['user']->getNewEmail()); + //$this->url = '@changeemail?key='.$mail_data['salt'].'&new_email_key='.$mail_data['newEmailKey']; + + } + + public function executeSendPasswordEmail() + { + $this->to = $this->getRequestParameter('toemail'); + $this->newpassKey = stringMagick::generateSalt(); + + $user = sfGuardUserPeer::retrieveByEmail($this->to); + $this->username = $user->getUsername(); + + $user->setNewPasswordKey($this->newpassKey); + $user->setKeyExpires("+1 day"); + $user->save(); + + $this->mail->addAddress($this->to); + } + + public function executeSendRejectArtworkOrFile() + { + $this->rejectionmsg = $this->getRequestParameter('rejectionmsg'); + + $this->mail->addAddress($this->getRequestParameter('to')); + $this->mail->addCC($this->getRequestParameter('cc')); + $this->mail->setSubject($this->getRequestParameter('subject')); + } + +} + + diff --git a/apps/reaktor/modules/mail/config/mailer.yml b/apps/reaktor/modules/mail/config/mailer.yml new file mode 100644 index 0000000..9040f67 --- /dev/null +++ b/apps/reaktor/modules/mail/config/mailer.yml @@ -0,0 +1,5 @@ +dev: + deliver: off + +all: + mailer: sendmail diff --git a/apps/reaktor/modules/mail/config/security.yml b/apps/reaktor/modules/mail/config/security.yml new file mode 100644 index 0000000..225dd93 --- /dev/null +++ b/apps/reaktor/modules/mail/config/security.yml @@ -0,0 +1,2 @@ +default: + is_secure: off diff --git a/apps/reaktor/modules/mail/templates/editorialTeamNotificationSuccess.altbody.php b/apps/reaktor/modules/mail/templates/editorialTeamNotificationSuccess.altbody.php new file mode 100644 index 0000000..2f37151 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/editorialTeamNotificationSuccess.altbody.php @@ -0,0 +1,5 @@ +setSubject(__('A new artwork has been submitted')) ?> + + $sf_request->getHost() , +)) ?> diff --git a/apps/reaktor/modules/mail/templates/editorialTeamNotificationSuccess.php b/apps/reaktor/modules/mail/templates/editorialTeamNotificationSuccess.php new file mode 100644 index 0000000..502b0dd --- /dev/null +++ b/apps/reaktor/modules/mail/templates/editorialTeamNotificationSuccess.php @@ -0,0 +1,5 @@ +setSubject(__('A new artwork has been submitted')) ?> + + $sf_request->getHost() , +)) ?> diff --git a/apps/reaktor/modules/mail/templates/sendActivationEmailSuccess.altbody.php b/apps/reaktor/modules/mail/templates/sendActivationEmailSuccess.altbody.php new file mode 100644 index 0000000..84b5ab8 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendActivationEmailSuccess.altbody.php @@ -0,0 +1,6 @@ +setSubject(__('Your Reaktor useraccount: ') . $user->getUsername()) ?> + + "http://".$sf_request->getHost().url_for($url), + "%username%" => $user->getUsername(), +)) ?> diff --git a/apps/reaktor/modules/mail/templates/sendActivationEmailSuccess.php b/apps/reaktor/modules/mail/templates/sendActivationEmailSuccess.php new file mode 100644 index 0000000..80fb920 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendActivationEmailSuccess.php @@ -0,0 +1,8 @@ +setSubject(__('Your Reaktor useraccount: ') . $user->getUsername()) ?> + + "http://".$sf_request->getHost().url_for($url), + "%username%" => $user->getUsername(), +)) ?> + + diff --git a/apps/reaktor/modules/mail/templates/sendCommentNotificationSuccess.altbody.php b/apps/reaktor/modules/mail/templates/sendCommentNotificationSuccess.altbody.php new file mode 100644 index 0000000..af76076 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendCommentNotificationSuccess.altbody.php @@ -0,0 +1,9 @@ +setSubject(__('Notice: Your comment was replied to')) ?> + + $artwork->getTitle(), + "%commenter%" => $comment->getsfGuardUser()->getUsername(), + "%comment_title%" => $comment->getTitle(), + "%comment%" => $comment->getText(), + "%url_comment%" => url_for("@show_artwork?id=".$artwork->getId()."&title=".$artwork->getTitle()."#message_".$comment->getId(), true), +)) ?> diff --git a/apps/reaktor/modules/mail/templates/sendCommentNotificationSuccess.php b/apps/reaktor/modules/mail/templates/sendCommentNotificationSuccess.php new file mode 100644 index 0000000..4b1bd2a --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendCommentNotificationSuccess.php @@ -0,0 +1,9 @@ +setSubject(__('Notice: Your comment was replied to')) ?> + + $artwork->getTitle(), + "%commenter%" => $comment->getsfGuardUser()->getUsername(), + "%comment_title%" => $comment->getTitle(), + "%comment%" => $comment->getText(), + "%url_comment%" => url_for("@show_artwork?id=".$artwork->getId()."&title=".$artwork->getTitle()."#message_".$comment->getId(), true), +)) ?> diff --git a/apps/reaktor/modules/mail/templates/sendNewEmailActivationNotificationSuccess.altbody.php b/apps/reaktor/modules/mail/templates/sendNewEmailActivationNotificationSuccess.altbody.php new file mode 100644 index 0000000..6d2bea6 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendNewEmailActivationNotificationSuccess.altbody.php @@ -0,0 +1,6 @@ +setSubject(__('Changed email on your reaktor account')) ?> + $oldemail, + "%newemail%" => $newemail, + "%username%" => $sf_user->getUsername(), +)) ?> diff --git a/apps/reaktor/modules/mail/templates/sendNewEmailActivationNotificationSuccess.php b/apps/reaktor/modules/mail/templates/sendNewEmailActivationNotificationSuccess.php new file mode 100644 index 0000000..0ca32e2 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendNewEmailActivationNotificationSuccess.php @@ -0,0 +1,8 @@ +setSubject(__('Changed email on your reaktor account')) ?> + $oldemail, + "%newemail%" => $newemail, + "%username%" => $sf_user->getUsername(), +)) ?> + + diff --git a/apps/reaktor/modules/mail/templates/sendNewEmailActivationSuccess.altbody.php b/apps/reaktor/modules/mail/templates/sendNewEmailActivationSuccess.altbody.php new file mode 100644 index 0000000..466fe18 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendNewEmailActivationSuccess.altbody.php @@ -0,0 +1,8 @@ +setSubject(__('Changed email on your reaktor account')) ?> + $oldemail, + "%newemail%" => $newemail, + "%username%" => $sf_user->getUsername(), + "%verifylink%" => "http://".$sf_request->getHost().url_for($url), +)); ?> + diff --git a/apps/reaktor/modules/mail/templates/sendNewEmailActivationSuccess.php b/apps/reaktor/modules/mail/templates/sendNewEmailActivationSuccess.php new file mode 100644 index 0000000..ad5677f --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendNewEmailActivationSuccess.php @@ -0,0 +1,9 @@ +setSubject(__('Changed email on your reaktor account %oldemail% %newemail%')) ?> + $oldemail, + "%newemail%" => $newemail, + "%username%" => $sf_user->getUsername(), + "%verifylink%" => "http://".$sf_request->getHost().url_for($url), +)); ?> + + diff --git a/apps/reaktor/modules/mail/templates/sendPasswordEmailSuccess.altbody.php b/apps/reaktor/modules/mail/templates/sendPasswordEmailSuccess.altbody.php new file mode 100644 index 0000000..0024992 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendPasswordEmailSuccess.altbody.php @@ -0,0 +1,8 @@ +setSubject(__("Password request for your reaktor account, %%username%%.", array("%%username%%" => $username))); ?> + + url_for('@changepassword?username=' .$username. '&key=' . $newpassKey, array("absolute" => true)), + "%username%" => $username, + "%fromname%" => $fromName, + "%frommail%" => $fromMail, +)) ?> \ No newline at end of file diff --git a/apps/reaktor/modules/mail/templates/sendPasswordEmailSuccess.php b/apps/reaktor/modules/mail/templates/sendPasswordEmailSuccess.php new file mode 100644 index 0000000..d9277cf --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendPasswordEmailSuccess.php @@ -0,0 +1,8 @@ +setSubject(__("Password request for your reaktor account, %%username%%.", array("%%username%%" => $username))); ?> + + link_to("", '@changepassword?username=' .$username. '&key=' . $newpassKey, array("absolute" => true)), + "%username%" => $username, + "%fromname%" => $fromName, + "%frommail%" => $fromMail, +)) ?> diff --git a/apps/reaktor/modules/mail/templates/sendProfileRegisteredByAdminSuccess.altbody.php b/apps/reaktor/modules/mail/templates/sendProfileRegisteredByAdminSuccess.altbody.php new file mode 100644 index 0000000..45899f8 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendProfileRegisteredByAdminSuccess.altbody.php @@ -0,0 +1,6 @@ +setSubject(__('Your Reaktor useraccount:') . $user->getUsername()) ?> + + $password, + "%username%" => $user->getUsername() , +)) ?> \ No newline at end of file diff --git a/apps/reaktor/modules/mail/templates/sendProfileRegisteredByAdminSuccess.php b/apps/reaktor/modules/mail/templates/sendProfileRegisteredByAdminSuccess.php new file mode 100644 index 0000000..2abc439 --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendProfileRegisteredByAdminSuccess.php @@ -0,0 +1,7 @@ +setSubject(__('Your Reaktor useraccount:') . $user->getUsername()) ?> + + + $password, + "%username%" => $user->getUsername() , +)) ?> \ No newline at end of file diff --git a/apps/reaktor/modules/mail/templates/sendRejectArtworkOrFileSuccess.php b/apps/reaktor/modules/mail/templates/sendRejectArtworkOrFileSuccess.php new file mode 100644 index 0000000..074af6c --- /dev/null +++ b/apps/reaktor/modules/mail/templates/sendRejectArtworkOrFileSuccess.php @@ -0,0 +1,3 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * actions used for messaging + * + * PHP version 5 + * + * @author olepw + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class messagingActions extends sfActions +{ + /** + * action used for sending messages + * + */ + public function executeSendMessageAction() + { + $this->forward404Unless($this->getUser()->isAuthenticated() && $this->getRequest()->isXmlHttpRequest() && $this->getUser()->hasCredential('sendmessages')); + + //TODO: isn't really necessary to duplicate the message when sending to all users + if($this->getRequestParameter('send_to_all')) + { + $all_users = sfGuardUserPeer::getAllActiveUsers(); + foreach ($all_users as $user) + { + MessagesPeer::sendMessage($user->getId(),$this->getUser()->getGuardUser()->getId(),$this->getRequestParameter('message_subject'),$this->getRequestParameter('message_body'),$this->getRequestParameter('reply_to')); + } + $this->to = true; + $this->duplicated = false; + } + else + { + $this->to = sfGuardUserPeer::getByUsername($this->getRequestParameter('message_to')); + $this->duplicated = 0; + if ($this->to) + { + //make sure message is not sent twice. Don't allow a user to sent a new message to that user within 30 seconds or so... + $this->duplicated = MessagesPeer::getMessagesByAge(0,$this->to->getId(),$this->getUser()->getGuardUser()->getId()); + if (!$this->duplicated) + { + MessagesPeer::sendMessage($this->to->getId(),$this->getUser()->getGuardUser()->getId(),$this->getRequestParameter('message_subject'),$this->getRequestParameter('message_body'),$this->getRequestParameter('reply_to')); + } + } + } + } + + /** + * action used for marking messages as read + * + */ + + public function executeMarkMessageRead() + { + if ($this->getUser()->isAuthenticated()) + { + MessagesPeer::markAsRead($this->getRequestParameter('id')); + } + } + + /** + * action used for deleting a message + * + */ + + public function executeDeleteMessage() + { + if ($this->getUser()->isAuthenticated()) + { + $user_id = $this->getUser()->getGuardUser()->getId(); + $m = MessagesPeer::retrieveByPK($this->getRequestParameter('id')); + if ($m->getFromUserId() == $user_id) + { + $m->markAsDeletedByFrom(); + } + elseif ($m->getToUserId() == $user_id) + { + $m->markAsDeletedByTo(); + } + else { + /* hax0r alert */ + return; + } + $m->setIsRead(1); + $m->save(); + } + } + + /** + * action used for restoring a message + * + */ + + public function executeRestoreMessage() + { + if ($this->getUser()->isAuthenticated()) + { + MessagesPeer::markAsRestored($this->getRequestParameter('id')); + } + } + + /** + * action used for periodically update message div + * + */ + public function executeGetNewMessages() + { + + } + + /** + * action used for manually updating message counter + * + */ + public function executeUpdateMessageCounter() + { + + } + +/** + * action used for pignoring user + * + */ + public function executeIgnoreUser() + { + if ($this->getUser()->isAuthenticated()) + { + switch ($this->getRequestParameter('do')) + { + case 'add': + $ignore = new MessagesIgnoredUser(); + $user = sfGuardUserPeer::retrieveByPK($this->getRequestParameter('id')); + + foreach($user->getsfGuardUserGroups() as $group) { + if (in_array($group->getsfGuardGroup()->getName(), array("admin", "staff"))) { + return $this->renderText($this->getContext()->getI18N()->__('Sorry, you cannot ignore our staff')); + } + } + + $ignore->setIgnoresUserId($user->getId()); + $ignore->setUserId($this->getUser()->getGuardUser()->getId()); + $ignore->save(); + if ($read = $this->getRequestParameter('read')) + { + $m = MessagesPeer::retrieveByPK($read); + if ($m->getToUserId() == $this->getUser()->getGuardUser()->getId()) + { + $m->setIsRead(1); + $m->save(); + } + } + $this->forward('messaging','InboxComponent'); + break; + case 'remove': + $c = new Criteria(); + $c->add(MessagesIgnoredUserPeer::IGNORES_USER_ID, $this->getRequestParameter('id')); + $c->add(MessagesIgnoredUserPeer::USER_ID, $this->getUser()->getGuardUser()->getId()); + MessagesIgnoredUserPeer::doDelete($c); + return $this->renderText($this->getContext()->getI18N()->__('The user is not ignored')); + break; + } + } + } + + /** + * action used for displaying message inbox page + * + */ + public function executeMessageInbox() + { + $this->pager = MessagesPeer::getMessagesPaginated($this->getUser()->getGuardUser()->getId()); + $this->pager->setPage($this->getRequestParameter('page', 1)); + $this->pager->init(); + } + /* + * Messagebox inbox doclet + */ + public function executeInboxComponent() { + + } + + public function executeMessageContentAjax() { + $this->messages = MessagesPeer::getAllMessages($this->getUser()->getGuardUser()->getId()); + } +} + + + +?> diff --git a/apps/reaktor/modules/messaging/actions/components.class.php b/apps/reaktor/modules/messaging/actions/components.class.php new file mode 100644 index 0000000..63c10b9 --- /dev/null +++ b/apps/reaktor/modules/messaging/actions/components.class.php @@ -0,0 +1,88 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Components used for messaging + * + * PHP version 5 + * + * @author olepw + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class messagingComponents extends sfComponents +{ + + public function executeSendMessageForm() + { + + } + + public function executeMessageCounter() + { + if (!isset($this->count)) + { + $messages = MessagesPeer::getAllMessages($this->getUser()->getGuardUser()->getId()); + $this->newMessagesCount = 0; + foreach ($messages as $message) + { + if (!$message->getIsRead()) + { + $this->newMessagesCount++; + } + } + } + else + { + $this->newMessagesCount = $this->count; + } + } + + public function executeMessagesSummary() + { + $this->readMessagesCount = 0; + $this->newMessagesCount = 0; + $this->archiveMessagesCount = 0; + + $this->messages = MessagesPeer::getAllMessages($this->getUser()->getGuardUser()->getId()); + foreach ($this->messages as $message) + { + if (!$message->getIsRead()) + { + $this->newMessagesCount++; + } + elseif ($message->getIsDeleted($this->getUser()->getGuardUser()->getId())) + { + $this->archiveMessagesCount++; + } + else + { + $this->readMessagesCount++; + } + } + $c = new Criteria(); + $c->add(MessagesIgnoredUserPeer::USER_ID, $this->getUser()->getGuardUser()->getId()); + $res = MessagesIgnoredUserPeer::doSelectJoinsfGuardUserRelatedByIgnoresUserId($c); + $this->ignoredusers = array(); + if (!empty($res)) + { + foreach ($res as $row) + { + $this->ignoredusers[] = array('id' => $row->getIgnoresUserId(), 'username' => $row->getsfGuardUserRelatedByIgnoresUserId()->getUsername()); + } + } + $this->hasignored = (count($this->ignoredusers) > 0) ? true : false; + } + +} + +?> diff --git a/apps/reaktor/modules/messaging/templates/InboxComponentSuccess.php b/apps/reaktor/modules/messaging/templates/InboxComponentSuccess.php new file mode 100644 index 0000000..f192f14 --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/InboxComponentSuccess.php @@ -0,0 +1 @@ + $sf_user)) ?> diff --git a/apps/reaktor/modules/messaging/templates/_messageContent.php b/apps/reaktor/modules/messaging/templates/_messageContent.php new file mode 100644 index 0000000..d63764c --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/_messageContent.php @@ -0,0 +1,85 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper('content'); +if (!isset($maxlen)) +{ + $maxlen = 0; +} +?> + +
      +
      $message->getsfGuardUserRelatedByFromUserId()->getUsername())) ?> getSubject(), array( 'url' => '@markmessageread?id='.$message->getId(), + // 'loading' => visual_effect('toggle_slide','message_body_holder_'.$message->getId()), + //)); ?> +
      +
      +
      +
      + hasCredential("sendmessages")): ?> + '@markmessageread?id='.$message->getId(), + 'update' => 'message_count_sidebar', + 'loading' => visual_effect('toggle_slide', 'send_message_form') .visual_effect('blind_up', 'message_subject_holder_archive') . visual_effect('blind_up', 'message_subject_holder_read') . visual_effect('blind_up', 'message_subject_holder') . ";$('message_to').value = '" . $message->getsfGuardUserRelatedByFromUserId()->getUsername() ."';$('reply_message').innerHTML = $('message_body_holder_" . $message->getId() . "').innerHTML;$('reply_to').value = '".$message->getId()."'", + 'complete' => remote_function(array('update'=>'message_subject_holder','url'=>'@updateMessageContentAjax','complete'=>"")) + )); ?> | + + getId();?> + '@markmessageread?id='.$message->getId(), + 'update' => 'message_count_sidebar', + 'loading' => "$('$msgid').setAttribute('style', 'background-color: #fff');" . visual_effect('toggle_slide', $msgid), + ), array("title" => __("Close message"))); ?> +
      +
      + +
      +
      getPartialMessage($maxlen, $cropped) ?> + + ", link_to(__('read the rest'), '@messageinbox#msg_' . $message->getId()) ?> + +

      +
      + getsfGuardUserRelatedByFromUserId()->getAvatar()): ?> + getsfGuardUserRelatedByFromUserId()->getAvatar(), array('size' => '16x16', 'alt' => $message->getsfGuardUserRelatedByFromUserId()->getUsername())) ?> + + '16x16', 'alt' => $message->getsfGuardUserRelatedByFromUserId()->getUsername())) ?> + + getsfGuardUserRelatedByFromUserId()->getUsername() ?>,
      + +
      + getTimestamp()) ?> +
      +
      + + getIsDeleted($message->getToUserId())): ?> + '@restoremessage?id='.$message->getId(), + 'loading' => visual_effect('appear', 'msg_loading'), + 'complete' => visual_effect('fade', 'message_'.$message->getId()).visual_effect('fade', 'msg_loading') + ))*/ ?> + + '@deletemessage?id='.$message->getId(), + 'confirm' => __('Are you sure'), + 'loading' => visual_effect('appear', 'msg_loading'), + 'complete' => visual_effect('fade', 'message_'.$message->getId()).visual_effect('fade', 'msg_loading') + )) ?> + + isIgnored()): ?> +
      + '@ignoreuser?id='.$message->getsfGuardUserRelatedByFromUserId()->getId().'&do=add&read='.$message->getId(), + 'loading' => visual_effect('toggle_slide','message_body_holder_'.$message->getId()), + 'update' => 'message_summary' + )); ?> + +
      + + + +
      +
      +
      diff --git a/apps/reaktor/modules/messaging/templates/_messageCounter.php b/apps/reaktor/modules/messaging/templates/_messageCounter.php new file mode 100644 index 0000000..49d4abb --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/_messageCounter.php @@ -0,0 +1,7 @@ + + $newMessagesCount)), visual_effect('toggle_slide', 'message_subject_holder')) ?> + 0): ?> + $newMessagesCount)), visual_effect('toggle_slide', 'message_subject_holder')) ?> + +
      $newMessagesCount)) ?>
      + \ No newline at end of file diff --git a/apps/reaktor/modules/messaging/templates/_messagesSummary.php b/apps/reaktor/modules/messaging/templates/_messagesSummary.php new file mode 100644 index 0000000..b963f90 --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/_messagesSummary.php @@ -0,0 +1,90 @@ + + * @author Daniel Andre Eikeland + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + + + +
      +
      +
      + + + $newMessagesCount)); ?> + +
      +
      +
      + + + hasCredential('sendmessages')): ?> + + + + 0): ?> + + +
      + + 0): ?> + + +
      + + | + + | + +
      +
      + + + + + + + +
      + + getIsRead()) continue; ?> + $message, 'maxlen' => sfConfig::get("app_message_max_length", 500))); ?> + +
      + + + + getIsDeleted()) continue; ?> + $message)); ?> + +
      + + + */?> diff --git a/apps/reaktor/modules/messaging/templates/_messagesWrapper.php b/apps/reaktor/modules/messaging/templates/_messagesWrapper.php new file mode 100644 index 0000000..f9c487e --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/_messagesWrapper.php @@ -0,0 +1,24 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + +
      + 300, + 'update' => 'message_summary', + 'url' => '@newMessages', + 'script' => true, + ) + ) ?> +
      + $sf_user)) ?> +
      +
      diff --git a/apps/reaktor/modules/messaging/templates/_sendMessageForm.php b/apps/reaktor/modules/messaging/templates/_sendMessageForm.php new file mode 100644 index 0000000..efd8e42 --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/_sendMessageForm.php @@ -0,0 +1,54 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('Javascript', 'wai'); +?> + +hasCredential('sendmessages')): ?> +
      +
      + 'message_form', + 'id' => 'message_form', + 'name' => 'message_form')); + ?> + + + + + 8, "cols" => 40)); ?> +
      + + 0.2,)) ?> +
      + +
      + + hasCredential('sendcommentstoall')): ?> + + + +
      +
      + 'display: none;')); ?> + array('success' => 'message_status', 'failure' => 'message_status'), + 'url' => '@sendmessage', + 'loading' => visual_effect('appear', 'msg_loading'), + 'complete' => visual_effect('toggle_slide', 'send_message_form').visual_effect('fade', 'msg_loading')."$('message_form').reset();", + 'script' => true), + array('class' => 'submit')); + ?> +
      + +
      + diff --git a/apps/reaktor/modules/messaging/templates/getNewMessagesSuccess.php b/apps/reaktor/modules/messaging/templates/getNewMessagesSuccess.php new file mode 100644 index 0000000..4d6e728 --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/getNewMessagesSuccess.php @@ -0,0 +1,15 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('Javascript'); +?> + + $sf_user)) ?> \ No newline at end of file diff --git a/apps/reaktor/modules/messaging/templates/markMessageReadSuccess.php b/apps/reaktor/modules/messaging/templates/markMessageReadSuccess.php new file mode 100644 index 0000000..76f0932 --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/markMessageReadSuccess.php @@ -0,0 +1,14 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript'); + +include_component("messaging","messageCounter"); ?> \ No newline at end of file diff --git a/apps/reaktor/modules/messaging/templates/messageContentAjaxSuccess.php b/apps/reaktor/modules/messaging/templates/messageContentAjaxSuccess.php new file mode 100644 index 0000000..efc8fe8 --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/messageContentAjaxSuccess.php @@ -0,0 +1,5 @@ + + + getIsRead()) continue; ?> + $message, 'maxlen' => sfConfig::get("app_message_max_length", 500))); ?> + \ No newline at end of file diff --git a/apps/reaktor/modules/messaging/templates/messageInboxSuccess.php b/apps/reaktor/modules/messaging/templates/messageInboxSuccess.php new file mode 100644 index 0000000..24ad1c8 --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/messageInboxSuccess.php @@ -0,0 +1,63 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'content', 'PagerNavigation'); +reaktor::setReaktorTitle(__('Message history for %username%', array("%username%" => $sf_user->getUsername()))); + +?> + +

      $sf_user->getUsername())); ?>

      +getResults() as $message): ?> + getToUserId() == $sf_user->getGuardUser()->getId(); ?> + + getsfGuardUserRelatedByFromUserId(); ?> +
      + + getsfGuardUserRelatedByToUserId(); ?> +
      + +
      + getAvatarOrDefault(), array('size' => '16x16', 'alt' => $sf_user->getUsername())) ?> + + + $theOtherGuy->getUsername())) ?> + + $theOtherGuy->getUsername())) ?> + + + getTimestamp()) ?> +
      +
      +
      + getMessage(), ENT_QUOTES, 'UTF-8') ?> +
        +
      + '@deletemessage?id='.$message->getId(), + 'confirm' => __('Are you sure'), + 'loading' => visual_effect('appear', 'msg_loading'), + 'complete' => 'window.location.reload()', + )) ?> + isIgnored()): ?> + '@ignoreuser?id='.$theOtherGuy->getId().'&do=add', + 'loading' => visual_effect('appear', 'msg_loading'), + 'complete' => 'window.location.reload()', + 'update' => 'ignoreuser_'.$message->getId() + )); ?> + + + + +
      + + + + + diff --git a/apps/reaktor/modules/messaging/templates/sendMessageActionSuccess.php b/apps/reaktor/modules/messaging/templates/sendMessageActionSuccess.php new file mode 100644 index 0000000..60134d4 --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/sendMessageActionSuccess.php @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/apps/reaktor/modules/messaging/templates/updateMessageCounterSuccess.php b/apps/reaktor/modules/messaging/templates/updateMessageCounterSuccess.php new file mode 100644 index 0000000..3c4724a --- /dev/null +++ b/apps/reaktor/modules/messaging/templates/updateMessageCounterSuccess.php @@ -0,0 +1,15 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('Javascript'); +?> + + $newMessagesCount)); ?> \ No newline at end of file diff --git a/apps/reaktor/modules/profile/actions/actions.class.php b/apps/reaktor/modules/profile/actions/actions.class.php new file mode 100644 index 0000000..e425a5d --- /dev/null +++ b/apps/reaktor/modules/profile/actions/actions.class.php @@ -0,0 +1,603 @@ + + * @author Ole Petter Wikene + * @author Kjell-Magne Oierud + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * Actions regarding a user and its profile is controlled from this + * class - like registering and updating a user, getting a new password, etc. + * + * PHP version 5 + * + * @author June Henriksen + * @author Ole Petter Wikene + * @author Kjell-Magne Oierud + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class profileActions extends sfActions +{ + + /** + * Add url to a users resource list and return message. + * + * @return void + */ + public function executeAddResource() + { + $this->forward404Unless($this->getUser()->isAuthenticated() && $this->getUser()->hasCredential('addresources')); + //Security: display if ajax, and the logged in user is admin or own the mypage + if (!$this->getRequest()->isXmlHttpRequest()) + { + //User shouldn't be here + die(); + } + $user = $this->getRequestParameter('user'); + $logged_in_user = $this->getUser()->getGuardUser()->getId(); + $url = $this->getRequestParameter('resource_url'); + + $this->forward404Unless(($user&&$user==$logged_in_user)||($user&&$this->getUser()->hasCredential('editprofile'))); + + + UserResourcePeer::addResource($user, $url); + + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_component('profile', 'resources', array('user' => $user) )); + } + + /** + * Remove a resource + * + * @return unknown + */ + public function executeRemoveResource() + { + $this->forward404Unless($this->getUser()->isAuthenticated() && $this->getUser()->hasCredential('addresources')); + //Security: display if ajax, and the logged in user is admin or own the mypage + if (!$this->getRequest()->isXmlHttpRequest()) + { + //User shouldn't be here + die(); + } + $user = $this->getRequestParameter('user'); + $logged_in_user = $this->getUser()->getGuardUser()->getId(); + + $this->forward404Unless(($user&&$user==$logged_in_user)||($user&&$this->getUser()->hasCredential('editprofile'))); + + //delete resource + $c = new Criteria(); + $c->add(UserResourcePeer::ID, $this->getRequestParameter('resourceid')); + UserResourcePeer::doDelete($c); + + //reload component + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_component('profile', 'resources', array('user' => $user) )); + + } + + /** + * Display page resources page. This is needed to display error messsages. Validation doesn't + * work with components. + * + * @return void + */ + public function executeResources() + { + $this->user = $this->getRequestParameter('user'); + } + + /** + * Handle validation errors when adding a resource + * + * @return void + */ + public function handleErrorAddResource() + { + + $params = $this->getContext()->getController()->convertUrlStringToParameters($this->getRequestParameter('sf_comment_referer')); + + foreach ($params[1] as $param => $value) + { + $this->getRequest()->setParameter($param, $value); + } + $this->getResponse()->setStatusCode(500); + + $this->forward('profile', 'resources'); + } + + /** + * We want to edit both the login and profile information at the same time, + * so we collect both for registerSuccess template. + * + * @return void + */ + public function executeRegister() + { + $this->redirectUnless(!$this->getUser()->isAuthenticated(), '@profile'); + $this->sf_guard_user = new sfGuardUser(); + $this->residence_array = ResidencePeer::getResidenceLevel(); + } + + /** + * In order to display the form again with error messages we have to + * override the error handling. + * + * @return void + */ + public function handleErrorUpdate() + { + $this->forward('profile', 'edit'); + } + + /** + * In order to display the form again with error messages we have to + * override the error handling. + * + * @return void + */ + public function handleErrorCreate() + { + $this->redirectIf($this->getUser()->isAuthenticated(), '@profile'); + $this->redirectIf($this->getRequest()->getMethod() != sfRequest::POST, '@register'); + + $this->forward('profile', 'register'); + } + + /** + * We want to edit both the login and profile information at the same time, + * so we collect both for editSuccess template. + * + * @return void + */ + public function executeEdit() + { + $this->redirectUnless($this->getUser()->isAuthenticated(), '@register'); + if ($this->getUser()->hasCredential('editprofile') && $this->getRequestParameter('id') != '') + { + $user_id = $this->getRequestParameter('id'); + } + else + { + $user_id = $this->getUser()->getGuardUser()->getId(); + } + + if ($this->getFlash('issaved')) + { + $this->issaved = true; + } + else + { + $this->issaved = false; + } + + $user_interests = UserInterestPeer::retrieveByUser($user_id); + $interests = array(); + if($user_interests) + { + $this->user_interests= $user_interests; + foreach($user_interests as $user_interest) + { + $id = $user_interest->getSubreaktorId(); + $interests[$id] = $id; + } + } + $this->interests = $interests; + $this->sf_guard_user = sfGuardUserPeer::retrieveByPk($user_id); + $this->forward404Unless($this->sf_guard_user); + if ($this->getRequestParameter('revert_email') == 'yes') + { + $this->sf_guard_user->setNewEmail(''); + $this->sf_guard_user->setNewEmailKey(''); + $this->sf_guard_user->save(); + } + $this->catalogue = CataloguePeer::getSelectArr(); + $this->cat_default = $this->sf_guard_user->getCulture(); + $this->residence_array = ResidencePeer::getResidenceLevel(); + } + + /** + * Create a new user and send an e-mail for validation. + * + * @return void + */ + public function executeCreate() + { + $sf_guard_user = new sfGuardUser(); + $sf_guard_user->registerUser($this); + + // + // Create and send e-mail + // + global $mail_data; + $mail_data = array('user' => $sf_guard_user); + $raw_email = $this->sendEmail('mail', 'sendActivationEmail'); + $this->logMessage($raw_email, 'debug'); + + //We've set up a goal at Google Analytics in order to track if users manage to register. + //This will help identify if the user is successful + $this->getTracker()->setPageName('/profile/thankyou', array( + 'use_flash' => true, + )); + $this->newUser = $sf_guard_user; + } + + public function validateCreate() + { + $userDate=$this->getRequestParameter("dob"); + $currentDate = getdate(); + + if( + ((int)$userDate['month']>$currentDate['mon'] && (int)$userDate['year']>=$currentDate['year']) || + ((int)$userDate['month']==$currentDate['mon'] && (int)$userDate['day']>$currentDate['mday'] && (int)$userDate['year']==$currentDate['year']) + ) { + $this->getRequest()->setError("dob", "Date is not correct"); + return false; + } + return true; + } + + + /** + * Update user and redirect to the same profile page. + * + * @return void + */ + public function executeUpdate() + { + $sf_guard_user = sfGuardUserPeer::retrieveByPk($this->getRequestParameter('id')); + $this->forward404Unless($sf_guard_user); + $sf_guard_user->setNeedProfileCheck(0); + $sf_guard_user->setDobIsDerived(0); + $sf_guard_user->updateUser($this); + $this->setFlash('issaved', true); + $this->redirect(Subreaktor::addSubreaktorToRoute('@otherprofile?id='.$this->getRequestParameter('id'))); + } + + public function validateUpdate() + { + + $userDate=$this->getRequestParameter("dob"); + $currentDate = getdate(); + + + if( + ((int)$userDate['month']>$currentDate['mon'] && (int)$userDate['year']>=$currentDate['year']) || + ((int)$userDate['month']==$currentDate['mon'] && (int)$userDate['day']>$currentDate['mday'] && (int)$userDate['year']==$currentDate['year']) + ) { + $this->getRequest()->setError("dob", "Date is not correct"); + return false; + } + + if ($this->getRequest()->getMethod() != sfRequest::POST) + { + return true; + } + + /* the `email` is semi-required. Only when new_email is not in use */ + $user = sfGuardUserPeer::retrieveByPk($this->getRequestParameter('id')); + if ($this->getRequestParameter("email") == $user->getEmail()) + { + return true; + } + + if ($this->getRequestParameter("new_email") == $user->getNewEmail()) { + return true; + } + + if ($this->getRequestParameter("email") == "") + { + if ($this->getRequestParameter("new_email") != "") + { + return true; + } + + $this->getRequest()->setError("email", "Please enter an email address"); + return false; + } + + + /* Everything else has been validated via Validation filters */ + return true; + } + + /** + * Activate user given key, and redirect according to success or not. + * TODO: format 404 template to show error message + * + * @return void + */ + public function executeActivate() + { + $sf_guard_user = sfGuardUserPeer::retrieveBySalt($this->getRequestParameter('key')); + + + $this->forward404Unless($sf_guard_user); + $this->forwardIf(@$this->getUser()->isAuthenticated(), 'home','index'); + $this->changed_email = false; + + $this->redirectIf($sf_guard_user->getIsVerified(), '@home'); + + $sf_guard_user->activateUser($this); + $this->newUser = $sf_guard_user; + } + + /** + * Ajax function for checking availability of a username on the registration form + * + * @return null + */ + public function executeCheckUsername() + { + $username = $this->getRequestParameter('username'); + $retval = ''; + $image = "cancel.png"; + + if (trim($username) == '') + { + $retval = sfContext::getInstance()->getI18N()->__('Please enter a username'); + } + elseif (strlen($username) < 3) + { + $retval = sfContext::getInstance()->getI18N()->__('Please enter a longer username'); + } + elseif (strlen($username) > 30) + { + $retval = sfContext::getInstance()->getI18N()->__('Please enter fewer than 30 characters'); + } + elseif (!preg_match('/^([A-Za-z0-9@_-\søåæäöØÅÆÖÄ])+$/', $username)) + { + $retval = sfContext::getInstance()->getI18N()->__('Only letters (A-Å), numbers, and -_@ are valid characters'); + } + elseif ($this->getUser()->isAuthenticated() && $this->getUser()->getGuardUser()->getUsername() == $username) + { + $retval = sfContext::getInstance()->getI18N()->__('Username availability will be displayed here'); + $image = "karakter_gronn.gif"; + } + else + { + $crit = new Criteria(); + $crit->add(sfGuardUserPeer::USERNAME, $username); + if (sfGuardUserPeer::doCount($crit) > 0) + { + $retval = sfContext::getInstance()->getI18N()->__('This username is unavailable'); + } + else + { + $retval = sfContext::getInstance()->getI18N()->__('This username is available'); + $image = "accept.png"; + } + } + $output = json_encode(array("image" => $image, "message" => $retval)); + $this->getResponse()->setHttpHeader("X-JSON", '('.$output.')'); + + return sfView::HEADER_ONLY; + } + + /** + * Change e-mail + * + * @return void + */ + public function executeChangeemail() + { + $this->changed_email = false; + $this->already_changed = false; + + $sf_guard_user = sfGuardUserPeer::retrieveBySalt($this->getRequestParameter('key')); + $this->forward404Unless($sf_guard_user, 'This user does not exist'); + + if ($sf_guard_user->getNewEmailKey() == $this->getRequestParameter('new_email_key') && $sf_guard_user->getNewEmail() != '') + { + $this->changed_email = true; + $sf_guard_user->setEmail($sf_guard_user->getNewEmail()); + $sf_guard_user->setNewEmail(''); + $sf_guard_user->setNewEmailKey(''); + $sf_guard_user->save(); + } + elseif (!$sf_guard_user->getNewEmailKey()) + { + $this->already_changed = true; + } + } + + /** + * In order to display the form again with error messages we have to + * override the error handling. + * + * @return void + */ + public function handleErrorPasswordSend() + { + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_partial('profile/passRequest')); + } + + public function executeChangePassword() + { + $this->verified = false; + $this->error = ''; + $this->verifyerror = ''; + $this->passworderror = false; + $this->passwordupdated = false; + $this->forgot = false; + if ($this->getUser()->isAuthenticated()) + { + $this->user = $this->getUser()->getGuardUser(); + $this->key = 0; + } + else + { + $this->forgot = true; + $c = new Criteria(); + $c->add(sfGuardUserPeer::NEW_PASSWORD_KEY, $this->getRequestParameter('key')); + $c->add(sfGuardUserPeer::USERNAME, $this->getRequestParameter('username')); + $this->user = sfGuardUserPeer::doSelectOne($c); + $this->key = $this->getRequestParameter('key'); + if (!$this->user instanceof sfGuardUser) + { + $this->error = 'Invalid key'; + } + elseif ($this->user->getKeyExpires("U") < $_SERVER["REQUEST_TIME"]) + { + $this->error = $this->getContext()->getI18n()->__('Key expired'); + } + } + if ($this->getRequestParameter('verify') != '') + { + $this->verifyerror = $this->getContext()->getI18n()->__('The information you provided was not correct'); + if ($this->getUser()->isAuthenticated()) + { + $current_pass_md5 = $this->getUser()->getGuardUser()->getPassword(); + $this->user->setPassword($this->getRequestParameter('current_pass')); + $new_pass_md5 = $this->getUser()->getGuardUser()->getPassword(); + $usr = sfGuardUserPeer::retrieveByUsername($this->getUser()->getUserName()); + if ($usr->checkPassword($this->getRequestParameter('current_pass')) || $usr->getIsActive() == 0 ) + { + $this->verified = true; + $this->setFlash('isverified', true); + } + elseif ($this->getFlash('isverified') == true) + { + $this->setFlash('isverified', true); + $this->verified = true; + } + } + else + { + $this->verified = true; + } + } + if ($this->verified) + { + if ($this->getRequestParameter('updatepassword') != '') + { + if ($this->getRequestParameter('new_password1') != '' && $this->getRequestParameter('new_password1') == $this->getRequestParameter('new_password2')) + { + $this->passwordupdated = true; + $this->user->setPassword($this->getRequestParameter('new_password1')); + $this->user->setNewPasswordKey(null); + $this->user->save(); + $this->setFlash('isverified', false); + } + else + { + $this->passworderror = true; + } + } + } + } + + /** + * Handles the sending of new password via email + * + * @return null + */ + public function executePasswordSend() + { + $thisUser = sfGuardUserPeer::retrieveByEmail($this->getRequestParameter('toemail')); + + // We'll need this to render the partials later on + sfLoader::loadHelpers(array('Partial')); + + //Simple validation + if (!$thisUser) + { + $this->getRequest()->setError('toemail', 'User not found'); + return $this->renderText(get_partial('profile/passRequest')); + } + + + $raw = $this->sendEmail('mail', 'sendPasswordEmail'); + $this->logMessage($raw, 'debug'); + + // Render the original partial (this is an ajax request so the least overhead the better) + return $this->renderText(get_partial('profile/passRequest', array("sentOk" => true))); + + } + + /** + * Display mypage + * + * @return void + */ + function executeMyPage() + { + + $this->forward404Unless($this->getUser()->isAuthenticated() ); + $user = $this->getRequestParameter('user'); + $logged_in_user = $this->getUser()->getGuardUser()->getUsername(); + + $this->forward404Unless(($user&&$user==$logged_in_user)||($user&&$this->getUser()->hasCredential('editprofile'))); + $this->user = sfGuardUserPeer::getByUsername($this->getRequestParameter('user')); + $this->forward404Unless($this->user); + + if ($this->getUser()->hasCredential("manageusercontent") && $this->getUser()->getId() != $this->user->getId()) + { + $this->contentRoute = "user_content"; + } + else + { + $this->contentRoute = "my_content"; + } + } + + /** + * Display portfolio page + * + * @return void + */ + function executePortfolio() + { + if ($this->hasRequestParameter('user')) + { + $this->user = sfGuardUserPeer::getByUsername($this->getRequestParameter('user')); + $this->forward404Unless($this->user); + + $this->blocked_profile = (!$this->user->getShowContent()) ? true : false; + if ($this->user->getId() == $this->getUser()->getId() || $this->getUser()->hasCredential('viewallcontent')) + { + $this->blocked_profile = false; + } + $this->page = $this->getRequestParameter('page'); + $this->orderBy = $this->getRequestParameter('orderby'); + } + else + { + $this->forward('profile','portfolio?user='.$this->getUser()->getUsername()); + } + + } + + function executeListMatchingUsers() + { + $this->forward404Unless($this->getUser()->isAuthenticated()); + //Security: display if ajax, and the logged in user is admin or own the mypage + if (!$this->getRequest()->isXmlHttpRequest()) + { + //User shouldn't be here + die(); + } + $user = $this->getRequestParameter('user_id'); + $all = $this->getRequestParameter('all'); + $logged_in_user = $this->getUser()->getGuardUser()->getId(); + + + $this->forward404Unless(($user&&$user==$logged_in_user)||($user&&$this->getUser()->hasCredential('editprofile'))); + + //reload component + sfLoader::loadHelpers(array('Partial')); + + return $this->renderText(get_component('profile', 'matchingInterests', array('user_id' => $user, 'all'=>$all))); + } + + +} diff --git a/apps/reaktor/modules/profile/actions/components.class.php b/apps/reaktor/modules/profile/actions/components.class.php new file mode 100644 index 0000000..cc4e387 --- /dev/null +++ b/apps/reaktor/modules/profile/actions/components.class.php @@ -0,0 +1,95 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +class profileComponents extends sfComponents +{ + /* + * Function for displaying the last created users + * + * @return void + */ + function executeLastUsers() + { + $limit = sfConfig::get('app_home_list_length', 5); + $showcontent = !sfContext::getInstance()->getUser()->hasCredential('viewallcontent'); + $this->last = sfGuardUserPeer::getLastUsers($limit, $showcontent, $this->subreaktor, $this->lokalreaktor, true); + } + + /** + * Component for displaying and adding a users resources + * + * @return void + */ + function executeResources() + { + $c = new Criteria(); + $c->add(UserResourcePeer::USER_ID, $this->user); + //$c->setLimit(sfConfig::get('app_mypage_resources_length', 5)); + $this->resources = UserResourcePeer::doSelect($c); + + + } + /** + * List users with matching interests, either all in a sidebar div, or a fixed length list + * in a normal box. + * + * @return void + */ + function executeMatchingInterests() + { + if ($this->all) + { + $this->users = sfGuardUserPeer::getUsersByMatchingInterests($this->user_id); + } + else + { + $this->users = sfGuardUserPeer::getUsersByMatchingInterests($this->user_id, sfConfig::get('app_home_list_length', 5)); + } + } + + /** + * Component for displaying userinfo on portifolio page + * + * @return void + */ + function executePortfolioUserinfo() + { + $c = new Criteria(); + $username = $this->getRequestParameter('user'); + $c->add(sfGuardUserPeer::USERNAME,$username); + $c->addJoin(sfGuardUserPeer::RESIDENCE_ID, ResidencePeer::ID, Criteria::LEFT_JOIN); + //$user = sfGuardUserPeer::doSelectJoinResidence($c); + $user = sfGuardUserPeer::doSelect($c); + $this->user = array_shift($user); + + if (!$this->user) + { + return 0; + } + + $c2 = new Criteria(); + $c2->add(UserInterestPeer::USER_ID, $this->user->getId()); + $this->interests = UserInterestPeer::doSelectJoinSubreaktor($c2); + + } + + function executeGetLoggedInStatus() + { + $this->status = sfGuardUserPeer::isUserOnline($this->userid) && $this->user->getShowLoginStatus(); + } + + function executeMostActiveUsers() + { + $this->active = sfGuardUserPeer::getMostActiveSince(time()-2592000,array(11,12),20); + } +} + +?> diff --git a/apps/reaktor/modules/profile/config/security.yml b/apps/reaktor/modules/profile/config/security.yml new file mode 100644 index 0000000..92ac9d1 --- /dev/null +++ b/apps/reaktor/modules/profile/config/security.yml @@ -0,0 +1,3 @@ +default: + is_secure: off + diff --git a/apps/reaktor/modules/profile/config/view.yml b/apps/reaktor/modules/profile/config/view.yml new file mode 100644 index 0000000..2d19f15 --- /dev/null +++ b/apps/reaktor/modules/profile/config/view.yml @@ -0,0 +1,7 @@ +myPageSuccess: + components: + sidebar_articles: [articles, myPageArticles] + +all: + javascripts: [prototype, inlineupload, main] + diff --git a/apps/reaktor/modules/profile/templates/_MostActiveUsers.php b/apps/reaktor/modules/profile/templates/_MostActiveUsers.php new file mode 100644 index 0000000..de4a2bd --- /dev/null +++ b/apps/reaktor/modules/profile/templates/_MostActiveUsers.php @@ -0,0 +1,14 @@ + + +

      + + + + + + +
      + +
      diff --git a/apps/reaktor/modules/profile/templates/_getLoggedInStatus.php b/apps/reaktor/modules/profile/templates/_getLoggedInStatus.php new file mode 100644 index 0000000..16f5040 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/_getLoggedInStatus.php @@ -0,0 +1,3 @@ + +
      + diff --git a/apps/reaktor/modules/profile/templates/_lastUsers.php b/apps/reaktor/modules/profile/templates/_lastUsers.php new file mode 100644 index 0000000..748f6ba --- /dev/null +++ b/apps/reaktor/modules/profile/templates/_lastUsers.php @@ -0,0 +1,31 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?> + __('latest registered users'), 'slug' => 'latest_users')); ?> +
      +
        + 0): ?> + + getAvatar()) ? $user->getAvatar() : "default.gif"; ?> +
      • + getUserName(),'@portfolio?user='.$user->getUserName()) ?> +
      • + + +
      • + +
      +
      + diff --git a/apps/reaktor/modules/profile/templates/_matchingInterests.php b/apps/reaktor/modules/profile/templates/_matchingInterests.php new file mode 100644 index 0000000..d594bdf --- /dev/null +++ b/apps/reaktor/modules/profile/templates/_matchingInterests.php @@ -0,0 +1,54 @@ + $user->getId(), + * 'username' => $user->getUsername(), + * 'all' => false, + * )) + * + * $user_id : Integer Match interest with this user + * $username: String Name of the same user + * $all : Boolean If false use config to decide length of list + * + * The controller passes the following information: + * $users - array of sfGuardUser objects + * + * PHP version 5 + * + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper('Javascript') +?> + __('users with shared interests'), 'slug' => 'shared_interest&username=' . $username, 'route' => 'userfeed')); ?> +
      id='matcing_interests_user_list' > + 0):?> + +
        + +
      • + getUserName(), '@portfolio?user='.$user->getUserName()) ?> +
      • + + + = sfConfig::get('app_home_list_length', 5))): ?> +
      • + '@allusersmatchinginterests?user_id='.$user_id.'&all=1', + 'class' => 'differ', + 'update' => 'matcing_interests_user_list' + )) ?> +
      • + +
      + + + + + +
      diff --git a/apps/reaktor/modules/profile/templates/_passRequest.php b/apps/reaktor/modules/profile/templates/_passRequest.php new file mode 100644 index 0000000..3794e36 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/_passRequest.php @@ -0,0 +1,44 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +use_helper("Javascript", 'wai'); +?> + + +

      + +

      + +
      +

      + 'lost_pass', + 'url' => 'profile/passwordSend', + 'loading' => "$('email_indicator').show();$('newpass_form').hide();", + 'complete' => "$('email_indicator').hide();$('newpass_form').show();", + 'success' => "$('toemail').value = ''"), + array("name" => "request_pass") + ) ?> +
      +
      +
      + + +
      +
      + + +
      + + +


      diff --git a/apps/reaktor/modules/profile/templates/_portfolioUserinfo.php b/apps/reaktor/modules/profile/templates/_portfolioUserinfo.php new file mode 100644 index 0000000..28be37d --- /dev/null +++ b/apps/reaktor/modules/profile/templates/_portfolioUserinfo.php @@ -0,0 +1,87 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +
      + + hasCredential('editprofile')): ?> +
      +

      Moderator:


      + getShowContent()): // Warn moderator that this users artworks have been blocked for other users to see ?> +


      + + getId()) ?> +
      + + + isAuthenticated() && $user->getUsername() == $sf_user->getUsername() && !$user->getShowContent()): // User's viewing own page, and content is blocked ?> +
      +

      +
      +
      + + getNamePrivate() && $user->getName()): ?> +
      getName(); ?>
      + +
      getUsername() ?>
      +
      getAge(); ?>
      + getResidence() instanceof Residence): ?> +
      getResidence()->getName(); ?>
      + + + 0): ?> +

      + + getSubreaktor()->getName(); ?>
      + + + getEmailPrivate() && $sf_user->isAuthenticated()) || $user->getIcq() || $user->getHomepage() || $user->getMsn()): ?> +
      + + " // Start javascript for mouseover ?> + ', FADEIN, 300, LEFT, true, FOLLOWMOUSE, false, DURATION, -5000)" // End javascript ?> + + + + getEmailPrivate() && $sf_user->isAuthenticated()): + // Check if user allows for displaying e-mail address, and only display to logged in users, it'll + // keep the spammers away ?> + ".__('Email:') . "

      ". + mail_to($user->getEmail(), $user->getEmail(), array('encode'=> true)).$mouseoverEnd ?> + getEmail() ,image_tag('email.png', array( + 'onmouseover' => $mouseover, + 'onmouseout' => $mouseOut)), array( + 'encode'=> true + )) ?> + + + getHomepage()): // Check if user has provided a homepage ?> + ".__('Homepage:') . "
      ". + link_to($user->getHomepage(), $user->getHomepage()).$mouseoverEnd?> + $mouseover, + 'onmouseout' => $mouseOut)), $user->getHomepage()) ?> + + + getIcq()): // Check if user has provided icq ?> + ".__('ICQ:') . "
      ".$user->getIcq().$mouseoverEnd?> + $mouseover, + 'onmouseout' => $mouseOut)) ?> + + + getMsn()): // Check if user has provided msn ?> + ".__('MSN:') . "
      ".$user->getMsn().$mouseoverEnd?> + $mouseover, + 'onmouseout' => $mouseOut)) ?> + + +
      diff --git a/apps/reaktor/modules/profile/templates/_resources.php b/apps/reaktor/modules/profile/templates/_resources.php new file mode 100644 index 0000000..74358bc --- /dev/null +++ b/apps/reaktor/modules/profile/templates/_resources.php @@ -0,0 +1,76 @@ + $user->getId())) + * + * The paramters needed: + * $user - the id of the user + * + * The controller passes the following information: + * $resources - The already added resources belonging to this user + * + * PHP version 5 + * + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +use_helper('Javascript', 'Validation', 'wai') +?> +
      + +

      + +

      +
        + +
      • + getUrl(), $resource->getUrl(), array("target" => "_new")) ?> + 'all_resources_block', + 'url' => '@removeresource?user='.$user.'&resourceid='.$resource->getId(), + //'loading' => "Element.show('resource_ajax_indicator')", + //'complete' => "Element.hide('resource_ajax_indicator')", + 'script' => true, + )) ?> +
      • + +
      + + 'all_resources_block', + 'url' => '@addresource?user='.$user, + 'loading' => "Element.show('resource_ajax_indicator')", + 'complete' => "Element.hide('resource_ajax_indicator')", + 'script' => true), array( + 'class' => 'add_resource_form', + 'id' => 'add_resource_form', + 'name' => 'add_resource_form' + )) ?> + +

      + +

      + + + + + 'width_shorter')) ?> + + 'submit' + )) ?> + + + +
      + diff --git a/apps/reaktor/modules/profile/templates/_userProfile.php b/apps/reaktor/modules/profile/templates/_userProfile.php new file mode 100644 index 0000000..2e7c578 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/_userProfile.php @@ -0,0 +1,208 @@ + $sf_guard_user, + * 'profile' =>'create', + * 'residence_array' => $residence_array)) + * + * The following parameters need to be passed: + * sf_guard_user - A sf_guard_user object of the user whose profile is to be either created or edited + * profile - Not mandatory, if not set its assumed to be edit, if set set to create the mode is assumed to be create + * residence_array - An array of arrays, which city, municipal or county can the user choose between in the residence drop down. + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper('Javascript', 'wai'); +?> + + + + +*
      + + + + + 30, + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for username**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", +// For some reason some of web browsers doesn't triger onkeyup event when typing special characters like øåæ - Thats the reason wy checkUsername(); method has been moved to onkeydown event +// 'onkeyup' => "if (!ignoreKeycodes.include(event.keyCode)) { checkUsername(); }", + 'onkeydown' => "if (!ignoreKeycodes.include(event.keyCode)) { clearUsernameCheck(); checkUsername(); }", + 'id' => 'username_profile', + 'name' => 'username_profile' +)); ?> + +

      + "username_check_img", "size" => "12x12")); ?> + + + +

      +
      + + + + + *
      + + 20, + 'id' => 'password_profile', + 'name' => 'password_profile', + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for password')."'" + )); ?>
      + + + *
      + + "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for password_repeat**')."'" + )); ?>
      + + + + + + * + + + +
      +getNewEmail() != '' && !$sf_user->hasCredential('editprofile')): ?> + + 80, + 'onfocus'=> "$('information_msg').innerHTML='".$emailhelptext."'" + )); ?> +
      + + link_to(__('here'), 'profile/edit?revert_email=yes')))?> + + + 80, + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".$emailhelptext."'" + )); ?> + + +
      + "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for hidden_email**')."'" + )); ?> + 'normal_text', + )); ?> +
      + + +*
      + +isAuthenticated()): ?> + getResidence(), array( + 'include_custom' => __('Choose a residence'), + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for residence**')."'" + ))); ?> + + + getResidenceId(), array( + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for residence**')."'" + ))); ?> + + +
      +getDobIsDerived()): ?> +
      + +
      + + +*
      + +getDob(); ?> + + false, + 'culture' => $sf_user->getCulture(), + 'year_start' => date('Y'), + 'year_end' => date('Y')-sfConfig::get('app_profile_max_age',100), + 'date_seperator' => ' ', + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) +)); ?> + +getDobIsDerived()): ?> + + + +
      + + +*
      + +getSex()=='1', array( + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for sex**')."'", + )); + echo wai_label_for('sex', __('male'), array('class'=>'normal_text')); + + echo radiobutton_tag('sex', '2', $sf_guard_user->getSex()=='2', array( + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for sex**')."'", + )); + echo wai_label_for('sex', __('female'),array('class'=>'normal_text')); +?> +

      + +
      + +

      + "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for terms and conditions**')."'", + + ) + ); ?> + reaktor_link_to(__("the terms and conditions"), + "@article?permalink=".sfConfig::get("app_fixed_articles_terms_and_conditions", "terms_and_conditions"), + array("onmouseover" => "$('information_msg').innerHTML='".__('**help-text for terms and conditions**')."'", + "onmouseout" => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + "target" => "_blank")))); + ?>* +

      + diff --git a/apps/reaktor/modules/profile/templates/activateSuccess.php b/apps/reaktor/modules/profile/templates/activateSuccess.php new file mode 100644 index 0000000..a2d73f0 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/activateSuccess.php @@ -0,0 +1,37 @@ + + * @author Russ + * @author Robert Strind + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('Activation success - Welcome to Reaktor!')); + +?> + +

      + +
      + Thank you, %username%!

      Your account is now verified and active.

      On Reaktor you can upload and present your own work,including film, photo, animation, music, comics, illustration and text. You can get feedback and tips from other users and find users that have the same interests as yourself.

      You may now log in using the boxes to the right.

      If you have any problems or feedback, please contact the reaktor team at the following address: %reaktor_help_email%", + array( + "%username%" => $newUser->getUsername(), + "%reaktor_help_email%" => mail_to( + sfConfig::get( + "app_help_email", + "reaktor@minreaktor.no" + ), + '', + array("encode" => true) + ) + ));?> +

      diff --git a/apps/reaktor/modules/profile/templates/changePasswordSuccess.php b/apps/reaktor/modules/profile/templates/changePasswordSuccess.php new file mode 100644 index 0000000..c6781cd --- /dev/null +++ b/apps/reaktor/modules/profile/templates/changePasswordSuccess.php @@ -0,0 +1,76 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__('Change password')); + +?> + + +
      + + + + + + +

      $user->getUsername())) ?>

      + 'update_password', + 'url' => '@changepassword?username='.$user->getUsername().'&key='.$key), + array("name" => "verify_info") + ) ?> + + + + + '; ?> + + + +

      Thank you!

      + +

      $user->getUsername())) ?>

      + +
      +
      + 'update_password', + 'url' => '@changepassword?username='.$user->getUsername().'&key='.$key), + array("name" => "update_password_form") + ) ?> + + + + + + + +
      +
      +
      +
      + + '; ?> + +
      + + + +

      + + + + + + +
      + + diff --git a/apps/reaktor/modules/profile/templates/changeemailSuccess.php b/apps/reaktor/modules/profile/templates/changeemailSuccess.php new file mode 100644 index 0000000..c215926 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/changeemailSuccess.php @@ -0,0 +1,26 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('Change email')); + +?> + + + + + + + + + + + diff --git a/apps/reaktor/modules/profile/templates/createSuccess.php b/apps/reaktor/modules/profile/templates/createSuccess.php new file mode 100644 index 0000000..4314023 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/createSuccess.php @@ -0,0 +1,28 @@ + + * @author Russ + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__("Registration successful")); + +?> + +

      +
      +

      %username%! You have successfully registered a new account on Reaktor.", + array("%username%" => $newUser->getUsername())); ?>

      +

      %email_address%, ", + array("%email_address%" => $newUser->getEmail())); ?>

      +

      mail_to(sfConfig::get("app_help_email", "reaktor@minreaktor.no"), '', array("encode" => true)))); ?> +

      \ No newline at end of file diff --git a/apps/reaktor/modules/profile/templates/editSuccess.php b/apps/reaktor/modules/profile/templates/editSuccess.php new file mode 100644 index 0000000..722e77d --- /dev/null +++ b/apps/reaktor/modules/profile/templates/editSuccess.php @@ -0,0 +1,269 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper('Validation', 'Object', 'm2mCheckBox', 'Javascript', 'wai'); +reaktor::setReaktorTitle(__('Edit profile of %username%', array("%username%" => $sf_guard_user->getUsername()))); + +?> +hasErrors()): ?> +
      +


      +

      +
      + +

      + +

      + $sf_guard_user->getUsername())); ?> +

      +getNeedProfileCheck()): ?> +
      + Welcome back to Reaktor!
      We have detected that your profile may need updating, please check the information below. +
      Even if the information is correct, please click 'save changes' to clear this message."); ?> +
      +
      + + + + +
      + + $sf_guard_user, + 'profile'=>'edit', + 'residence_array' => $residence_array + )); ?> +
      +
      + + "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for language**')."'" + )); ?> +
      + + + 80, + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for fullname**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + )); ?> + +
      + "$('information_msg').innerHTML='".__('**help-text for hidden fullname**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + )); ?> + 'normal_text' + )); ?> +
      +
      + "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for show_login_status**')."'" + )); ?> + 'normal_text', + )); ?> +
      + + + false, + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for description**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'" + )) + */ + ?> + +
      +
      + +
      +
      80, + 'class'=>'short', + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for msn**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'" + ))?>
      + +
      +
      15, + 'class'=>'short', + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for icq**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + )); ?>
      + +
      +
      80, + 'class'=>'short', + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for homepage**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + )); ?>
      + +
      +
      32, + 'class'=>'short', + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for phone**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + )); ?>
      +
      +
      +
      +
      + "$('information_msg').innerHTML='".__('**help-text for receiving admin email**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + )); ?> + 'normal_text' + )); ?> +
      +
      + + +
      + +
      + +
      + +

      + +

      + + + +
      +
      +
      + +
      +
      + getAvatar()) ? $sf_guard_user->getAvatar() : "default.gif"; + +echo ''; +echo ''; +echo ""; +echo '
      '.image_tag(sfConfig::get("app_profile_avatar_url").$avatar_path).'
      '; + + ?> + +
      +
      +
      + + + + + + +
      + + + $value)://, $interests)?> + +
      + "$('information_msg').innerHTML='".__('**help-text for interest**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + )); ?> + +
      + + + $value)://, $interests)?> + +
      + "$('information_msg').innerHTML='".__('**help-text for interest**')."'", + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + )); ?> + +
      + +
      + +
      + + + + +getEditorialTeams()) > 0): ?> +
      +

      + + $sf_guard_user)); ?> +
      + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/reaktor/modules/profile/templates/myPageSuccess.php b/apps/reaktor/modules/profile/templates/myPageSuccess.php new file mode 100644 index 0000000..8685df9 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/myPageSuccess.php @@ -0,0 +1,173 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('content'); +reaktor::setReaktorTitle(__('My page - %username%', array("%username%" => $user->getUsername()))); + +?> + +

      + +
      + +
      + $user->getId(), + )); ?> +
      + getId())) > 0): ?> + + + +
      + +
      +

      + $user->getId(), + 'mode' => 'received', + 'username' => $user->getUsername(), + 'header' => __("Received comments"), + )) ?> +
      +
      +
      + $user->getId(), + 'header' => __('My latest commented artworks') + )); ?> +
      +
      + +
      +
      +
      + +
      +
      + 'user', + 'artwork_or_user_id' => $user->getId(), + 'header' => __("I'm a favourite with"), + )); ?> +
      +
      +
      +
      + 'user', + 'who' => 'Me', + 'artwork_or_user_id' => $user->getId(), + 'header' => __("My favourite users"), + )); ?> +
      +
      +
      + +
      + +
      + +
      +
      + 'artwork', + 'who' => 'Me', + 'artwork_or_user_id' => $user->getId(), + 'header' => __("My favourite artworks"), + )); ?> +
      +
      + +
      +

      + $user->getId(), + 'username' => $user->getUsername(), + 'all' => false, + )); ?> +
      +
      + +
      + +
      +
      +

      + $user->getId(), + 'mode' => 'written', + 'username' => $user->getUsername(), + 'header' => __("Written comments"), + )); ?> + getId())) > 0): ?> +
      + getUsername()) ?> +
      + +
      +
      + +
      + + +
      + +
      + getGuardUser()->getEditorialTeams()) > 0): ?> +

      +
        + getGuardUser()->getEditorialTeams() as $ateam): ?> +
      • getDescription(); ?>
      • + +
      + +

      +
        +
      • get("user")); ?>
      • +
      • get("user")); ?>
      • +
      • get("user")); ?>
      • +
      +
      + +
      + $user->getId() + )); ?> +
      + +
      +
      +
      + 'article', + 'who' => 'Me', + 'artwork_or_user_id' => $user->getId(), + 'header' => __("My favourite articles"), + )); ?> +
      +
      +
      + + +
      + diff --git a/apps/reaktor/modules/profile/templates/portfolioSuccess.php b/apps/reaktor/modules/profile/templates/portfolioSuccess.php new file mode 100644 index 0000000..b47a0b6 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/portfolioSuccess.php @@ -0,0 +1,152 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('content','Javascript'); +reaktor::setReaktorTitle(__('Portfolio for %username%', array("%username%" => $user->getUsername()))); + +?> + + +

      + +
      +
      + getAvatar()): ?> + getAvatar(), array('size' => '48x48', 'alt' => $user->getUsername())) ?> + + '48x48', 'alt' => $user->getUsername())) ?> + +
      +
      + + +
      $user->getUsername()))?>
      +
      + false, 'user_id' => $user->getId(), 'list' => 'user', 'nofavload' => 'true')); ?> +
      + +
      + $user->getId(), + 'user' => $user, + )) ?> +
      +
      +
      + $user->getUsername())) ?> + 'portfolio_image_list', + 'url' => Subreaktor::addProvidedLinkIfValid('artwork/lastArtworksFromUserAction?&orderBy=date&userid='.$user->getId(). '&page=' . $page), + )) ?> | + 'portfolio_image_list', + 'url' => Subreaktor::addProvidedLinkIfValid('artwork/lastArtworksFromUserAction?orderBy=rating&userid='.$user->getId(). '&page=' . $page), + )) ?> | + 'portfolio_image_list', + 'url' => Subreaktor::addProvidedLinkIfValid('artwork/lastArtworksFromUserAction?orderBy=title&userid='.$user->getId(). '&page=' . $page), + )) ?> | + + +
      + +
      + +
      + + +
      + +
      + __("All artworks by %username%", array("%username%" => $user->getUsername())), + 'slug' => "all&username=".$user->getUsername(), + 'route' => "userfeed")); ?> + $user->getId(), + 'portfolio' => true, + 'user' => $user, + 'orderBy' => $orderBy, + )) ?> + +
      +
      + +
      +
      +
      + 'user', + 'artwork_or_user_id' => $user->getId(), + 'header' => __("Users who have marked %username% as favourite", array("%username%" => $user->getUsername())), + )); ?> +
      + +
      +
      + +
      +
      + $user->getId(), + 'header' => __("%username%'s latest commented artwork", array("%username%" => $user->getUsername())), + )); ?> +
      +
      +
      + + +
      + +
      +
      + 'user', + 'who' => 'Me', + 'artwork_or_user_id' => $user->getId(), + 'header' => __("%username%'s favourite users", array("%username%" => $user->getUsername())), + )); ?> +
      + +
      + + +
      +
      + 'artwork', + 'who' => 'Me', + 'artwork_or_user_id' => $user->getId(), + 'header' => __("%username%'s favourite artwork", array("%username%" => $user->getUsername())), + )); ?> +
      +
      + +
      + +
      + diff --git a/apps/reaktor/modules/profile/templates/registerSuccess.php b/apps/reaktor/modules/profile/templates/registerSuccess.php new file mode 100644 index 0000000..1f849b5 --- /dev/null +++ b/apps/reaktor/modules/profile/templates/registerSuccess.php @@ -0,0 +1,103 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('Register')); +use_helper('Validation', 'Object', 'Date', 'Javascript', 'recaptcha', 'wai'); + +?> + +

      +

      +
      + +
      + $sf_guard_user, + 'profile' =>'create', + 'residence_array' => $residence_array + )); ?> + +
      + +
      + + + setError('recaptcha_response_field', __("Please fill out the CAPTCHA correctly")); ?> + + + getError('recaptcha_response_field')); ?> + + +
      +
      + +
      +

      +
      + + +
      +
      +
      +

      + +

      +
      + + + diff --git a/apps/reaktor/modules/profile/templates/resourcesSuccess.php b/apps/reaktor/modules/profile/templates/resourcesSuccess.php new file mode 100644 index 0000000..4c9db1a --- /dev/null +++ b/apps/reaktor/modules/profile/templates/resourcesSuccess.php @@ -0,0 +1,15 @@ + $user)); + +?> \ No newline at end of file diff --git a/apps/reaktor/modules/profile/validate/addResource.yml b/apps/reaktor/modules/profile/validate/addResource.yml new file mode 100644 index 0000000..b2e8029 --- /dev/null +++ b/apps/reaktor/modules/profile/validate/addResource.yml @@ -0,0 +1,7 @@ +fillin: + enabled: true + +fields: + resource_url: + sfUrlValidator: + url_error: "Please enter a valid URL, starting with http://" \ No newline at end of file diff --git a/apps/reaktor/modules/profile/validate/create.yml b/apps/reaktor/modules/profile/validate/create.yml new file mode 100644 index 0000000..68321d8 --- /dev/null +++ b/apps/reaktor/modules/profile/validate/create.yml @@ -0,0 +1,86 @@ +methods: [post, get] +fillin: + enabled: true + +magickDateValidator: + class: myMagickDateValidator + param: + class: sfGuardUser + column: dob + date_error: The date you entered is not valid + date_incomplete: Please select a complete date + +doubleCheckEmailValidator: + class: sfEmailValidator + param: + class: sfGuardUser + column: email + strict: true + email_error: This email address is invalid + +fields: + #username + username_profile: + required: + msg: You must enter a username + sfPropelUniqueValidator: + class: sfGuardUser + column: username + unique_error: This username is already in use + sfRegexValidator: + match: Yes + match_error: Only letters (A-Å), numbers, and -_@ are valid characters + pattern: /^([A-Za-z0-9@_-\søåæäöØÅÆÖÄ])+$/ + sfStringValidator: + min: 2 + min_error: Please enter a longer username + max: 30 + max_error: Please enter fewer than 30 characters + #email + email: + required: + msg: Please enter an email address + sfEmailValidator: + email_error: This email address is invalid + strict: false + sfPropelUniqueValidator: + class: sfGuardUser + column: email + unique_error: This email is already in use + doubleCheckEmailValidator: + #passwords + password_profile: + required: + msg: You must choose a password + myPasswordValidator: + min: 6 + min_error: Password must be longer than 5 characters + password_repeat: + required: + msg: You must type the password twice + sfCompareValidator: + check: password_profile + compare_error: The passwords do not match. Please try again. + #residence + residence_id: + required: + msg: You must choose where your residence is + #dob + dob: + required: + msg: Please choose the date you were born #{ name: Published, params: date_format='dd/MM' } + magickDateValidator: + #sfDateValidator: + #gender + sex: + required: + msg: Please choose your sex + + terms_and_conditions: + required: + msg: You must indicate that you have read and understood the terms and conditions of Reaktor + recaptcha_response_field: + required: + msg: Please fill out the CAPTCHA correctly my friend + sfReCaptchaValidator: + diff --git a/apps/reaktor/modules/profile/validate/passwordSend.yml b/apps/reaktor/modules/profile/validate/passwordSend.yml new file mode 100644 index 0000000..f611ac1 --- /dev/null +++ b/apps/reaktor/modules/profile/validate/passwordSend.yml @@ -0,0 +1,9 @@ +fillin: + enabled: true + +fields: + toemail: + required: + msg: Please enter an email address + sfEmailValidator: + email_error: This email address is invalid diff --git a/apps/reaktor/modules/profile/validate/update.yml b/apps/reaktor/modules/profile/validate/update.yml new file mode 100644 index 0000000..fd6d665 --- /dev/null +++ b/apps/reaktor/modules/profile/validate/update.yml @@ -0,0 +1,114 @@ +methods: [post, get] +fillin: + enabled: true + +magickDateValidator: + class: myMagickDateValidator + param: + class: sfGuardUser + column: dob + date_error: The date you entered is not valid + date_incomplete: Please select a complete date + +doubleCheckEmailValidator: + class: sfEmailValidator + param: + class: sfGuardUser + column: email + strict: true + email_error: This email address is invalid + +doubleCheckMsnValidator: + class: sfEmailValidator + param: + class: sfGuardUser + column: msn + strict: true + email_error: This email address is invalid + +fields: + #username + username_profile: + required: + msg: You must enter a username + sfPropelUniqueValidator: + class: sfGuardUser + column: username + unique_error: This username is already in use + sfRegexValidator: + match: Yes + match_error: Only letters A to Å, numbers, and -_@ are valid characters for username + pattern: /^([A-Za-z0-9@_-\søåæäöØÅÆÖÄ])+$/ + sfStringValidator: + min: 2 + min_error: Please enter a longer username + max: 30 + max_error: Please enter fewer than 30 characters + #email + email: + sfEmailValidator: + email_error: This email address is invalid + strict: false + sfPropelUniqueValidator: + class: sfGuardUser + column: email + unique_error: This email is already in use + doubleCheckEmailValidator: + #passwords + password_profile: + group: password_group + myPasswordValidator: + min: 6 + min_error: password must be longer than 5 characters + password_repeat: + group: password_group + sfCompareValidator: + check: password_profile + compare_error: The passwords do not match. Please retry. + #residence + residence_id: + required: + msg: You must choose where your residence is + #dob + dob: + required: + msg: Please choose your date of birth + magickDateValidator: + #gender + sex: + required: + msg: Please choose your sex + + #msn, icq, homepage and phone have very little space to display error messages, be careful! + + #msn + msn: + sfEmailValidator: + strict: false + email_error: This msn address is invalid + doubleCheckMsnValidator: + #icq + icq: + sfNumberValidator: + nan_error: Please enter a number + min: 9999 + min_error: The number is too low + max: 999999999999999 + max_error: The number is too high + #homepage: + homepage: + sfUrlValidator: + url_error: This URL is invalid + #phone + phone: + sfRegexValidator: + match: Yes + match_error: This is not a phone number + pattern: /^([0-9\s+])+$/ + sfStringValidator: + min: 5 + min_error: This phone number is too short + max: 15 + max_error: This phone number is too long + + diff --git a/apps/reaktor/modules/reports/actions/actions.class.php b/apps/reaktor/modules/reports/actions/actions.class.php new file mode 100644 index 0000000..d0a9988 --- /dev/null +++ b/apps/reaktor/modules/reports/actions/actions.class.php @@ -0,0 +1,415 @@ + + * @author dae@linpro.no + * @author olepw@linpro.no + * @author juneh@linpro.no + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Reports to get useful statistics on artwork and users. + * + * PHP Version 5 + * + * @author Russ Flynn + * @author dae@linpro.no + * @author olepw@linpro.no + * @author juneh@linpro.no + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class reportsActions extends sfActions +{ + + /** + * Execute the artwork report template + * + * @return null + */ + public function executeArtworkReports() + { + $this->subreaktor_id = $this->getRequestParameter('subreaktor_id'); + $this->subreaktor_check = ($this->getRequestParameter('subreaktor_check') != '') ? true : false; + $this->category_id = $this->getRequestParameter('category_id'); + $this->category_check = ($this->getRequestParameter('category_check') != '') ? true : false; + $this->tags = $this->getRequestParameter('tags'); + $this->tags_check = ($this->getRequestParameter('tags_check') != '') ? true : false; + $this->editorial_team_id = $this->getRequestParameter('editorial_team_id'); + $this->editorial_team_check = ($this->getRequestParameter('editorial_team_check') != '') ? true : false; + $this->editorial_team_member_id = $this->getRequestParameter('editorial_team_member_id'); + $this->editorial_team_member_check = ($this->getRequestParameter('editorial_team_member_check') != '') ? true : false; + $this->status_value = $this->getRequestParameter('status_value'); + $this->status_check = ($this->getRequestParameter('status_check') != '') ? true : false; + $this->under_discussion_check = ($this->getRequestParameter('under_discussion_check') != '') ? true : false; + $this->from_date_check = $this->getRequestParameter('from_date_check'); + $this->from_date = $this->getRequestParameter('from_date'); + $this->from_date = ($this->from_date_check) ? $this->from_date : date(''); + $this->to_date_check = $this->getRequestParameter('to_date_check'); + $this->to_date = $this->getRequestParameter('to_date'); + $this->to_date = ($this->to_date_check) ? $this->to_date : date(''); + $this->num_artworks = 0; + // If current month is checked we can generate the dates automatically + if ($this->getRequestParameter("current_month_check")) + { + $this->from_date["year"] = date("Y"); + $this->from_date["month"] = date("m"); + $this->from_date["day"] = 1; + $this->to_date["year"] = date("Y"); + $this->to_date["month"] = date("m"); + $this->to_date["day"] = date("t"); + } + + $crit = new Criteria(); + if ($this->subreaktor_check) + { + $crit->addJoin(ReaktorArtworkPeer::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $crit->addJoin(ReaktorArtworkPeer::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $ctn = $crit->getNewCriterion(SubreaktorArtworkPeer::SUBREAKTOR_ID, $this->subreaktor_id); + $ctn2 = $crit->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $this->subreaktor_id); + $ctn->addOr($ctn2); + $crit->add($ctn); + } + if ($this->category_check) + { + $crit->addJoin(ReaktorArtworkPeer::ID, CategoryArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $crit->add(CategoryArtworkPeer::CATEGORY_ID, $this->category_id); + } + if ($this->tags_check) + { + $artwork_ids = TagPeer::getObjectsTaggedWith($this->tags, array('return_ids' => true)); + $crit->add(ReaktorArtworkPeer::ID, $artwork_ids, Criteria::IN); + } + if ($this->editorial_team_check) + { + $crit->add(ReaktorArtworkPeer::TEAM_ID, $this->editorial_team_id); + } + if ($this->editorial_team_member_check) + { + $crit->add(ReaktorArtworkPeer::ACTIONED_BY, $this->editorial_team_member_id); + } + if ($this->status_check) + { + $crit->add(ReaktorArtworkPeer::STATUS, $this->status_value); + } + if ($this->under_discussion_check) + { + $crit->add(ReaktorArtworkPeer::UNDER_DISCUSSION, true); + } + if (($this->from_date_check && $this->to_date_check) || $this->getRequestParameter("current_month_check")) + { + $ctn = $crit->getNewCriterion(ReaktorArtworkPeer::ACTIONED_AT, $this->from_date['year'].'-'.$this->from_date['month'].'-'.$this->from_date['day'].' 00:00:00', Criteria::GREATER_EQUAL); + $ctn2 = $crit->getNewCriterion(ReaktorArtworkPeer::ACTIONED_AT, $this->to_date['year'].'-'.$this->to_date['month'].'-'.$this->to_date['day'].' 00:00:00', Criteria::LESS_EQUAL); + $ctn->addAnd($ctn2); + $crit->add($ctn); + } + elseif ($this->from_date_check) + { + $crit->add(ReaktorArtworkPeer::ACTIONED_AT, $this->from_date['year'].'-'.$this->from_date['month'].'-'.$this->from_date['day'].' 00:00:00', Criteria::GREATER_EQUAL); + } + elseif ($this->to_date_check) + { + $crit->add(ReaktorArtworkPeer::ACTIONED_AT, $this->to_date['year'].'-'.$this->to_date['month'].'-'.$this->to_date['day'].' 00:00:00', Criteria::LESS_EQUAL); + } + $this->report_type = $this->getRequestParameter('report_type'); + if ($this->getRequest()->getMethod() == sfRequest::GET) + { + $artworks_res = ReaktorArtworkPeer::doSelect($crit); + if ($artworks_res && $this->report_type == 1) + { + $this->num_artworks = count($artworks_res); + $this->diff = 0; + foreach ($artworks_res as $artwork) + { + $artwork = new genericArtwork($artwork); + if ($artwork->getActionedBy(true) != 0) + { + $this->diff += (strtotime($artwork->getActionedAt()) - strtotime($artwork->getSubmittedAt())); + } + } + $this->diff = ($this->diff / $this->num_artworks); + } + else + { + $this->artworks = array(); + foreach ($artworks_res as $artwork) + { + $this->artworks[] = new genericArtwork($artwork); + } + } + } + } + + /** + * executes user report page + * + * @return null + */ + public function executeUserReports() + { + $interests = Subreaktor::getAll(); + $this->interests = array(0 => sfContext::getInstance()->getI18n()->__("Any")); + + foreach ($interests as $interest) + { + $this->interests[$interest->getId()] = $interest->getName(); + } + + $residences = ResidencePeer::doSelect(new Criteria()); + $this->residences = array(); + + foreach ($residences as $residence) + { + $this->residences[$residence->getId()] = $residence->getName(); + } + + $this->report_types = array(0 => $this->getContext()->getI18n()->__('Most active users uploading'), + 1 => $this->getContext()->getI18n()->__('Most active users commenting')); + + // Has a report been submitted? + switch ($this->getRequestParameter("execute")) + { + case "userReport": + $this->_executeUserReportsQuery(); + break; + case "activityReport": + $this->_executeUserActivityReportsQuery(); + break; + default: + //Nothing to process + break; + } + } + + /** + * Show a list of bookmarked reports + * + * @return null - render the template + */ + public function executeShowBookmarks() + { + // Get all the bookmarked reports + $this->groupedReports = ReportBookmarkPeer::getAllGroupedByType(); + } + + /** + * executes user report query + * + * @return null - just passes the required output to the template + */ + protected function _executeUserReportsQuery() + { + $args = array(); + + $args["startDateArr"] = $this->getRequestParameter('startDateArr'); + $args["endDateArr"] = $this->getRequestParameter('endDateArr'); + $args["interest"] = $this->getRequestParameter('interest'); + $args["residence"] = $this->getRequestParameter('residence'); + $args["sex"] = $this->getRequestParameter('sex'); + if($this->getRequestParameter('activated_check')=='1') + $args["activated"] = ($this->getRequestParameter('activatedYesNo')=='0' ? false : true ); + if($this->getRequestParameter('verified_check')=='1') + $args["verified"] = ($this->getRequestParameter('verifiedYesNo')=='0' ? false : true ); + if($this->getRequestParameter('showContent_check')=='1') + $args["showContent"] = ($this->getRequestParameter('showContentYesNo')=='0' ? false : true ); + // Check the above to see if we should process them (have their corresponding checkboxes been checked?) + foreach ($args as $key => $arg) + { + if (!$this->getRequestParameter($key."_check")) + { + unset ($args[$key]); + } + } + + $args["publishedArtwork"] = $this->getRequestParameter('publishedArtwork'); + $args["notPublishedArtwork"] = $this->getRequestParameter('notPublishedArtwork'); + $args["commentedArtwork"] = $this->getRequestParameter('commentedArtwork'); + $args["notCommentedArtwork"] = $this->getRequestParameter('notCommentedArtwork'); + $args["voted"] = $this->getRequestParameter('voted'); + $args["notVoted"] = $this->getRequestParameter('notVoted'); + $args["commentAndOr"] = $this->getRequestParameter('commentAndOr'); + $args["voteAndOr"] = $this->getRequestParameter('voteAndOr'); + + // If current month is checked we can generate the start and end dates automatically + if ($this->getRequestParameter("current_month_check")) + { + $args["startDateArr"]["year"] = date("Y"); + $args["startDateArr"]["month"]= date("m"); + $args["startDateArr"]["day"] = "01"; + $args["endDateArr"]["year"] = date("Y"); + $args["endDateArr"]["month"] = date("m"); + $args["endDateArr"]["day"] = date("t"); + } + + // Strip out null and empty data + foreach ($args as $key => $arg) + { + if (!$arg && !is_bool($arg)) + { + unset ($args[$key]); + } + } + + if (isset($args["startDateArr"]) && isset($args["startDateArr"]['day']) + && isset($args["startDateArr"]['month']) && isset($args["startDateArr"]['year'])) + { + $args['startDate'] = $args["startDateArr"]['year']."-".$args["startDateArr"]['month']."-".$args["startDateArr"]['day']; + } + + if (isset($args["endDateArr"]) && isset($args["endDateArr"]['day']) && isset($args["endDateArr"]['month']) + && isset($args["endDateArr"]['year'])) + { + $args['endDate'] = $args["endDateArr"]['year']."-".$args["endDateArr"]['month']."-".$args["endDateArr"]['day']; + } + $this->resultset = sfGuardUserPeer::reportQuery($args); + } + + /** + * Execute the user activity report query + * + * @return null - just passes the required output to the template + */ + protected function _executeUserActivityReportsQuery() + { + $startActivityDateArr = $this->getRequestParameter('startActivityDate'); + $endActivityDateArr = $this->getRequestParameter('endActivityDate'); + $startActivityDate = ""; + $endActivityDate = ""; + $sex = $this->getRequestParameter('sex'); + $subreaktor = $this->getRequestParameter('subreaktor'); + + // If current month is checked we can generate the start and end dates automatically + if ($this->getRequestParameter("current_month_activity_check")) + { + $startActivityDateArr["year"] = date("Y"); + $startActivityDateArr["month"]= date("m"); + $startActivityDateArr["day"] = "01"; + $endActivityDateArr["year"] = date("Y"); + $endActivityDateArr["month"] = date("m"); + $endActivityDateArr["day"] = date("t"); + } + + if ($startActivityDateArr['day'] && $startActivityDateArr['month'] && $startActivityDateArr['year']) + { + $startActivityDate = $startActivityDateArr['year']."-".$startActivityDateArr['month']."-".$startActivityDateArr['day']; + } + if ($endActivityDateArr['day'] && $endActivityDateArr['month'] && $endActivityDateArr['year']) + { + $endActivityDate = $endActivityDateArr['year']."-".$endActivityDateArr['month']."-".$endActivityDateArr['day']; + } + switch ($this->getRequestParameter('reportType')) + { + case 0: + $this->res = sfGuardUserPeer::getMostActiveUsers(20, $startActivityDate, $endActivityDate, $subreaktor, $sex); + break; + case 1: + $this->res = sfGuardUserPeer::getMostCommentingUsers(20, $startActivityDate, $endActivityDate, $subreaktor, $sex); + break; + default: + $this->res = array(); + break; + } + } + + /** + * Ajax function for saving new bookmark + * + * @return null - renders the ajax response + */ + public function executeSaveNewBookmark() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && $this->getUser()->hasCredential("viewreports")); + $queryArray = explode("?", $this->getRequestParameter("url")); + + $this->forward404Unless(isset($queryArray[1])); + $queryString = $queryArray[1]; + + //Create a restful URI + $url_parameters = $this->getController()->convertUrlStringToParameters('admin/reports?'.$queryString); + + $url = ''; + foreach ($url_parameters[1] as $key => $value) + { + if($value && $key != 'action' && $key != 'module' + && $key != 'sf_culture' && $key != 'commit' + && $key != 'report_type' && $value != '0') + { + $url.= '/'.$key.'/'.$value; + } + + } + $queryString = $url; + + // Time to create the new report bookmark + $newReport = new ReportBookmark(); + $newReport->setTitle($this->getRequestParameter("title")); + $newReport->setDescription($this->getRequestParameter("description")); + $newReport->setArgs($queryString); + $newReport->setType($this->getRequestParameter("type")); + $newReport->save(); + + // Don't want to spend time on validation, so we'll go for a default title instead + if (!trim($newReport->getTitle())) + { + $newReport->setTitle(sfContext::getInstance()->getI18N()->__("Untitled report %report_id%", array("%report_id%" => $newReport->getId()))); + $newReport->save(); + } + + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_partial("reports/savedReportBlock", array("savedReport" => $newReport, "type" => $this->getRequestParameter("type")))); + } + + /** + * Ajax function to update the priority order of bookmarked reports + * + * @return null - renders an appropriate response + */ + public function executeUpdateBookmarkOrder() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && $this->getUser()->hasCredential("viewreports")); + + // Loop through all the posted data to find any sort lists + // This means we can potentially sort any type of report and handle it automatically + // There are multiple sorted lists on the same page which all use this action, so they have different IDs + foreach ($this->getRequest()->getParameterHolder()->getNames() as $param) + { + if (strpos($param, "sort_") !== false) + { + $sortValues = $this->getRequestParameter($param); + } + } + foreach ($sortValues as $sortOrder => $reportId) + { + $reportBookmark = ReportBookmarkPeer::retrieveByPK($reportId); + $reportBookmark->setListOrder($sortOrder); + $reportBookmark->save(); + } + return true; + } + + /** + * Delete a report via ajax + * + * @return null + */ + public function executeDeleteReport() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && $this->getUser()->hasCredential("viewreports")); + + $bookmarkToDelete = ReportBookmarkPeer::retrieveByPK($this->getRequestParameter("id")); + if ($bookmarkToDelete) + { + $bookmarkToDelete->Delete(); + } + + //For debug if someone is looking at the ajax response + return $this->renderText("deleted report ".($this->getRequestParameter("id") ? $this->getRequestParameter("id") : "none")); + } +} diff --git a/apps/reaktor/modules/reports/actions/components.class.php b/apps/reaktor/modules/reports/actions/components.class.php new file mode 100644 index 0000000..4fd0733 --- /dev/null +++ b/apps/reaktor/modules/reports/actions/components.class.php @@ -0,0 +1,91 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Components for reporting + * + * PHP Version 5 + * + * @author Russ + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class reportsComponents extends sfComponents +{ + /** + * Generate the result graph + * + * @return null + */ + function executeResultGraph() + { + + } + + /** + * Show a list of reports that are relevant to this report page + * + * @return null + */ + function executeSavedReportsFloatBox() + { + // If a value has been posted, we should check if it's a report we know about, or offer to save it + if ($this->getRequestParameter("commit")) + { + $queryArray = explode("?", sfRouting::getInstance()->getCurrentInternalUri()); + $queryString = $queryArray[1]; + + //Remove all unnecessary keys before storing + $url_parameters = $this->getController()->convertUrlStringToParameters('admin/reports?'.$queryString); + $url = ''; + foreach ($url_parameters[1] as $key => $value) + { + if($value && $key != 'action' && $key != 'module' + && $key != 'sf_culture' && $key != 'commit' + && $key != 'report_type' && $value != '0' ) + { + $url.='/'.$key.'/'.$value; + } + } + $queryString = $url; + + // Now we take a look in the DB to see if we already have an identical report + $c = new Criteria(); + $c->add(ReportBookmarkPeer::ARGS, $queryString); + $savedReport = ReportBookmarkPeer::doSelectOne($c); + } + else + { + $savedReport = false; + } + + // Get all the reports up to the limit in config, except the one we are looking at from the query above + $c = new Criteria(); + $c->setLimit(sfConfig::get("app_reports_bookmarks_to_show", 6)); + $c->addAscendingOrderByColumn(ReportBookmarkPeer::LIST_ORDER); + $c->add(ReportBookmarkPeer::TYPE, $this->type); + if ($savedReport) + { + $c->add(ReportBookmarkPeer::ID, $savedReport->getId(), Criteria::NOT_EQUAL); + } + + $bookmarks = ReportBookmarkPeer::doSelect($c); + + $this->report_title=$this->getContext()->getI18N()->__('artwork', '', 'messages'); + $this->report_type=$this->getContext()->getI18N()->__($this->type,'',''); + + // Send the required values to the template + $this->bookmarks = $bookmarks; + $this->savedReport = $savedReport; + } +} diff --git a/apps/reaktor/modules/reports/config/security.yml b/apps/reaktor/modules/reports/config/security.yml new file mode 100644 index 0000000..55d8295 --- /dev/null +++ b/apps/reaktor/modules/reports/config/security.yml @@ -0,0 +1,3 @@ +all: + is_secure: on + credentials: [viewreports] #OR diff --git a/apps/reaktor/modules/reports/templates/_resultGraph.php b/apps/reaktor/modules/reports/templates/_resultGraph.php new file mode 100644 index 0000000..8ba503a --- /dev/null +++ b/apps/reaktor/modules/reports/templates/_resultGraph.php @@ -0,0 +1,36 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + + + +
      +

      +
        + $data): ?> +
      • + ":" " ?> + ".__('to')."
        ":"" ?> + ":"" ?> +
      • + + +
      +
      + diff --git a/apps/reaktor/modules/reports/templates/_savedReportBlock.php b/apps/reaktor/modules/reports/templates/_savedReportBlock.php new file mode 100644 index 0000000..07f0659 --- /dev/null +++ b/apps/reaktor/modules/reports/templates/_savedReportBlock.php @@ -0,0 +1,47 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript", 'wai'); +?> + + +

      +

      + getTitle(); ?> + url_for("@".$type."reports").$savedReport->getArgs()."/commit/generate_report/report_type/1")) ?> + url_for("@".$type."reports").$savedReport->getArgs()."/commit/generate_report/report_type/2"))." ]" ?> +

      + + 'report_save_box', + 'url' => '@reportBookmarkSave')); ?> +

      +
      + + +
      + + "20x3")); ?> +
      +

      + +

      +
      + getCurrentInternalUri())?> + + + diff --git a/apps/reaktor/modules/reports/templates/_savedReportsFloatBox.php b/apps/reaktor/modules/reports/templates/_savedReportsFloatBox.php new file mode 100644 index 0000000..dc6fd2e --- /dev/null +++ b/apps/reaktor/modules/reports/templates/_savedReportsFloatBox.php @@ -0,0 +1,51 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript"); +?> + +
      +

      $report_type)); ?>

      + 0): ?> +
        + +
      • + getTitle(); ?> + url_for("@".$type."reports").$bookmark->getArgs()."/commit/generate_report/report_type/1", + "label" => __("This report - %report_title% (stats view)", array("%report_title%" => htmlentities($bookmark->getTitle()))) + )); ?> + url_for("@".$type."reports").$bookmark->getArgs()."/commit/generate_report/report_type/2", + "label" => __("This report - %report_title% (list view)", array("%report_title%" => htmlentities($bookmark->getTitle()))) + ))." ]"; ?> +
      • + +
      + +

      + +

      + get("commit")): ?> +
      + $savedReport, "type" => $type)); ?> +
      + +
      diff --git a/apps/reaktor/modules/reports/templates/_userActivityReportsQuery.php b/apps/reaktor/modules/reports/templates/_userActivityReportsQuery.php new file mode 100644 index 0000000..c30c5d3 --- /dev/null +++ b/apps/reaktor/modules/reports/templates/_userActivityReportsQuery.php @@ -0,0 +1,28 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('User activity reports')); +?> + + +
        + +
      • + +
      + + + + $res['graphData'], 'dateData' => $res['dateData'])); ?> + \ No newline at end of file diff --git a/apps/reaktor/modules/reports/templates/_userReportsQuery.php b/apps/reaktor/modules/reports/templates/_userReportsQuery.php new file mode 100644 index 0000000..aaff69a --- /dev/null +++ b/apps/reaktor/modules/reports/templates/_userReportsQuery.php @@ -0,0 +1,28 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + +
      + get("report_type") == 1): ?> + : + + + getUsername(),'@portfolio?user='.$res->getUsername()) ?>
      + + + + $resultset['graphData'], 'dateData' => $resultset['dateData'])); ?> + +
      \ No newline at end of file diff --git a/apps/reaktor/modules/reports/templates/artworkReportsSuccess.php b/apps/reaktor/modules/reports/templates/artworkReportsSuccess.php new file mode 100644 index 0000000..9e1a0f0 --- /dev/null +++ b/apps/reaktor/modules/reports/templates/artworkReportsSuccess.php @@ -0,0 +1,136 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'seconds', 'wai'); +reaktor::setReaktorTitle(__('Artwork reports')); + +?> + + "artwork")); ?> +
      + +

      +

      +

      + + "get")); ?> +
      +
      + + +
      + +
      +
      + + +
      + +
      +
      + + +
      +
      +
      + + +
      + +
      +
      + + +
      + +
      +
      + + +
      + __('Awaiting approval'), '3' => __('Approved'), '4' => __('Rejected'), '5' => __('Removed')), $status_value)); ?> +
      + + +
      +
      + get('from_date_check'), array("onclick" => "$('current_month_check').checked=false;")); ?> + +
      + false, + 'culture' => $sf_user->getCulture(), + 'year_end' => date('Y'), + 'year_start' => 2004, + 'date_seperator' => ' ', + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) + )); ?> +
      + +
      + get('to_date_check'), array("onclick" => "$('current_month_check').checked=false;")); ?> + +
      + + false, + 'culture' => $sf_user->getCulture(), + 'year_end' => date('Y'), + 'year_start' => 2004, + 'date_seperator' => ' ', + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) + )); ?> +
      +
      + get("current_month_check"), + array("onclick" => "$('to_date_check').checked=false;$('from_date_check').checked=false;")); ?> + +
      +

      + +
      + +
      + __('Statistics'), '2' => __('Artwork list')), $report_type)); ?> + +
      + +
      + + +
      + +
      +
      + +

      + $num_artworks)); ?> + 1): ?> +

      + + $avg_time['weeks'], '%days%' => $avg_time['days'], '%hours%' => $avg_time['hours'])); ?> + + +

      +
        + +
      • + getUser()->getNamePrivate())&&($artwork->getUser()->getName() != '')) ? $artwork->getUser()->getName() : $artwork->getUser()->getUsername(); ?> + '' . link_to($artwork->getTitle(), $artwork->getLink()) . '', + '%username%' => '' . reaktor_link_to($displayname, '@portfolio?user=' . $artwork->getUser()->getUsername()) . '')); ?> +
      • + +
      + +
      + diff --git a/apps/reaktor/modules/reports/templates/indexSuccess.php b/apps/reaktor/modules/reports/templates/indexSuccess.php new file mode 100644 index 0000000..e69de29 diff --git a/apps/reaktor/modules/reports/templates/showBookmarksSuccess.php b/apps/reaktor/modules/reports/templates/showBookmarksSuccess.php new file mode 100644 index 0000000..eb39caa --- /dev/null +++ b/apps/reaktor/modules/reports/templates/showBookmarksSuccess.php @@ -0,0 +1,75 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript"); + +?> +
      +

      +
        +
      • +
      • +
      +
      + +
      +

      +

      + +

      +
      + $reportGroup): ?> + + +

      + + +

      + + + +

      ucfirst(__($groupName)))); ?>

      + + +
        + +
      • +

        getTitle(); ?>

        +

        getDescription(); ?>

        + + url_for("@".$groupName."reports").$report->getArgs()."/commit/generate_report/report_type/1", + "label" => $report->getTitle()." stats" + )); ?> + url_for("@".$groupName."reports").$report->getArgs()."/commit/generate_report/report_type/2", + "label" => $report->getTitle()." list" + )); ?> + '@deletereport?id='.$report->getId(), + 'success' => "$('report_".$report->getId()."').hide();".visual_effect('highlight', 'sort_'.$groupName), + "confirm" => __("Delete '%report_title%'?", array("%report_title%" => $report->getTitle()))))." ]"; ?> + +
      • + +
      + 'reports/updateBookmarkOrder', + 'success' => visual_effect('highlight', 'sort_'.$groupName) + )); ?> + +
      diff --git a/apps/reaktor/modules/reports/templates/userReportsSuccess.php b/apps/reaktor/modules/reports/templates/userReportsSuccess.php new file mode 100644 index 0000000..48f00d9 --- /dev/null +++ b/apps/reaktor/modules/reports/templates/userReportsSuccess.php @@ -0,0 +1,254 @@ + + + "user")); ?> + +
      " id="query_generator"> +

      +

      +

      +
      +
      get("execute") == "activityReport") echo "style = 'display:none;'"; ?>> + "get")); ?> +
      +
      + get("residence_check")); ?> + +
      + get("residence"))); ?> + + get("residence"), array( + 'include_custom' => __('Choose a residence'), + ))); ?> +
      + +
      + get("interest_check")); ?> + +
      + get("interest"))); ?> +
      + +
      + get("sex_check")); ?> + +
      + __('Male'), 2 =>__('Female')), $sf_params->get("sex"))); ?> +
      + +
      + get("startDateArr_check"), array("onclick" => "$('current_month_check').checked=false;")); ?> + +
      + get("startDateArr", ""), array( + 'rich' => false, + 'culture' => $sf_user->getCulture(), + 'year_end' => date('Y')-sfConfig::get('app_profile_max_age',100), + 'year_start' => date('Y'), + 'date_seperator' => ' ', + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for date of birth**')."'", + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')), + )); ?> +
      + +
      + get("endDateArr_check"), array("onclick" => "$('current_month_check').checked=false;")); ?> + +
      + get("endDateArr", ""), array( + 'rich' => false, + 'culture' => $sf_user->getCulture(), + 'year_end' => date('Y')-sfConfig::get('app_profile_max_age',100), + 'year_start' => date('Y'), + 'date_seperator' => ' ', + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for date of birth**')."'", + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) + )); ?> +
      + +
      +
      + get("activated_check"), array('id' => 'voted')); ?> + 'inline')); ?> +
      + get("activatedYesNo"))); ?> +
      + +
      + get("verified_check"), array('id' => 'verified')); ?> + 'inline')); ?> +
      + get("verifiedYesNo"))); ?> + + +
      +
      + get("showContent_check"), array('id' => 'showContent')); ?> + 'inline')); ?> +
      + get("showContentYesNo"))); ?> +

      + +
      + get("current_month_check"), + array("onclick" => "$('endDateArr_check').checked=false;$('startDateArr_check').checked=false;")); ?> + +
      +

      + +
      + get("publishedArtwork"), + array('id' => 'publishedArtwork', 'onclick' => '$("notPublishedArtwork").checked = false;')); ?> + +
      +
      + +
      + get("notPublishedArtwork"), + array('id' => 'notPublishedArtwork', 'onclick' => '$("publishedArtwork").checked = false;')); ?> + +
      +

      + + get("commentAndOr"))); ?> +
      +
      + get("commentedArtwork"), + array('id' => 'commentedArtwork', 'onclick' => '$("notCommentedArtwork").checked = false;')); ?> + 'inline')); ?> +
      +
      + +
      + get("notCommentedArtwork"), + array('id' => 'notCommentedArtwork', 'onclick' => '$("commentedArtwork").checked = false;')); ?> + 'inline')); ?> +
      + +

      + + get("voteAndOr"))); ?> +
      +
      + get("voted"), + array('id' => 'voted', 'onclick' => '$("notVoted").checked = false;')); ?> + 'inline')); ?> +
      +
      + +
      + get("notVoted"), + array('id' => 'notVoted', 'onclick' => '$("voted").checked = false;')); ?> + 'inline')); ?> +
      + +

      + +
      + +
      + __('Statistics'), '2' => __('User list')), $sf_params->get("report_type"))); ?> + +
      + + +
      +
      + +
      get("execute") != "activityReport") echo "style = 'display:none;'"; ?>> + "get")); ?> + +
      + +
      + get("reportType"))); ?> +
      + +
      + +
      + get("subreaktor"))); ?> +
      + +
      + +
      + __('Both'), 1 => __('Male'), 2 => __('Female')), $sf_params->get("sex"))); ?> +
      + +
      + +
      + get("startActivityDate", ""), array( + 'rich' => false, + 'culture' => $sf_user->getCulture(), + 'year_end' => date('Y')-sfConfig::get('app_profile_max_age',100), + 'year_start' => date('Y'), + 'date_seperator' => ' ', + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for date of birth**')."'", + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) + ))?> +
      + +
      + +
      + get("endActivityDate", ""), array( + 'rich' => false, + 'culture' => $sf_user->getCulture(), + 'year_end' => date('Y')-sfConfig::get('app_profile_max_age',100), + 'year_start' => date('Y'), + 'date_seperator' => ' ', + 'onblur' => "$('information_msg').innerHTML='".__('**help-text when no field is selected**')."'", + 'onfocus' => "$('information_msg').innerHTML='".__('**help-text for date of birth**')."'", + 'include_custom' => array('day'=>__('Day'), 'month'=>__('Month'), 'year'=>__('Year')) + )); ?> +
      +
      + get("current_month_activity_check"), + array("onclick" => "$('endActivityDate_check').checked=false;$('startActivity_check').checked=false;")); ?> + +
      +

      + + + + +
      +
      + +get("execute")): ?> +
      + +
      +
      +

      :

      + get("execute") == "userReport"): ?> + $resultset)); ?> + get("execute") == "activityReport"): ?> + $res)); ?> + +
      + diff --git a/apps/reaktor/modules/residence/actions/actions.class.php b/apps/reaktor/modules/residence/actions/actions.class.php new file mode 100644 index 0000000..b916672 --- /dev/null +++ b/apps/reaktor/modules/residence/actions/actions.class.php @@ -0,0 +1,13 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentActions.class.php'; +require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/sfCommentPeer.php'; +require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'lib/model/sfComment.php'; +require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'apps/reaktor/lib/commentCalendar.class.php'; + + +/** + * Functionality regarding comments, both for frontend and backend. + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class sfCommentActions extends BasesfCommentActions +{ + private + $config, + $config_user, + $config_anonymous; + + /** + * Saves a comment, for an authentified user + */ + public function executeAuthenticatedComment() + { + $this->getConfig(); + + if ((sfContext::getInstance()->getUser()->isAuthenticated() + && $this->config_user['enabled']) + && $this->getRequest()->getMethod() == sfRequest::POST) + { + if (!$this->getUser()->hasCredential('postnewcomments')) + { + return; + } + $token = $this->getRequestParameter('sf_comment_object_token'); + $object = sfPropelActAsCommentableToolkit::retrieveFromToken($token); + $comment = array('text' => htmlspecialchars(urldecode($this->getRequestParameter('sf_comment')))); + $id_method = $this->config_user['id_method']; + $namespace = $this->getRequestParameter('sf_comment_namespace', null); + $this->namespace = $namespace; + + $this->validateNamespace($namespace); + + $session = sfContext::getInstance()->getUser(); + $comment['author_id'] = $session->getGuardUser()->getId(); + $comment['namespace'] = $namespace; + + //HACK: get callables doesn't include title, this is a temporary fix + $comment['title'] = htmlspecialchars(urldecode($this->getRequestParameter('sf_comment_title'))); + + foreach (sfMixer::getCallables('sfCommentActions:addComment:pre') as $callable) + { + call_user_func($callable, $comment, $object); + } + + $comment_object = $object->addComment($comment); + $comment_object->setParentId($this->getRequestParameter('comment_parent_id')); + $comment_object->setEmailNotify($this->getRequestParameter('sf_comment_email_notify')); + $comment_object->save(); + HistoryPeer::logAction(12, $this->getUser()->getId(), $comment_object); + + foreach (sfMixer::getCallables('sfCommentActions:addComment:post') as $callable) + { + call_user_func($callable, $comment_object, $object); + } + + $this->object = $object; + + //get parent to see if we shall notify anyone + if ($parent_id = $this->getRequestParameter('comment_parent_id')) + { + $parent = sfCommentPeer::retrieveByPk($parent_id); + /* + * Email: http://www.symfony-project.org/cookbook/1_0/email + */ + if ($parent->getEmailNotify()) + { + global $mail_data; + $mail_data = array('comment' => $comment_object, + 'artwork' => $object, + 'parent' => $parent); + $raw_email = $this->sendEmail('mail', 'sendCommentNotification'); + $this->logMessage($raw_email, 'debug'); + } + } + + if (!$this->getContext()->getRequest()->isXmlHttpRequest()) + { + $this->redirect($this->getRequestParameter('sf_comment_referer')); + } + } + + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_component('sfComment', 'commentList', array('object' => $object, 'namespace' => $namespace)). + '
      '. + get_component('sfComment', 'commentForm', array('object' => $object, 'namespace' => $namespace)). + '
      '); + //$this->setTemplate('comment'); + } + + protected function getConfig() + { + $config_anonymous = array('enabled' => true, + 'layout' => array('name' => 'required', + 'email' => 'required', + 'title' => 'optional', + 'comment' => 'required'), + 'name' => 'Anonymous User'); + $config_user = array('enabled' => true, + 'layout' => array('title' => 'optional', + 'comment' => 'required'), + 'table' => 'sf_guard_user', + 'id' => 'id', + 'class' => 'sfGuardUser', + 'id_method' => 'getUserId', + 'toString' => 'toString', + 'save_name' => false); + + $this->config_anonymous = sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_anonymous', $config_anonymous); + $this->config_user = sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_user', $config_user); + + $config = array('user' => $this->config_user, + 'anonymous' => $this->config_anonymous, + 'use_ajax' => sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_use_ajax', false), + 'namespaces' => sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_namespaces', false)); + $this->config = $config; + } + + /** + * List comments within a period of time + * + */ + public function executeListComments() + { + $comment_object = 'ReaktorArtwork'; + $namespace = 'frontend'; + $this->comments = array(); + $this->namespace = $namespace; + if ($this->getRequestParameter("subreaktor")) + { + $subRoute = "subreaktor=".$this->getRequestParameter("subreaktor")."&"; + } + else + { + $subRoute = ""; + } + + if ($this->getRequestParameter('username') + && $this->getRequestParameter('username') === $this->getUser()->getGuardUser()->getUsername() + || $this->getUser()->hasCredential("commentadmin")) + { + $this->thisUser = $this->getRequestParameter('username'); + $this->route = '@'.sfRouting::getInstance()->getCurrentRouteName().'?'.$subRoute.'username='.$this->getRequestParameter('username'); + + $this->userId = sfGuardUserPeer::getByUsername($this->getRequestParameter('username')); + $this->comment_pager = sfCommentPeer::getCommentsByUser($this->userId, $comment_object, $namespace, $this->getRequestParameter("page", 1)); + }else + { + $this->forward404(); + } + + if ($this->getRequestParameter('user_id')) + { + if ($thisUser = sfGuardUserPeer::retrieveByPK($this->getRequestParameter('user_id'))) + { + $this->thisUser = $thisUser->getUsername(); + $this->route = '@'.sfRouting::getInstance()->getCurrentRouteName().'?'.$subRoute.'user_id='.$this->getRequestParameter('user_id'); + } + else + { + return $this->forward404(); + } + $this->comment_pager = sfCommentPeer::getCommentsByUser($this->getRequestParameter('user_id'), $comment_object, $namespace, $this->getRequestParameter("page", 1)); + } + elseif (!$this->getRequestParameter('username')) + { + $date = $this->getRequestParameter('date') ? $this->getRequestParameter('date') : date('Y-m-d'); + $this->comment_pager = sfCommentPeer::getCommentsByDate($comment_object, $namespace, $date, $this->getRequestParameter("page", 1)); + $this->date = date("d/m/Y", strtotime($date)); + $this->route = '@'.sfRouting::getInstance()->getCurrentRouteName().'?'.$subRoute.'&date='.$this->getRequestParameter('date'); + } + + $comments = array(); + + foreach ($this->comment_pager->getResults() as $comment_object) + { + $commentId = $comment_object->getId(); + + $comment = $comment_object->toArray(); + $comments[$commentId] = $comment; + $comments[$commentId]["AuthorName"] = $comment_object->getUser()->getUsername(); + $comments[$commentId]["ArtworkTitle"] = $comment_object->getArtwork()->getTitle(); + $comments[$commentId]["ArtworkId"] = $comment_object->getArtwork()->getId(); + $comments[$commentId]['AuthorVisible'] = $comment_object->getUser()->getShowContent(); + } + + $this->unsuitable = 0; + CommentMagick::sortRecursive($comments, $this->comments, -1); + } + + /** + * Updates a comment (Ajax request) + * + */ + public function executeUnsuitableToggle() + { + // Must be an ajax request + if (!$this->getRequest()->isXmlHttpRequest()) + { + die(); + } + + // Check we have the right details and credentials + if ($this->getUser()->isAuthenticated() && $this->getUser()->hasCredential("commentadmin")) + { + try + { + $commentObject = sfCommentPeer::retrieveByPK($this->getRequestParameter("id")); + + switch ($this->getRequestParameter("mode")) + { + case "remove": + $newVal = 2; + break; + case "restore": + $newVal = 0; + } + + $commentObject->setUnsuitable($newVal); + $commentObject->save(); + + $comment["Id"] = $commentObject->getId(); + $comment["Unsuitable"] = $commentObject->getUnsuitable(); + + sfLoader::loadHelpers(array('Partial')); + return $this->renderText(get_partial('sfComment/adminButtons', array("comment" => $comment))); + } + catch (Exception $e) + { + return $this->renderText($e->getMessage()); + } + } + else + { + // No need for nice things - this is a remote request and this user should not be here + die(); + } + } + + /** + * Show calendar overview over when comments are made + * + * @return void + */ + public function executeCommentsCalendar() + { + $date = $this->getRequestParameter('date'); + $date = !$date?date('Y-m-d'):$date; + $c = new commentCalendar('month', $date); + $calendar = $c->getEventCalendar(); + $date_array = explode('-', $date); + $this->prev_month = $c->getCalendar()->beginOfPrevMonth($date_array[2],$date_array[1],$date_array[0], '%Y-%m-%d'); + $this->next_month = $c->getCalendar()->beginOfNextMonth($date_array[2],$date_array[1],$date_array[0], '%Y-%m-%d'); + $this->date = $date; + $this->calendar = $calendar; + } + + /** + * Flag a comment as reported, ajax request + * + * @return unknown + */ + public function executeReport() + { + if(!$this->getRequest()->isXmlHttpRequest()) + { + die(); + } + if(!$this->getUser()->isAuthenticated()) + { + return $this->renderText("Please log in!"); + } + + $id = $this->getRequestParameter('id'); + if($id) + { + $comment = sfCommentPeer::retrieveByPK($id); + $comment->setUnsuitable(1); + $comment->save(); + } + else + { + return $this->renderText("Fail!"); + } + + return $this->renderText("OK!"); + } + + /** + * List reported comments + * + * @return void + */ + public function executeListReportedComments() + { + $this->doUnsuitableList(); + } + + /** + * List unsuitable comments + * + * @return void + */ + public function executeListUnsuitableComments() + { + $this->doUnsuitableList(2); + } + + /** + * Function to remove a lot of code duplication + * + * @param $unsuitable integer Value to check for in unsuitable column in db + * @return void + * + */ + protected function doUnsuitableList($unsuitable = 1) + { + $comment_object = 'ReaktorArtwork'; + $this->namespace = 'frontend'; + $this->comments = array(); + $this->date = $this->getRequestParameter('date') ? $this->getRequestParameter('date') : date('Y-m-d'); + list($year, $month, $day) = split('[/.-]', $this->date); + $this->prev_month = date('Y-m-d', strtotime('-1 month', strtotime($this->date))); + $this->next_month = date('Y-m-d', strtotime('+1 month', strtotime($this->date))); + $this->comment_pager = sfCommentPeer::getCommentsByUnsuitableStatus($comment_object, $this->namespace, $this->getRequestParameter("page", 1), $unsuitable); + //$this->comment_pager = sfCommentPeer::getCommentsByDate($comment_object, $this->namespace, $year.'-'.$month, $this->getRequestParameter("page", 1), $unsuitable); + $this->route = '@'.sfRouting::getInstance()->getCurrentRouteName().'?date='.$this->date; + + // Extract the data into an array - one query gives us all the data we need + foreach ($this->comment_pager->getResults() as $comment_object) + { + $commentId = $comment_object->getId(); + $comment = $comment_object->toArray(); + + $comments[$commentId] = $comment; + $comments[$commentId]['AuthorVisible'] = $comment_object->getUser()->getShowContent(); + $comments[$commentId]["AuthorName"] = $comment_object->getUser()->getUsername(); + $comments[$commentId]["ArtworkTitle"] = $comment_object->getArtwork()->getTitle(); + $comments[$commentId]["ArtworkId"] = $comment_object->getArtwork()->getId(); + } + if (!empty($comments)) + { + CommentMagick::sortRecursive($comments, $this->comments, 0, true); + } + } +} + diff --git a/apps/reaktor/modules/sfComment/actions/components.class.php b/apps/reaktor/modules/sfComment/actions/components.class.php new file mode 100644 index 0000000..9fde2e7 --- /dev/null +++ b/apps/reaktor/modules/sfComment/actions/components.class.php @@ -0,0 +1,116 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsCommentableBehaviorPlugin + */ +class sfCommentComponents extends BasesfCommentComponents +{ + + + public function executeCommentForm() + { + sfContext::getInstance()->getResponse()->addStylesheet('sf_comment'); + $this->getConfig(); + + if ($this->object instanceof sfOutputEscaperObjectDecorator) + { + $object = $this->object->getRawValue(); + } + else + { + $object = $this->object; + } + + $this->object_model = get_class($object); + $this->object_id = $object->getPrimaryKey(); + $this->token = sfPropelActAsCommentableToolkit::addTokenToSession($this->object_model, $this->object_id); + + if ($this->getUser()->isAuthenticated() && $this->config_user['enabled']) + { + $this->action = 'authenticatedComment'; + $this->config_used = $this->config_user; + } + else + { + $this->action = 'anonymousComment'; + $this->config_used = $this->config_anonymous; + } + } + + public function executeCommentList() + { + + $object = $this->object; + $order = $this->order; + $namespace = $this->namespace; + $limit = $this->limit; + + if (!$order) + { + $order = 'asc'; + } + + if (!$namespace) + { + $namespace = null; + } + + if (!$limit) + { + $criteria = null; + } + else + { + $criteria = new Criteria(); + $criteria->setLimit($limit); + } + + $comments = sfCommentPeer::getComments($object, array('order' => $order, 'namespace' => $namespace), $criteria); + //sort comments threaded + $this->comments = array(); + + CommentMagick::sortRecursive($comments,$this->comments); + + + } + + /** + * The latest commented artworks by a user. The comments object + * is a join between comments and artworks. + * + * @return void + */ + public function executeLatestCommentedArtworksByUser() + { + $this->comments = sfComment::getLatestCommented($this->user_id); + } + + /** + * List the latest comments made to user or reaktor + * + * + */ + public function executeCommentTitleList() + { + if($this->mode == 'written') + { + $this->comments = sfComment::getLatestWrittenComments($this->user_id); + } + elseif($this->mode =='reaktor') + { + $this->comments = sfComment::getReaktorsLatestComments($this->subreaktor, 5, $this->lokalreaktor); + } + else + { + $this->comments = sfComment::getLatestReceivedComments($this->user_id); + } + + } + +} diff --git a/apps/reaktor/modules/sfComment/config/security.yml b/apps/reaktor/modules/sfComment/config/security.yml new file mode 100644 index 0000000..c2cf527 --- /dev/null +++ b/apps/reaktor/modules/sfComment/config/security.yml @@ -0,0 +1,5 @@ +listComments: + is_secure: off +report: + is_secure: off + diff --git a/apps/reaktor/modules/sfComment/templates/_adminButtons.php b/apps/reaktor/modules/sfComment/templates/_adminButtons.php new file mode 100644 index 0000000..dd01e4b --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/_adminButtons.php @@ -0,0 +1,52 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper("Javascript", "button"); + +if ($comment['Unsuitable'] == 2) +{ + $restoreText = __("Restore this comment"); +} +else +{ + $restoreText = __("Mark comment ok"); +} +$num_comments = isset($comment_pager)?$comment_pager->getNbResults()-1:0; +?> +
      " style = "display: inline"> + + 'sfComment/unsuitableToggle?mode=remove&id='.$comment['Id'], + 'complete'=> "$('comment_header_total').innerHTML = '".__('Total %number_of_comments% comments', array('%number_of_comments%' => $num_comments))."'; Effect.BlindUp('sf_comment_".$comment['Id']."'); $('delete_button_".$comment['Id']."').value='".__("Restore comment")."'; ", + 'confirm' => __("Mark this comment unsuitable?"), + 'update' => "admin_buttons_".$comment["Id"] + ), array("id" => "delete_button_".$comment['Id']))?> + + 'sfComment/unsuitableToggle?mode=restore&id='.$comment['Id'], + 'complete'=> "Effect.BlindDown('sf_comment_".$comment['Id']."'); + $('delete_button_".$comment['Id']."').value='".__("Remove comment")."'; + $('message_".$comment['Id']."').hide();", + 'confirm' => __("Restore this comment?"), + 'update' => "admin_buttons_".$comment["Id"] +), array("id" => "restore_button_".$comment['Id']))?> + + + 'sfComment/unsuitableToggle?mode=restore&id='.$comment['Id'], + 'complete'=> "$('delete_button_".$comment['Id']."').value='".__("Remove comment")."'; + $('message_".$comment['Id']."').hide();", + 'confirm' => __("Remove the flag on this comment?"), + 'update' => "admin_buttons_".$comment["Id"] +), array("id" => "flagok_button_".$comment['Id']))?> + + +
      diff --git a/apps/reaktor/modules/sfComment/templates/_commentButtons.php b/apps/reaktor/modules/sfComment/templates/_commentButtons.php new file mode 100644 index 0000000..9833d35 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/_commentButtons.php @@ -0,0 +1,20 @@ +isAuthenticated()): ?> + + + + + hasCredential('postnewcomments')): ?> + isAuthenticated()) ?> + isAuthenticated()) ?> + + isAuthenticated()); ?> + isAuthenticated()); ?> + + + + 'sfComment/report?id='.$comment['Id'], +'complete'=> "$('report_button_".$comment['Id']."').value='reported';$('report_button_".$comment['Id']."').disable();", +'confirm' => __("Report this comment to a moderator?")), + array("id" => "report_button_".$comment['Id']),$sf_user->isAuthenticated())?> + diff --git a/apps/reaktor/modules/sfComment/templates/_commentForm.php b/apps/reaktor/modules/sfComment/templates/_commentForm.php new file mode 100644 index 0000000..af32853 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/_commentForm.php @@ -0,0 +1,136 @@ + $object, 'namespace' => $namespace, 'parentId' => $comment['Id'])) + * - $object The article object the comment should be added to + * - $namespace This is either 'frontend' or 'admin', comments can be added by users, but an artwork can also be discussed by admin users. + * - $parentId The comments can be nested, in a list, if replying to a thread, the parent Id is needed + * + * The controller has the possibility to pass the following information: + * + * The following are configuration data from REAKTOR_ROOT/apps/reaktor/config/app.yml (which fields are required, how to get userinfo etc) + * - $config_user + * - $config_anonymous + * + * Depending on whether the user is logged in or not these are either user or anonymous + * - $config_used: set to either $config_used or $config_anonymous + * - $action: which action to run when submitting form (authenticatedComment or anonymousComment) + * + */ + +/* + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + + + +isAuthenticated() && $config_user['enabled']) + || $config_anonymous['enabled']): ?> + +
      +

      +
      + + 'sf_comment_form', + 'id' => 'sf_comment_form', + 'name' => 'sf_comment_form')); + ?> +
      + hasError('unauthorized')): ?> +
      + getError('unauthorized') ?> +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + + +
      + + +
      + + + +
      +
      + + "display: inline;")); ?> +
      +
      + + getCurrentInternalUri(); + + if ($pathInfoArray['QUERY_STRING'] != '') + { + $referer .= '?'.$pathInfoArray['QUERY_STRING']; + } + ?> + getRequest()->getParameter('sf_comment_referer', $referer)) ?> + + + + + + + + + + + array('success' => 'all_sf_comments_list', 'failure' => 'comment_new'), + 'url' => 'sfComment/'.$action, + 'loading' => "Element.show('sf_comment_ajax_indicator" . $parentId . "')", + 'complete' => "Element.hide('sf_comment_ajax_indicator" . $parentId . "');Element.scrollTo('all_sf_comment_list')", + 'script' => true), + array('class' => 'submit')); + ?> + + + 'submit')) ?> + + + diff --git a/apps/reaktor/modules/sfComment/templates/_commentList.php b/apps/reaktor/modules/sfComment/templates/_commentList.php new file mode 100644 index 0000000..1509048 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/_commentList.php @@ -0,0 +1,149 @@ + $object, 'namespace' => $namespace) + * + * The following parameters can be passed when using the component: + * $object - Usually artwork or file + * $namespace - In Reaktor the two namespaces used are 'frontend' for user comments and 'administration' for discussion + * $limit - How many comments should be displayed in the list + * $order - Order comments by date (desc/asc) + * $unsuitable - Include only comments with the unsuitable flag set to this + * $adminlist - Is this an adminlist or not + * $comment_pager - Which page, if using a pager + * $overview - Boolean, if list is an overview, and not possible to add comments to + * + * This template can be used in an administration list as a partial: + * include_partial('sfComment/commentList', array( + * 'comments' => $comments, + * 'adminlist' => true, + * 'unsuitable' => 2, + * "comment_pager" => $comment_pager)) + * + * The $comment_pager helps make the the list paginated. + * + * The controller passes the following information: + * $comments - An array of sfComment objects + * + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'array', 'comment', 'button'); +?> + +isAuthenticated(); +$count = 0; + + +?> + +
      + +

      $comment_pager->getNbResults())) ?>

      +
      + + +

      + $object->getCommentCount($namespace))) ?> + +   -   + + +

      + +
      + + + + +
        + 0): //Display comments?> + + + +
      • + + $comment, 'adminlist'=> $adminlist, 'unsuitable'=>$unsuitable)) ?> + + + +
        + hasCredential('commentadmin'))): ?> +
        + hasCredential('postnewcomments') && $sf_user->isAuthenticated()): ?> + + + $comment, 'namespace' => $namespace)); ?> + hasCredential("commentadmin")): ?> + $comment, "comment_pager" => (isset($comment_pager) ? $comment_pager : null))); ?> + +
        + + + + +
        + + hasCredential("commentadmin")): ?> +
        + $comment, "comment_pager" => (isset($comment_pager) ? $comment_pager : null))); ?> + + + + + $comment, + 'recursive' => 1, + 'adminlist' => $adminlist, + 'unsuitable'=>$unsuitable, + 'namespace'=>$namespace, + 'object' => $object,)) ?> + + $comment, + 'recursive' => 1, + 'adminlist' => $adminlist, + 'unsuitable'=>$unsuitable)) ?> + + + +
      • + + + + +
      • + +
      • + + $object, 'namespace' => $namespace)) ?> +
      • + +
      + + +
      + + +
      diff --git a/apps/reaktor/modules/sfComment/templates/_commentTitleList.php b/apps/reaktor/modules/sfComment/templates/_commentTitleList.php new file mode 100644 index 0000000..de272c5 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/_commentTitleList.php @@ -0,0 +1,33 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('string'); +?> + + isset($header) ? $header : __('latest comments'), 'slug' => $slug)); ?> +
      + +
        + +
      • + getTitle(),20), $comment->getArtwork()->getLink()."#sf_comment_".$comment->getId())?> +
      • + +
      + + + +
      diff --git a/apps/reaktor/modules/sfComment/templates/_commentView.php b/apps/reaktor/modules/sfComment/templates/_commentView.php new file mode 100644 index 0000000..2496a5a --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/_commentView.php @@ -0,0 +1,66 @@ + + +
      + + hasCredential('commentadmin')):?> +
      ' class = 'message'> + + + + + + + + +
      + + +
      + hasCredential('commentadmin'))): ?> + " . __('This comment has been removed') . "" ?> + + + +
      +
      + hasCredential('commentadmin'))): ?> + + +

      + + + + + + + + + + $toString();*/ + ?> + + date('d.m.y',strtotime($comment['CreatedAt'])), '%time%' => date('H.i',strtotime($comment['CreatedAt']))));?> + + + +

      +

      + hasCredential('commentadmin'))): ?> + + + + + + + + +

      + +
      diff --git a/apps/reaktor/modules/sfComment/templates/_latestCommentedArtworksByUser.php b/apps/reaktor/modules/sfComment/templates/_latestCommentedArtworksByUser.php new file mode 100644 index 0000000..67e12ba --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/_latestCommentedArtworksByUser.php @@ -0,0 +1,28 @@ +getArtwork()->getUserId())->getUsername(); + $slug = $username . "_latest_commented"; + include_partial('feed/rssLink', array('description' => $header, 'slug' => $slug)); +} +?> +
      +

      + +
        + + +
      • + getArtwork()->getTitle(), + '@show_artwork?id='.$comment->getArtwork()->getId().'&title='.$comment->getArtwork()->getTitle()) ?> +
      • + + +
      + + + + +
      + diff --git a/apps/reaktor/modules/sfComment/templates/authenticatedCommentSuccess.php b/apps/reaktor/modules/sfComment/templates/authenticatedCommentSuccess.php new file mode 100644 index 0000000..49ff068 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/authenticatedCommentSuccess.php @@ -0,0 +1,5 @@ + $object, 'namespace' => $namespace)) ?> + + \ No newline at end of file diff --git a/apps/reaktor/modules/sfComment/templates/commentFormSuccess.php b/apps/reaktor/modules/sfComment/templates/commentFormSuccess.php new file mode 100644 index 0000000..2fc03f0 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/commentFormSuccess.php @@ -0,0 +1,3 @@ + $object, 'namespace' => $namespace)); +?> \ No newline at end of file diff --git a/apps/reaktor/modules/sfComment/templates/commentSuccess.php b/apps/reaktor/modules/sfComment/templates/commentSuccess.php new file mode 100644 index 0000000..d1aa284 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/commentSuccess.php @@ -0,0 +1,3 @@ + + + $object, 'namespace' => $namespace)) ?> diff --git a/apps/reaktor/modules/sfComment/templates/commentsCalendarSuccess.php b/apps/reaktor/modules/sfComment/templates/commentsCalendarSuccess.php new file mode 100644 index 0000000..c034dc3 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/commentsCalendarSuccess.php @@ -0,0 +1,49 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + ?> + +

      +
      + + + + + + + + + + + + + + + $event): ?> +

      ' : '

      + + + +
      + + + +
      MonTueWedThuFriSatSun

      '?> +

      + + + + + ' ?> + +

      +
      +
      +>' , 'admin/commentsCalendar?date='.$next_month) ?> diff --git a/apps/reaktor/modules/sfComment/templates/listCommentsSuccess.php b/apps/reaktor/modules/sfComment/templates/listCommentsSuccess.php new file mode 100644 index 0000000..b33f66e --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/listCommentsSuccess.php @@ -0,0 +1,33 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('PagerNavigation'); +reaktor::setReaktorTitle(__('List comments')); + +?> + +
      +

      + + + + ( ) +get('user_id')): ?> + + +

      +
      + +
      + $comments, "adminlist" => true, 'unsuitable' => $unsuitable, 'namespace' => $namespace))?> + +
      + \ No newline at end of file diff --git a/apps/reaktor/modules/sfComment/templates/listReportedCommentsSuccess.php b/apps/reaktor/modules/sfComment/templates/listReportedCommentsSuccess.php new file mode 100644 index 0000000..c0998ec --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/listReportedCommentsSuccess.php @@ -0,0 +1,41 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('PagerNavigation'); +reaktor::setReaktorTitle(__('List reported comments')); + +?> + +
      +

      + +

      +
      + + + $comments, + "adminlist" => true, + 'unsuitable' => 1, + "overview" => true, + "comment_pager" => $comment_pager))?> + + diff --git a/apps/reaktor/modules/sfComment/templates/listUnsuitableCommentsSuccess.php b/apps/reaktor/modules/sfComment/templates/listUnsuitableCommentsSuccess.php new file mode 100644 index 0000000..2a9dbf8 --- /dev/null +++ b/apps/reaktor/modules/sfComment/templates/listUnsuitableCommentsSuccess.php @@ -0,0 +1,39 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper("PagerNavigation"); +reaktor::setReaktorTitle(__('Unsuitable comments')); + +?> + +
      +

      + +

      + + + +
    • + +
    • + +
    • +
    +*/ +?> +
    + + + $comments, "adminlist" => true, 'unsuitable'=>2, "comment_pager" => $comment_pager))?> + + diff --git a/apps/reaktor/modules/sfGuardAuth/actions/actions.class.php b/apps/reaktor/modules/sfGuardAuth/actions/actions.class.php new file mode 100644 index 0000000..bab0350 --- /dev/null +++ b/apps/reaktor/modules/sfGuardAuth/actions/actions.class.php @@ -0,0 +1,97 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +require_once(sfConfig::get('sf_plugins_dir').'/sfGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php'); + +class sfGuardAuthActions extends BasesfGuardAuthActions +{ + public function executeSignin() + { + if ($this->getRequest()->getMethod() == sfRequest::POST) + { + $referer = $this->getRequestParameter('referer') ? $this->getRequestParameter('referer') : "/"; + + $signin_url = sfConfig::get('app_sf_guard_plugin_success_signin_url', $referer); + $languages = CataloguePeer::doSelect(new Criteria()); + + $loggedInUser = $this->getUser()->getGuardUser(); + + // Set the session culture from the db culture when the user has signed in + $this->getUser()->setCulture($loggedInUser->getCulture()); + + //Check if this user needs to go to the profile + if ($loggedInUser->getDobIsDerived() || $loggedInUser->getNeedProfileCheck()) + { + $this->redirect('@profile'); + } + + //Switch the language in the URL (if it exists) with the one from user culture in DB + foreach ($languages as $language) + { + $signin_url = str_replace("sf_culture=".$language->getTargetLang(),"sf_culture=".$this->getUser()->getGuardUser()->getCulture(), $signin_url); + } + + if ($this->getUser()->hasCredential('staff') && strpos($this->getRequestParameter('referer'), "home") !== false) + { + $this->redirect('@admin_home'); + } + // Don't redirect to pages such as profile/activate + elseif (strpos($referer, "profile/") === 0) + { + if (strpos($referer, "profile/portfolio") === false && strpos($referer, "profile/myPage") === false) + { + $this->redirect('@home'); + } + elseif (strpos($referer, "user={$this->getUser()->getUsername()}") === false) + { + $this->redirect('@home'); + } + } + try + { + $this->redirect('' != $signin_url ? $signin_url : '@home'); + } + catch (sfConfigurationException $e) + { + $this->redirect('@home'); + } + + } + + // Do the rest of the stuff provided by sfGuardUser plugin signin function + parent::executeSignin(); + } + + /** + * Doesn't seem like the built in security does the following, so we will + * + * @return null + */ + public function executeSignout() + { + if (sfConfig::get('sf_environment') != 'test') + { + $_SESSION = array(); + session_destroy(); + session_write_close(); + session_regenerate_id(); + } + + $this->getUser()->signOut(); + //XXX: could add logic here, see issue #516 , and example logic in signin function + //$this->redirect($this->getRequest()->getReferer()); + sfLoader::loadHelpers(array("Url", 'subreaktor')); + $this->redirect(reaktor_url_for('@home', true)); + + } + +} diff --git a/apps/reaktor/modules/sfGuardAuth/config/security.yml b/apps/reaktor/modules/sfGuardAuth/config/security.yml new file mode 100644 index 0000000..a72fbc4 --- /dev/null +++ b/apps/reaktor/modules/sfGuardAuth/config/security.yml @@ -0,0 +1,3 @@ +password: + is_secure: off + \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardAuth/lib/validate/reaktorAuth.class.php b/apps/reaktor/modules/sfGuardAuth/lib/validate/reaktorAuth.class.php new file mode 100644 index 0000000..57def77 --- /dev/null +++ b/apps/reaktor/modules/sfGuardAuth/lib/validate/reaktorAuth.class.php @@ -0,0 +1,75 @@ + + * @version SVN: $Id: reaktorAuth.class.php 1343 2008-06-20 08:04:58Z bjori $ + */ +class reaktorAuth extends sfValidator +{ + public function initialize($context, $parameters = null) + { + // initialize parent + parent::initialize($context); + + // set defaults + $this->getParameterHolder()->set('username_error', 'Username or password is not valid.'); + $this->getParameterHolder()->set('password_field', 'password'); + $this->getParameterHolder()->set('remember_field', 'remember'); + $this->getParameterHolder()->set('validated_error', 'The account is not validated.'); + $this->getParameterHolder()->set('verified_error', 'The account has not been verified.'); + + $this->getParameterHolder()->add($parameters); + + return true; + } + + public function execute(&$value, &$error) + { + $password_field = $this->getParameterHolder()->get('password_field'); + $password = $this->getContext()->getRequest()->getParameter($password_field); + + $remember = false; + $remember_field = $this->getParameterHolder()->get('remember_field'); + $remember = $this->getContext()->getRequest()->getParameter($remember_field); + + $username = $value; + + $user = sfGuardUserPeer::retrieveByUsername($username); + // user exists? + if ($user) + { + + // password is ok? + if ($user->checkPassword($password) || $user->getIsActive() == 0 ) + { + // Make sure the account is active and verified + if ($user->getIsActive() == 1 && $user->getIsVerified() == 1) + { + $this->getContext()->getUser()->signIn($user, $remember); + return true; + } + // OK. So we failed, why? + if ($user->getIsVerified() != 1) + { + $error = $this->getParameterHolder()->get('verified_error'); + return false; + } + } + } else { + $user = sfGuardUserPeer::retrieveByUsername($username,0); + if ($user) + { + $error = $this->getParameterHolder()->get('validated_error'); + return false; + } + } + + $error = $this->getParameterHolder()->get('username_error'); + + return false; + } +} diff --git a/apps/reaktor/modules/sfGuardAuth/templates/secureSuccess.php b/apps/reaktor/modules/sfGuardAuth/templates/secureSuccess.php new file mode 100644 index 0000000..1157fb4 --- /dev/null +++ b/apps/reaktor/modules/sfGuardAuth/templates/secureSuccess.php @@ -0,0 +1,15 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__('Access denied')); ?> + +

    \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardAuth/templates/signinSuccess.php b/apps/reaktor/modules/sfGuardAuth/templates/signinSuccess.php new file mode 100644 index 0000000..5200f7c --- /dev/null +++ b/apps/reaktor/modules/sfGuardAuth/templates/signinSuccess.php @@ -0,0 +1,26 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> +
    +get('username')): ?> +

    + +

    + +

    +
    \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardAuth/validate/signin.yml b/apps/reaktor/modules/sfGuardAuth/validate/signin.yml new file mode 100644 index 0000000..b03484f --- /dev/null +++ b/apps/reaktor/modules/sfGuardAuth/validate/signin.yml @@ -0,0 +1,18 @@ +methods: + post: [username, password] + +names: + username: + required: true + required_msg: Username required + validators: [userValidator] + + password: + required: true + required_msg: Password required + +userValidator: + class: reaktorAuth + param: + password_field: password + remember_field: remember \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardGroup/config/generator.yml b/apps/reaktor/modules/sfGuardGroup/config/generator.yml new file mode 100644 index 0000000..8da5370 --- /dev/null +++ b/apps/reaktor/modules/sfGuardGroup/config/generator.yml @@ -0,0 +1,56 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: sfGuardGroup + theme: default + + list: + title: Group list + display: [id, =name, description, is_editorial_team, is_enabled ] + filters: [ is_editorial_team, is_enabled ] + fields: + is_editorial_team: + name: Editorial team + is_enabled: + name: Enabled + object_actions: + _edit: { action: ~, credentials: editgroup } + _delete: { action: ~, credentials: deletegroup } + actions: + _create: { name: Create new group, action: ~, credentials: editgroup } + + edit: + title: Edit "%%name%%" group + fields: + name: + params: size=20 + name: Group name + description: + name: Group description + is_enabled: + name: Is enabled + is_editorial_team: + name: Is an editorial team + permissions_help: + name: "Information" + help: "Below is a list of permissions that you can give to users in this user group/editorial team. Check each permission you want to apply to this group, then save your changes.

    All users in this user group/editorial team will then automatically inherit the permissions you select below." + permissions: + type: admin_check_list + name: Available permissions + params: through_class=sfGuardGroupPermission + members_help: + name: "Information" + help: "The list to the right contains all the members in this group/team, and the one to the left contains the rest.

    Select one or more users (hold down the CTRL-key to select multiple users), then use the blue arrows between the boxes to move users in or out of the group/team. Remember to save your changes when you're done." + members: + type: admin_double_list + name: Members + params: through_class=sfGuardUserGroup + actions: + _save: { name: Save, action: ~, credentials: editgroup } + _list: { name: Cancel, action: ~, credentials: listgroup } + _delete: { name: Delete group, action: ~, credentials: deletegroup } + display: + "Information": [ name, description ] + "Editorial team settings": [ is_enabled, is_editorial_team ] + "Group/team permissions": [ _permissions_help, permissions ] + "Members": [ _members_help, members ] diff --git a/apps/reaktor/modules/sfGuardGroup/config/security.yml b/apps/reaktor/modules/sfGuardGroup/config/security.yml new file mode 100644 index 0000000..bc30342 --- /dev/null +++ b/apps/reaktor/modules/sfGuardGroup/config/security.yml @@ -0,0 +1,11 @@ +delete: + credentials: deletegroup + +list: + credentials: listgroup + +edit: + credentials: editgroup + +all: + credentials: listgroup \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardGroup/templates/_edit_header.php b/apps/reaktor/modules/sfGuardGroup/templates/_edit_header.php new file mode 100644 index 0000000..c50739b --- /dev/null +++ b/apps/reaktor/modules/sfGuardGroup/templates/_edit_header.php @@ -0,0 +1,15 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +// print_r($this->getContext()); + +?><< 
    +
    \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardGroup/templates/_members_help.php b/apps/reaktor/modules/sfGuardGroup/templates/_members_help.php new file mode 100644 index 0000000..bb65874 --- /dev/null +++ b/apps/reaktor/modules/sfGuardGroup/templates/_members_help.php @@ -0,0 +1,12 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardGroup/templates/_permissions_help.php b/apps/reaktor/modules/sfGuardGroup/templates/_permissions_help.php new file mode 100644 index 0000000..80d3417 --- /dev/null +++ b/apps/reaktor/modules/sfGuardGroup/templates/_permissions_help.php @@ -0,0 +1,12 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardGroup/validate/edit.yml b/apps/reaktor/modules/sfGuardGroup/validate/edit.yml new file mode 100644 index 0000000..3e11d64 --- /dev/null +++ b/apps/reaktor/modules/sfGuardGroup/validate/edit.yml @@ -0,0 +1,27 @@ +methods: + post: + - "sf_guard_group{name}" + - "associated_permissions" + +names: + sf_guard_group{name}: + required: yes + required_msg: Please enter a group name + validators: nameUniqueValidator + + associated_permissions: + required: yes + validators: myMagickArrayValidator + +myMagickArrayValidator: + class: myMagickArrayValidator + param: + min: 1 + min_error: Please select at least one permission + +nameUniqueValidator: + class: sfPropelUniqueValidator + param: + class: sfGuardGroup + column: name + unique_error: This group name already exists diff --git a/apps/reaktor/modules/sfGuardPermission/config/generator.yml b/apps/reaktor/modules/sfGuardPermission/config/generator.yml new file mode 100644 index 0000000..040691a --- /dev/null +++ b/apps/reaktor/modules/sfGuardPermission/config/generator.yml @@ -0,0 +1,45 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: sfGuardPermission + theme: default + + list: + title: Permission list + display: [=name, description] + actions: + _create: { name: Create new specific permission, action: ~, credentials: editpermission } + object_actions: + _edit: { action: ~, credentials: editpermission } + _delete: { action: ~, credentials: deletepermission } + filters: [ name ] + + + edit: + title: Edit "%%name%%" permission + fields: + name: + params: size=20 + description: + credentials: translator + help: "To edit this description, please use the translation interface" + permissions: + type: admin_check_list + name: Groups + params: through_class=sfGuardGroupPermission + help:
    Select which group(s) to have this permission + members_help: + name: "" + help: "Remember that users mainly get their permission(s) from their group/team membership, not from this list.

    The list to the right contains all the users who has this permission explicitly set, and the one to the left contains the rest.

    Select one or more users (hold down the CTRL-key to select multiple users), then use the blue arrows between the boxes to move users. Remember to save your changes when you're done." + members: + type: admin_double_list + name: Users with this permission + params: through_class=sfGuardUserPermission + actions: + _save: { name: Save, action: ~, credentials: editpermission } + _list: { name: Cancel, action: ~, credentials: listpermission } + _delete: { name: Delete permission, action: ~, credentials: deletepermission } + display: + "Information": [ name, description ] + "Groups with this permission": [ permissions ] + "Users with this permission explicitly set": [ _members_help, members ] diff --git a/apps/reaktor/modules/sfGuardPermission/config/security.yml b/apps/reaktor/modules/sfGuardPermission/config/security.yml new file mode 100644 index 0000000..fed298e --- /dev/null +++ b/apps/reaktor/modules/sfGuardPermission/config/security.yml @@ -0,0 +1,15 @@ +delete: + credentials: deletepermission + +list: + credentials: listpermission + +edit: + credentials: editpermission + +update_profile: + is_secure: on + credentials: [ editprofile ] + +all: + credentials: [ listpermission, editprofile ] diff --git a/apps/reaktor/modules/sfGuardPermission/templates/_edit_header.php b/apps/reaktor/modules/sfGuardPermission/templates/_edit_header.php new file mode 100644 index 0000000..cbb7681 --- /dev/null +++ b/apps/reaktor/modules/sfGuardPermission/templates/_edit_header.php @@ -0,0 +1,13 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +?><< 
    +
    \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardPermission/templates/_members_help.php b/apps/reaktor/modules/sfGuardPermission/templates/_members_help.php new file mode 100644 index 0000000..43f5dc1 --- /dev/null +++ b/apps/reaktor/modules/sfGuardPermission/templates/_members_help.php @@ -0,0 +1,12 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/actions/actions.class.php b/apps/reaktor/modules/sfGuardUser/actions/actions.class.php new file mode 100644 index 0000000..0c28a45 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/actions/actions.class.php @@ -0,0 +1,251 @@ + + * @author Ole-Petter Wikene + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +require_once SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'plugins/sfGuardPlugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php'; + +class sfGuardUserActions extends BasesfGuardUserActions +{ + /** + * Send mail to user + * + * @param integer $db_user + */ + public function sendAdminMail($db_user) + { + // + // Create and send e-mail + // + + global $mail_data; + $mail_data = array('user' => $db_user, + 'password' => $this->getRequestParameter('sf_guard_user[password]')); + $raw_email = $this->sendEmail('mail', 'sendProfileRegisteredByAdmin'); + $this->logMessage($raw_email, 'debug'); + + } + + public function sendActivationEmail($sf_guard_user) + { + // + // Create and send e-mail + // + + global $mail_data; + + $mail_data = array('user' => $sf_guard_user, + 'password' => "tjall");//$this->getRequestParameter('password_profile')); + $raw_email = $this->sendEmail('mail', 'sendActivationEmail'); + $this->logMessage($raw_email, 'debug'); + + } + + /** + * Overriding the action used by the admin generator to process user lists + * Added automatic wildcards so searching for "monkey" will now find "monkeyboy" automatically + * + * @return null + */ + public function executeList() + { + //Add fields to auto-wildcard to this list + $wildcardFields = array("username"); + $originalFilters = array(); + + if ($filters = $this->getRequestParameter("filters")) + { + $originalFilters = $filters; + + foreach ($wildcardFields as $fieldName) + { + // Only add the wildcards if the user is not already using them + if (strpos($filters[$fieldName], "*") === false) + { + $filters[$fieldName] = "*".$filters[$fieldName]."*"; + } + } + $this->getRequest()->getParameterHolder()->set("filters", $filters); + + } + parent::executeList(); + // Set the filters back to their original values before the template is rendered + $this->filters = $originalFilters; + + } + + /** + * Redirect the user to comment list view for this user + * This is the only way I can see that we can generate a link via a generated admin + * page, but it works and is clean enough. + * + * @return void + */ + public function executeListComments() + { + $this->redirect("@commentsbyuser?user_id=".$this->getRequestParameter("id")); + } + + public function executeListUsers() + { + $exclude = sfConfig::get("app_userlist_exclude", array()); + // Autocomplete usernames + if ($this->getRequest()->isXmlHttpRequest()) + { + $chars = $this->getRequestParameter("message_to"); + if (!$chars) + { + $chars = $this->getRequestParameter("startingwith"); + if (!$chars) + { + return; + } + } + + $output = ""; + foreach((array)sfGuardUserPeer::getUsernamesStartingWith($chars) as $user) + { + if (!in_array($user->getUsername(), $exclude)) + { + $output .= "
  • " . $user->getUsername() . "
  • "; + } + } + return $this->renderText("
      $output
    "); + } + + $this->users = array(); + $startingwith = ''; + $startingwith = $this->getRequestParameter('startingwith', ''); + if ($startingwith == '') + { + $startingwith = $this->getRequestParameter('tag', ''); + } + if ($startingwith) + { + $this->users = sfGuardUserPeer::getUsernamesStartingWith($startingwith, -1); + } + + foreach ($this->users as $k =>$user) + { + if (in_array($user->getUsername(), $exclude)) + { + unset($this->users[$k]); + } + } + + $this->startingwith = $startingwith; + } + + /** + * Redirect the admin user to portfolio for this user + * + * @return void + */ + public function executeShowPortfolio() + { + $this->redirect("@portfolio?user=".sfGuardUserPeer::retrieveByPK($this->getRequestParameter("id"))->getUsername()); + } + + /** + * Redirect the admin user to the content manage page for this user + * + * @return null + */ + public function executeShowUserContent() + { + $this->redirect("@user_content?mode=menu&user=".sfGuardUserPeer::retrieveByPK($this->getRequestParameter("id"))->getUsername()); + } + + public function executeEdit() + { + if (!($this->getRequestParameter('id') == '' || $this->getUser()->hasCredential('edituser'))) + { + sfActions::forward('sfGuardUser', 'list'); + } + $this->sf_guard_user = $this->getsfGuardUserOrCreate(); + $sendnotify_email = ($this->sf_guard_user->getId() != '') ? false : true; + + if ($this->getRequest()->getMethod() == sfRequest::POST) + { + $this->updatesfGuardUserFromRequest(); + + + $this->savesfGuardUser($this->sf_guard_user); + + if (!$this->getUser()->hasCredential('editprofile')) + { + $this->sendActivationEmail($this->sf_guard_user); + $this->sf_guard_user->setIsActive(false); + $this->sf_guard_user->save(); + $this->setTemplate('newuser'); + } + else + { + if ($sendnotify_email) $this->sendAdminMail($this->sf_guard_user); + + $this->setFlash('notice', 'Your modifications have been saved'); + if ($this->getRequestParameter('save_and_add')) + { + return $this->redirect('sfGuardUser/create'); + } + else if ($this->getRequestParameter('save_and_list')) + { + return $this->redirect('sfGuardUser/list'); + } + else + { + return $this->redirect('sfGuardUser/edit?id='.$this->sf_guard_user->getId()); + } + } + } + else + { + $this->labels = $this->getLabels(); + } + } + + public function validateEdit() + { + if ($this->getRequest()->getMethod() == sfRequest::POST && !$this->getRequestParameter('id')) + { + if ($this->getRequestParameter('sf_guard_user[password]') == '' || $this->getRequestParameter('sf_guard_user[password_bis]') == '') + { + $this->getRequest()->setError('sf_guard_user{password}', 'Password is mandatory'); + $this->getRequest()->setError('sf_guard_user{password_bis}', 'Don\'t forget to verify the password'); + return false; + } + } + return true; + } + + protected function savesfGuardUser($sf_guard_user) + { + // We have to execute the parent first, it drops all the permissions + $retval = parent::savesfGuardUser($sf_guard_user); + + if ($this->getUser()->hasCredential('editprofile')) + { + $ids = $this->getRequestParameter('unassociated_permissions'); + if (is_array($ids)) + { + foreach ($ids as $id) + { + $SfGuardUserPermission = new sfGuardUserPermission(); + $SfGuardUserPermission->setUserId($sf_guard_user->getPrimaryKey()); + $SfGuardUserPermission->setPermissionId($id); + $SfGuardUserPermission->setExclude(1); + $SfGuardUserPermission->save(); + } + } + } + return $retval; + } + +} + diff --git a/apps/reaktor/modules/sfGuardUser/config/generator.yml b/apps/reaktor/modules/sfGuardUser/config/generator.yml new file mode 100644 index 0000000..6a2c73a --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/config/generator.yml @@ -0,0 +1,100 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: sfGuardUser + theme: default + + list: + title: List of users + display: [ =username, created_at, last_login, is_active, is_verified, show_content ] + fields: + is_active: { name: Activated } + is_verified: { name: Verified } + show_content: { name: Shows content } + groups: + type: admin_check_list + params: through_class=sfGuardUserGroup + filters: [ username, email, name, is_active, is_verified, show_content, groups] + object_actions: + _edit: { action: ~, credentials: edituser } + viewcomments: { name: View user comments, action: listComments, icon: user_comment.png } + showprofile: { name: Show user portfolio, action: showPortfolio, icon: icon_profile.png } + showcontent: { name: Manage user content, action: showUserContent, icon: page_find.png } + actions: + _create: { name: Create a new user, action: ~, credentials: edituser } + max_per_page: 20 + + edit: + title: 'Edit %%username%% user' + actions: + _save: { name: Save, action: ~, credentials: edituser } + _list: { name: Cancel, action: ~, credentials: listuser } + _delete: + name: Delete user + action: ~ + credentials: deleteuser + params: confirm=Er du sikker på at du vil slette denne brukeren? + fields: + password: + password_bis: { name: Repeat password } + email: { name: Email address, params: size=30 } + name: { name: Full name, params: size=30 } + dob: { name: Date of birth } + username: + name: Username + params: size=20 + interests: + name: Interests + type: admin_check_list + params: through_class=UserInterest + is_active: + credentials: editprofile + name: Activated + show_content: + name: Show this users content + email_private: + name: Hide email + name_private: + name: Hide full name + is_verified: + name: Verified + #residence_id: + #name: Location + #type: select_tag + #params: related_class=Residence include_custom="Choose residence" + msn: + params: size=30 + credentials: editprofile + icq: + params: size=20 + credentials: editprofile + homepage: + params: size=40 + credentials: editprofile + phone: + params: size=15 + credentials: editprofile + avator: + name: User Avatar + + sex: + params: include_custom="Please select" + groups_help: + name: "" + help: "The user will automatically inherit the permissions defined in the groups you select below.
    If this user is a part of any editorial teams, you should also check them in the list below.

    Tip:
    By hovering over a user group name/editorial team name, you can see which permissions this user group/editorial team gives the user." + groups: { name: "", credentials: editprofile, type: admin_check_list, params: through_class=sfGuardUserGroup } + permissions_help: + name: "" + help: "If a user inherits a permission from a group membership, a green tick will be displayed next to the permission name, and the second checkbox will be enabled. (Note: If you change group membership with the checkboxes above, you must save the changes before you will see the new ticks).

    Use this list only to add or remove permissions in special cases. Usually, group memberships will control what the user can do." + permissions: + name: "" + credentials: editprofile + type: admin_check_list + params: through_class=sfGuardUserPermission + last_login: { type: plain, credentials: editprofile } + display: + "Basic details": [ username, _password, _password_bis, is_active, show_content, email, is_verified, _dob, _sex, _avator, _residence_id ] + "Groups/team membership": [ _groups_help, _groups, _editorial_notification ] + "Optional details": [ email_private, _interests, name, name_private, msn, icq, homepage, phone ] + "Permission settings": [ _permissions_help, _permissions ] + diff --git a/apps/reaktor/modules/sfGuardUser/config/security.yml b/apps/reaktor/modules/sfGuardUser/config/security.yml new file mode 100644 index 0000000..6920439 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/config/security.yml @@ -0,0 +1,18 @@ +delete: + credentials: deleteuser + is_secure: on + +list: + credentials: listuser + is_secure: on + +listUsers: + is_secure: off + +edit: + is_secure: on + credentials: edituser + +all: + credentials: listuser + is_secure: on \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/config/view.yml b/apps/reaktor/modules/sfGuardUser/config/view.yml new file mode 100644 index 0000000..9cb0e46 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/config/view.yml @@ -0,0 +1,2 @@ +all: + javascripts: [prototype, main, inlineupload] \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/templates/_alphaPager.php b/apps/reaktor/modules/sfGuardUser/templates/_alphaPager.php new file mode 100644 index 0000000..4f4281b --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_alphaPager.php @@ -0,0 +1,39 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +$first = true; +?> + +
    + +
    diff --git a/apps/reaktor/modules/sfGuardUser/templates/_avator.php b/apps/reaktor/modules/sfGuardUser/templates/_avator.php new file mode 100644 index 0000000..ec81e15 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_avator.php @@ -0,0 +1,42 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + + +use_helper('wai'); + +if ($sf_params->get('id') && $sf_user->hasCredential("edituser")) +{ + $thisUserId = $sf_params->get('id'); +} +elseif ($sf_user->isAuthenticated()) +{ + $thisUserId = $sf_guard_user->getId(); +} + +if (isset($thisUserId)): +?> + "avatar_label")); ?> +

    + getAvatar()) ? $sf_guard_user->getAvatar() : "default.gif"; +echo ''; +echo ''; +echo ""; +echo '
    '.image_tag(sfConfig::get("app_profile_avatar_url").$avatar_path).'
    '; + + ?> + + + + + diff --git a/apps/reaktor/modules/sfGuardUser/templates/_dob.php b/apps/reaktor/modules/sfGuardUser/templates/_dob.php new file mode 100644 index 0000000..285542b --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_dob.php @@ -0,0 +1,68 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + /* + $date = $sf_guard_user->getDob(); +$date = $date?$date:date('') ; + +echo input_date_tag('sf_guard_user[dob]', $date, array( + 'rich'=>false, + 'culture'=>$sf_user->getCulture(), + 'year_end'=>date('Y'), + 'year_start'=>date('Y')-100, + 'date_seperator'=>'.', + 'include_custom'=> array('day'=>__('--'), 'month'=>__('--'), 'year'=>__('--')))) ; + +*/ + $theday = 0; + $day_arr = array(); + $themonth = 0; + $month_arr = array(); + $theyear = 0; + $year_arr = array(); + + //echo $sf_guard_user->getId(); + + if ($sf_guard_user->getDob() != '') + { + $theday = date('j', strtotime($sf_guard_user->getDob())); + $themonth = date('n', strtotime($sf_guard_user->getDob())); + $theyear = date('Y', strtotime($sf_guard_user->getDob())); + } + + if ($this->getContext()->getRequest()->getError('sf_guard_user{dob}') != '') + { + $theday = 0; + $themonth = 0; + $theyear = 0; + } + + $day_arr[0] = '--'; + for ($cc=1;$cc<=31;$cc++) + { + $day_arr[$cc] = $cc; + } + + $month_arr[0] = '--'; + for ($cc=1;$cc<=12;$cc++) + { + $month_arr[$cc] = date('F', mktime(0, 0, 1, $cc)); + } + + $year_arr[0] = '--'; + for ($cc=date('Y');$cc>=(date('Y') - 100);$cc--) + { + $year_arr[$cc] = $cc; + } + + echo select_tag('sf_guard_user[dob][day]', options_for_select($day_arr, $theday)); + echo select_tag('sf_guard_user[dob][month]', options_for_select($month_arr, $themonth)); + echo select_tag('sf_guard_user[dob][year]', options_for_select($year_arr, $theyear)); \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/templates/_edit_footer.php b/apps/reaktor/modules/sfGuardUser/templates/_edit_footer.php new file mode 100644 index 0000000..c8d0a62 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_edit_footer.php @@ -0,0 +1,68 @@ + + + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('wai'); + +if ($sf_params->get('id') && $sf_user->hasCredential("edituser")) +{ + $thisUserId = $sf_params->get('id'); +} +elseif ($sf_user->isAuthenticated()) +{ + $thisUserId = $sf_guard_user->getId(); +} + +if (isset($thisUserId)): +?> + + + + + + + + + + + + + + diff --git a/apps/reaktor/modules/sfGuardUser/templates/_edit_header.php b/apps/reaktor/modules/sfGuardUser/templates/_edit_header.php new file mode 100644 index 0000000..2b3a97b --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_edit_header.php @@ -0,0 +1,24 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +

    + hasCredential('edituser')) : ?> + <<  + + + + +    + +
    +

    \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/templates/_editorial_notification.php b/apps/reaktor/modules/sfGuardUser/templates/_editorial_notification.php new file mode 100644 index 0000000..1dad339 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_editorial_notification.php @@ -0,0 +1,15 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + echo select_tag('sf_guard_user[editorial_notification]', options_for_select(array( + '0' => __('No email'), + '1' => __('Email on first incoming artwork'), + '2' => __('Email on all incoming artworks')), + $sf_guard_user->getEditorialNotification())); \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/templates/_groups.php b/apps/reaktor/modules/sfGuardUser/templates/_groups.php new file mode 100644 index 0000000..75ed145 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_groups.php @@ -0,0 +1,60 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + use_helper('content', 'wai'); + + if (!function_exists("tmp_getTip")) + { + function tmp_getTip($aGroup) + { + $mouseOver = 'Tip(\'
    '; + $mouseOver .= '

    ' . __('By selecting this user group/editorial team, the user
    will automatically get the permissions listed below') . '

    '; + $mouseOver .= '

    ' . __('Permissions in this user group/editorial team') . '

    '; + + $mouseOver .= '
      '; + foreach ($aGroup->getsfGuardGroupPermissions() as $aGroupPermission) + { + $mouseOver .= '
    • ' . str_replace('\'', '"', $aGroupPermission->getsfGuardPermission()->getDescription()) . '
    • '; + } + if (count($aGroup->getsfGuardGroupPermissions()) == 0) + { + $mouseOver .= '
    • ' . __('This user group/editorial team has no specific permissions set') . '
    • '; + } + $mouseOver .= '
    '; + $mouseOver .= '\')'; + return $mouseOver; + } + } + +?> +

    +
      + + +
    • + getId().']', $aGroup->getId(), (($sf_request->getMethod() == sfRequest::POST && $sf_request->getParameter('associated_groups['.$aGroup->getId().']')) || ($sf_request->getMethod() != sfRequest::POST && $sf_guard_user->hasGroup($aGroup->getName()))), array('id' => 'associated_groups_' . $aGroup->getId())); ?> + getId(), $aGroup->getDescription(), array('onMouseOver' => $mouseOver, 'onMouseOut' => 'UnTip()')); ?> + [ getId(), array('target' => '_new')); ?> ] +
    • + +
    +
    +

    +
      + + +
    • + getId().']', $aTeam->getId(), (($sf_request->getMethod() == sfRequest::POST && $sf_request->getParameter('associated_groups['.$aTeam->getId().']')) || ($sf_request->getMethod() != sfRequest::POST && $sf_guard_user->hasGroup($aTeam->getName()))), array('id' => 'associated_groups_' . $aTeam->getId())); ?> + getId(), $aTeam->getDescription(), array('onMouseOver' => $mouseOver, 'onMouseOut' => 'UnTip()')); ?> + [ getId(), array('target' => '_new')); ?> ] +
    • + +
    diff --git a/apps/reaktor/modules/sfGuardUser/templates/_groups_help.php b/apps/reaktor/modules/sfGuardUser/templates/_groups_help.php new file mode 100644 index 0000000..f9b4b3a --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_groups_help.php @@ -0,0 +1,12 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/templates/_interests.php b/apps/reaktor/modules/sfGuardUser/templates/_interests.php new file mode 100644 index 0000000..3d813e1 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_interests.php @@ -0,0 +1,17 @@ +
      + +getUserInterests() as $userInterests) + $userInterestsArr[]=$userInterests->getSubreaktorId(); + +foreach($subReaktors as $reaktor) { + echo '
    • '; + echo 'getId(),$userInterestsArr)? 'checked' : '').' type="checkbox" value="'.$reaktor->getId().'" id="associated_interests_'.$reaktor->getId().'" name="associated_interests[]"/> '; + echo '
    • '; +} + +?> +
    diff --git a/apps/reaktor/modules/sfGuardUser/templates/_permissions.php b/apps/reaktor/modules/sfGuardUser/templates/_permissions.php new file mode 100644 index 0000000..6e556ac --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_permissions.php @@ -0,0 +1,95 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + use_helper('content', 'wai'); + + $crit = new Criteria(); + $crit->add(sfGuardUserPermissionPeer::USER_ID, $sf_guard_user->getId()); + $crit->add(sfGuardUserPermissionPeer::EXCLUDE, 0); + $permissions = array(); + $res = sfGuardUserPermissionPeer::doSelect($crit); + + foreach ($res as $row) + { + $permissions[] = $row->getsfGuardPermission()->getName(); + } + // Exclude + $crit = new Criteria(); + $crit->add(sfGuardUserPermissionPeer::USER_ID, $sf_guard_user->getId()); + $crit->add(sfGuardUserPermissionPeer::EXCLUDE, 1); + $exclude = array(); + $res = sfGuardUserPermissionPeer::doSelect($crit); + + foreach ($res as $row) + { + $exclude[] = $row->getsfGuardPermission()->getName(); + } + + + $group_ids = array(); + foreach ($sf_guard_user->getGroups() as $aGroup) + { + $group_ids[] = $aGroup->getId(); + } + + $crit = new Criteria(); + $crit->add(sfGuardGroupPermissionPeer::GROUP_ID, $group_ids, Criteria::IN); + $res = sfGuardGroupPermissionPeer::doSelect($crit); + + $credentials = array(); + foreach ($res as $row) + { + $credentials[] = $row->getsfGuardPermission()->getName(); + } + $credentials = array_unique($credentials); + +?> +
      +
    • +   + +
    • + +getId(); ?> +getMethod() == sfRequest::POST): + if ($sf_request->getParameter('unassociated_permissions['.$aPermission->getId().']')): + $unval = array('id' => 'un' . $id); + endif; + if ($sf_request->getParameter('associated_permissions['.$aPermission->getId().']')): + $val = array('id' => $id); + endif; +else: + if(in_array($aPermission->getName(), $exclude)): + $unval = array('id' => 'un' .$id); + endif; + if(in_array($aPermission->getName(), $permissions)): + $val = array('id' => $id); + endif; +endif; +?> +
    • + getName(), $credentials)): ?> + getId().']', $aPermission->getId(), $val, array("onclick" => "$('un$id').checked=false;", 'title' => __('Check this box to explicitly grant this user this permission'))); ?>  + getId().']', $aPermission->getId(), $unval, array("onclick" => "$('$id').checked=false;", 'title' => __('Check this box to explicitly deny this user this permission, even when inherited from another group'))); ?> + + getId().']', $aPermission->getId(), $val, array("onclick" => "$('un$id').checked=false;", 'title' => __('Check this box to explicitly grant this user this permission'))); ?>  + getId().']', $aPermission->getId(), $unval, array('disabled' => 'disabled')); ?> + +   + getName(), $credentials)): ?> + __('This user inherits this permission from a group membership'), 'style' => 'height: 12px; margin-right: 4px;')); ?> + + getId(), $aPermission->getDescription()); ?> +
    • + +
    diff --git a/apps/reaktor/modules/sfGuardUser/templates/_permissions_help.php b/apps/reaktor/modules/sfGuardUser/templates/_permissions_help.php new file mode 100644 index 0000000..3c52d1c --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_permissions_help.php @@ -0,0 +1,13 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +
    +

    \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/templates/_residence_id.php b/apps/reaktor/modules/sfGuardUser/templates/_residence_id.php new file mode 100644 index 0000000..3b496a7 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_residence_id.php @@ -0,0 +1,15 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + $res = ($residence = $sf_guard_user->getResidence()) ? $residence->getId() : null; + echo select_tag('sf_guard_user[residence_id]', options_for_select(ResidencePeer::getResidenceLevel(), $res, array( + 'include_custom' => __('Choose a residence') + ))); ?> diff --git a/apps/reaktor/modules/sfGuardUser/templates/_sex.php b/apps/reaktor/modules/sfGuardUser/templates/_sex.php new file mode 100644 index 0000000..26aa0cd --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/_sex.php @@ -0,0 +1,17 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + echo select_tag('sf_guard_user[sex]', options_for_select(array( + '' => 'Please select', + '1' => 'Male', + '2' => 'Female'), + $sf_guard_user->getSex())); \ No newline at end of file diff --git a/apps/reaktor/modules/sfGuardUser/templates/listUsersSuccess.php b/apps/reaktor/modules/sfGuardUser/templates/listUsersSuccess.php new file mode 100644 index 0000000..ba8969c --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/listUsersSuccess.php @@ -0,0 +1,46 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + __('users starting with %char%', array("%char%" => $startingwith)), 'slug' => 'users_by_'.$startingwith)); ?> +

    + $startingwith)); ?>
    + +

    '"' . $startingwith . '"')); ?>

    +

    '"' . $startingwith . '"')); ?>

    + +
      + +
    • +
      + getAvatar()): ?> + getAvatar(), array('size' => '48x48', 'alt' => $user->getUsername())) ?> + + + +
      + + getNamePrivate()): ?> + getName() . ' (' . $user->getUsername() . ')'; ?> + + getUsername(); ?> + + getResidence()): ?> + '', '%residence%' => $user->getResidence()->getName())) ?>
      + + substr($user->getCreatedAt(), 0, 10))) ?>
      + getUsername()); ?>
    • +

    • + +
    + + + + diff --git a/apps/reaktor/modules/sfGuardUser/templates/newuserSuccess.php b/apps/reaktor/modules/sfGuardUser/templates/newuserSuccess.php new file mode 100644 index 0000000..a593b0a --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/templates/newuserSuccess.php @@ -0,0 +1,18 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +reaktor::setReaktorTitle(__('User registration')); +?> + +

    + +

    + diff --git a/apps/reaktor/modules/sfGuardUser/validate/edit.yml b/apps/reaktor/modules/sfGuardUser/validate/edit.yml new file mode 100644 index 0000000..da08d24 --- /dev/null +++ b/apps/reaktor/modules/sfGuardUser/validate/edit.yml @@ -0,0 +1,82 @@ +methods: + post: + - "sf_guard_user{username}" + - "sf_guard_user{password}" + - "sf_guard_user{password_bis}" + - "sf_guard_user{dob}" + - "sf_guard_user{sex}" + - "sf_guard_user{residence_id}" + - "sf_guard_user{email}" + +fillin: + enabled: true + +names: + sf_guard_user{username}: + required: yes + required_msg: Please enter a username + validators: usernameUniqueValidator + + sf_guard_user{dob}: + required: yes + required_msg: Please enter a date of birth + validators: magickDateValidator + + sf_guard_user{password}: + required: no + group: password + validators: passwordValidator + + sf_guard_user{password_bis}: + required: no + group: password + validators: comparePasswordValidator + + sf_guard_user{residence_id}: + required: yes + required_msg: Please select a residence + + + sf_guard_user{email}: + required: yes + required_msg: Please enter your email address + validators: emailUniqueValidator + + sf_guard_user{sex}: + required: true + msg: Please select sex + +magickDateValidator: + class: myMagickDateValidator + param: + class: sfGuardUser + column: dob + date_error: The date you entered is not valid + required_msg: Please select a date of birth + +usernameUniqueValidator: + class: sfPropelUniqueValidator + param: + class: sfGuardUser + column: username + unique_error: This username already exists + +passwordValidator: + class: sfStringValidator + param: + min: 4 + min_error: The minimum length for the password is 4 + +comparePasswordValidator: + class: sfCompareValidator + param: + check: "sf_guard_user[password]" + compare_error: Passwords do not match + +emailUniqueValidator: + class: sfPropelUniqueValidator + param: + class: sfGuardUser + column: email + unique_error: This email address is in use + diff --git a/apps/reaktor/modules/sfRating/actions/actions.class.php b/apps/reaktor/modules/sfRating/actions/actions.class.php new file mode 100644 index 0000000..f3321f7 --- /dev/null +++ b/apps/reaktor/modules/sfRating/actions/actions.class.php @@ -0,0 +1,14 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsRatableBehaviorPlugin + */ +class sfRatingActions extends BasesfRatingActions +{ +} diff --git a/apps/reaktor/modules/sfRating/actions/components.class.php b/apps/reaktor/modules/sfRating/actions/components.class.php new file mode 100644 index 0000000..f546177 --- /dev/null +++ b/apps/reaktor/modules/sfRating/actions/components.class.php @@ -0,0 +1,34 @@ +object) + { + $total_ratings = $this->object->countRatings(); + $details = $this->object->getRatingDetails(true); + $full_details = array(); + foreach ($details as $rating => $nb_ratings) + { + if ($total_ratings > 0) + { + $percent = $nb_ratings / $total_ratings * 100; + } else $percent = 0; + $full_details[$rating] = array('count' => $nb_ratings, + 'percent' => $percent); + } + $this->rating_details = $full_details; + $this->object_type = get_class($this->object); + } + } + +} diff --git a/apps/reaktor/modules/sfRating/lib/BasesfRatingActions.class.php b/apps/reaktor/modules/sfRating/lib/BasesfRatingActions.class.php new file mode 100644 index 0000000..cbbc853 --- /dev/null +++ b/apps/reaktor/modules/sfRating/lib/BasesfRatingActions.class.php @@ -0,0 +1,123 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsRatableBehaviorPlugin + */ +class BasesfRatingActions extends sfActions +{ + + /** + * Here we will initiate system messages translatable strings + * + */ + public function preExecute() + { + parent::preExecute(); + sfLoader::loadHelpers('I18N'); + $this->messages = array( + 'already_voted' => __('You have already voted'), + 'missing_params' => __('Parameters are missing to retrieve ratable object'), + 'post_only' => __('POST requests only'), + 'ratable_error' => __('Unable to retrieve ratable object: %s'), + 'thank_you' => __('Thank you for voting!'), + 'thank_you_update' => __('Your vote has been updated!'), + 'user_error' => __('Oops, a problem has occured'), + ); + } + + /** + *

    Rate a propel object. This action is typically executed from an AJAX + * request.

    + * + *

    You should override this method in your own exteends actions class if + * you need to associate current rating with a user.

    + * + * @see sfPropelActAsRatableBehavior API + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsRatableBehaviorPlugin + */ + public function executeRate() + { + try + { + if ($this->getRequest()->getMethod() !== sfRequest::POST) + { + return $this->renderText($this->messages['post_only']); + } + + // Retrieve parameters from request + $token = $this->getRequestParameter('token'); + $rating = $this->getRequestParameter('rating'); + $star_width = $this->getRequestParameter('star_width', sfConfig::get('app_rating_star_width', 25)); + + // Retrieve ratable propel object + if (is_null($token) or is_null($rating)) + { + return $this->renderFatalError($this->messages['missing_params']); + } + + $object = sfPropelActAsRatableBehaviorToolkit::retrieveFromToken($token); + + if (is_null($object)) + { + return $this->renderFatalError($this->message['ratable_error']); + } + + // User retrieval + $user_id = sfPropelActAsRatableBehaviorToolkit::getUserId(); + if (is_null($user_id)) + { + // Votes are cookie based + $cookie_name = sprintf('%s_%s', sfConfig::get('app_rating_cookie_prefix', 'rating'), $token); + if (!is_null($this->getRequest()->getCookie($cookie_name))) + { + $message = $this->messages['already_voted']; + } + else + { + $object->setRating((int) $rating); + $cookie_ttl = sfConfig::get('app_rating_cookie_ttl', (86400*365*10)); + $cookie_expires = date('Y-m-d H:m:i', time() + $cookie_ttl); + $this->getResponse()->setCookie($cookie_name, (int)$rating, $cookie_expires); + $message = $this->messages['thank_you']; + } + } + else + { + $already_rated = $object->hasBeenRatedByUser($user_id); + $object->setRating((int) $rating, $user_id); + $message = $already_rated === true ? + $this->messages['thank_you_update'] : + $this->messages['thank_you']; + } + + $this->token = $token; + $this->rating = $object->getRating(); + $this->star_width = $star_width; + $this->message = $message; + } + catch (Exception $e) + { + return $this->renderFatalError($e->getMessage()); + } + } + + /** + * This methods will returns a basic user error message while logging a + * complete one if provided in the debug log file + * + * @param string $log_info Log information message + */ + protected function renderFatalError($log_info = null) + { + if (!is_null($log_info)) + { + sfLogger::getInstance()->warning('Rating error: '.$log_info); + } + return $this->renderText($this->messages['user_error']); + } + +} diff --git a/apps/reaktor/modules/sfRating/templates/_ratingDetails.php b/apps/reaktor/modules/sfRating/templates/_ratingDetails.php new file mode 100644 index 0000000..0be91f9 --- /dev/null +++ b/apps/reaktor/modules/sfRating/templates/_ratingDetails.php @@ -0,0 +1,18 @@ + + +getId() ?> + + $details): ?> + + + + + + +
    $rating)) ?> +
    +   +
    +
    ()
    + \ No newline at end of file diff --git a/apps/reaktor/modules/sfRating/templates/rateSuccess.php b/apps/reaktor/modules/sfRating/templates/rateSuccess.php new file mode 100644 index 0000000..1844535 --- /dev/null +++ b/apps/reaktor/modules/sfRating/templates/rateSuccess.php @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/apps/reaktor/modules/sfTransUnit/actions/actions.class.php b/apps/reaktor/modules/sfTransUnit/actions/actions.class.php new file mode 100644 index 0000000..68da62a --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/actions/actions.class.php @@ -0,0 +1,220 @@ + + * @version SVN: $Id$ + */ +require_once(dirname(__FILE__).'/../lib/BasesfTransUnitActions.class.php'); + +class sfTransUnitActions extends BasesfTransUnitActions +{ + public function executeEdit() + { + $this->trans_unit = $this->getTransUnitOrCreate(); + + if ($this->getRequest()->getMethod() == sfRequest::POST) + { + $catalogues = CataloguePeer::getCatalogues(); + foreach ($catalogues as $catalogue) { + $trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + $c = new Criteria(); + if($this->trans_unit->getSource()) + { +// Ticket 23733 - in some cases LIKE operator matches to much +// $c->add(TransUnitPeer::SOURCE, $this->trans_unit->getSource(), ' LIKE BINARY '); + $c->add(TransUnitPeer::SOURCE, $this->trans_unit->getSource(), ' = BINARY '); + } + else + { + $c->add(TransUnitPeer::SOURCE, $this->getRequestParameter("${trans_unit_string}[target]"),Criteria::EQUAL); + } + $c->add(TransUnitPeer::CAT_ID, $catalogue->getCatId()); + $trans_unit_cat = TransUnitPeer::doSelectOne($c); + + if ($trans_unit_cat) { + $this->$trans_unit_string = $this->getTransUnitByMsgIdOrCreate($trans_unit_cat->getMsgId()); + } else { +// If translation is missing create the object + $this->$trans_unit_string = $this->getTransUnitByMsgIdOrCreate(); + $this->$trans_unit_string->setSource($this->trans_unit->getSource()); + $this->$trans_unit_string->setFilename($this->trans_unit->getFilename()); + $this->$trans_unit_string->setModule($this->trans_unit->getModule()); + $this->$trans_unit_string->setId($this->trans_unit->getId()); + } + } + + + foreach ($catalogues as $catalogue) { + $this->updateTransUnitCatIdFromRequest($catalogue->getCatId()); + $trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + $this->$trans_unit_string->setCatId($catalogue->getCatId()); + $this->saveTransUnit($this->$trans_unit_string); + } + + $this->setFlash('notice', 'Your modifications have been saved'); + + if ($this->getRequestParameter('save_and_add')) + { + return $this->redirect('sfTransUnit/create'); + } + else if ($this->getRequestParameter('save_and_list')) + { + return $this->redirect('sfTransUnit/list'); + } + else + { + if ($this->trans_unit->getMsgId()) + { + return $this->redirect('sfTransUnit/edit?msg_id='.$this->trans_unit->getMsgId()); + } + else + { + return $this->redirect('sfTransUnit/list'); + } + } + } + else + { + $this->labels = $this->getLabels(); + } + } + + + + + function hex2bin($h) + { + if (!is_string($h)) return null; + $r=''; + for ($a=0; $agetRequestParameter('ref'); + $redirect = $this->hex2bin($redirect); + $newCulture = $this->getRequestParameter("lang"); + $cult = strpos($redirect, "sf_culture="); + if ($cult !== false) { + // 10 = sf_culture, +1 = =, 2 == no/en/ + $redirect = substr_replace($redirect, $newCulture, $cult+10+1, 2); + } + else + { + if (strpos($redirect, "?") !== false) { + $redirect .= "&"; + } + else + { + $redirect .= "?"; + } + + $redirect .= "sf_culture=" . $newCulture; + } + + if ($this->getUser()->isAuthenticated()) + { + $this->getUser()->getGuardUser()->setCulture($newCulture); + $this->getUser()->getGuardUser()->save(); + } + else + { + sfContext::getInstance()->getResponse()->setCookie(sfConfig::get('app_sf_guard_plugin_lang_cookie_name', 'lang'), + $newCulture, time()+60*60*24*10); + } + + $this->redirect($redirect); + } + + public function executeNextString() + { + $msg_id = $this->getRequestParameter('msg_id') + 1; + $this->redirect('@trans_edit?msg_id='.$msg_id); + } + + public function executePreviousString() + { + $msg_id = $this->getRequestParameter('msg_id') - 1; + if ($msg_id <= 0) $msg_id = 1; + $this->redirect('@trans_edit?msg_id='.$msg_id); + } + + /** + * Process the new translation form - if we are here then the validation must have passed + * + * @return void - the user is redirected + */ + public function executeNewTranslation() + { + $languages = $this->languages = CataloguePeer::getCatalogues(true); + $translateObject = $this->getrequestParameter("translateObject"); + $translateField = $this->getrequestParameter("translateField"); + + if (!class_exists($translateObject)) + { + throw new exception ("Need a class to translate"); + } + else + { + $trans = new $translateObject; + } + + $trans->setBasename($this->getrequestParameter("basename")); + $trans->save(); + + foreach ($languages as $key => $language) + { + $trans->setCulture($key); + $trans->{"set".$translateField}($this->getrequestParameter($key)); + $trans->save(); + } + + // Send the user back to the page they want to go to + $this->redirect($this->getrequestParameter("redirect")); + } + + /** + * Validator for adding new translation + * Here and not in the yaml file because number of fields can change + * Basename is validated in yaml - the languages here + * + * @return void + */ + public function validateNewTranslation() + { + + $languages = $this->languages = CataloguePeer::getCatalogues(true); + + foreach ($languages as $key => $language) + { + if (!$this->getrequestParameter($key)) + { + $this->getRequest()->setError($key, $this->getContext()->getI18n()->__("Required")); + } + } + + if ($this->getRequest()->hasErrors()) + { + return false; + } + + return true; + } + + /** + * Handle errors for new translations if there are any + * + * @return void + */ + public function handleErrorNewTranslation() + { + // Send the response back to the calling module, with errors intact + $this->forward($this->getrequestParameter("referingModule"), $this->getrequestParameter("referingAction")); + } + +} diff --git a/apps/reaktor/modules/sfTransUnit/actions/components.class.php b/apps/reaktor/modules/sfTransUnit/actions/components.class.php new file mode 100644 index 0000000..bff07b7 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/actions/components.class.php @@ -0,0 +1,82 @@ + + * @author Ole Petter Wikene + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * Components for translation functionality + * + * PHP version 5 + * + * @author Russ Flynn + * @author Ole Petter Wikene + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class sfTransUnitComponents extends sfComponents +{ + /** + * List the language options, used in header template + * + * @return void Exectutes the _langLinks component + */ + public function executeLangLinks() + { + $cache = reaktorCache::singleton("langbarnssadfasdfasdf"); + if (!($languages = $cache->get())) + { + $tmp = CataloguePeer::doSelect(new Criteria()); + $languages = array(); + foreach($tmp as $lang) + { + $languages[] = array( + "targetLang" => $lang->getTargetLang(), + "description" => $lang->getDescription(), + ); + } + $cache->set($languages); + } + + $links = array(); + $i = 0; + + // Generate the correct URLs + foreach($languages as $language) + { + $links[$i]['class'] = ''; + if ($language["targetLang"] == $this->getUser()->getCulture()) + { + $links[$i]['class'] = 'selected'; + } + $links[$i]['lang'] = $language["targetLang"]; + $links[$i++]['description'] = $language["description"]; + } + + // Pass the required array to the template + $this->links = $links; + $referer = sfRouting::getInstance()->getCurrentInternalUri(); + $this->ref =bin2hex(($referer)); + } + + /** + * Reuseable translation component for translating database content + * + * @return void + */ + public function executeNewTranslationForm() + { + if (!class_exists($this->translateObject)) + { + throw new Exception ("You must pass an object name to translate"); + } + + $this->languages = CataloguePeer::getCatalogues(true); + } +} diff --git a/apps/reaktor/modules/sfTransUnit/config/generator.yml b/apps/reaktor/modules/sfTransUnit/config/generator.yml new file mode 100644 index 0000000..33b0a59 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/config/generator.yml @@ -0,0 +1,51 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: TransUnit + theme: default + + fields: + filemodule: { name: Module/Template } + + list: + title: Translation list + max_per_page: 50 + display: [_lang, =source, target, comments, translated, _filemodule ] + + filters: [source, target, _translated, _catfilter, filename, module, comments] + object_actions: + _edit: ~ + _delete: ~ + # sort: source + fields: + source: { params: disabled=false } + translated: { params: disabled=false, type: boolean } + _lang: { params: lang } + catfilter: { name: language } + actions: + # _search: { name: Search for new untranslated text, action: ~ } + _create: { name: Create new , action: ~ } + + create: + title: create Translation + display: [source, comments] + fields: + source: { params: disabled=false size=80, type: input_tag } + comments: { params: disabled=false size=80×5, type: textarea_tag } + actions: + _list: ~ + _save: ~ + _delete: ~ + + edit: + title: "Edit Translation" + display: [source, _target] + fields: + source: { params: disabled=true size=80, type: input_tag, name: Opprinnelig tekst } + # comments: { params: disabled=false size=80x5, type: textarea_tag } + actions: + previous: { name: Previous string, action: previousString, icon: backend/next.png } + _list: ~ + _save: ~ + next: { name: Next string, action: nextString, icon: backend/next.png } + _delete: ~ \ No newline at end of file diff --git a/apps/reaktor/modules/sfTransUnit/config/security.yml b/apps/reaktor/modules/sfTransUnit/config/security.yml new file mode 100644 index 0000000..de79d90 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/config/security.yml @@ -0,0 +1,6 @@ +all: + credentials: translator + is_secure: on + +setCulture: + is_secure: off \ No newline at end of file diff --git a/apps/reaktor/modules/sfTransUnit/lib/BasesfTransUnitActions.class.php b/apps/reaktor/modules/sfTransUnit/lib/BasesfTransUnitActions.class.php new file mode 100644 index 0000000..cca3f34 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/lib/BasesfTransUnitActions.class.php @@ -0,0 +1,229 @@ + + * (c) 2008 Gareth James + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Gareth James + * @version SVN: $Id$ + */ + +class BasesfTransUnitActions extends autoSfTransUnitActions +{ + public function executeEdit() + { + $this->trans_unit = $this->getTransUnitOrCreate(); + + $catalogues = CataloguePeer::getCatalogues(); + foreach ($catalogues as $catalogue) { + $c = new Criteria(); + $c->add(TransUnitPeer::SOURCE, $this->trans_unit->getSource()); + $c->add(TransUnitPeer::CAT_ID, $catalogue->getCatId()); + $trans_unit_cat = TransUnitPeer::doSelectOne($c); + $trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + if ($trans_unit_cat) { + $this->$trans_unit_string = $this->getTransUnitByMsgIdOrCreate($trans_unit_cat->getMsgId()); + } else { + $this->$trans_unit_string = $this->getTransUnitOrCreate(); + } + } + + if ($this->getRequest()->getMethod() == sfRequest::POST) + { + foreach ($catalogues as $catalogue) { + $this->updateTransUnitCatIdFromRequest($catalogue->getCatId()); + $trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + $this->$trans_unit_string->setCatId($catalogue->getCatId()); + $this->saveTransUnit($this->$trans_unit_string); + } + + $this->setFlash('notice', 'Your modifications have been saved'); + + if ($this->getRequestParameter('save_and_add')) + { + return $this->redirect('sfTransUnit/create'); + } + else if ($this->getRequestParameter('save_and_list')) + { + return $this->redirect('sfTransUnit/list'); + } + else + { + if ($this->trans_unit->getMsgId()) + { + return $this->redirect('sfTransUnit/edit?msg_id='.$this->trans_unit->getMsgId()); + } + else + { + return $this->redirect('sfTransUnit/list'); + } + } + } + else + { + $this->labels = $this->getLabels(); + } + } + + protected function updateTransUnitCatIdFromRequest($cat_id) + { + $trans_unit_string = 'trans_unit_' . $cat_id; + ${$trans_unit_string} = $this->getRequestParameter("trans_unit_$cat_id"); + $trans_source = $this->getRequestParameter('trans_unit'); + if (isset($trans_source['source'])) + { + $this->$trans_unit_string->setSource($trans_source['source']); + } + if (isset(${$trans_unit_string}['target']) && isset(${$trans_unit_string}['translated'])) { + $this->$trans_unit_string->setTranslated(1); + } else if (! isset(${$trans_unit_string}['translated'])) + { + $this->$trans_unit_string->setTranslated(0); + } + if (isset(${$trans_unit_string}['default']) ) { + $this->$trans_unit_string->setTarget($this->$trans_unit_string->getSource()); + } else if (isset(${$trans_unit_string}['target'])) + { + $this->$trans_unit_string->setTarget(${$trans_unit_string}['target']); + } + if (isset(${$trans_unit_string}['comments'])) + { + $this->$trans_unit_string->setComments(${$trans_unit_string}['comments']); + } + + + } + /*protected function updateTransUnitCatIdFromRequest($cat_id) + { + $trans_unit_string = 'trans_unit_' . $cat_id; + ${$trans_unit_string} = $this->getRequestParameter("trans_unit_$cat_id"); + + if (isset(${$trans_unit_string}['source'])) + { + $this->$trans_unit_string->setSource(${$trans_unit_string}['source']); + } + if (isset(${$trans_unit_string}['target']) && (${$trans_unit_string}['target'] != $this->$trans_unit_string->getTarget())) { + $this->$trans_unit_string->setTranslated(1); + } else if (! isset(${$trans_unit_string}['translated'])) + { + $this->$trans_unit_string->setTranslated(0); + } + if (isset(${$trans_unit_string}['default']) ) { + $this->$trans_unit_string->setTarget($this->$trans_unit_string->getSource()); + } else if (isset(${$trans_unit_string}['target'])) + { + $this->$trans_unit_string->setTarget(${$trans_unit_string}['target']); + } + if (isset(${$trans_unit_string}['comments'])) + { + $this->$trans_unit_string->setComments(${$trans_unit_string}['comments']); + } + }*/ + + protected function addFiltersCriteria($c) + { + if (isset($this->filters['source_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::SOURCE, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::SOURCE, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['source']) && $this->filters['source'] !== '') + { + $c->add(TransUnitPeer::SOURCE, '%' . $this->filters['source']. '%', Criteria::LIKE); + } + if (isset($this->filters['module_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::MODULE, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::MODULE, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['module']) && $this->filters['module'] !== '') + { + $c->add(TransUnitPeer::MODULE, '%' . $this->filters['module']. '%', Criteria::LIKE); + } + if (isset($this->filters['filename_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::FILENAME, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::FILENAME, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['filename']) && $this->filters['filename'] !== '') + { + $c->add(TransUnitPeer::FILENAME, '%' . $this->filters['filename']. '%', Criteria::LIKE); + } + if (isset($this->filters['translated_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::TRANSLATED, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::TRANSLATED, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['translated']) && $this->filters['translated'] !== '') + { + $c->add(TransUnitPeer::TRANSLATED, $this->filters['translated']); + } + if (isset($this->filters['cat_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::CAT_ID, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::CAT_ID, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['cat_id']) && $this->filters['cat_id'] !== '') + { + $c->add(TransUnitPeer::CAT_ID, $this->filters['cat_id']); + } + if (isset($this->filters['comments_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::COMMENTS, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::COMMENTS, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['comments']) && $this->filters['comments'] !== '') + { + $c->add(TransUnitPeer::COMMENTS, '%' . $this->filters['comments']. '%', Criteria::LIKE); + } + if (isset($this->filters['target_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::TARGET, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::TARGET, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['target']) && $this->filters['target'] !== '') + { + $c->add(TransUnitPeer::TARGET, '%' . $this->filters['target']. '%', Criteria::LIKE); + } + + } + + protected function getTransUnitByMsgIdOrCreate($msg_id = NULL) + { + if (is_null($msg_id)) + { + $trans_unit = new TransUnit(); + } + else + { + $trans_unit = TransUnitPeer::retrieveByPk($msg_id); + + $this->forward404Unless($trans_unit); + } + return $trans_unit; + } + + protected function getLabels() + { + return array( + 'trans_unit{source}' => sfContext::getInstance()->getI18N()->__('Key text').':', + 'trans_unit{target}' => sfContext::getInstance()->getI18N()->__('Translations').':', + ); + } +} \ No newline at end of file diff --git a/apps/reaktor/modules/sfTransUnit/templates/_cat.php b/apps/reaktor/modules/sfTransUnit/templates/_cat.php new file mode 100644 index 0000000..603bb0a --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_cat.php @@ -0,0 +1,2 @@ + + true) )) ?> diff --git a/apps/reaktor/modules/sfTransUnit/templates/_catfilter.php b/apps/reaktor/modules/sfTransUnit/templates/_catfilter.php new file mode 100644 index 0000000..827ca89 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_catfilter.php @@ -0,0 +1,2 @@ + + true) )) ?> \ No newline at end of file diff --git a/apps/reaktor/modules/sfTransUnit/templates/_edit_form.php b/apps/reaktor/modules/sfTransUnit/templates/_edit_form.php new file mode 100644 index 0000000..c1be233 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_edit_form.php @@ -0,0 +1,76 @@ + $trans_unit, 'labels' => $labels)) + * $trans_unit - The object describing what is about to be translated + * $labels - The form labels + * + * PHP version 5 + * + * @author Ole-Petter Wikene + * + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('wai'); +?> + + 'sf_admin_edit_form', + 'name' => 'sf_admin_edit_form', + 'multipart' => true, +)) ?> + $trans_unit)) ?> + + +
    + +
    + +
    + hasError('trans_unit{source}')): ?> + 'form-error-msg')) ?> + + + 'trans_unit[source]', + 'id' => 'trans_source', + 'disabled' => true, + 'style' => "width:480px;", +)); echo $value ? $value : ' ' ?> + + +
    + +
    + +
    + +
    + hasError('trans_unit{target}')): ?> + 'form-error-msg')) ?> + + + 'edit', 'trans_unit' => $trans_unit)); echo $value ? $value : ' ' ?> +
    +
    + +
    + + $trans_unit)) ?> + + + +
      +
    • getMsgId()): ?> +getMsgId(), array ( + 'post' => true, + 'confirm' => __('Are you sure?'), + 'class' => 'sf_admin_action_delete', +)) ?> +
    • +
    diff --git a/apps/reaktor/modules/sfTransUnit/templates/_filemodule.php b/apps/reaktor/modules/sfTransUnit/templates/_filemodule.php new file mode 100644 index 0000000..5de073c --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_filemodule.php @@ -0,0 +1 @@ +getModule().'/'.$trans_unit->getFilename().''; ?> diff --git a/apps/reaktor/modules/sfTransUnit/templates/_lang.php b/apps/reaktor/modules/sfTransUnit/templates/_lang.php new file mode 100644 index 0000000..87d4dc0 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_lang.php @@ -0,0 +1 @@ +getCatalogue()->getTargetLang(); ?> diff --git a/apps/reaktor/modules/sfTransUnit/templates/_langLinks.php b/apps/reaktor/modules/sfTransUnit/templates/_langLinks.php new file mode 100644 index 0000000..752b12d --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_langLinks.php @@ -0,0 +1,26 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +$first = 1; + +?> + + + + + + + + $link['description'],'class' => $link['class'])); ?> + + diff --git a/apps/reaktor/modules/sfTransUnit/templates/_newTranslationForm.php b/apps/reaktor/modules/sfTransUnit/templates/_newTranslationForm.php new file mode 100644 index 0000000..60acbc6 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_newTranslationForm.php @@ -0,0 +1,47 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("subreaktor", 'wai'); + +$referer = sfRouting::getInstance()->getCurrentInternalUri(); +$redirect = isset($redirect) ? $redirect : $referer; +$referingModule = $sf_params->get("referingModule", $sf_params->get('module')); +$referingAction = $sf_params->get("referingAction", $sf_params->get('action')); + +?> +

    $translateObject)); ?>

    +
    +
    + + + + +

    + $language): ?> +
    + + + + +
    + + + + + + + +
    diff --git a/apps/reaktor/modules/sfTransUnit/templates/_target.php b/apps/reaktor/modules/sfTransUnit/templates/_target.php new file mode 100644 index 0000000..abcff21 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_target.php @@ -0,0 +1,83 @@ + 'edit', 'trans_unit' => $trans_unit)) + * + * $type - This variable is not used, but it does indicate that the form is used in edit mote + * $trans_unit - The object describing what is about to be translated + * + * PHP version 5 + * + * @author Ole-Petter Wikene + * @author Hannes Magnusson + * @author Russ Flynn + * @author June Henriksen + * + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +$catalogues = CataloguePeer::getCatalogues(); + +echo input_hidden_tag("trans_unit[msg_id]", $trans_unit->getMsgId()); +foreach ($catalogues as $catalogue) +{ + $trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + + if($trans_unit->getMsgId()) //Get current catalogue's/culture's translation of source + { + $c = new Criteria(); + $c->add(TransUnitPeer::CAT_ID, $catalogue->getCatId()); +// Ticket 23733 + $c->add(TransUnitPeer::SOURCE, $trans_unit->getSource(), ' = BINARY '); + //$trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + //$cat_id = $catalogue->getCatId(); + $$trans_unit_string = TransUnitPeer::doSelectOne($c); + } + //if ($$trans_unit_string) { + if (isset($$trans_unit_string)&&$$trans_unit_string) //If translated string is set + { + $msg_id_string = 'msg_id_' . $catalogue->getCatId(); + echo input_hidden_tag("${trans_unit_string}[msg_id]", ${$trans_unit_string}->getMsgId()); + } + else { + $$trans_unit_string = new TransUnit(); + } + + echo ''.$catalogue->getDescription().''; //Header + + echo '
    ';//Is the string translated + echo checkbox_tag("${trans_unit_string}[translated]", 1, $$trans_unit_string->getTranslated()); + echo __(" Publish translation for %language%", array('%language%' => $catalogue->getDescription())); + echo '

    '; + + //Translation + echo label_for("${trans_unit_string}[target]", $catalogue->getDescription().' '.__("translation").':'); + echo textarea_tag("${trans_unit_string}[target]", $$trans_unit_string->getTarget(), array('style' => 'width: 480px; height: 200px;')); + echo '
    '; + + //Copy source string + echo '
    '.checkbox_tag("${trans_unit_string}[default]", 1, '');//($catalogue->getTargetLang()=='en')?1:0); + echo __("Copy source string and use it as translation for %language%", array('%language%' => $catalogue->getDescription())).'
    '; + + + //Comment box + echo '
    '; + echo label_for("${trans_unit_string}[target]", __("Kommentar til oversettelse").':'); + echo textarea_tag("${trans_unit_string}[comments]", $$trans_unit_string->getComments(), array('style' => 'width: 480px; height: 30px;')); + echo '
    '; + + //Use comment globally + echo checkbox_tag("${trans_unit_string}[global]", 1, ''); + echo __(" Use this comment for all translations"); + echo '


    '; + echo "
    \n"; +} + +?> \ No newline at end of file diff --git a/apps/reaktor/modules/sfTransUnit/templates/_translated.php b/apps/reaktor/modules/sfTransUnit/templates/_translated.php new file mode 100644 index 0000000..6c1c9b8 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/_translated.php @@ -0,0 +1,5 @@ + 'all', + '0' => 'untranslated', + '1' => 'translated', + ), isset($filters['translated']) ? $filters['translated'] : '' )) ?> diff --git a/apps/reaktor/modules/sfTransUnit/templates/editSuccess.php b/apps/reaktor/modules/sfTransUnit/templates/editSuccess.php new file mode 100644 index 0000000..2b01c70 --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/templates/editSuccess.php @@ -0,0 +1,47 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + + + + +
    + +

    + +
    + $trans_unit)) ?> +
    + +
    + $trans_unit, 'labels' => $labels)) ?> + $trans_unit, 'labels' => $labels)) ?> +
    + + + +
    diff --git a/apps/reaktor/modules/sfTransUnit/validate/newTranslation.yml b/apps/reaktor/modules/sfTransUnit/validate/newTranslation.yml new file mode 100644 index 0000000..a5b794f --- /dev/null +++ b/apps/reaktor/modules/sfTransUnit/validate/newTranslation.yml @@ -0,0 +1,10 @@ +fillin: + enabled: true + +methods: + post: [basename] + +names: + basename: + required: yes + required_msg: Please enter the basename for this translation \ No newline at end of file diff --git a/apps/reaktor/modules/sidebar/actions/components.class.php b/apps/reaktor/modules/sidebar/actions/components.class.php new file mode 100644 index 0000000..2481ccd --- /dev/null +++ b/apps/reaktor/modules/sidebar/actions/components.class.php @@ -0,0 +1,97 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Sidebar components class + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class sidebarComponents extends sfComponents +{ + + /** + * Display the main sidebar element + * + * @return void Template will be parsed + */ + public function executeSidebar() + { + $residence = $subreaktor = $lokarreaktor = 0; + + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + $subreaktor = Subreaktor::getProvidedSubreaktor()->getId(); + } + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $lokarreaktor = Subreaktor::getProvidedLokalreaktor()->getId(); + $residence = Subreaktor::getProvidedLokalreaktor()->getResidences(); + } + + //Get artwork count in subreaktor + $apc_key = "artworkCount_r{$residence}_s{$subreaktor}_l{$lokarreaktor}"; + + if (!function_exists("apc_store") || ! ($artwork_count = sfProcessCache::get($apc_key)) ) { + $c = new Criteria(); + $c->add(ReaktorArtworkPeer::STATUS, 3); + $c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID); + $c->add(sfGuardUserPeer::SHOW_CONTENT, 1); + $c->add(ReaktorArtworkPeer::DELETED, 0); + $c->setDistinct(); + $c->addJoin(ReaktorArtworkPeer::ID, ReaktorArtworkFilePeer::ARTWORK_ID, Criteria::LEFT_JOIN); + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + $c->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $subreaktor); + } + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $c->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokarreaktor); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $residence, Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + + $artwork_count = ReaktorArtworkPeer::doCount($c); + + if (function_exists("apc_store")) { + sfProcessCache::set($apc_key, $artwork_count, 1800); + } + } + + $this->artwork_count = $artwork_count; + $this->user_count = sfGuardUserPeer::getOnlineCount(); + $action = $this->getRequestParameter('action'); + $module = $this->getRequestParameter('module'); + + //Choose which articles to display, if any at all + if (/*strpos($this->getRequest()->getUri(), 'admin') &&*/ $this->getUser()->hasCredential('staff')) //Display internal articles on admin pages + { + $this->internal_articles = ArticlePeer::getByFieldAndOrType(ArticlePeer::INTERNAL_ARTICLE, 'date', null, null, ArticlePeer::PUBLISHED, 5); + } + + + } + + public function executeSidebarArticles() + { + return ''; + } +} diff --git a/apps/reaktor/modules/sidebar/templates/_login.php b/apps/reaktor/modules/sidebar/templates/_login.php new file mode 100644 index 0000000..088a3ea --- /dev/null +++ b/apps/reaktor/modules/sidebar/templates/_login.php @@ -0,0 +1,69 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper("Javascript", 'wai'); +$loginStyle = $lostPassStyle = ""; +if ($sf_params->get("toemail")) +{ + $loginStyle = "Display: none"; +} +else +{ + $lostPassStyle = "Display: none"; +} +?> +
    +
    + + +
    +

    + +
    + ", + input_tag('username', $sf_data->get('sf_params')->get('username'), array("class" => "sidebar_text", "title" => __('Username'))); + ?> +
    + +
    + ", + input_password_tag('password', '', array("class" => "sidebar_text", "title" => __('Password'))); + ?> +
    + +
    + +
    +
    + + 'sf_guard_auth_button', 'class' =>'button')).'
    '; ?> + +
    + +
    + + get('referer') ? $sf_params->get('referer') : sfRouting::getInstance()->getCurrentInternalUri()); ?> + +
    +
    + +
    +
    diff --git a/apps/reaktor/modules/sidebar/templates/_send_in.php b/apps/reaktor/modules/sidebar/templates/_send_in.php new file mode 100644 index 0000000..ae8f58a --- /dev/null +++ b/apps/reaktor/modules/sidebar/templates/_send_in.php @@ -0,0 +1,22 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +hasCredential('uploadcontent') || !$sf_user->isAuthenticated()): ?> +
    +

    +

    for free'); ?>

    + isAuthenticated()): ?> + + + + +
    + \ No newline at end of file diff --git a/apps/reaktor/modules/sidebar/templates/_sidebar.php b/apps/reaktor/modules/sidebar/templates/_sidebar.php new file mode 100644 index 0000000..8038b0d --- /dev/null +++ b/apps/reaktor/modules/sidebar/templates/_sidebar.php @@ -0,0 +1,65 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + + +get('module') == 'profile' && $sf_params->get('action') == 'portfolio'): ?> + +
    + + +isAuthenticated()): ?> + +hasCredential('staff')): ?> + + + + + + + + + +hasCredential('staff')): ?> + + +
    + $internal_articles)); ?> +
    + + + + + +
    +

    diff --git a/apps/reaktor/modules/sidebar/templates/_sidebarArticles.php b/apps/reaktor/modules/sidebar/templates/_sidebarArticles.php new file mode 100644 index 0000000..72b8536 --- /dev/null +++ b/apps/reaktor/modules/sidebar/templates/_sidebarArticles.php @@ -0,0 +1,18 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + 'http://www.deichmanske-bibliotek.oslo.kommune.no/rss.php', + 'items' => 2, + 'timeout' => 1, + 'title' => __('News from Deichman') + )); */ ?> diff --git a/apps/reaktor/modules/sidebar/templates/_user_summary.php b/apps/reaktor/modules/sidebar/templates/_user_summary.php new file mode 100644 index 0000000..23ded46 --- /dev/null +++ b/apps/reaktor/modules/sidebar/templates/_user_summary.php @@ -0,0 +1,37 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?>
    +

    + '' . $sf_user->getUsername() . '')); ?> +
    +[] +
    +
      +
    • getUsername()); ?>
    • +
    • getUsername()); ?>
    • +
    +
      +
    • +
    • +
    +
      +
    • +
    • getUsername().'&key=0'); ?>
    • +
    +

    + +

    +
    diff --git a/apps/reaktor/modules/subreaktors/actions/actions.class.php b/apps/reaktor/modules/subreaktors/actions/actions.class.php new file mode 100644 index 0000000..00f6c62 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/actions/actions.class.php @@ -0,0 +1,269 @@ +lokalreaktor = null; + $this->subreaktor = null; + + if (Subreaktor::hasProvidedValidLokal()) + { + $this->lokalreaktor = Subreaktor::getProvidedLokalreaktor(); + } + $this->subreaktor = Subreaktor::getProvidedSubreaktor(); + + if ($this->subreaktor) + { + $this->forward404Unless($this->subreaktor->getLive() == 1 || $this->getUser()->hasCredential("subreaktoradministrator")); + } + if ($this->lokalreaktor) + { + $this->forward404Unless($this->lokalreaktor->getLive() == 1 || $this->getUser()->hasCredential("subreaktoradministrator")); + $cache = reaktorCache::singleton("lokalreaktor_index_" . $this->lokalreaktor->getReference()); + } + + + $bannerfarger = array('orange', 'turkis', 'graa'); + $this->bannerfarge = $bannerfarger[rand(0,count($bannerfarger)-1)]; + + if ($this->lokalreaktor) + { + $last = $cache->get(); + if (!$last) + { + foreach (Subreaktor::getAll() as $aSubreaktor) + { + if (!$aSubreaktor->getLokalReaktor() && $aSubreaktor->getLive()) + { + $last[] = array('subreaktor' => $aSubreaktor, 'last' => ReaktorArtworkPeer::getLatestSubmittedApproved(1, null, null, $aSubreaktor, $this->lokalreaktor)); + } + } + $cache->set(serialize($last)); + } + else + { + $last = unserialize($last); + } + $this->last = $last; + } + if ($this->lokalreaktor == null && $this->subreaktor !== null || ($this->lokalreaktor !== null && $this->subreaktor !== null)) + { + $this->setTemplate($this->subreaktor->getReference() . 'Reaktor'); + } + else + { + $this->setTemplate($this->lokalreaktor->getReference() . 'Reaktor'); + } + } + else + { + $this->forward404(); + } + + } + + public function executeList() + { + $this->activeSubreaktors = SubreaktorPeer::getLiveReaktors(); + $this->inactiveSubreaktors = SubreaktorPeer::getNotLiveReaktors(); + + } + + public function executeEdit() + { + $this->subreaktor = SubreaktorPeer::retrieveByPK($this->getRequestParameter('id')); + if (!$this->subreaktor) + { + $this->forward404(); + } + + $lokalresidences = array(); + if ($this->subreaktor->getLokalReaktor()) { + $residences = LokalreaktorResidencePeer::getResidenceBySubreaktor($this->subreaktor); + foreach($residences as $obj) { + $lokalresidences[$obj->getResidenceId()] = $obj->getResidence()->getName(); + } + } + $this->lokalresidences = $lokalresidences; + + $this->redirectUnless($this->subreaktor, '@listsubreaktors'); + + $this->logo_filename = 'logo' . ucfirst($this->subreaktor->getReference()) . '.gif'; + $this->logo_path = sfConfig::get('sf_web_dir').'/images/'; + $this->template_filename = $this->subreaktor->getReference() . 'ReaktorSuccess.php'; + $this->template_path = SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'apps/reaktor/modules/subreaktors/templates/'; + } + + public function handleErrorUpdate() + { + $this->forward('subreaktors', 'edit'); + } + + public function executeUpdate() + { + $this->subreaktor = SubreaktorPeer::retrieveByPK($this->getRequestParameter('id')); + $this->redirectUnless($this->subreaktor, '@listsubreaktors'); + + //$this->subreaktor->setName($this->getRequestParameter('name')); + if (!$this->subreaktor->getLive() && $this->getRequestParameter('subreaktor_reference')) + { + $newref = $this->getRequestParameter('subreaktor_reference'); + if ($newref != $this->subreaktor->getReference()) + { + $this->subreaktor->editReference($newref); + reaktorCache::deleteSimilar("lokalreaktor_index_"); + } + } + if ($this->getRequestParameter('subreaktor_live') != $this->subreaktor->getLive()) + { + $this->subreaktor->setLive($this->getRequestParameter('subreaktor_live')); + reaktorCache::deleteSimilar("lokalreaktor_index_"); + } + $this->subreaktor->setLokalReaktor($this->getRequestParameter('subreaktor_lokalreaktor')); + + if ($this->getRequestParameter('subreaktor_lokalreaktor')) + { + $c = new Criteria(); + $c->add(LokalreaktorResidencePeer::SUBREAKTOR_ID, $this->subreaktor->getPrimaryKey()); + LokalreaktorResidencePeer::doDelete($c); + + + $ids = $this->getrequestparameter('associated_lokalreaktor_residence'); + if (is_array($ids)) + { + foreach ($ids as $id) + { + $lokalreaktorresidence = new LokalreaktorResidence(); + $lokalreaktorresidence->setsubreaktorid($this->subreaktor->getprimarykey()); + $lokalreaktorresidence->setresidenceid($id); + $lokalreaktorresidence->save(); + } + } + } + + $this->subreaktor->save(); + reaktorCache::deleteSimilar('artwork_link_'); + $this->redirect('@editsubreaktor?id=' . $this->getRequestParameter('id')); + } + + public function handleErrorAdd() + { + $this->forward('subreaktors', 'list'); + } + + public function executeAdd() + { + try + { + $this->subreaktor = Subreaktor::createNew($this->getRequestParameter('name'), $this->getRequestParameter('reference')); + } + catch (Exception $e) + { + $this->getRequest()->setError("global", $e->getMessage()); + $this->forward("subreaktors", "list"); + } + $this->redirect('@editsubreaktor?id=' . $this->subreaktor->getId()); + } + + public function handleErrorCategoryAction() + { + $this->subreaktor = SubreaktorPeer::retrieveByPK($this->getRequestParameter('subreaktor')); + sfLoader::loadHelpers(array('Partial', 'Javascript')); + return $this->renderText(get_component('subreaktors', 'categoriesList', array('subreaktor' => $this->subreaktor))); + } + + public function executeCategoryAction() + { + $this->subreaktor = SubreaktorPeer::retrieveByPK($this->getRequestParameter('subreaktor')); + + if (!$this->subreaktor || !$this->getRequest()->isXmlHttpRequest()) + { + die(); + } + + switch ($this->getRequestParameter('mode')) + { + case 'delete': + $this->subreaktor->deleteCategory($this->getRequestParameter("category")); + break; + case 'add': + if ($this->getRequestParameter('category') > 0) + { + $this->subreaktor->addCategory($this->getRequestParameter("category")); + } + else + { + $this->subreaktor->addCategory(); // Adds a "blank" category + } + break; + } + sfLoader::loadHelpers(array('Partial', 'Javascript')); + return $this->renderText(get_component('subreaktors', 'categoriesList', array('subreaktor' => $this->subreaktor))); + } + + public function executeFiletypeAction() + { + $this->subreaktor = SubreaktorPeer::retrieveByPK($this->getRequestParameter('subreaktor')); + if (!$this->subreaktor || !$this->getRequest()->isXmlHttpRequest() || !$this->getRequestParameter('filetype')) + { + die(); + } + switch ($this->getRequestParameter('mode')) + { + case 'delete': + $this->subreaktor->deleteFileType($this->getRequestParameter("filetype")); + break; + case 'add': + $this->subreaktor->addFileType($this->getRequestParameter("filetype")); + break; + } + sfLoader::loadHelpers(array('Partial', 'Javascript')); + return $this->renderText(get_component('subreaktors', 'filetypesList', array('subreaktor' => $this->subreaktor))); + } + + /** + * Update Subreaktor order when draggin' and droppin' + * + * @return void + */ + public function executeUpdateOrder() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + try + { + $theorder = 1; + + foreach ($this->getRequestParameter('subreaktor_list') as $asubreaktor) + { + sfContext::getInstance()->getLogger()->info("Now setting artwork " . $asubreaktor); + $subreaktor = SubreaktorPeer::retrieveByPK($asubreaktor); + $subreaktor->setSubreaktorOrder($theorder); + $subreaktor->save(); + $theorder++; + } + sfContext::getInstance()->getLogger()->info("Done"); + return $this->renderText($this->getContext()->getI18N()->__("Changes were saved")); + } + catch (Exception $e) + { + return $this->renderText($this->getContext()->getI18N()->__("An error occured, your list was not updated")); + } + + } + +} diff --git a/apps/reaktor/modules/subreaktors/actions/components.class.php b/apps/reaktor/modules/subreaktors/actions/components.class.php new file mode 100644 index 0000000..699072f --- /dev/null +++ b/apps/reaktor/modules/subreaktors/actions/components.class.php @@ -0,0 +1,81 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +/** + * Category component class used for Ajax category view + * + * PHP version 5 + * + * @author Daniel Andre Eikeland + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class subreaktorsComponents extends sfComponents +{ + function executeCategoriesList() + { + } + + function executeNewFiletypeField() + { + $this->filetypes = sfConfig::get("app_files_location_identifiers"); + } + + function executeFiletypesList() + { + } + + /** + * List all subcategories in a subreaktor, with number + * of artworks per category + * + */ + function executeListSubcategories() + { + if (!isset($this->subreaktor)) + { + $this->subreaktor = Subreaktor::getProvidedSubreaktor(); + + } +if($this->subreaktor) + $this->categories = Subreaktor::listSubcategories($this->subreaktor, sfConfig::get('app_subreaktors_subcategory_list_length', 7)); + } + + function executeListLokalReaktorSubcategories() + { + + $cache = reaktorCache::singleton(__METHOD__); + if (!($serialized = $cache->get())) + { + $retval = array(); + $retval[] = Subreaktor::listLokalReaktorSubcategories($this->subreaktor, sfConfig::get('app_subreaktors_subcategory_list_length', 7)); + $retval[] = Subreaktor::listSubcategories($this->subreaktor, sfConfig::get('app_subreaktors_subcategory_list_length', 7)); + $cache->set(serialize($retval)); + } + else { + $retval = unserialize($serialized); + } + + $this->subreaktorcategories = $retval[0]; + $this->categories = $retval[1]; + } + + /** + * New category dropdown for edit page + * + * @return void + */ + function executeNewCategoryField() + { + $this->categories = CategorySubreaktorPeer::getCategoriesNotUsedBySubreaktor($this->subreaktor); + } + +} +?> diff --git a/apps/reaktor/modules/subreaktors/config/security.yml b/apps/reaktor/modules/subreaktors/config/security.yml new file mode 100644 index 0000000..cdb8046 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/config/security.yml @@ -0,0 +1,20 @@ +#All users should be able to view subreaktors +list: + credentials: [ subreaktoradministrator, subreaktorcategorizer ] + is_secure: on + +edit: + credentials: [ subreaktoradministrator, subreaktorcategorizer ] + is_secure: on + +add: + credentials: subreaktoradministrator + is_secure: on + +delete: + credentials: subreaktoradministrator + is_secure: on + +all: + is_secure: off + \ No newline at end of file diff --git a/apps/reaktor/modules/subreaktors/templates/_categoriesList.php b/apps/reaktor/modules/subreaktors/templates/_categoriesList.php new file mode 100644 index 0000000..e4a6e17 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/_categoriesList.php @@ -0,0 +1,38 @@ + $this->subreaktor)) + * + * The controller does not pass any information. + * + * PHP version 5 + * + * @author Daniel Andre Eikeland + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + + $subreaktor)); ?> +
    +
    +

    + getCategories() as $categoryId => $category): ?> + "10")),"@editCategory?id=".$categoryId); ?> + "10")), array( + 'update' => 'subreaktorCategories', + 'url' => 'subreaktors/categoryAction', + 'with' => "'category=".$categoryId."&mode=delete&subreaktor=".$subreaktor->getId()."'", + 'loading' => "Element.show('category_indicator')", + 'complete' => "setTimeout('Element.hide(\'category_indicator\')', 500)", + 'confirm' => __('Are you sure you wish to remove this category (%category%) from this Subreaktor?', array('%category%'=> $category)) + )) ?> +
    + + getCategories()) == 0): ?> + +
    + +
    +
    diff --git a/apps/reaktor/modules/subreaktors/templates/_filetypesList.php b/apps/reaktor/modules/subreaktors/templates/_filetypesList.php new file mode 100644 index 0000000..b41440b --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/_filetypesList.php @@ -0,0 +1,26 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +getFiletypes() as $value): ?> + "10")), array( + 'update' => 'subreaktorFiletypes', + 'url' => 'subreaktors/filetypeAction', + 'with' => "'filetype=".$value."&mode=delete&subreaktor=".$subreaktor->getId()."'", + 'loading' => "Element.show('filetype_indicator')", + 'complete' => "Element.hide('filetype_indicator')", + 'confirm' => __('Remove %content_type% from this subreaktor? Uploaded content of type %content_type% will no longer be assigned to this subreaktor', array('%content_type%'=> $value)) + )) ?> + +
    + +getFiletypes()) == 0): ?> + + diff --git a/apps/reaktor/modules/subreaktors/templates/_listLokalReaktorSubcategories.php b/apps/reaktor/modules/subreaktors/templates/_listLokalReaktorSubcategories.php new file mode 100644 index 0000000..5c4a970 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/_listLokalReaktorSubcategories.php @@ -0,0 +1,37 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +
    + 0 || count($categories) > 0): ?> +
      + + $value): ?> +
    • + 'subcategorylink')).'   '.__('%number_of_artworks% artworks', array('%number_of_artworks%' => $value['count'])) ?> +
    • + + $value): ?> +
    • + getReference().'&tag='.$key, array( + 'class'=>'subcategorylink')).'   '.__('%number_of_artworks% artworks', array('%number_of_artworks%' => $value)) ?> +
    • + + 0 || count($categories) > 0): ?> +
    + + + + + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/_listSubcategories.php b/apps/reaktor/modules/subreaktors/templates/_listSubcategories.php new file mode 100644 index 0000000..eddb4f5 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/_listSubcategories.php @@ -0,0 +1,31 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> +
    +

    + +
      + $value): ?> +
    • + 'subcategorylink')); ?> + + $value), $value); ?> + +
    • + +
    + + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/_newCategoryField.php b/apps/reaktor/modules/subreaktors/templates/_newCategoryField.php new file mode 100644 index 0000000..204e871 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/_newCategoryField.php @@ -0,0 +1,34 @@ + + * @author Russ Flynn + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + +
    + +

    + +

    + + "position:absolute;right:10px;bottom:-10px;")); ?> +
    \ No newline at end of file diff --git a/apps/reaktor/modules/subreaktors/templates/_newFiletypeField.php b/apps/reaktor/modules/subreaktors/templates/_newFiletypeField.php new file mode 100644 index 0000000..a55351b --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/_newFiletypeField.php @@ -0,0 +1,14 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + + + "display: none; margin-left: 2px; margin-top: 2px;", "id" => "filetype_indicator")) ?> \ No newline at end of file diff --git a/apps/reaktor/modules/subreaktors/templates/editSuccess.php b/apps/reaktor/modules/subreaktors/templates/editSuccess.php new file mode 100644 index 0000000..c513e53 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/editSuccess.php @@ -0,0 +1,169 @@ + + * @author Russ Flynn + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Object', 'content', 'Javascript', 'doubleList', 'wai'); +reaktor::setReaktorTitle(__('Edit %subReaktor_name% subReaktor', array("%subReaktor_name%" => $subreaktor->getName()))); ?> + +

    $subreaktor->getName())); ?>

    +
    + +
    +
    + getName(); ?>
    +

    + '' . link_to(__('translation interface'), '@subreaktornames') . '')); ?>.
    +

    +
    + getReference(); ?>
    +

    + '')); ?>
    + + getReference(), + '/' . $subreaktor->getReference()); ?> + +

    + + +
    + +

    +

    + %filename% in the %directory% directory.', + array('%filename%' => $logo_filename, '%directory%' => $logo_path)); ?> +

    + +

    + +
    + +
    + getId(), array( + 'id' => 'sf_admin_edit_form', + 'name' => 'sf_admin_edit_form', + 'onsubmit' => 'double_list_submit(); return true;' + )) ?> + getLive()): ?> +
    + + + getReference(), array("length" => 25, "class" => "short_input")) ?> + +
    + + __('Yes'), + '' => __('No')), $subreaktor->getLive())); ?> +
    + + __('Yes'), + '' => __('No')), $subreaktor->getLokalReaktor())); ?> +
    + + getLokalReaktor()):?> + +

    + +
    + +
    + + +
    + + +
    + '; ?> +

    +

    + + + +
    + getLokalReaktor()):?> +
    + +
    +

    + + 'subreaktorCategories', + 'url' => 'subreaktors/categoryAction?subreaktor='.$subreaktor->getId().'&mode=add', + 'loading' => "Element.show('category_indicator')", + 'complete' => "Element.hide('category_indicator'); doSubmit();", + 'success' => "$('category').value = ''"), + array("name" => "tag_form") + ) ?> + + + +
    + $subreaktor)); ?> +
    + +
    +
    + +
    +

    +
    + + 'subreaktorFiletypes', + 'url' => 'subreaktors/filetypeAction?subreaktor='.$subreaktor->getId().'&mode=add', + 'loading' => "Element.show('filetype_indicator')", + 'complete' => "Element.hide('filetype_indicator'); doSubmit();", + 'success' => "$('filetype').value = ''"), + array("name" => "filetype_form") + ) ?> + + + +
    + $subreaktor)) ?> +
    + + '; ?> + +
    + $subreaktor)); ?> +
    + +
    +
    + +
    +

    + %file% in the %directory% directory.', + array('%file%' => $template_filename, '%directory%' => $template_path));?> +

    +
    + + + + diff --git a/apps/reaktor/modules/subreaktors/templates/filmReaktorSuccess.php b/apps/reaktor/modules/subreaktors/templates/filmReaktorSuccess.php new file mode 100644 index 0000000..e5b12a9 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/filmReaktorSuccess.php @@ -0,0 +1,98 @@ + + * @author Russ Flynn + * @author Ole Petter Wikene + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('home', 'content'); + +?> + +
    + +
    +

    + +
    + + +
    +

    + 'thumb', + 'limit' => 1, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )) ?> + +
    + +
    + +
    +
    +
    + +
    + 'mini', + 'limit' => 6, + 'exclude_first' => true, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )) ?> +
    + +
    +
    +
    +
    + +
    +
    +

    + +
    + +
    +

    + 'reaktor', + )) ?> +
    + +
    +

    + false, + 'limit' => 5, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + ))?> +
    +
    + +
    + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/fotoReaktorSuccess.php b/apps/reaktor/modules/subreaktors/templates/fotoReaktorSuccess.php new file mode 100644 index 0000000..010ed45 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/fotoReaktorSuccess.php @@ -0,0 +1,98 @@ + + * @author Russ Flynn + * @author Ole Petter Wikene + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('home', 'content'); + +?> + +
    + +
    +

    + +
    + + +
    +

    + 'thumb', + 'limit' => 1, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )); ?> + +
    + +
    + +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    + +
    + +
    +

    + 'reaktor', + )); ?> +
    + +
    +

    + +
    +
    + +
    + +
    + 'mini', + 'limit' => 12, + 'random' => false, + 'exclude_first' => true, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )); ?> +
    + +
    + + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/groruddalenReaktorSuccess.php b/apps/reaktor/modules/subreaktors/templates/groruddalenReaktorSuccess.php new file mode 100644 index 0000000..d843a47 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/groruddalenReaktorSuccess.php @@ -0,0 +1,93 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('home', 'content'); + +?> + +
    + +
    +

    + +
    + +
    + +

    $aSubreaktor[0]['subreaktor']->getName())); ?>

    + 'subreaktorthumb', + 'limit' => 1, + 'last' => $aSubreaktor[0], + 'show_username'=> true, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )) ?> + +
    + +
    +

    + $lokalreaktor + )) ?> + +
    +
    +
    + +
    +

    + +
    +

    + 'reaktor', + )) ?> +
    +

    + +
    + +
    + + $aSubreaktor['subreaktor'], + 'image' => 'subreaktorlist', + 'limit' => 1, + 'last' => $aSubreaktor, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )) ?> + +
    + +
    + + + + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/indexSuccess.php b/apps/reaktor/modules/subreaktors/templates/indexSuccess.php new file mode 100644 index 0000000..e69de29 diff --git a/apps/reaktor/modules/subreaktors/templates/listSuccess.php b/apps/reaktor/modules/subreaktors/templates/listSuccess.php new file mode 100644 index 0000000..2d3fd3e --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/listSuccess.php @@ -0,0 +1,144 @@ + + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('Javascript', 'content', 'PagerNavigation', 'wai'); +reaktor::setReaktorTitle(__('List subReaktors')); ?> + + + + +
    +
    +

    +
    + + + +
    +
    +
    + __('The name is displayed in links, mouse-overs and on imagemaps') + )) ?> +
    + +
    + 'short_input' + )); ?> +
    + +
    + __('Reference is what appears in the URL') + )) ?> +
    + +
    + 'short_input' + )); ?> +
    +
    + +
    +
    + + '; ?> + +
    + + + +
    + + +

    + + + +
      + +
    • +
      + getReference()) . ".gif", array()); ?> +
      +
      +

      + getName() ?>
      +

      + getReference(), '/' . $aSubReaktor->getReference()); ?>
      +
      + getLokalReaktor()) ? __('This is a LokalReaktor') : __('This is a normal subReaktor'); ?> +
      +
      + getId()) ?> +
      +
    • + +
    + + + +

    + +
      + +
    • +
      + getReference()) . ".gif", array()); ?> +
      +
      +

      + getName() ?>
      +

      + getReference(), '/' . $aSubReaktor->getReference()); ?>
      +
      + getLokalReaktor()) ? __('This is a LokalReaktor') : __('This is a normal subReaktor'); ?> +
      +
      + getId()) ?> +
      +
    • + +
    + + diff --git a/apps/reaktor/modules/subreaktors/templates/lydReaktorSuccess.php b/apps/reaktor/modules/subreaktors/templates/lydReaktorSuccess.php new file mode 100644 index 0000000..181fa61 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/lydReaktorSuccess.php @@ -0,0 +1,84 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('home', 'content'); + +?> + +
    + +
    +

    + 1, + 'show_username' => true, + )); ?> + +
    + +
    +

    + 5, + 'tags' => true, + 'show_username' => true, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )); ?> +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    + +
    + +
    +

    + 'reaktor')); ?> +
    + +
    +

    + +
    + +
    + + +
    + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/subreaktorTemplate.php b/apps/reaktor/modules/subreaktors/templates/subreaktorTemplate.php new file mode 100644 index 0000000..010ed45 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/subreaktorTemplate.php @@ -0,0 +1,98 @@ + + * @author Russ Flynn + * @author Ole Petter Wikene + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('home', 'content'); + +?> + +
    + +
    +

    + +
    + + +
    +

    + 'thumb', + 'limit' => 1, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )); ?> + +
    + +
    + +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    + +
    + +
    +

    + 'reaktor', + )); ?> +
    + +
    +

    + +
    +
    + +
    + +
    + 'mini', + 'limit' => 12, + 'random' => false, + 'exclude_first' => true, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )); ?> +
    + +
    + + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/tegneserierReaktorSuccess.php b/apps/reaktor/modules/subreaktors/templates/tegneserierReaktorSuccess.php new file mode 100644 index 0000000..82f8af3 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/tegneserierReaktorSuccess.php @@ -0,0 +1,90 @@ + + * @author Russ Flynn + * @author Ole Petter Wikene + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('home', 'content'); + +?> + +
    + +
    +

    + +
    + + +
    +

    + 'thumb', + 'limit' => 1, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )) ?> + +
    + +
    + + +
    +
    +
    + +
    + +
    + +
    +
    +

    + +
    + +
    +

    + 'reaktor', + )) ?> +
    + +
    +

    + true, + 'limit' => 5, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + ))?> +
    +
    + +
    + + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/tegningReaktorSuccess.php b/apps/reaktor/modules/subreaktors/templates/tegningReaktorSuccess.php new file mode 100644 index 0000000..3cb8071 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/tegningReaktorSuccess.php @@ -0,0 +1,107 @@ + + * @author Russ Flynn + * @author Ole Petter Wikene + * @author June Henriksen + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('home', 'content'); + +?> + +
    + +
    +

    + +
    + + +
    +

    + 'thumb', + 'limit' => 1, + )) ?> + +
    + +
    + +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    + +
    + +
    +

    + 'reaktor')) ?> +
    + +
    +

    + true, + 'limit' => 5, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + ))?> +
    +
    + +
    + +
    + 'mini', + 'limit' => 6, + 'random' => true, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )) ?> +
    + +
    +
    +
    +
    + +
    +
    + +
    + + + +
    diff --git a/apps/reaktor/modules/subreaktors/templates/tekstReaktorSuccess.php b/apps/reaktor/modules/subreaktors/templates/tekstReaktorSuccess.php new file mode 100644 index 0000000..a037b9c --- /dev/null +++ b/apps/reaktor/modules/subreaktors/templates/tekstReaktorSuccess.php @@ -0,0 +1,91 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('home', 'content'); + +?> + +
    + +
    +

    + 1, + 'show_username' => true, + )) ?> + +
    + +
    +

    + 5, + 'tags' => 1, + 'show_username' => true, + 'cache' => 'sub_' . Subreaktor::getProvidedSubreaktorReference() . '_lok_' . Subreaktor::getProvidedLokalReference(), + )); ?> + +
    + +
    + + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +

    + 'reaktor', + )); ?> +
    + +
    +

    + +
    +
    + +
    +
    +
    +
    +
    +
    + +
    + + +
    diff --git a/apps/reaktor/modules/subreaktors/validate/add.yml b/apps/reaktor/modules/subreaktors/validate/add.yml new file mode 100644 index 0000000..9f7321b --- /dev/null +++ b/apps/reaktor/modules/subreaktors/validate/add.yml @@ -0,0 +1,22 @@ +fillin: + enabled: true + +fields: + name: + required: + msg: You must give the subReaktor a name + reference: + required: + msg: You must give the subReaktor a reference + myMagickWorkingRegexValidator: + match: Yes + match_error: Please use only alphanumeric characters in the reference + pattern: /[0-9a-zA-Z]*/ + sfPropelUniqueValidator: + class: Subreaktor + column: reference + unique_error: This subReaktor reference already exists + sfLokalReaktorNameValidator: + url_error: This reference URL is already in use + max_len: 15 + max_len_error: The reference length cannot be longer than 15 chars diff --git a/apps/reaktor/modules/subreaktors/validate/categoryAction.yml b/apps/reaktor/modules/subreaktors/validate/categoryAction.yml new file mode 100644 index 0000000..4a26ab7 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/validate/categoryAction.yml @@ -0,0 +1,7 @@ +fillin: + enabled: true + +fields: + category: + required: + msg: You must enter a category name \ No newline at end of file diff --git a/apps/reaktor/modules/subreaktors/validate/update.yml b/apps/reaktor/modules/subreaktors/validate/update.yml new file mode 100755 index 0000000..f007295 --- /dev/null +++ b/apps/reaktor/modules/subreaktors/validate/update.yml @@ -0,0 +1,18 @@ +fillin: + enabled: true + +fields: + subreaktor_reference: + myMagickWorkingRegexValidator: + match: Yes + match_error: Please use only alphanumeric characters in the reference + pattern: /[0-9a-zA-Z]*/ + sfPropelUniqueValidator: + class: Subreaktor + column: reference + unique_error: This subReaktor reference already exists + sfLokalReaktorNameValidator: + url_error: This reference URL is already in use + max_len: 15 + max_len_error: The reference length cannot be longer than 15 chars + diff --git a/apps/reaktor/modules/tags/actions/actions.class.php b/apps/reaktor/modules/tags/actions/actions.class.php new file mode 100644 index 0000000..f9b793c --- /dev/null +++ b/apps/reaktor/modules/tags/actions/actions.class.php @@ -0,0 +1,614 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * The main class for tags actions + * + * PHP version 5 + * + * @author Daniel Andre Eikeland + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class tagsActions extends sfActions +{ + /** + * Executes index action + * + * @return void + */ + public function executeIndex() + { + // This has no route so should not happen + $this->forward404(); + } + + /** + * Executes find actions + * + * @return void + */ + public function executeFind() + { + $results = array(); + if ($this->getRequestParameter('findtype') == 'user') + { + $c = new Criteria(); + $c->add(sfGuardUserPeer::USERNAME, strtolower(trim($this->getRequestParameter('tag')))); + $thisuser = sfGuardUserPeer::doSelectOne($c); + if ($thisuser instanceof sfGuardUser && strtolower(trim($this->getRequestParameter('tag'))) != 'admin') + { + $this->redirect(Subreaktor::addSubreaktorToRoute('@portfolio?user='.$thisuser->getUsername())); + } + else + { + $this->forward('sfGuardUser', 'listUsers'); + } + } + else + { + $tags = explode(',', urldecode($this->getRequestParameter("tag"))); + foreach ($tags as &$tag) + { + $tag = trim($tag); + } + + //sort($tags); + // Commented out since the customer didn't want tags sorted alphabetically before presented + + $this->sortmode = ($this->getRequestParameter('sortby')) ? $this->getRequestParameter('sortby') : 'date'; + $this->sortdirection = ($this->getRequestParameter('sortdirection')) ? $this->getRequestParameter('sortdirection') : 'desc'; + $this->results = $this->processResults($tags); + $this->tags = $tags; + } + $this->mode = 'tag'; + return sfView::SUCCESS; + } + + /** + * Shared functionality for processing tags or categories + * + * @param array $searchArray The array of strings to search for + * @param string $type The type of search (tag/category) + * + * @return array of reaktorFile objects + */ + protected function processResults($searchArray = array(), $type = "tag") + { + // Initialise the arrays we know about + $results = array(); + $matchingSet = array(); + + foreach ($searchArray as $item) + { + + switch ($type) + { + + case "tag": + if ($this->getUser()->hasCredential("viewallcontent")) { + // Staff members are allowed to see everything + $matchingSet["All"] = TagPeer::getObjectsTaggedWith(trim($item)); + } + else + { + $matchingSet["All"] = TagPeer::getObjectsTaggedWith(trim($item), array("approved" => 1, "parent_approved" => 1)); + } + break; + case "category": + $matchingSet["genericArtwork"] = CategoryArtworkPeer::getArtworksInCategory(trim($item)); + $matchingSet["Article"] = ArticleCategoryPeer::getArticlesInCategory(trim($item)); + break; + default: + throw new exception ("Unsupported type"); + break; + } + + $matching = array(); + foreach ($matchingSet as $matching) + { + foreach ($matching as $match) + { + // If it is a file we have matched, we need to extract the artworks + if ($match instanceof reaktorFile ) + { + foreach ($match->getParentArtworks() as $artwork) + { + if ($artwork->isViewable()) + { + $results[get_class($artwork)][$item][$artwork->getId()] = $artwork; + } + } + } + else + { + // Skip internal articles, unless you have the staff credentials + if ($match instanceof Article) + { + if ($match->getArticleType() == ArticlePeer::INTERNAL_ARTICLE && !$this->getUser()->hasCredential("staff")) + { + continue; + } + else + { + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + if ((!in_array(Subreaktor::getProvidedLokalreaktor()->getId(), $match->getLokalReaktors())) && count($match->getLokalReaktors()) > 0) + { + continue; + } + } + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + if (!in_array(Subreaktor::getProvidedSubreaktorReference(), $match->getSubreaktors(true))) + { + continue; + } + } + } + } + $results[get_class($match)][$item][$match->getId()] = $match; + } + } + } + foreach($results as &$resultItem) + { + if (!empty($resultItem[$item])) + { + usort($resultItem[$item], array($this, '_sortResults')); + } + } + } + return $results; + } + + /** + * Sorts artworks in a results array + * + * @param genericArtwork $a + * @param genericArtwork $b + */ + protected function _sortResults($a, $b) + { + $match_a = ''; + $match_b = ''; + switch ($this->sortmode) + { + case 'title': + $match_a = strtolower($a->getTitle()); + $match_b = strtolower($b->getTitle()); + break; + case 'rating': + if ($a instanceof genericArtwork) + { + $match_a = strtolower($a->getAverageRating()); + $match_b = strtolower($b->getAverageRating()); + } + break; + case 'username': + $match_a = strtolower($a->getUser()->getUsername()); + $match_b = strtolower($b->getUser()->getUsername()); + break; + case 'date': + default: + $match_a = strtolower($a->getCreatedAt()); + $match_b = strtolower($b->getCreatedAt()); + break; + } + if ($match_a == $match_b) + { + return 0; + } + if ($this->sortdirection == 'desc') + { + return ($match_a > $match_b) ? -1 : 1; + } + else + { + return ($match_a < $match_b) ? -1 : 1; + } + } + + /** + * Find category rather than tag + * + * @return void + */ + public function executeFindcategory() + { + if ($this->getRequest()->getMethod() == sfRequest::GET) + { + $categories = explode(',', urldecode($this->getRequestParameter("category"))); + $this->sortmode = ($this->getRequestParameter('sortby')) ? $this->getRequestParameter('sortby') : 'date'; + $this->sortdirection = ($this->getRequestParameter('sortdirection')) ? $this->getRequestParameter('sortdirection') : 'desc'; + + $this->categories = $this->getRequestParameter("category"); + + $this->results = $this->processResults($categories, "category"); + $this->setTemplate("find"); + $this->mode = 'category'; + return sfView::SUCCESS; + } + } + + /** + * Used for ajax calls to return a suggest list + * of tags for tag input form field + * + * @return void + */ + public function executeAutocomplete() + { + if (!$this->getRequest()->isXmlHttpRequest()) + { + die(); + } + + $tagStart = $this->getRequestParameter('tags'); + $excludeFirstLine = false; + $suggestions = ""; + + $suggestedTagArray = TagPeer::getTagsStartingwithStringExludingTaggables($tagStart, + array($this->getRequestParameter("id", 0)), + $this->getRequestParameter("taggableModel"), null, $this->getRequestParameter("limit")); + foreach ($suggestedTagArray as $tagObject) + { + if (strtolower($tagObject->getName()) == strtolower($tagStart)) + { + $excludeFirstLine = true; + } + $suggestions .= "
  • ".$tagObject->getName()."
  • \n"; + } + + if (!$excludeFirstLine) + { + $suggestions = "
  • ". + sfContext::getInstance()->getI18n()->__("New tag (%tag%)", + array("%tag%" => "".$tagStart."")). + "
  • \n".$suggestions; + } + $output = "
      \n".$suggestions."
    \n"; + + return $this->renderText($output); + } + + public function executeAutocompletetag() + { + if (!$this->getRequest()->isXmlHttpRequest()) + { + exit; + } + + $output = "
      \n"; + $s = $this->getRequestParameter('tags'); + $tags = TagPeer::getTagsStartingWithString($s); + foreach((array)$tags as $tag) + { + $output .= "
    • " .$tag->getName(). "
    • \n"; + } + $output .= "
    \n"; + return $this->renderText($output); + } + + /** + * adds a tag (ajax call from admin interface) + * + * @return void + */ + public function executeAddTag() + { + $new_tag_name = $this->getRequestParameter('tag_name'); + if (trim($new_tag_name) != '') + { + $tag = TagPeer::addNewApprovedTag($new_tag_name, $this->getUser()->getId()); + if ($tag instanceof Tag) + { + $retval = sfContext::getInstance()->getI18n()->__('The tag has been added!'); + } + else + { + $retval = sfContext::getInstance()->getI18n()->__('This tag already exists'); + } + } + else + { + $retval = sfContext::getInstance()->getI18n()->__('Please enter a tag name'); + } + return $this->renderText($retval); + } + + + /** + * Used for adding a tag (Just Ajax calls at present) + * + * @return void + */ + public function executeTagAction() + { + if (!$this->getRequest()->isXmlHttpRequest() && sfConfig::get('sf_environment') != 'test') + { + die(); + } + $taggableObject = null; + $options = $this->getRequestParameter("options",array()); + switch($this->getRequestParameter("taggable")) + { + case "genericArtwork": + case "reaktorArtwork": + try + { + $taggableObject = new genericArtwork($this->getRequestParameter("file")); + $taggableModel = "ReaktorArtwork"; + $options["extraId"] = "_artwork".$taggableObject->getId(); + } + catch (Exception $e) + { + return $this->renderText($e->getMessage()); + } + break; + case "reaktorFile": + case "artworkFile": + try + { + $taggableObject = new artworkFile($this->getRequestParameter("file")); + $taggableModel = "ReaktorFile"; + + if (isset($options["artworkList"]) && $options["artworkList"]) + { + $options["extraId"] = "_artwork".$options["artworkList"]; + } + else + { + $options["extraId"] = "_file".$taggableObject->getId(); + } + } + catch (Exception $e) + { + return $this->renderText($e->getMessage()); + } + break; + case "Article": + try + { + $taggableObject = ArticlePeer::retrieveByPK($this->getRequestParameter("file")); + $taggableModel = "Article"; + $options["extraId"] = "_article".$taggableObject->getId(); + } + catch (Exception $e) + { + return $this->renderText($e->getMessage()); + } + break; + default: + // There can be cases where we are doing actions without a taggable object, these cases are checked and caught below + break; + } + + $tag = urldecode($this->getRequestParameter("tag")); + try + { + if(function_exists('apc_clear_cache')) apc_clear_cache('user'); + switch($this->getRequestParameter("mode")) + { + case "edittagname": + // Shares tag adding functions so is called "tags" even though this time there is only one + // So we should treat it as such - any commas this time will cause an error + $cleanTagArray = stringMagick::cleanTag($this->getRequestParameter("tags")); + + if (!isset($cleanTagArray["error"])) + { + if (TagPeer::renameOrMergeTag($tag, $cleanTagArray["cleantag"])) + { + $output = json_encode(array("success" => true)); + } + } + else + { + $output = json_encode(array("error" => $cleanTagArray["error"])); + } + + $this->getResponse()->setHttpHeader("X-JSON", '('.$output.')'); + return sfView::HEADER_ONLY; + break; + case "approveall": + if ($this->getUser()->hasCredential("approvetags")) + { + foreach($this->getRequestParameter("unapprovedTags", array()) as $tag) + { + $tag = urldecode($tag); + TagPeer::approveTagByName($tag, $this->getUser()->getGuardUser()->getId()); + HistoryPeer::logAction(6, $this->getUser()->getGuarduser(), TagPeer::retrieveByTagname($tag)); + } + } + break; + case "approve": + if ($this->getUser()->hasCredential("approvetags")) + { + TagPeer::approveTagByName($tag, $this->getUser()->getGuardUser()->getId()); + HistoryPeer::logAction(6, $this->getUser()->getGuarduser(), TagPeer::retrieveByTagname($tag)); + } + break; + // Unapprove effectively deletes the tag from the system + case "unapproveall": + if ($this->getUser()->hasCredential("tagadministrator")) + { + foreach($this->getRequestParameter("unapprovedTags", array()) as $tag) + { + TagPeer::unapproveTagByName(urldecode($tag), $this->getUser()->getGuardUser()->getId()); + } + } + break; + case "unapprove": + if ($this->getUser()->hasCredential("tagadministrator")) + { + TagPeer::unapproveTagByName($tag, $this->getUser()->getGuardUser()->getId()); + } + break; + case "deleteall": + if (!$taggableObject) + { + throw new Exception("Cannot remove a tag from a non-object"); + } + elseif ($this->getUser()->hasCredential("approvetags")) + { + foreach ($this->getRequestParameter("unapprovedTags", array()) as $tag) + { + $taggableObject->removeTag(urldecode($tag)); + } + } + break; + case "delete": + if (!$taggableObject) + { + throw new Exception("Cannot remove a tag from a non-object"); + } + elseif ($this->getUser()->hasCredential("approvetags") || ($this->getUser()->getGuardUser()->getId() == $taggableObject->getUserId() && $taggableObject->countTags() > 1)) + { + $taggableObject->removeTag($tag); + } + else + { + $this->tag_error = sfContext::getInstance()->getI18n()->__('You cannot remove the last tag, it needs to have at least one tag') . "\\n\\n"; + } + break; + case "add": + if (!$taggableObject) + { + throw new Exception("Cannot add a tag without a taggable object to tag"); + } + elseif ($this->getUser()->hasCredential("approvetags") || $this->getUser()->hasCredential("tagadministrator") || $this->getUser()->getGuardUser()->getId() == $taggableObject->getUserId()) + { + //If it contains commas then it is multiple tags + $tagArray = explode(',', $this->getRequestParameter("tags")); + + //Add the tag + // Don't do anything if there is no tag + if( !$this->getRequestParameter("tags")===false ) + foreach ($tagArray as $thisTag) + { + $thisTagCleanArray = stringMagick::cleanTag($thisTag); + if (!isset($thisTagCleanArray["error"])) + { + $thisTag = $thisTagCleanArray["cleantag"]; + + $taggableObject->addTag($thisTag); + $taggableObject->save(); + + // If this is an approved file and tag then we can approve this relationship straight away + $tagObject = TagPeer::retrieveByTagname($thisTag); + + if ($tagObject) + { + if ($taggableObject instanceof artworkFile && $taggableObject->hasArtwork() && $taggableObject->getParentArtwork()->getStatus() == 3 && $tagObject->getApproved() == 1) + { + TaggingPeer::setTaggingApproved($tagObject, "ReaktorFile", $taggableObject->getId()); + } + elseif ($taggableObject instanceof genericArtwork && $taggableObject->getStatus() == 3 && $tagObject->getApproved() == 1) + { + TaggingPeer::setTaggingApproved($tagObject, "ReaktorArtwork", $taggableObject->getId()); + } + elseif ($taggableObject instanceof Article && $taggableObject->isPublished() && $tagObject->getApproved() == 1) + { + TaggingPeer::setTaggingApproved($tagObject, "Article", $taggableObject->getId()); + } + if ($taggableObject instanceof Article || $taggableObject instanceof genericArtwork || $taggableObject instanceof artworkFile) + { + TaggingPeer::setParentUserId($tagObject, $taggableModel, $taggableObject->getId(), $taggableObject->getUserId()); + } + } + } + else + { + $this->tag_error .= $thisTagCleanArray["error"]."\\n\\n"; + } + } + } + break; + default: + return $this->renderText(""); + break; + } + } + catch (Exception $e) + { + throw $e; + } + + sfLoader::loadHelpers(array('Partial')); + if (isset($taggableObject)) + { + $taggableObject->save(); + return $this->renderText(get_component('tags', 'tagEditList', array("taggableObject"=>$taggableObject, 'tag_error'=>$this->tag_error, 'options' => $options))); + } + else + { + return $this->renderText(get_component('tags', 'tagEditList', array('options' => $options, "page" => $this->getRequestParameter("page"), "unapproved" => $this->getRequestParameter("unapproved")))); + } + + } + + /** + * Alphabetised list of all the tags for approval + * + * @return void + */ + public function executeListTags() + { + $c = new Criteria(); + $c->addAscendingOrderByColumn(TagPeer::NAME); + if ($this->getRequestParameter("unapproved")) + { + $c->add(TagPeer::APPROVED, 0); + } + $tags = TagPeer::doSelect($c); + + //now we need an array of all the first letters. + $pageLetter = strtoupper($this->getRequestParameter('page', '')); + $arrayOfFirstLetters = array(); + $thisList = array(); + $x = 0; + $y = 0; + + foreach ($tags as $entry) + { + $firstLetter = mb_strtoupper(mb_substr($entry->getName(), 0, 1, 'UTF-8'), 'UTF-8'); + $arrayOfFirstLetters[$x++] = $firstLetter; + + if ($this->getRequestParameter("page") == "ALL" || $pageLetter == $firstLetter) + { + if (!($this->getRequestParameter("unapproved") && $entry->getApproved() == 1)) + { + $thisList[$y++] = $entry; + } + } + } + $arrayOfFirstLetters = array_unique($arrayOfFirstLetters); + sort($arrayOfFirstLetters); + + //Go to the first page that has results, if this one doesn't + if (!$this->getRequestParameter("page") == "ALL" && !in_array($pageLetter, $arrayOfFirstLetters)) + { + if ($this->getRequestParameter("unapproved")) + { + $this->redirect("@taglist_unapproved?page=".$arrayOfFirstLetters[0]); + } + elseif(!empty($arrayOfFirstLetters)) + { + $this->redirect("@taglist?page=".$arrayOfFirstLetters[0]); + } + } + $this->page = $pageLetter; + $this->pageLinks = $arrayOfFirstLetters; + $this->tags = $thisList; + } +} diff --git a/apps/reaktor/modules/tags/actions/components.class.php b/apps/reaktor/modules/tags/actions/components.class.php new file mode 100644 index 0000000..8fcb53d --- /dev/null +++ b/apps/reaktor/modules/tags/actions/components.class.php @@ -0,0 +1,175 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * Tag component class used for Ajax tag view + * + * PHP version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class tagsComponents extends sfComponents +{ + /** + * Generate an array of tags for the tag edit template + * Based on an object that has been tagged + * + * @return void + */ + function executeTagEditList() + { + $c = new Criteria(); + $c->addAscendingOrderByColumn(TagPeer::NAME); + $this->options = isset($this->options) ? $this->options : array(); + + if (isset($this->taggableObject)) + { + if ($this->taggableObject instanceof artworkFile) + { + $c->add(TaggingPeer::TAGGABLE_MODEL, "ReaktorFile"); + $this->taggable = "reaktorFile"; + if (isset($this->options["artworkList"]) && $this->options["artworkList"]) + { + $this->options["extraId"] = "_artwork".$this->options["artworkList"]; + } + else + { + $this->options["extraId"] = "_file".$this->taggableObject->getId(); + } + + } + elseif ($this->taggableObject instanceof genericArtwork) + { + $c->add(TaggingPeer::TAGGABLE_MODEL, "ReaktorArtwork"); + $this->taggable = "genericArtwork"; + $this->options["extraId"] = "_artwork".$this->taggableObject->getId(); + } + elseif ($this->taggableObject instanceof Article) + { + $c->add(TaggingPeer::TAGGABLE_MODEL, "Article"); + $this->taggable = "Article"; + $this->options["extraId"] = "_article".$this->taggableObject->getId(); + } + else + { + throw new exception ("Unsupported object"); + } + + $c->add(TaggingPeer::TAGGABLE_ID, $this->taggableObject->getId()); + $c->addJoin(TaggingPeer::TAG_ID, TagPeer::ID); + $c->addDescendingOrderByColumn(TaggingPeer::ID); + $this->objectId = $this->taggableObject->getId(); + } + + if (isset($this->page) && $this->page != "ALL") + { + $c->add(TagPeer::NAME, $this->page."%", Criteria::LIKE); + } + + if (isset($this->unapproved) && $this->unapproved == 1) + { + $c->add(TagPeer::APPROVED, 0); + } + + $this->tags = TagPeer::doSelect($c); + } + + function executeTagSearchBox() + { + + } + + /** + * Show intelligent tag cloud + * + * @return void - generate the intellitags component + */ + function executeShowintellitags() + { + $tags = $this->tags; + + // Get related tags + $first_tags = TagPeer::getRelatedTags($tags, array('limit' => 100, 'parent_approved' => 1)); + + // uncomment the following if-block to do a second pass + /* + if (count($first_tags) <= 10) + { + $second_tags = array_keys($first_tags); + $second_tags = TagPeer::getRelatedTags($second_tags, array('limit' => 100, 'parent_approved' => 1)); + + $second_tags = array_merge($first_tags, $second_tags); + + // uncomment the following three lines to do a third pass + /* + $third_tags = array_keys($second_tags); + $third_tags = TagPeer::getRelatedTags($third_tags, array('limit' => 100, 'parent_approved' => 1)); + $second_tags = array_merge($first_tags, $third_tags); + */ + + //$first_tags = array_merge($first_tags, $second_tags); + //} + + // Checking to see if the artworks tags is in the tag cloud and merging them if not + foreach ($tags as $arrtag) + { + foreach((array)$arrtag as $atag) + { + if (!isset($first_tags[$atag])) + { + $first_tags[$atag] = -1; + } + } + } + + $cloud_tags = $first_tags; + + // Sort the tags so the artwork tags don't appear at the end or in the beginning + ksort($cloud_tags); + ksort($tags); + + // Send the required values to the template + $this->cloud_tags = $cloud_tags; + if (count(array_keys($cloud_tags)) == count(array_keys($tags))) + { + $this->cloud_tags = TagPeer::getPopulars(null, array('limit' => 20, 'parent_approved' => 1)); + foreach ($tags as $atag) + { + if (!isset($this->cloud_tags[$atag])) + { + $this->cloud_tags[$atag] = -1; + } + } + ksort($this->cloud_tags); + } + while (count($this->cloud_tags) > sfConfig::get('app_home_max_tags', 100)) + { + array_splice($this->cloud_tags, rand(0, count($this->cloud_tags)), 1); + } + } + + /** + * Component for showing a list of tags with coloured status + * + * @return null + */ + function executeViewTagsWithStatus() + { + // Get all the tags + $this->tagStatusArray = $this->artwork->getTags(true, true); + } +} + + +?> diff --git a/apps/reaktor/modules/tags/config/security.yml b/apps/reaktor/modules/tags/config/security.yml new file mode 100644 index 0000000..cdc79cb --- /dev/null +++ b/apps/reaktor/modules/tags/config/security.yml @@ -0,0 +1,7 @@ +listTags: + is_secure: on # This is an admin function + credentials: [[tagadministrator]] + +#All users should be able to view tags +all: + is_secure: off \ No newline at end of file diff --git a/apps/reaktor/modules/tags/templates/_addTag.php b/apps/reaktor/modules/tags/templates/_addTag.php new file mode 100644 index 0000000..8f2bf09 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_addTag.php @@ -0,0 +1,26 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + +

    +
    + '@admin_addtag', 'update' => 'tag_add_status')); ?> +
    +
    +
    'short')); ?>
    +
    + +'; ?> +
    \ No newline at end of file diff --git a/apps/reaktor/modules/tags/templates/_alphaPager.php b/apps/reaktor/modules/tags/templates/_alphaPager.php new file mode 100644 index 0000000..969e888 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_alphaPager.php @@ -0,0 +1,67 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +$first = true; +?> + +
    + get("unapproved")) + { + echo link_to($letter, '@taglist_unapproved?page='.$letter); + } + else + { + echo link_to($letter, '@taglist?page='.$letter); + } + } + } + if ($sf_params->get("page") == "ALL") + { + echo " | ".__("ALL"); + } + elseif (!$sf_params->get("unapproved")) + { + echo " | ".link_to(__("ALL"), "@taglist?page=ALL"); + } + else + { + echo " | ".link_to(__("ALL"), "@taglist_unapproved?page=ALL"); + } + ?> +
    \ No newline at end of file diff --git a/apps/reaktor/modules/tags/templates/_newTagField.php b/apps/reaktor/modules/tags/templates/_newTagField.php new file mode 100644 index 0000000..512b246 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_newTagField.php @@ -0,0 +1,36 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + + + 'short_input','style'=>"width: 140px;"), + array('use_style' => false, + 'indicator' => 'tag_indicator', + 'tokens' => ',', + 'frequency' => 0.3, + 'with' => "value+'&taggableModel=".$taggableModel."&id=".$id."'") + );?> + "$('error_for_tags').hide();" + )); ?> + + diff --git a/apps/reaktor/modules/tags/templates/_showMini.php b/apps/reaktor/modules/tags/templates/_showMini.php new file mode 100644 index 0000000..c4384a0 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_showMini.php @@ -0,0 +1,43 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +// Generate the mouseover tooltip if any +if (!isset($nomouseover) || !$nomouseover): + $thisMouseover = "Tip('

    ".addslashes($artwork->getTitle())."

    "; + if (!$artwork->isMultiUser()) + { + $thisMouseover .= __("by")." ".$artwork->getUser()->getUsername()."
    "; + } + $thisMouseover .= __('Created on: %creation_date%', array('%creation_date%' => date("d/m/Y", strtotime($artwork->getCreatedAt()))))."

    "; + $thisMouseover .= get_partial('artwork/artworkRating', array('artwork' => $artwork, 'noedit' => false, 'login' => false))."
    ', FADEIN, 300, BGCOLOR, '#FFFFFF')"; + $thisMouseout = "UnTip()"; +else: + $thisMouseover = ""; + $thisMouseout = ""; +endif; + +// Display the thumbnail on the page +if (!isset($nolink) || $nolink == false): +echo reaktor_link_to(image_tag(contentPath($artwork, "mini"), array('size' => '78x65', 'alt' => $artwork->getTitle(), 'title' => $artwork->getTitle())), + $artwork->getLink(), array( + 'onmouseover' => $thisMouseover, + 'onmouseout' => $thisMouseout)); +else: + echo image_tag(contentPath($artwork, "mini"), array('size' => '78x65', 'alt' => $artwork->getTitle(), 'title' => $artwork->getTitle())); +endif; + diff --git a/apps/reaktor/modules/tags/templates/_showintellitags.php b/apps/reaktor/modules/tags/templates/_showintellitags.php new file mode 100644 index 0000000..f7362be --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_showintellitags.php @@ -0,0 +1,20 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +use_helper('cloud'); + +echo tag_cloud($cloud_tags, '@findtags?tag=', array('class' => 'tag-cloud-right'), __('Related tags')); +?> \ No newline at end of file diff --git a/apps/reaktor/modules/tags/templates/_showtags.php b/apps/reaktor/modules/tags/templates/_showtags.php new file mode 100644 index 0000000..93c32e7 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_showtags.php @@ -0,0 +1,44 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('cloud'); + + //$cloud_type = (isset($cloud_type)) ? $cloud_type : sfConfig::get('app_tagging_cloud_type'); + + /*switch ($cloud_type) + { + case 'pretty':*/ + echo tag_cloud(TagPeer::getPopulars(null, array('notmodel' => 'Article')), '@findtags?tag=', + array('class' => 'tag-cloud-right'), + __('Popular tags')); + /* break; + default: + echo tag_cloud_with_count(TagPeer::getPopularTagsWithCount(sfConfig::get("app_home_max_tags", 20), + sfConfig::get("app_home_max_tag_length", 500) + ), '@findtags?tag=', + array('class' => 'tag-cloud-right'), + __('Popular tags')); + break; + }*/ + +?> \ No newline at end of file diff --git a/apps/reaktor/modules/tags/templates/_sortlinks.php b/apps/reaktor/modules/tags/templates/_sortlinks.php new file mode 100644 index 0000000..bcf46de --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_sortlinks.php @@ -0,0 +1,41 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + $sortdirection_date = ($sortmode == 'date') ? (($sortdirection == 'asc') ? 'desc' : 'asc') : 'desc'; + $sortdirection_title = ($sortmode == 'title') ? (($sortdirection == 'asc') ? 'desc' : 'asc') : 'asc'; + $sortdirection_rating = ($sortmode == 'rating') ? (($sortdirection == 'asc') ? 'desc' : 'asc') : 'desc'; + $sortdirection_username = ($sortmode == 'username') ? (($sortdirection == 'asc') ? 'desc' : 'asc') : 'asc'; + + if (isset($tags) && is_array($tags)) + { + $tags = implode(",", $tags); + } + + $route = ($mode == 'tag') ? '@findtags?tag='.$tags : '@findcategory?category='.$categories; + +?> + diff --git a/apps/reaktor/modules/tags/templates/_tagEditList.php b/apps/reaktor/modules/tags/templates/_tagEditList.php new file mode 100644 index 0000000..1b5e46d --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_tagEditList.php @@ -0,0 +1,181 @@ + tag every time this limit is reached when listing tags + * - artworkList : Tells the component that this is an artwork list, overrides the use of extra file id + * - nomargin : If set removes the left margin from the ul element + * - extraId : File id or artwork id that will be appended + * - tageditor : True or false, includes a tag editor partial to handle normalisation - should only be used on vertical lists + * - completeFuncs : Javascript functions to be called when ajax requests have completed, seperate with semi-colon. + * - commas : Show commas next to tags in list view + * + * This template may be rendered by a calling (parent) template or an ajax call. + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +$tagList = ""; +$notTheFirst = false; +use_helper("Javascript"); + +$objectId = isset($objectId) ? $objectId : 0; +$taggable = isset($taggable) ? $taggable : 0; +$tagCount = 0; +$unapprovedTagsExist = array(); + +$DEFAULT_OPTIONS = array( + "rowLimit" => 0, + "artworkList" => false, + "nomargin" => false, + "extraId" => "", + "completeFuncs" => "", + "tageditor" => false, + "commas" => false, +); +if (isset($options) && !empty($options)) +{ + $options = $options + $DEFAULT_OPTIONS; +} +else +{ + $options = $DEFAULT_OPTIONS; +} + +?> + + + + +
      > + + +
    • + + + hasCredential("approvetags") && $tagObject->getApproved() == 0): ?> + "10")), array( + 'update' => 'currentTags'.$options["extraId"], + 'url' => 'tags/tagAction', + 'script' => true, + 'with' => "'".http_build_query(array("options" => $options))."&file=".$objectId."&taggable=".$taggable."&tag=".$tagObject->getName()."&mode=approve&page=".$sf_params->get("page")."&unapproved=".$sf_params->get("unapproved")."'", + 'loading' => "Element.show('tag_indicator')", + 'complete' => "setTimeout('Element.hide(\'tag_indicator\')', 500);".($options["completeFuncs"]), + 'confirm' => __('Are you sure you wish to approve the tag: %1% ?', array('%1%' => $tagObject->getName())) + )); + $unapprovedTags[] = $tagObject->getName(); + ?> + + hasCredential("tagadministrator") && ($tagObject->getApproved() == 1 || $sf_params->get("page"))): ?> + getApproved()) ? "indent" : ""; ?> + "10", "class" => $class)), array( + 'update' => 'currentTags'.$options["extraId"], + 'url' => 'tags/tagAction', + 'script' => true, + 'with' => "'".http_build_query(array("options" => $options))."&file=".$objectId."&taggable=".$taggable."&tag=".$tagObject->getName()."&mode=unapprove&page=".$sf_params->get("page")."&unapproved=".$sf_params->get("unapproved")."'", + 'loading' => "Element.show('tag_indicator')", + 'complete' => "setTimeout('Element.hide(\'tag_indicator\')', 500);".($options["completeFuncs"]), + 'confirm' => __('Are you sure you wish to unapprove and completely remove this tag (%1%) from the system? This will affect all other tagged objects using this tag.', array('%1%'=> $tagObject->getName())) + )); ?> + + 0): ?> + hasCredential("tagadministrator")) ? "indent" : "" ?> + + $tagObject->getName())); ?> + + $tagObject->getName())); ?> + + "10", "class" => $class)), array( + 'update' => 'currentTags'.$options["extraId"], + 'url' => 'tags/tagAction', + 'script' => true, + 'with' => "'".http_build_query(array("options" => $options))."&file=".$objectId."&taggable=".$taggable."&tag=".$tagObject->getName()."&mode=delete&page=".$sf_params->get("page")."&unapproved=".$sf_params->get("unapproved")."'", + 'loading' => "Element.show('tag_indicator')", + 'complete' => "setTimeout('Element.hide(\'tag_indicator\')', 500);".($options["completeFuncs"]), + 'confirm' => $confirm_string + )); ?> + + hasCredential("tagadministrator")): ?> + 10)), + "Effect.toggle('tageditor_".$tagObject->getId()."', 'slide')"); ?> + + + '> + + getName(), "@findtags?tag=".$tagObject->getName()); ?> + + getName(); ?> + + + + hasCredential("tagadministrator")): ?> + $tagObject)); ?> + + 0 && $tagcc < (count($tags) - 1)) echo ', '; ?> +
    • + 0 && ++$tagCount % $options["rowLimit"] == 0): ?> +
      + + + +
    + hasCredential("approvetags")): ?> + ".__("These actions apply to unapproved tags only, you can quickly approve or remove all the red tags by clicking one of these icons")."
    "; ?> +
    " class="all_tag_actions"> + "")); ?> + "10")), array( + 'update' => 'currentTags'.$options["extraId"], + 'url' => 'tags/tagAction', + 'with' => "'".http_build_query(array("options" => $options, "unapprovedTags" => $unapprovedTags))."&file=".$objectId."&taggable=".$taggable."&tag=".$tagObject->getName()."&mode=approveall&page=".$sf_params->get("page")."&unapproved=".$sf_params->get("unapproved")."'", + 'loading' => "Element.show('tag_indicator')", + 'complete' => "setTimeout('Element.hide(\'tag_indicator\')', 500);".($options["completeFuncs"]), + 'confirm' => __('Are you sure you wish to APPROVE all of the following tags? %tag_list%', array("%tag_list%" => "\\n\\n".implode(", ", $unapprovedTags))), + ), array("onMouseover" => "Tip('".$tiptext."');", "onMouseout" => "UnTip();")); ?> + 0): ?> + "10")), array( + 'update' => 'currentTags'.$options["extraId"], + 'url' => 'tags/tagAction', + 'with' => "'".http_build_query(array("options" => $options, "unapprovedTags" => $unapprovedTags))."&file=".$objectId."&taggable=".$taggable."&tag=".$tagObject->getName()."&mode=deleteall&page=".$sf_params->get("page")."&unapproved=".$sf_params->get("unapproved")."'", + 'loading' => "Element.show('tag_indicator')", + 'complete' => "setTimeout('Element.hide(\'tag_indicator\')', 500);".($options["completeFuncs"]), + 'confirm' => __('Are you sure you wish to REMOVE all of the following tags from this work? %tag_list%', array("%tag_list%" => "\\n\\n".implode(", ", $unapprovedTags))), + ), array("onMouseover" => "Tip('".$tiptext."');", "onMouseout" => "UnTip();")); ?> + + hasCredential("tagadministrator")): ?> + "10")), array( + 'update' => 'currentTags'.$options["extraId"], + 'url' => 'tags/tagAction', + 'with' => "'".http_build_query(array("options" => $options, "unapprovedTags" => $unapprovedTags))."&file=".$objectId."&taggable=".$taggable."&tag=".$tagObject->getName()."&mode=unapproveall&page=".$sf_params->get("page")."&unapproved=".$sf_params->get("unapproved")."'", + 'loading' => "Element.show('tag_indicator')", + 'complete' => "setTimeout('Element.hide(\'tag_indicator\')', 500);".($options["completeFuncs"]), + 'confirm' => __('Are you sure you wish to DELETE all of the following tags from the system? %tag_list%', array("%tag_list%" => "\\n\\n".implode(", ", $unapprovedTags))), + ), array("onMouseover" => "Tip('".$tiptext."');", "onMouseout" => "UnTip();")); ?> + +
    + +get("page")): ?> + $taggableObject, "options" => $options)); ?> + +
    +
      +
    • +
    +
    + + diff --git a/apps/reaktor/modules/tags/templates/_tagKey.php b/apps/reaktor/modules/tags/templates/_tagKey.php new file mode 100644 index 0000000..ca95822 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_tagKey.php @@ -0,0 +1,32 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + +

    +
    +
      +
    • + + +
    • +
    • + + +
    • +
    • + 10)); ?> + +
    • +
    \ No newline at end of file diff --git a/apps/reaktor/modules/tags/templates/_tagSearchBox.php b/apps/reaktor/modules/tags/templates/_tagSearchBox.php new file mode 100644 index 0000000..6150558 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_tagSearchBox.php @@ -0,0 +1,35 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('wai'); +?> + diff --git a/apps/reaktor/modules/tags/templates/_tagWarningMessage.php b/apps/reaktor/modules/tags/templates/_tagWarningMessage.php new file mode 100644 index 0000000..244710e --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_tagWarningMessage.php @@ -0,0 +1,37 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + +
    +
    > + + +
  • */ ?> +
    +
    + +
    +
      > +
    • + +
    • */ ?> +
    +
    + \ No newline at end of file diff --git a/apps/reaktor/modules/tags/templates/_tagWrapper.php b/apps/reaktor/modules/tags/templates/_tagWrapper.php new file mode 100644 index 0000000..6b72041 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_tagWrapper.php @@ -0,0 +1,74 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript", "wai"); +if (!isset($completeFuncs)) +{ + $completeFuncs = ""; +} +switch (get_class($thisObject)) +{ + case "genericArtwork": $extraId = "artwork".$thisObject->getId(); + case "artworkFile" : + if (isset($artworkList) && $artworkList) + { + $extraId = "artwork".$artworkList; + } + else + { + $extraId = "file".$thisObject->getId(); + } + break; + case "Article" : $extraId = "article".$thisObject->getId();break; + default : $extraId = ""; break; +} +if(isset($artworkList)){ + $options = array("completeFuncs" => $completeFuncs, "artworkList" => $artworkList , "extraId" => $extraId); + } + else + { + $options = array("completeFuncs" => $completeFuncs, "extraId" => $extraId); + } +?> + + 'currentTags_'.$extraId, + 'url' => 'tags/tagAction?file='.$thisObject->getId().'&mode=add&taggable='.get_class($thisObject) .'&'. http_build_query(array("options" => $options), null, "&"), + 'loading' => "Element.show('tag_indicator')", + 'complete' => "Element.hide('tag_indicator'); ".$completeFuncs, + 'script' => true, + 'success' => "$('tags').value = ''", + ), + array("name" => "tag_form")) ?> +
    +
    + +
    +
    + $thisObject->getTaggableModel(), "id" => $thisObject->getId())); ?> +
    +
    + +
    +
    +
    + $thisObject, "options" => $options)); ?> +
    +
    +
    + diff --git a/apps/reaktor/modules/tags/templates/_tageditor.php b/apps/reaktor/modules/tags/templates/_tageditor.php new file mode 100644 index 0000000..7792c28 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_tageditor.php @@ -0,0 +1,45 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + + + + diff --git a/apps/reaktor/modules/tags/templates/_viewTagsWithLinks.php b/apps/reaktor/modules/tags/templates/_viewTagsWithLinks.php new file mode 100644 index 0000000..952e2d6 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_viewTagsWithLinks.php @@ -0,0 +1,25 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + + + + "tag")) ?> + + + + + + diff --git a/apps/reaktor/modules/tags/templates/_viewTagsWithStatus.php b/apps/reaktor/modules/tags/templates/_viewTagsWithStatus.php new file mode 100644 index 0000000..51d9080 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/_viewTagsWithStatus.php @@ -0,0 +1,36 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +$tagsToDisplay = array(); +?> + $tagArray): ?> + + + + ".$tag.""; ?> + + ".$tag.""; ?> + + + + + + + ""));?> + + + diff --git a/apps/reaktor/modules/tags/templates/findSuccess.php b/apps/reaktor/modules/tags/templates/findSuccess.php new file mode 100644 index 0000000..38b3945 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/findSuccess.php @@ -0,0 +1,164 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper('content', 'home', 'Cache'); +if (isset($tags)) reaktor::setReaktorTitle(__("Search for %search_items%", array("%search_items%" => implode(", ", $tags)))); +elseif (isset($categories)) reaktor::setReaktorTitle( __('work in %category% category', array("%category%" => $categories))); + +?> + + 0): ?> +
    + + $tags, 'mode' => $mode, 'sortmode' => $sortmode, 'sortdirection' => $sortdirection, 'results' => $results)); ?> + + $categories, 'mode' => $mode, 'sortmode' => $sortmode, 'sortdirection' => $sortdirection, 'results' => $results)); ?> + + + +
    + $articleMatches): ?> +
    +
    + + __('articles in %category% category', array("%category%" => $tag)), 'slug' => 'articles_in_category_'.$tag)); ?> +

    $tag)); ?> ()

    + + __('articles tagged with %tag%', array("%tag%" => $tag)), 'slug' => 'articles_tagged_with_'.$tag)); ?> +

    $tag)); ?> ()

    + + +
    +

    getTitle(), $article->getLink()); ?>

    +

    + date("H:i", strtotime($article->getUpdatedAt())), + "%publish_date%" => date("d/m/Y", strtotime($article->getUpdatedAt())))); ?> +

    +
    +

    + getIngress()); ?> + getContent()): ?> + getLink())." ]"; ?> + +

    +
    + +
    + +
    + 1): ?> + + __('articles tagged with %tags%', + array("%tags%" => implode(', ', $justTags))), + 'slug' => 'articles_tagged_with_'.implode('_', $justTags), + 'class' => 'bottom_right_outside', + 'caption' => __('Subscribe to this result set'))); ?> + +
    + + + +
    + $matches): ?> +
    +
    + + __('work in %category% category', array("%category%" => $tag)), 'slug' => 'in_category_'.$tag)); ?> +

    $tag)); ?> ()

    + + __('work tagged with %tag%', array("%tag%" => $tag)), 'slug' => 'tagged_with_'.$tag)); ?> +

    $tag)); ?> ()

    + + +
    +
    + getAverageRating()); ?> +
    + '78x65', 'alt' => $match->getTitle(), 'title' => $match->getTitle())), + $match->getLink()); ?> +

    + getTitle(), + "@show_artwork?id=".$match->getId(). + "&title=".$match->getTitle()); ?> + getUser()->getUsername(), "@portfolio?user=".$match->getUser()->getUsername()); + $tmp_username = '' .$tmp_username. ''; + echo __('%artwork_title% by %username%', + array('%artwork_title%' => $tmp_artwork_title, + '%username%' => $tmp_username)); ?> +

    + + date("H:i", strtotime($match->getCreatedAt())), + '%upload_date%' => date("d/m/Y", strtotime($match->getCreatedAt())))); ?> +
    +
    + + getTags() as $aTag): ?> + "tag")); ?> + + + + +
    +
    + +
    +
    + + 1): ?> + + __('work tagged with %tags%', + array("%tags%" => implode(', ', $justTags))), + 'slug' => 'tagged_with_'.implode('_', $justTags), + 'class' => 'bottom_right_outside', + 'caption' => __('Subscribe to this result set'))); ?> + +
    + +
    + +
    + get('tag')): ?> + get("findtype") == "user"): $search_type = __("users"); ?> + + + $search_type, "%search_string%" => "".$sf_params->get("tag")."")); ?> + + + +

    + 'tag-cloud-right', 'parent_approved' => 1, + 'subreaktor' => Subreaktor::getProvidedSubreaktor(), 'lokalreaktor' => Subreaktor::getProvidedLokalreaktor())); + + ?> + diff --git a/apps/reaktor/modules/tags/templates/listTagsSuccess.php b/apps/reaktor/modules/tags/templates/listTagsSuccess.php new file mode 100644 index 0000000..9159487 --- /dev/null +++ b/apps/reaktor/modules/tags/templates/listTagsSuccess.php @@ -0,0 +1,55 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::setReaktorTitle(__("Tags (%tag_letter%)", array("%tag_letter%" => $page))); + +?> +
    + $pageLinks, 'thisPage'=>$page)); ?> +

    + + + get("unapproved")): ?> + + get("unapproved")): ?> + + + + + + +

    + +
    + +
    + $tags, "unapproved" => $sf_params->get("unapproved"), "options" => array("tageditor" => true))); ?> +
    + +
    +

    +
    +
      +
    • + get("unapproved")): ?> + + + + + + +
    • +
    + + +
    diff --git a/apps/reaktor/modules/upload/actions/actions.class.php b/apps/reaktor/modules/upload/actions/actions.class.php new file mode 100644 index 0000000..2a07990 --- /dev/null +++ b/apps/reaktor/modules/upload/actions/actions.class.php @@ -0,0 +1,1628 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * The main upload class file + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class uploadActions extends sfActions +{ + /** + * The identifier used to connect the file to a type + * For example: image, video, pdf... + * + * @var string + */ + protected $identifier; + + /** + * The subdirectory to use based on the type + * + * @var string + */ + protected $subdir; + + /** + * The mimetype of the file + * + * @var string + */ + protected $mimeType; + + /** + * The thumbnail name + * + * @var string + */ + protected $thumbname = ""; + + /** + * Shows a list of the user's files, or if admin any user based on params + * + * @return void + */ + public function executeShowFiles() + { + // Lets see if we are an admin user accessing a specific user page + if ($this->getRequestParameter("user")) + { + $this->forward404Unless($this->getUser()->hasCredential('viewallcontent')); + $userId = $this->getRequestParameter("user"); + } + else + { + $userId = $this->getUser()->getGuardUser()->getId(); + } + + $c = new Criteria(); + $c->add(ReaktorFilePeer::USER_ID, $userId); + $c->addAscendingOrderByColumn(ReaktorFilePeer::UPLOADED_AT); + + if (!$userFilesArray = ReaktorFilePeer::doSelect($c)) + { + return sfView::SUCCESS; + } + + foreach ($userFilesArray as $key => $fileObject) + { + $userFiles[] = new artworkFile($fileObject->getId()); + } + + $this->userFiles = $userFiles; + + } + + + + + +/** + * Uploads the file and triggers events associated with the upload + * + * @return void + */ + public function executeUpload() + { +//sfLoader::loadHelpers(array("Debug")); +// log_message('test message'); + // Is the user trying to link this file to another artwork? + + + + + + + if ($this->getRequestParameter("link_artwork_id") > 0) + { + // Check if they own the artwork, or are allowed to link to it + try + { + $linkArtwork = new genericArtwork($this->getRequestParameter("link_artwork_id")); + } + catch (exception $e) + { + return $this->redirect(Subreaktor::addSubreaktorToRoute("@upload_content")); + } + if ($linkArtwork->getUserId() != $this->getUser()->getGuardUser()->getId() && !$this->getUser()->hasCredential('editusercontent')) + { + return $this->redirect(Subreaktor::addSubreaktorToRoute("@upload_content")); + } + else + { + $this->artwork = $linkArtwork; // For the template + $extraParam = "&link=".$linkArtwork->getId(); + } + } + else + { + $extraParam = ""; //x + } + + $this->forward404Unless($this->getUser()->hasCredential('uploadcontent')); + + if ($this->getRequest()->getMethod() != sfRequest::POST && !$this->getRequestParameter("mce_data")) + { + return sfView::SUCCESS; + } + + //******* File has been uploaded ********/ + + if (!$this->getRequest()->getFileName('file') && !$this->getRequestParameter('mce_data')) + { + return $this->returnError('Please select a valid file'); + } + + $webAbsCurrentDir = '/'.$this->uploadDirName; + $meta = array(); + + if ( !$this->getRequestParameter('mce_data') ) + { + $this->originalFilename = $this->sanitizeFile($this->getRequest()->getFileName('file')); + $this->filename = $this->nameFile($this->originalFilename); + + /* mime_content_type is deprecated but the alternatives were becoming a nightmare to set up + * sometimes this function returns false (for example with wma files) in which case we then revert to + * the mime type that the browser sends. It seems to work. + */ + +# if (!$this->mimeType = mime_content_type($this->getRequest()->getFilePath('file'))) + + +/* + + mime_content_type funcion have been replaced by getFileType2 in the transcoderlibrary + + !!!!!!!!!!!!!!!!!!!!!!!!! + If you have problem witch mimetype detection! + Please remeber to give write access to apache user home direcory, so it can create ~/.gnome folder which is needed by one of library + !!!!!!!!!!!!!!!!!!!!!!!!! + +*/ + + $outputBaseDir = sfConfig::get('sf_root_dir')."/".sfConfig::get('app_upload_upload_dir')."/"; + $transcoder = new transcoder($outputBaseDir); + + + if (!$this->mimeType = $transcoder->getFileType2($this->getRequest()->getFilePath('file'))) + { + $this->mimeType = $this->getRequest()->getFileType('file'); + + } + } + else + { + $this->filename = $this->nameFile($this->originalFilename).".html"; + $this->originalFilename = $this->filename; + $this->mimeType = "text/html"; + } + + + $info['ext'] = strtolower(substr($this->filename, strpos($this->filename, '.') - mb_strlen($this->filename, 'UTF-8') + 1)); + $info['size'] = $this->getRequest()->getFileSize('file'); + $convertedMime = $this->mimeType; // ZOID: These are a bit dirty in the db so improve + $thumbMime = $this->mimeType; + $this->originalPath = $this->filename; + + //Get parameters + if ($paramArray = $this->getParams($this->mimeType)) + { + $this->identifier = $paramArray["identifier"]; + $this->subdir = $paramArray["subdir"]; + + } + else + { + if ($this->getUser()->hasCredential("viewdetailederrors")) + { + return $this->returnError('Mime type does not exist in db: '.$this->mimeType); + } + //Trick to make script translate + $translateMe = sfContext::getInstance()->getI18N()->__('Unsupported file type'); + return $this->returnError('Unsupported file type'); + } + + //If linking, lets check that the user is uploading a file of the same type + + if (isset($linkArtwork) && !in_array($this->identifier, $linkArtwork->getEligbleFileTypes())) + { + $this->getRequest()->setError('link_error', $this->identifier); + return $this->returnError("Wrong file type"); + } + + $this->absCurrentDir = $this->uploadDir.'/'.$this->subdir; + + if ( !is_dir($this->absCurrentDir) || !file_exists($this->getRequest()->getFilePath('file')) ) + { + if ( $this->getRequestParameter('mce_data') && is_dir($this->absCurrentDir) ) + { + $text = $this->stripTags($this->getRequestParameter('mce_data')); + file_put_contents($this->absCurrentDir . '/' . $this->filename,$text); + } + else + { + return $this->returnError('The upload failed'); + } + } + + + switch ($this->identifier) { + + case "image": + + try + { + if ($this->useThumbnails) + { + $this->createThumb(); + } + $this->processImage(); + } + catch (Exception $e) + { + $this->getRequest()->setError('file', sfContext::getInstance()->getI18N()->__('Reading the image failed')); + return sfView::SUCCESS; + } + + break; + + + case "pdf": + try + { + $this->createPdfThumb(); + } + catch (Exception $e) + { + $this->getRequest()->setError('file', 'Reading the pdf failed'); + return sfView::SUCCESS; + } + break; + + case "text": + //After moving the text creation, text is written _after_ the thumb is generated, + //We better leave the artwork with the default thumb + /*try + { + $this->createHTMLThumb($this->uploadDir.'/'.$this->subdir.'/'.$this->filename); + + } + catch (Exception $e) + { + $this->getRequest()->setError('file', 'Reading the text failed'); + return sfView::SUCCESS; + } + */ + break; + +default: + +; + + + + } + + + + // Is this a media type we must transcode? + if ((($this->identifier == "video" && $this->mimeType != 'application/x-shockwave-flash') || ($this->identifier == "audio" && $info['ext'] != "mp3") || ($this->identifier == "container")) && ($this->mimeType != 'image/gif')) + { + // Now send for transcoding + + try + { +// $outputBaseDir = sfConfig::get('sf_root_dir')."/".sfConfig::get('app_upload_upload_dir')."/"; +// $transcoder = new transcoder($outputBaseDir); + $file = $this->getRequest()->getFilePath('file'); + $transcodingInfo = $transcoder->transcode($file, $this->filename, array("suggested_mime" => $this->mimeType)); + + $this->filename = $transcodingInfo['newFileName']; + $this->convertedMime = $transcodingInfo['convertedMime']; + $this->mimeType = $transcodingInfo['detectedMime']; + + $dir = null; + switch ($this->convertedMime) + { + case 'video/flv': + $dir = 'video'; + $this->identifier = "video"; + $this->subdir = "video"; + $this->absCurrentDir = $this->uploadDir.'/'.$this->subdir; + + break; + case 'audio/mpeg': + $dir = 'audio'; + $this->identifier = "audio"; + $this->subdir = "audio"; + $this->absCurrentDir = $this->uploadDir.'/'.$this->subdir; + break; + + default: + throw new Exception('Unhandled mime type'); + break; + } + } + catch (Exception $e) + { + if ($this->getUser()->hasCredential("viewdetailederrors")) + { + return $this->returnError(sfContext::getInstance()->getI18N()->__("Converting the file failed")." - ".$e->getMessage()); + } + return $this->returnError(sfContext::getInstance()->getI18N()->__("Converting the file failed")); + } + $orig = $outputBaseDir.$dir."/original/".$this->originalPath; + copy($file, $orig); + + if ($this->convertedMime == 'video/flv') + { + + new videoFrame(); + $vf = videoFrame::fromVideoFile($file); + if ($vf) + { + $this->createThumbFromVideoFrame($vf); + } + + } + } + else + { + // Doesn't need transcoding, move the file from temp dir to main dir + $this->getRequest()->moveFile('file', $this->absCurrentDir.'/'.$this->filename); + if ($this->mimeType == "text/html") + { + $html_data = file_get_contents($this->absCurrentDir.'/'.$this->filename); + file_put_contents($this->absCurrentDir.'/'.$this->filename,$this->stripTags($html_data)); + } + } + + //Save file information to database via the artworkFile object + try + { + $uploadedFile = new artworkFile(); + $uploadedFile->setPath($this->filename); + $uploadedFile->setOriginalpath($this->originalPath); + $uploadedFile->setFilename($this->originalFilename); + $uploadedFile->setThumbpath($this->thumbname); + + $uploadedFile->setIdentifier($this->identifier); + $uploadedFile->setMimetype($convertedMime, "converted"); + $uploadedFile->setMimetype($this->mimeType, "original"); + $uploadedFile->setMimetype($thumbMime, "thumbnail"); + $uploadedFile->setUploadedAt(time()); + $uploadedFile->setModifiedAt(time()); + if (isset($linkArtwork) && $this->getUser()->hasCredential("editusercontent")) + { + $uploadedFile->setUserId($linkArtwork->getUserId()); + } + else + { + $uploadedFile->setUserId($this->getUser()->getGuardUser()->getId()); + } + + $uploadedFile->save(); + + + //Add the file metadata that we can automatically extract + $this->addMeta($info, $uploadedFile); + + // Lets add the current user as "creator" + if (!$uploadedFile->getMetadata("creator") && $this->getUser()->getGuardUser()->getUserName()) + { + $uploadedFile->addMetadata("creator", null, $this->getUser()->getGuardUser()->getUserName()); + } + HistoryPeer::logAction(11, $this->getUser()->getId(), $uploadedFile); + $this->redirect(Subreaktor::addSubreaktorToRoute('@edit_upload?fileId='.$uploadedFile->getId().$extraParam)); + } + + catch (Exception $e) + { + if ($this->getUser()->hasCredential("viewdetailederrors")) + { + return $this->returnError('Error saving file: '.$e->getMessage()); + } + $this->returnError('Unsupported file type'); + } + } + + function executeUploadAttachment() + { + $this->getTracker()->setEnabled(false); + sfConfig::set('sf_web_debug', false); + do { + if (!($this->getUser()->isAuthenticated())) + { + $error = "You cannot do that"; + break; + } + + if (!is_uploaded_file($this->getRequest()->getFilePath('file'))) + { + $error = "Not uploading?"; + break; + } + + $article_id = $this->getRequestParameter("article_id"); + + if (!$article_id || !($article = ArticlePeer::retrieveByPK($article_id))) + { + $error = "Cannot find the article to attach to"; + break; + } + + $access = ArticlePeer::getArticleTypesByPermission($this->getUser()); + if (!isset($access[$article->getArticleType()])) + { + $error = "You are not allowed to do that"; + break; + } + + $banner = (bool)$this->getRequestParameter("banner"); + + $path = sfConfig::get("sf_web_dir") . sfConfig::get("app_upload_attachment_dir", "attachment") . "/"; + $ofn = $this->sanitizeFile($this->getRequest()->getFileName('file')); + $fn = $this->nameFile($ofn); + + $mime = FileMimetypePeer::retrieveByMimetype($this->getRequest()->getFileType('file')); + if (!$mime) + { + $error = "Invalid mime type"; + break; + } + + $file = new ArticleFile; + $file->setPath($path); + $file->setFilename($fn); + $file->setsfGuardUser($this->getUser()->getGuardUser()); + $file->setUploadedAt($_SERVER['REQUEST_TIME']); + $file->upload($this->getRequest()->getFilePath('file')); + $file->setFileMimeType($mime); + $file->save(); + + //if($article->getArticletype()==2){ +// if (!$banner) +// { +// $attachment = new ArticleAttachment; +// $attachment->setArticleFile($file); +// +// $article->addArticleAttachment($attachment); +// +// $attachment->save(); +// } +// else +// { +// $article->setBannerFileId($file->getId()); +// } + +//7 $article->save(); +// } +# sfLoader::loadHelpers('Partial'); +# return $this->renderText(get_component('filelist', 'browseFiles', array( +# 'article' => $article->getId(), +# 'chosen_format' => $this->getRequestParameter('chosen_format'), +# ))); + + $this->forward('filelist', 'browseFiles',array()); + // return $this->renderText("OK"); + + } while(false); + return $this->renderText($error); + } + + /** + * File uploaded, now we need to do something with it + * Could also be used for editing "after the event" + * + * @return void - the template + */ + public function executeEdit() + { + $fileId = intval($this->getRequestParameter('fileId')); + try + { + //sfContext::getInstance()->getLogger()->info("Before creating file object with ID: ".$fileId); + $this->thisFile = new artworkFile($fileId); + //sfContext::getInstance()->getLogger()->info("After creating file object".$fileId); + } + catch (Exception $e) + { + $this->forward404($e); + } + + $filename = $this->thisFile->getFilename(); + $submitter_id = $this->thisFile->getUserId(); + + //Check that this user is allowed to be on this page, either the user who submitted + //the file, or an admin user with the correct credentials. + $this->forward404Unless($submitter_id == $this->getUser()->getGuardUser()->getId() + || $this->getUser()->hasCredential('editusercontent')); + + // This will be overridden by the i18n in the template but must be set here so it appears at the top + $artworkArray[0] = "--- Select the artwork to attach this file to ---"; + + $eligibleArtwork = ReaktorArtworkPeer::getLinkableArtworks($this->thisFile); + + if ($eligibleArtwork) + { + foreach ($eligibleArtwork as $artworkObject) + { + $artworkArray[$artworkObject->getId()] = $artworkObject->getTitle(); + } + } + $this->artworkArray = $artworkArray; + + //if not post, and html file, read the file content + if ($this->getRequest()->getMethod() != sfRequest::POST && $this->thisFile->getIdentifier() == "text") + { + $paramArray = $this->getParams($this->thisFile->getMimetype()); + $this->identifier = $paramArray["identifier"]; + $this->subdir = $paramArray["subdir"]; + + $this->filename = $this->thisFile->getRealPath(); + $this->absCurrentDir = $this->uploadDir.'/'.$this->subdir; + $this->mce_data = file_get_contents($this->absCurrentDir . '/' . $this->filename); + + } + // Stop here and display the form if no form submission + if ($this->getRequest()->getMethod() != sfRequest::POST) + { + return sfView::SUCCESS; + } + + if ($this->getRequest()->hasErrors()) + { + //Take care of the already entered metadata when form errs + $this->thisFile->fillinMetaData("title", null, $this->getRequestParameter('title')); + $this->thisFile->fillinMetaData("creator", null, $this->getRequestParameter("author")); + $this->thisFile->fillinMetaData("relation", "references", $this->getRequestParameter("resources")); + $this->thisFile->fillinMetaData("license", null, $this->getRequestParameter("meta_license")); + if ($this->thisFile->getMimetype() != "text/html") + { + $this->thisFile->fillinMetadata("description", "abstract", $this->getRequestParameter("description")); + $this->thisFile->fillinMetadata("description", "creation", $this->getRequestParameter("production")); + //$this->thisFile->fillinMetadata("relation", "references", $this->getRequestParameter("resources")); + } + return sfView::SUCCESS; + } + + $this->thisFile->addMetadata("title", null, $this->getRequestParameter('title')); + $this->thisFile->addMetadata("creator", null, $this->getRequestParameter("author")); + $this->thisFile->addMetadata("relation", "references", $this->getRequestParameter("resources")); + $this->thisFile->addMetadata("license", null, $this->getRequestParameter("meta_license")); + $main_mime_type = substr($this->thisFile->getMimetype(),0,4); + if ( $main_mime_type == "text" ) + { + $paramArray = $this->getParams($this->thisFile->getMimetype()); + $this->identifier = $paramArray["identifier"]; + $this->subdir = $paramArray["subdir"]; + + $this->filename = $this->thisFile->getRealPath(); + $text = $this->stripTags($this->getRequestParameter('mce_data')); + $this->absCurrentDir = $this->uploadDir.'/'.$this->subdir; + file_put_contents($this->absCurrentDir . '/' . $this->filename,$text); + $this->mce_data = $text; + + } + else + { + $this->thisFile->addMetadata("description", "abstract", $this->getRequestParameter("description")); + $this->thisFile->addMetadata("description", "creation", $this->getRequestParameter("production")); + } + + /* Check if this file is linked to any artworks already, and if so, we need to + Make sure they are flagged for follow up - unless being + Edited by an admin user with editusercontent credential*/ + + try + { + if ($this->thisFile->hasArtwork() && !$this->getUser()->hasCredential('editusercontent')) + { + $parentArtworks = $this->thisFile->getParentArtworks(); + foreach($parentArtworks as $parentArtwork) + { + if ($parentArtwork->getStatus() == 3) + { + sfLoader::loadHelpers(array("Url", "Tag")); + $translateMe = sfContext::getInstance()->getI18n()->__("The following file was edited"); + $parentArtwork->flagChanged($this->getUser(), "The following file was edited"); + $parentArtwork->flagChanged($this->getUser(), " - ".link_to($this->thisFile->getTitle()." (".$this->thisFile->getId().")", "@edit_upload?fileId=".$this->thisFile->getId())); + $parentArtwork->save(); + } + } + } + } + catch (Exception $e) + { + die($e->getMessage()); + } + $this->thisFile->save(); + // Are we creating a new artwork? + if ($this->getRequestParameter("new_artwork")) + { + try + { + $newArtwork = new genericArtwork(); + $newArtwork->setTitle($this->getRequestParameter('title')); + $newArtwork->setUserId($submitter_id); + $newArtwork->setArtworkType($this->thisFile->getIdentifier()); + $newArtwork->setDescription($this->thisFile->getMetadata("description", "abstract")); + $newArtwork->save(); + + // Add local reaktor automatically if we are in one now + if (Subreaktor::getProvidedLokalReference()) + { + $newArtwork->addSubreaktor(Subreaktor::getProvidedLokalReference()); + } + +//Add artwork to LokalReaktor if user residence = reaktor residence +// Ticket 23735 + $LokalReaktorsByResidences=LokalreaktorResidencePeer::getSubreaktorsByResidence($this->getUser()->getGuardUser()->getResidenceId()); + + if(is_array($LokalReaktorsByResidences)) { + foreach($LokalReaktorsByResidences as $LokalReaktor) + $newArtwork->addSubreaktor($LokalReaktor->getSubreaktorId()); + + } + + + $newArtwork->addFile($this->thisFile->getId()); + + // Add subreaktor too if we are in one + // Will only work if subreaktor is relevant, for example an image won't be added to video subreaktor + // Fix bug #473, customer does not want this. + /*if (Subreaktor::getProvidedSubreaktor()) + { + $newArtwork->addSubreaktor(Subreaktor::getProvidedSubreaktor()->getId()); + }*/ + $newArtwork->resetFirstFile(); + } + catch (Exception $e) + { + // ZOID: Move to general error area + $this->getRequest()->setError("title", $e->getMessage()); + //$this->getRequest()->setError("title", "Error creating new artwork"); + return sfView::SUCCESS; + } + // Redirect back to upload page if they chose to + if ($this->getRequestParameter("upload_another")) + { + return $this->redirect(Subreaktor::addSubreaktorToRoute("@artwork_link?link_artwork_id=".$newArtwork->getId())); + } + else + { + //$tmproute = '@show_artwork?title='.$newArtwork->getTitle().'&id='.$newArtwork->getId(); + //Subreaktor::addSubreaktorToRoute('@show_artwork?title='.$newArtwork->getTitle().'&id='.$newArtwork->getId()); + $this->redirect(Subreaktor::addSubreaktorToRoute('@edit_artwork?id='.$newArtwork->getId())); + } + } + elseif ($this->getRequestParameter("link_artwork")) + { + try + { + $artwork = new genericArtwork($this->getRequestParameter("artwork_select")); + $artwork->addFile($this->thisFile); + if (!$artwork->isDraft()) + { + $artwork->changeStatus($this->getUser()->getGuardUser()->getId(), ReaktorArtwork::SUBMITTED); //Set the status back to ready for approval + } + $artwork->save(); + $artwork->resetFirstFile(); + } + catch (Exception $e) + { + //ZOID: Move to general error area + $this->getRequest()->setError("title", "Error linking artwork"); + return sfView::SUCCESS; + } + if ($this->getRequestParameter("link_another")) + { + return $this->redirect(Subreaktor::addSubreaktorToRoute("@artwork_link?link_artwork_id=".$artwork->getId())); + } + else + { + return $this->redirect(Subreaktor::addSubreaktorToRoute('@edit_artwork?id='.$artwork->getId())); + } + } + else + { + //Everything went ok so lets give a message to say so + $this->successful = true; + return sfView::SUCCESS; + } + } + + /** + * File validator - ZOID: IS THIS USED? + * Placed here instead of in Yaml file so it will be processed regardless + * of any other form errors + * + * @param string $fieldName the value to look for in the post request + * + * @return boolean success or failure of validation + */ + protected function validateFile($fieldName) + { + $name = $this->getRequest()->getFilename($fieldName); + if (!$name) + { + return false; + } + + $myValidator = new sfFileValidator(); + $myValidator->initialize($this->getContext(), array( + 'mime_types' => array('image/jpeg'), + 'mime_types_error' => 'Only JPEG images are allowed', + 'max_size' => 512000, + 'max_size_error' => 'Max size is 512Kb' + )); + $file_array = $this->getRequest()->getFile($fieldName); + if (!$myValidator->execute($file_array, $error)) + { + $this->getRequest()->setError($fieldName, $error); + return false; + } + return true; + } + + /** + * Direct form errors back to main template + * + * @return void + */ + public function handleErrorEdit() + { + $this->executeEdit(); + return sfView::SUCCESS; + } + + /** + * Set new thumbnail for artwork file or avatar for user + * + * @param object $selectedObject The file or user object + * @param string $postname The name of the posted file + * + * @return void The thumb is written to the thumbnail dir + */ + protected function setNewThumb($selectedObject, $postname = "newimage") + { + $tempFile = $this->getRequest()->getFileValue($postname, 'tmp_name'); + + if ($selectedObject instanceof artworkFile) + { + $identifier = $selectedObject->getIdentifier(); + $name = $selectedObject->getRealpath(); + $path = sfConfig::get('sf_root_dir')."/".sfConfig::get("app_upload_upload_dir")."/".$selectedObject->getIdentifier()."/thumbnail/".$selectedObject->getRealpath(); + $miniPath = sfConfig::get('sf_root_dir')."/".sfConfig::get("app_upload_upload_dir")."/".$selectedObject->getIdentifier()."/thumbnail/mini/".$selectedObject->getRealpath(); + $maxWidth = sfConfig::get('app_upload_fix_thumb_width', '150'); + $maxHeight = sfConfig::get('app_upload_fix_thumb_height', '150'); + $miniMaxWidth = sfConfig::get('app_upload_fix_mini_width', '150'); + $miniMaxHeight = sfConfig::get('app_upload_fix_mini_height', '150'); + } + elseif ($selectedObject instanceof sfGuardUser) + { + $identifier = "image"; + $oldAvatar = $selectedObject->getAvatar(); + + if ($oldAvatar != "" && file_exists(sfConfig::get('app_profile_avatar_path').$oldAvatar)) + { + //IE was not updating the image so instead of overwriting we're deleting and replacing (with new filename) + unlink(sfConfig::get('app_profile_avatar_path').$oldAvatar); + } + + $explodeAvatarFilename = explode(".", $this->getRequest()->getFilename($postname)); + $fileExtension = end($explodeAvatarFilename); + $random = stringMagick::randomString(); + $avatar = time().$random.'.'.$fileExtension; + $selectedObject->setAvatar($avatar); + $selectedObject->save(); + + $path = sfConfig::get('app_profile_avatar_path').$avatar; + $maxWidth = sfConfig::get('app_profile_max_image_width'); + $maxHeight = sfConfig::get('app_profile_max_image_height'); + + } + else + { + throw new Exception("Wrong object type"); + } + + if (!$this->getRequest()->getFilename($postname)) + { + throw new Exception("No image submitted"); + } + $ext = ""; + if ($identifier != "image") + { + $ext = ".jpg"; + } + + try + { + if ($selectedObject instanceof artworkFile || $selectedObject instanceof sfGuardUser ) + { + $force = true; + } + else + { + $force = false; + } + $resizedImage = new imageResize($tempFile, + $path.$ext, + $maxWidth, + $maxHeight, + $force); + // ZOID: Should refactor the create thumb function, maybe in the imageresize class + + $resizedImage->imageWrite(); + + if ($selectedObject instanceof artworkFile) + { + $miniImage = new imageResize($tempFile, + $miniPath.$ext, + $miniMaxWidth, + $miniMaxHeight, + true); + + $miniImage->imageWrite(); + + $selectedObject->setThumbpath($name.$ext); + $selectedObject->save(); + } + } + catch (Exception $e) + { + if ($selectedObject instanceof sfGuardUser) + { + $selectedObject->setAvatar(null); + $selectedObject->save(); + } + throw new Exception($e->getMessage()); + } + } + + /** + * Get the meta data values and save them + * + * @param array $info the info array + * @param reaktorFile $selectedFile the file object + * + * @return void - just writes the meta values to the db + */ + protected function addMeta($info, $selectedFile) + { + $metaMap = sfYaml::load(sfConfig::get('sf_root_dir')."/apps/reaktor/config/metaMap.yml"); + + if ($this->identifier == "image") + { + $meta = @exif_read_data($this->absCurrentDir.'/'.$this->filename, 0, true); + $metaList = $metaMap["image_list"]; + } + elseif ($this->identifier == "audio") + { + $meta = $this->getAudioMeta(); + $metaList = $metaMap["audio_list"]; + + $selectedFile->addMetadata("format", "mime", $this->mimeType); + $selectedFile->addMetadata("format", "size", $info['size']); + } + else + { + // Can't continue with other types + return; + } + + // Process extra mappings from yaml file + foreach ($metaList as $metaMap => $valuesArray) + { + $dcArray = explode(".", $metaMap); + $element = $dcArray[0]; + $qualifier = isset($dcArray[1]) ? $dcArray[1] : null; + + foreach ($valuesArray as $thisVal) + { + $arrayMap = explode(".", $thisVal); + $thisVal = $meta; + + for ($i = 0; $i < count($arrayMap); $i++) + { + $thisItem = $arrayMap[$i]; + if (isset($thisVal[$thisItem])) + { + $thisVal = $thisVal[$thisItem]; + } + else + { + continue 2; + } + } + if ($thisVal != "") + { + try + { + $selectedFile->addMetadata($element, $qualifier, trim($thisVal)); + continue 2; + } + catch (Exception $e) + { + $this->returnError('The upload failed'); + } + break; + } + } + } + } + + /** + * Check the file format so we know what to process + * + * @param string $mimetype the file mimetype + * + * @return string or false + */ + protected function getParams($mimetype) + { + $c = new Criteria(); + + $c->add(FileMimetypePeer::MIMETYPE, $mimetype); + $thisType = FileMimetypePeer::doSelectOne($c); + +if (!$thisType) + { + return false; + } + $identifier = $thisType->getIdentifier(); + $subdir = sfConfig::get('app_upload_'.$identifier.'_dir', 'text'); + return array("identifier" => $identifier, "subdir" => $subdir); + } + + /** + * Some preExecute tasks + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + * @return void + */ + public function preExecute() + { + if (sfConfig::get('app_upload_use_thumbnails', true) && class_exists('sfThumbnail')) + { + $this->useThumbnails = true; + $this->thumbnailsDir = sfConfig::get('app_upload_thumbnails_dir', 'thumbnail'); + } + + $this->uploadDirName = sfConfig::get('app_upload_upload_dir', 'content'); + $this->uploadDir = sfConfig::get('sf_root_dir').'/'.$this->uploadDirName; + } + + /** + * Returns the information about a file that has been uploaded + * + * @param string $filename the uploaded file + * + * @return array + */ + protected function getInfo($filename) + { + $info = array(); + $info['ext'] = substr($filename, strpos($filename, '.') - mb_strlen($filename, 'UTF-8') + 1); + $stats = stat($this->absCurrentDir.'/'.$filename); + $info['size'] = $stats['size']; + $info['thumbnail'] = true; + + if ($this->identifier = "image") + { + if ($this->useThumbnails && is_readable(sfConfig::get('sf_web_dir').$this->webAbsCurrentDir.'/'.$this->thumbnailsDir.'/'.$filename)) + { + $info['icon'] = $this->webAbsCurrentDir.'/'.$this->thumbnailsDir.'/'.$filename; + } + else + { + $info['icon'] = $this->webAbsCurrentDir.'/'.$filename; + $info['thumbnail'] = false; + } + } + else + { + if (is_readable(sfConfig::get('sf_web_dir').'/image/'.$info['ext'].'.png')) + { + $info['icon'] = '/image/'.$info['ext'].'.png'; + } + else + { + $info['icon'] = '/image/unknown.png'; + } + } + return $info; + } + + /** + * Create thumbnail from standard image + * + * @return void - the image is written to th thumbnail directory + */ + protected function createThumb() + { + if (!is_dir($this->absCurrentDir.'/'.$this->thumbnailsDir)) + { + // If the thumbnails directory doesn't exist, create it now + $old = umask(0000); + @mkdir($this->absCurrentDir.'/'.$this->thumbnailsDir, 0777, true); + umask($old); + } + try + { + $thumbnail = new sfThumbnail(sfConfig::get('app_upload_fix_thumb_width', '150'), + sfConfig::get('app_upload_fix_thumb_height', '150'), false, true, 80, 'sfImageMagickAdapter'); + $thumbnail->loadFile($this->getRequest()->getFilePath('file')); + $thumbnail->save($this->absCurrentDir.'/'.$this->thumbnailsDir.'/'.$this->filename); + $this->thumbname = $this->filename; + + $miniThumbnail = new sfThumbnail(sfConfig::get('app_upload_fix_mini_width', '150'), + sfConfig::get('app_upload_fix_mini_height', '150'), false, true, 80, 'sfImageMagickAdapter'); + $miniThumbnail->loadFile($this->getRequest()->getFilePath('file')); + $miniThumbnail->save($this->absCurrentDir.'/'.$this->thumbnailsDir.'/mini/'.$this->filename); + + } + catch (Exception $e) + { + throw new Exception($e); + } + } + + /** + * Create thumbnail from a videoFrame + * + * @param object $frame the video frame object + * + * @return void - the image is written to the thumbnail directory + */ + protected function createThumbFromVideoFrame($frame) + { + if (!is_dir($this->absCurrentDir.'/'.$this->thumbnailsDir)) + { + // If the thumbnails directory doesn't exist, create it now + $old = umask(0000); + @mkdir($this->absCurrentDir.'/'.$this->thumbnailsDir, 0777, true); + umask($old); + } + $thumbnail = new sfThumbnail(sfConfig::get('app_upload_fix_thumb_width', '150'), + sfConfig::get('app_upload_fix_thumb_height', '150'), false, true, 80, 'sfGDAdapter'); + $thumbnail->loadData($frame->getContent(), $frame->getMime()); + $thumbnail->save($this->absCurrentDir.'/'.$this->thumbnailsDir.'/'.$this->filename.'.jpg', 'image/jpeg'); + $this->thumbname = $this->filename; + + $miniThumbnail = new sfThumbnail(sfConfig::get('app_upload_fix_mini_width', '150'), + sfConfig::get('app_upload_fix_mini_height', '150'), false, true, 80, 'sfGDAdapter'); + $miniThumbnail->loadData($frame->getContent(), $frame->getMime()); + $miniThumbnail->save($this->absCurrentDir.'/'.$this->thumbnailsDir.'/mini/'.$this->filename.'.jpg', 'image/jpeg'); + } + + /** + * Create thumbnail from first page of Pdf + * Uses imagemagick + * + * @return void - the image is written to th thumbnail directory + */ + protected function createPdfThumb() + { + if (!is_dir($this->absCurrentDir.'/'.$this->thumbnailsDir)) + { + // If the thumbnails directory doesn't exist, create it now + $old = umask(0000); + @mkdir($this->absCurrentDir.'/'.$this->thumbnailsDir, 0777, true); + umask($old); + } + + //ZOID: This should be combined with the image resize class + $command = "convert ".$this->getRequest()->getFilePath('file')."[0] -colorspace rgb -resize "; + $command .= sfConfig::get('app_upload_fix_thumb_width', '106')."x"; + $command .= sfConfig::get('app_upload_fix_thumb_height', '150')."\! "; + $command .= $this->absCurrentDir.'/'.$this->thumbnailsDir.'/'.$this->filename.".jpg"; + + $response = `$command`; + $this->thumbname = $this->filename.".jpg"; + + //ZOID: This should be combined with the image resize class + $command = "convert ".$this->getRequest()->getFilePath('file')."[0] -colorspace rgb -resize "; + $command .= sfConfig::get('app_upload_fix_mini_width', '106')."x"; + $command .= sfConfig::get('app_upload_fix_mini_height', '150')."\! "; + $command .= $this->absCurrentDir.'/'.$this->thumbnailsDir.'/mini/'.$this->filename.".jpg"; + + $response = `$command`; + } + + /** + * Create thumbnail from first page of HTML document + * Uses imagemagick and html2ps + * + * @return void - the image is written to th thumbnail directory + */ + protected function createHTMLThumb($filename) + { + if (!is_dir($this->absCurrentDir.'/'.$this->thumbnailsDir)) + { + // If the thumbnails directory doesn't exist, create it now + $old = umask(0000); + @mkdir($this->absCurrentDir.'/'.$this->thumbnailsDir, 0777, true); + umask($old); + } + + //ZOID: This should be combined with the image resize class + $command = "html2ps ".$filename." | "; + $command .= "convert -[0] -colorspace rgb -resize "; + $command .= sfConfig::get('app_upload_fix_thumb_width', '106')."x"; + $command .= sfConfig::get('app_upload_fix_thumb_height', '150')."\! "; + $command .= $this->absCurrentDir.'/'.$this->thumbnailsDir.'/'.$this->filename.".jpg 2>&1"; + + $response = `$command`; + $this->thumbname = $this->filename.".jpg"; + /*echo "
    "; + echo $command; + echo "
    "; + echo $this->absCurrentDir; + echo "
    "; + echo $this->thumbnailsDir; + echo "
    "; + echo $this->filename; + echo "
    "; + print_r($response); + die();*/ + + //ZOID: This should be combined with the image resize class + $command = "html2ps ".$filename." | "; + $command .= "convert -[0] -colorspace rgb -resize "; + $command .= sfConfig::get('app_upload_fix_mini_width', '106')."x"; + $command .= sfConfig::get('app_upload_fix_mini_height', '150')."\! "; + $command .= $this->absCurrentDir.'/'.$this->thumbnailsDir.'/mini/'.$this->filename.".jpg"; + + $response = `$command`; + } + + /** + * Resize and copy the image + * + * @return void - the image is copied and resized + */ + protected function processImage() + { + if (!is_dir($this->absCurrentDir.'/original')) + { + // If the original image dir doesn't exist + $old = umask(0000); + @mkdir($this->absCurrentDir.'/original', 0777, true); + umask($old); + } + + try + { + $resizedImage = new imageResize($this->getRequest()->getFilePath('file'), + $this->absCurrentDir.'/'.$this->filename, sfConfig::get('app_upload_max_image_width', '500'), + sfConfig::get('app_upload_max_image_height', '500')); + $resizedImage->imageWrite(); + } + catch (Exception $e) + { + throw new Exception($e->getMessage()); + } + $this->absCurrentDir .= "/original"; + } + + /** + * Get all know id3 tags from Audio file + * + * @return array - the meta data array + */ + protected function getAudioMeta() + { + $thisInfo = new audioInfo(); + try { + $meta = $thisInfo->info($this->uploadDir.'/'.$this->identifier.'/original/'.$this->originalPath); + } + catch (Exception $e) + { + try { + // Try again, without the original path.. + $meta = $thisInfo->info($this->uploadDir.'/'.$this->identifier.'/' .$this->originalPath); + $fail = false; + } catch(Exception $e) { + $fail = true; + } + if ($fail) { + //Unhandled - so the user gets no metadata + $meta = array(); + + // If we are in dev environment - probably good to display this error + if (sfConfig::get("sf_environment" == "dev")) + { + die("Could not extract metadata for file: ".$this->uploadDir.'/'.$this->identifier.'/original/'.$this->originalPath); + } + } + } + + return $meta; + } + + /** + * Give the file a unique filename on the filesystem + * Uses timestamp and user id + * + * @param string $file the existing filename + * + * @return string the new filename + */ + protected function nameFile($file) + { + return time()."_".$this->getUser()->getGuardUser()->getId()."_".$file; + } + + /** + * Return the upload page with an error + * + * @param string $message the error message to append to the file field + * + * @return void the template is rendered with error message + */ + protected function returnError($message) + { + if ($this->getRequestParameter('add')) + { + $this->getRequest()->setError('file', sfContext::getInstance()->getI18N()->__($message)); + return sfView::SUCCESS; + } + } + + /** + * Validate edit, the required fields differ depending on the user + * submission so we'll handle the required fields here. + * + * @return boolean only if validation success + * + */ + public function validateEdit() + { + $thisFile = new artworkFile($this->getRequestParameter('fileId')); + + if ($this->getRequest()->getMethod() != sfRequest::POST) + { + return true; + } + if ($this->getRequestParameter("save_draft")) + { + $requiredArray = array("title" => $this->getRequestParameter('title')); + } + else + { + if ($this->hasRequestParameter("mce_data")) + { + $requiredArray = array("author" => $this->getRequestParameter('author'), + "mce_data" => $this->getRequestParameter("mce_data"), + "title" => $this->getRequestParameter('title'), + "meta_license"=> $this->getRequestParameter('meta_license')); + } + else + { + $requiredArray = array("author" => $this->getRequestParameter('author'), + "description" => $this->getRequestParameter("description"), + "title" => $this->getRequestParameter('title'), + "meta_license"=> $this->getRequestParameter('meta_license')); + } + // We need to check that there are some tags assigned to this file + // fix for issue #466 - don't require tags for files - CHANGE IN YML DO NOT COMMENT OUT WORKING CODE! + $fileTags = $thisFile->getTags(true); + + if (count($fileTags) < sfConfig::get("app_tagging_minimum_tags")) + { + $error = $this->getContext()->getI18n()->__("Please enter at least %1%", array("%1%" => sfConfig::get("app_tagging_minimum_tags")))." "; + if (sfConfig::get("app_tagging_minimum_tags") > 1) + { + $error .= $this->getContext()->getI18n()->__("tags"); + } + else + { + $error .= $this->getContext()->getI18n()->__("tag"); + } + $this->getRequest()->setError("tags", $error); + + } + } + + foreach ($requiredArray as $param => $value) + { + if (!$value) + { + $this->getRequest()->setError($param, $this->getContext()->getI18n()->__("Required")); + } + } + + if ($this->getRequest()->hasErrors()) + { + return false; + } + return true; + } + + /** + * Ajax method for updating uploaded images inline + * Used for thumbnails and avatars + * + * @return void + */ + public function executeUpdateInline() + { + if ($this->getRequest()->getMethod() != sfRequest::POST) + { + die(); + } + elseif (!$this->getUser()->isAuthenticated()) + { + // Handle potential session timeout + $this->getRequest()->setError("newimage", "Session timed out, refresh and try again"); + return $this->handleErrorUpdateInline(); + } + + // Are we editing a thumbnail for a file? + if ($this->getRequestParameter("fileId")) + { + // Since this is a kind of Ajax request, we should be sure that this user should be editing this file + try + { + $thisFile = new artworkFile($this->getRequestParameter("fileId")); + if ($thisFile->getUserId() != $this->getUser()->getGuardUser()->getId() && !$this->getUser()->hasCredential('editusercontent')) + { + die(); // This person/request should not be here + } + $this->setNewThumb($thisFile); + } + catch (Exception $e) + { + $this->getRequest()->setError("newimage", "Upload failed ".$e->getMessage()); + return $this->handleErrorUpdateInline(); + } + + if ($thisFile->hasArtwork()) + { + $parentArtworks = $thisFile->getParentArtworks(); + foreach($parentArtworks as $parentArtwork) + { + if ($parentArtwork->getStatus() == 3) + { + sfLoader::loadHelpers(array("Url", "Tag")); + $selectedFile = $thisFile; + $translateMe = sfContext::getInstance()->getI18n()->__("The following file's thumbnail was changed"); + $parentArtwork->flagChanged($this->getUser(), "The following file's thumbnail was changed"); + $parentArtwork->flagChanged($this->getUser(), " - ".link_to($selectedFile->getTitle()." (".$selectedFile->getId().")", "@edit_upload?fileId=".$selectedFile->getId())); + $parentArtwork->save(); + } + } + } + + $imageResponse = $this->getRequestParameter("imgTag"); + $imageResponse = str_replace("?id", "?id" . rand(0, 100), $imageResponse); + } + elseif ($this->getRequestParameter("avatarUserId")) + { + $selectedUser = sfGuardUserPeer::retrieveByPK($this->getRequestParameter("avatarUserId")); + + if (!$selectedUser || ($selectedUser->getId() != $this->getUser()->getGuardUser()->getId() && !$this->getUser()->hasCredential('editprofile'))) + { + die(); // This person/request should not be here + } + try + { + $this->setNewThumb($selectedUser); + } + catch (Exception $e) + { + $this->getRequest()->setError("newimage", "Upload failed: ".$e->getMessage()); + return $this->handleErrorUpdateInline(); + } + $imageResponse = "getAvatar()."' alt = 'Avatar' />"; + } + else + { + die(); // Nothing to output + } + // All went well then + return $this->renderText($imageResponse); + } + + /** + * Re-send the partial if there are validation errors + * Errors can come from the validation yml or from the + * above method. + * + * @return void + */ + public function handleErrorUpdateInline() + { + //Return original image and the error message + //return $this->renderPartial('inlineUpload'); ZOID: Not available in this version of Symfony!! Update when released + $response = $this->getRequestParameter("imgTag")."
    "; + $response .= "↓ ".$this->getRequest()->getError("newimage")." ↓"; + return $this->renderText($response); + } + + /** + * Additional custom validator for inline upload of thumbnails + * Validation here extends the validation offered by the validate/updateInline.yml file + * + * @return boolean true on validation success + */ + public function validateUpdateInline() + { + // See if we have any extra rules for this type + $thisFile = ReaktorFilePeer::retrieveByPK($this->getRequestParameter("fileId")); + $allowedMimeArray = sfConfig::get("app_upload_thumb_allowed_mime"); + if (is_array($allowedMimeArray) && isset($thisFile) &&isset($allowedMimeArray[$thisFile->getIdentifier()])) + { + $myValidator = new sfFileValidator(); + $myValidator->initialize($this->getContext(), array( + 'mime_types' => $allowedMimeArray[$thisFile->getIdentifier()], + 'mime_types_error' => 'Only JPEG images are allowed', + )); + + $file_array = $this->getRequest()->getFile("newimage"); + if (!$myValidator->execute($file_array, $error)) + { + $this->getRequest()->setError("newimage", $error); + } + } + + if (!$this->getRequest()->hasErrors()) + { + return true; + } + return false; + } + + /** + * Delete a file completely, admin only function + * + * @return void the file is deleted + */ + public function executeDeleteFile() + { + // ZOID: Expand to allow users to delete own files? Also change button in template + $this->forward404Unless($this->getUser()->hasCredential("deletecontent")); + + // Get the File details ZOID: Move to pre-execute? + $fileId = intval($this->getRequestParameter('fileId')); + try + { + $selectedFile = new artworkFile($fileId); + } + catch (Exception $e) + { + $this->forward404($e); + } + + try + { + $fileUser = $selectedFile->getUser(); + $selectedFile->deleteFile(); + } + catch (Exception $e) + { + die($e->getMessage()); + } + //$tmproute = '@user_files?user='.$fileUser; + //Subreaktor::addSubreaktorToRoute('@user_files?user='.$fileUser); + $this->redirect(Subreaktor::addSubreaktorToRoute('@user_content?mode=allartwork&user='.$fileUser->getUsername())); + } + + /** + * Strips tags from html data + * + * @return string + */ + public function stripTags($text) + { + return strip_tags($text,"

      1. ");
        +  }
        +  
        +  protected function sanitizeFile($file)
        +  {
        +    return preg_replace('/[^a-z0-9_\.-]/i', '_', $file);
        +  }
        +  
        +  /**
        +   * Show the thumbnail cropping page for an uploaded file
        +   * 
        +   * @return void
        +   */
        +  public function executeThumbnailCrop()
        +  {
        +    try 
        +    {
        +      $file = new artworkFile($this->getRequestParameter("fileId"));
        +        
        +      // Send required values to template
        +      $this->file = $file;
        +    }
        +    catch (exception $e)
        +    {
        +      $this->forward404();
        +    }
        +    if (!$file->getId() || !$file->hasStaticThumbnail())
        +    {
        +      $this->forward404();
        +    }
        +  }
        +
        +  /**
        +   * Show the thumbnail cropping page for an uploaded file
        +   * 
        +   * @return void
        +   */
        +  public function executeCrop()
        +  {
        +    try 
        +    {
        +      $file = new artworkFile($this->getRequestParameter("file"));
        +      $this->file = $file;
        +    }
        +    catch (exception $e)
        +    {
        +      $this->forward404();
        +    }
        +    if (!$file->getId() || !$file->hasStaticThumbnail())
        +    {
        +      $this->forward404();
        +    }
        +
        +    $sourceFile = $file->getFullFilePath('normal');
        +    
        +    $x1 = $this->getRequestParameter('x1');
        +    $x2 = $this->getRequestParameter('x2');
        +    $y1 = $this->getRequestParameter('y1');
        +    $y2 = $this->getRequestParameter('y2');
        +    
        +    $cropWidth = $this->getRequestParameter('width');
        +    $cropHeight = $this->getRequestParameter('height');
        +
        +    $cropX = $x1;
        +    $cropY = $y1;
        +    $destinationFile = $file->getFullFilePath('thumb');
        +    
        +    $output = array();
        +    sfLoader::loadHelpers(array('content', 'Partial', 'Url'));
        +    
        +    $convertString = "convert $sourceFile -crop " . $cropWidth . "x" . $cropHeight . "+" . $cropX . "+" . $cropY . " +repage $destinationFile 2>&1";
        +    //echo $convertString;
        +    exec($convertString, $output);
        +
        +    $sourceFile = $destinationFile;
        +    
        +    $resizeString = "convert $sourceFile -resize 240x160! $destinationFile 2>&1";
        +    exec($resizeString, $output);
        +    
        +    $destinationFile = $file->getFullFilePath('mini');
        +    
        +    $cropWidth -= 50;
        +    
        +    $convertString = "convert $sourceFile -resize 78x65! -gravity center +repage $destinationFile 2>&1";
        +    exec($convertString, $output);
        +    
        +    $this->redirect(Subreaktor::addSubreaktorToRoute('@edit_upload?fileId='.$file->getId()));
        +  }
        +  
        +  public function executeResolveUploadFileId()
        +  {
        +    $this->forward404Unless($this->getUser()->hasCredential('staff'));
        +    $attachment = ArticleAttachmentPeer::retrieveById($this->getRequestParameter("id"));
        +    $this->forward404Unless($attachment);
        +    $file = $attachment->getArticleFile();
        +    $this->forward404Unless($file);
        +
        +    list($width, $height,) = getimagesize($file->getFullPath());
        +    $retval = array(
        +      "absolutePath" => $file->getDirectLink(),
        +      "width"        => $width,
        +      "height"       => $height,
        +    );
        +
        +    $output = json_encode($retval);
        +    $this->getResponse()->setHttpHeader("X-JSON", '('.$output.')');
        +    return sfView::HEADER_ONLY;
        +  }
        +}
        +
        diff --git a/apps/reaktor/modules/upload/actions/components.class.php b/apps/reaktor/modules/upload/actions/components.class.php
        new file mode 100644
        index 0000000..eb65420
        --- /dev/null
        +++ b/apps/reaktor/modules/upload/actions/components.class.php
        @@ -0,0 +1,31 @@
        +
        + * @copyright 2008 Linpro AS
        + * @license   http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
        + *
        + */
        +
        +/**
        + * Components for upload page
        + *
        + * PHP Version 5
        + *
        + * @author    Russ Flynn 
        + * @copyright 2008 Linpro AS
        + * @license   http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
        + *
        + */
        +class uploadComponents extends sfComponents
        +{
        +  function executeTinymce()
        +  {
        +    $this->component = true;
        +  }
        +}
        +
        +   
        \ No newline at end of file
        diff --git a/apps/reaktor/modules/upload/config/security.yml b/apps/reaktor/modules/upload/config/security.yml
        new file mode 100644
        index 0000000..8709cbd
        --- /dev/null
        +++ b/apps/reaktor/modules/upload/config/security.yml
        @@ -0,0 +1,3 @@
        +updateInline:
        +  is_secure: off #Handles own security, stops login box appearing in inline elements!
        +  credentials: [[admin, editprofile]]
        \ No newline at end of file
        diff --git a/apps/reaktor/modules/upload/config/validate.yml b/apps/reaktor/modules/upload/config/validate.yml
        new file mode 100644
        index 0000000..8dc081f
        --- /dev/null
        +++ b/apps/reaktor/modules/upload/config/validate.yml
        @@ -0,0 +1,5 @@
        +sf_asset_upload_form:
        +  class:              sfFileValidator
        +  param:
        +    max_size:         100000000
        +    max_size_error:   Max size is 100MB
        \ No newline at end of file
        diff --git a/apps/reaktor/modules/upload/config/view.yml b/apps/reaktor/modules/upload/config/view.yml
        new file mode 100644
        index 0000000..5073ec7
        --- /dev/null
        +++ b/apps/reaktor/modules/upload/config/view.yml
        @@ -0,0 +1,6 @@
        +all:
        +  stylesheets: [/css/cropper, /css/lightwindow]
        +  javascripts: [inlineupload, cropper, lightwindow]
        +    
        +choiceSuccess:
        +  has_layout: false
        diff --git a/apps/reaktor/modules/upload/lib/myUrlFieldValidator.class.php b/apps/reaktor/modules/upload/lib/myUrlFieldValidator.class.php
        new file mode 100644
        index 0000000..791a639
        --- /dev/null
        +++ b/apps/reaktor/modules/upload/lib/myUrlFieldValidator.class.php
        @@ -0,0 +1,92 @@
        +
        + * @copyright 2008 Linpro AS
        + * @license   http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
        + *
        + */
        +
        +/**
        + * Validator for multiple URL field
        + *
        + * PHP Version 5
        + *
        + * @author    Russ Flynn 
        + * @copyright 2008 Linpro AS
        + * @license   http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
        + *
        + */
        +class myUrlFieldValidator extends sfValidator
        +{
        +  /**
        +   * Validator looking for URL on each line of text field
        +   *
        +   * @param mixed  &$value Pointer to the value to validate
        +   * @param string &$error Pointer to the error
        +   * 
        +   * @return boolean
        +   */
        +  public function execute (&$value, &$error)
        +  {
        +    //Break into the text, line by line
        +    $url_lines = explode("\n", $value);
        +    
        +    //Lets look at each one, line by line
        +    foreach ($url_lines as $key => $line)
        +    {
        +      $line = trim($line);
        +      if ($line == "")
        +      {
        +        unset ($url_lines[$key]);
        +        continue;
        +      }
        +      
        +      $re = '/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i';
        +
        +      if (!preg_match($re, $line))
        +      {
        +        $error = $this->getParameterHolder()->get('format_error');
        +      }
        +      $url_lines[$key] = $line;
        +    }
        +        
        +    //Rebuild the text field
        +    $value              = implode("\n", $url_lines);
        +    $_POST['resources'] = $value;
        +    
        +    if (isset($error))
        +    {
        +      return false;
        +    }
        +    return true;
        +    
        +    //$error = parent::getParameter('url_error');
        +    //return false;
        +  }
        + 
        +  /**
        +   * Initializes the validator
        +   *
        +   * @param unknown_type $context    Context
        +   * @param unknown_type $parameters Parameters
        +   * 
        +   * @return boolean
        +   */
        +  public function initialize ($context, $parameters = null)
        +  {
        +    // Initialize parent
        +    parent::initialize($context);
        + 
        +    // Set default parameters value
        +    $this->setParameter('format_error', 'Invalid format');
        +    
        +    // Set parameters
        +    $this->getParameterHolder()->add($parameters);
        + 
        +    return true;
        +  }	
        +}
        \ No newline at end of file
        diff --git a/apps/reaktor/modules/upload/templates/_inlineUpload.php b/apps/reaktor/modules/upload/templates/_inlineUpload.php
        new file mode 100644
        index 0000000..10d0887
        --- /dev/null
        +++ b/apps/reaktor/modules/upload/templates/_inlineUpload.php
        @@ -0,0 +1,82 @@
        + tags as this will create a nested form
        + * and break the script. Must also be placed AFTER existing page forms or Symfony
        + * messes something up with the params.
        + *
        + * PHP Version 5
        + *
        + * @author    Russ Flynn 
        + * @copyright 2008 Linpro AS
        + * @license   http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
        + *
        + */
        +use_helper('Javascript');
        +
        +?>
        +
        +
        +
        +
        +
        +
        +
        +
        +
        + $loading_room))."'; 
        +    return true;
        +}
        +
        +function completeCallback(response) 
        +{
        +    // make something useful after (onComplete)
        +    $('image_block').innerHTML = response;
        +    $('$upload_id').value = '';
        +}"); ?>
        +
        + "true",
        +  "name"      => "image_upload_form",
        +  "onsubmit"  => "return AIM.submit(this, {'onStart' : startCallback, 'onComplete' : ".$completeCallback." })")); ?>
        +
        +  
        + + +

        + +
        +

        +

        + +
        +

        +
        + "newimagebutton", + "onclick" => "if($('$upload_id').value=='') + { alert('".__('Please choose a file first')."');return false; }" )); + echo $extra_button; + ?> +
        + + + + + + + + + + diff --git a/apps/reaktor/modules/upload/templates/_saveAndAttach.php b/apps/reaktor/modules/upload/templates/_saveAndAttach.php new file mode 100644 index 0000000..1f9a84f --- /dev/null +++ b/apps/reaktor/modules/upload/templates/_saveAndAttach.php @@ -0,0 +1,40 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + + \ No newline at end of file diff --git a/apps/reaktor/modules/upload/templates/_tinymce.php b/apps/reaktor/modules/upload/templates/_tinymce.php new file mode 100644 index 0000000..84bae02 --- /dev/null +++ b/apps/reaktor/modules/upload/templates/_tinymce.php @@ -0,0 +1,46 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + + + + + + "80x52")) ?> + + "80x52")) ?> + + diff --git a/apps/reaktor/modules/upload/templates/editSuccess.php b/apps/reaktor/modules/upload/templates/editSuccess.php new file mode 100644 index 0000000..bc3bbd7 --- /dev/null +++ b/apps/reaktor/modules/upload/templates/editSuccess.php @@ -0,0 +1,261 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper('content', 'Javascript', 'Debug', 'wai'); +reaktor::setReaktorTitle(__('Upload artwork')); + +?> + + +
        +
        isImage()) echo "class='leaveagap'"; ?>> + isImage()): ?> + + getIdentifier() == 'video' && !$thisFile->getThumbpath() && file_exists($videoPath. $thisFile->getRealpath().".temp.flv")): ?> + + + + get('fileId'), 'thumb')); ?> + hasStaticthumbnail()): ?> +
        + getId(), + array("confirm" => "If you have made any changes on this page, click cancel then save your + changes before continuing")); ?> +
        + + +
        +
        + +
          + getMetadatas() as $metaElement => $aMetadata): ?> + $metaValue): ?> + + ', ucfirst($metaElement . ' - ' . $metaKey), ': ', $metaValue; ?> + + + + + +
        • + +
        + + hasArtwork()): ?> +

        + $thisFile, "completeFuncs" => "doSubmit();")); ?> + +
        +
        + get('fileId'), 'name=edit_upload_form'); ?> +

        +

        + hasArtwork()): ?> + getParentArtworks(); ?> +

        + + reaktor_link_to($firstArtwork->getTitle(), + '@show_artwork_file?id='.$firstArtwork->getId().'&file='.$thisFile->getId().'&title='.$firstArtwork->getTitle()), + '%link_to_edit%' => reaktor_link_to(__('edit'), + '@edit_artwork?id='.$firstArtwork->getId()))); ?> + + + + 12)), "$('all_artworks').toggle();"); ?> + +

        + + +
    + + + hasErrors()): ?> +

    +

    + +

    + +
    +
    + * +
    +
    + + getMetadata('title'), array("class"=>"mediuminput", "maxlength"=>40)); ?> +
    +
    + * +
    +
    + + getMetadata('creator'), array("class"=>"mediuminput", "maxlength"=>40)); ?> +
    + + getIdentifier() == "text"): ?> +
    +
    + + + $mce_data)); ?> + + + +
    + + +
    + * +
    +
    + + getMetadata('description', 'abstract'), "size=40x8"); ?> +
    +
    + +
    +
    + + getMetadata('description', 'creation'), "size=40x8"); ?> +
    + +
    + +
    +
    + + getMetadata('relation', 'references'), "size=40x8"); ?> +
    +
    + * +
    +
    + getLicense(), array('no_allow', 'contact', 'free_use', 'non_commercial', ''))): ?> + '
    ')) . '
    '; ?> + '; ?> + ".__('Read more about the different licenses')."" ?> + . + + + __('--- please select a license ---'), + 'by' => 'CC: Navngivelse (by)', + 'by-sa' => 'CC: Navngivelse - Del på samme vilkår (by-sa)', + 'by-nd' => 'CC: Navngivelse - Ingen bearbeidelse (by-nd)', + 'by-nc' => 'CC: Navngivelse - Ikke-kommersiell (by-nc)', + 'by-nc-sa' => 'CC: Navngivelse ‑ Ikke‑kommersiell ‑ Del på samme vilkår (by‑nc‑sa)', + 'by-nc-nd' => 'CC: Navngivelse ‑ Ikke‑kommersiell ‑ Ingen Bearbeidelse (by‑nc‑nd)'), + /*'free_use' => 'Allow free use for other users', + 'contact' => 'Contact me for further use', + 'no_allow' => 'Do not allow any non-private use'),*/ + $thisFile->getMetadata('license'))); ?> + +
    +
    + + +
    +
    + 1 && is_numeric($sf_params->get("link"))): // The first item is the default value set in the action?> + $artworkArray)); ?> + + hasArtwork()): ?> +
    +

    +

    + "new_artwork", "class" => "status_approve")); ?> +

    +

    + "; ?> + + + +
    + "Tip('".$helpText."');", + "onMouseOut" => "UnTip();")); ?> +

    +
    + + hasArtwork()): ?> +
    +

    +

    + "save_draft", "class" => "status_draft")); ?> + hasCredential("deletecontent")): ?> + getId(), array("method"=> "post", "class" => "cancel", "confirm" => __("The file will be completely removed, are you sure?"))); ?> + +

    +
    + +
    +

    + +
    +

    + "save_edit", "class" => "status_draft")); ?> + "", "confirm" => __("All changes will be lost, are you sure?"))); ?> + hasCredential("deletecontent")): ?> + getId(), array("method"=> "post", "class" => "cancel", "confirm" => __("The file will be completely removed, are you sure?"))); ?> + +

    +
    + + 1 && !is_numeric($sf_params->get("link"))): // The first item is the default value set in the action?> + isUnsuitable()) + include_partial("saveAndAttach", array("artworkArray" => $artworkArray)); + ?> + + get("link")): ?> + get("link")); ?> + + + + isImage()): ?> +
    + +

    :

    + $thisFile->getId(), "imgTag" => image_tag(contentPath($sf_params->get('fileId'), 'thumb', false, true)))); ?> +
    + + diff --git a/apps/reaktor/modules/upload/templates/helpArticles.php b/apps/reaktor/modules/upload/templates/helpArticles.php new file mode 100644 index 0000000..6c29754 --- /dev/null +++ b/apps/reaktor/modules/upload/templates/helpArticles.php @@ -0,0 +1,11 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> \ No newline at end of file diff --git a/apps/reaktor/modules/upload/templates/showFilesSuccess.php b/apps/reaktor/modules/upload/templates/showFilesSuccess.php new file mode 100644 index 0000000..3ee4625 --- /dev/null +++ b/apps/reaktor/modules/upload/templates/showFilesSuccess.php @@ -0,0 +1,54 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("content"); +reaktor::setReaktorTitle(__('My files')); + +?> + +

    +
    + + + +
    + getId()); ?> +
    +
    +

    + getMetadata('title') != "" ? $fileObject->getMetadata('title') : __("unnamed"); ?>
    +

    + hasArtwork()): ?> +

    reaktor_link_to($fileObject->getParentArtwork()->getTitle(), '@show_artwork_file?id='.$fileObject->getParentArtwork()->getId().'&file='.$fileObject->getId().'&title='.$fileObject->getParentArtwork()->getTitle()))); ?>

    + +
    +
    + getId()); ?>
    + +
    + date('d/m/y', $fileObject->getUploadedAt(true)).', '.date('H.i', $fileObject->getUploadedAt(true)))); ?> +
    + date('d/m/y', $fileObject->getModifiedAt(true)).', '.date('H.i', $fileObject->getModifiedAt(true)))); ?> +
    + $fileObject->getFiletype())); ?> +
    +
    + + + link_to(__("Upload artwork now"), "@upload_content"))); ?> + \ No newline at end of file diff --git a/apps/reaktor/modules/upload/templates/thumbnailCropSuccess.php b/apps/reaktor/modules/upload/templates/thumbnailCropSuccess.php new file mode 100644 index 0000000..a3d6545 --- /dev/null +++ b/apps/reaktor/modules/upload/templates/thumbnailCropSuccess.php @@ -0,0 +1,83 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("content", "Javascript"); +reaktor::setReaktorTitle(__('Thumbnail crop')); + +?> + +
    +

    $file->getTitle())); ?>

    + "testImage")); ?> +
    +
    +
    +
    +

    +
    +

    + +

    +
    +
    + +
    + getId()); ?> + + + + + + + hasStaticThumbnail()): ?> +

    + + + + ' ?> +
    +
    + getId()); ?> +
    +
    + + \ No newline at end of file diff --git a/apps/reaktor/modules/upload/templates/uploadSuccess.php b/apps/reaktor/modules/upload/templates/uploadSuccess.php new file mode 100644 index 0000000..2767eee --- /dev/null +++ b/apps/reaktor/modules/upload/templates/uploadSuccess.php @@ -0,0 +1,189 @@ + + * @author Ole-Peter Wikene + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper('Javascript', 'wai', 'content'); +reaktor::setReaktorTitle(__('Upload content')); +$adminWarning = ""; + +if ($sf_user->hasCredential("editusercontent") && isset($artwork) && $artwork->getUserId() != $sf_user->getId()) +{ + $adminWarning = "return confirm('".__("You are about to upload a file and link it to an artwork on behalf of a user, ". + "the user will take ownership of the file as soon as it is uploaded, are you sure?")."');"; +} +$submitRoute = $sf_params->get("link_artwork_id") ? "artwork_link?link_artwork_id=".$sf_params->get("link_artwork_id") : "upload_content"; + +?> +

    +
    + +
    +1 +
    + +
    +

    + + getTitle()."\"", "@show_artwork?id=".$artwork->getId()."&title=".$artwork->getTitle()); ?> + + + +

    +
    +
    + + + +
    +
    + + +
    +
    +
      +
    • 'add', + 'class' => '', + 'onclick' => $adminWarning."if($('file').value=='') { alert('".__('Please choose a file first')."');return false; } + else { uploadStatusShow(); + if ($('upload_error')) + { $('upload_error').hide(); } + if ($('upload_right_box')) + { $('upload_right_box').hide(); } + setTimeout(\"$('progressbar').src = '/images/progressbar.gif'\", 10); }", + )) ?>
    • +
    + get("link_artwork_id")); ?> + +
    +
    + +
    +

    +

    +
    330, 'height' => 25, 'id' => 'progressbar')); ?> +
    + + + + +
    + +
    +

    +

    + + getEligbleFileTypes() as $eligbleType): ?> + ".__("or")." "; ?> + + + %upload_type%, + however this artwork requires type: %allowed_types%", + array("%upload_type%" => collectionType($sf_request->getError("link_error"), false, true), + "%allowed_types%" => $allowedList)); ?> +

    +

    + "; ?> + "; ?> +

    + reaktor_link_to(__("click here if you wish to create a new artwork"), "@upload_content"))); ?> +

    +
    + +
    +

    "", "class"=> "", "suffix"=> "")); ?>

    +
    + get("link_artwork_id")): ?> +

    +

    ".collectionType($artwork, false, true)."";?>

    +

    + +

    +

    + get("link_artwork_id")); ?> +

    + + +

    +

    + +

    +

    + +

    + +
    +
    +
    + +
    + +
    +
    +
    +isTextBased()): ?> +
    +2 +
    + + +
    +

    + "float-left", + "id" => "upload_form", + "name" => "upload_form", + "multipart" => "true")); ?> + 'add', 'class' => 'add_file') + ); ?> + + getId()); ?> + + +
    + +

    + +
    +
    + +

    +

    + +

    +
    + +
    +
    diff --git a/apps/reaktor/modules/upload/validate/edit.yml b/apps/reaktor/modules/upload/validate/edit.yml new file mode 100644 index 0000000..3e21c89 --- /dev/null +++ b/apps/reaktor/modules/upload/validate/edit.yml @@ -0,0 +1,78 @@ +#All required fields should be no as they are handled in the action based on draft or submission +#Look at validateEdit() function for details. All other validation handled here. +methods: + post: [author, description, title, production, resources, tags, meta_license] + +fillin: + enabled: true + +names: + author: + required: no + required_msg: Please enter the author + validators: myStringValidator + + description: + required: no + required_msg: Please enter a valid description + validators: myTextValidator + + title: + required: no + required_msg: Title should be at least 3 characters + validators: myTitleValidator + + production: + required: no + class: myTextValidator + + resources: + required: no + validators: myUrlFieldValidator, myTextValidator + + tags: + required: no + required_msg: You should enter some keywords so your work can be found by other users + validators: myCsvValidator + + meta_license: + required: no + required_msg: Please select the license that best describes this work + +myStringValidator: + class: sfStringValidator + param: + min: 3 + min_error: Enter at least 3 characters + max: 40 + max_error: Enter less than 40 characters + +myTitleValidator: + class: myArtworkTitleValidator + param: + invalid_error: Invalid title!
    Use letters, numbers, spaces, hyphens and underscores only + # Valid characters are specified in app.yml + + +myTextValidator: + class: sfStringValidator + param: + min: 5 + min_error: Enter at least 5 characters + max: 500 + max_error: Enter less than 500 characters + +myCsvValidator: + class: sfStringValidator + param: + min: 3 + min_error: Enter at least 3 characters + max: 300 + max_error: Enter fewer keywords + +myUrlFieldValidator: + class: myUrlFieldValidator + param: + url_error: Please enter valid URLs, one per line + format_error: An invalid URL has been specified + \ No newline at end of file diff --git a/apps/reaktor/modules/upload/validate/updateInline.yml b/apps/reaktor/modules/upload/validate/updateInline.yml new file mode 100644 index 0000000..f747787 --- /dev/null +++ b/apps/reaktor/modules/upload/validate/updateInline.yml @@ -0,0 +1,16 @@ +fields: + newimage: + methods: post + required: + msg: Select a file + file: true + sfFileValidator: + mime_types: + - 'image/jpeg' + - 'image/pjpeg' + - 'image/png' + - 'image/x-png' + - 'image/gif' + mime_types_error: Invalid image + max_size: 100000000 + max_size_error: File too big \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/actions/actions.class.php b/apps/reaktor/modules/userContent/actions/actions.class.php new file mode 100644 index 0000000..936ecd0 --- /dev/null +++ b/apps/reaktor/modules/userContent/actions/actions.class.php @@ -0,0 +1,428 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * User content management, allows users to see and manage everything they have on the site, including files and artworks + * and all the statuses involved. (Awaiting approval etc) + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class userContentActions extends sfActions +{ + /** + * The user object that we are managing files for + * + * @var sfGuardUser + */ + private static $thisUser; + + /** + * The artwork object we are linking to if provided + * + * @var genericArtwork + */ + private static $linkArtwork; + + /** + * The file object we are working on if provided + * + * @var artworkFile + */ + private static $file; + + /** + * Common functions to execute before all on this page + * There is a user and an admin action for all the tasks when it comes to managing content, so this function + * ensures that we are always covered. + * + * @return null + */ + public function preExecute() + { + // Are we managing our own content or somebody elses? + if ($this->getRequestParameter("user")) + { + $thisUser = sfGuardUserPeer::getByUsername($this->getRequestParameter("user")); + $this->forward404Unless($thisUser && ($this->getUser()->hasCredential("editusercontent") || $thisUser->getId() == $this->getUser()->getId())); + $this->route = "@user_content"; + } + else + { + $thisUser = $this->getUser()->getGuardUser(); + $this->route = "@my_content"; + } + + if ($this->getRequestParameter("fileId")) + { + try + { + $this->file = new artworkFile($this->getRequestParameter("fileId")); + } + catch (exception $e) + { + throw new exception ($e); + } + } + + if ($this->getRequestParameter("artworkId")) + { + $reaktorArtwork = ReaktorArtworkPeer::retrieveByPK($this->getRequestParameter("artworkId")); + if ($reaktorArtwork && ($reaktorArtwork->getUserId() == $this->getUser()->getId() || $this->getUser()->hasCredential("editusercontent"))) + { + $this->linkArtwork = new genericArtwork($reaktorArtwork); + } + else + { + $this->forward404(); + } + } + elseif ($this->getRequestParameter("link") && $this->getRequestParameter("fileId") && $this->getUser()->hasCredential("createcompositeartwork")) + // Creating a new one (composite)- admin only + { + $this->linkArtwork = new genericArtwork(); + $this->linkArtwork->setCreatedAt(time()); + $this->linkArtwork->setArtworkType($this->file->getIdentifier()); + $this->linkArtwork->setUser($this->getUser()->getGuardUser()); + $this->linkArtwork->setMultiUser(); + $this->linkArtwork->save(); + $this->linkArtwork->setTitle(sfContext::getInstance()->getI18n()->__("New composite artwork %artwork_id%", array("%artwork_id%" => $this->linkArtwork->getId()))); + $this->linkArtwork->save(); + } + + $includeHidden = false; + if ($this->getUser()->hasCredential("viewallcontent")) + { + $includeHidden = true; + } + + // Pass the required template variables that are common to all actions + $this->thisUser = $thisUser; + $this->uploadedCount = ReaktorFilePeer::countFilesByUser($this->thisUser, null, false, $includeHidden); + + } + + /** + * Executes overview (manage) page template with counts and links, or loads the correct tamplates based on the mode + * + * @return null + */ + public function executeManage() + { + $this->mode = $this->getRequestParameter('mode'); + switch ($this->getRequestParameter("mode")) + { + case "allartwork": + $this->titleFilter = ""; + return $this->artworkList(); + break; + case "allfiles": + $this->titleFilter = ""; + return $this->fileList(); + break; + case "orphanedfiles": + $this->titleFilter = sfContext::getInstance()->getI18N()->__("unused"); + return $this->fileList(true); + break; + case "unsuitablefiles": + $this->titleFilter = sfContext::getInstance()->getI18N()->__("unsuitable"); + return $this->fileList(null, true); + break; + case "draftartwork": + $this->titleFilter = sfContext::getInstance()->getI18N()->__("draft"); + return $this->artworkList(ReaktorArtwork::DRAFT); + break; + case "submittedartwork": + $this->titleFilter = sfContext::getInstance()->getI18N()->__("awaiting approval"); + return $this->artworkList(ReaktorArtwork::SUBMITTED); + break; + case "allrejected": + $this->titleFilter = sfContext::getInstance()->getI18N()->__("rejected"); + return $this->artworkList(ReaktorArtwork::REJECTED); + break; + case "allremoved": + $this->titleFilter = sfContext::getInstance()->getI18N()->__("removed"); + return $this->artworkList(array(ReaktorArtwork::REMOVED)); + break; + case "allapproved": + $this->titleFilter = sfContext::getInstance()->getI18N()->__("approved"); + return $this->artworkList(array(ReaktorArtwork::APPROVED, ReaktorArtwork::APPROVED_HIDDEN)); + break; + case "link": + $this->titleFilter = '"'.$this->linkArtwork->getTitle().'"'; + $this->makeCollection(); + break; + default: + $c = null; + if (!$this->getUser()->hasCredential("viewallcontent")) + { + $c = new Criteria(); + $c->add(ReaktorArtworkPeer::STATUS, ReaktorArtwork::REMOVED, Criteria::NOT_EQUAL); + } + $artworkCountArray = ReaktorArtworkPeer::countUserArtworks($this->thisUser, null, null, true, $c); + $this->allArtworkCount = 0; + $this->draftArtworkCount = isset($artworkCountArray[1]) ? array_sum($artworkCountArray[1]) : false; + $this->rejectedArtworkCount = isset($artworkCountArray[4]) ? array_sum($artworkCountArray[4]) : false; + $this->submittedArtworkCount = isset($artworkCountArray[2]) ? array_sum($artworkCountArray[2]) : false; + + $this->approvedCount = isset($artworkCountArray[3]) ? array_sum($artworkCountArray[3]) : false; + $this->approvedHiddenCount = isset($artworkCountArray[6]) ? array_sum($artworkCountArray[6]) : false; + + $this->approvedArtworkCount = $this->approvedCount + $this->approvedHiddenCount; + + $this->orphanedCount = ReaktorFilePeer::countFilesByUser($this->thisUser, null, true); + + foreach($artworkCountArray as $item) + { + $this->allArtworkCount += array_sum($item); + } + break; + } + } + + /** + * Execute the list of all the users artwork, or artwork with a certain status + * + * @param integer $status if set, will return only artworks that match the status id supplied + * + * @return null + */ + private function artworkList($status = null) + { + // Get all the artworks for this user, passing status to filter on if need be + // If not admin, do not show artworks the user has removed + if ($this->getUser()->hasCredential("viewallcontent")) + { + $statusExclude = array(); + } + else + { + $statusExclude = array(ReaktorArtwork::REMOVED); + } + $c = null; + + // If we are filtering on year, we'll pass some extra criteria to the query + if ($this->getRequestParameter("year")) + { + $c = new Criteria(); + $critA = $c->getNewCriterion(ReaktorArtworkPeer::ACTIONED_AT, $this->getRequestParameter("year")."-01-01 00:00:00", Criteria::GREATER_EQUAL); + $critB = $c->getNewCriterion(ReaktorArtworkPeer::ACTIONED_AT, $this->getRequestParameter("year")."-12-31 23:59:59", Criteria::LESS_EQUAL); + $critA->addAnd($critB); + $c->add($critA); + } + + $this->artworks = ReaktorArtworkPeer::getArtworksByUser($this->thisUser, 0, false, array(), $status, $statusExclude, $c); + + // Set whether to allow ordering in the template (only applicable if we are not filtering) + if (1) // Set to always on but will leave this here in case this flag is useful in future + { + $this->allowOrdering = true; + } + else + { + $this->allowOrdering = false; + } + + $this->setTemplate("artworkList"); + } + + /** + * Execute the list of all the users files, or files with a certain criteria + * + * @param boolean $orphaned If set will check to see if the file is orphaned or not - if not set, all files are returned + * @param boolean $link If set, will show link options + * + * @return null + */ + private function fileList($orphaned = null, $unsuitable = null) + { + $showHidden = false; + if ($this->getUser()->hasCredential("viewallcontent")) + { + $showHidden = true; + } + $this->files = ReaktorFilePeer::getFilesByUser($this->thisUser, null, $orphaned, false, false, array(), $showHidden, $unsuitable); + $this->setTemplate("fileList"); + } + + /** + * Execute the collection page for making drag and drop galleries + * + * @return null + */ + private function makeCollection() + { + if ($this->getRequestParameter("allusers") && $this->getUser()->hasCredential("createcompositeartwork")) + { + $this->eligibleFiles = ReaktorFilePeer::getFilesByType($this->linkArtwork->getEligbleFileTypes(), $this->linkArtwork->getFiles(true), false); + } + else + { + $this->eligibleFiles = ReaktorFilePeer::getFilesByUser($this->thisUser, $this->linkArtwork->getEligbleFileTypes(), null, null, true, $this->linkArtwork->getFiles(true), false, false); + } + $this->setTemplate("collection"); + $this->artworkFiles = $this->linkArtwork->getFiles(); + } + + /** + * Ajax function for adding a file to the gallery + * + * @return null + */ + public function executeAdd() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && + ($this->getUser()->getId() == $this->thisUser->getId() || $this->getUser()->hasCredential("editusercontent"))); + + try + { + $this->linkArtwork->addFile($this->getRequestParameter("fileId")); + + // Set it back to ready for approval + if (!$this->linkArtwork->isDraft()) + { + if (!$this->getUser()->hasCredential("editusercontent")) + { + $this->linkArtwork->changeStatus($this->getUser(), 2, sfContext::getInstance()->getI18n()->__("New files added to collection")); + } + } + // Or just mark it as changed + else + { + sfLoader::loadHelpers(array("Url", "Tag")); + $selectedFile = ReaktorFilePeer::retrieveByPK($this->getRequestParameter("fileId"), null, true); + $translateMe = sfContext::getInstance()->getI18n()->__("The following file was added to the collection"); + $this->linkArtwork->flagChanged($this->getUser(), "The following file was added to the collection"); + $this->linkArtwork->flagChanged($this->getUser(), " - ".link_to($selectedFile->getTitle()." (".$selectedFile->getId().")", "@edit_upload?fileId=".$selectedFile->getId())); + } + $this->linkArtwork->save(); + } + catch (Exception $e) + { + throw new exception($e);// Not too fussed if it doesn't work - just means someone is trying to add the same file again + } + $this->artworkFiles = ReaktorArtworkFilePeer::getFilesInArtwork($this->linkArtwork); + + sfLoader::loadHelpers("Partial"); + + if ($this->getRequestParameter("miniResult")) + { + $file = new artworkFile($this->getRequestParameter("fileId")); + return $this->renderText(get_component("userContent", "artworkCompositeSelect", + array("file" => $file, "thisUser" => $this->thisUser))); + } + else + { + return $this->renderText(get_partial("userContent/simpleFileListForAjax", + array("artworkFiles" => $this->artworkFiles, + "button" => "remove", + "linkArtwork" => $this->linkArtwork, + "thisUser" => $this->thisUser, + "allowOrdering" => true ))); + } + } + + /** + * Ajax function for removing a file from gallery + * + * @return null + */ + public function executeRemove() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest() && + ($this->getUser()->getId() == $this->thisUser->getId() || $this->getUser()->hasCredential("editusercontent") || $this->getUser()->hasCredential("createcompositeartwork"))); + + try + { + // Shouldn't be here if they don't have more than one file + if (count(ReaktorArtworkFilePeer::getFilesInArtwork($this->linkArtwork)) > 1) + { + $this->linkArtwork->removeFile($this->getRequestParameter("fileId")); + + sfLoader::loadHelpers(array("Url", "Tag")); + $selectedFile = ReaktorFilePeer::retrieveByPK($this->getRequestParameter("fileId"), null, true); + $translateMe = sfContext::getInstance()->getI18n()->__("The following file was removed from the collection"); + $this->linkArtwork->flagChanged($this->getUser(), "The following file was removed from the collection"); + $this->linkArtwork->flagChanged($this->getUser(), " - ".link_to($selectedFile->getTitle()." (".$selectedFile->getId().")", "@edit_upload?fileId=".$selectedFile->getId())); + } + } + catch (Exception $e) + { + // Not too fussed if it doesn't work - just means someone is trying to add the same file again + } + $this->linkArtwork->save(); + + if ($this->getRequestParameter("allusers") && $this->getUser()->hasCredential("createcompositeartwork")) + { + $this->eligibleFiles = ReaktorFilePeer::getFilesByType($this->linkArtwork->getArtworkType(), $this->linkArtwork->getFiles(true)); + } + else + { + $this->eligibleFiles = ReaktorFilePeer::getFilesByUser($this->thisUser, $this->linkArtwork->getArtworkType(), null, null, true, $this->linkArtwork->getFiles(true)); + } + + sfLoader::loadHelpers("Partial"); + return $this->renderText(get_partial("userContent/simpleFileListForAjax", + array("artworkFiles" => $this->eligibleFiles, + "button" => "add", "linkArtwork" => $this->linkArtwork, + "thisUser" => $this->thisUser ))); + } + + /** + * Ajax responder for getting a list of artworks from a partial + * + * @return null + */ + public function executeGetArtworkList() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + + $file = new artworkFile($this->getRequestParameter("fileId")); + sfLoader::loadHelpers("Partial"); + return $this->renderText(get_partial("userContent/listArtworks", array("file" => $file))); + } + + /** + * Ajax functionality for hiding a file + * + * @return string "ok" on success + */ + public function executeHideFile() + { + $this->forward404Unless($this->getRequest()->isXmlHttpRequest()); + + $file = new artworkFile($this->getRequestParameter("fileId")); + $this->forward404Unless($file->getUserId() == $this->getUser()->getId() || $this->getUser()->hasCredential("editusercontent")); + + $file->setHidden(); + $file->save(); + + return $this->renderText("ok"); + + } + + /** + * Ajax call to update the sidebar menu + * + * @return null + */ + public function executeUpdateSidebar() + { + sfLoader::loadHelpers("Partial"); + return $this->renderText(get_component('userContent', 'contentManagerSidebarAjaxblock')); + } +} diff --git a/apps/reaktor/modules/userContent/actions/components.class.php b/apps/reaktor/modules/userContent/actions/components.class.php new file mode 100644 index 0000000..5c33bd4 --- /dev/null +++ b/apps/reaktor/modules/userContent/actions/components.class.php @@ -0,0 +1,105 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +/** + * Components for user content + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +class userContentComponents extends sfComponents +{ + /** + * Select dropdown for making composite artworks + * + * @return null + */ + function executeArtworkCompositeSelect() + { + // Get the list of eligible artworks + $this->thisUser = sfGuardUserPeer::getByUsername($this->getRequestParameter("user")); + $this->artworks = ReaktorArtworkPeer::getArtworksByType($this->file->getIdentifier(), null, true, true, $this->file->getParentArtworks(true)); + } + + /** + * The sidebar menu for content management + * + * @returm null + */ + public function executeContentManagerSidebarAjaxblock() + { + if ($this->getRequestParameter("user")) + { + $this->thisUser = sfGuardUserPeer::getByUsername($this->getRequestParameter("user")); + $this->route = "@user_content"; + } + else + { + $this->thisUser = $this->getUser()->getGuardUser(); + $this->route = "@my_content"; + } + + $c = new Criteria(); + if ($this->getUser()->hasCredential("viewallcontent")) + { + $includeHidden = true; + } + else + { + $includeHidden = false; + $c->add(ReaktorArtworkPeer::STATUS, ReaktorArtwork::REMOVED, Criteria::NOT_EQUAL); + } + + $artworkCount = ReaktorArtworkPeer::countUserArtworks($this->thisUser, null, null, true, $c); + $this->fileCount = ReaktorFilePeer::countFilesByUser($this->thisUser, null, false, $includeHidden); + $this->unusedCount = ReaktorFilePeer::countFilesByUser($this->thisUser, null, true, $includeHidden); + $this->unsuitableCount = ReaktorFilePeer::countFilesByUser($this->thisUser, null, false, $includeHidden, true); + + // If an artwork is status 6, then it can show up with the approved artworks so we'll just lump them all together + if (isset($artworkCount [ReaktorArtwork::APPROVED]) && isset($artworkCount [ReaktorArtwork::APPROVED_HIDDEN])) + { + foreach ($artworkCount [ReaktorArtwork::APPROVED_HIDDEN] as $year => $count) + { + if (isset($artworkCount [ReaktorArtwork::APPROVED][$year])) + { + $artworkCount [ReaktorArtwork::APPROVED][$year] += $count; + } + else + { + $artworkCount [ReaktorArtwork::APPROVED][$year] = $count; + } + } + } + elseif (!isset($artworkCount [ReaktorArtwork::APPROVED]) && isset($artworkCount [ReaktorArtwork::APPROVED_HIDDEN])) + { + $artworkCount [ReaktorArtwork::APPROVED] = $artworkCount [ReaktorArtwork::APPROVED_HIDDEN]; + } + $this->artworkCount = $artworkCount; + $this->total = 0; + + foreach($artworkCount as $status => $item) + { + if ($status != ReaktorArtwork::REMOVED || $this->getUser()->hasCredential("viewallcontent")) + { + $this->total += array_sum($item); + } + } + } +} + + + + \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/templates/_artworkCompositeSelect.php b/apps/reaktor/modules/userContent/templates/_artworkCompositeSelect.php new file mode 100644 index 0000000..a25daca --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/_artworkCompositeSelect.php @@ -0,0 +1,36 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript", "content"); + +?> + +

    + 'composite_'.$file->getId(), + 'url' => 'userContent/add', + 'loading' => "", + 'complete' => visual_effect('highlight', 'artwork_list_'.$file->getId()). + "new Ajax.Updater('artwork_list_".$file->getId()."', '".url_for("@getartworklist?fileId=".$file->getId())."')"), + array( + 'class' => 'composite_add_form', + 'id' => 'composite_add_form_'.$file->getId(), + 'name' => 'composite_add_form_'.$file->getId())); ?> + __("---Create new---")))); ?> + getId()); ?> + getUsername()); ?> + + "link")); ?> + \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/templates/_contentManagerSidebarAjaxblock.php b/apps/reaktor/modules/userContent/templates/_contentManagerSidebarAjaxblock.php new file mode 100644 index 0000000..d9932d8 --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/_contentManagerSidebarAjaxblock.php @@ -0,0 +1,69 @@ + so it can be updated via an ajax call + * + * PHP Version 5 + * + * @author Russ + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + +

    + +

    $total)), $route."?mode=allartwork&user=".$thisUser->getUsername()); ?>

    + + +

    array_sum($artworkCount[3]))), $route."?mode=allapproved&user=".$thisUser->getUsername()); ?>

    +
      + $count): ?> +
    • getUsername()); ?>
    • + +
    + + + +

    array_sum($artworkCount[2]))), $route."?mode=submittedartwork&user=".$thisUser->getUsername()); ?>

    + + + +

    array_sum($artworkCount[1]))), $route."?mode=draftartwork&user=".$thisUser->getUsername()); ?>

    + + + +

    array_sum($artworkCount[4]))), $route."?mode=allrejected&user=".$thisUser->getUsername()); ?>

    + + +hasCredential("viewallcontent")): ?> +

    array_sum($artworkCount[5]))), $route."?mode=allremoved&user=".$thisUser->getUsername()); ?>

    + + +
    +
    +

    + + +

    $fileCount)), $route."?mode=allfiles&user=".$thisUser->getUsername()); ?>

    + +

    $unusedCount)), $route."?mode=orphanedfiles&user=".$thisUser->getUsername()); ?>

    + + +

    $unsuitableCount)), $route."?mode=unsuitablefiles&user=".$thisUser->getUsername()); ?>

    + + + + + \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/templates/_listArtworks.php b/apps/reaktor/modules/userContent/templates/_listArtworks.php new file mode 100644 index 0000000..4798781 --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/_listArtworks.php @@ -0,0 +1,28 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +$first = true; +?> + +countParentArtworks()): ?> + ' . __("Part of: %list_of_artworks%", array("%list_of_artworks%" => "")); ?> + getParentArtworks() as $artwork): ?> + isMultiUser() || $artwork->isApproved() || $sf_user->hasCredential("viewallcontent")): ?> + + getTitle(), "@show_artwork?title=".$artwork->getTitle()."&id=".$artwork->getId()); ?> + + + + + ' . __('Part of: %list_of_artworks%', array('%list_of_artworks%' => '' . __("No artworks"))); ?> + \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/templates/_sideMenu.php b/apps/reaktor/modules/userContent/templates/_sideMenu.php new file mode 100644 index 0000000..09f61c5 --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/_sideMenu.php @@ -0,0 +1,18 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +reaktor::addJsToFooter("$('content_manager_sidebar').setStyle({height: $('sidebar').offsetHeight + 'px'});"); +?> + +
    + +
    \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/templates/_simpleFileListForAjax.php b/apps/reaktor/modules/userContent/templates/_simpleFileListForAjax.php new file mode 100644 index 0000000..34cdf63 --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/_simpleFileListForAjax.php @@ -0,0 +1,56 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript", "content"); +$admin = (sfConfig::get("admin_mode")) ? "admin" : ""; +?> + +
      + + +
    • + isApproved() && !$sf_user->hasCredential("editusercontent")) ? "confirm" : "noconfirm"; ?> + collectionType($linkArtwork))), + array( + 'url' => "@".$admin."addToCollection?user=".$thisUser->getUsername()."&artworkId=".$linkArtwork->getId()."&fileId=".$file->getId(), + 'complete' => "removeButtons++;Effect.BlindUp('bottom_".$file->getId()."');", + 'update' => "artwork_collection_files", + $confirm => ($linkArtwork->isApproved() ? __("Warning - you are adding files to an approved artwork. Adding this file to your artwork will force the artwork to be resubmitted for approval by the editorial staff, continue?") : ""), + 'script' => true), + array("class" => "")); ?> + +
    • + collectionType($linkArtwork))), + array( + 'url' => "@".$admin."removeFromCollection?user=".$thisUser->getUsername()."&artworkId=".$linkArtwork->getId()."&fileId=".$file->getId()."&allusers=".$sf_params->get("allusers", "false"), + 'complete' => "removeButtons--;Effect.BlindUp('file_".$file->getId()."');", + 'update' => "artwork_eligible_files", + 'confirm' => __("Are you sure? Note: Artworks must contain at least 1 file."), + 'condition' => "removeButtons > 1"), + array("class" => "remove")); ?> + + $file, "thisUser" => $thisUser, "extraButton" => $extraButton)); ?> +
    • + +
    + + + + '@artworkupdatefield?id='.$linkArtwork->getId().'&field=files', + 'loading' => "", + 'success' => visual_effect('highlight', 'artwork_files'), + )); ?> + \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/templates/_userFileInList.php b/apps/reaktor/modules/userContent/templates/_userFileInList.php new file mode 100644 index 0000000..3c60cef --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/_userFileInList.php @@ -0,0 +1,85 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +use_helper("content", "Javascript"); +$title = $file->getTitle() ? $file->getTitle() : __("no title"); + +?> +
    + $title, + 'alt' => $title, + 'height' => 65, + 'width' => 78, + )); ?> +
    + +
    + [ ".reaktor_link_to(__("edit"), "@edit_upload?fileId=".$file->getId())." ]"; ?> +
      +
    • + + getIdentifier())); ?> + date("d/m/Y", strtotime($file->getUploadedAt())), + "%created_time%" => date("H:i", strtotime($file->getUploadedAt())), + "%action%" => strtolower(__("Uploaded")), + "%user%" => link_to($file->getUser()->getUsername(), "@portfolio?user=".$file->getUser()->getUsername()))); ?> +
      + : + + getTags() as $aTag): ?> + + + + + getTags()): ?> + + $file, "options" => array("rowLimit" => 4, "nomargin" => true,'noicons' => true))); ?> + + getTags(true)): ?> + ' . __('This file has no approved tags. Tags makes your files easier to find.') . ''; ?> + + ' . __('This file has no tags. Tags makes your files easier to find.') . ''; ?> + + +
      + $file)); ?> +
    • +
    +
    +
    + isHidden() && !$sf_params->get("artworkId")): ?> +
    + $file, "thisUser" => $thisUser)); ?> +
    + +
    + + + + isHidden()): ?> + "Effect.BlindUp('file_".$file->getId()."');updateContentSidebar('".$thisUser->getUsername()."');", + 'url' => '@hide_file?fileId='.$file->getId(), + 'confirm' => __("You are about to completely remove this file. Any artworks that contain only this file will also be removed, are you sure?"), + ), array("id" => "remove_button_".$file->getId())); ?> + + + +
    +
    diff --git a/apps/reaktor/modules/userContent/templates/artworkListSuccess.php b/apps/reaktor/modules/userContent/templates/artworkListSuccess.php new file mode 100644 index 0000000..aed394f --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/artworkListSuccess.php @@ -0,0 +1,106 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +if ($thisUser->getId() == $sf_user->getId()) +{ + $title = __("My artwork with status: %filter_eg_submitted% %from_year_statement%", + array("%filter_eg_submitted%" => ucfirst($titleFilter), + "%from_year_statement%" => ($sf_params->get("year") ? __("%artworks_statement% in %year%", + array("%year%" => $sf_params->get("year"), + "%artworks_statement%" => "")) : ""))); +} +else +{ + $title = __("(%username%), artwork with status: %filter_eg_submitted% %from_year%", + array("%username%" => $thisUser->getUsername(), + "%filter_eg_submitted%" => ucfirst($titleFilter), + "%from_year%" => ($sf_params->get("year") ? "(".$sf_params->get("year").")" : "" + ))); +} +reaktor::setReaktorTitle($title); +?> + +
    +
    + +
    +

    :

      +

    +
    +

    +
    + + + +
    +

    :

      +

    +
    +

    .

    +
    + +
    +

    :

      +

    +
    +

    +
    + +

    + + +

    + +

    */ ?> +
    + $artworks, "thisUser" => $thisUser)); ?> + +
      + + getFilesCount() == 0) continue; ?> +
    • + $artwork, "thisUser" => $thisUser)); ?> +
    • + +
    + +
    +
    \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/templates/collectionSuccess.php b/apps/reaktor/modules/userContent/templates/collectionSuccess.php new file mode 100644 index 0000000..1558a06 --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/collectionSuccess.php @@ -0,0 +1,45 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +use_helper("content", "Javascript"); +$title = __("Manage files in %artwork_title%", array("%artwork_title%" => $linkArtwork->getTitle())); + +reaktor::setReaktorTitle($title); +?> + +
    +

    reaktor_link_to($linkArtwork->getTitle(), + "@show_artwork?id=".$linkArtwork->getId()."&title=".$linkArtwork->getTitle()))); ?>

    + getId())." ]"; ?> + getUsername()."&mode=menu")." ]"; ?> +
    +

    +
    + $artworkFiles, "button" => "delete", "linkArtwork" => $linkArtwork, "thisUser" => $thisUser, "allowOrdering" => true)); ?> +
    +
    +

    collectionType($linkArtwork))); ?>

    + getId()); ?> + hasCredential("createcompositeartwork")): ?> + get("allusers")): ?> + getUser()->getUsername()."&artworkId=".$linkArtwork->getId()); ?> + + getId(), array("confirm" => __("If you add files from other users, this artwork will become a composite (multi-user) artwork"))); ?> + + + +
    +
    + $eligibleFiles, "button" => "add", "linkArtwork" => $linkArtwork, "thisUser" => $thisUser)); ?> +
    +
    \ No newline at end of file diff --git a/apps/reaktor/modules/userContent/templates/fileListSuccess.php b/apps/reaktor/modules/userContent/templates/fileListSuccess.php new file mode 100644 index 0000000..4ff4c3a --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/fileListSuccess.php @@ -0,0 +1,50 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +if ($thisUser->getId() == $sf_user->getId()) +{ + $title = __("My %filter_eg_submitted% files", array("%filter_eg_submitted%" => $titleFilter)); +} +else +{ + $title = __("%filter_eg_submitted% files for %username%", + array("%username%" => $thisUser->getUsername(), + "%filter_eg_submitted%" => strtoupper($titleFilter))); +} +$rowCount = 1; +reaktor::setReaktorTitle($title); +?> + +
    +
    +

    getUsername()."&mode=menu")." ]"; */ ?> +

    +
    + +
      + + +
    • > + $file, "thisUser" => $thisUser)); ?> +
    • + +
    + getId() == $sf_user->getId()): ?> + $titleFilter))." - ".reaktor_link_to(__("click here to upload more!"), "@upload_content"); ?> + + $titleFilter)); ?> + +
    diff --git a/apps/reaktor/modules/userContent/templates/manageSuccess.php b/apps/reaktor/modules/userContent/templates/manageSuccess.php new file mode 100644 index 0000000..9b60a21 --- /dev/null +++ b/apps/reaktor/modules/userContent/templates/manageSuccess.php @@ -0,0 +1,94 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +if ($thisUser->getId() == $sf_user->getId()) +{ + reaktor::setReaktorTitle(__("Manage my Artworks")); +} +else +{ + reaktor::setReaktorTitle(__("Manage Artwork for %username%", array("%username%" => $thisUser->getUsername()))); +} + +?> + +
    +

    + getId() == $sf_user->getId()): ?> + + + $thisUser->getUsername())); ?> + +

    +

    .

    +
    +

    +

    +
      +
    • *
    • +
    • *
    • +
    +

    + +
    + +
      + +

      +
    • $allArtworkCount)), $route."?mode=allartwork&user=".$thisUser->getUsername()); ?>
    • + +
    • $draftArtworkCount)), $route."?mode=draftartwork&user=".$thisUser->getUsername()); ?>
    • + + + +
    • $submittedArtworkCount)), $route."?mode=submittedartwork&user=".$thisUser->getUsername()); ?>
    • + + + +
    • $approvedArtworkCount)), $route."?mode=allapproved&user=".$thisUser->getUsername()); ?>
    • + + + +
    • $rejectedArtworkCount)), $route."?mode=allrejected&user=".$thisUser->getUsername()); ?>
    • + + + +

      +
    • $uploadedCount)), $route."?mode=allfiles&user=".$thisUser->getUsername()); ?>
    • + + +
    • $orphanedCount)), $route."?mode=orphanedfiles&user=".$thisUser->getUsername()); ?>
    • + +
    + getId() == $sf_user->getId()): ?> + + + + +
    \ No newline at end of file diff --git a/apps/reaktor/templates/_adminmenubar.php b/apps/reaktor/templates/_adminmenubar.php new file mode 100644 index 0000000..4f8bb45 --- /dev/null +++ b/apps/reaktor/templates/_adminmenubar.php @@ -0,0 +1,206 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +?> + diff --git a/apps/reaktor/templates/_bottom_menu.php b/apps/reaktor/templates/_bottom_menu.php new file mode 100644 index 0000000..adb1f67 --- /dev/null +++ b/apps/reaktor/templates/_bottom_menu.php @@ -0,0 +1,42 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper('Javascript'); +?> + + + + + +
    + + diff --git a/apps/reaktor/templates/_footer.php b/apps/reaktor/templates/_footer.php new file mode 100644 index 0000000..80ceaeb --- /dev/null +++ b/apps/reaktor/templates/_footer.php @@ -0,0 +1,45 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ +?> + + + + + + +getAttribute('footer_js', array()); + if (!empty($footerJs)) + { + echo javascript_tag(implode("\n", $footerJs)); + } +?> + + + \ No newline at end of file diff --git a/apps/reaktor/templates/_header.php b/apps/reaktor/templates/_header.php new file mode 100644 index 0000000..d05d2a9 --- /dev/null +++ b/apps/reaktor/templates/_header.php @@ -0,0 +1,114 @@ + ) should be the doctype declaration. Technically layout.php + * is rendered before this one, but this file should be the first one that layout.php includes. + * + * Header file mainly contains the content of the head tags and any opening + * Tags such as body, html and the wrapper div which are all closed in _footer.php + * + * Also in the header template is anything that should appear at the top of every page, such as the font resizer + * and language links. + * + * PHP Version 5 + * + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +use_helper("Javascript"); +$supported_browser = false; +//var_dump(browser_detection('moz_version')); +switch (browser_detection('browser')) +{ + case 'op': + if (browser_detection('math_number') >= 9) $supported_browser = true; + break; + case 'moz': + $moz_info = browser_detection('moz_version'); + if ($moz_info[1] >= 2) $supported_browser = true; + break; + case 'ie': + if (browser_detection('math_number') >= 7) $supported_browser = true; + break; + case 'saf': + if (browser_detection('math_number') >= 3) $supported_browser = true; + break; +} + +// Page output for the entire site begins after this tag +?> + + + + + + + + + + + getAttribute('rss_head_meta', array()); + + foreach ($rss_headers as $rss_header) + { + echo auto_discovery_link_tag('rss', $rss_header['url'], array('title' => $rss_header['title'])); + } + + ?> + + + + + + + + + + +
    + +
    "
    \n", '%firefox%' => 'Firefox', '%opera%' => 'Opera', '%safari%' => 'Safari'))?>. +
    + +
    + + +
    + __("Use normal font size"), "id" => "font_size_normal")); ?> + __("Use larger font size"), "id" => "font_size_larger")); ?> + __("Use largest font size"), "id" => "font_size_largest")); ?> +
    + +
    + $sf_user->getCulture())); ?> +
    +
    + + $sf_user->getCulture(), "current_for_cache" => Subreaktor::getProvidedSubreaktorReference().Subreaktor::getProvidedLokalReference())); ?> + + + + diff --git a/apps/reaktor/templates/_lightheader.php b/apps/reaktor/templates/_lightheader.php new file mode 100644 index 0000000..403b9cc --- /dev/null +++ b/apps/reaktor/templates/_lightheader.php @@ -0,0 +1,27 @@ + + + + + + + + + + + getAttribute('rss_head_meta', array()); + foreach ($rss_headers as $rss_header) + { + echo auto_discovery_link_tag('rss', $rss_header['url'], array('title' => $rss_header['title'])); + } + ?> + + + + + + + + +
    + \ No newline at end of file diff --git a/apps/reaktor/templates/_logo.php b/apps/reaktor/templates/_logo.php new file mode 100644 index 0000000..4f4c702 --- /dev/null +++ b/apps/reaktor/templates/_logo.php @@ -0,0 +1,54 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +$lokalreaktor = Subreaktor::getProvidedLokalreaktor(); +$subreaktor = Subreaktor::getProvidedSubreaktor(); +?> + + + "header_image", "usemap" => "#admin_map")); ?> + + " title=" sfConfig::get("app_main_title"))); ?>" alt=" sfConfig::get("app_main_title"))); ?>" /> + " title="" alt="" /> + + + "header_image", "usemap" => "#user_map")); ?> + + " title=" sfConfig::get("app_main_title"))); ?>" alt=" sfConfig::get("app_main_title"))); ?>" /> + get("username", $sf_user->getUsername())))); ?>" title="" alt="" /> + + + getReference()) . ".gif", array("id" => "header_image", "usemap" => "#header_map")); ?> + + " title=" sfConfig::get("app_main_title"))); ?>" alt=" sfConfig::get("app_main_title"))); ?>" /> + $lokalreaktor->getName())); ?>" alt=" $lokalreaktor->getName())); ?>" /> + + + getReference()) . ".gif", array("id" => "header_image", "usemap" => "#header_map")); ?> + + " title=" sfConfig::get("app_main_title"))); ?>" alt=" sfConfig::get("app_main_title"))); ?>" /> + $subreaktor->getName())); ?>" alt=" $subreaktor->getName())); ?>" /> + + + "header_image", 'usemap' => '#forsidemap', 'border' => 0)); ?> + + " title=" sfConfig::get("app_main_title"))); ?>" alt=" sfConfig::get("app_main_title"))); ?>" /> + " title="getName(); ?>" alt="getName(); ?>" /> + " title="getName(); ?>" alt="getName(); ?>" /> + " title="getName(); ?>" alt="getName(); ?>" /> + " title="getName(); ?>" alt="getName(); ?>" /> + " title="getName(); ?>" alt="getName(); ?>" /> + " title="getName(); ?>" alt="getName(); ?>" /> + + diff --git a/apps/reaktor/templates/_menubar.php b/apps/reaktor/templates/_menubar.php new file mode 100644 index 0000000..7e6b80b --- /dev/null +++ b/apps/reaktor/templates/_menubar.php @@ -0,0 +1,59 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +$lokalreaktor = $sf_request->getAttribute("lokalreaktor"); +$subreaktor = $sf_request->getAttribute("subreaktor"); + +?> + diff --git a/apps/reaktor/templates/emptyLayout.php b/apps/reaktor/templates/emptyLayout.php new file mode 100644 index 0000000..77755f7 --- /dev/null +++ b/apps/reaktor/templates/emptyLayout.php @@ -0,0 +1,17 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + */ + +?> + +getRaw('sf_content'); ?> \ No newline at end of file diff --git a/apps/reaktor/templates/layout.php b/apps/reaktor/templates/layout.php new file mode 100644 index 0000000..f7b4bf6 --- /dev/null +++ b/apps/reaktor/templates/layout.php @@ -0,0 +1,33 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include_partial('global/header'); + +?> +
    +
    + getRaw('sf_content') ?> +
    + + +
    + \ No newline at end of file diff --git a/apps/reaktor/templates/no_decor_layout.php b/apps/reaktor/templates/no_decor_layout.php new file mode 100644 index 0000000..41e32a3 --- /dev/null +++ b/apps/reaktor/templates/no_decor_layout.php @@ -0,0 +1,29 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include_partial('global/lightheader'); + +?> +
    +
    + getRaw('sf_content') ?> +
    +
    +
    \ No newline at end of file diff --git a/batch/load_data.php b/batch/load_data.php new file mode 100755 index 0000000..43a1bb4 --- /dev/null +++ b/batch/load_data.php @@ -0,0 +1,27 @@ +#! /usr/bin/php + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..')); +define('SF_APP', 'reaktor'); +define('SF_ENVIRONMENT', 'dev'); +define('SF_DEBUG', true); + +require_once SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'; + +// initialize database manager +$databaseManager = new sfDatabaseManager(); +$databaseManager->initialize(); + +$data = new sfPropelData(); +$data->loadData(sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fixtures'); + +?> diff --git a/cache/reaktor/dev/config/config_app.yml.php b/cache/reaktor/dev/config/config_app.yml.php new file mode 100644 index 0000000..5a9e4e2 --- /dev/null +++ b/cache/reaktor/dev/config/config_app.yml.php @@ -0,0 +1,274 @@ + 'Reaktor', + 'app_rss_email' => 'reaktor@deichman.no', + 'app_rss_authorname' => 'Reaktor', + 'app_rss_url' => NULL, + 'app_rss_artwork_items' => 10, + 'app_reaktor_url' => 'http://reaktor', + 'app_image_path' => 'images', + 'app_logged_in_time' => 1800, + 'app_main_title' => 'Reaktor', + 'app_site_title' => 'Reaktor', + 'app_title_seperator' => ' ~ ', + 'app_admin_logo' => 'logoAdmin.gif', + 'app_redaksjon_logo' => 'reaktor_red.gif', + 'app_help_email' => 'help@minreaktor.no', + 'app_fixed_articles_terms_and_conditions' => 'Vilkaar_for_bruk', + 'app_fixed_articles_login_help' => 'login_help', + 'app_files_location_identifiers' => array ( + 'image' => 'image', + 'pdf' => 'pdf', + 'audio' => 'audio', + 'video' => 'video', + 'flash_animation' => 'flash_animation', + 'text' => 'text', +), + 'app_sf_google_analytics_plugin_enabled' => true, + 'app_sf_google_analytics_plugin_profile_id' => 'UA-4885488-1', + 'app_sf_google_analytics_plugin_tracker' => 'google', + 'app_recaptcha_publickey' => '6Lf7mQIAAAAAAG0NGOQMemqzYMViFHl4Egu0qHH-', + 'app_recaptcha_privatekey' => '6Lf7mQIAAAAAAO26Xy8xoRmfqKvteF_v7oohruog', + 'app_admin_commentlistmax' => 10, + 'app_admin_opt_in_email_blocks' => 20, + 'app_admin_pma_readonly_user' => 'pma_user', + 'app_admin_pma_password' => 'R3ak+0rpmA', + 'app_admin_ga_tracker_number' => 'UA-4885488-1', + 'app_upload_upload_dir' => 'content', + 'app_upload_image_dir' => 'image', + 'app_upload_video_dir' => 'video', + 'app_upload_audio_dir' => 'audio', + 'app_upload_pdf_dir' => 'pdf', + 'app_upload_text_dir' => 'text', + 'app_upload_flash_animation_dir' => 'flash_animation', + 'app_upload_attachment_dir' => '/uploads/attachments', + 'app_upload_max_image_width' => 700, + 'app_upload_max_image_height' => 700, + 'app_upload_image_extensions' => array ( + 0 => 'jpg', + 1 => 'png', + 2 => 'gif', +), + 'app_upload_pdf_extensions' => array ( + 0 => 'pdf', +), + 'app_upload_audio_extensions' => array ( + 0 => 'mp3', + 1 => 'wav', +), + 'app_upload_video_extensions' => array ( + 0 => 'mpg', + 1 => 'mpeg', + 2 => 'avi', + 3 => 'swf', +), + 'app_upload_text_extensions' => array ( + 0 => 'txt', +), + 'app_upload_max_thumb_height' => 150, + 'app_upload_max_thumb_width' => 150, + 'app_upload_fix_thumb_height' => 160, + 'app_upload_fix_thumb_width' => 240, + 'app_upload_fix_mini_height' => 65, + 'app_upload_fix_mini_width' => 78, + 'app_upload_pdf_thumb_width' => 116, + 'app_upload_pdf_thumb_height' => 150, + 'app_upload_thumb_allowed_mime' => array ( + 'audio' => + array ( + 0 => 'image/jpeg', + 1 => 'image/jpg', + 2 => 'image/pjpeg', + ), +), + 'app_upload_crop_safe_mime' => array ( + 0 => 'image/jpeg', + 1 => 'image/pjpeg', + 2 => 'image/png', + 3 => 'image/x-png', +), + 'app_sf_guard_plugin_profile_class' => 'sfGuardUserData', + 'app_sf_guard_plugin_remember_key_expiration_age' => 1296000, + 'app_sf_guard_plugin_remember_cookie_name' => 'ReaktorRemember', + 'app_subreaktors_logo_path' => '/home/benjamin/reaktor/trunk/web/images/', + 'app_subreaktors_subcategory_list_length' => 7, + 'app_profile_max_image_width' => 48, + 'app_profile_max_image_height' => 48, + 'app_profile_max_age' => 105, + 'app_profile_min_password_length' => 6, + 'app_profile_email_template' => 'apps/reaktor/modules/profile/data/mail.ini', + 'app_profile_avatar_path' => '/home/benjamin/reaktor/trunk/web/uploads/profile_images/', + 'app_profile_avatar_url' => '/uploads/profile_images/', + 'app_profile_portfolio_pagination' => 21, + 'app_artwork_content_path' => '../content/', + 'app_artwork_max_score' => 6, + 'app_artwork_pagination' => 10, + 'app_artwork_sender' => 'The reaktor team', + 'app_artwork_sender_email' => 'reaktor@deichman.no', + 'app_artwork_valid_title_chars' => 'a-z0-9-_\\søåæäöØÅÆÖÄ!?\'"', + 'app_artwork_max_title_length' => 100, + 'app_artwork_min_title_length' => 3, + 'app_artwork_teaser_len' => 22, + 'app_artwork_other_by_user' => 6, + 'app_artwork_other_usrs_also_like' => 6, + 'app_artwork_additional_file_types' => array ( + 'text' => + array ( + 0 => 'pdf', + ), + 'pdf' => + array ( + 0 => 'text', + ), +), + 'app_artwork_show_navigation' => array ( + 0 => 'text', + 1 => 'pdf', + 2 => 'video', + 3 => 'flash_animation', +), + 'app_articles_teaser_len' => 100, + 'app_articles_help_max_count' => 5, + 'app_articles_internal_max_count' => 5, + 'app_articles_footer_max_count' => 5, + 'app_articles_my_page_max_count' => 5, + 'app_articles_regular_max_count' => 5, + 'app_tagging_minimum_tags' => 0, + 'app_tagging_max_length' => 35, + 'app_tagging_min_length' => 2, + 'app_tagging_cloud_type' => 'pretty', + 'app_category_max_count_on_reaktors' => 3, + 'app_home_list_length' => 5, + 'app_home_max_tags' => 40, + 'app_home_max_tag_length' => 1000, + 'app_message_max_length' => 500, + 'app_sfPropelActAsCommentableBehaviorPlugin_use_ajax' => true, + 'app_sfPropelActAsCommentableBehaviorPlugin_css' => false, + 'app_sfPropelActAsCommentableBehaviorPlugin_anonymous' => array ( + 'enabled' => false, + 'layout' => + array ( + 'name' => 'required', + 'email' => 'required', + 'title' => 'required', + 'comment' => 'required', + ), + 'name' => 'Anonymous User', +), + 'app_sfPropelActAsCommentableBehaviorPlugin_user' => array ( + 'enabled' => true, + 'layout' => + array ( + 'title' => 'required', + 'comment' => 'require', + ), + 'table' => 'sf_guard_user', + 'id' => 'id', + 'class' => 'sfGuardUser', + 'id_method' => 'getId', + 'toString' => '__toString', +), + 'app_sfPropelActAsCommentableBehaviorPlugin_namespaces' => array ( + 'backend' => 'administrator', +), + 'app_sfPropelActAsCommentableBehaviorPlugin_count' => array ( + 'enabled' => true, + 'method' => 'setSfCommentCount', + 'namespace' => 'frontend', +), + 'app_rating_star_width' => 20, + 'app_userlist_exclude' => array ( + 0 => 'admin', + 1 => 'editorialboy1', + 2 => 'editorialboy2', + 3 => 'editorialboy3', + 4 => 'articleboy', + 5 => 'languageboy', + 6 => NULL, +), + 'app_editorial_team_competitions' => array ( + 'competition1' => + array ( + 'start' => '2008-04-04', + 'end' => '2008-04-11', + 'subreaktors' => + array ( + 0 => 'foto', + ), + 'categories' => + array ( + 0 => 3, + ), + 'team' => 'konkurranse_redaksjon', + ), +), + 'app_editorial_team_assignment_groruddalen' => array ( + 0 => 'groruddalen_redaksjon', +), + 'app_editorial_team_assignment_foto' => array ( + 0 => 'assign_by_residence', +), + 'app_editorial_team_assignment_tegneserier' => array ( + 0 => 'serieteket_redaksjon', +), + 'app_editorial_team_assignment_tegning' => array ( + 0 => 'assign_by_residence', +), + 'app_editorial_team_assignment_film' => array ( + 0 => 'assign_by_residence', +), + 'app_editorial_team_assignment_lyd' => array ( + 0 => 'musikk_redaksjon', +), + 'app_editorial_team_assignment_tekst' => array ( + 0 => 'assign_by_residence', +), + 'app_editorial_team_default' => 'deichman_redaksjon', + 'app_editorial_team_assign_by_residence' => array ( + 'deichman_redaksjon' => + array ( + 0 => 1, + 1 => 2, + 2 => 3, + 3 => 5, + 4 => 10, + 5 => 11, + 6 => 12, + 7 => 14, + 8 => 16, + 9 => 17, + 10 => 18, + 11 => 19, + 12 => 21, + 13 => 22, + 14 => 23, + 15 => 24, + ), + 'trondheim_redaksjon' => + array ( + 0 => 4, + 1 => 6, + 2 => 7, + 3 => 9, + 4 => 8, + 5 => 13, + 6 => 25, + 7 => 15, + 8 => 26, + ), + 'groruddalen_redaksjon' => + array ( + 0 => 20, + ), +), + 'app_editorial_team_backup_teams_deichman_redaksjon' => array ( + 0 => 'trondheim_redaksjon', +), + 'app_editorial_team_backup_teams_trondheim_redaksjon' => array ( + 0 => 'deichman_redaksjon', +), + 'app_reports_bookmarks_to_show' => 5, + 'app_sf_use_process_cache' => 'apc', +)); diff --git a/cache/reaktor/dev/config/config_autoload.yml.php b/cache/reaktor/dev/config/config_autoload.yml.php new file mode 100644 index 0000000..ed28ca8 --- /dev/null +++ b/cache/reaktor/dev/config/config_autoload.yml.php @@ -0,0 +1,928 @@ + '/usr/share/php/symfony/request/sfRequest.class.php', +'sfWebRequest' => '/usr/share/php/symfony/request/sfWebRequest.class.php', +'sfConsoleRequest' => '/usr/share/php/symfony/request/sfConsoleRequest.class.php', +'sfLogger' => '/usr/share/php/symfony/log/sfLogger.class.php', +'sfLogManager' => '/usr/share/php/symfony/log/sfLogManager.class.php', +'sfFileLogger' => '/usr/share/php/symfony/log/sfLogger/sfFileLogger.class.php', +'sfWebDebugLogger' => '/usr/share/php/symfony/log/sfLogger/sfWebDebugLogger.class.php', +'sfMySQLDatabase' => '/usr/share/php/symfony/database/sfMySQLDatabase.class.php', +'sfPostgreSQLDatabase' => '/usr/share/php/symfony/database/sfPostgreSQLDatabase.class.php', +'sfDatabase' => '/usr/share/php/symfony/database/sfDatabase.class.php', +'sfDatabaseManager' => '/usr/share/php/symfony/database/sfDatabaseManager.class.php', +'sfPDODatabase' => '/usr/share/php/symfony/database/sfPDODatabase.class.php', +'sfPHPView' => '/usr/share/php/symfony/view/sfPHPView.class.php', +'sfMailView' => '/usr/share/php/symfony/view/sfMailView.class.php', +'sfViewCacheManager' => '/usr/share/php/symfony/view/sfViewCacheManager.class.php', +'sfOutputEscaperIteratorDecorator' => '/usr/share/php/symfony/view/escaper/sfOutputEscaperIteratorDecorator.class.php', +'sfOutputEscaper' => '/usr/share/php/symfony/view/escaper/sfOutputEscaper.class.php', +'sfOutputEscaperGetterDecorator' => '/usr/share/php/symfony/view/escaper/sfOutputEscaperGetterDecorator.class.php', +'Countable' => '/usr/share/php/symfony/view/escaper/sfOutputEscaperArrayDecorator.class.php', +'sfOutputEscaperArrayDecorator' => '/usr/share/php/symfony/view/escaper/sfOutputEscaperArrayDecorator.class.php', +'sfOutputEscaperObjectDecorator' => '/usr/share/php/symfony/view/escaper/sfOutputEscaperObjectDecorator.class.php', +'sfPartialView' => '/usr/share/php/symfony/view/sfPartialView.class.php', +'sfView' => '/usr/share/php/symfony/view/sfView.class.php', +'sfIMessageSource' => '/usr/share/php/symfony/i18n/sfIMessageSource.class.php', +'TGettext_PO' => '/usr/share/php/symfony/i18n/Gettext/PO.php', +'TGettext' => '/usr/share/php/symfony/i18n/Gettext/TGettext.class.php', +'TGettext_MO' => '/usr/share/php/symfony/i18n/Gettext/MO.php', +'sfDateFormat' => '/usr/share/php/symfony/i18n/sfDateFormat.class.php', +'sfDateTimeFormatInfo' => '/usr/share/php/symfony/i18n/sfDateTimeFormatInfo.class.php', +'sfNumberFormatInfo' => '/usr/share/php/symfony/i18n/sfNumberFormatInfo.class.php', +'sfCultureInfo' => '/usr/share/php/symfony/i18n/sfCultureInfo.class.php', +'sfMessageSource_MySQL' => '/usr/share/php/symfony/i18n/sfMessageSource_MySQL.class.php', +'sfMessageSource_SQLite' => '/usr/share/php/symfony/i18n/sfMessageSource_SQLite.class.php', +'sfMessageSource_XLIFF' => '/usr/share/php/symfony/i18n/sfMessageSource_XLIFF.class.php', +'sfMessageSource_gettext' => '/usr/share/php/symfony/i18n/sfMessageSource_gettext.class.php', +'sfMessageSource' => '/usr/share/php/symfony/i18n/sfMessageSource.class.php', +'sfI18N' => '/usr/share/php/symfony/i18n/sfI18N.class.php', +'sfMessageFormat' => '/usr/share/php/symfony/i18n/sfMessageFormat.class.php', +'sfChoiceFormat' => '/usr/share/php/symfony/i18n/sfChoiceFormat.class.php', +'sfNumberFormat' => '/usr/share/php/symfony/i18n/sfNumberFormat.class.php', +'sfMessageCache' => '/usr/share/php/symfony/i18n/sfMessageCache.class.php', +'sfExecutionFilter' => '/usr/share/php/symfony/filter/sfExecutionFilter.class.php', +'sfRenderingFilter' => '/usr/share/php/symfony/filter/sfRenderingFilter.class.php', +'sfFilter' => '/usr/share/php/symfony/filter/sfFilter.class.php', +'sfWebDebugFilter' => '/usr/share/php/symfony/filter/sfWebDebugFilter.class.php', +'sfCommonFilter' => '/usr/share/php/symfony/filter/sfCommonFilter.class.php', +'sfFlashFilter' => '/usr/share/php/symfony/filter/sfFlashFilter.class.php', +'sfSecurityFilter' => '/usr/share/php/symfony/filter/sfSecurityFilter.class.php', +'sfFilterChain' => '/usr/share/php/symfony/filter/sfFilterChain.class.php', +'sfFillInFormFilter' => '/usr/share/php/symfony/filter/sfFillInFormFilter.class.php', +'sfBasicSecurityFilter' => '/usr/share/php/symfony/filter/sfBasicSecurityFilter.class.php', +'sfCacheFilter' => '/usr/share/php/symfony/filter/sfCacheFilter.class.php', +'sfFileCache' => '/usr/share/php/symfony/cache/sfFileCache.class.php', +'sfSQLiteCache' => '/usr/share/php/symfony/cache/sfSQLiteCache.class.php', +'sfFunctionCache' => '/usr/share/php/symfony/cache/sfFunctionCache.class.php', +'sfProcessCache' => '/usr/share/php/symfony/cache/sfProcessCache.class.php', +'sfCache' => '/usr/share/php/symfony/cache/sfCache.class.php', +'sfTestBrowser' => '/usr/share/php/symfony/test/sfTestBrowser.class.php', +'sfTimer' => '/usr/share/php/symfony/debug/sfTimer.class.php', +'sfDebug' => '/usr/share/php/symfony/debug/sfDebug.class.php', +'sfTimerManager' => '/usr/share/php/symfony/debug/sfTimerManager.class.php', +'sfWebDebug' => '/usr/share/php/symfony/debug/sfWebDebug.class.php', +'sfCallbackValidator' => '/usr/share/php/symfony/validator/sfCallbackValidator.class.php', +'sfEmailValidator' => '/usr/share/php/symfony/validator/sfEmailValidator.class.php', +'sfFileValidator' => '/usr/share/php/symfony/validator/sfFileValidator.class.php', +'sfStringValidator' => '/usr/share/php/symfony/validator/sfStringValidator.class.php', +'sfRegexValidator' => '/usr/share/php/symfony/validator/sfRegexValidator.class.php', +'sfHtmlValidator' => '/usr/share/php/symfony/validator/sfHtmlValidator.class.php', +'sfDateValidator' => '/usr/share/php/symfony/validator/sfDateValidator.class.php', +'sfValidatorManager' => '/usr/share/php/symfony/validator/sfValidatorManager.class.php', +'sfNumberValidator' => '/usr/share/php/symfony/validator/sfNumberValidator.class.php', +'sfUrlValidator' => '/usr/share/php/symfony/validator/sfUrlValidator.class.php', +'sfCompareValidator' => '/usr/share/php/symfony/validator/sfCompareValidator.class.php', +'sfValidator' => '/usr/share/php/symfony/validator/sfValidator.class.php', +'sfConsoleController' => '/usr/share/php/symfony/controller/sfConsoleController.class.php', +'sfFrontWebController' => '/usr/share/php/symfony/controller/sfFrontWebController.class.php', +'sfController' => '/usr/share/php/symfony/controller/sfController.class.php', +'sfWebController' => '/usr/share/php/symfony/controller/sfWebController.class.php', +'sfRouting' => '/usr/share/php/symfony/controller/sfRouting.class.php', +'sfSessionStorage' => '/usr/share/php/symfony/storage/sfSessionStorage.class.php', +'sfStorage' => '/usr/share/php/symfony/storage/sfStorage.class.php', +'sfSessionTestStorage' => '/usr/share/php/symfony/storage/sfSessionTestStorage.class.php', +'sfPDOSessionStorage' => '/usr/share/php/symfony/storage/sfPDOSessionStorage.class.php', +'sfPostgreSQLSessionStorage' => '/usr/share/php/symfony/storage/sfPostgreSQLSessionStorage.class.php', +'sfMySQLSessionStorage' => '/usr/share/php/symfony/storage/sfMySQLSessionStorage.class.php', +'sfStorageException' => '/usr/share/php/symfony/exception/sfStorageException.class.php', +'sfFilterException' => '/usr/share/php/symfony/exception/sfFilterException.class.php', +'sfStopException' => '/usr/share/php/symfony/exception/sfStopException.class.php', +'sfDatabaseException' => '/usr/share/php/symfony/exception/sfDatabaseException.class.php', +'sfFactoryException' => '/usr/share/php/symfony/exception/sfFactoryException.class.php', +'sfError404Exception' => '/usr/share/php/symfony/exception/sfError404Exception.class.php', +'sfConfigurationException' => '/usr/share/php/symfony/exception/sfConfigurationException.class.php', +'sfContextException' => '/usr/share/php/symfony/exception/sfContextException.class.php', +'sfFileException' => '/usr/share/php/symfony/exception/sfFileException.class.php', +'sfCacheException' => '/usr/share/php/symfony/exception/sfCacheException.class.php', +'sfControllerException' => '/usr/share/php/symfony/exception/sfControllerException.class.php', +'sfActionException' => '/usr/share/php/symfony/exception/sfActionException.class.php', +'sfForwardException' => '/usr/share/php/symfony/exception/sfForwardException.class.php', +'sfViewException' => '/usr/share/php/symfony/exception/sfViewException.class.php', +'sfRenderException' => '/usr/share/php/symfony/exception/sfRenderException.class.php', +'sfParseException' => '/usr/share/php/symfony/exception/sfParseException.class.php', +'sfValidatorException' => '/usr/share/php/symfony/exception/sfValidatorException.class.php', +'sfSecurityException' => '/usr/share/php/symfony/exception/sfSecurityException.class.php', +'sfInitializationException' => '/usr/share/php/symfony/exception/sfInitializationException.class.php', +'sfAutoloadException' => '/usr/share/php/symfony/exception/sfAutoloadException.class.php', +'sfException' => '/usr/share/php/symfony/exception/sfException.class.php', +'sfUser' => '/usr/share/php/symfony/user/sfUser.class.php', +'sfBasicSecurityUser' => '/usr/share/php/symfony/user/sfBasicSecurityUser.class.php', +'sfSecurityUser' => '/usr/share/php/symfony/user/sfSecurityUser.class.php', +'sfRichTextEditorTinyMCE' => '/usr/share/php/symfony/helper/sfRichTextEditorTinyMCE.class.php', +'sfRichTextEditorFCK' => '/usr/share/php/symfony/helper/sfRichTextEditorFCK.class.php', +'sfRichTextEditor' => '/usr/share/php/symfony/helper/sfRichTextEditor.class.php', +'sfMail' => '/usr/share/php/symfony/addon/sfMail.class.php', +'sfZendFrameworkBridge' => '/usr/share/php/symfony/addon/bridge/sfZendFrameworkBridge.class.php', +'sfEzComponentsBridge' => '/usr/share/php/symfony/addon/bridge/sfEzComponentsBridge.class.php', +'sfCreoleDatabase' => '/usr/share/php/symfony/addon/creole/database/sfCreoleDatabase.class.php', +'sfMessageSource_Creole' => '/usr/share/php/symfony/addon/creole/i18n/sfMessageSource_Creole.class.php', +'sfCreoleSessionStorage' => '/usr/share/php/symfony/addon/creole/storage/sfCreoleSessionStorage.class.php', +'sfDebugConnection' => '/usr/share/php/symfony/addon/creole/drivers/sfDebugConnection.php', +'sfPropelPager' => '/usr/share/php/symfony/addon/propel/sfPropelPager.class.php', +'sfPropelDatabase' => '/usr/share/php/symfony/addon/propel/database/sfPropelDatabase.class.php', +'sfPropelDataRetriever' => '/usr/share/php/symfony/addon/propel/database/sfPropelDataRetriever.class.php', +'sfPropelManyToMany' => '/usr/share/php/symfony/addon/propel/sfPropelManyToMany.class.php', +'sfPropelData' => '/usr/share/php/symfony/addon/propel/sfPropelData.class.php', +'sfPropelUniqueValidator' => '/usr/share/php/symfony/addon/propel/validator/sfPropelUniqueValidator.class.php', +'sfPropelAdminGenerator' => '/usr/share/php/symfony/addon/propel/generator/sfPropelAdminGenerator.class.php', +'sfPropelCrudGenerator' => '/usr/share/php/symfony/addon/propel/generator/sfPropelCrudGenerator.class.php', +'sfPropelBehavior' => '/usr/share/php/symfony/addon/propel/sfPropelBehavior.class.php', +'sfPropelDatabaseSchema' => '/usr/share/php/symfony/addon/propel/sfPropelDatabaseSchema.class.php', +'SfMapBuilderBuilder' => '/usr/share/php/symfony/addon/propel/builder/SfMapBuilderBuilder.php', +'SfMultiExtendObjectBuilder' => '/usr/share/php/symfony/addon/propel/builder/SfMultiExtendObjectBuilder.php', +'SfExtensionPeerBuilder' => '/usr/share/php/symfony/addon/propel/builder/SfExtensionPeerBuilder.php', +'SfObjectBuilder' => '/usr/share/php/symfony/addon/propel/builder/SfObjectBuilder.php', +'SfExtensionObjectBuilder' => '/usr/share/php/symfony/addon/propel/builder/SfExtensionObjectBuilder.php', +'SfPeerBuilder' => '/usr/share/php/symfony/addon/propel/builder/SfPeerBuilder.php', +'sfPager' => '/usr/share/php/symfony/addon/sfPager.class.php', +'sfData' => '/usr/share/php/symfony/addon/sfData.class.php', +'sfConfigCache' => '/usr/share/php/symfony/config/sfConfigCache.class.php', +'sfFilterConfigHandler' => '/usr/share/php/symfony/config/sfFilterConfigHandler.class.php', +'sfYamlConfigHandler' => '/usr/share/php/symfony/config/sfYamlConfigHandler.class.php', +'sfDefineEnvironmentConfigHandler' => '/usr/share/php/symfony/config/sfDefineEnvironmentConfigHandler.class.php', +'sfValidatorConfigHandler' => '/usr/share/php/symfony/config/sfValidatorConfigHandler.class.php', +'sfFactoryConfigHandler' => '/usr/share/php/symfony/config/sfFactoryConfigHandler.class.php', +'sfConfigHandler' => '/usr/share/php/symfony/config/sfConfigHandler.class.php', +'sfDatabaseConfigHandler' => '/usr/share/php/symfony/config/sfDatabaseConfigHandler.class.php', +'sfConfig' => '/usr/share/php/symfony/config/sfConfig.class.php', +'sfRootConfigHandler' => '/usr/share/php/symfony/config/sfRootConfigHandler.class.php', +'sfRoutingConfigHandler' => '/usr/share/php/symfony/config/sfRoutingConfigHandler.class.php', +'sfPhpConfigHandler' => '/usr/share/php/symfony/config/sfPhpConfigHandler.class.php', +'sfLoader' => '/usr/share/php/symfony/config/sfLoader.class.php', +'sfViewConfigHandler' => '/usr/share/php/symfony/config/sfViewConfigHandler.class.php', +'sfSimpleYamlConfigHandler' => '/usr/share/php/symfony/config/sfSimpleYamlConfigHandler.class.php', +'sfAutoloadConfigHandler' => '/usr/share/php/symfony/config/sfAutoloadConfigHandler.class.php', +'sfLoggingConfigHandler' => '/usr/share/php/symfony/config/sfLoggingConfigHandler.class.php', +'sfGeneratorConfigHandler' => '/usr/share/php/symfony/config/sfGeneratorConfigHandler.class.php', +'sfCacheConfigHandler' => '/usr/share/php/symfony/config/sfCacheConfigHandler.class.php', +'sfCompileConfigHandler' => '/usr/share/php/symfony/config/sfCompileConfigHandler.class.php', +'sfSecurityConfigHandler' => '/usr/share/php/symfony/config/sfSecurityConfigHandler.class.php', +'sfFinder' => '/usr/share/php/symfony/util/sfFinder.class.php', +'sfGlobToRegex' => '/usr/share/php/symfony/util/sfFinder.class.php', +'sfNumberCompare' => '/usr/share/php/symfony/util/sfFinder.class.php', +'YAMLNode' => '/usr/share/php/symfony/util/Spyc.class.php', +'Spyc' => '/usr/share/php/symfony/util/Spyc.class.php', +'sfParameterHolder' => '/usr/share/php/symfony/util/sfParameterHolder.class.php', +'sfInflector' => '/usr/share/php/symfony/util/sfInflector.class.php', +'sfFillInForm' => '/usr/share/php/symfony/util/sfFillInForm.class.php', +'sfCore' => '/usr/share/php/symfony/util/sfCore.class.php', +'sfBrowser' => '/usr/share/php/symfony/util/sfBrowser.class.php', +'sfFakeRenderingFilter' => '/usr/share/php/symfony/util/sfBrowser.class.php', +'sfContext' => '/usr/share/php/symfony/util/sfContext.class.php', +'sfToolkit' => '/usr/share/php/symfony/util/sfToolkit.class.php', +'sfDomCssSelector' => '/usr/share/php/symfony/util/sfDomCssSelector.class.php', +'sfYaml' => '/usr/share/php/symfony/util/sfYaml.class.php', +'sfMixer' => '/usr/share/php/symfony/util/sfMixer.class.php', +'sfConsoleResponse' => '/usr/share/php/symfony/response/sfConsoleResponse.class.php', +'sfWebResponse' => '/usr/share/php/symfony/response/sfWebResponse.class.php', +'sfResponse' => '/usr/share/php/symfony/response/sfResponse.class.php', +'sfAdminGenerator' => '/usr/share/php/symfony/generator/sfAdminGenerator.class.php', +'sfAdminColumn' => '/usr/share/php/symfony/generator/sfAdminGenerator.class.php', +'sfGenerator' => '/usr/share/php/symfony/generator/sfGenerator.class.php', +'sfGeneratorManager' => '/usr/share/php/symfony/generator/sfGeneratorManager.class.php', +'sfCrudGenerator' => '/usr/share/php/symfony/generator/sfCrudGenerator.class.php', +'sfActions' => '/usr/share/php/symfony/action/sfActions.class.php', +'sfActionStack' => '/usr/share/php/symfony/action/sfActionStack.class.php', +'sfAction' => '/usr/share/php/symfony/action/sfAction.class.php', +'sfComponents' => '/usr/share/php/symfony/action/sfComponents.class.php', +'sfComponent' => '/usr/share/php/symfony/action/sfComponent.class.php', +'sfActionStackEntry' => '/usr/share/php/symfony/action/sfActionStackEntry.class.php', + +// propel +'ValidatorMap' => '/usr/share/php/symfony/vendor/propel/map/ValidatorMap.php', +'DatabaseMap' => '/usr/share/php/symfony/vendor/propel/map/DatabaseMap.php', +'TableMap' => '/usr/share/php/symfony/vendor/propel/map/TableMap.php', +'MapBuilder' => '/usr/share/php/symfony/vendor/propel/map/MapBuilder.php', +'ColumnMap' => '/usr/share/php/symfony/vendor/propel/map/ColumnMap.php', +'PreOrderNodeIterator' => '/usr/share/php/symfony/vendor/propel/om/PreOrderNodeIterator.php', +'Persistent' => '/usr/share/php/symfony/vendor/propel/om/Persistent.php', +'BaseObject' => '/usr/share/php/symfony/vendor/propel/om/BaseObject.php', +'DBNone' => '/usr/share/php/symfony/vendor/propel/adapter/DBNone.php', +'DBSQLite' => '/usr/share/php/symfony/vendor/propel/adapter/DBSQLite.php', +'DBMySQL' => '/usr/share/php/symfony/vendor/propel/adapter/DBMySQL.php', +'DBAdapter' => '/usr/share/php/symfony/vendor/propel/adapter/DBAdapter.php', +'DBOracle' => '/usr/share/php/symfony/vendor/propel/adapter/DBOracle.php', +'DBMSSQL' => '/usr/share/php/symfony/vendor/propel/adapter/DBMSSQL.php', +'DBMySQLi' => '/usr/share/php/symfony/vendor/propel/adapter/DBMySQLi.php', +'DBSybase' => '/usr/share/php/symfony/vendor/propel/adapter/DBSybase.php', +'DBPostgres' => '/usr/share/php/symfony/vendor/propel/adapter/DBPostgres.php', +'BasicLogger' => '/usr/share/php/symfony/vendor/propel/logger/BasicLogger.php', +'MojaviLogAdapter' => '/usr/share/php/symfony/vendor/propel/logger/MojaviLogAdapter.php', +'PropelException' => '/usr/share/php/symfony/vendor/propel/PropelException.php', +'RequiredValidator' => '/usr/share/php/symfony/vendor/propel/validator/RequiredValidator.php', +'MatchValidator' => '/usr/share/php/symfony/vendor/propel/validator/MatchValidator.php', +'UniqueValidator' => '/usr/share/php/symfony/vendor/propel/validator/UniqueValidator.php', +'ValidValuesValidator' => '/usr/share/php/symfony/vendor/propel/validator/ValidValuesValidator.php', +'MinValueValidator' => '/usr/share/php/symfony/vendor/propel/validator/MinValueValidator.php', +'BasicValidator' => '/usr/share/php/symfony/vendor/propel/validator/BasicValidator.php', +'MaxLengthValidator' => '/usr/share/php/symfony/vendor/propel/validator/MaxLengthValidator.php', +'NotMatchValidator' => '/usr/share/php/symfony/vendor/propel/validator/NotMatchValidator.php', +'MaxValueValidator' => '/usr/share/php/symfony/vendor/propel/validator/MaxValueValidator.php', +'MinLengthValidator' => '/usr/share/php/symfony/vendor/propel/validator/MinLengthValidator.php', +'ValidationFailed' => '/usr/share/php/symfony/vendor/propel/validator/ValidationFailed.php', +'Transaction' => '/usr/share/php/symfony/vendor/propel/util/Transaction.php', +'Criteria' => '/usr/share/php/symfony/vendor/propel/util/Criteria.php', +'CriterionIterator' => '/usr/share/php/symfony/vendor/propel/util/Criteria.php', +'Criterion' => '/usr/share/php/symfony/vendor/propel/util/Criteria.php', +'Join' => '/usr/share/php/symfony/vendor/propel/util/Criteria.php', +'PeerInfo' => '/usr/share/php/symfony/vendor/propel/util/PeerInfo.php', +'BasePeer' => '/usr/share/php/symfony/vendor/propel/util/BasePeer.php', +'PropelPager' => '/usr/share/php/symfony/vendor/propel/util/PropelPager.php', +'Propel' => '/usr/share/php/symfony/vendor/propel/Propel.php', + +// creole +'SQLException' => '/usr/share/php/symfony/vendor/creole/SQLException.php', +'StatementCommon' => '/usr/share/php/symfony/vendor/creole/common/StatementCommon.php', +'PreparedStatementCommon' => '/usr/share/php/symfony/vendor/creole/common/PreparedStatementCommon.php', +'ConnectionCommon' => '/usr/share/php/symfony/vendor/creole/common/ConnectionCommon.php', +'ResultSetCommon' => '/usr/share/php/symfony/vendor/creole/common/ResultSetCommon.php', +'ForeignKeyInfo' => '/usr/share/php/symfony/vendor/creole/metadata/ForeignKeyInfo.php', +'IndexInfo' => '/usr/share/php/symfony/vendor/creole/metadata/IndexInfo.php', +'TableInfo' => '/usr/share/php/symfony/vendor/creole/metadata/TableInfo.php', +'ColumnInfo' => '/usr/share/php/symfony/vendor/creole/metadata/ColumnInfo.php', +'DatabaseInfo' => '/usr/share/php/symfony/vendor/creole/metadata/DatabaseInfo.php', +'PrimaryKeyInfo' => '/usr/share/php/symfony/vendor/creole/metadata/PrimaryKeyInfo.php', +'Statement' => '/usr/share/php/symfony/vendor/creole/Statement.php', +'PreparedStatement' => '/usr/share/php/symfony/vendor/creole/PreparedStatement.php', +'Creole' => '/usr/share/php/symfony/vendor/creole/Creole.php', +'Connection' => '/usr/share/php/symfony/vendor/creole/Connection.php', +'CreoleTypes' => '/usr/share/php/symfony/vendor/creole/CreoleTypes.php', +'IdGenerator' => '/usr/share/php/symfony/vendor/creole/IdGenerator.php', +'ResultSetIterator' => '/usr/share/php/symfony/vendor/creole/ResultSetIterator.php', +'CallableStatement' => '/usr/share/php/symfony/vendor/creole/CallableStatement.php', +'DebugConnection' => '/usr/share/php/symfony/vendor/creole/contrib/DebugConnection.php', +'Blob' => '/usr/share/php/symfony/vendor/creole/util/Blob.php', +'Lob' => '/usr/share/php/symfony/vendor/creole/util/Lob.php', +'Clob' => '/usr/share/php/symfony/vendor/creole/util/Clob.php', +'SQLStatementExtractor' => '/usr/share/php/symfony/vendor/creole/util/sql/SQLStatementExtractor.php', +'SQLiteTableInfo' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/metadata/SQLiteTableInfo.php', +'SQLiteDatabaseInfo' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/metadata/SQLiteDatabaseInfo.php', +'SQLiteStatement' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/SQLiteStatement.php', +'SQLiteResultSetIterator' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/SQLiteResultSetIterator.php', +'SQLiteIdGenerator' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/SQLiteIdGenerator.php', +'SQLiteResultSet' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/SQLiteResultSet.php', +'SQLitePreparedStatement' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/SQLitePreparedStatement.php', +'SQLiteTypes' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/SQLiteTypes.php', +'SQLiteConnection' => '/usr/share/php/symfony/vendor/creole/drivers/sqlite/SQLiteConnection.php', +'MSSQLStatement' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/MSSQLStatement.php', +'MSSQLCallableStatement' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/MSSQLCallableStatement.php', +'MSSQLDatabaseInfo' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/metadata/MSSQLDatabaseInfo.php', +'MSSQLTableInfo' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/metadata/MSSQLTableInfo.php', +'MSSQLResultSet' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/MSSQLResultSet.php', +'MSSQLTypes' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/MSSQLTypes.php', +'MSSQLPreparedStatement' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/MSSQLPreparedStatement.php', +'MSSQLConnection' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/MSSQLConnection.php', +'MSSQLIdGenerator' => '/usr/share/php/symfony/vendor/creole/drivers/mssql/MSSQLIdGenerator.php', +'PgSQLDatabaseInfo' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/metadata/PgSQLDatabaseInfo.php', +'PgSQLTableInfo' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/metadata/PgSQLTableInfo.php', +'PgSQLTypes' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/PgSQLTypes.php', +'PgSQLStatement' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/PgSQLStatement.php', +'PgSQLResultSetIterator' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/PgSQLResultSetIterator.php', +'PgSQLConnection' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/PgSQLConnection.php', +'PgSQLResultSet' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/PgSQLResultSet.php', +'PgSQLPreparedStatement' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/PgSQLPreparedStatement.php', +'PgSQLIdGenerator' => '/usr/share/php/symfony/vendor/creole/drivers/pgsql/PgSQLIdGenerator.php', +'ODBCDatabaseInfo' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/metadata/ODBCDatabaseInfo.php', +'ODBCTableInfo' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/metadata/ODBCTableInfo.php', +'ODBCCachedResultSet' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCCachedResultSet.php', +'ODBCResultSet' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCResultSet.php', +'ODBCResultSetCommon' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCResultSetCommon.php', +'ODBCIdGenerator' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCIdGenerator.php', +'ODBCAdapter' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/adapters/ODBCAdapter.php', +'CodeBaseAdapter' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/adapters/CodeBaseAdapter.php', +'MySQLAdapter' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/adapters/MySQLAdapter.php', +'ODBCPreparedStatement' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCPreparedStatement.php', +'ODBCTypes' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCTypes.php', +'ODBCStatement' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCStatement.php', +'ODBCConnection' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCConnection.php', +'ODBCResultResource' => '/usr/share/php/symfony/vendor/creole/drivers/odbc/ODBCConnection.php', +'OCI8Types' => '/usr/share/php/symfony/vendor/creole/drivers/oracle/OCI8Types.php', +'OCI8TableInfo' => '/usr/share/php/symfony/vendor/creole/drivers/oracle/metadata/OCI8TableInfo.php', +'OCI8DatabaseInfo' => '/usr/share/php/symfony/vendor/creole/drivers/oracle/metadata/OCI8DatabaseInfo.php', +'OCI8PreparedStatement' => '/usr/share/php/symfony/vendor/creole/drivers/oracle/OCI8PreparedStatement.php', +'OCI8Connection' => '/usr/share/php/symfony/vendor/creole/drivers/oracle/OCI8Connection.php', +'OCI8Statement' => '/usr/share/php/symfony/vendor/creole/drivers/oracle/OCI8Statement.php', +'OCI8IdGenerator' => '/usr/share/php/symfony/vendor/creole/drivers/oracle/OCI8IdGenerator.php', +'OCI8ResultSet' => '/usr/share/php/symfony/vendor/creole/drivers/oracle/OCI8ResultSet.php', +'MySQLiDatabaseInfo' => '/usr/share/php/symfony/vendor/creole/drivers/mysqli/metadata/MySQLiDatabaseInfo.php', +'MySQLiTableInfo' => '/usr/share/php/symfony/vendor/creole/drivers/mysqli/metadata/MySQLiTableInfo.php', +'MySQLiIdGenerator' => '/usr/share/php/symfony/vendor/creole/drivers/mysqli/MySQLiIdGenerator.php', +'MySQLiConnection' => '/usr/share/php/symfony/vendor/creole/drivers/mysqli/MySQLiConnection.php', +'MySQLiPreparedStatement' => '/usr/share/php/symfony/vendor/creole/drivers/mysqli/MySQLiPreparedStatement.php', +'MySQLiStatement' => '/usr/share/php/symfony/vendor/creole/drivers/mysqli/MySQLiStatement.php', +'MySQLiResultSet' => '/usr/share/php/symfony/vendor/creole/drivers/mysqli/MySQLiResultSet.php', +'MySQLTableInfo' => '/usr/share/php/symfony/vendor/creole/drivers/mysql/metadata/MySQLTableInfo.php', +'MySQLDatabaseInfo' => '/usr/share/php/symfony/vendor/creole/drivers/mysql/metadata/MySQLDatabaseInfo.php', +'MySQLIdGenerator' => '/usr/share/php/symfony/vendor/creole/drivers/mysql/MySQLIdGenerator.php', +'MySQLResultSet' => '/usr/share/php/symfony/vendor/creole/drivers/mysql/MySQLResultSet.php', +'MySQLConnection' => '/usr/share/php/symfony/vendor/creole/drivers/mysql/MySQLConnection.php', +'MySQLPreparedStatement' => '/usr/share/php/symfony/vendor/creole/drivers/mysql/MySQLPreparedStatement.php', +'MySQLTypes' => '/usr/share/php/symfony/vendor/creole/drivers/mysql/MySQLTypes.php', +'MySQLStatement' => '/usr/share/php/symfony/vendor/creole/drivers/mysql/MySQLStatement.php', +'ResultSet' => '/usr/share/php/symfony/vendor/creole/ResultSet.php', + +// propel addon +'Propel' => '/usr/share/php/symfony/addon/propel/sfPropelAutoload.php', + +// plugins lib +'sfJpGraph' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/sfJpGraph.class.php', +'GanttActivityInfo' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'GanttGraph' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'PredefIcons' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'IconImage' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'TextProperty' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'HeaderProperty' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'GanttScale' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'GanttConstraint' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'GanttPlotObject' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'Progress' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'HorizontalGridLine' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'GanttBar' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'MileStone' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'TextPropertyBelow' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'GanttVLine' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'LinkArrow' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'GanttLink' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php', +'FieldArrow' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_scatter.php', +'FieldPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_scatter.php', +'ScatterPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_scatter.php', +'MGraph' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_mgraph.php', +'HandDigits' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam-digits.php', +'AntiSpam' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam-digits.php', +'PiePlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie.php', +'PiePlotC' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie.php', +'PieGraph' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie.php', +'CanvasScale' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvtools.php', +'Shape' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvtools.php', +'CanvasRectangleText' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvtools.php', +'FlagImages' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_flags.php', +'CanvasGraph' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvas.php', +'LogScale' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_log.php', +'LogTicks' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_log.php', +'ErrorPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_error.php', +'ErrorLinePlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_error.php', +'LineErrorPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_error.php', +'RadarLogTicks' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php', +'RadarLinearTicks' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php', +'RadarAxis' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php', +'RadarGrid' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php', +'RadarPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php', +'RadarGraph' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php', +'Gradient' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gradient.php', +'ErrMsgText' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_errhandler.inc.php', +'JpGraphError' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_errhandler.inc.php', +'JpGraphErrObject' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_errhandler.inc.php', +'JpGraphErrObjectImg' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_errhandler.inc.php', +'HandDigits' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam.php', +'AntiSpam' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam.php', +'PlotMark' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotmark.inc.php', +'ImgData' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotmark.inc.php', +'FlagCache' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotmark.inc.php', +'PiePlot3D' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie3d.php', +'PolarPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php', +'PolarAxis' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php', +'PolarScale' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php', +'PolarLogScale' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php', +'PolarGraph' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php', +'DateScale' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_date.php', +'LanguageConv' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_ttf.inc.php', +'TTF' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_ttf.inc.php', +'Rectangle' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPattern' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPatternSolid' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPatternHor' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPatternVert' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPatternRDiag' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPatternLDiag' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPattern3DPlane' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPatternCross' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPatternDiagCross' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'RectPatternFactory' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'PlotBand' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php', +'ImgTrans' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_imgtrans.php', +'IconPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_iconplot.php', +'JpgTimer' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'DateLocale' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Footer' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Graph' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'LineProperty' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Text' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'GraphTabTitle' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'SuperScriptText' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Grid' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'AxisPrototype' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Axis' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Ticks' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'LinearTicks' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'LinearScale' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'RGB' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Image' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'RotImage' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'ImgStreamCache' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Legend' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'DisplayValue' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'Plot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'PlotLine' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php', +'BarPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_bar.php', +'GroupBarPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_bar.php', +'AccBarPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_bar.php', +'StockPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_stock.php', +'BoxPlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_stock.php', +'Spline' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_regstat.php', +'Bezier' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_regstat.php', +'LinePlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_line.php', +'AccLinePlot' => '/home/benjamin/reaktor/trunk/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_line.php', +'getid3_bonk' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.bonk.php', +'getid3_mpc' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.mpc.php', +'getid3_flv' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.flv.php', +'AMFStream' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.flv.php', +'AMFReader' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.flv.php', +'getid3_monkey' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.monkey.php', +'getid3_jpg' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.graphic.jpg.php', +'getid3_id3v2' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.tag.id3v2.php', +'getid3_iso' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.misc.iso.php', +'getid3_mod' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.mod.php', +'getid3_pcd' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.graphic.pcd.php', +'getid3_optimfrog' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.optimfrog.php', +'getid3_mpc_old' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.mpc_old.php', +'getid3_mp3' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.mp3.php', +'getid3_wavpack' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.wavpack.php', +'getid3_shorten' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.shorten.php', +'getid3_vqf' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.vqf.php', +'getid3_tiff' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.graphic.tiff.php', +'getid3_writetags' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/write.php', +'getid3_rkau' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.rkau.php', +'getid3_cached_mysql' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/extension.cache.mysql.php', +'getid3_png' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.graphic.png.php', +'getid3' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/getid3.php', +'getid3_handler' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/getid3.php', +'getid3_exception' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/getid3.php', +'getid3_lib' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/getid3.php', +'getid3_lib_replaygain' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/getid3.php', +'getid3_la' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.la.php', +'getid3_szip' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.archive.szip.php', +'getid3_asf' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.asf.php', +'getid3_cached_dbm' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/extension.cache.dbm.php', +'getid3_bmp' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.graphic.bmp.php', +'getid3_aac' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.aac.php', +'getid3_lyrics3' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.tag.lyrics3.php', +'getid3_quicktime' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.quicktime.php', +'getid3_zip' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.archive.zip.php', +'getid3_write_real' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/write.real.php', +'getid3_id3v1' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.tag.id3v1.php', +'getid3_au' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.au.php', +'getid3_gif' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.graphic.gif.php', +'getid3_rar' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.archive.rar.php', +'getid3_apetag' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.tag.apetag.php', +'getid3_ac3' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.ac3.php', +'getid3_voc' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.voc.php', +'getid3_midi' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.midi.php', +'getid3_flac' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.flac.php', +'getid3_write_id3v1' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/write.id3v1.php', +'getid3_ogg' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.ogg.php', +'getid3_write_apetag' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/write.apetag.php', +'getid3_real' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.real.php', +'getid3_mpeg' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.mpeg.php', +'getid3_write_vorbiscomment' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/write.vorbiscomment.php', +'getid3_lib' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/getid3.lib.php', +'getid3_riff' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.riff.php', +'getid3_lib_image_size' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.lib.image_size.php', +'getid3_svg' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.graphic.svg.php', +'getid3_write_lyrics3' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/write.lyrics3.php', +'getid3_tta' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.tta.php', +'getid3_avr' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.avr.php', +'getid3_xiph' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.xiph.php', +'getid3_jpeg' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.graphic.jpeg.php', +'getid3_aac_adif' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.aac_adif.php', +'getid3_iconv_replacement' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.lib.iconv_replacement.php', +'getid3_gzip' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.archive.gzip.php', +'getid3_exe' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.misc.exe.php', +'getid3_aac_adts' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.aac_adts.php', +'getid3_nsv' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.nsv.php', +'getid3_swf' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.swf.php', +'getid3_lpac' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio.lpac.php', +'getid3_bink' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.bink.php', +'getid3_matroska' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.audio-video.matroska.php', +'getid3_write_metaflac' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/write.metaflac.php', +'getid3_write_id3v2' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/write.id3v2.php', +'getid3_lib_data_hash' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.lib.data_hash.php', +'getid3_tar' => '/home/benjamin/reaktor/trunk/plugins/getId3Plugin/lib/module.archive.tar.php', +'sfFeed' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfFeed.class.php', +'sfFeedLicense' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfFeedLicense.class.php', +'sfFeedItem' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfFeedItem.class.php', +'sfRss10Feed' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfRss10Feed.class.php', +'sfRss201Feed' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfRss201Feed.class.php', +'sfRss091Feed' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfRss091Feed.class.php', +'sfRssFeed' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfRssFeed.class.php', +'sfFeedPeer' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfFeedPeer.class.php', +'sfFeedEnclosure' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfFeedEnclosure.class.php', +'sfAtom1Feed' => '/home/benjamin/reaktor/trunk/plugins/sfFeed2Plugin/lib/sfAtom1Feed.class.php', +'sfGoogleAnalyticsFilter' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/filter/sfGoogleAnalyticsFilter.class.php', +'sfGoogleAnalyticsTrackerGoogle' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerGoogle.class.php', +'sfGoogleAnalyticsTracker' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTracker.class.php', +'sfGoogleAnalyticsTrackerUrchin' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerUrchin.class.php', +'sfGoogleAnalyticsItem' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsItem.class.php', +'sfGoogleAnalyticsTransaction' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsTransaction.class.php', +'sfGoogleAnalyticsToolkit' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/util/sfGoogleAnalyticsToolkit.class.php', +'sfGoogleAnalyticsListener' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/listener/sfGoogleAnalyticsListener.class.php', +'sfGoogleAnalyticsMixin' => '/home/benjamin/reaktor/trunk/plugins/sfGoogleAnalyticsPlugin/lib/mixin/sfGoogleAnalyticsMixin.class.php', +'sfGuardGroupMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/map/sfGuardGroupMapBuilder.php', +'sfGuardGroupPermissionMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/map/sfGuardGroupPermissionMapBuilder.php', +'sfGuardRememberKeyMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/map/sfGuardRememberKeyMapBuilder.php', +'sfGuardUserGroupMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/map/sfGuardUserGroupMapBuilder.php', +'sfGuardPermissionI18nMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionI18nMapBuilder.php', +'sfGuardUserMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/map/sfGuardUserMapBuilder.php', +'sfGuardUserPermissionMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/map/sfGuardUserPermissionMapBuilder.php', +'sfGuardPermissionMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionMapBuilder.php', +'BasesfGuardGroupPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php', +'BasesfGuardRememberKeyPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKeyPeer.php', +'BasesfGuardGroupPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermission.php', +'BasesfGuardUserPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php', +'BasesfGuardPermissionI18nPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18nPeer.php', +'BasesfGuardPermissionI18n' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18n.php', +'BasesfGuardUserGroupPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php', +'BasesfGuardUserGroup' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroup.php', +'BasesfGuardUserPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermission.php', +'BasesfGuardPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionPeer.php', +'BasesfGuardGroupPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPeer.php', +'BasesfGuardRememberKey' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKey.php', +'BasesfGuardUser' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUser.php', +'BasesfGuardPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermission.php', +'BasesfGuardUserPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php', +'BasesfGuardGroupPermissionI18n' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionI18n.php', +'BasesfGuardGroup' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroup.php', +'BasesfGuardGroupPermissionI18nPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionI18nPeer.php', +'sfGuardUserGroupPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardUserGroupPeer.php', +'sfGuardRememberKey' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardRememberKey.php', +'sfGuardUser' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardUser.php', +'sfGuardPermissionI18nPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardPermissionI18nPeer.php', +'sfGuardGroupPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardGroupPeer.php', +'sfGuardUserGroup' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardUserGroup.php', +'sfGuardGroup' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardGroup.php', +'sfGuardPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardPermission.php', +'sfGuardGroupPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermission.php', +'PluginsfGuardPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermission.php', +'PluginsfGuardUserGroupPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroupPeer.php', +'PluginsfGuardRememberKey' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKey.php', +'PluginsfGuardUser' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUser.php', +'PluginsfGuardRememberKeyPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKeyPeer.php', +'PluginsfGuardGroup' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroup.php', +'PluginsfGuardUserPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermissionPeer.php', +'PluginsfGuardPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermissionPeer.php', +'PluginsfGuardUserPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPeer.php', +'PluginsfGuardUserGroup' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroup.php', +'PluginsfGuardGroupPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPeer.php', +'PluginsfGuardUserPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermission.php', +'PluginsfGuardGroupPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermissionPeer.php', +'PluginsfGuardGroupPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermission.php', +'sfGuardUserPermission' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardUserPermission.php', +'sfGuardGroupPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermissionPeer.php', +'sfGuardUserPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardUserPeer.php', +'sfGuardUserPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardUserPermissionPeer.php', +'sfGuardRememberKeyPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardRememberKeyPeer.php', +'sfGuardPermissionPeer' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardPermissionPeer.php', +'sfGuardPermissionI18n' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/model/sfGuardPermissionI18n.php', +'sfGuardUserValidator' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/validator/sfGuardUserValidator.class.php', +'sfGuardSecurityUser' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/user/sfGuardSecurityUser.class.php', +'sfGuardBasicSecurityFilter' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/lib/sfGuardBasicSecurityFilter.class.php', +'sfI18nExtractorInterface' => '/home/benjamin/reaktor/trunk/plugins/sfI18nExtractPlugin/lib/sfI18nExtractorInterface.class.php', +'sfI18nYamlGeneratorExtractor' => '/home/benjamin/reaktor/trunk/plugins/sfI18nExtractPlugin/lib/sfI18nYamlGeneratorExtractor.class.php', +'sfI18nPhpExtractor' => '/home/benjamin/reaktor/trunk/plugins/sfI18nExtractPlugin/lib/sfI18nPhpExtractor.class.php', +'sfI18nApplicationExtract' => '/home/benjamin/reaktor/trunk/plugins/sfI18nExtractPlugin/lib/sfI18nApplicationExtract.class.php', +'sfI18nExtract' => '/home/benjamin/reaktor/trunk/plugins/sfI18nExtractPlugin/lib/sfI18nExtract.class.php', +'sfI18nModuleExtract' => '/home/benjamin/reaktor/trunk/plugins/sfI18nExtractPlugin/lib/sfI18nModuleExtract.class.php', +'sfI18nYamlValidateExtractor' => '/home/benjamin/reaktor/trunk/plugins/sfI18nExtractPlugin/lib/sfI18nYamlValidateExtractor.class.php', +'sfI18nYamlExtractor' => '/home/benjamin/reaktor/trunk/plugins/sfI18nExtractPlugin/lib/sfI18nYamlExtractor.class.php', +'sfModelTest' => '/home/benjamin/reaktor/trunk/plugins/sfModelTestPlugin/lib/sfModelTest.php', +'sfPropelTest' => '/home/benjamin/reaktor/trunk/plugins/sfModelTestPlugin/lib/sfModelTest.php', +'sfDoctrineTest' => '/home/benjamin/reaktor/trunk/plugins/sfModelTestPlugin/lib/sfModelTest.php', +'sfPropel13Test' => '/home/benjamin/reaktor/trunk/plugins/sfModelTestPlugin/lib/sfModelTest.php', +'sfCommentMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/map/sfCommentMapBuilder.php', +'BasesfComment' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfComment.php', +'BasesfCommentPeer' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfCommentPeer.php', +'sfComment' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/sfComment.php', +'sfCommentPeer' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/sfCommentPeer.php', +'sfPropelActAsCommentableToolkit' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/sfPropelActAsCommentableToolkit.class.php', +'sfPropelActAsCommentableBehavior' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/sfPropelActAsCommentableBehavior.class.php', +'sfRatingMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/map/sfRatingMapBuilder.php', +'BasesfRating' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRating.php', +'BasesfRatingPeer' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRatingPeer.php', +'sfRating' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/sfRating.php', +'sfRatingPeer' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/sfRatingPeer.php', +'sfPropelActAsRatableBehavior' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableBehavior.class.php', +'sfPropelActAsRatableBehaviorToolkit' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableBehaviorToolkit.class.php', +'sfPropelActAsRatableException' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableException.class.php', +'sfPropelActAsTaggableBehavior' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableBehavior.class.php', +'TaggingMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TaggingMapBuilder.php', +'TagMapBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TagMapBuilder.php', +'BaseTag' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTag.php', +'BaseTaggingPeer' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php', +'BaseTagging' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagging.php', +'BaseTagPeer' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagPeer.php', +'TagPeer' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TagPeer.php', +'TaggingPeer' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TaggingPeer.php', +'Tag' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tag.php', +'Tagging' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tagging.php', +'sfPropelActAsTaggableToolkit' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableToolkit.class.php', +'SfAlternativeObjectBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfPropelAlternativeSchemaPlugin/lib/SfAlternativeObjectBuilder.php', +'SfAlternativePeerBuilder' => '/home/benjamin/reaktor/trunk/plugins/sfPropelAlternativeSchemaPlugin/lib/SfAlternativePeerBuilder.php', +'sfPropelDatabaseSchema' => '/home/benjamin/reaktor/trunk/plugins/sfPropelAlternativeSchemaPlugin/lib/sfPropelDatabaseSchema.class.php', +'ReCaptchaResponse' => '/home/benjamin/reaktor/trunk/plugins/sfReCaptchaPlugin/lib/recaptchalib.php', +'sfReCaptchaValidator' => '/home/benjamin/reaktor/trunk/plugins/sfReCaptchaPlugin/lib/sfReCaptchaValidator.class.php', +'sfImageMagickAdapter' => '/home/benjamin/reaktor/trunk/plugins/sfThumbnailPlugin/lib/sfImageMagickAdapter.class.php', +'sfGDAdapter' => '/home/benjamin/reaktor/trunk/plugins/sfThumbnailPlugin/lib/sfGDAdapter.class.php', +'sfThumbnail' => '/home/benjamin/reaktor/trunk/plugins/sfThumbnailPlugin/lib/sfThumbnail.class.php', +'sfFopenAdapter' => '/home/benjamin/reaktor/trunk/plugins/sfWebBrowserPlugin/lib/sfFopenAdapter.class.php', +'sfSocketsAdapter' => '/home/benjamin/reaktor/trunk/plugins/sfWebBrowserPlugin/lib/sfSocketsAdapter.class.php', +'sfWebBrowser' => '/home/benjamin/reaktor/trunk/plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php', +'sfCurlAdapter' => '/home/benjamin/reaktor/trunk/plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php', + +// plugins module lib +'sfGuardAuth/BasesfGuardAuthActions' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php', +'sfGuardUser/BasesfGuardUserActions' => '/home/benjamin/reaktor/trunk/plugins/sfGuardPlugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php', +'sfTransUnit/BasesfTransUnitActions' => '/home/benjamin/reaktor/trunk/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/lib/BasesfTransUnitActions.class.php', +'sfComment/BasesfCommentComponents' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentComponents.class.php', +'sfComment/BasesfCommentActions' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentActions.class.php', +'sfRating/BasesfRatingActions' => '/home/benjamin/reaktor/trunk/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/lib/BasesfRatingActions.class.php', + +// project + +// project model +'ReaktorArtworkMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ReaktorArtworkMapBuilder.php', +'SubreaktorI18nMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/SubreaktorI18nMapBuilder.php', +'ReaktorArtworkFileMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ReaktorArtworkFileMapBuilder.php', +'CatalogueMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/CatalogueMapBuilder.php', +'ArtworkStatusI18nMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArtworkStatusI18nMapBuilder.php', +'CategoryArtworkMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/CategoryArtworkMapBuilder.php', +'CategorySubreaktorMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/CategorySubreaktorMapBuilder.php', +'RejectionTypeI18nMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/RejectionTypeI18nMapBuilder.php', +'MessagesIgnoredUserMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/MessagesIgnoredUserMapBuilder.php', +'ArticleArtworkRelationMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArticleArtworkRelationMapBuilder.php', +'RelatedArtworkMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/RelatedArtworkMapBuilder.php', +'ResidenceMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ResidenceMapBuilder.php', +'ArticleSubreaktorMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArticleSubreaktorMapBuilder.php', +'ResidenceLevelI18nMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ResidenceLevelI18nMapBuilder.php', +'TransUnitMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/TransUnitMapBuilder.php', +'AdminMessageMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/AdminMessageMapBuilder.php', +'ReportBookmarkMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ReportBookmarkMapBuilder.php', +'ArticleArticleRelationMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArticleArticleRelationMapBuilder.php', +'HistoryActionMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/HistoryActionMapBuilder.php', +'HistoryActionI18nMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/HistoryActionI18nMapBuilder.php', +'SubreaktorIdentifierMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/SubreaktorIdentifierMapBuilder.php', +'SubreaktorArtworkMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/SubreaktorArtworkMapBuilder.php', +'FileMetadataMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/FileMetadataMapBuilder.php', +'ArticleFileMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArticleFileMapBuilder.php', +'ResidenceLevelMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ResidenceLevelMapBuilder.php', +'UserResourceMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/UserResourceMapBuilder.php', +'ArticleMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArticleMapBuilder.php', +'CategoryI18nMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/CategoryI18nMapBuilder.php', +'ReaktorFileMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ReaktorFileMapBuilder.php', +'FileMimetypeMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/FileMimetypeMapBuilder.php', +'CategoryMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/CategoryMapBuilder.php', +'HistoryMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/HistoryMapBuilder.php', +'RejectionTypeMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/RejectionTypeMapBuilder.php', +'ArticleCategoryMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArticleCategoryMapBuilder.php', +'SubreaktorMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/SubreaktorMapBuilder.php', +'UserInterestMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/UserInterestMapBuilder.php', +'ReaktorArtworkHistoryMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ReaktorArtworkHistoryMapBuilder.php', +'LokalreaktorArtworkMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/LokalreaktorArtworkMapBuilder.php', +'MessagesMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/MessagesMapBuilder.php', +'LokalreaktorResidenceMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/LokalreaktorResidenceMapBuilder.php', +'RecommendedArtworkMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/RecommendedArtworkMapBuilder.php', +'ArticleI18nMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArticleI18nMapBuilder.php', +'ArtworkStatusMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArtworkStatusMapBuilder.php', +'FavouriteMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/FavouriteMapBuilder.php', +'ArticleAttachmentMapBuilder' => '/home/benjamin/reaktor/trunk/lib/model/map/ArticleAttachmentMapBuilder.php', +'ArtworkStatus' => '/home/benjamin/reaktor/trunk/lib/model/ArtworkStatus.php', +'BaseResidenceLevelI18n' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseResidenceLevelI18n.php', +'BaseLokalreaktorArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseLokalreaktorArtworkPeer.php', +'BaseLokalreaktorArtwork' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseLokalreaktorArtwork.php', +'BaseRelatedArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseRelatedArtworkPeer.php', +'BaseResidenceLevel' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseResidenceLevel.php', +'BaseResidenceLevelI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseResidenceLevelI18nPeer.php', +'BaseArticleAttachment' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleAttachment.php', +'BaseResidencePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseResidencePeer.php', +'BaseHistoryActionI18n' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseHistoryActionI18n.php', +'BaseArticleI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleI18nPeer.php', +'BaseCategorySubreaktorPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCategorySubreaktorPeer.php', +'BaseSubreaktorArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseSubreaktorArtworkPeer.php', +'BaseReaktorFilePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReaktorFilePeer.php', +'BaseCategoryI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCategoryI18nPeer.php', +'BaseArtworkStatusPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArtworkStatusPeer.php', +'BaseReaktorArtworkFile' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReaktorArtworkFile.php', +'BaseArticleSubreaktorPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleSubreaktorPeer.php', +'BaseArticleFile' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleFile.php', +'BaseFileMimetype' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseFileMimetype.php', +'BaseArticleArticleRelationPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleArticleRelationPeer.php', +'BaseRelatedArtwork' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseRelatedArtwork.php', +'BaseReaktorArtworkHistoryPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReaktorArtworkHistoryPeer.php', +'BaseReaktorArtworkHistory' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReaktorArtworkHistory.php', +'BaseTransUnitPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseTransUnitPeer.php', +'BaseUserResourcePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseUserResourcePeer.php', +'BaseHistoryAction' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseHistoryAction.php', +'BaseCategoryArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCategoryArtworkPeer.php', +'BaseReaktorArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReaktorArtworkPeer.php', +'BaseMessagesPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseMessagesPeer.php', +'BaseArticleFilePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleFilePeer.php', +'BaseCatalogue' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCatalogue.php', +'BaseRejectionType' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseRejectionType.php', +'BaseRecommendedArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseRecommendedArtworkPeer.php', +'BaseUserInterest' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseUserInterest.php', +'BaseReportBookmarkPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReportBookmarkPeer.php', +'BaseArticleArtworkRelation' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleArtworkRelation.php', +'BaseSubreaktor' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseSubreaktor.php', +'BaseSubreaktorI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseSubreaktorI18nPeer.php', +'BaseArticleI18n' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleI18n.php', +'BaseRejectionTypeI18n' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseRejectionTypeI18n.php', +'BaseCategoryArtwork' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCategoryArtwork.php', +'BaseHistoryActionI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseHistoryActionI18nPeer.php', +'BaseAdminMessagePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseAdminMessagePeer.php', +'BaseSubreaktorIdentifierPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseSubreaktorIdentifierPeer.php', +'BaseMessagesIgnoredUserPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseMessagesIgnoredUserPeer.php', +'BaseCategory' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCategory.php', +'BaseArticleArticleRelation' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleArticleRelation.php', +'BaseFileMetadataPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseFileMetadataPeer.php', +'BaseHistory' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseHistory.php', +'BaseReaktorFile' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReaktorFile.php', +'BaseResidence' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseResidence.php', +'BaseArtworkStatusI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArtworkStatusI18nPeer.php', +'BaseCategoryI18n' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCategoryI18n.php', +'BaseFavourite' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseFavourite.php', +'BaseMessagesIgnoredUser' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseMessagesIgnoredUser.php', +'BaseSubreaktorI18n' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseSubreaktorI18n.php', +'BaseFavouritePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseFavouritePeer.php', +'BaseUserResource' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseUserResource.php', +'BaseRejectionTypePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseRejectionTypePeer.php', +'BaseArticleCategory' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleCategory.php', +'BaseReaktorArtwork' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReaktorArtwork.php', +'BaseCategorySubreaktor' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCategorySubreaktor.php', +'BaseLokalreaktorResidencePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseLokalreaktorResidencePeer.php', +'BaseArtworkStatus' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArtworkStatus.php', +'BaseResidenceLevelPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseResidenceLevelPeer.php', +'BaseCataloguePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCataloguePeer.php', +'BaseArticleArtworkRelationPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleArtworkRelationPeer.php', +'BaseSubreaktorArtwork' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseSubreaktorArtwork.php', +'BaseArticleAttachmentPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleAttachmentPeer.php', +'BaseFileMetadata' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseFileMetadata.php', +'BaseHistoryPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseHistoryPeer.php', +'BaseLokalreaktorResidence' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseLokalreaktorResidence.php', +'BaseUserInterestPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseUserInterestPeer.php', +'BaseMessages' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseMessages.php', +'BaseArtworkStatusI18n' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArtworkStatusI18n.php', +'BaseRejectionTypeI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseRejectionTypeI18nPeer.php', +'BaseSubreaktorPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseSubreaktorPeer.php', +'BaseArticlePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticlePeer.php', +'BaseRecommendedArtwork' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseRecommendedArtwork.php', +'BaseArticleCategoryPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleCategoryPeer.php', +'BaseTransUnit' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseTransUnit.php', +'BaseArticle' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticle.php', +'BaseAdminMessage' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseAdminMessage.php', +'BaseHistoryActionPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseHistoryActionPeer.php', +'BaseFileMimetypePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseFileMimetypePeer.php', +'BaseReportBookmark' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReportBookmark.php', +'BaseCategoryPeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseCategoryPeer.php', +'BaseReaktorArtworkFilePeer' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseReaktorArtworkFilePeer.php', +'BaseSubreaktorIdentifier' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseSubreaktorIdentifier.php', +'BaseArticleSubreaktor' => '/home/benjamin/reaktor/trunk/lib/model/om/BaseArticleSubreaktor.php', +'sfGuardUserGroupPeer' => '/home/benjamin/reaktor/trunk/lib/model/sfGuardUserGroupPeer.php', +'MessagesIgnoredUserPeer' => '/home/benjamin/reaktor/trunk/lib/model/MessagesIgnoredUserPeer.php', +'ReaktorArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/ReaktorArtworkPeer.php', +'ReaktorArtworkFilePeer' => '/home/benjamin/reaktor/trunk/lib/model/ReaktorArtworkFilePeer.php', +'ResidenceLevel' => '/home/benjamin/reaktor/trunk/lib/model/ResidenceLevel.php', +'CategoryI18n' => '/home/benjamin/reaktor/trunk/lib/model/CategoryI18n.php', +'Catalogue' => '/home/benjamin/reaktor/trunk/lib/model/Catalogue.php', +'sfGuardUser' => '/home/benjamin/reaktor/trunk/lib/model/sfGuardUser.php', +'LokalreaktorArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/LokalreaktorArtworkPeer.php', +'UserInterestPeer' => '/home/benjamin/reaktor/trunk/lib/model/UserInterestPeer.php', +'ArticleAttachmentPeer' => '/home/benjamin/reaktor/trunk/lib/model/ArticleAttachmentPeer.php', +'TagPeer' => '/home/benjamin/reaktor/trunk/lib/model/TagPeer.php', +'RecommendedArtwork' => '/home/benjamin/reaktor/trunk/lib/model/RecommendedArtwork.php', +'CategoryArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/CategoryArtworkPeer.php', +'ArticleArticleRelationPeer' => '/home/benjamin/reaktor/trunk/lib/model/ArticleArticleRelationPeer.php', +'ReaktorArtworkFile' => '/home/benjamin/reaktor/trunk/lib/model/ReaktorArtworkFile.php', +'ArticleFilePeer' => '/home/benjamin/reaktor/trunk/lib/model/ArticleFilePeer.php', +'RejectionTypeI18n' => '/home/benjamin/reaktor/trunk/lib/model/RejectionTypeI18n.php', +'ArticleAttachment' => '/home/benjamin/reaktor/trunk/lib/model/ArticleAttachment.php', +'SubreaktorArtwork' => '/home/benjamin/reaktor/trunk/lib/model/SubreaktorArtwork.php', +'ReaktorArtwork' => '/home/benjamin/reaktor/trunk/lib/model/ReaktorArtwork.php', +'HistoryActionI18n' => '/home/benjamin/reaktor/trunk/lib/model/HistoryActionI18n.php', +'ArtworkStatusI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/ArtworkStatusI18nPeer.php', +'sfComment' => '/home/benjamin/reaktor/trunk/lib/model/sfComment.php', +'CategoryArtwork' => '/home/benjamin/reaktor/trunk/lib/model/CategoryArtwork.php', +'ArticleSubreaktor' => '/home/benjamin/reaktor/trunk/lib/model/ArticleSubreaktor.php', +'SubreaktorPeer' => '/home/benjamin/reaktor/trunk/lib/model/SubreaktorPeer.php', +'UserResource' => '/home/benjamin/reaktor/trunk/lib/model/UserResource.php', +'ReaktorFilePeer' => '/home/benjamin/reaktor/trunk/lib/model/ReaktorFilePeer.php', +'CategoryI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/CategoryI18nPeer.php', +'Residence' => '/home/benjamin/reaktor/trunk/lib/model/Residence.php', +'FileMimetypePeer' => '/home/benjamin/reaktor/trunk/lib/model/FileMimetypePeer.php', +'TransUnit' => '/home/benjamin/reaktor/trunk/lib/model/TransUnit.php', +'sfGuardGroupPeer' => '/home/benjamin/reaktor/trunk/lib/model/sfGuardGroupPeer.php', +'sfGuardUserGroup' => '/home/benjamin/reaktor/trunk/lib/model/sfGuardUserGroup.php', +'ArticleArtworkRelationPeer' => '/home/benjamin/reaktor/trunk/lib/model/ArticleArtworkRelationPeer.php', +'FavouritePeer' => '/home/benjamin/reaktor/trunk/lib/model/FavouritePeer.php', +'AdminMessage' => '/home/benjamin/reaktor/trunk/lib/model/AdminMessage.php', +'ArticlePeer' => '/home/benjamin/reaktor/trunk/lib/model/ArticlePeer.php', +'ArticleSubreaktorPeer' => '/home/benjamin/reaktor/trunk/lib/model/ArticleSubreaktorPeer.php', +'LokalreaktorResidencePeer' => '/home/benjamin/reaktor/trunk/lib/model/LokalreaktorResidencePeer.php', +'ReaktorArtworkHistoryPeer' => '/home/benjamin/reaktor/trunk/lib/model/ReaktorArtworkHistoryPeer.php', +'FileMetadata' => '/home/benjamin/reaktor/trunk/lib/model/FileMetadata.php', +'RecommendedArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/RecommendedArtworkPeer.php', +'ResidenceLevelPeer' => '/home/benjamin/reaktor/trunk/lib/model/ResidenceLevelPeer.php', +'ReportBookmark' => '/home/benjamin/reaktor/trunk/lib/model/ReportBookmark.php', +'TaggingPeer' => '/home/benjamin/reaktor/trunk/lib/model/TaggingPeer.php', +'ArticleFile' => '/home/benjamin/reaktor/trunk/lib/model/ArticleFile.php', +'sfGuardGroup' => '/home/benjamin/reaktor/trunk/lib/model/sfGuardGroup.php', +'sfGuardPermission' => '/home/benjamin/reaktor/trunk/lib/model/sfGuardPermission.php', +'SubreaktorI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/SubreaktorI18nPeer.php', +'RelatedArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/RelatedArtworkPeer.php', +'ArticleI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/ArticleI18nPeer.php', +'CategorySubreaktorPeer' => '/home/benjamin/reaktor/trunk/lib/model/CategorySubreaktorPeer.php', +'RelatedArtwork' => '/home/benjamin/reaktor/trunk/lib/model/RelatedArtwork.php', +'ArtworkStatusPeer' => '/home/benjamin/reaktor/trunk/lib/model/ArtworkStatusPeer.php', +'CataloguePeer' => '/home/benjamin/reaktor/trunk/lib/model/CataloguePeer.php', +'SubreaktorIdentifier' => '/home/benjamin/reaktor/trunk/lib/model/SubreaktorIdentifier.php', +'Article' => '/home/benjamin/reaktor/trunk/lib/model/Article.php', +'FileMetadataPeer' => '/home/benjamin/reaktor/trunk/lib/model/FileMetadataPeer.php', +'ArticleCategoryPeer' => '/home/benjamin/reaktor/trunk/lib/model/ArticleCategoryPeer.php', +'Messages' => '/home/benjamin/reaktor/trunk/lib/model/Messages.php', +'ResidenceLevelI18n' => '/home/benjamin/reaktor/trunk/lib/model/ResidenceLevelI18n.php', +'SubreaktorArtworkPeer' => '/home/benjamin/reaktor/trunk/lib/model/SubreaktorArtworkPeer.php', +'Favourite' => '/home/benjamin/reaktor/trunk/lib/model/Favourite.php', +'ResidencePeer' => '/home/benjamin/reaktor/trunk/lib/model/ResidencePeer.php', +'UserInterest' => '/home/benjamin/reaktor/trunk/lib/model/UserInterest.php', +'ReportBookmarkPeer' => '/home/benjamin/reaktor/trunk/lib/model/ReportBookmarkPeer.php', +'ArticleArtworkRelation' => '/home/benjamin/reaktor/trunk/lib/model/ArticleArtworkRelation.php', +'ReaktorArtworkHistory' => '/home/benjamin/reaktor/trunk/lib/model/ReaktorArtworkHistory.php', +'ArticleCategory' => '/home/benjamin/reaktor/trunk/lib/model/ArticleCategory.php', +'CategoryPeer' => '/home/benjamin/reaktor/trunk/lib/model/CategoryPeer.php', +'SubreaktorI18n' => '/home/benjamin/reaktor/trunk/lib/model/SubreaktorI18n.php', +'ResidenceLevelI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/ResidenceLevelI18nPeer.php', +'MessagesIgnoredUser' => '/home/benjamin/reaktor/trunk/lib/model/MessagesIgnoredUser.php', +'Category' => '/home/benjamin/reaktor/trunk/lib/model/Category.php', +'History' => '/home/benjamin/reaktor/trunk/lib/model/History.php', +'LokalreaktorResidence' => '/home/benjamin/reaktor/trunk/lib/model/LokalreaktorResidence.php', +'sfGuardUserPeer' => '/home/benjamin/reaktor/trunk/lib/model/sfGuardUserPeer.php', +'LokalreaktorArtwork' => '/home/benjamin/reaktor/trunk/lib/model/LokalreaktorArtwork.php', +'MessagesPeer' => '/home/benjamin/reaktor/trunk/lib/model/MessagesPeer.php', +'HistoryPeer' => '/home/benjamin/reaktor/trunk/lib/model/HistoryPeer.php', +'TransUnitPeer' => '/home/benjamin/reaktor/trunk/lib/model/TransUnitPeer.php', +'ArticleI18n' => '/home/benjamin/reaktor/trunk/lib/model/ArticleI18n.php', +'RejectionType' => '/home/benjamin/reaktor/trunk/lib/model/RejectionType.php', +'CategorySubreaktor' => '/home/benjamin/reaktor/trunk/lib/model/CategorySubreaktor.php', +'AdminMessagePeer' => '/home/benjamin/reaktor/trunk/lib/model/AdminMessagePeer.php', +'Subreaktor' => '/home/benjamin/reaktor/trunk/lib/model/Subreaktor.php', +'SubreaktorIdentifierPeer' => '/home/benjamin/reaktor/trunk/lib/model/SubreaktorIdentifierPeer.php', +'HistoryAction' => '/home/benjamin/reaktor/trunk/lib/model/HistoryAction.php', +'ReaktorFile' => '/home/benjamin/reaktor/trunk/lib/model/ReaktorFile.php', +'UserResourcePeer' => '/home/benjamin/reaktor/trunk/lib/model/UserResourcePeer.php', +'ArticleArticleRelation' => '/home/benjamin/reaktor/trunk/lib/model/ArticleArticleRelation.php', +'ArtworkStatusI18n' => '/home/benjamin/reaktor/trunk/lib/model/ArtworkStatusI18n.php', +'sfGuardPermissionPeer' => '/home/benjamin/reaktor/trunk/lib/model/sfGuardPermissionPeer.php', +'HistoryActionPeer' => '/home/benjamin/reaktor/trunk/lib/model/HistoryActionPeer.php', +'RejectionTypePeer' => '/home/benjamin/reaktor/trunk/lib/model/RejectionTypePeer.php', +'Tagging' => '/home/benjamin/reaktor/trunk/lib/model/Tagging.php', +'FileMimetype' => '/home/benjamin/reaktor/trunk/lib/model/FileMimetype.php', +'HistoryActionI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/HistoryActionI18nPeer.php', +'sfCommentPeer' => '/home/benjamin/reaktor/trunk/lib/model/sfCommentPeer.php', +'RejectionTypeI18nPeer' => '/home/benjamin/reaktor/trunk/lib/model/RejectionTypeI18nPeer.php', + +// application +'sfLokalReaktorNameValidator' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/sfLokalReaktorNameValidator.class.php', +'myArtworkTitleValidator' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/myArtworkTitleValidator.class.php', +'artworkFile' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/artworkFile.class.php', +'audioInfo' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/audioinfo.class.php', +'imageResize' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/imageResize.class.php', +'adminFilter' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/adminFilter.class.php', +'myMagickDateValidator' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/myMagickDateValidator.class.php', +'rememberMeFilter' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/rememberMeFilter.class.php', +'myMagickArrayValidator' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/myMagickArrayValidator.class.php', +'myUser' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/myUser.class.php', +'userFilter' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/userFilter.class.php', +'transcoder' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/transcoder.class.php', +'subreaktorFilter' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/subreaktorFilter.class.php', +'stringMagick' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/stringMagick.class.php', +'myMagickWorkingRegexValidator' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/myMagickWorkingRegexValidator.class.php', +'videoInfo' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/videoInfo.class.php', +'reaktor' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/reaktor.class.php', +'upload' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/upload.class.php', +'ccLicense' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/ccLicense.class.php', +'commentCalendar' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/commentCalendar.class.php', +'genericArtwork' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/genericArtwork.class.php', +'reaktorCache' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/reaktorCache.class.php', +'videoFrame' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/videoFrame.class.php', +'reaktorQuickStorage' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/reaktorQuickStorage.php', +'myPasswordValidator' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/myPasswordValidator.class.php', +'CommentMagick' => '/home/benjamin/reaktor/trunk/apps/reaktor/lib/commentMagick.class.php', + +// module +'sfGuardAuth/reaktorAuth' => '/home/benjamin/reaktor/trunk/apps/reaktor/modules/sfGuardAuth/lib/validate/reaktorAuth.class.php', +'sfRating/BasesfRatingActions' => '/home/benjamin/reaktor/trunk/apps/reaktor/modules/sfRating/lib/BasesfRatingActions.class.php', +'sfTransUnit/BasesfTransUnitActions' => '/home/benjamin/reaktor/trunk/apps/reaktor/modules/sfTransUnit/lib/BasesfTransUnitActions.class.php', +'upload/myUrlFieldValidator' => '/home/benjamin/reaktor/trunk/apps/reaktor/modules/upload/lib/myUrlFieldValidator.class.php', +); diff --git a/cache/reaktor/dev/config/config_config_handlers.yml.php b/cache/reaktor/dev/config/config_config_handlers.yml.php new file mode 100644 index 0000000..6c2bd90 --- /dev/null +++ b/cache/reaktor/dev/config/config_config_handlers.yml.php @@ -0,0 +1,56 @@ +handlers['config/autoload.yml'] = new sfAutoloadConfigHandler(); +$this->handlers['config/autoload.yml']->initialize(); +$this->handlers['config/php.yml'] = new sfPhpConfigHandler(); +$this->handlers['config/php.yml']->initialize(); +$this->handlers['config/databases.yml'] = new sfDatabaseConfigHandler(); +$this->handlers['config/databases.yml']->initialize(); +$this->handlers['config/settings.yml'] = new sfDefineEnvironmentConfigHandler(); +$this->handlers['config/settings.yml']->initialize(array ( + 'prefix' => 'sf_', +)); +$this->handlers['config/app.yml'] = new sfDefineEnvironmentConfigHandler(); +$this->handlers['config/app.yml']->initialize(array ( + 'prefix' => 'app_', +)); +$this->handlers['config/factories.yml'] = new sfFactoryConfigHandler(); +$this->handlers['config/factories.yml']->initialize(); +$this->handlers['config/bootstrap_compile.yml'] = new sfCompileConfigHandler(); +$this->handlers['config/bootstrap_compile.yml']->initialize(); +$this->handlers['config/core_compile.yml'] = new sfCompileConfigHandler(); +$this->handlers['config/core_compile.yml']->initialize(); +$this->handlers['config/filters.yml'] = new sfFilterConfigHandler(); +$this->handlers['config/filters.yml']->initialize(); +$this->handlers['config/logging.yml'] = new sfLoggingConfigHandler(); +$this->handlers['config/logging.yml']->initialize(array ( + 'prefix' => 'sf_logging_', +)); +$this->handlers['config/routing.yml'] = new sfRoutingConfigHandler(); +$this->handlers['config/routing.yml']->initialize(); +$this->handlers['config/i18n.yml'] = new sfDefineEnvironmentConfigHandler(); +$this->handlers['config/i18n.yml']->initialize(array ( + 'prefix' => 'sf_i18n_', +)); +$this->handlers['modules/*/config/generator.yml'] = new sfGeneratorConfigHandler(); +$this->handlers['modules/*/config/generator.yml']->initialize(); +$this->handlers['modules/*/config/view.yml'] = new sfViewConfigHandler(); +$this->handlers['modules/*/config/view.yml']->initialize(); +$this->handlers['modules/*/config/mailer.yml'] = new sfDefineEnvironmentConfigHandler(); +$this->handlers['modules/*/config/mailer.yml']->initialize(array ( + 'prefix' => 'sf_mailer_', + 'module' => true, +)); +$this->handlers['modules/*/config/security.yml'] = new sfSecurityConfigHandler(); +$this->handlers['modules/*/config/security.yml']->initialize(); +$this->handlers['modules/*/config/cache.yml'] = new sfCacheConfigHandler(); +$this->handlers['modules/*/config/cache.yml']->initialize(); +$this->handlers['modules/*/validate/*.yml'] = new sfValidatorConfigHandler(); +$this->handlers['modules/*/validate/*.yml']->initialize(); +$this->handlers['modules/*/config/module.yml'] = new sfDefineEnvironmentConfigHandler(); +$this->handlers['modules/*/config/module.yml']->initialize(array ( + 'prefix' => 'mod_', + 'module' => true, +)); diff --git a/cache/reaktor/dev/config/config_i18n.yml.php b/cache/reaktor/dev/config/config_i18n.yml.php new file mode 100644 index 0000000..3587685 --- /dev/null +++ b/cache/reaktor/dev/config/config_i18n.yml.php @@ -0,0 +1,12 @@ + 'no', + 'sf_i18n_source' => 'MySQL', + 'sf_i18n_debug' => true, + 'sf_i18n_cache' => false, + 'sf_i18n_untranslated_prefix' => '', + 'sf_i18n_untranslated_suffix' => '', + 'sf_i18n_database' => 'mysql://reaktor_user:cT0PHPCm@localhost/reaktor', +)); diff --git a/cache/reaktor/dev/config/config_logging.yml.php b/cache/reaktor/dev/config/config_logging.yml.php new file mode 100644 index 0000000..59e3b4e --- /dev/null +++ b/cache/reaktor/dev/config/config_logging.yml.php @@ -0,0 +1,25 @@ + true, + 'sf_logging_level' => 'debug', + 'sf_logging_rotate' => false, + 'sf_logging_period' => 7, + 'sf_logging_history' => 10, + 'sf_logging_purge' => true, +)); + +$logger = sfLogger::getInstance(); +$logger->setLogLevel(constant('SF_LOG_'.strtoupper(sfConfig::get('sf_logging_level')))); + +$log = new sfWebDebugLogger(); +$log->initialize(array ( +)); +$logger->registerLogger($log); + +$log = new sfFileLogger(); +$log->initialize(array ( + 'file' => '/home/benjamin/reaktor/trunk/log/reaktor_dev.log', +)); +$logger->registerLogger($log); diff --git a/cache/reaktor/dev/config/config_settings.yml.php b/cache/reaktor/dev/config/config_settings.yml.php new file mode 100644 index 0000000..83f11f8 --- /dev/null +++ b/cache/reaktor/dev/config/config_settings.yml.php @@ -0,0 +1,77 @@ + 'home', + 'sf_default_action' => 'index', + 'sf_error_404_module' => 'home', + 'sf_error_404_action' => 'error404', + 'sf_login_module' => 'sfGuardAuth', + 'sf_login_action' => 'signin', + 'sf_secure_module' => 'sfGuardAuth', + 'sf_secure_action' => 'secure', + 'sf_module_disabled_module' => 'default', + 'sf_module_disabled_action' => 'disabled', + 'sf_unavailable_module' => 'default', + 'sf_unavailable_action' => 'unavailable', + 'sf_available' => true, + 'sf_use_database' => true, + 'sf_use_security' => true, + 'sf_use_flash' => true, + 'sf_i18n' => true, + 'sf_check_symfony_version' => false, + 'sf_use_process_cache' => true, + 'sf_compressed' => false, + 'sf_check_lock' => false, + 'sf_escaping_strategy' => 'bc', + 'sf_escaping_method' => 'ESC_ENTITIES', + 'sf_suffix' => '.', + 'sf_no_script_name' => false, + 'sf_validation_error_prefix' => ' ↓ ', + 'sf_validation_error_suffix' => '  ↓', + 'sf_validation_error_class' => 'form_error', + 'sf_validation_error_id_prefix' => 'error_for_', + 'sf_cache' => true, + 'sf_etag' => false, + 'sf_web_debug' => true, + 'sf_error_reporting' => 8191, + 'sf_rich_text_js_dir' => 'js/tiny_mce', + 'sf_prototype_web_dir' => NULL, + 'sf_admin_web_dir' => '/sf/sf_admin', + 'sf_web_debug_web_dir' => '/sf/sf_web_debug', + 'sf_calendar_web_dir' => '/sf/calendar', + 'sf_standard_helpers' => array ( + 0 => 'I18N', + 1 => 'Validation', + 2 => 'Form', + 3 => 'Tags', + 4 => 'Partial', + 5 => 'subreaktor', + 6 => 'browserDetection', +), + 'sf_enabled_modules' => array ( + 0 => 'sfGuardGroup', + 1 => 'sfGuardUser', + 2 => 'sfGuardPermission', + 3 => 'sfGuardAuth', + 4 => 'sfMediaLibrary', + 5 => 'sfThumbnail', + 6 => 'sfPropelActAsTaggableBehavior', + 7 => 'sfPropelActAsCommentableBehavior', + 8 => 'sfComment', + 9 => 'sfRating', + 10 => 'getId3', + 11 => 'sfI18nDbTranslation', + 12 => 'sfTransUnit', + 13 => 'recaptcha', +), + 'sf_charset' => 'utf-8', + 'sf_strip_comments' => true, + 'sf_autoloading_functions' => NULL, + 'sf_timeout' => 1800, + 'sf_max_forwards' => 5, + 'sf_path_info_array' => 'SERVER', + 'sf_path_info_key' => 'PATH_INFO', + 'sf_url_format' => 'PATH', + 'sf_orm' => 'propel', +)); diff --git a/config/articles-schema.yml b/config/articles-schema.yml new file mode 100644 index 0000000..fcc7192 --- /dev/null +++ b/config/articles-schema.yml @@ -0,0 +1,59 @@ +propel: + _attributes: { package: lib.model } + + article: + id: + created_at: + author_id: { type: integer, foreignTable: sf_guard_user, required: true, foreignReference: id } + base_title: { type: varchar, size: 255, required: true } + permalink: { type: varchar, size: 255, required: true } + ingress: { type: longvarchar } + content: { type: longvarchar, required: true } + updated_at: { type: timestamp } + updated_by: { type: integer, required: true, default: 0 } + article_type: { type: integer, required: true } + article_order: { type: integer, required: true } + expires_at: { type: timestamp } + status: { type: integer, required: true } + published_at: { type: timestamp } + banner_file_id: { type: integer, default: 0, foreignTable: article_file, required: false, foreignReference: id } + is_sticky: { type: boolean, default: false } + frontpage: { type: integer, default: 0 } + + article_i18n: + title: { type: varchar, size: 255, required: true } + + article_article_relation: + id: + created_at: + first_article: { type: integer, foreignTable: article, required: true, foreignReference: id } + second_article: { type: integer, foreignTable: article, required: true, foreignReference: id } + created_by: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + + article_artwork_relation: + id: + created_at: + article_id: { type: integer, required: true, foreignTable: article, foreignReference: id } + artwork_id: { type: integer, required: true, foreignTable: reaktor_artwork, foreignReference: id } + created_by: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + + article_file: + id: + filename: { type: varchar, size: 255, required: true } + path: { type: varchar, size: 255, required: true } + uploaded_by: { type: integer, foreignTable: sf_guard_user, required: true, foreignReference: id } + uploaded_at: { type: timestamp, required: true } + description: { type: varchar, size: 255 } + file_mimetype_id: { type: integer, foreignTable: file_mimetype, required: true, foreignReference: id } + + article_category: + article_id: { type: integer, foreignTable: article, required: true, foreignReference: id } + category_id: { type: integer, foreignTable: category, required: true, foreignReference: id } + + article_subreaktor: + article_id: { type: integer, foreignTable: article, required: true, foreignReference: id } + subreaktor_id: { type: integer, foreignTable: subreaktor, required: true, foreignReference: id } + + article_attachment: + article_id: { type: integer, foreignTable: article, required: true, foreignReference: id } + file_id: { type: integer, foreignTable: article_file, required: true, foreignReference: id } diff --git a/config/artwork_status-schema.yml b/config/artwork_status-schema.yml new file mode 100644 index 0000000..11ccee1 --- /dev/null +++ b/config/artwork_status-schema.yml @@ -0,0 +1,10 @@ +propel: + _attributes: { package: lib.model } + + artwork_status: + id: + name: { type: varchar, size: 30, required: true } + + artwork_status_i18n: + id: + description: { type: varchar, size: 30, required: true } \ No newline at end of file diff --git a/config/category-schema.yml b/config/category-schema.yml new file mode 100644 index 0000000..ccff86d --- /dev/null +++ b/config/category-schema.yml @@ -0,0 +1,21 @@ +propel: + _attributes: { package: lib.model } + + category: + id: + basename: { type: varchar, size: 75, required: true } + + category_i18n: + name: { type: varchar, size: 75, required: true } + + category_artwork: + id: + category_id: { type: integer, foreignTable: category, foreignReference: id, required: true; } + artwork_id: { type: integer, foreignTable: reaktor_artwork, foreignReference: id, required: true; } + added_by: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true; } + created_at: { type: timestamp, required: true; } + + category_subreaktor: + id: + category_id: { type: integer, foreignTable: category, foreignReference: id, required: true; } + subreaktor_id: { type: integer, foreignTable: subreaktor, foreignReference: id, required: true; } \ No newline at end of file diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..db50b90 --- /dev/null +++ b/config/config.php @@ -0,0 +1,22 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +if (is_dir("c:\windows")) +{ + $sf_symfony_lib_dir = 'C:\xampp\php\PEAR\symfony'; + $sf_symfony_data_dir = 'C:\xampp\php\PEAR\data\symfony'; +} +else +{ + $sf_symfony_lib_dir = '/usr/share/php/symfony'; + $sf_symfony_data_dir = '/usr/share/php/data/symfony'; +} \ No newline at end of file diff --git a/config/databases.yml b/config/databases.yml new file mode 100644 index 0000000..cc09b7e --- /dev/null +++ b/config/databases.yml @@ -0,0 +1,21 @@ +test: + propel: + class: sfPropelDatabase + param: + phptype: mysql + host: localhost + database: reaktor_test + username: reaktor_user + password: cT0PHPCm #Crack team of PHP code monkeys :) + encoding: utf8 + +all: + propel: + class: sfPropelDatabase + param: + phptype: mysql + host: localhost + database: reaktor + username: reaktor_user + password: cT0PHPCm #Crack team of PHP code monkeys :) + encoding: utf8 \ No newline at end of file diff --git a/config/favourite-schema.yml b/config/favourite-schema.yml new file mode 100644 index 0000000..107f6ec --- /dev/null +++ b/config/favourite-schema.yml @@ -0,0 +1,10 @@ +propel: + _attributes: { package: lib.model } + + favourite: + id: + user_id: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + artwork_id: { type: integer, required: true, foreignTable: reaktor_artwork, foreignReference: id } + article_id: { type: integer, required: true, foreignTable: article, foreignReference: id } + friend_id: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + fav_type: { type: varchar, size: 8, required: true} diff --git a/config/file_metadata-schema.yml b/config/file_metadata-schema.yml new file mode 100644 index 0000000..ae492bc --- /dev/null +++ b/config/file_metadata-schema.yml @@ -0,0 +1,9 @@ +propel: + _attributes: { package: lib.model } + + file_metadata: + id: + file: { type: integer, foreignTable: reaktor_file, required: true, foreignReference: id, onDelete: cascade } + meta_element: { type: varchar, size: 100, required: true } + meta_qualifier: { type: varchar, size: 100, required: true } + meta_value: { type: longvarchar, required: true } \ No newline at end of file diff --git a/config/file_mimetype-schema.yml b/config/file_mimetype-schema.yml new file mode 100644 index 0000000..6cf2d37 --- /dev/null +++ b/config/file_mimetype-schema.yml @@ -0,0 +1,7 @@ +propel: + _attributes: { package: lib.model } + + file_mimetype: + id: + mimetype: { type: varchar, size: 100, required: true } + identifier: { type: varchar, required: true, size: 20 } \ No newline at end of file diff --git a/config/generated-articles-schema-transformed.xml b/config/generated-articles-schema-transformed.xml new file mode 100644 index 0000000..54e9099 --- /dev/null +++ b/config/generated-articles-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-artwork_status-schema-transformed.xml b/config/generated-artwork_status-schema-transformed.xml new file mode 100644 index 0000000..3909512 --- /dev/null +++ b/config/generated-artwork_status-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-artwork_type-schema-transformed.xml b/config/generated-artwork_type-schema-transformed.xml new file mode 100644 index 0000000..1371122 --- /dev/null +++ b/config/generated-artwork_type-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-category-schema-transformed.xml b/config/generated-category-schema-transformed.xml new file mode 100644 index 0000000..e51a8c5 --- /dev/null +++ b/config/generated-category-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-editorial_team-schema-transformed.xml b/config/generated-editorial_team-schema-transformed.xml new file mode 100644 index 0000000..e172121 --- /dev/null +++ b/config/generated-editorial_team-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-favourite-schema-transformed.xml b/config/generated-favourite-schema-transformed.xml new file mode 100644 index 0000000..2a03f1c --- /dev/null +++ b/config/generated-favourite-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-file_metadata-schema-transformed.xml b/config/generated-file_metadata-schema-transformed.xml new file mode 100644 index 0000000..4f59736 --- /dev/null +++ b/config/generated-file_metadata-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-file_mimetype-schema-transformed.xml b/config/generated-file_mimetype-schema-transformed.xml new file mode 100644 index 0000000..9950711 --- /dev/null +++ b/config/generated-file_mimetype-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-history-schema-transformed.xml b/config/generated-history-schema-transformed.xml new file mode 100644 index 0000000..c6eb947 --- /dev/null +++ b/config/generated-history-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-lokalreaktorartwork-schema-transformed.xml b/config/generated-lokalreaktorartwork-schema-transformed.xml new file mode 100644 index 0000000..49141d4 --- /dev/null +++ b/config/generated-lokalreaktorartwork-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-messaging-schema-transformed.xml b/config/generated-messaging-schema-transformed.xml new file mode 100644 index 0000000..d6b2524 --- /dev/null +++ b/config/generated-messaging-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-reaktor_artwork-schema-transformed.xml b/config/generated-reaktor_artwork-schema-transformed.xml new file mode 100644 index 0000000..29c2edb --- /dev/null +++ b/config/generated-reaktor_artwork-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-reaktor_artwork_file-schema-transformed.xml b/config/generated-reaktor_artwork_file-schema-transformed.xml new file mode 100644 index 0000000..c383764 --- /dev/null +++ b/config/generated-reaktor_artwork_file-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-reaktor_artwork_history-schema-transformed.xml b/config/generated-reaktor_artwork_history-schema-transformed.xml new file mode 100644 index 0000000..fbb38c5 --- /dev/null +++ b/config/generated-reaktor_artwork_history-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-reaktor_file-schema-transformed.xml b/config/generated-reaktor_file-schema-transformed.xml new file mode 100644 index 0000000..ca2fff3 --- /dev/null +++ b/config/generated-reaktor_file-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-recommended_artwork-schema-transformed.xml b/config/generated-recommended_artwork-schema-transformed.xml new file mode 100644 index 0000000..a5e62f9 --- /dev/null +++ b/config/generated-recommended_artwork-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-rejection_type-schema-transformed.xml b/config/generated-rejection_type-schema-transformed.xml new file mode 100644 index 0000000..cf413a2 --- /dev/null +++ b/config/generated-rejection_type-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-related_artwork-schema-transformed.xml b/config/generated-related_artwork-schema-transformed.xml new file mode 100644 index 0000000..51c3e15 --- /dev/null +++ b/config/generated-related_artwork-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-report_bookmark-schema-transformed.xml b/config/generated-report_bookmark-schema-transformed.xml new file mode 100644 index 0000000..0a509c9 --- /dev/null +++ b/config/generated-report_bookmark-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-residence-schema-transformed.xml b/config/generated-residence-schema-transformed.xml new file mode 100644 index 0000000..f1bcc4f --- /dev/null +++ b/config/generated-residence-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-sfGuardPlugin-schema-transformed.xml b/config/generated-sfGuardPlugin-schema-transformed.xml new file mode 100644 index 0000000..4a6089a --- /dev/null +++ b/config/generated-sfGuardPlugin-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-sfI18nDbTranslationPlugin-translation_schema-transformed.xml b/config/generated-sfI18nDbTranslationPlugin-translation_schema-transformed.xml new file mode 100644 index 0000000..1e6dbbd --- /dev/null +++ b/config/generated-sfI18nDbTranslationPlugin-translation_schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-sfPropelActAsCommentableBehaviorPlugin-schema-transformed.xml b/config/generated-sfPropelActAsCommentableBehaviorPlugin-schema-transformed.xml new file mode 100644 index 0000000..63962d5 --- /dev/null +++ b/config/generated-sfPropelActAsCommentableBehaviorPlugin-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-sfPropelActAsRatableBehaviorPlugin-schema-transformed.xml b/config/generated-sfPropelActAsRatableBehaviorPlugin-schema-transformed.xml new file mode 100644 index 0000000..18da75e --- /dev/null +++ b/config/generated-sfPropelActAsRatableBehaviorPlugin-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-sfPropelActAsTaggableBehaviorPlugin-schema-transformed.xml b/config/generated-sfPropelActAsTaggableBehaviorPlugin-schema-transformed.xml new file mode 100644 index 0000000..ea8b3ac --- /dev/null +++ b/config/generated-sfPropelActAsTaggableBehaviorPlugin-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-sfSimpleCMSPlugin-schema-transformed.xml b/config/generated-sfSimpleCMSPlugin-schema-transformed.xml new file mode 100644 index 0000000..b4a8dbf --- /dev/null +++ b/config/generated-sfSimpleCMSPlugin-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-subreaktor-schema-transformed.xml b/config/generated-subreaktor-schema-transformed.xml new file mode 100644 index 0000000..b512230 --- /dev/null +++ b/config/generated-subreaktor-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-subreaktor_identifier-schema-transformed.xml b/config/generated-subreaktor_identifier-schema-transformed.xml new file mode 100644 index 0000000..cc9d95a --- /dev/null +++ b/config/generated-subreaktor_identifier-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-subreaktorartwork-schema-transformed.xml b/config/generated-subreaktorartwork-schema-transformed.xml new file mode 100644 index 0000000..e1909b2 --- /dev/null +++ b/config/generated-subreaktorartwork-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-translation_schema-transformed.xml b/config/generated-translation_schema-transformed.xml new file mode 100644 index 0000000..d9c351f --- /dev/null +++ b/config/generated-translation_schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-user_interest-schema-transformed.xml b/config/generated-user_interest-schema-transformed.xml new file mode 100644 index 0000000..d264161 --- /dev/null +++ b/config/generated-user_interest-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/generated-user_resource-schema-transformed.xml b/config/generated-user_resource-schema-transformed.xml new file mode 100644 index 0000000..b36c93d --- /dev/null +++ b/config/generated-user_resource-schema-transformed.xml @@ -0,0 +1,2 @@ + +
    diff --git a/config/history-schema.yml b/config/history-schema.yml new file mode 100644 index 0000000..50f8f05 --- /dev/null +++ b/config/history-schema.yml @@ -0,0 +1,17 @@ +propel: + _attributes: { package: lib.model } + + history: + id: + created_at: + action_id: { type: integer, foreignTable: history_action, required: true, foreignReference: id } + user_id: { type: integer, foreignTable: sf_guard_user, required: true, foreignReference: id } + object_id: { type: integer} + extra_details: { type: longvarchar } + + history_action: + id: + name: { type: varchar, size: 50 } + + history_action_i18n: + description: { type: longvarchar, required: true} \ No newline at end of file diff --git a/config/lokalreaktorartwork-schema.yml b/config/lokalreaktorartwork-schema.yml new file mode 100644 index 0000000..1f98f39 --- /dev/null +++ b/config/lokalreaktorartwork-schema.yml @@ -0,0 +1,15 @@ +propel: + _attributes: { package: lib.model } + + lokalreaktor_artwork: + id: + subreaktor_id: { type: integer, required: true, foreignTable: subreaktor, foreignReference: id } + artwork_id: { type: integer, required: true, foreignTable: reaktor_artwork, foreignReference: id } + + lokalreaktor_residence : + id: + created_at: + subreaktor_id: { type: integer, required: true, foreignTable: subreaktor, foreignReference: id } + residence_id: { type: integer, required: true, foreignTable: residence, foreignReference: id } + + \ No newline at end of file diff --git a/config/messaging-schema.yml b/config/messaging-schema.yml new file mode 100644 index 0000000..b74c979 --- /dev/null +++ b/config/messaging-schema.yml @@ -0,0 +1,33 @@ +propel: + _attributes: { package: lib.model } + + messages: + id: + to_user_id: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + from_user_id: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + subject: { type: varchar, size: 255, required: false } + message: { type: longvarchar, required: false } + timestamp: { type: timestamp, required: true } + deleted_by_from: { type: integer, required: true, default: 0 } + deleted_by_to: { type: integer, required: true, default: 0 } + is_read: { type: boolean, required: true, default: false } + is_ignored: { type: boolean, required: true, default: false } + is_archived: { type: boolean, required: true, default: false } + reply_to: { type: integer, default: 0 } + + messages_ignored_user: + id: + user_id: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + ignores_user_id: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + + admin_message: + id: + subject: { type: varchar, size: 255, required: false } + message: { type: longvarchar, required: true} + author: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + updated_at: + expires_at: { type: timestamp, required: true } + is_deleted: { type: boolean, default: false } + + + diff --git a/config/propel.ini b/config/propel.ini new file mode 100644 index 0000000..c60576c --- /dev/null +++ b/config/propel.ini @@ -0,0 +1,44 @@ +propel.targetPackage = lib.model +propel.packageObjectModel = true +propel.project = reaktor +propel.database = mysql +propel.database.createUrl = mysql://reaktor_user:cT0PHPCm@localhost/ +propel.database.url = mysql://reaktor_user:cT0PHPCm@localhost/reaktor + +propel.addGenericAccessors = true +propel.addGenericMutators = true +propel.addTimeStamp = false + +propel.schema.validate = false + +; directories +propel.home = . +propel.output.dir = ${reaktor_realdir} +propel.schema.dir = ${propel.output.dir}/config +propel.conf.dir = ${propel.output.dir}/config +propel.phpconf.dir = ${propel.output.dir}/config +propel.sql.dir = ${propel.output.dir}/data/sql +propel.runtime.conf.file = runtime-conf.xml +propel.php.dir = ${propel.output.dir} +propel.default.schema.basename = schema +propel.datadump.mapper.from = *schema.xml +propel.datadump.mapper.to = *data.xml + +; builder settings +propel.builder.peer.class = addon.propel.builder.SfPeerBuilder +propel.builder.object.class = addon.propel.builder.SfObjectBuilder + +propel.builder.objectstub.class = addon.propel.builder.SfExtensionObjectBuilder +propel.builder.peerstub.class = addon.propel.builder.SfExtensionPeerBuilder +propel.builder.objectmultiextend.class = addon.propel.builder.SfMultiExtendObjectBuilder +propel.builder.mapbuilder.class = addon.propel.builder.SfMapBuilderBuilder +propel.builder.interface.class = propel.engine.builder.om.php5.PHP5InterfaceBuilder +propel.builder.node.class = propel.engine.builder.om.php5.PHP5NodeBuilder +propel.builder.nodepeer.class = propel.engine.builder.om.php5.PHP5NodePeerBuilder +propel.builder.nodestub.class = propel.engine.builder.om.php5.PHP5ExtensionNodeBuilder +propel.builder.nodepeerstub.class = propel.engine.builder.om.php5.PHP5ExtensionNodePeerBuilder + +propel.builder.addIncludes = false +propel.builder.addComments = false + +propel.builder.addBehaviors = true diff --git a/config/properties.ini b/config/properties.ini new file mode 100644 index 0000000..fa2d0a2 --- /dev/null +++ b/config/properties.ini @@ -0,0 +1,2 @@ +[symfony] + name=reaktor diff --git a/config/reaktor_artwork-schema.yml b/config/reaktor_artwork-schema.yml new file mode 100644 index 0000000..30602a1 --- /dev/null +++ b/config/reaktor_artwork-schema.yml @@ -0,0 +1,23 @@ +propel: + _attributes: { package: lib.model } + + reaktor_artwork: + id: + user_id: { type: integer, foreignTable: sf_guard_user, required: true, foreignReference: id } + artwork_identifier: { type: varchar, size: 20, required: true } + created_at: { type: timestamp, required: true } + submitted_at: { type: timestamp, required: false } + actioned_at: { type: timestamp, required: false } + modified_flag: { type: timestamp, required: false} + title: { type: varchar, size: 255, required: true } + actioned_by: { type: integer, required: true } + status: { type: integer, foreignTable: artwork_status, required: true, foreignReference: id, onDelete: restrict } + description: { type: longvarchar } + modified_note: { type: longvarchar } + artwork_order: { type: integer, default: 0 } + average_rating: { type: float, default: 0 } + team_id: { type: integer, foreignTable: sf_guard_group, required: true, foreignReference: id } + under_discussion: { type: integer, size: 1, default: 0, required: true } + multi_user: { type: integer, size: 1, default: 0, required: true } + first_file_id: { type: integer, foreignTable: reaktor_file, foreignReference: id } + deleted: { type: integer, default: 0 } \ No newline at end of file diff --git a/config/reaktor_artwork_file-schema.yml b/config/reaktor_artwork_file-schema.yml new file mode 100644 index 0000000..45ec5d5 --- /dev/null +++ b/config/reaktor_artwork_file-schema.yml @@ -0,0 +1,7 @@ +propel: + _attributes: { package: lib.model } + + reaktor_artwork_file: + artwork_id: { type: integer, primaryKey: true, foreignTable: reaktor_artwork, required: true, foreignReference: id} + file_id: { type: integer, primaryKey: true, foreignTable: reaktor_file, required: true, foreignReference: id} + file_order: { type: integer, required: false, default: 1 } \ No newline at end of file diff --git a/config/reaktor_artwork_history-schema.yml b/config/reaktor_artwork_history-schema.yml new file mode 100644 index 0000000..8bb4dff --- /dev/null +++ b/config/reaktor_artwork_history-schema.yml @@ -0,0 +1,13 @@ +propel: + _attributes: { package: lib.model } + + reaktor_artwork_history: + id: + artwork_id: { type: integer, foreignTable: reaktor_artwork, foreignReference: id } + file_id: { type: integer, foreignTable: reaktor_artwork, foreignReference: id } + created_at: + #status_at: { type: timestamp, required: false } + modified_flag: { type: timestamp, required: false} + user_id: { type: integer, foreignTable: sf_guard_user, required: true, foreignReference: id } + status: { type: integer, foreignTable: artwork_status, required: true, foreignReference: id, onDelete: restrict } + comment: { type: longvarchar } diff --git a/config/reaktor_file-schema.yml b/config/reaktor_file-schema.yml new file mode 100644 index 0000000..aa419c8 --- /dev/null +++ b/config/reaktor_file-schema.yml @@ -0,0 +1,23 @@ +propel: + _attributes: { package: lib.model } + + reaktor_file: + id: + filename: { type: varchar, size: 200, required: true } + user_id: { type: integer, foreignTable: sf_guard_user, required: true, foreignReference: id } + realpath: { type: varchar, size: 300, required: true } + thumbpath: { type: varchar, size: 300, required: true } + originalpath: { type: varchar, size: 300, required: true } + original_mimetype_id: { type: integer, required: true} # These should be foreign keys but the propel joinall + converted_mimetype_id: { type: integer, required: true} # Command had issues with foreign keys that reference the + thumbnail_mimetype_id: { type: integer, required: true} # Same table... maybe it will be fixed in 1.1? + uploaded_at: { type: timestamp, required: true } + modified_at: { type: timestamp, required: true } + reported_at: { type: timestamp, required: false } + reported: { type: integer, size: 8, required: true, default: 0 } + total_reported_ever: { type: integer, size: 8, required: true, default: 0 } + marked_unsuitable: { type: integer, size: 1, required: true, default: 0 } + under_discussion: { type: integer, size: 1, required: true, default: 0 } + identifier: { type: varchar, required: true, size: 20 } + hidden: { type: integer, size: 1, default: 0, required: true } + deleted: { type: integer, default: 0 } \ No newline at end of file diff --git a/config/recommended_artwork-schema.yml b/config/recommended_artwork-schema.yml new file mode 100644 index 0000000..71bfbe3 --- /dev/null +++ b/config/recommended_artwork-schema.yml @@ -0,0 +1,10 @@ +propel: + _attributes: { package: lib.model } + + recommended_artwork: + id: + artwork: { type: integer, required: true, foreignTable: reaktor_artwork, foreignReference: id } + subreaktor: { type: integer, required: true, foreignTable: subreaktor, foreignReference: id } + localsubreaktor: { type: integer, foreignTable: subreaktor, foreignReference: id } + updated_by: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id} + updated_at: diff --git a/config/rejection_type-schema.yml b/config/rejection_type-schema.yml new file mode 100644 index 0000000..25c289e --- /dev/null +++ b/config/rejection_type-schema.yml @@ -0,0 +1,11 @@ +propel: + _attributes: { package: lib.model } + + rejection_type: + id: + basename: { type: varchar, size: 255, required: true} + + rejection_type_i18n: + id: + name: { type: varchar, size: 255, required: true} + description: { type: longvarchar, required: true} diff --git a/config/related_artwork-schema.yml b/config/related_artwork-schema.yml new file mode 100644 index 0000000..d18df67 --- /dev/null +++ b/config/related_artwork-schema.yml @@ -0,0 +1,10 @@ +propel: + _attributes: { package: lib.model } + + related_artwork: + id: + first_artwork: { type: integer, required: true, foreignTable: reaktor_artwork, foreignReference: id } + second_artwork: { type: integer, required: true, foreignTable: reaktor_artwork, foreignReference: id } + created_at: { type: timestamp, required: true } + created_by: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + order_by: { type: integer, required: false, default: 0 } \ No newline at end of file diff --git a/config/report_bookmark-schema.yml b/config/report_bookmark-schema.yml new file mode 100644 index 0000000..22afaa9 --- /dev/null +++ b/config/report_bookmark-schema.yml @@ -0,0 +1,10 @@ +propel: + _attributes: { package: lib.model } + + report_bookmark: + id: + title: { type: varchar, size: 255, required: true } + description: { type: longvarchar, required: true } + args: { type: longvarchar, required: true } + type: { type: varchar, size: 10, required: true, default: artwork } + list_order: { type: integer, default: 0 } \ No newline at end of file diff --git a/config/residence-schema.yml b/config/residence-schema.yml new file mode 100644 index 0000000..d6b1ac4 --- /dev/null +++ b/config/residence-schema.yml @@ -0,0 +1,16 @@ +propel: + _attributes: { package: lib.model } + + residence_level: + id: + levelname: { type: varchar, size: 255, required: true } + listorder: { type: integer, size: 2 } + + residence_level_i18n: + name: { type: varchar, size: 255, required: true } + + residence: + id: + name: { type: varchar, size: 255, required: true } + level: { type: integer, foreignTable: residence_level, required: true, foreignReference: id} + parent: { type: integer, required: false } \ No newline at end of file diff --git a/config/rsync_exclude.txt b/config/rsync_exclude.txt new file mode 100644 index 0000000..4b76ea8 --- /dev/null +++ b/config/rsync_exclude.txt @@ -0,0 +1,4 @@ +.svn +/web/uploads/* +/cache/* +/log/* diff --git a/config/sfGuardPlugin_schema.custom.yml b/config/sfGuardPlugin_schema.custom.yml new file mode 100644 index 0000000..6f42b92 --- /dev/null +++ b/config/sfGuardPlugin_schema.custom.yml @@ -0,0 +1,50 @@ + +propel: + _attributes: { package: plugins.sfGuardPlugin.lib.model } + + sf_guard_user: + _attributes: { phpName: sfGuardUser } + is_verified: { type: boolean, required: false, default: 0 } + show_content: { type: boolean, required: false, default: 0 } + culture: { type: varchar, size: 10, required: false, default: 'no' } + email: { type: varchar, size: 128, required: true } + email_private: { type: boolean, required: false, default: 1 } + new_email: { type: varchar, size: 128, required: false } + new_email_key: { type: varchar, size: 128, required: false } + new_password_key: { type: varchar, size: 128, required: false } + key_expires: { type: timestamp, required: false } + name: { type: varchar, size: 128, required: false } + name_private: { type: boolean, required: false, default: 0 } + dob: { type: bu_date, required: true } + sex: { type: integer, size: 1, required: true} + description: { type: longvarchar, required: false } + residence_id: { type: integer, required: true, foreignTable: residence, foreignReference: id } + avatar: { type: varchar, size: 255, required: false } + msn: { type: varchar, size: 128, required: false } + icq: { type: integer, required: false } + homepage: { type: varchar, size: 256, required: false } + phone: { type: varchar, size: 32, required: false } + opt_in: { type: boolean, required: false, default: 0 } + editorial_notification: { type: integer, required: false, default: 0 } + show_login_status: { type: integer, required: false, default: 1 } + last_active: { type: timestamp, required: false } + + # The following are import related - need_profile_check could also be used later, it's a flag to alert the user of possible issues + # in their profile information. First_reaktor_login is for historical purposes so we can see when people first hit the new Reaktor site + # We can also see how many "veteran" prototype users migrate, and how many choose not to. + dob_is_derived: { type: integer, required: true, default: 0 } + need_profile_check: { type: integer, size: 1, required: true, default: 0 } + first_reaktor_login: { type: timestamp, required: false } + + sf_guard_group: + _attributes: { phpName: sfGuardGroup } + is_editorial_team: { type: boolean, required: false, default: 0 } + is_enabled: { type: boolean, required: false, default: 0 } + + sf_guard_user_permission: + _attributes: { phpName: sfGuardUserPermission } + exclude: { type: boolean, required: false, default: 0 } + + sf_guard_permission_i18n: + _attributes: { phpName: sfGuardPermissionI18n } + description: { type: longvarchar, required: true } diff --git a/config/sfPropelActAsCommentableBehaviorPlugin_schema.custom.yml b/config/sfPropelActAsCommentableBehaviorPlugin_schema.custom.yml new file mode 100644 index 0000000..fba7d53 --- /dev/null +++ b/config/sfPropelActAsCommentableBehaviorPlugin_schema.custom.yml @@ -0,0 +1,32 @@ + + +propel: + _attributes: { package: plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model } + + # a comment applies to one Propel object + # a comment is defined by : + # - a title + # - a text + # - an author (set the related user model in app.yml) + # - a creation date + sf_comment: + _attributes: { phpName: sfComment, package: plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model } + id: { phpName: Id, type: integer, required: true, primaryKey: true, autoincrement: true } + parent_id: integer + commentable_model: varchar(30) + commentable_id: integer + namespace: varchar(50) + title: longvarchar + text: longvarchar + author_id: integer + author_name: varchar(50) + author_email: varchar(100) + created_at: + _indexes: + comments_index: [namespace, commentable_model, commentable_id] + object_index: [commentable_model, commentable_id] + author_index: [author_id] + _attributes: { phpName: sfComment, package: plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model } + unsuitable: { type: integer, required: true, default: 0 } + author_id: { type: integer, required: true, foreignTable: sf_guard_user, foreignReference: id } + email_notify: { type: integer, required: true, default: 0 } diff --git a/config/sfPropelActAsRatableBehaviorPlugin_schema.custom.yml b/config/sfPropelActAsRatableBehaviorPlugin_schema.custom.yml new file mode 100644 index 0000000..dff3760 --- /dev/null +++ b/config/sfPropelActAsRatableBehaviorPlugin_schema.custom.yml @@ -0,0 +1,7 @@ + +propel: + _attributes: { package: plugins.sfPropelActAsRatableBehaviorPlugin.lib.model } + + sf_ratings: + _attributes: { phpName: sfRating, package: plugins.sfPropelActAsRatableBehaviorPlugin.lib.model } + rated_at: { type: timestamp, required: true } diff --git a/config/sfPropelActAsTaggableBehaviorPlugin_schema.custom.yml b/config/sfPropelActAsTaggableBehaviorPlugin_schema.custom.yml new file mode 100644 index 0000000..3b8931c --- /dev/null +++ b/config/sfPropelActAsTaggableBehaviorPlugin_schema.custom.yml @@ -0,0 +1,15 @@ + +propel: + _attributes: { package: plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model } + + tag: + _attributes: { phpName: Tag, package: plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model } + approved: { type: tinyint, required: true, default: 0 } + approved_by: { type: integer, foreignTable: sf_guard_user, required: false, foreignReference: id } + approved_at: { type: timestamp, required: false } + width: { type: integer, required: false } + + tagging: + parent_approved: { type: tinyint, required: true, default: 0 } + tag_id: { foreignTable: tag, foreignReference: id, required: true, type: integer } + parent_user_id: { foreignTable: sf_guard_user, foreignReference: id, required: true, type: integer } \ No newline at end of file diff --git a/config/subreaktor-schema.yml b/config/subreaktor-schema.yml new file mode 100644 index 0000000..ce8e694 --- /dev/null +++ b/config/subreaktor-schema.yml @@ -0,0 +1,12 @@ +propel: + _attributes: { package: lib.model } + + subreaktor: + id: + reference: { type: varchar, size: 15, required: true } + lokalreaktor: { type: boolean, required: true, default: false } + live: { type: boolean, required: true, default: false } + subreaktor_order: { type: integer, required: false, default: 0 } + + subreaktor_i18n: + name: { type: varchar, size: 255, required: true } \ No newline at end of file diff --git a/config/subreaktor_identifier-schema.yml b/config/subreaktor_identifier-schema.yml new file mode 100644 index 0000000..22b8651 --- /dev/null +++ b/config/subreaktor_identifier-schema.yml @@ -0,0 +1,10 @@ +# Links subreaktors to file types, the same as the ones in file table "identifier" +# Used by artwork edit for example, when choosing a subreaktor based on the uploaded file + +propel: + _attributes: { package: lib.model } + + subreaktor_identifier: + id: + subreaktor_id: { type: integer, required: true, foreignTable: subreaktor, foreignReference: id } + identifier: { type: varchar, required: true, size: 20 } \ No newline at end of file diff --git a/config/subreaktorartwork-schema.yml b/config/subreaktorartwork-schema.yml new file mode 100644 index 0000000..39be3df --- /dev/null +++ b/config/subreaktorartwork-schema.yml @@ -0,0 +1,7 @@ +propel: + _attributes: { package: lib.model } + + subreaktor_artwork: + id: + subreaktor_id: { type: integer, required: true, foreignTable: subreaktor, foreignReference: id } + artwork_id: { type: integer, required: true, foreignTable: reaktor_artwork, foreignReference: id } \ No newline at end of file diff --git a/config/translation_schema.yml b/config/translation_schema.yml new file mode 100644 index 0000000..e13171f --- /dev/null +++ b/config/translation_schema.yml @@ -0,0 +1,26 @@ +propel: + _attributes: { package: lib.model } + + catalogue: + cat_id: { type: integer, size: 11, required: true, autoincrement: true, primaryKey: true } + name: { type: varchar, size: 100, required: true, default: '' } + source_lang: { type: varchar, size: 100, required: true, default: '' } + target_lang: { type: varchar, size: 100, required: true, default: '' } + date_created: { type: integer, size: 11, required: true, default: 0 } + date_modified: { type: integer, size: 11, required: true, default: 0 } + author: { type: varchar, size: 255, required: true, default: '' } + description: { type: varchar, size: 255, required: true, default: '' } + + trans_unit: + msg_id: { type: integer, size: 11, required: true, autoincrement: true, primaryKey: true } + cat_id: { type: integer, size: 11, required: true, default: 1, foreignTable: catalogue, foreignReference: cat_id } + id: { type: varchar, size: 255, default: '' } + source: { type: longvarchar, required: true } + target: { type: longvarchar, required: true } + module: { type: varchar, size: 255, default: '' } + filename: { type: varchar, size: 255, default: '' } + comments: { type: longvarchar } + date_added: { type: integer, size: 11, required: true, default: 0 } + date_modified: { type: integer, size: 11, required: true, default: 0 } + author: { type: varchar, size: 255, required: true, default: ''} + translated: { type: boolean, size: 1, required: true, default: 0 } diff --git a/config/user_interest-schema.yml b/config/user_interest-schema.yml new file mode 100644 index 0000000..6dc2433 --- /dev/null +++ b/config/user_interest-schema.yml @@ -0,0 +1,6 @@ +propel: + _attributes: { package: lib.model } + + user_interest: + user_id: {type: integer, primaryKey: true, required: true, foreignTable: sf_guard_user, foreignReference: id, onDelete: cascade} + subreaktor_id: {type: integer, primaryKey: true, required: true, foreignTable: subreaktor, foreignReference: id, onDelete: cascade} diff --git a/config/user_resource-schema.yml b/config/user_resource-schema.yml new file mode 100644 index 0000000..d134513 --- /dev/null +++ b/config/user_resource-schema.yml @@ -0,0 +1,7 @@ +propel: + _attributes: { package: lib.model } + + user_resource: + id: + user_id: {type: integer, primaryKey: true, required: true, foreignTable: sf_guard_user, foreignReference: id, onDelete: cascade} + url: {type: varchar, size: 255, required: true} diff --git a/content/audio/thumbnail/default.gif b/content/audio/thumbnail/default.gif new file mode 100644 index 0000000..95fa538 Binary files /dev/null and b/content/audio/thumbnail/default.gif differ diff --git a/content/audio/thumbnail/mini/default.gif b/content/audio/thumbnail/mini/default.gif new file mode 100644 index 0000000..2e53f1f Binary files /dev/null and b/content/audio/thumbnail/mini/default.gif differ diff --git a/content/flash_animation/thumbnail/default.gif b/content/flash_animation/thumbnail/default.gif new file mode 100755 index 0000000..d116152 Binary files /dev/null and b/content/flash_animation/thumbnail/default.gif differ diff --git a/content/flash_animation/thumbnail/mini/default.gif b/content/flash_animation/thumbnail/mini/default.gif new file mode 100755 index 0000000..19ff8d8 Binary files /dev/null and b/content/flash_animation/thumbnail/mini/default.gif differ diff --git a/content/image/thumbnail/default.gif b/content/image/thumbnail/default.gif new file mode 100644 index 0000000..bd5949e Binary files /dev/null and b/content/image/thumbnail/default.gif differ diff --git a/content/image/thumbnail/mini/default.gif b/content/image/thumbnail/mini/default.gif new file mode 100644 index 0000000..f45de6f Binary files /dev/null and b/content/image/thumbnail/mini/default.gif differ diff --git a/content/pdf/thumbnail/default.gif b/content/pdf/thumbnail/default.gif new file mode 100644 index 0000000..f5b6174 Binary files /dev/null and b/content/pdf/thumbnail/default.gif differ diff --git a/content/pdf/thumbnail/mini/default.gif b/content/pdf/thumbnail/mini/default.gif new file mode 100644 index 0000000..cf088e8 Binary files /dev/null and b/content/pdf/thumbnail/mini/default.gif differ diff --git a/content/text/thumbnail/default.gif b/content/text/thumbnail/default.gif new file mode 100644 index 0000000..f5b6174 Binary files /dev/null and b/content/text/thumbnail/default.gif differ diff --git a/content/text/thumbnail/mini/default.gif b/content/text/thumbnail/mini/default.gif new file mode 100644 index 0000000..cf088e8 Binary files /dev/null and b/content/text/thumbnail/mini/default.gif differ diff --git a/content/video/thumbnail/default.gif b/content/video/thumbnail/default.gif new file mode 100644 index 0000000..d116152 Binary files /dev/null and b/content/video/thumbnail/default.gif differ diff --git a/content/video/thumbnail/mini/default.gif b/content/video/thumbnail/mini/default.gif new file mode 100644 index 0000000..19ff8d8 Binary files /dev/null and b/content/video/thumbnail/mini/default.gif differ diff --git a/data/fixtures/00fixtures.yml b/data/fixtures/00fixtures.yml new file mode 100644 index 0000000..edc3d1a --- /dev/null +++ b/data/fixtures/00fixtures.yml @@ -0,0 +1,2964 @@ +## This file should contain data that will carry over into the production server +## Should be included first to comply with foreign key constraints + +## The other files contain test/temporary data for the development environment +## Must be loaded in the correct order to satisfy foreign key dependencies +## hence the numeric index at the start of the filename + +## Feel free to break the files up more if they become unmanageable... +## Note: Some of the tags will also be part of the static fixtures, for example the category tags + +ArtworkStatus: + ArtworkStatus_1: + name: Draft + ArtworkStatus_2: + name: Ready for approval + ArtworkStatus_3: + name: Approved + ArtworkStatus_4: + name: Rejected + ArtworkStatus_5: + name: Removed + ArtworkStatus_6: + name: Approved hidden + +ArtworkStatusI18n: + ArtworkStatus_1_no: + description: Draft + id: ArtworkStatus_1 + culture: 'no' + ArtworkStatus_1_en: + description: Draft + id: ArtworkStatus_1 + culture: 'en' + ArtworkStatus_1_nn: + description: Draft + id: ArtworkStatus_1 + culture: 'nn' + ArtworkStatus_2_no: + description: Ready for approval + id: ArtworkStatus_2 + culture: 'no' + ArtworkStatus_2_en: + description: Ready for approval + id: ArtworkStatus_2 + culture: 'en' + ArtworkStatus_2_nn: + description: Ready for approval + id: ArtworkStatus_2 + culture: 'nn' + ArtworkStatus_3_no: + description: Approved + id: ArtworkStatus_3 + culture: 'no' + ArtworkStatus_3_en: + description: Approved + id: ArtworkStatus_3 + culture: 'en' + ArtworkStatus_3_nn: + description: Approved + id: ArtworkStatus_3 + culture: 'nn' + ArtworkStatus_4_no: + description: Rejected + id: ArtworkStatus_4 + culture: 'no' + ArtworkStatus_4_en: + description: Rejected + id: ArtworkStatus_4 + culture: 'en' + ArtworkStatus_4_nn: + description: Rejected + id: ArtworkStatus_4 + culture: 'nn' + ArtworkStatus_5_no: + description: Removed + id: ArtworkStatus_5 + culture: 'no' + ArtworkStatus_5_en: + description: Removed + id: ArtworkStatus_5 + culture: 'en' + ArtworkStatus_5_nn: + description: Removed + id: ArtworkStatus_5 + culture: 'nn' + ArtworkStatus_6_no: + description: "Approved hidden" + id: ArtworkStatus_6 + culture: 'no' + ArtworkStatus_6_en: + description: "Approved hidden" + id: ArtworkStatus_6 + culture: 'en' + ArtworkStatus_6_nn: + description: "Approved hidden" + id: ArtworkStatus_6 + culture: 'nn' + +ResidenceLevel: + ResidenceLevel_1: + levelname: Bydel + listorder: 2 + ResidenceLevel_2: + levelname: By + listorder: 1 + ResidenceLevel_3: + levelname: Kommune + listorder: 3 + ResidenceLevel_4: + levelname: Fylke + listorder: 4 + ResidenceLevel_5: + levelname: Annet + listorder: 5 + +ResidenceLevelI18n: + ResidenceLevel_1_no: + name: Bydel + id: ResidenceLevel_1 + culture: 'no' + ResidenceLevel_1_en: + name: District + id: ResidenceLevel_1 + culture: 'en' + ResidenceLevel_1_nn: + name: Bydel + id: ResidenceLevel_1 + culture: 'nn' + ResidenceLevel_2_no: + name: By + id: ResidenceLevel_2 + culture: 'no' + ResidenceLevel_2_en: + name: City + id: ResidenceLevel_2 + culture: 'en' + ResidenceLevel_2_nn: + name: By + id: ResidenceLevel_2 + culture: 'nn' + ResidenceLevel_3_no: + name: Kommune + id: ResidenceLevel_3 + culture: 'no' + ResidenceLevel_3_en: + name: Municipality + id: ResidenceLevel_3 + culture: 'en' + ResidenceLevel_3_nn: + name: Kommune + id: ResidenceLevel_3 + culture: 'nn' + ResidenceLevel_4_no: + name: Fylke + id: ResidenceLevel_4 + culture: 'no' + ResidenceLevel_4_en: + name: County + id: ResidenceLevel_4 + culture: 'en' + ResidenceLevel_4_nn: + name: Fylkje + id: ResidenceLevel_4 + culture: 'nn' + ResidenceLevel_5_no: + name: Annet + id: ResidenceLevel_5 + culture: 'no' + ResidenceLevel_5_en: + name: Other + id: ResidenceLevel_5 + culture: 'en' + ResidenceLevel_5_nn: + name: Anna + id: ResidenceLevel_5 + culture: 'nn' + + +Residence: + Residence_1: + name: Akershus + level: ResidenceLevel_4 + Residence_2: + name: Aust-Agder + level: ResidenceLevel_4 + Residence_3: + name: Buskerud + level: ResidenceLevel_4 + Residence_4: + name: Finnmark + level: ResidenceLevel_4 + Residence_5: + name: Hedmark + level: ResidenceLevel_4 + Residence_6: + name: Hordaland + level: ResidenceLevel_4 + Residence_7: + name: Møre og Romsdal + level: ResidenceLevel_4 + Residence_8: + name: Nordland + level: ResidenceLevel_4 + Residence_9: + name: Nord-Trøndelag + level: ResidenceLevel_4 + Residence_10: + name: Oppland + level: ResidenceLevel_4 + Residence_11: + name: Rogaland + level: ResidenceLevel_4 + Residence_12: + name: Sogn og Fjordane + level: ResidenceLevel_4 + Residence_13: + name: Sør-Trøndelag + level: ResidenceLevel_4 + Residence_14: + name: Telemark + level: ResidenceLevel_4 + Residence_15: + name: Troms + level: ResidenceLevel_4 + Residence_16: + name: Vest-Agder + level: ResidenceLevel_4 + Residence_17: + name: Vestfold + level: ResidenceLevel_4 + Residence_18: + name: Østfold + level: ResidenceLevel_4 + Residence_19: + name: Bergen + level: ResidenceLevel_2 + Residence_20: + name: Groruddalen + level: ResidenceLevel_1 + Residence_21: + name: Kristiansand + level: ResidenceLevel_2 + Residence_22: + name: Lillehammer + level: ResidenceLevel_2 + Residence_23: + name: Oslo + level: ResidenceLevel_2 + Residence_24: + name: Stavanger + level: ResidenceLevel_2 + Residence_25: + name: Tromsø + level: ResidenceLevel_2 + Residence_26: + name: Trondheim + level: ResidenceLevel_2 + Residence_27: + name: Skandinavia + level: ResidenceLevel_5 + Residence_28: + name: Norden + level: ResidenceLevel_5 + Residence_29: + name: Europa + level: ResidenceLevel_5 + Residence_30: + name: Amerika + level: ResidenceLevel_5 + Residence_31: + name: Afrika + level: ResidenceLevel_5 + Residence_32: + name: Oceania + level: ResidenceLevel_5 + Residence_33: + name: Asia + level: ResidenceLevel_5 + + + + + +FileMimetype: + FileMimetype_1: + mimetype: image/png + identifier: image + FileMimetype_2: + mimetype: image/jpeg + identifier: image + FileMimetype_3: + mimetype: application/pdf + identifier: pdf + FileMimetype_4: + mimetype: video/flv + identifier: video + FileMimetype_5: + mimetype: audio/mpeg + identifier: audio + FileMimetype_6: + mimetype: application/x-shockwave-flash + identifier: flash_animation + FileMimetype_7: + mimetype: image/gif + identifier: image + FileMimetype_8: + mimetype: image/tiff + identifier: image + FileMimetype_9: + mimetype: text/plain + identifier: text + FileMimetype_10: + mimetype: video/mpeg + identifier: video + FileMimetype_11: + mimetype: video/quicktime + identifier: video + FileMimetype_12: + mimetype: video/x-msvideo + identifier: container + FileMimetype_13: + mimetype: video/ogg + identifier: video + FileMimetype_14: + mimetype: audio/ogg + identifier: audio + FileMimetype_15: + mimetype: audio/flac + identifier: audio + FileMimetype_16: + mimetype: application/ogg + identifier: video + FileMimetype_17: + mimetype: audio/x-wav + identifier: audio + FileMimetype_18: + mimetype: video/avi + identifier: video + FileMimetype_19: + mimetype: video/x-ms-wmv + identifier: video + FileMimetype_20: + mimetype: video/mp4 + identifier: video + FileMimetype_21: + mimetype: audio/mid + identifier: audio + FileMimetype_22: + mimetype: image/pjpeg + identifier: image + FileMimetype_23: + mimetype: audio/x-ms-wma + identifier: audio + FileMimetype_24: + mimetype: image/x-png + identifier: image + FileMimetype_25: + mimetype: audio/wav + identifier: audio + FileMimetype_26: + mimetype: audio/midi + identifier: audio + FileMimetype_27: + mimetype: text/html + identifier: text + FileMimetype_28: + mimetype: application/octet-stream + identifier: container + FileMimetype_29: + mimetype: video/x-flv + identifier: video + FileMimetype_30: + mimetype: image/jpg + identifier: image + FileMimeType_31: + mimetype: video/x-ms-asf + identifier: container + FileMimeType_32: + mimetype: audio/x-vorbis+ogg + identifier: audio + FileMimeType_33: + mimetype: video/x-theora+ogg + identifier: video + +Subreaktor: + Subreaktor_1: + reference: foto + live: true + subreaktor_order: 1 + Subreaktor_2: + reference: tegning + live: true + subreaktor_order: 2 + Subreaktor_3: + reference: film + live: true + subreaktor_order: 3 + Subreaktor_4: + reference: lyd + live: true + subreaktor_order: 4 + Subreaktor_5: + reference: tegneserier + live: true + subreaktor_order: 5 + Subreaktor_6: + reference: tekst + live: true + subreaktor_order: 6 + Subreaktor_7: + reference: groruddalen + live: true + lokalreaktor: true + subreaktor_order: 7 + +SubreaktorI18n: + Subreaktor_1_no: + name: Foto + id: Subreaktor_1 + culture: 'no' + Subreaktor_1_nn: + name: Foto + id: Subreaktor_1 + culture: nn + Subreaktor_1_en: + name: Photo + id: Subreaktor_1 + culture: en + Subreaktor_2_no: + name: Tegning/grafikk + id: Subreaktor_2 + culture: 'no' + Subreaktor_2_nn: + name: Tegning/grafikk + id: Subreaktor_2 + culture: nn + Subreaktor_2_en: + name: Drawing/graphics + id: Subreaktor_2 + culture: en + Subreaktor_3_no: + name: Film/animasjon + id: Subreaktor_3 + culture: 'no' + Subreaktor_3_nn: + name: Film/animasjon + id: Subreaktor_3 + culture: nn + Subreaktor_3_en: + name: Movie/animation + id: Subreaktor_3 + culture: en + Subreaktor_4_no: + name: Lyd/musikk + id: Subreaktor_4 + culture: 'no' + Subreaktor_4_nn: + name: Lyd/musikk + id: Subreaktor_4 + culture: nn + Subreaktor_4_en: + name: Sound/music + id: Subreaktor_4 + culture: en + Subreaktor_5_no: + name: Tegneserier + id: Subreaktor_5 + culture: 'no' + Subreaktor_5_nn: + name: Tegneserier + id: Subreaktor_5 + culture: nn + Subreaktor_5_en: + name: Cartoons + id: Subreaktor_5 + culture: en + Subreaktor_6_no: + name: Tekst + id: Subreaktor_6 + culture: 'no' + Subreaktor_6_nn: + name: Tekst + id: Subreaktor_6 + culture: nn + Subreaktor_6_en: + name: Text + id: Subreaktor_6 + culture: en + Subreaktor_7_no: + name: GroruddalsReaktor + id: Subreaktor_7 + culture: 'no' + Subreaktor_7_nn: + name: GroruddalsReaktor + id: Subreaktor_7 + culture: nn + Subreaktor_7_en: + name: GroruddalsReaktor + id: Subreaktor_7 + culture: en + +RejectionType: + RejectionType_1: + basename: Copyright violation + RejectionType_2: + basename: Unsuitable artwork content + RejectionType_3: + basename: Question of ownership + RejectionType_4: + basename: Unsuitable description of content + RejectionType_5: + basename: Other + +RejectionTypeI18n: + RejectionType_1_no: + id: RejectionType_1 + culture: 'no' + name: Copyright violation + description: This artwork is a copyright violation, and will not be displayed on reaktor. + RejectionType_1_en: + id: RejectionType_1 + culture: en + name: Copyright violation + description: This artwork is a copyright violation, and will not be displayed on reaktor. + RejectionType_1_nn: + id: RejectionType_1 + culture: nn + name: Copyright violation + description: This artwork is a copyright violation, and will not be displayed on reaktor. + RejectionType_2_no: + id: RejectionType_2 + culture: 'no' + name: Unsuitable artwork content + description: This artwork has unsuitable content that Reaktor cannot display. + RejectionType_2_en: + id: RejectionType_2 + culture: en + name: Unsuitable artwork content + description: This artwork has unsuitable content that Reaktor cannot display. + RejectionType_2_nn: + id: RejectionType_2 + culture: nn + name: Unsuitable artwork content + description: This artwork has unsuitable content that Reaktor cannot display. + RejectionType_3_no: + id: RejectionType_3 + culture: 'no' + name: Question of ownership + description: There are evidence indicating you are not the correct author of this artwork. + RejectionType_3_en: + id: RejectionType_3 + culture: en + name: Question of ownership + description: There are evidence indicating you are not the correct author of this artwork. + RejectionType_3_nn: + id: RejectionType_3 + culture: nn + name: Question of ownership + description: There are evidence indicating you are not the correct author of this artwork. + RejectionType_4_no: + id: RejectionType_4 + culture: 'no' + name: Unsuitable description of content + description: Your description of the artwork is completely wrong. + RejectionType_4_en: + id: RejectionType_4 + culture: en + name: Unsuitable description of content + description: Your description of the artwork is completely wrong. + RejectionType_4_nn: + id: RejectionType_4 + culture: nn + name: Unsuitable description of content + description: Your description of the artwork is completely wrong. + RejectionType_5_no: + id: RejectionType_5 + culture: 'no' + name: Other + description: Your artwork has been rejected. + RejectionType_5_en: + id: RejectionType_5 + culture: en + name: Other + description: Your artwork has been rejected. + RejectionType_5_nn: + id: RejectionType_5 + culture: nn + name: Other + description: Your artwork has been rejected. + +sfGuardGroup: + sfGuardGroup_1: + name: admin + description: Administrator group + is_editorial_team: 0 + is_enabled: 0 + sfGuardGroup_2: + name: users + description: > + Normal users who can interact on the + site + is_editorial_team: 0 + is_enabled: 0 + sfGuardGroup_3: + name: staff + description: Staff group + is_editorial_team: 0 + is_enabled: 0 + sfGuardGroup_4: + name: translators + description: Translator group + is_editorial_team: 0 + is_enabled: 0 + sfGuardGroup_5: + name: deichman_redaksjon + description: Deichman + is_editorial_team: 1 + is_enabled: 1 + sfGuardGroup_6: + name: musikk_redaksjon + description: Musikk + is_editorial_team: 1 + is_enabled: 1 + sfGuardGroup_7: + name: serieteket_redaksjon + description: Serieteket + is_editorial_team: 1 + is_enabled: 1 + sfGuardGroup_8: + name: trondheim_redaksjon + description: Trondheim + is_editorial_team: 1 + is_enabled: 1 + sfGuardGroup_9: + name: groruddalen_redaksjon + description: Groruddalen + is_editorial_team: 1 + is_enabled: 1 + sfGuardGroup_10: + name: konkurranse_redaksjon + description: Competitions editorial team + is_editorial_team: 1 + is_enabled: 1 + sfGuardGroup_11: + name: publishers + description: Publisher group + is_editorial_team: 0 + is_enabled: 0 + +HistoryAction: + HistoryAction_1: + name: File reported + HistoryAction_2: + name: File removed + HistoryAction_3: + name: File restored + HistoryAction_4: + name: Tag approved + HistoryAction_5: + name: Article Created + HistoryAction_6: + name: File marked for discussion + HistoryAction_7: + name: File unmarked from discussion + HistoryAction_8: + name: Artwork marked for discussion + HistoryAction_9: + name: Artwork unmarked from discussion + HistoryAction_10: + name: Article edited + + +HistoryActionI18n: + HistoryAction_1_no: + id: HistoryAction_1 + culture: 'no' + description: Fil rapportert + HistoryAction_2_no: + id: HistoryAction_2 + culture: 'no' + description: Fil fjernet + HistoryAction_3_no: + id: HistoryAction_3 + culture: 'no' + description: Fil gjenopprettet + HistoryAction_4_no: + id: HistoryAction_4 + culture: 'no' + description: Tag godkjent + HistoryAction_5_no: + id: HistoryAction_5 + culture: 'no' + description: Artikkel opprettet + HistoryAction_6_no: + id: HistoryAction_6 + culture: 'no' + description: Fil markert for diskusjon + HistoryAction_7_no: + id: HistoryAction_7 + culture: 'no' + description: Fil fjernet fra diskusjonen + HistoryAction_8_no: + id: HistoryAction_8 + culture: 'no' + description: Verk merket for diskusjon + HistoryAction_9_no: + id: HistoryAction_9 + culture: 'no' + description: Verk fjernet fra diskusjonen + HistoryAction_10_no: + id: HistoryAction_10 + culture: 'no' + description: Artikkel endret + +Catalogue: + Catalogue_1: + name: messages.no + source_lang: en + target_lang: 'no' + date_created: 0 + date_modified: 1197401129 + author: username + description: Bokmål + Catalogue_2: + name: messages.nn + source_lang: en + target_lang: nn + date_created: 0 + date_modified: 1197401130 + author: username + description: Nynorsk + Catalogue_3: + name: messages.en + source_lang: en + target_lang: en + date_created: 0 + date_modified: 1197401102 + author: username + description: English + +sfGuardPermission: + sfGuardPermission_1: + name: staff + sfGuardPermission_2: + name: listgroup + sfGuardPermission_3: + name: editgroup + sfGuardPermission_4: + name: deletegroup + sfGuardPermission_5: + name: listpermission + sfGuardPermission_6: + name: editpermission + sfGuardPermission_7: + name: deletepermission + sfGuardPermission_8: + name: listuser + sfGuardPermission_9: + name: edituser + sfGuardPermission_10: + name: deleteuser + sfGuardPermission_11: + name: editprofile + sfGuardPermission_12: + name: viewallcontent + sfGuardPermission_13: + name: viewdetailederrors + sfGuardPermission_14: + name: editusercontent + sfGuardPermission_15: + name: isuser + sfGuardPermission_16: + name: deletecontent + sfGuardPermission_17: + name: approveartwork + sfGuardPermission_18: + name: approvetags + sfGuardPermission_19: + name: commentadmin + sfGuardPermission_20: + name: tagadministrator + sfGuardPermission_21: + name: subreaktoradministrator + sfGuardPermission_22: + name: subreaktorcategorizer + sfGuardPermission_23: + name: translator + sfGuardPermission_24: + name: viewmetadata + sfGuardPermission_25: + name: debug + sfGuardPermission_26: + name: discussartwork + sfGuardPermission_27: + name: recommendartwork + sfGuardPermission_28: + name: sendcommentstoall + sfGuardPermission_29: + name: adminmessages + sfGuardPermission_30: + name: postnewcomments + sfGuardPermission_31: + name: uploadcontent + sfGuardPermission_32: + name: sendmessages + sfGuardPermission_33: + name: rateartwork + sfGuardPermission_34: + name: markfavourite + sfGuardPermission_35: + name: addresources + sfGuardPermission_36: + name: reruntranscoding + sfGuardPermission_37: + name: createresidence + sfGuardPermission_38: + name: deleteresidence + sfGuardPermission_39: + name: listresidences + sfGuardPermission_40: + name: viewreports + sfGuardPermission_41: + name: phpmyadmin + sfGuardPermission_42: + name: editcategories + sfGuardPermission_43: + name: createcompositeartwork + sfGuardPermission_44: + name: createhelparticle + sfGuardPermission_45: + name: createthemearticle + sfGuardPermission_46: + name: createinternalarticle + sfGuardPermission_47: + name: createfooterarticle + sfGuardPermission_48: + name: createmypagearticle + sfGuardPermission_49: + name: createregulararticle + sfGuardPermission_50: + name: createspecialarticle + sfGuardPermission_51: + name: adminfunctions + sfGuardPermission_52: + name: managenotifications + sfGuardPermission_53: + name: createsystemadminmessages + sfGuardPermission_54: + name: listsystemadminmessages + sfGuardPermission_55: + name: deletesystemadminmessages + sfGuardPermission_56: + name: downloadoriginalfile + sfGuardPermission_57: + name: viewothereditorialteams + +sfGuardPermissionI18n: + sfGuardPermissionI18n_1_en: + id: sfGuardPermission_1 + culture: en + description: > + Show admin links such as moderator box + and admin portal + sfGuardPermissionI18n_2_en: + id: sfGuardPermission_2 + culture: en + description: Can list/view groups + sfGuardPermissionI18n_3_en: + id: sfGuardPermission_3 + culture: en + description: Can edit groups + sfGuardPermissionI18n_4_en: + id: sfGuardPermission_4 + culture: en + description: Can delete groups + sfGuardPermissionI18n_5_en: + id: sfGuardPermission_5 + culture: en + description: Can list/view permissions + sfGuardPermissionI18n_6_en: + id: sfGuardPermission_6 + culture: en + description: Can edit permissions + sfGuardPermissionI18n_7_en: + id: sfGuardPermission_7 + culture: en + description: Can delete permissions + sfGuardPermissionI18n_8_en: + id: sfGuardPermission_8 + culture: en + description: Can list/view users + sfGuardPermissionI18n_9_en: + id: sfGuardPermission_9 + culture: en + description: Can edit users + sfGuardPermissionI18n_10_en: + id: sfGuardPermission_10 + culture: en + description: Can delete users + sfGuardPermissionI18n_11_en: + id: sfGuardPermission_11 + culture: en + description: Can edit any users profile + sfGuardPermissionI18n_12_en: + id: sfGuardPermission_12 + culture: en + description: > + Can view all content, including + unmoderated + sfGuardPermissionI18n_13_en: + id: sfGuardPermission_13 + culture: en + description: > + Will see enhanced error messages where + available + sfGuardPermissionI18n_14_en: + id: sfGuardPermission_14 + culture: en + description: Can edit file/artwork details + sfGuardPermissionI18n_15_en: + id: sfGuardPermission_15 + culture: en + description: > + Is a registered user (used for yml + checks) + sfGuardPermissionI18n_16_en: + id: sfGuardPermission_16 + culture: en + description: Can delete files from the system + sfGuardPermissionI18n_17_en: + id: sfGuardPermission_17 + culture: en + description: Can approve artworks + sfGuardPermissionI18n_18_en: + id: sfGuardPermission_18 + culture: en + description: Can approve and delete tags on artworks + sfGuardPermissionI18n_19_en: + id: sfGuardPermission_19 + culture: en + description: Can administer comments + sfGuardPermissionI18n_20_en: + id: sfGuardPermission_20 + culture: en + description: Can remove tags from the system + sfGuardPermissionI18n_21_en: + id: sfGuardPermission_21 + culture: en + description: Can add/remove/edit subreaktors + sfGuardPermissionI18n_22_en: + id: sfGuardPermission_22 + culture: en + description: Can add/remove/edit subreaktor tags + sfGuardPermissionI18n_23_en: + id: sfGuardPermission_23 + culture: en + description: Can access the translation interface + sfGuardPermissionI18n_24_en: + id: sfGuardPermission_24 + culture: en + description: Can view artwork/file metadata + sfGuardPermissionI18n_25_en: + id: sfGuardPermission_25 + culture: en + description: > + Can view extra debug information on the + site + sfGuardPermissionI18n_26_en: + id: sfGuardPermission_26 + culture: en + description: > + Can view and discuss artwork under + discussion + sfGuardPermissionI18n_27_en: + id: sfGuardPermission_27 + culture: en + description: Can mark artwork as recommended + sfGuardPermissionI18n_28_en: + id: sfGuardPermission_28 + culture: en + description: Can send comments to all users + sfGuardPermissionI18n_29_en: + id: sfGuardPermission_29 + culture: en + description: Can create admin messages + sfGuardPermissionI18n_30_en: + id: sfGuardPermission_30 + culture: en + description: Can post new comments + sfGuardPermissionI18n_31_en: + id: sfGuardPermission_31 + culture: en + description: Can upload new content + sfGuardPermissionI18n_32_en: + id: sfGuardPermission_32 + culture: en + description: Can send messages to other users + sfGuardPermissionI18n_33_en: + id: sfGuardPermission_33 + culture: en + description: Can rate artwork + sfGuardPermissionI18n_34_en: + id: sfGuardPermission_34 + culture: en + description: Can mark users or artworks as favourites + sfGuardPermissionI18n_35_en: + id: sfGuardPermission_35 + culture: en + description: Can add resources to their profile + sfGuardPermissionI18n_36_en: + id: sfGuardPermission_36 + culture: en + description: Can re-run transcoding if failed + sfGuardPermissionI18n_37_en: + id: sfGuardPermission_37 + culture: en + description: Can add a new residence + sfGuardPermissionI18n_38_en: + id: sfGuardPermission_38 + culture: en + description: Can delete a residence + sfGuardPermissionI18n_39_en: + id: sfGuardPermission_39 + culture: en + description: Can list all residences + sfGuardPermissionI18n_40_en: + id: sfGuardPermission_40 + culture: en + description: Can view and create reports + sfGuardPermissionI18n_41_en: + id: sfGuardPermission_41 + culture: en + description: Can use PHPMyAdmin with read only user + sfGuardPermissionI18n_42_en: + id: sfGuardPermission_42 + culture: en + description: Can add/remove categories on all artwork + sfGuardPermissionI18n_43_en: + id: sfGuardPermission_43 + culture: en + description: can create multi-user composite artwork + sfGuardPermissionI18n_44_en: + id: sfGuardPermission_44 + culture: en + description: can create a help article + sfGuardPermissionI18n_45_en: + id: sfGuardPermission_45 + culture: en + description: can create a theme article + sfGuardPermissionI18n_46_en: + id: sfGuardPermission_46 + culture: en + description: can create an internal article + sfGuardPermissionI18n_47_en: + id: sfGuardPermission_47 + culture: en + description: can create a footer article + sfGuardPermissionI18n_48_en: + id: sfGuardPermission_48 + culture: en + description: can create a mypage article + sfGuardPermissionI18n_49_en: + id: sfGuardPermission_49 + culture: en + description: can create a regular article + sfGuardPermissionI18n_50_en: + id: sfGuardPermission_50 + culture: en + description: can create a special article + sfGuardPermissionI18n_51_en: + id: sfGuardPermission_51 + culture: en + description: can access special admin functions + sfGuardPermissionI18n_52_en: + id: sfGuardPermission_52 + culture: en + description: can manage other users notification settings + sfGuardPermissionI18n_53_en: + id: sfGuardPermission_53 + culture: en + description: Can create system messages + sfGuardPermissionI18n_54_en: + id: sfGuardPermission_54 + culture: en + description: Can see system message list + sfGuardPermissionI18n_55_en: + id: sfGuardPermission_55 + culture: en + description: Can delete system messages + sfGuardPermissionI18n_56_en: + id: sfGuardPermission_56 + culture: en + description: Can download original files + sfGuardPermissionI18n_57_en: + id: sfGuardPermission_57 + culture: en + description: Can see artwork awaiting approval by other editorial teams + sfGuardPermissionI18n_1_no: + id: sfGuardPermission_1 + culture: "no" + description: > + Tilgang til å se admin-meny og + moderator-boks, samt admin-portalen + sfGuardPermissionI18n_2_no: + id: sfGuardPermission_2 + culture: "no" + description: > + Kan se liste over brukergrupper og + redaksjoner + sfGuardPermissionI18n_3_no: + id: sfGuardPermission_3 + culture: "no" + description: > + Kan redigere brukergrupper og + redaksjoner + sfGuardPermissionI18n_4_no: + id: sfGuardPermission_4 + culture: "no" + description: Kan slette brukergrupper og redaksjoner + sfGuardPermissionI18n_5_no: + id: sfGuardPermission_5 + culture: "no" + description: Kan se liste over tilganger + sfGuardPermissionI18n_6_no: + id: sfGuardPermission_6 + culture: "no" + description: Kan redigere tilganger + sfGuardPermissionI18n_7_no: + id: sfGuardPermission_7 + culture: "no" + description: Kan slette tilganger + sfGuardPermissionI18n_8_no: + id: sfGuardPermission_8 + culture: "no" + description: Kan se liste over alle brukere + sfGuardPermissionI18n_9_no: + id: sfGuardPermission_9 + culture: "no" + description: > + Kan redigere brukere via + admin-grensesnittet + sfGuardPermissionI18n_10_no: + id: sfGuardPermission_10 + culture: "no" + description: Kan slette enkeltbrukere + sfGuardPermissionI18n_11_no: + id: sfGuardPermission_11 + culture: "no" + description: Kan redigere brukeres profil + sfGuardPermissionI18n_12_no: + id: sfGuardPermission_12 + culture: "no" + description: > + Kan se alle verk, inkludert + ikke-godkjente verk + sfGuardPermissionI18n_13_no: + id: sfGuardPermission_13 + culture: "no" + description: > + Får ekstra detaljerte feilmeldinger der + disse er tilgjengelig + sfGuardPermissionI18n_14_no: + id: sfGuardPermission_14 + culture: "no" + description: Kan redigere alle verk og filer + sfGuardPermissionI18n_15_no: + id: sfGuardPermission_15 + culture: "no" + description: > + Er en registrert bruker (må være på + alle grupper) + sfGuardPermissionI18n_16_no: + id: sfGuardPermission_16 + culture: "no" + description: Kan slette filer fullstendig + sfGuardPermissionI18n_17_no: + id: sfGuardPermission_17 + culture: "no" + description: > + Har generell tilgang til å redigere og + moderere verk + sfGuardPermissionI18n_18_no: + id: sfGuardPermission_18 + culture: "no" + description: > + Kan moderere tagger på verk (fjerne fra + verk + godkjenne) + sfGuardPermissionI18n_19_no: + id: sfGuardPermission_19 + culture: "no" + description: Kan redigere og moderere kommentarer + sfGuardPermissionI18n_20_no: + id: sfGuardPermission_20 + culture: "no" + description: Kan fjerne tagger fra systemet + sfGuardPermissionI18n_21_no: + id: sfGuardPermission_21 + culture: "no" + description: > + Kan redigere (endre, slette, legge til) + subReaktorer + sfGuardPermissionI18n_22_no: + id: sfGuardPermission_22 + culture: "no" + description: > + Kan redigere (endre, slette, legge til) + tagger på subReaktorer + sfGuardPermissionI18n_23_no: + id: sfGuardPermission_23 + culture: "no" + description: > + Har tilgang til grensesnittet for + oversetting + sfGuardPermissionI18n_24_no: + id: sfGuardPermission_24 + culture: "no" + description: > + Kan se metadata på verk via egen side + for metadata + sfGuardPermissionI18n_25_no: + id: sfGuardPermission_25 + culture: "no" + description: > + Får se debuggings-informasjon (kun til + bruk ved problemer) + sfGuardPermissionI18n_26_no: + id: sfGuardPermission_26 + culture: "no" + description: > + Kan diskutere verk og se verk under + diskusjon + sfGuardPermissionI18n_27_no: + id: sfGuardPermission_27 + culture: "no" + description: > + Kan anbefale verk i subReaktorer og på + forsiden + sfGuardPermissionI18n_28_no: + id: sfGuardPermission_28 + culture: "no" + description: > + Kan sende meldinger til flere brukere + samtidig + sfGuardPermissionI18n_29_no: + id: sfGuardPermission_29 + culture: "no" + description: Kan poste admin-meldinger + sfGuardPermissionI18n_30_no: + id: sfGuardPermission_30 + culture: "no" + description: Kan kommentere verk + sfGuardPermissionI18n_31_no: + id: sfGuardPermission_31 + culture: "no" + description: Kan laste opp filer og lage verk + sfGuardPermissionI18n_32_no: + id: sfGuardPermission_32 + culture: "no" + description: Kan sende meldinger til andre brukere + sfGuardPermissionI18n_33_no: + id: sfGuardPermission_33 + culture: "no" + description: Kan gi karakter på verk + sfGuardPermissionI18n_34_no: + id: sfGuardPermission_34 + culture: "no" + description: > + Kan merke brukere og verk som sine + favoritter + sfGuardPermissionI18n_35_no: + id: sfGuardPermission_35 + culture: "no" + description: Kan lagre ressurser på "Min side" + sfGuardPermissionI18n_36_no: + id: sfGuardPermission_36 + culture: "no" + description: Kan kjøre transkoding på nytt ved feil + sfGuardPermissionI18n_37_no: + id: sfGuardPermission_37 + culture: "no" + description: > + Kan opprette nye bosted som brukere kan + velge i sin profil + sfGuardPermissionI18n_38_no: + id: sfGuardPermission_38 + culture: "no" + description: Kan fjerne bosted fra systemet + sfGuardPermissionI18n_39_no: + id: sfGuardPermission_39 + culture: "no" + description: Kan se liste over alle bosteder + sfGuardPermissionI18n_40_no: + id: sfGuardPermission_40 + culture: "no" + description: > + Kan generere rapporter og lagre nye + hurtigrapporter + sfGuardPermissionI18n_41_no: + id: sfGuardPermission_41 + culture: "no" + description: Har tilgang til PHPMyAdmin + sfGuardPermissionI18n_42_no: + id: sfGuardPermission_42 + culture: "no" + description: > + Kan redigere (legge til, fjerne) + kategorier på verk + sfGuardPermissionI18n_43_no: + id: sfGuardPermission_43 + culture: "no" + description: > + Kan opprette sammensatte verk med filer + fra flere brukere + sfGuardPermissionI18n_44_no: + id: sfGuardPermission_44 + culture: "no" + description: Kan lage hjelp artikkel + sfGuardPermissionI18n_45_no: + id: sfGuardPermission_45 + culture: "no" + description: Kan lage tema artikkel + sfGuardPermissionI18n_46_no: + id: sfGuardPermission_46 + culture: "no" + description: Kan lage internal artikkel + sfGuardPermissionI18n_47_no: + id: sfGuardPermission_47 + culture: "no" + description: Kan lage footer artikkel + sfGuardPermissionI18n_48_no: + id: sfGuardPermission_48 + culture: "no" + description: Kan lage mypage artikkel + sfGuardPermissionI18n_49_no: + id: sfGuardPermission_49 + culture: "no" + description: Kan lage vanlige artikkel + sfGuardPermissionI18n_50_no: + id: sfGuardPermission_50 + culture: "no" + description: Kan lage spesial artikkel + sfGuardPermissionI18n_51_no: + id: sfGuardPermission_51 + culture: "no" + description: Kan bruke spesielle admin-funksjoner + sfGuardPermissionI18n_52_no: + id: sfGuardPermission_52 + culture: "no" + description: Kan endre andre brukeres epost-varslinger + sfGuardPermissionI18n_53_no: + id: sfGuardPermission_53 + culture: "no" + description: Kan opprette nye systemmeldinger + sfGuardPermissionI18n_54_no: + id: sfGuardPermission_54 + culture: "no" + description: Kan se listen over systemmeldinger + sfGuardPermissionI18n_55_no: + id: sfGuardPermission_55 + culture: "no" + description: Kan slette systemmeldinger + sfGuardPermissionI18n_56_no: + id: sfGuardPermission_56 + culture: "no" + description: Kan laste ned originalfil + sfGuardPermissionI18n_57_no: + id: sfGuardPermission_57 + culture: "no" + description: Kan se andre redaksjoners ventende verk + +sfGuardGroupPermission: + sfGuardGroupPermission_1_1: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_1 + sfGuardGroupPermission_1_2: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_2 + sfGuardGroupPermission_1_3: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_3 + sfGuardGroupPermission_1_4: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_4 + sfGuardGroupPermission_1_5: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_5 + sfGuardGroupPermission_1_6: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_6 + sfGuardGroupPermission_1_7: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_7 + sfGuardGroupPermission_1_8: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_8 + sfGuardGroupPermission_1_9: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_9 + sfGuardGroupPermission_1_10: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_10 + sfGuardGroupPermission_1_11: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_11 + sfGuardGroupPermission_1_12: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_12 + sfGuardGroupPermission_1_13: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_13 + sfGuardGroupPermission_1_14: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_14 + sfGuardGroupPermission_1_15: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_15 + sfGuardGroupPermission_1_16: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_16 + sfGuardGroupPermission_1_17: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_17 + sfGuardGroupPermission_1_18: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_18 + sfGuardGroupPermission_1_19: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_19 + sfGuardGroupPermission_1_20: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_20 + sfGuardGroupPermission_1_21: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_21 + sfGuardGroupPermission_1_22: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_22 + sfGuardGroupPermission_1_23: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_23 + sfGuardGroupPermission_1_24: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_24 + sfGuardGroupPermission_1_25: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_25 + sfGuardGroupPermission_1_26: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_26 + sfGuardGroupPermission_1_27: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_27 + sfGuardGroupPermission_1_28: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_28 + sfGuardGroupPermission_1_29: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_29 + sfGuardGroupPermission_1_30: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_30 + sfGuardGroupPermission_1_31: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_31 + sfGuardGroupPermission_1_32: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_32 + sfGuardGroupPermission_1_33: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_33 + sfGuardGroupPermission_1_34: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_34 + sfGuardGroupPermission_1_35: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_35 + sfGuardGroupPermission_1_36: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_36 + sfGuardGroupPermission_1_37: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_37 + sfGuardGroupPermission_1_38: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_38 + sfGuardGroupPermission_1_39: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_39 + sfGuardGroupPermission_1_40: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_40 + sfGuardGroupPermission_1_41: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_41 + sfGuardGroupPermission_1_42: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_42 + sfGuardGroupPermission_1_43: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_43 + sfGuardGroupPermission_1_44: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_44 + sfGuardGroupPermission_1_45: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_45 + sfGuardGroupPermission_1_46: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_46 + sfGuardGroupPermission_1_47: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_47 + sfGuardGroupPermission_1_48: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_48 + sfGuardGroupPermission_1_49: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_49 + sfGuardGroupPermission_1_50: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_50 + sfGuardGroupPermission_1_51: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_51 + sfGuardGroupPermission_1_52: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_52 + sfGuardGroupPermission_1_53: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_53 + sfGuardGroupPermission_1_54: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_54 + sfGuardGroupPermission_1_55: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_55 + sfGuardGroupPermission_1_56: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_56 + sfGuardGroupPermission_1_57: + group_id: sfGuardGroup_1 + permission_id: sfGuardPermission_57 + sfGuardGroupPermission_2_8: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_8 + sfGuardGroupPermission_2_15: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_15 + sfGuardGroupPermission_2_24: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_24 + sfGuardGroupPermission_2_30: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_30 + sfGuardGroupPermission_2_31: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_31 + sfGuardGroupPermission_2_32: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_32 + sfGuardGroupPermission_2_33: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_33 + sfGuardGroupPermission_2_34: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_34 + sfGuardGroupPermission_2_35: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_35 + sfGuardGroupPermission_2_36: + group_id: sfGuardGroup_2 + permission_id: sfGuardPermission_36 + sfGuardGroupPermission_3_1: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_1 + sfGuardGroupPermission_3_8: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_8 + sfGuardGroupPermission_3_12: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_12 + sfGuardGroupPermission_3_13: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_13 + sfGuardGroupPermission_3_14: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_14 + sfGuardGroupPermission_3_15: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_15 + sfGuardGroupPermission_3_17: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_17 + sfGuardGroupPermission_3_18: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_18 + sfGuardGroupPermission_3_19: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_19 + sfGuardGroupPermission_3_24: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_24 + sfGuardGroupPermission_3_25: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_25 + sfGuardGroupPermission_3_26: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_26 + sfGuardGroupPermission_3_30: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_30 + sfGuardGroupPermission_3_31: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_31 + sfGuardGroupPermission_3_32: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_32 + sfGuardGroupPermission_3_33: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_33 + sfGuardGroupPermission_3_34: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_34 + sfGuardGroupPermission_3_35: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_35 + sfGuardGroupPermission_3_36: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_36 + sfGuardGroupPermission_3_38: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_38 + sfGuardGroupPermission_3_39: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_39 + sfGuardGroupPermission_3_40: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_40 + sfGuardGroupPermission_3_42: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_42 + sfGuardGroupPermission_3_46: + group_id: sfGuardGroup_3 + permission_id: sfGuardPermission_46 + sfGuardGroupPermission_4_23: + group_id: sfGuardGroup_4 + permission_id: sfGuardPermission_23 + sfGuardGroupPermission_5_27: + group_id: sfGuardGroup_5 + permission_id: sfGuardPermission_27 + sfGuardGroupPermission_5_43: + group_id: sfGuardGroup_5 + permission_id: sfGuardPermission_43 + sfGuardGroupPermission_5_44: + group_id: sfGuardGroup_5 + permission_id: sfGuardPermission_44 + sfGuardGroupPermission_5_45: + group_id: sfGuardGroup_5 + permission_id: sfGuardPermission_45 + sfGuardGroupPermission_6_27: + group_id: sfGuardGroup_6 + permission_id: sfGuardPermission_27 + sfGuardGroupPermission_6_43: + group_id: sfGuardGroup_6 + permission_id: sfGuardPermission_43 + sfGuardGroupPermission_6_44: + group_id: sfGuardGroup_6 + permission_id: sfGuardPermission_44 + sfGuardGroupPermission_6_45: + group_id: sfGuardGroup_6 + permission_id: sfGuardPermission_45 + sfGuardGroupPermission_7_27: + group_id: sfGuardGroup_7 + permission_id: sfGuardPermission_27 + sfGuardGroupPermission_7_43: + group_id: sfGuardGroup_7 + permission_id: sfGuardPermission_43 + sfGuardGroupPermission_7_44: + group_id: sfGuardGroup_7 + permission_id: sfGuardPermission_44 + sfGuardGroupPermission_7_45: + group_id: sfGuardGroup_7 + permission_id: sfGuardPermission_45 + sfGuardGroupPermission_8_27: + group_id: sfGuardGroup_8 + permission_id: sfGuardPermission_27 + sfGuardGroupPermission_8_43: + group_id: sfGuardGroup_8 + permission_id: sfGuardPermission_43 + sfGuardGroupPermission_8_44: + group_id: sfGuardGroup_8 + permission_id: sfGuardPermission_44 + sfGuardGroupPermission_8_45: + group_id: sfGuardGroup_8 + permission_id: sfGuardPermission_45 + sfGuardGroupPermission_9_27: + group_id: sfGuardGroup_9 + permission_id: sfGuardPermission_27 + sfGuardGroupPermission_9_43: + group_id: sfGuardGroup_9 + permission_id: sfGuardPermission_43 + sfGuardGroupPermission_9_44: + group_id: sfGuardGroup_9 + permission_id: sfGuardPermission_44 + sfGuardGroupPermission_9_45: + group_id: sfGuardGroup_9 + permission_id: sfGuardPermission_45 + sfGuardGroupPermission_10_27: + group_id: sfGuardGroup_10 + permission_id: sfGuardPermission_27 + sfGuardGroupPermission_10_43: + group_id: sfGuardGroup_10 + permission_id: sfGuardPermission_43 + sfGuardGroupPermission_10_44: + group_id: sfGuardGroup_10 + permission_id: sfGuardPermission_44 + sfGuardGroupPermission_10_45: + group_id: sfGuardGroup_10 + permission_id: sfGuardPermission_45 + sfGuardGroupPermission_11_1: + group_id: sfGuardGroup_11 + permission_id: sfGuardPermission_1 + sfGuardGroupPermission_11_44: + group_id: sfGuardGroup_11 + permission_id: sfGuardPermission_44 + sfGuardGroupPermission_11_45: + group_id: sfGuardGroup_11 + permission_id: sfGuardPermission_45 + sfGuardGroupPermission_11_46: + group_id: sfGuardGroup_11 + permission_id: sfGuardPermission_46 + sfGuardGroupPermission_11_47: + group_id: sfGuardGroup_11 + permission_id: sfGuardPermission_47 + sfGuardGroupPermission_11_48: + group_id: sfGuardGroup_11 + permission_id: sfGuardPermission_48 + sfGuardGroupPermission_11_49: + group_id: sfGuardGroup_11 + permission_id: sfGuardPermission_49 + sfGuardGroupPermission_11_50: + group_id: sfGuardGroup_11 + permission_id: sfGuardPermission_50 + sfGuardGroupPermission_4_1: + group_id: sfGuardGroup_4 + permission_id: sfGuardPermission_1 + +# These values link subreaktors to file identifiers, for example "foto" to "image" +# This link is what determines the options a user gets when selecting a subreaktor after uploading + +SubreaktorIdentifier: + # Photos + Identifier_1: + subreaktor_id: Subreaktor_1 # Foto + identifier: image + Identifier_2: + subreaktor_id: Subreaktor_2 # Drawing + identifier: image + Identifier_3: + subreaktor_id: Subreaktor_5 # Cartoon + identifier: image + # Pdf docs + Identifier_4: + subreaktor_id: Subreaktor_6 # Text + identifier: pdf + Identifier_10: + subreaktor_id: Subreaktor_5 + identifier: pdf # Cartoon + Identifier_11: + subreaktor_id: Subreaktor_2 + identifier: pdf # Drawing + # Audio clips + Identifier_5: + subreaktor_id: Subreaktor_4 # Audio + identifier: audio + # Movie clips + Identifier_6: + subreaktor_id: Subreaktor_3 # Film + identifier: video + Identifier_7: + subreaktor_id: Subreaktor_3 # Film (flash animation) + identifier: flash_animation + Identifier_8: + subreaktor_id: Subreaktor_4 # Audio + identifier: video # Music vid perhaps + # Non-pdf text + Identifier_9: + subreaktor_id: Subreaktor_6 # Text + identifier: text + + +Category: + Category_1: + basename: arkitektur + Category_2: + basename: barn + Category_3: + basename: dyr + Category_4: + basename: kjøretøy + Category_5: + basename: landskap + Category_6: + basename: makro + Category_7: + basename: manipulasjon + Category_8: + basename: mennesker + Category_9: + basename: nattbilder + Category_10: + basename: natur + Category_11: + basename: portrett + Category_12: + basename: reise + Category_13: + basename: sport + Category_14: + basename: stilleben + Category_15: + basename: undervannsfoto + Category_16: + basename: datagrafikk + Category_17: + basename: 3d + Category_18: + basename: maleri + Category_19: + basename: skisser + Category_20: + basename: tegning + Category_21: + basename: animasjonsfilm + Category_22: + basename: dataanimasjon + Category_23: + basename: dokumentar + Category_24: + basename: kortfilm + Category_25: + basename: musikkvideo + Category_26: + basename: blues + Category_27: + basename: elektronika + Category_28: + basename: folkemusikk + Category_30: + basename: jazz + Category_31: + basename: klassisk musikk + Category_32: + basename: pop + Category_33: + basename: rock + Category_34: + basename: hørespill + Category_35: + basename: intervjuer + Category_36: + basename: lydeffekter + Category_37: + basename: opplesninger + Category_38: + basename: rockabilly + Category_39: + basename: techno + Category_40: + basename: viser + Category_41: + basename: world music + Category_43: + basename: biografisk + Category_44: + basename: drama + Category_45: + basename: fantasy + Category_46: + basename: funny animals + Category_47: + basename: historisk + Category_48: + basename: humor + Category_49: + basename: manga + Category_50: + basename: samfunnssatire + Category_51: + basename: science fiction + Category_52: + basename: skrekk + Category_53: + basename: spenning + Category_54: + basename: superhelter + Category_55: + basename: western + Category_56: + basename: essays + Category_57: + basename: eventyr + Category_58: + basename: fabler + Category_60: + basename: filmmanus + Category_61: + basename: foredrag + Category_62: + basename: fortellinger + Category_63: + basename: haikudikt + Category_66: + basename: krim + Category_67: + basename: noveller + Category_68: + basename: prosadikt + Category_69: + basename: rollespill + Category_70: + basename: science rollespill + Category_71: + basename: mitsetegning + Category_72: + basename: metaserie + Category_73: + basename: arrangementer + +CategoryI18n: + CategoryI18n_1_no: + id: Category_1 + culture: 'no' + name: arkitektur + CategoryI18n_2_no: + id: Category_2 + culture: 'no' + name: barn + CategoryI18n_3_no: + id: Category_3 + culture: 'no' + name: dyr + CategoryI18n_4_no: + id: Category_4 + culture: 'no' + name: kjøretøy + CategoryI18n_5_no: + id: Category_5 + culture: 'no' + name: landskap + CategoryI18n_6_no: + id: Category_6 + culture: 'no' + name: makro + CategoryI18n_7_no: + id: Category_7 + culture: 'no' + name: manipulasjon + CategoryI18n_8_no: + id: Category_8 + culture: 'no' + name: mennesker + CategoryI18n_9_no: + id: Category_9 + culture: 'no' + name: nattbilder + CategoryI18n_10_no: + id: Category_10 + culture: 'no' + name: natur + CategoryI18n_11_no: + id: Category_11 + culture: 'no' + name: portrett + CategoryI18n_12_no: + id: Category_12 + culture: 'no' + name: reise + CategoryI18n_13_no: + id: Category_13 + culture: 'no' + name: sport + CategoryI18n_14_no: + id: Category_14 + culture: 'no' + name: stilleben + CategoryI18n_15_no: + id: Category_15 + culture: 'no' + name: undervannsfoto + CategoryI18n_16_no: + id: Category_16 + culture: 'no' + name: datagrafikk + CategoryI18n_17_no: + id: Category_17 + culture: 'no' + name: 3d + CategoryI18n_18_no: + id: Category_18 + culture: 'no' + name: maleri + CategoryI18n_19_no: + id: Category_19 + culture: 'no' + name: skisser + CategoryI18n_20_no: + id: Category_20 + culture: 'no' + name: tegning + CategoryI18n_21_no: + id: Category_21 + culture: 'no' + name: animasjonsfilm + CategoryI18n_22_no: + id: Category_22 + culture: 'no' + name: dataanimasjon + CategoryI18n_23_no: + id: Category_23 + culture: 'no' + name: dokumentar + CategoryI18n_24_no: + id: Category_24 + culture: 'no' + name: kortfilm + CategoryI18n_25_no: + id: Category_25 + culture: 'no' + name: musikkvideo + CategoryI18n_26_no: + id: Category_26 + culture: 'no' + name: blues + CategoryI18n_27_no: + id: Category_27 + culture: 'no' + name: elektronika + CategoryI18n_28_no: + id: Category_28 + culture: 'no' + name: folkemusikk + CategoryI18n_30_no: + id: Category_30 + culture: 'no' + name: jazz + CategoryI18n_31_no: + id: Category_31 + culture: 'no' + name: klassisk musikk + CategoryI18n_32_no: + id: Category_32 + culture: 'no' + name: pop + CategoryI18n_33_no: + id: Category_33 + culture: 'no' + name: rock + CategoryI18n_34_no: + id: Category_34 + culture: 'no' + name: hørespill + CategoryI18n_35_no: + id: Category_35 + culture: 'no' + name: intervjuer + CategoryI18n_36_no: + id: Category_36 + culture: 'no' + name: lydeffekter + CategoryI18n_37_no: + id: Category_37 + culture: 'no' + name: opplesninger + CategoryI18n_38_no: + id: Category_38 + culture: 'no' + name: rockabilly + CategoryI18n_39_no: + id: Category_39 + culture: 'no' + name: techno + CategoryI18n_40_no: + id: Category_40 + culture: 'no' + name: viser + CategoryI18n_41_no: + id: Category_41 + culture: 'no' + name: world music + CategoryI18n_43_no: + id: Category_43 + culture: 'no' + name: biografisk + CategoryI18n_44_no: + id: Category_44 + culture: 'no' + name: drama + CategoryI18n_45_no: + id: Category_45 + culture: 'no' + name: fantasy + CategoryI18n_46_no: + id: Category_46 + culture: 'no' + name: funny animals + CategoryI18n_47_no: + id: Category_47 + culture: 'no' + name: historisk + CategoryI18n_48_no: + id: Category_48 + culture: 'no' + name: humor + CategoryI18n_49_no: + id: Category_49 + culture: 'no' + name: manga + CategoryI18n_50_no: + id: Category_50 + culture: 'no' + name: samfunnssatire + CategoryI18n_51_no: + id: Category_51 + culture: 'no' + name: science fiction + CategoryI18n_52_no: + id: Category_52 + culture: 'no' + name: skrekk + CategoryI18n_53_no: + id: Category_53 + culture: 'no' + name: spenning + CategoryI18n_54_no: + id: Category_54 + culture: 'no' + name: superhelter + CategoryI18n_55_no: + id: Category_55 + culture: 'no' + name: western + CategoryI18n_56_no: + id: Category_56 + culture: 'no' + name: essays + CategoryI18n_57_no: + id: Category_57 + culture: 'no' + name: eventyr + CategoryI18n_58_no: + id: Category_58 + culture: 'no' + name: fabler + CategoryI18n_60_no: + id: Category_60 + culture: 'no' + name: filmmanus + CategoryI18n_61_no: + id: Category_61 + culture: 'no' + name: foredrag + CategoryI18n_62_no: + id: Category_62 + culture: 'no' + name: fortellinger + CategoryI18n_63_no: + id: Category_63 + culture: 'no' + name: haikudikt + CategoryI18n_66_no: + id: Category_66 + culture: 'no' + name: krim + CategoryI18n_67_no: + id: Category_67 + culture: 'no' + name: noveller + CategoryI18n_68_no: + id: Category_68 + culture: 'no' + name: prosadikt + CategoryI18n_69_no: + id: Category_69 + culture: 'no' + name: rollespill + CategoryI18n_70_no: + id: Category_70 + culture: 'no' + name: science rollespill + CategoryI18n_71_no: + id: Category_71 + culture: 'no' + name: mitsetegning + CategoryI18n_72_no: + id: Category_72 + culture: 'no' + name: metaserie + CategoryI18n_73_no: + id: Category_73 + culture: 'no' + name: arrangementer + + CategoryI18n_1_en: + id: Category_1 + culture: en + name: architecture + CategoryI18n_2_en: + id: Category_2 + culture: en + name: children + CategoryI18n_3_en: + id: Category_3 + culture: en + name: animals + CategoryI18n_4_en: + id: Category_4 + culture: en + name: vehicles + CategoryI18n_5_en: + id: Category_5 + culture: en + name: landscape + CategoryI18n_6_en: + id: Category_6 + culture: en + name: macro + CategoryI18n_7_en: + id: Category_7 + culture: en + name: manipulation + CategoryI18n_8_en: + id: Category_8 + culture: en + name: people + CategoryI18n_9_en: + id: Category_9 + culture: en + name: night pictures + CategoryI18n_10_en: + id: Category_10 + culture: en + name: nature + CategoryI18n_11_en: + id: Category_11 + culture: en + name: portrait + CategoryI18n_12_en: + id: Category_12 + culture: en + name: travel + CategoryI18n_13_en: + id: Category_13 + culture: en + name: sport + CategoryI18n_14_en: + id: Category_14 + culture: en + name: still life + CategoryI18n_15_en: + id: Category_15 + culture: en + name: underwater photo + CategoryI18n_16_en: + id: Category_16 + culture: en + name: computer graphics + CategoryI18n_17_en: + id: Category_17 + culture: en + name: 3d + CategoryI18n_18_en: + id: Category_18 + culture: en + name: painting + CategoryI18n_19_en: + id: Category_19 + culture: en + name: sketch + CategoryI18n_20_en: + id: Category_20 + culture: en + name: drawing + CategoryI18n_21_en: + id: Category_21 + culture: en + name: animation + CategoryI18n_22_en: + id: Category_22 + culture: en + name: computer animation + CategoryI18n_23_en: + id: Category_23 + culture: en + name: documentary + CategoryI18n_24_en: + id: Category_24 + culture: en + name: short film + CategoryI18n_25_en: + id: Category_25 + culture: en + name: music video + CategoryI18n_26_en: + id: Category_26 + culture: en + name: blues + CategoryI18n_27_en: + id: Category_27 + culture: en + name: electronica + CategoryI18n_28_en: + id: Category_28 + culture: en + name: folk music + CategoryI18n_30_en: + id: Category_30 + culture: en + name: jazz + CategoryI18n_31_en: + id: Category_31 + culture: en + name: classical music + CategoryI18n_32_en: + id: Category_32 + culture: en + name: pop + CategoryI18n_33_en: + id: Category_33 + culture: en + name: rock + CategoryI18n_34_en: + id: Category_34 + culture: en + name: radio entertainment + CategoryI18n_35_en: + id: Category_35 + culture: en + name: interview + CategoryI18n_36_en: + id: Category_36 + culture: en + name: sound effects + CategoryI18n_37_en: + id: Category_37 + culture: en + name: recitals + CategoryI18n_38_en: + id: Category_38 + culture: en + name: rockabilly + CategoryI18n_39_en: + id: Category_39 + culture: en + name: techno + CategoryI18n_40_en: + id: Category_40 + culture: en + name: demonstration + CategoryI18n_41_en: + id: Category_41 + culture: en + name: world music + CategoryI18n_43_en: + id: Category_43 + culture: en + name: biography + CategoryI18n_44_en: + id: Category_44 + culture: en + name: drama + CategoryI18n_45_en: + id: Category_45 + culture: en + name: fantasy + CategoryI18n_46_en: + id: Category_46 + culture: en + name: funny animals + CategoryI18n_47_en: + id: Category_47 + culture: en + name: historical + CategoryI18n_48_en: + id: Category_48 + culture: en + name: humor + CategoryI18n_49_en: + id: Category_49 + culture: en + name: manga + CategoryI18n_50_en: + id: Category_50 + culture: en + name: satire + CategoryI18n_51_en: + id: Category_51 + culture: en + name: science fiction + CategoryI18n_52_en: + id: Category_52 + culture: en + name: horror + CategoryI18n_53_en: + id: Category_53 + culture: en + name: suspense + CategoryI18n_54_en: + id: Category_54 + culture: en + name: super heroes + CategoryI18n_55_en: + id: Category_55 + culture: en + name: western + CategoryI18n_56_en: + id: Category_56 + culture: en + name: essays + CategoryI18n_57_en: + id: Category_57 + culture: en + name: events + CategoryI18n_58_en: + id: Category_58 + culture: en + name: fables + CategoryI18n_60_en: + id: Category_60 + culture: en + name: film scripts + CategoryI18n_61_en: + id: Category_61 + culture: en + name: speech + CategoryI18n_62_en: + id: Category_62 + culture: en + name: story telling + CategoryI18n_63_en: + id: Category_63 + culture: en + name: haiku poems + CategoryI18n_66_en: + id: Category_66 + culture: en + name: crime + CategoryI18n_67_en: + id: Category_67 + culture: en + name: novels + CategoryI18n_68_en: + id: Category_68 + culture: en + name: prose poems + CategoryI18n_69_en: + id: Category_69 + culture: en + name: roleplay + CategoryI18n_70_en: + id: Category_70 + culture: en + name: science roleplay + CategoryI18n_71_en: + id: Category_71 + culture: en + name: funny drawing + CategoryI18n_72_en: + id: Category_72 + culture: en + name: meta series + CategoryI18n_73_en: + id: Category_73 + culture: en + name: arrangements + CategoryI18n_1_nn: + id: Category_1 + culture: nn + name: arkitektur + CategoryI18n_2_nn: + id: Category_2 + culture: nn + name: barn + CategoryI18n_3_nn: + id: Category_3 + culture: nn + name: dyr + CategoryI18n_4_nn: + id: Category_4 + culture: nn + name: kjøretøy + CategoryI18n_5_nn: + id: Category_5 + culture: nn + name: landskap + CategoryI18n_6_nn: + id: Category_6 + culture: nn + name: makro + CategoryI18n_7_nn: + id: Category_7 + culture: nn + name: manipulasjon + CategoryI18n_8_nn: + id: Category_8 + culture: nn + name: mennesker + CategoryI18n_9_nn: + id: Category_9 + culture: nn + name: nattbilder + CategoryI18n_10_nn: + id: Category_10 + culture: nn + name: natur + CategoryI18n_11_nn: + id: Category_11 + culture: nn + name: portrett + CategoryI18n_12_nn: + id: Category_12 + culture: nn + name: reise + CategoryI18n_13_nn: + id: Category_13 + culture: nn + name: sport + CategoryI18n_14_nn: + id: Category_14 + culture: nn + name: stilleban + CategoryI18n_15_nn: + id: Category_15 + culture: nn + name: undervannsfoto + CategoryI18n_16_nn: + id: Category_16 + culture: nn + name: datagrafikk + CategoryI18n_17_nn: + id: Category_17 + culture: nn + name: 3d + CategoryI18n_18_nn: + id: Category_18 + culture: nn + name: maleri + CategoryI18n_19_nn: + id: Category_19 + culture: nn + name: skisser + CategoryI18n_20_nn: + id: Category_20 + culture: nn + name: tegning + CategoryI18n_21_nn: + id: Category_21 + culture: nn + name: animasjonsfilm + CategoryI18n_22_nn: + id: Category_22 + culture: nn + name: dataanimasjon + CategoryI18n_23_nn: + id: Category_23 + culture: nn + name: dokumentar + CategoryI18n_24_nn: + id: Category_24 + culture: nn + name: kortfilm + CategoryI18n_25_nn: + id: Category_25 + culture: nn + name: musikkvideo + CategoryI18n_26_nn: + id: Category_26 + culture: nn + name: blues + CategoryI18n_27_nn: + id: Category_27 + culture: nn + name: elektronika + CategoryI18n_28_nn: + id: Category_28 + culture: nn + name: folkemusikk + CategoryI18n_30_nn: + id: Category_30 + culture: nn + name: jazz + CategoryI18n_31_nn: + id: Category_31 + culture: nn + name: klassisk musikk + CategoryI18n_32_nn: + id: Category_32 + culture: nn + name: pop + CategoryI18n_33_nn: + id: Category_33 + culture: nn + name: rock + CategoryI18n_34_nn: + id: Category_34 + culture: nn + name: hørespill + CategoryI18n_35_nn: + id: Category_35 + culture: nn + name: intervjuer + CategoryI18n_36_nn: + id: Category_36 + culture: nn + name: lydeffekter + CategoryI18n_37_nn: + id: Category_37 + culture: nn + name: opplesninger + CategoryI18n_38_nn: + id: Category_38 + culture: nn + name: rockabilly + CategoryI18n_39_nn: + id: Category_39 + culture: nn + name: techno + CategoryI18n_40_nn: + id: Category_40 + culture: nn + name: viser + CategoryI18n_41_nn: + id: Category_41 + culture: nn + name: world music + CategoryI18n_43_nn: + id: Category_43 + culture: nn + name: biografisk + CategoryI18n_44_nn: + id: Category_44 + culture: nn + name: drama + CategoryI18n_45_nn: + id: Category_45 + culture: nn + name: fantasy + CategoryI18n_46_nn: + id: Category_46 + culture: nn + name: funny animals + CategoryI18n_47_nn: + id: Category_47 + culture: nn + name: historisk + CategoryI18n_48_nn: + id: Category_48 + culture: nn + name: humor + CategoryI18n_49_nn: + id: Category_49 + culture: nn + name: manga + CategoryI18n_50_nn: + id: Category_50 + culture: nn + name: samfunnssatire + CategoryI18n_51_nn: + id: Category_51 + culture: nn + name: science fiction + CategoryI18n_52_nn: + id: Category_52 + culture: nn + name: skrekk + CategoryI18n_53_nn: + id: Category_53 + culture: nn + name: spenning + CategoryI18n_54_nn: + id: Category_54 + culture: nn + name: superhelter + CategoryI18n_55_nn: + id: Category_55 + culture: nn + name: western + CategoryI18n_56_nn: + id: Category_56 + culture: nn + name: essays + CategoryI18n_57_nn: + id: Category_57 + culture: nn + name: eventyr + CategoryI18n_58_nn: + id: Category_58 + culture: nn + name: fabler + CategoryI18n_60_nn: + id: Category_60 + culture: nn + name: filmmanus + CategoryI18n_61_nn: + id: Category_61 + culture: nn + name: foredrag + CategoryI18n_62_nn: + id: Category_62 + culture: nn + name: fortellinger + CategoryI18n_63_nn: + id: Category_63 + culture: nn + name: haikudikt + CategoryI18n_66_nn: + id: Category_66 + culture: nn + name: krim + CategoryI18n_67_nn: + id: Category_67 + culture: nn + name: noveller + CategoryI18n_68_nn: + id: Category_68 + culture: nn + name: prosadikt + CategoryI18n_69_nn: + id: Category_69 + culture: nn + name: rollespill + CategoryI18n_70_nn: + id: Category_70 + culture: nn + name: science rollespill + CategoryI18n_71_nn: + id: Category_71 + culture: nn + name: mitsetegning + CategoryI18n_72_nn: + id: Category_72 + culture: nn + name: metaserie + CategoryI18n_73_nn: + id: Category_73 + culture: nn + name: arrangementer + + +CategorySubreaktor: + CategorySubreaktor_1: + category_id: Category_1 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_2: + category_id: Category_2 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_3: + category_id: Category_3 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_4: + category_id: Category_4 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_5: + category_id: Category_5 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_6: + category_id: Category_6 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_7: + category_id: Category_7 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_8: + category_id: Category_8 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_9: + category_id: Category_9 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_10: + category_id: Category_10 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_11: + category_id: Category_11 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_12: + category_id: Category_12 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_13: + category_id: Category_13 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_14: + category_id: Category_14 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_15: + category_id: Category_15 + subreaktor_id: Subreaktor_1 + CategorySubreaktor_16: + category_id: Category_16 + subreaktor_id: Subreaktor_2 + CategorySubreaktor_17: + category_id: Category_17 + subreaktor_id: Subreaktor_2 + CategorySubreaktor_18: + category_id: Category_18 + subreaktor_id: Subreaktor_2 + CategorySubreaktor_19: + category_id: Category_19 + subreaktor_id: Subreaktor_2 + CategorySubreaktor_20: + category_id: Category_20 + subreaktor_id: Subreaktor_2 + CategorySubreaktor_21: + category_id: Category_21 + subreaktor_id: Subreaktor_3 + CategorySubreaktor_22: + category_id: Category_22 + subreaktor_id: Subreaktor_3 + CategorySubreaktor_23: + category_id: Category_23 + subreaktor_id: Subreaktor_3 + CategorySubreaktor_24: + category_id: Category_24 + subreaktor_id: Subreaktor_3 + CategorySubreaktor_25: + category_id: Category_25 + subreaktor_id: Subreaktor_3 + CategorySubreaktor_26: + category_id: Category_26 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_27: + category_id: Category_27 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_28: + category_id: Category_28 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_30: + category_id: Category_30 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_31: + category_id: Category_31 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_32: + category_id: Category_32 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_33: + category_id: Category_33 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_34: + category_id: Category_34 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_35: + category_id: Category_35 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_36: + category_id: Category_36 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_37: + category_id: Category_37 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_38: + category_id: Category_38 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_39: + category_id: Category_39 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_40: + category_id: Category_40 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_41: + category_id: Category_41 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_42: + category_id: Category_25 + subreaktor_id: Subreaktor_4 + CategorySubreaktor_43: + category_id: Category_43 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_44: + category_id: Category_44 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_45: + category_id: Category_45 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_46: + category_id: Category_46 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_47: + category_id: Category_47 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_48: + category_id: Category_48 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_49: + category_id: Category_49 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_50: + category_id: Category_50 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_51: + category_id: Category_51 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_52: + category_id: Category_52 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_53: + category_id: Category_53 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_54: + category_id: Category_54 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_55: + category_id: Category_55 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_56: + category_id: Category_56 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_57: + category_id: Category_57 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_58: + category_id: Category_58 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_59: + category_id: Category_45 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_60: + category_id: Category_60 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_61: + category_id: Category_61 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_62: + category_id: Category_62 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_63: + category_id: Category_63 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_64: + category_id: Category_48 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_65: + category_id: Category_34 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_66: + category_id: Category_66 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_67: + category_id: Category_67 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_68: + category_id: Category_68 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_69: + category_id: Category_69 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_70: + category_id: Category_70 + subreaktor_id: Subreaktor_6 + CategorySubreaktor_71: + category_id: Category_72 + subreaktor_id: Subreaktor_5 + CategorySubreaktor_72: + category_id: Category_73 + subreaktor_id: Subreaktor_5 + diff --git a/data/fixtures/02user.yml b/data/fixtures/02user.yml new file mode 100644 index 0000000..330e69e --- /dev/null +++ b/data/fixtures/02user.yml @@ -0,0 +1,357 @@ +sfGuardUser: + sfGuardUser_1: + username: admin + password: admin + culture: 'no' + created_at: 2008-03-05 18:30:37 + last_login: 2008-03-05 23:16:00 + is_active: 1 + is_verified: 1 + is_super_admin: 1 + show_content: 1 + email: reaktor-test@linpro.no + email_private: 1 + name: admin + name_private: 0 + dob: 1980-01-01 00:00:00 + sex: 2 + description: Hest er best + residence_id: Residence_1 + msn: reaktor@msn.no + icq: 54321 + homepage: http://reaktor.lab.linpro.no + sfGuardUser_2: + username: monkeyboy + password: monkeyboy + culture: 'no' + created_at: 2008-03-05 18:30:37 + is_active: 1 + is_verified: 1 + is_super_admin: 0 + show_content: 1 + email: monkeyboy@linpro.no + email_private: 1 + name: monkey johns son + name_private: 0 + dob: 1990-12-24 00:00:00 + sex: 1 + description: > + Monkey is the name, coding is the game. + Now - choose your weapon! + residence_id: Residence_4 + msn: monkeyboy@hotmail.com + icq: 55323 + homepage: http://reaktor.lab.linpro.no + opt_in: 1 + sfGuardUser_3: + username: userboy + password: userboy + culture: 'no' + created_at: 2008-03-05 18:30:37 + is_active: 1 + is_verified: 1 + is_super_admin: 0 + show_content: 1 + email: userboy@linpro.no + email_private: 1 + name: User Boy + name_private: 0 + dob: 2000-03-08 00:00:00 + sex: 1 + description: > + I am a normal user, no groups or + priveledges whatsoever <|:o(8 + residence_id: Residence_6 + msn: userboy@hotmail.com + icq: 123456 + homepage: http://reaktor.lab.linpro.no + opt_in: 1 + sfGuardUser_4: + username: leo + password: leo + culture: 'no' + created_at: 2008-03-05 18:30:37 + is_active: 1 + is_verified: 1 + is_super_admin: 0 + show_content: 1 + email: anne-lena.westrum@kie.oslo.kommune.no + email_private: 1 + name: Anne-Lena Westrum + name_private: 0 + dob: 1977-04-20 00:00:00 + sex: 2 + description: I'm the owner don't you know :) + residence_id: Residence_4 + homepage: http://minreaktor.no + opt_in: 1 + sfGuardUser_5: + username: Kerry + password: kerry + culture: 'no' + created_at: 2008-04-07 21:00:00 + is_active: 1 + is_verified: 1 + show_content: 1 + email: kerry@nowhere.com + email_private: 0 + name: Kerry + name_private: 1 + dob: 1979-07-02 21:00:00 + sex: 2 + description: Just Kerry + residence_id: Residence_2 + homepage: http://kerry.com + opt_in: 1 + sfGuardUser_6: + username: dave + password: dave + culture: 'no' + created_at: 2008-04-07 22:00:00 + is_active: 1 + is_verified: 1 + show_content: 0 + email: dave@nowhere.com + email_private: 1 + name: Dave + name_private: 1 + dob: 1979-07-02 22:00:00 + sex: 2 + description: Just Dave + residence_id: Residence_7 + homepage: http://dave.com + sfGuardUser_7: + username: languageboy + password: languageboy + culture: 'no' + created_at: 2008-05-08 13:45:00 + is_active: 1 + is_verified: 1 + show_content: 1 + email: languageboy@nowhere.com + email_private: 1 + name: Language boy + name_private: 1 + dob: 1979-07-02 22:00:00 + sex: 1 + description: I am the LANGUAGE BOY! + residence_id: Residence_7 + homepage: http://google.com/translate + sfGuardUser_8: + username: editorialboy1 + password: editorialboy1 + culture: 'no' + created_at: 2008-05-08 13:45:00 + is_active: 1 + is_verified: 1 + show_content: 1 + email: reaktor-editorialboy1@linpro.no + email_private: 1 + name: Ed I. Torialboy + name_private: 1 + dob: 1973-12-12 10:00:00 + sex: 1 + description: I am ED I. TORIALBOY! + residence_id: Residence_7 + homepage: http://vg.no + sfGuardUser_9: + username: editorialboy2 + password: editorialboy2 + culture: 'no' + created_at: 2008-05-08 13:45:00 + is_active: 1 + is_verified: 1 + show_content: 1 + email: reaktor-editorialboy2@linpro.no + email_private: 1 + name: Ed I. Torialboy II + name_private: 1 + dob: 1973-12-12 10:00:00 + sex: 1 + description: I am ED I. TORIALBOY II! + residence_id: Residence_7 + homepage: http://vg.no + sfGuardUser_10: + username: editorialboy3 + password: editorialboy3 + culture: 'no' + created_at: 2008-05-08 13:45:00 + is_active: 1 + is_verified: 1 + show_content: 1 + email: reaktor-editorialboy3@linpro.no + email_private: 1 + name: Ed I. Torialboy III + name_private: 1 + dob: 1973-12-12 10:00:00 + sex: 1 + description: I am ED I. TORIALBOY III! + residence_id: Residence_7 + homepage: http://vg.no + sfGuardUser_11: + username: articleboy + password: articleboy + culture: 'no' + created_at: 2008-05-08 13:45:00 + is_active: 1 + is_verified: 1 + show_content: 1 + email: reaktor-articleboy@linpro.no + email_private: 1 + name: Article Boy + name_private: 1 + dob: 1973-12-12 10:00:00 + sex: 1 + description: I am Article Boy! Bow before me! + residence_id: Residence_5 + homepage: http://dagbladet.no + sfGuardUser_12: + username: veteran + algorithm: sha1 + password: veteran + created_at: 2008-08-11 10:50:54 + is_active: 1 + is_super_admin: 0 + is_verified: 1 + show_content: 1 + culture: en + email: veteran@linpro.no + email_private: 1 + name_private: 0 + dob: 1993-01-01 + sex: 1 + residence_id: Residence_19 + opt_in: 0 + editorial_notification: 0 + show_login_status: 1 + dob_is_derived: 1 + need_profile_check: 1 + +UserInterest: + UserInterest_1_4: + user_id: sfGuardUser_2 + subreaktor_id: Subreaktor_4 + UserInterest_2_1: + user_id: sfGuardUser_3 + subreaktor_id: Subreaktor_1 + UserInterest_2_2: + user_id: sfGuardUser_3 + subreaktor_id: Subreaktor_2 + UserInterest_2_3: + user_id: sfGuardUser_3 + subreaktor_id: Subreaktor_3 + + +sfGuardUserGroup: + sfGuardUserGroup_1_1: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_1 + sfGuardUserGroup_1_3: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_3 + sfGuardUserGroup_1_4: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_4 + sfGuardUserGroup_1_5: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_5 + sfGuardUserGroup_1_6: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_6 + sfGuardUserGroup_1_7: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_7 + sfGuardUserGroup_1_8: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_8 + sfGuardUserGroup_1_9: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_9 + sfGuardUserGroup_1_10: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_10 + sfGuardUserGroup_1_11: + user_id: sfGuardUser_1 + group_id: sfGuardGroup_11 + sfGuardUserGroup_2_2: + user_id: sfGuardUser_2 + group_id: sfGuardGroup_2 + sfGuardUserGroup_3_2: + user_id: sfGuardUser_3 + group_id: sfGuardGroup_2 + sfGuardUserGroup_4_2: + user_id: sfGuardUser_4 + group_id: sfGuardGroup_2 + sfGuardUserGroup_5_2: + user_id: sfGuardUser_5 + group_id: sfGuardGroup_2 + sfGuardUserGroup_6_2: + user_id: sfGuardUser_6 + group_id: sfGuardGroup_2 + sfGuardUserGroup_7_2: + user_id: sfGuardUser_7 + group_id: sfGuardGroup_2 + sfGuardUserGroup_7_4: + user_id: sfGuardUser_7 + group_id: sfGuardGroup_4 + sfGuardUserGroup_8_2: + user_id: sfGuardUser_8 + group_id: sfGuardGroup_2 + sfGuardUserGroup_8_3: + user_id: sfGuardUser_8 + group_id: sfGuardGroup_3 + sfGuardUserGroup_8_5: + user_id: sfGuardUser_8 + group_id: sfGuardGroup_5 + sfGuardUserGroup_8_6: + user_id: sfGuardUser_8 + group_id: sfGuardGroup_6 + sfGuardUserGroup_8_7: + user_id: sfGuardUser_8 + group_id: sfGuardGroup_7 + sfGuardUserGroup_9_3: + user_id: sfGuardUser_9 + group_id: sfGuardGroup_3 + sfGuardUserGroup_9_8: + user_id: sfGuardUser_9 + group_id: sfGuardGroup_8 + sfGuardUserGroup_10_3: + user_id: sfGuardUser_10 + group_id: sfGuardGroup_3 + sfGuardUserGroup_10_11: + user_id: sfGuardUser_10 + group_id: sfGuardGroup_11 + sfGuardUserGroup_11_3: + user_id: sfGuardUser_11 + group_id: sfGuardGroup_3 + sfGuardUserGroup_11_11: + user_id: sfGuardUser_11 + group_id: sfGuardGroup_11 + sfGuardUserGroup_12_2: + user_id: sfGuardUser_12 + group_id: sfGuardGroup_2 +UserResource: + Resource_1: + user_id: sfGuardUser_3 + url: http://photoshop.com + Resource_2: + user_id: sfGuardUser_3 + url: http://gimp.org + Resource_3: + user_id: sfGuardUser_3 + url: http://vg.no + Resource_4: + user_id: sfGuardUser_3 + url: http://facebook.com + Resource_5: + user_id: sfGuardUser_1 + url: http://photoshop.com + Resource_6: + user_id: sfGuardUser_4 + url: http://gimp.org + Resource_7: + user_id: sfGuardUser_2 + url: http://vg.no + Resource_8: + user_id: sfGuardUser_5 + url: http://facebook.com diff --git a/data/fixtures/03tags.yml b/data/fixtures/03tags.yml new file mode 100644 index 0000000..c8bdda2 --- /dev/null +++ b/data/fixtures/03tags.yml @@ -0,0 +1,978 @@ +Tag: + Tag_1: + name: fred + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_2: + name: bob + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 3 + Tag_3: + name: jim + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 3 + Tag_4: + name: elephant + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 8 + Tag_5: + name: sugar cube + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 10 + Tag_6: + name: monkeydust + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 10 + Tag_7: + name: zoidberg + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 8 + Tag_8: + name: gardening + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 9 + Tag_9: + name: japan + approved: 0 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_10: + name: rest + approved: 0 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_11: + name: subway + approved: 0 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 6 + Tag_12: + name: lady + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_13: + name: php + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 3 + Tag_14: + name: cookbook + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 8 + Tag_15: + name: car + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 3 + Tag_16: + name: ford + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_17: + name: focus + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_18: + name: saudi arabia + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 12 + Tag_19: + name: bahrain + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 7 + Tag_20: + name: squash + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 6 + Tag_21: + name: boat + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_22: + name: water + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_23: + name: psalive + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 7 + Tag_24: + name: bird + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_25: + name: wet + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 3 + Tag_26: + name: eden project + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 12 + Tag_27: + name: fingers + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 7 + Tag_28: + name: strange + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 7 + Tag_29: + name: count + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_30: + name: text + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_31: + name: filler + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 6 + Tag_32: + name: abigail + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 7 + Tag_33: + name: statue + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 6 + Tag_34: + name: frogner + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 7 + Tag_35: + name: dave + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_36: + name: scuba diving + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 12 + Tag_37: + name: egypt + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_38: + name: robin + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_39: + name: space + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_40: + name: sound + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_41: + name: marianne + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 8 + Tag_42: + name: bus + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 3 + Tag_43: + name: latin + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 5 + Tag_44: + name: snow + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 4 + Tag_45: + name: ski + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 3 + Tag_46: + name: sam + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-01-01 01:01:00 + width: 3 + Tag_47: + name: bollocks + approved: 0 + width: 8 + Tag_48: + name: birds + approved: 0 + width: 5 + Tag_49: + name: random crappy long tag + approved: 0 + width: 22 + Tag_50: + name: monkey + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-07 21:52:30 + width: 6 + Tag_51: + name: fluffy + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-07 21:52:38 + width: 6 + Tag_52: + name: lake district + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-07 21:52:37 + width: 13 + Tag_53: + name: lemur + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-07 21:53:10 + width: 5 + Tag_54: + name: lakes + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-07 21:53:08 + width: 5 + Tag_55: + name: wildlife + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-07 21:53:06 + width: 8 + Tag_56: + name: animal + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-07 21:53:03 + width: 6 + Tag_57: + name: fuckit + approved: 0 + width: 6 + Tag_58: + name: bil + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-24 13:41:17 + width: 3 + Tag_59: + name: bike + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-24 13:41:15 + width: 4 + Tag_60: + name: filming + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-24 13:41:43 + width: 7 + Tag_61: + name: camera + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-24 13:41:42 + width: 6 + Tag_62: + name: crazy + approved: 0 + width: 5 + Tag_63: + name: funny + approved: 0 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:24:54 + width: 5 + Tag_64: + name: grass + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:27:23 + width: 5 + Tag_65: + name: field + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:27:21 + width: 5 + Tag_66: + name: camping + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:27:29 + width: 7 + Tag_67: + name: russ + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:28:22 + width: 4 + Tag_68: + name: red + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:29:23 + width: 3 + Tag_69: + name: silly + approved: 0 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:29:52 + width: 5 + Tag_70: + name: norefjell + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:30:17 + width: 9 + Tag_71: + name: coach + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:30:15 + width: 5 + Tag_72: + name: baby + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:30:52 + width: 4 + Tag_73: + name: cute + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:30:50 + width: 4 + Tag_74: + name: park + approved: 1 + approved_by: sfGuardUser_4 + approved_at: 2008-04-25 16:31:31 + width: 4 + Tag_75: + name: magic + approved: 1 + approved_by: sfGuardUser_2 + approved_at: 2008-05-15 11:57:59 + Tag_76: + name: roundabout + approved: 1 + approved_by: sfGuardUser_2 + approved_at: 2008-05-15 11:58:01 + Tag_77: + name: swindon + approved: 1 + approved_by: sfGuardUser_2 + approved_at: 2008-05-15 11:58:02 + Tag_78: + name: driving + approved: 1 + approved_by: sfGuardUser_2 + approved_at: 2008-05-15 11:57:56 + Tag_79: + name: tourist + approved: 1 + approved_by: sfGuardUser_2 + approved_at: 2008-05-15 11:58:04 + Tag_80: + name: england + approved: 1 + approved_by: sfGuardUser_2 + approved_at: 2008-05-15 11:57:58 + +Tagging: + Tagging_1: + tag_id: Tag_9 + taggable_model: ReaktorFile + taggable_id: 1 + parent_approved: 0 + parent_user_id: sfGuardUser_3 + Tagging_2: + tag_id: Tag_11 + taggable_model: ReaktorFile + taggable_id: 1 + parent_approved: 0 + parent_user_id: sfGuardUser_3 + Tagging_3: + tag_id: Tag_1 + taggable_model: ReaktorFile + taggable_id: 1 + parent_approved: 0 + parent_user_id: sfGuardUser_3 + Tagging_4: + tag_id: Tag_15 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_5: + tag_id: Tag_17 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_6: + tag_id: Tag_58 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_7: + tag_id: Tag_59 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_8: + tag_id: Tag_52 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_9: + tag_id: Tag_54 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_10: + tag_id: Tag_60 + taggable_model: ReaktorFile + taggable_id: 3 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_11: + tag_id: Tag_18 + taggable_model: ReaktorFile + taggable_id: 3 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_12: + tag_id: Tag_61 + taggable_model: ReaktorFile + taggable_id: 3 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_13: + tag_id: Tag_21 + taggable_model: ReaktorFile + taggable_id: 3 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_14: + tag_id: Tag_24 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_15: + tag_id: Tag_51 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_16: + tag_id: Tag_26 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_17: + tag_id: Tag_38 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_18: + tag_id: Tag_27 + taggable_model: ReaktorFile + taggable_id: 5 + parent_approved: 1 + parent_user_id: sfGuardUser_2 + Tagging_19: + tag_id: Tag_62 + taggable_model: ReaktorFile + taggable_id: 5 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_20: + tag_id: Tag_41 + taggable_model: ReaktorFile + taggable_id: 6 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_21: + tag_id: Tag_44 + taggable_model: ReaktorFile + taggable_id: 6 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_22: + tag_id: Tag_44 + taggable_model: ReaktorFile + taggable_id: 7 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_23: + tag_id: Tag_46 + taggable_model: ReaktorFile + taggable_id: 7 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_24: + tag_id: Tag_41 + taggable_model: ReaktorFile + taggable_id: 7 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_25: + tag_id: Tag_45 + taggable_model: ReaktorFile + taggable_id: 7 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_26: + tag_id: Tag_32 + taggable_model: ReaktorFile + taggable_id: 8 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_27: + tag_id: Tag_34 + taggable_model: ReaktorFile + taggable_id: 8 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_28: + tag_id: Tag_33 + taggable_model: ReaktorFile + taggable_id: 8 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_29: + tag_id: Tag_50 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_30: + tag_id: Tag_54 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_31: + tag_id: Tag_52 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_32: + tag_id: Tag_55 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_33: + tag_id: Tag_53 + taggable_model: ReaktorFile + taggable_id: 10 + parent_approved: 1 + parent_user_id: sfGuardUser_5 + Tagging_34: + tag_id: Tag_50 + taggable_model: ReaktorFile + taggable_id: 10 + parent_approved: 1 + parent_user_id: sfGuardUser_5 + Tagging_35: + tag_id: Tag_54 + taggable_model: ReaktorFile + taggable_id: 10 + parent_approved: 1 + parent_user_id: sfGuardUser_5 + Tagging_36: + tag_id: Tag_55 + taggable_model: ReaktorFile + taggable_id: 10 + parent_approved: 1 + parent_user_id: sfGuardUser_5 + Tagging_37: + tag_id: Tag_63 + taggable_model: ReaktorFile + taggable_id: 1 + parent_approved: 0 + parent_user_id: sfGuardUser_3 + Tagging_38: + tag_id: Tag_64 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_39: + tag_id: Tag_65 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_40: + tag_id: Tag_66 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_41: + tag_id: Tag_67 + taggable_model: ReaktorFile + taggable_id: 3 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_42: + tag_id: Tag_67 + taggable_model: ReaktorFile + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_43: + tag_id: Tag_22 + taggable_model: ReaktorFile + taggable_id: 3 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_44: + tag_id: Tag_64 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_45: + tag_id: Tag_8 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_46: + tag_id: Tag_66 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_47: + tag_id: Tag_61 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_48: + tag_id: Tag_68 + taggable_model: ReaktorFile + taggable_id: 4 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_49: + tag_id: Tag_9 + taggable_model: ReaktorFile + taggable_id: 5 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_50: + tag_id: Tag_11 + taggable_model: ReaktorFile + taggable_id: 5 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_51: + tag_id: Tag_10 + taggable_model: ReaktorFile + taggable_id: 5 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_52: + tag_id: Tag_69 + taggable_model: ReaktorFile + taggable_id: 5 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_53: + tag_id: Tag_63 + taggable_model: ReaktorFile + taggable_id: 5 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_54: + tag_id: Tag_70 + taggable_model: ReaktorFile + taggable_id: 6 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_55: + tag_id: Tag_45 + taggable_model: ReaktorFile + taggable_id: 6 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_56: + tag_id: Tag_71 + taggable_model: ReaktorFile + taggable_id: 6 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_57: + tag_id: Tag_42 + taggable_model: ReaktorFile + taggable_id: 6 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_58: + tag_id: Tag_70 + taggable_model: ReaktorFile + taggable_id: 7 + parent_approved: 0 + parent_user_id: sfGuardUser_2 + Tagging_59: + tag_id: Tag_72 + taggable_model: ReaktorFile + taggable_id: 8 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_60: + tag_id: Tag_73 + taggable_model: ReaktorFile + taggable_id: 8 + parent_approved: 1 + parent_user_id: sfGuardUser_3 + Tagging_61: + tag_id: Tag_64 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_62: + tag_id: Tag_56 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_63: + tag_id: Tag_63 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_64: + tag_id: Tag_73 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_65: + tag_id: Tag_69 + taggable_model: ReaktorFile + taggable_id: 9 + parent_approved: 0 + parent_user_id: sfGuardUser_5 + Tagging_66: + tag_id: Tag_74 + taggable_model: ReaktorFile + taggable_id: 10 + parent_approved: 1 + parent_user_id: sfGuardUser_5 + Tagging_67: + tag_id: Tag_51 + taggable_model: ReaktorFile + taggable_id: 10 + parent_approved: 1 + parent_user_id: sfGuardUser_5 + Tagging_68: + tag_id: Tag_73 + taggable_model: ReaktorFile + taggable_id: 10 + parent_approved: 1 + parent_user_id: sfGuardUser_5 + Tagging_69: + tag_id: Tag_74 + taggable_model: ReaktorFile + taggable_id: 11 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_70: + tag_id: Tag_62 + taggable_model: ReaktorFile + taggable_id: 11 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_71: + tag_id: Tag_1 + taggable_model: ReaktorFile + taggable_id: 11 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_72: + tag_id: Tag_75 + taggable_model: ReaktorFile + taggable_id: 12 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_73: + tag_id: Tag_76 + taggable_model: ReaktorFile + taggable_id: 12 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_74: + tag_id: Tag_77 + taggable_model: ReaktorFile + taggable_id: 12 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_75: + tag_id: Tag_78 + taggable_model: ReaktorFile + taggable_id: 12 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_76: + tag_id: Tag_79 + taggable_model: ReaktorFile + taggable_id: 12 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_77: + tag_id: Tag_80 + taggable_model: ReaktorFile + taggable_id: 12 + parent_approved: 1 + parent_user_id: sfGuardUser_6 + Tagging_78: + tag_id: Tag_43 + taggable_model: Article + taggable_id: 1 + parent_approved: 1 + parent_user_id: sfGuardUser_4 + Tagging_79: + tag_id: Tag_1 + taggable_model: Article + taggable_id: 1 + parent_approved: 1 + parent_user_id: sfGuardUser_4 + Tagging_80: + tag_id: Tag_43 + taggable_model: Article + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_4 + Tagging_81: + tag_id: Tag_34 + taggable_model: Article + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_4 + Tagging_82: + tag_id: Tag_31 + taggable_model: Article + taggable_id: 2 + parent_approved: 1 + parent_user_id: sfGuardUser_4 + Tagging_83: + tag_id: Tag_31 + taggable_model: Article + taggable_id: 1 + parent_approved: 1 + parent_user_id: sfGuardUser_4 + Tagging_84: + tag_id: Tag_70 + taggable_model: ReaktorFile + taggable_id: 13 + parent_approved: 1 + parent_user_id: sfGuardUser_2 + Tagging_85: + tag_id: Tag_12 + taggable_model: ReaktorFile + taggable_id: 13 + parent_approved: 1 + parent_user_id: sfGuardUser_2 + \ No newline at end of file diff --git a/data/fixtures/04filesArtworks.yml b/data/fixtures/04filesArtworks.yml new file mode 100644 index 0000000..de484a8 --- /dev/null +++ b/data/fixtures/04filesArtworks.yml @@ -0,0 +1,403 @@ +ReaktorFile: + ReaktorFile_1: + filename: myimage.jpg + user_id: sfGuardUser_3 + realpath: image0044.jpg + thumbpath: image0044.jpg + originalpath: image0044.jpg + original_mimetype_id: 2 + converted_mimetype_id: 2 + thumbnail_mimetype_id: 2 + uploaded_at: 2008-02-10 12:54:08 + modified_at: 2008-02-10 12:54:08 + identifier: image + under_discussion: 0 + deleted: 0 + ReaktorFile_2: + filename: mydoc.pdf + user_id: sfGuardUser_3 + realpath: > + 1202926111_1__O__Reilly__PHP__Cookbook_.pdf + thumbpath: > + 1202926111_1__O__Reilly__PHP__Cookbook_.pdf.jpg + originalpath: > + 1202926111_1__O__Reilly__PHP__Cookbook_.pdf + original_mimetype_id: 3 + converted_mimetype_id: 3 + thumbnail_mimetype_id: 2 + uploaded_at: 2008-02-12 13:12:09 + modified_at: 2008-02-12 13:12:09 + identifier: pdf + deleted: 0 + ReaktorFile_3: + filename: lovely.jpg + user_id: sfGuardUser_3 + realpath: 1204733647_1_IMG_5382.JPG + thumbpath: 1204733647_1_IMG_5382.JPG + originalpath: 1204733647_1_IMG_5382.JPG + original_mimetype_id: 2 + converted_mimetype_id: 2 + thumbnail_mimetype_id: 2 + uploaded_at: 2007-01-01 01:01:54 + modified_at: 2007-01-01 01:01:54 + identifier: image + deleted: 0 + ReaktorFile_4: + filename: wetbird.jpg + user_id: sfGuardUser_3 + realpath: 1204735759_1_IMG_1252.jpg + thumbpath: 1204735759_1_IMG_1252.jpg + originalpath: 1204735759_1_IMG_1252.jpg + original_mimetype_id: 2 + converted_mimetype_id: 2 + thumbnail_mimetype_id: 2 + uploaded_at: 2007-02-01 01:01:54 + modified_at: 2007-02-01 01:01:54 + identifier: image + deleted: 0 + ReaktorFile_5: + filename: fingers.flv + user_id: sfGuardUser_2 + realpath: fingers.flv + thumbpath: fingers.flv.jpg + originalpath: fingers.flv + original_mimetype_id: 4 + converted_mimetype_id: 4 + thumbnail_mimetype_id: 2 + uploaded_at: 2008-02-10 14:54:08 + modified_at: 2008-02-10 14:54:08 + identifier: video + deleted: 0 + ReaktorFile_6: + filename: space-door.mp3 + user_id: sfGuardUser_2 + realpath: space-door.mp3 + thumbpath: space-door.mp3.jpg + originalpath: space-door.mp3 + original_mimetype_id: 5 + converted_mimetype_id: 5 + thumbnail_mimetype_id: 2 + uploaded_at: 2008-02-10 14:54:09 + modified_at: 2008-02-10 14:54:09 + identifier: audio + deleted: 0 + ReaktorFile_7: + filename: dolor_sit.txt + user_id: sfGuardUser_2 + realpath: dolor_sit.txt + thumbpath: dolor_sit.txt.jpg + originalpath: dolor_sit.txt + original_mimetype_id: 9 + converted_mimetype_id: 9 + thumbnail_mimetype_id: 2 + uploaded_at: 2008-02-20 13:10:17 + modified_at: 2008-02-20 13:10:17 + identifier: text + deleted: 0 + ReaktorFile_8: + filename: abigail_frogner.jpg + user_id: sfGuardUser_3 + realpath: 1204736133_1_IMG_3154x.jpg + thumbpath: 1204736133_1_IMG_3154x.jpg + originalpath: 1204736133_1_IMG_3154x.jpg + original_mimetype_id: 2 + converted_mimetype_id: 2 + thumbnail_mimetype_id: 2 + uploaded_at: 2007-03-01 01:01:54 + modified_at: 2007-03-01 01:01:54 + identifier: image + deleted: 0 + ReaktorFile_9: + filename: IMG_0318.JPG + user_id: sfGuardUser_5 + realpath: 1207596441_5_IMG_0318.JPG + thumbpath: 1207596441_5_IMG_0318.JPG + originalpath: 1207596441_5_IMG_0318.JPG + original_mimetype_id: 2 + converted_mimetype_id: 2 + thumbnail_mimetype_id: 2 + uploaded_at: 2008-04-07 21:27:23 + modified_at: 2008-04-07 21:27:23 + identifier: image + deleted: 0 + ReaktorFile_10: + filename: IMG_0057c.jpg + user_id: sfGuardUser_5 + realpath: 1207596762_5_IMG_0057c.jpg + thumbpath: 1207596762_5_IMG_0057c.jpg + originalpath: 1207596762_5_IMG_0057c.jpg + original_mimetype_id: 2 + converted_mimetype_id: 2 + thumbnail_mimetype_id: 2 + uploaded_at: 2008-04-07 21:32:43 + modified_at: 2008-04-07 21:32:43 + reported_at: 2008-04-08 22:14:10 + reported: 6 + total_reported_ever: 24 + identifier: image + deleted: 0 + ReaktorFile_11: + filename: mcartoon.gif + user_id: sfGuardUser_6 + realpath: 1210074241_1_mcartoon.gif + thumbpath: 1210074241_1_mcartoon.gif + originalpath: 1210074241_1_mcartoon.gif + original_mimetype_id: 7 + converted_mimetype_id: 7 + thumbnail_mimetype_id: 7 + uploaded_at: 2008-05-06 13:44:02 + modified_at: 2008-05-06 13:44:02 + reported: 0 + total_reported_ever: 0 + identifier: image + ReaktorFile_12: + filename: swindonRAB.jpg + user_id: sfGuardUser_6 + realpath: 1210845302_6_swindonRAB.jpg + thumbpath: 1210845302_6_swindonRAB.jpg + originalpath: 1210845302_6_swindonRAB.jpg + original_mimetype_id: 2 + converted_mimetype_id: 2 + thumbnail_mimetype_id: 2 + uploaded_at: 2008-05-15 11:55:03 + modified_at: 2008-05-15 11:55:03 + reported: 0 + total_reported_ever: 0 + marked_unsuitable: 0 + identifier: image + deleted: 0 + ReaktorFile_13: + filename: 31D108EFB82DBA8654FD35499218B9A111B3E96792071F3DDCC0FE97FD4D517E.swf + user_id: sfGuardUser_2 + realpath: 1216811137_2_31D108EFB82DBA8654FD35499218B9A111B3E96792071F3DDCC0FE97FD4D517E.swf + thumbpath: + originalpath: 1216811137_2_31D108EFB82DBA8654FD35499218B9A111B3E96792071F3DDCC0FE97FD4D517E.swf + original_mimetype_id: 6 + converted_mimetype_id: 6 + thumbnail_mimetype_id: 5 + uploaded_at: 2008-07-23 13:05:38 + modified_at: 2008-07-23 13:05:38 + reported: 0 + total_reported_ever: 0 + marked_unsuitable: 0 + identifier: flash_animation + deleted: 0 + +ReaktorArtwork: + ReaktorArtwork_1: + user_id: sfGuardUser_3 + artwork_identifier: image + created_at: 2008-03-05 18:30:37 + submitted_at: 2008-03-02 21:28:08 + title: The wonderful painting + status: ArtworkStatus_2 + description: This painting is wonderful + artwork_order: 0 + deleted: 0 + average_rating: 0 + team_id: sfGuardGroup_9 + first_file_id: ReaktorFile_1 + ReaktorArtwork_2: + user_id: sfGuardUser_3 + artwork_identifier: image + created_at: 2008-03-05 18:30:37 + submitted_at: 2008-02-20 21:30:54 + actioned_at: 2008-03-10 21:00:00 + title: The fancy gallery + actioned_by: 1 + status: ArtworkStatus_3 + description: This is an awesome gallery + artwork_order: 0 + deleted: 0 + average_rating: 5.5 + team_id: sfGuardGroup_5 + under_discussion: 1 + first_file_id: ReaktorFile_3 + ReaktorArtwork_3: + user_id: sfGuardUser_3 + artwork_identifier: pdf + created_at: 2008-03-05 18:30:37 + submitted_at: 2008-01-23 21:31:21 + actioned_at: 2008-03-03 21:31:27 + title: My Pdf + actioned_by: 0 + status: ArtworkStatus_3 + description: This pdf is the bomb + artwork_order: 0 + deleted: 0 + average_rating: 3.5 + team_id: sfGuardGroup_9 + first_file_id: ReaktorFile_2 + ReaktorArtwork_4: + user_id: sfGuardUser_2 + artwork_identifier: video + created_at: 2008-03-05 18:30:37 + submitted_at: 2008-03-02 21:31:35 + actioned_at: 2008-03-02 21:31:41 + title: Fingers + actioned_by: 0 + status: ArtworkStatus_3 + description: Fingers, what more do you want? + artwork_order: 0 + deleted: 0 + average_rating: 4.5 + team_id: sfGuardGroup_8 + first_file_id: ReaktorFile_5 + ReaktorArtwork_5: + user_id: sfGuardUser_2 + artwork_identifier: audio + created_at: 2008-03-05 18:30:37 + submitted_at: 2008-02-14 21:31:50 + title: Spacy + actioned_by: 0 + status: ArtworkStatus_2 + description: woooooosh + artwork_order: 0 + deleted: 0 + average_rating: 0 + team_id: sfGuardGroup_6 + first_file_id: ReaktorFile_6 + ReaktorArtwork_6: + user_id: sfGuardUser_2 + artwork_identifier: text + created_at: 2008-03-05 18:30:37 + submitted_at: 2008-01-07 21:32:05 + title: Dolor Sit + actioned_by: 0 + status: ArtworkStatus_2 + description: Lorem Ipsum blah blah blah + artwork_order: 0 + deleted: 0 + average_rating: 0 + team_id: sfGuardGroup_7 + first_file_id: ReaktorFile_7 + ReaktorArtwork_7: + user_id: sfGuardUser_5 + artwork_identifier: image + created_at: 2008-04-07 21:28:03 + submitted_at: 2008-04-07 21:28:03 + title: Cute monkeys + actioned_by: 0 + status: ArtworkStatus_2 + description: Awwwww, so cute + artwork_order: 0 + deleted: 0 + average_rating: 0 + team_id: sfGuardGroup_5 + first_file_id: ReaktorFile_9 + ReaktorArtwork_8: + user_id: sfGuardUser_5 + artwork_identifier: image + created_at: 2008-04-07 21:33:25 + submitted_at: 2008-04-07 21:33:25 + actioned_at: 2008-04-08 21:31:27 + title: Nice monkeys + actioned_by: 1 + status: ArtworkStatus_3 + description: W00t + artwork_order: 0 + deleted: 0 + average_rating: 0 + team_id: sfGuardGroup_5 + first_file_id: ReaktorFile_10 + ReaktorArtwork_9: + user_id: sfGuardUser_6 + artwork_identifier: image + created_at: 2008-05-06 13:45:41 + submitted_at: 2008-05-06 13:45:41 + actioned_at: 2008-05-06 13:46:27 + title: Nice cartoon + actioned_by: 1 + status: ArtworkStatus_3 + description: Did it make you laugh too? + artwork_order: 0 + deleted: 0 + average_rating: 0 + team_id: sfGuardGroup_10 + first_file_id: ReaktorFile_11 + ReaktorArtwork_10: + user_id: sfGuardUser_6 + artwork_identifier: image + created_at: 2008-05-15 11:56:46 + submitted_at: 2008-05-15 11:56:46 + actioned_at: 2008-05-15 11:57:39 + title: Magic roundabout - Swindon + actioned_by: 1 + status: ArtworkStatus_3 + description: 'It''s magic, don''t you think?' + artwork_order: 0 + deleted: 0 + average_rating: 0 + team_id: sfGuardGroup_5 + first_file_id: ReaktorFile_12 + ReaktorArtwork_11: + user_id: sfGuardUser_2 + artwork_identifier: flash_animation + created_at: 2008-07-23 13:05:38 + submitted_at: 2008-07-23 13:05:38 + actioned_at: 2008-07-23 13:05:38 + title: Magic animations + actioned_by: 1 + status: ArtworkStatus_3 + description: '''tis my magic animation file! Watch it! Oh, and you need sound.' + artwork_order: 0 + deleted: 0 + average_rating: 0 + team_id: sfGuardGroup_10 + first_file_id: ReaktorFile_13 + + + +ReaktorArtworkFile: + ReaktorArtworkFile_1_1: + artwork_id: ReaktorArtwork_1 + file_id: ReaktorFile_1 + file_order: 1 + ReaktorArtworkFile_2_3: + artwork_id: ReaktorArtwork_2 + file_id: ReaktorFile_3 + file_order: 1 + ReaktorArtworkFile_2_4: + artwork_id: ReaktorArtwork_2 + file_id: ReaktorFile_4 + file_order: 1 + ReaktorArtworkFile_2_8: + artwork_id: ReaktorArtwork_2 + file_id: ReaktorFile_8 + file_order: 1 + ReaktorArtworkFile_3_2: + artwork_id: ReaktorArtwork_3 + file_id: ReaktorFile_2 + file_order: 1 + ReaktorArtworkFile_4_5: + artwork_id: ReaktorArtwork_4 + file_id: ReaktorFile_5 + file_order: 1 + ReaktorArtworkFile_5_6: + artwork_id: ReaktorArtwork_5 + file_id: ReaktorFile_6 + file_order: 1 + ReaktorArtworkFile_6_7: + artwork_id: ReaktorArtwork_6 + file_id: ReaktorFile_7 + file_order: 1 + ReaktorArtworkFile_7_9: + artwork_id: ReaktorArtwork_7 + file_id: ReaktorFile_9 + file_order: 1 + ReaktorArtworkFile_8_10: + artwork_id: ReaktorArtwork_8 + file_id: ReaktorFile_10 + file_order: 1 + ReaktorArtworkFile_9_11: + artwork_id: ReaktorArtwork_9 + file_id: ReaktorFile_11 + file_order: 1 + ReaktorArtworkFile_10_12: + artwork_id: ReaktorArtwork_10 + file_id: ReaktorFile_12 + file_order: 1 + ReaktorArtworkFile_11_13: + artwork_id: ReaktorArtwork_11 + file_id: ReaktorFile_13 + file_order: 1 diff --git a/data/fixtures/04metadata.yml b/data/fixtures/04metadata.yml new file mode 100644 index 0000000..a121395 --- /dev/null +++ b/data/fixtures/04metadata.yml @@ -0,0 +1,454 @@ +FileMetadata: + FileMetadata_1: + file: ReaktorFile_1 + meta_element: creator + meta_qualifier: + meta_value: Spartacus + FileMetadata_2: + file: ReaktorFile_2 + meta_element: creator + meta_qualifier: + meta_value: Uncle Sam + FileMetadata_4: + file: ReaktorFile_6 + meta_element: creator + meta_qualifier: + meta_value: Bob + FileMetadata_5: + file: ReaktorFile_6 + meta_element: description + meta_qualifier: abstract + meta_value: Something Kjellm uploaded + FileMetadata_6: + file: ReaktorFile_6 + meta_element: description + meta_qualifier: creation + meta_value: > + Kinda out there... + FileMetadata_7: + file: ReaktorFile_6 + meta_element: relation + meta_qualifier: references + meta_value: | + http://www.google.co.uk + http://eatmymonkeydust.com + FileMetadata_8: + file: ReaktorFile_6 + meta_element: subject + meta_qualifier: + meta_value: > + text, latin, filler, snow, ski, + marianne, sam + FileMetadata_9: + file: ReaktorFile_6 + meta_element: license + meta_qualifier: + meta_value: free_use + FileMetadata_10: + file: ReaktorFile_1 + meta_element: license + meta_qualifier: + meta_value: free_use + FileMetadata_11: + file: ReaktorFile_2 + meta_element: license + meta_qualifier: + meta_value: contact + FileMetadata_12: + file: ReaktorFile_3 + meta_element: license + meta_qualifier: + meta_value: free_use + FileMetadata_13: + file: ReaktorFile_1 + meta_element: title + meta_qualifier: + meta_value: Japan subway + FileMetadata_14: + file: ReaktorFile_2 + meta_element: title + meta_qualifier: + meta_value: PHP Cookbook + FileMetadata_15: + file: ReaktorFile_3 + meta_element: title + meta_qualifier: + meta_value: Filming in Saudi Arabia + FileMetadata_16: + file: ReaktorFile_6 + meta_element: title + meta_qualifier: + meta_value: My first nice sound clip + FileMetadata_17: + file: ReaktorFile_5 + meta_element: title + meta_qualifier: + meta_value: Some crazy fingers + FileMetadata_18: + file: ReaktorFile_7 + meta_element: license + meta_qualifier: + meta_value: free_use + FileMetadata_19: + file: ReaktorFile_6 + meta_element: license + meta_qualifier: + meta_value: no_allow + FileMetadata_20: + file: ReaktorFile_5 + meta_element: license + meta_qualifier: + meta_value: contact + FileMetadata_21: + file: ReaktorFile_1 + meta_element: description + meta_qualifier: abstract + meta_value: | + What is this crazy lady doing? + Well, I suppose if you spend every day on the subway... ! + FileMetadata_22: + file: ReaktorFile_1 + meta_element: subject + meta_qualifier: + meta_value: japan, rest, subway, lady + FileMetadata_23: + file: ReaktorFile_2 + meta_element: description + meta_qualifier: abstract + meta_value: > + It might be a picture of my car, but + underneath lies a useful PDF :o) + FileMetadata_24: + file: ReaktorFile_2 + meta_element: description + meta_qualifier: creation + meta_value: > + I didn't produce this, although I did + take the picture for the thumbnail! + FileMetadata_25: + file: ReaktorFile_2 + meta_element: subject + meta_qualifier: + meta_value: php, cookbook, car, ford, focus + FileMetadata_26: + file: ReaktorFile_3 + meta_element: description + meta_qualifier: abstract + meta_value: > + On the water between Bahrain and Saudi + Arabia, filming an interview + FileMetadata_27: + file: ReaktorFile_3 + meta_element: description + meta_qualifier: creation + meta_value: > + Clearly I didn't take this picture, that + was probably Sean! + FileMetadata_28: + file: ReaktorFile_3 + meta_element: subject + meta_qualifier: + meta_value: > + Saudi Arabia, Bahrain, Squash, boat, + water, psalive + FileMetadata_29: + file: ReaktorFile_3 + meta_element: creator + meta_qualifier: + meta_value: Sean + FileMetadata_30: + file: ReaktorFile_5 + meta_element: description + meta_qualifier: abstract + meta_value: Something Kjellm uploaded + FileMetadata_31: + file: ReaktorFile_5 + meta_element: description + meta_qualifier: creation + meta_value: No idea who created this, or why! + FileMetadata_32: + file: ReaktorFile_5 + meta_element: subject + meta_qualifier: + meta_value: fingers, strange, count + FileMetadata_33: + file: ReaktorFile_5 + meta_element: creator + meta_qualifier: + meta_value: Some dude + FileMetadata_34: + file: ReaktorFile_7 + meta_element: description + meta_qualifier: abstract + meta_value: Something Kjellm uploaded + FileMetadata_35: + file: ReaktorFile_7 + meta_element: description + meta_qualifier: creation + meta_value: > + Somebody pressed the latin filler text + button + FileMetadata_36: + file: ReaktorFile_7 + meta_element: subject + meta_qualifier: + meta_value: text, latin, filler + FileMetadata_37: + file: ReaktorFile_7 + meta_element: creator + meta_qualifier: + meta_value: Spartacus + FileMetadata_38: + file: ReaktorFile_7 + meta_element: title + meta_qualifier: + meta_value: Random plain text + FileMetadata_39: + file: ReaktorFile_7 + meta_element: license + meta_qualifier: + meta_value: contact + FileMetadata_40: + file: ReaktorFile_4 + meta_element: description + meta_qualifier: abstract + meta_value: Taken inside the Eden Project + FileMetadata_41: + file: ReaktorFile_4 + meta_element: description + meta_qualifier: creation + meta_value: | + EOS 350D + f/2.8 + 1/80 + ISO: 100 + 50mm + FileMetadata_42: + file: ReaktorFile_4 + meta_element: subject + meta_qualifier: + meta_value: bird, wet, Eden project + FileMetadata_43: + file: ReaktorFile_4 + meta_element: creator + meta_qualifier: + meta_value: Russ + FileMetadata_44: + file: ReaktorFile_4 + meta_element: title + meta_qualifier: + meta_value: Wet Robin + FileMetadata_45: + file: ReaktorFile_4 + meta_element: license + meta_qualifier: + meta_value: contact + FileMetadata_46: + file: ReaktorFile_8 + meta_element: description + meta_qualifier: abstract + meta_value: Loving the B&W + FileMetadata_47: + file: ReaktorFile_8 + meta_element: description + meta_qualifier: creation + meta_value: | + EOS 350D + f/6.3 + 1/50 + ISO: 100 + 40mm + FileMetadata_48: + file: ReaktorFile_8 + meta_element: subject + meta_qualifier: + meta_value: abigail, statue, frogner + FileMetadata_49: + file: ReaktorFile_8 + meta_element: creator + meta_qualifier: + meta_value: Russ + FileMetadata_50: + file: ReaktorFile_8 + meta_element: title + meta_qualifier: + meta_value: Abigail at Frogner + FileMetadata_51: + file: ReaktorFile_8 + meta_element: license + meta_qualifier: + meta_value: contact + FileMetadata_52: + file: ReaktorFile_9 + meta_element: description + meta_qualifier: creation + meta_value: Me and my camera + FileMetadata_53: + file: ReaktorFile_9 + meta_element: type + meta_qualifier: + meta_value: image/jpeg + FileMetadata_54: + file: ReaktorFile_9 + meta_element: format + meta_qualifier: width + meta_value: 2996 + FileMetadata_55: + file: ReaktorFile_9 + meta_element: format + meta_qualifier: height + meta_value: 2084 + FileMetadata_56: + file: ReaktorFile_9 + meta_element: date + meta_qualifier: creation + meta_value: 2007:06:19 14:37:01 + FileMetadata_57: + file: ReaktorFile_9 + meta_element: format + meta_qualifier: size + meta_value: 5280277 + FileMetadata_58: + file: ReaktorFile_9 + meta_element: creator + meta_qualifier: + meta_value: dave + FileMetadata_59: + file: ReaktorFile_9 + meta_element: title + meta_qualifier: + meta_value: Cute monkeys + FileMetadata_60: + file: ReaktorFile_9 + meta_element: description + meta_qualifier: abstract + meta_value: Cute monkeys!! + FileMetadata_61: + file: ReaktorFile_9 + meta_element: license + meta_qualifier: + meta_value: contact + FileMetadata_62: + file: ReaktorFile_10 + meta_element: description + meta_qualifier: creation + meta_value: Me and my camera + FileMetadata_63: + file: ReaktorFile_10 + meta_element: type + meta_qualifier: + meta_value: image/jpeg + FileMetadata_64: + file: ReaktorFile_10 + meta_element: format + meta_qualifier: width + meta_value: 1432 + FileMetadata_65: + file: ReaktorFile_10 + meta_element: format + meta_qualifier: height + meta_value: 1040 + FileMetadata_66: + file: ReaktorFile_10 + meta_element: date + meta_qualifier: creation + meta_value: 2007:06:19 11:29:26 + FileMetadata_67: + file: ReaktorFile_10 + meta_element: format + meta_qualifier: size + meta_value: 1302543 + FileMetadata_68: + file: ReaktorFile_10 + meta_element: creator + meta_qualifier: + meta_value: dave + FileMetadata_69: + file: ReaktorFile_10 + meta_element: title + meta_qualifier: + meta_value: Nice monkeys + FileMetadata_70: + file: ReaktorFile_10 + meta_element: description + meta_qualifier: abstract + meta_value: Actually Lemurs... ! + FileMetadata_71: + file: ReaktorFile_10 + meta_element: license + meta_qualifier: + meta_value: no_allow + FileMetadata_72: + file: ReaktorFile_11 + meta_element: creator + meta_qualifier: + meta_value: June + FileMetadata_73: + file: ReaktorFile_11 + meta_element: title + meta_qualifier: + meta_value: Nice cartoon + FileMetadata_74: + file: ReaktorFile_11 + meta_element: description + meta_qualifier: abstract + meta_value: A cartoon I don't understand... + FileMetadata_75: + file: ReaktorFile_11 + meta_element: description + meta_qualifier: creation + meta_value: > + June uploaded it and I nicked it to put + in the fixtures + FileMetadata_76: + file: ReaktorFile_11 + meta_element: license + meta_qualifier: + meta_value: free_use + FileMetadata_77: + file: ReaktorFile_12 + meta_element: creator + meta_qualifier: + meta_value: dave + FileMetadata_78: + file: ReaktorFile_12 + meta_element: title + meta_qualifier: + meta_value: Magic roundabout - Swindon + FileMetadata_79: + file: ReaktorFile_12 + meta_element: relation + meta_qualifier: references + meta_value: > + http://en.wikipedia.org/wiki/Magic_Roundabout_(Swindon) + FileMetadata_80: + file: ReaktorFile_12 + meta_element: license + meta_qualifier: + meta_value: free_use + FileMetadata_81: + file: ReaktorFile_12 + meta_element: description + meta_qualifier: abstract + meta_value: Yes it exists + FileMetadata_82: + file: ReaktorFile_12 + meta_element: description + meta_qualifier: creation + meta_value: Nicked it from Google images + FileMetadata_83: + file: ReaktorFile_13 + meta_element: title + meta_qualifier: + meta_value: Magic animations + FileMetadata_84: + file: ReaktorFile_13 + meta_element: description + meta_qualifier: abstract + meta_value: '''tis my magic animation file! Watch it! Oh, and you need sound.' + FileMetadata_85: + file: ReaktorFile_13 + meta_element: license + meta_qualifier: + meta_value: by-sa + \ No newline at end of file diff --git a/data/fixtures/05commentRatingFavourite.yml b/data/fixtures/05commentRatingFavourite.yml new file mode 100644 index 0000000..4df36b8 --- /dev/null +++ b/data/fixtures/05commentRatingFavourite.yml @@ -0,0 +1,292 @@ +sfComment: + sfComment_1: + commentable_model: ReaktorArtwork + commentable_id: 1 + namespace: frontend + title: Something I made + text: She made me giggle when I saw her :D + author_id: sfGuardUser_3 + created_at: 2008-04-07 13:18:36 + unsuitable: 0 + sfComment_2: + commentable_model: ReaktorArtwork + commentable_id: 3 + namespace: frontend + title: Nice PDF? + text: | + Anybody like my PDF? + + bøøøøøøøø + author_id: sfGuardUser_3 + created_at: 2008-04-07 13:19:10 + unsuitable: 0 + sfComment_3: + commentable_model: ReaktorArtwork + commentable_id: 2 + namespace: frontend + title: This is a very fancy gallery, no? + text: > + Looks like I'm the only person making + comments then :( + author_id: sfGuardUser_3 + created_at: 2008-04-07 13:19:45 + unsuitable: 0 + sfComment_4: + commentable_model: ReaktorArtwork + commentable_id: 4 + namespace: frontend + title: Hey Monkey! + text: | + Nice Vid :D + + I especially like the fingers + author_id: sfGuardUser_3 + created_at: 2008-04-07 13:20:13 + unsuitable: 0 + sfComment_5: + parent_id: 4 + commentable_model: ReaktorArtwork + commentable_id: 4 + namespace: frontend + title: Haha + text: Cheers Monkey + author_id: sfGuardUser_2 + created_at: 2008-04-07 13:21:16 + unsuitable: 0 + sfComment_6: + commentable_model: ReaktorArtwork + commentable_id: 4 + namespace: frontend + title: My note... ! + text: > + Personally, I like the way the fingers + are all the same length... ! + author_id: sfGuardUser_2 + created_at: 2008-04-07 13:21:38 + unsuitable: 0 + sfComment_7: + commentable_model: ReaktorArtwork + commentable_id: 2 + namespace: frontend + title: Sheesh + text: | + Calm down Userboy... there aren't exactly a flood of visiors yet are there? + + Give it time... God Påske! + author_id: sfGuardUser_2 + created_at: 2008-04-07 13:22:27 + unsuitable: 0 + sfComment_8: + commentable_model: ReaktorArtwork + commentable_id: 3 + namespace: frontend + title: Huh? + text: | + It's just a pdf... calm down. + + åøæøåøæøå <--- Random :D + author_id: sfGuardUser_2 + created_at: 2008-04-07 13:23:02 + unsuitable: 0 + sfComment_9: + commentable_model: ReaktorArtwork + commentable_id: 5 + namespace: frontend + title: Music to my ears + text: hmm... ! + author_id: sfGuardUser_2 + created_at: 2008-04-07 13:23:44 + unsuitable: 0 + sfComment_10: + commentable_model: ReaktorArtwork + commentable_id: 7 + namespace: frontend + title: Like my monkeys? + text: I do! + author_id: sfGuardUser_5 + created_at: 2008-04-07 21:28:17 + unsuitable: 0 + sfComment_11: + commentable_model: ReaktorArtwork + commentable_id: 2 + namespace: frontend + title: Great + text: Great picture mate! + author_id: sfGuardUser_5 + created_at: 2008-04-07 21:28:39 + unsuitable: 0 + sfComment_12: + commentable_model: ReaktorArtwork + commentable_id: 4 + namespace: frontend + title: WTF + text: I mean seriously, wtf? + author_id: sfGuardUser_5 + created_at: 2008-04-07 21:29:06 + unsuitable: 1 + sfComment_13: + parent_id: 4 + commentable_model: ReaktorArtwork + commentable_id: 4 + namespace: frontend + title: Not me + text: I have to disagree... they freak me out + author_id: sfGuardUser_5 + created_at: 2008-04-07 21:29:23 + unsuitable: 0 + sfComment_14: + commentable_model: ReaktorArtwork + commentable_id: 2 + namespace: frontend + title: Wow + text: I love this pic mate! Nice one... ! + author_id: sfGuardUser_5 + created_at: 2008-04-07 21:30:18 + unsuitable: 0 + sfComment_15: + parent_id: 7 + commentable_model: ReaktorArtwork + commentable_id: 2 + namespace: frontend + title: huh? + text: God what? + author_id: sfGuardUser_5 + created_at: 2008-04-07 21:30:35 + unsuitable: 1 + sfComment_16: + commentable_model: ReaktorArtwork + commentable_id: 3 + namespace: frontend + title: What? + text: | + I come looking for porn and all I get is a lousy PDF :( + + I must say I am disappointed... ! + author_id: sfGuardUser_5 + created_at: 2008-04-07 21:32:35 + unsuitable: 0 + sfComment_17: + commentable_model: ReaktorArtwork + commentable_id: 3 + namespace: frontend + title: C1alis at net prices + text: | + Please your woman today! + author_id: sfGuardUser_5 + created_at: 2008-05-07 13:15:15 + unsuitable: 2 + sfComment_18: + parent_id: 2 + commentable_model: ReaktorArtwork + commentable_id: 3 + namespace: frontend + title: Short in bed? + text: | + Go to myenlargement.ru and give your p3n1s a lift! + author_id: sfGuardUser_5 + created_at: 2008-05-07 13:15:15 + unsuitable: 1 + sfComment_19: + parent_id: 2 + commentable_model: ReaktorArtwork + commentable_id: 3 + namespace: frontend + title: I hate Colin + text: | + Colin is nothing but a spongy stack of vapid grits + author_id: sfGuardUser_5 + created_at: 2008-04-07 12:15:15 + unsuitable: 1 + sfComment_20: + commentable_model: ReaktorArtwork + commentable_id: 2 + namespace: administrator + title: A comment + text: I just wanted to comment + author_id: sfGuardUser_1 + created_at: 2008-07-11 11:24:10 + unsuitable: 0 + email_notify: 0 + +sfRating: + sfRating_1: + ratable_model: ReaktorArtwork + ratable_id: 4 + user_id: 3 + rating: 4 + sfRating_2: + ratable_model: ReaktorArtwork + ratable_id: 3 + user_id: 2 + rating: 3 + sfRating_3: + ratable_model: ReaktorArtwork + ratable_id: 2 + user_id: 2 + rating: 6 + sfRating_4: + ratable_model: ReaktorArtwork + ratable_id: 4 + user_id: 5 + rating: 5 + sfRating_5: + ratable_model: ReaktorArtwork + ratable_id: 2 + user_id: 5 + rating: 5 + sfRating_6: + ratable_model: ReaktorArtwork + ratable_id: 3 + user_id: 5 + rating: 4 + + +Favourite: + Favourite_1: + user_id: sfGuardUser_2 + artwork_id: ReaktorArtwork_2 + fav_type: artwork + Favourite_2: + user_id: sfGuardUser_4 + artwork_id: ReaktorArtwork_2 + fav_type: artwork + Favourite_3: + user_id: sfGuardUser_3 + artwork_id: ReaktorArtwork_4 + fav_type: artwork + Favourite_4: + user_id: sfGuardUser_4 + artwork_id: ReaktorArtwork_1 + fav_type: artwork + Favourite_5: + user_id: sfGuardUser_5 + artwork_id: ReaktorArtwork_6 + fav_type: artwork + Favourite_6: + user_id: sfGuardUser_6 + artwork_id: ReaktorArtwork_2 + fav_type: artwork + Favourite_7: + user_id: sfGuardUser_1 + artwork_id: ReaktorArtwork_2 + fav_type: artwork + Favourite_8: + user_id: sfGuardUser_2 + friend_id: sfGuardUser_1 + fav_type: user + Favourite_9: + user_id: sfGuardUser_2 + friend_id: sfGuardUser_4 + fav_type: user + Favourite_10: + user_id: sfGuardUser_2 + friend_id: sfGuardUser_5 + fav_type: user + Favourite_11: + user_id: sfGuardUser_2 + friend_id: sfGuardUser_6 + fav_type: user + Favourite_12: + user_id: sfGuardUser_6 + friend_id: sfGuardUser_2 + fav_type: user diff --git a/data/fixtures/06artworkcategories.yml b/data/fixtures/06artworkcategories.yml new file mode 100644 index 0000000..b33e94c --- /dev/null +++ b/data/fixtures/06artworkcategories.yml @@ -0,0 +1,121 @@ +CategoryArtwork: + CategoryArtwork_1: + category_id: Category_12 + artwork_id: ReaktorArtwork_1 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:01:09 + CategoryArtwork_2: + category_id: Category_8 + artwork_id: ReaktorArtwork_1 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:01:11 + CategoryArtwork_3: + category_id: Category_4 + artwork_id: ReaktorArtwork_2 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:01:27 + CategoryArtwork_4: + category_id: Category_8 + artwork_id: ReaktorArtwork_2 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:01:29 + CategoryArtwork_5: + category_id: Category_12 + artwork_id: ReaktorArtwork_2 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:01:34 + CategoryArtwork_6: + category_id: Category_56 + artwork_id: ReaktorArtwork_3 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:01:52 + CategoryArtwork_7: + category_id: Category_67 + artwork_id: ReaktorArtwork_3 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:01:55 + CategoryArtwork_8: + category_id: Category_24 + artwork_id: ReaktorArtwork_4 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:03 + CategoryArtwork_9: + category_id: Category_23 + artwork_id: ReaktorArtwork_4 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:05 + CategoryArtwork_10: + category_id: Category_40 + artwork_id: ReaktorArtwork_5 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:14 + CategoryArtwork_11: + category_id: Category_36 + artwork_id: ReaktorArtwork_5 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:16 + CategoryArtwork_12: + category_id: Category_56 + artwork_id: ReaktorArtwork_6 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:23 + CategoryArtwork_13: + category_id: Category_62 + artwork_id: ReaktorArtwork_6 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:24 + CategoryArtwork_14: + category_id: Category_68 + artwork_id: ReaktorArtwork_6 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:28 + CategoryArtwork_15: + category_id: Category_3 + artwork_id: ReaktorArtwork_7 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:34 + CategoryArtwork_16: + category_id: Category_10 + artwork_id: ReaktorArtwork_7 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:37 + CategoryArtwork_17: + category_id: Category_3 + artwork_id: ReaktorArtwork_8 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:48 + CategoryArtwork_18: + category_id: Category_10 + artwork_id: ReaktorArtwork_8 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:49 + CategoryArtwork_19: + category_id: Category_54 + artwork_id: ReaktorArtwork_9 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:03:04 + CategoryArtwork_20: + category_id: Category_48 + artwork_id: ReaktorArtwork_9 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:02:58 + CategoryArtwork_21: + category_id: Category_44 + artwork_id: ReaktorArtwork_9 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:03:07 + CategoryArtwork_22: + category_id: Category_19 + artwork_id: ReaktorArtwork_10 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:03:29 + CategoryArtwork_23: + category_id: Category_21 + artwork_id: ReaktorArtwork_11 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:03:29 + CategoryArtwork_24: + category_id: Category_22 + artwork_id: ReaktorArtwork_11 + added_by: sfGuardUser_2 + created_at: 2008-05-15 18:03:29 \ No newline at end of file diff --git a/data/fixtures/07relatedArtworks.yml b/data/fixtures/07relatedArtworks.yml new file mode 100644 index 0000000..a0937a3 --- /dev/null +++ b/data/fixtures/07relatedArtworks.yml @@ -0,0 +1,28 @@ +# These values link two artworks that are somehow related +# Relationships will be used in the "see also" list + +RelatedArtwork: + RelatedArtwork_1: + first_artwork: ReaktorArtwork_1 + second_artwork: ReaktorArtwork_3 + created_at: 2008-05-06 15:51:44 + created_by: sfGuardUser_4 + order_by: 0 + RelatedArtwork_2: + first_artwork: ReaktorArtwork_1 + second_artwork: ReaktorArtwork_2 + created_at: 2008-05-05 15:52:37 + created_by: sfGuardUser_4 + order_by: 0 + RelatedArtwork_3: + first_artwork: ReaktorArtwork_5 + second_artwork: ReaktorArtwork_4 + created_at: 2008-05-06 14:52:37 + created_by: sfGuardUser_3 + order_by: 0 + RelatedArtwork_3: + first_artwork: ReaktorArtwork_2 + second_artwork: ReaktorArtwork_3 + created_at: 2008-05-06 14:52:37 + created_by: sfGuardUser_4 + order_by: 0 \ No newline at end of file diff --git a/data/fixtures/09SubreaktorArtwork.yml b/data/fixtures/09SubreaktorArtwork.yml new file mode 100644 index 0000000..e11a549 --- /dev/null +++ b/data/fixtures/09SubreaktorArtwork.yml @@ -0,0 +1,63 @@ +# These values link subreaktors to artworks + +SubreaktorArtwork: + SubreaktorArtwork_1: + subreaktor_id: Subreaktor_1 + artwork_id: ReaktorArtwork_1 + + SubreaktorArtwork_2: + subreaktor_id: Subreaktor_1 + artwork_id: ReaktorArtwork_2 + + SubreaktorArtwork_3: + subreaktor_id: Subreaktor_1 + artwork_id: ReaktorArtwork_7 + + SubreaktorArtwork_4: + subreaktor_id: Subreaktor_1 + artwork_id: ReaktorArtwork_8 + + SubreaktorArtwork_5: + subreaktor_id: Subreaktor_5 + artwork_id: ReaktorArtwork_9 + + SubreaktorArtwork_6: + subreaktor_id: Subreaktor_6 + artwork_id: ReaktorArtwork_3 + + SubreaktorArtwork_7: + subreaktor_id: Subreaktor_3 + artwork_id: ReaktorArtwork_4 + + SubreaktorArtwork_8: + subreaktor_id: Subreaktor_4 + artwork_id: ReaktorArtwork_5 + + SubreaktorArtwork_9: + subreaktor_id: Subreaktor_6 + artwork_id: ReaktorArtwork_6 + + SubreaktorArtwork_10: + subreaktor_id: Subreaktor_2 + artwork_id: ReaktorArtwork_10 + + SubreaktorArtwork_11: + subreaktor_id: Subreaktor_3 + artwork_id: ReaktorArtwork_11 + +LokalreaktorArtwork: + lokalreaktorwork_1: + subreaktor_id: Subreaktor_7 + artwork_id: ReaktorArtwork_1 + + lokalreaktorwork_2: + subreaktor_id: Subreaktor_7 + artwork_id: ReaktorArtwork_3 + + lokalreaktorwork_3: + subreaktor_id: Subreaktor_7 + artwork_id: ReaktorArtwork_5 + + lokalreaktorwork_4: + subreaktor_id: Subreaktor_7 + artwork_id: ReaktorArtwork_8 \ No newline at end of file diff --git a/data/fixtures/10Messaging.yml b/data/fixtures/10Messaging.yml new file mode 100644 index 0000000..47a13e8 --- /dev/null +++ b/data/fixtures/10Messaging.yml @@ -0,0 +1,7 @@ +# System message when the system has been rebuilt + +AdminMessage: + AdminMessage_1: + message: System has been updated! + author: sfGuardUser_1 + expires_at: \ No newline at end of file diff --git a/data/fixtures/11RecommendedArtwork.yml b/data/fixtures/11RecommendedArtwork.yml new file mode 100644 index 0000000..40b07fb --- /dev/null +++ b/data/fixtures/11RecommendedArtwork.yml @@ -0,0 +1,17 @@ +# These values links an artwork to a subreaktor, including subreaktors within a localreaktor +# The relations will be displayed/listed in an admin backend, and updated by admins by clicking +# links next to artworks + +RecommendedArtwork: + RecommendedArtwork_1: + artwork: ReaktorArtwork_8 + subreaktor: Subreaktor_7 #Grorudalen + localsubreaktor: Subreaktor_1 #Photo + updated_by: sfGuardUser_2 + updated_at: 2008-05-06 14:52:37 + RecommendedArtwork_2: + artwork: ReaktorArtwork_9 + subreaktor: Subreaktor_5 #Cartoon + updated_by: sfGuardUser_2 + updated_at: 2008-05-06 14:53:37 + diff --git a/data/fixtures/12ReportBookmarks.yml b/data/fixtures/12ReportBookmarks.yml new file mode 100644 index 0000000..6be0901 --- /dev/null +++ b/data/fixtures/12ReportBookmarks.yml @@ -0,0 +1,155 @@ +ReportBookmark: + ReportBookmark_1: + title: All approved + description: > + All approved artworks - no other filters + applied + args: > + /category_id/17/editorial_team_id/5/editorial_team_member_id/1/status_check/1/status_value/3/subreaktor_id/1 + type: artwork + list_order: 0 + ReportBookmark_2: + title: All rejected + description: > + All rejected artwork - no other filters + applied + args: > + /category_id/17/editorial_team_id/5/editorial_team_member_id/1/status_check/1/status_value/4/subreaktor_id/1 + type: artwork + list_order: 2 + ReportBookmark_3: + title: All under discussion + description: > + All artwork that is currently marked + under discussion + args: > + /category_id/17/editorial_team_id/5/editorial_team_member_id/1/status_value/4/subreaktor_id/1/under_discussion_check/1 + type: artwork + list_order: 1 + ReportBookmark_4: + title: All awaiting approval + description: > + All artwork that is currently submitted + for approval + args: > + /category_id/17/editorial_team_id/5/editorial_team_member_id/1/status_check/1/status_value/2/subreaktor_id/1 + type: artwork + list_order: 5 + ReportBookmark_7: + title: All this month + description: > + Artworks that have been submitted in the + current month (dynamic) + args: > + /category_id/17/current_month_check/1/editorial_team_id/5/editorial_team_member_id/1/status_value/2/subreaktor_id/1 + type: artwork + list_order: 0 + ReportBookmark_6: + title: Awaiting approval in Tekst + description: > + Artwork in tekst subreaktor that has + been submitted and is awaiting approval + args: > + /category_id/17/editorial_team_id/5/editorial_team_member_id/1/status_check/1/status_value/2/subreaktor_check/1/subreaktor_id/6 + type: artwork + list_order: 3 + ReportBookmark_8: + title: All registered users + description: > + This report will return all the + registered users on the system, + regardless of status + args: > + /execute/userReport/residence/1/sex/1 + type: user + list_order: 1 + ReportBookmark_9: + title: All registered this month + description: > + All the users that have registered this + month (dynamic) + args: > + /current_month_check/1/execute/userReport/residence/1/sex/1 + type: user + list_order: 2 + ReportBookmark_10: + title: Active uploaders this month + description: > + The users that have been most active + when uploading content this month + args: > + /execute/activityReport + type: user + list_order: 3 + ReportBookmark_11: + title: Most comments this month + description: > + The users that have been most active at + commenting this month + args: > + /current_month_activity_check/1/execute/activityReport/reportType/1 + type: user + list_order: 4 + ReportBookmark_12: + title: Active users + description: > + Users that have commented or written + comments or uploaded + args: > + /commentedArtwork/1/execute/userReport/publishedArtwork/1/residence/1/sex/1/voted/1 + type: user + list_order: 5 + ReportBookmark_13: + title: Passive users + description: > + Users that have not uploaded, commented + or voted + args: > + /commentAndOr/1/execute/userReport/notCommentedArtwork/1/notPublishedArtwork/1/notVoted/1/residence/1/sex/1/voteAndOr/1 + type: user + list_order: 6 + ReportBookmark_14: + title: Active non-uploaders + description: > + Users who have commented and voted but + have not published anything + args: > + /commentAndOr/1/commentedArtwork/1/execute/userReport/notPublishedArtwork/1/residence/1/sex/1voteAndOr/1/voted/1 + type: user + list_order: 7 + ReportBookmark_15: + title: Super-active male users + description: > + Male users that have uploaded, commented + and voted + args: > + /commentAndOr/1/commentedArtwork/1/execute/userReport/publishedArtwork/1/residence/1/sex/1/sex_check/1/voteAndOr/1/voted/1 + type: user + list_order: 8 + ReportBookmark_16: + title: Super-active Female users + description: > + Female users that have uploaded, + commented and voted + args: > + /commentAndOr/1/commentedArtwork/1/execute/userReport/publishedArtwork/1/residence/1/sex/2/sex_check/1/voteAndOr/1/voted/1 + type: user + list_order: 0 + ReportBookmark_17: + title: Active female users + description: > + Female users that have commented, + uploaded or voted + args: > + /commentedArtwork/1/execute/userReport/publishedArtwork/1/residence/1/sex/2/sex_check/1/voted/1 + type: user + list_order: 0 + ReportBookmark_18: + title: Active male users + description: > + Male users that have commented, voted or + uploaded + args: > + /commentedArtwork/1/execute/userReport/publishedArtwork/1/residence/1/sex/1/sex_check/1/voted/1 + type: user + list_order: 0 \ No newline at end of file diff --git a/data/fixtures/13Articles.yml b/data/fixtures/13Articles.yml new file mode 100644 index 0000000..fed5b57 --- /dev/null +++ b/data/fixtures/13Articles.yml @@ -0,0 +1,444 @@ +ArticleFile: + ArticleFile_1: + filename: 1219391213_1_talenter_i_tusj.jpg + path: /opt/reaktor/web/uploads/attachments/ + uploaded_by: sfGuardUser_1 + uploaded_at: 2008-08-22 09:46:52 + file_mimetype_id: FileMimetype_2 + ArticleFile_2: + filename: 1219391824_1_jack-russell-terrier.jpg + path: /opt/reaktor/web/uploads/attachments/ + uploaded_by: sfGuardUser_1 + uploaded_at: 2008-08-22 09:57:03 + file_mimetype_id: FileMimetype_2 +Article: + Article_1: + created_at: 2008-08-22 09:18:55 + author_id: sfGuardUser_4 + base_title: Lorem Ipsum + permalink: Lorem_Ipsum + ingress: > + Lorem ipsum dolor sit amet, consectetuer + adipiscing elit. Suspendisse consequat + sagittis dui. Aenean tincidunt pulvinar + neque. In fermentum, purus eu iaculis + ultricies, augue urna accumsan arcu, vel + pulvinar turpis massa non neque. Nunc + congue dapibus libero. Vivamus ut quam. + In pede. Proin ac leo. Phasellus + fermentum lacus quis eros. Sed dignissim + elit volutpat massa interdum rutrum. + Cras non felis vel dolor vestibulum + lacinia. + content: | + Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse consequat sagittis dui. Aenean tincidunt pulvinar neque. In fermentum, purus eu iaculis ultricies, augue urna accumsan arcu, vel pulvinar turpis massa non neque. Nunc congue dapibus libero. Vivamus ut quam. In pede. Proin ac leo. Phasellus fermentum lacus quis eros. Sed dignissim elit volutpat massa interdum rutrum. Cras non felis vel dolor vestibulum lacinia. + + Nullam porttitor purus in nunc. Sed quis pede vel orci faucibus aliquet. Duis adipiscing. Cras at leo. Morbi tortor nunc, adipiscing at, facilisis quis, lobortis imperdiet, ligula. Donec faucibus consequat mauris. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam erat volutpat. Phasellus ipsum. Duis et turpis ac augue dictum accumsan. Curabitur dictum risus non justo. Sed consequat, ligula vel varius euismod, arcu justo accumsan massa, ut porta elit massa sed tellus. Praesent eleifend euismod sapien. Proin pede mi, condimentum vitae, rhoncus ut, facilisis eu, justo. In tellus odio, aliquet quis, adipiscing a, tristique mollis, justo. Pellentesque ac leo nec est iaculis pellentesque. + + Nam id nunc. Donec magna ante, elementum sed, venenatis at, ornare in, ipsum. Aliquam erat volutpat. Aliquam ac lectus. Phasellus consequat odio et sapien. Vivamus eu ligula ac libero varius congue. Pellentesque tincidunt, justo vitae ultricies tincidunt, mauris justo aliquam pede, ac tristique nibh leo in dui. Nunc ut lacus. Nulla eu lectus. Nullam pretium, diam sit amet euismod viverra, leo lectus imperdiet odio, at elementum ipsum nulla eget est. In hac habitasse platea dictumst. Praesent ut mi. Fusce ultricies, erat vel blandit porta, justo nisi tempus metus, sed bibendum velit mi et lorem. Suspendisse id arcu sit amet elit semper pellentesque. Maecenas risus lacus, iaculis non, consequat id, iaculis id, tortor. Aenean ipsum leo, aliquet vitae, adipiscing a, eleifend sit amet, augue. Donec congue sagittis risus. Pellentesque eu turpis. Integer fringilla dictum metus. + updated_at: 2008-08-22 09:18:55 + updated_by: 1 + article_type: 1 + article_order: 0 + status: 2 + is_sticky: 0 + frontpage: 0 + Article_2: + created_at: 2008-08-22 09:18:55 + author_id: sfGuardUser_4 + base_title: What is Lorem Ipsum? + permalink: What_is_Lorem_Ipsum_ + ingress: > + Lorem Ipsum is simply dummy text of the + printing and typesetting industry. Lorem + Ipsum has been the industry's standard + dummy text ever since the 1500s, when an + unknown printer took a galley of type + and scrambled it to make a type specimen + book. It has survived not only five + centuries, but also the leap into + electronic typesetting, remaining + essentially unchanged. + content: | + What is Lorem Ipsum? + Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. + + Why do we use it? + It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like). + + Where does it come from? + Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. + updated_at: 2008-08-22 09:18:55 + updated_by: 1 + article_type: 1 + article_order: 0 + status: 2 + is_sticky: 0 + frontpage: 0 + Article_3: + created_at: 2008-08-22 09:18:55 + author_id: sfGuardUser_4 + base_title: What is up in the tech world? + permalink: What_is_up_in_the_tech_world_ + ingress: > + This is an example of how to include RSS + feeds in your articles + content: > +

    Here are the latest stories from + OSNews.com: + [feed=http://osnews.com/files/recent.xml]4[/feed] + Where does it come + from? This is automatically + fetched from the URL provided in this + article. Sweet!

    + updated_at: 2008-08-22 10:12:52 + updated_by: 1 + article_type: 6 + article_order: 0 + status: 2 + is_sticky: 0 + frontpage: 1 + Article_4: + created_at: 2008-08-22 09:21:42 + author_id: sfGuardUser_1 + base_title: Talenter i tusj + permalink: Talenter_i_tusj + ingress: Lyst til å vise frem din tusjtalenter? + content: | +

    +

     

    +

     

    +

     

    +

     

    +

    Nå er høstens Talenter i tusj resultater på plass!
    Mandag 10. desember kl 17 åpner utstillingen på SERIETEKET, Deichmanske bibliotek på Grünerløkka. +

    Talenter i tusj er et nybegynnerkurs i tegneserietegning for unge mellom 12 og 16 år som SERIETEKET avholder to ganger i året. Resultatet denne gangen er 18 fantastisk flotte og kreative tegneserier.

    +

    Kursledere har vært Flu Hartberg Fagprat og Geir Moen De fire store og Når de døde våkner. Kurset var støttet av Kulturrådet.

    +

    Utstillingen vil stå fram til 13. januar på SERIETEKET - men vil for alltid være dokumentert her på Reaktor.

    +

    + updated_at: 2008-08-22 09:49:26 + updated_by: 1 + article_type: 2 + article_order: 0 + expires_at: 2008-12-31 00:00:00 + status: 2 + banner_file_id: ArticleFile_1 + is_sticky: 1 + frontpage: 1 + Article_5: + created_at: 2008-08-22 09:53:45 + author_id: sfGuardUser_1 + base_title: Fotoeditering i GIMP + permalink: Fotoeditering_i_GIMP + ingress: > + Ikke råd til å betale for Photoshop? + Har du prøvd Gimp? + content: | +

    Om Gimp

    +

    Gimp står for "Gnu image manipulation program", og er opprinnelig laget for Linux operativsystemet. Det er et svært avansert bildebehandlingsprogram som ofte sammenlignes med Adobe PhotoShop, og har i mange år har vært Unix- og Linux brukeres førstevalg for å bearbeide bilder eller lage grafikk med. Det kan brukes i mange ulike operativsystemer, deriblant Microsoft Windows og Mac. Programmet er utviklet på frivillig basis av mange programmerere fra hele verden, etter at studentene Spencer Kimball og Peter Mattis startet prosjektet sommeren 1995, ved Berkeley Universitet i California, USA.

    +

     

    +

    OS versjoner

    +

    Gimp finnes for flere ulike operativsystem og plattformer:
    GNU/Linux, Apple Darwin/Mac OSX, Microsoft Windows95, 98, NT4, 2000, og XP, OpenBSD, NetBSD, og FreeBSD, Solaris, SunOS, AIX, HP-UX, Tru64, Digital Unix, OSF/1, IRIX, OS/2, og BeOS.

    +

     

    +

    Installere Gimp i Windows

    +

    På websiden til Gimp kan du laste ned Windows-versjonen. For at Gimp skal fungere i Windows må du også laste ned GTK, et grafisk "bibliotek" som er nødvendig for å kunne bruke det grafiske brukergrensesnittet til Gimp. GTK må installeres først. Både GTK og Gimp er "pakket inn" i vanlige Windows installerings-filer (exe-filer), og installeres på vanlig windows-måte, etter at du har pakket dem ut av zip-filene. Når du dobbel klikker på exe-filene starter installasjons-programmet, som gir veiledende informasjon underveis i installasjons-prosessen. Det anbefales at du også installerer brukermanualen til Gimp, slik at du har tilgang til denne via «Hjelp»-menyen i Gimp. Brukermanualen kan du også laste ned fra Gimp´ s webside, og installasjonen foregår på samme måte, ved at du laster ned en exe-fil (innpakket i en zip-fil), som starter opp et installasjons-program med veiledende instruksjoner når du dobbel klikker den.

    + updated_at: 2008-08-22 09:55:08 + updated_by: 1 + article_type: 1 + article_order: 0 + status: 2 + is_sticky: 0 + frontpage: 0 + Article_6: + created_at: 2008-08-22 09:56:32 + author_id: sfGuardUser_1 + base_title: Hvordan ta dyrebilder + permalink: Hvordan_ta_dyrebilder + ingress: > + Når du skal fotografere dyr - ville + eller tamme - er det en ting du bør ha + i tillegg til kamera - nemlig + tålmodighet. Rikelig med tålmodighet. + Og selvsagt god tid. For du bør belage + deg på en del venting på de riktige + situasjoner. Men tar du deg tid, øker + også sjansene for å få noen fine + blinkskudd. Det hjelper også å ha et + stativ - slik at du er "skuddklar" på + kort varsel når anledningen byr seg. + content: | +

    Generelt
    Konsentrer deg gjerne om en type bilder om gangen - f. eks. oversiktsbilder, når de spiser, andre aktiviteter, nærbilder osv. Da vil du jobbe på en langt mer rolig og strukturert måte, og du får en føling med når du har tatt mange nok bilder av de ulike situasjoner. Dette prinsippet gjelder også i andre situasjoner, med mindre situasjonen tilsier noe annet.

    +

    Ha alltidtid ny film eller tomt minnekort i kamera når du forventer "noe stort" skal skje. Om du har noen bilder igjen på filmen - bytt til ny i et rolig øyeblikk. Du går glipp av mange blinkskudd hvis du må skifte film midt i en stor "happeningen".

    +

    Uventede situasjoner
    Vær på vakt for spesielle hendelser. Prøv å se for deg hvilke situasjoner som kan oppstå. Da kan du få mange artige bilder slik som her - der det ser ut som om føllet hvisker noe i øret til moren.

    +

    Ville dyr
    Å fotografere ville dyr ute i naturen er som regel litt av en tålmodighetsprøve. Men noen ganger har man bare flaks - og dumper midt oppi det. Da gjelder det å beholde roen, slik at dyret ikke blir forstyrret for mye og stikker. Beveg deg rolig og ikke lag skarpe lyder. Mens du gjør klar utstyret, bør du ikke være "på jakt" etter dyret samtidig. Dette oppfatter de som regel, og forsvinner. Prøv å finne ut hvor det beveger seg og leit etter naturlige åpninger i greiner etc. VÆR TÅLMODIG. Stresser du - blir det garantert mislykket.

    +

    I sitt rette element
    Er du heldig - og ikke opptrer truende mot dyret, kan du få flere blinkskudd og den venner seg til både deg og lydene du lager. Du kan nå ha fått en enestående mulighet til å portrettere "Nøtte-liten" i sitt rette element. Etter hvert vil du opptre sikrere i slike situasjoner, og sjansen vil øke for at du får flere slike opplevelser og nye bidrag til albumet.

    + updated_at: 2008-08-22 09:59:03 + updated_by: 1 + article_type: 1 + article_order: 0 + status: 2 + is_sticky: 0 + frontpage: 0 + Article_7: + created_at: 2008-08-22 10:06:53 + author_id: sfGuardUser_1 + base_title: Forskjellen på tags og kategorier + permalink: Forskjellen_paa_tags_og_kategorier + ingress: > + Vi bibliotekarer er jo vant til + kategorier. Men nå, med Web 2.0 har et + nytt konsept kalt tags dukket opp. Hva + er dette, og hvordan er det forskjellig + fra kategorier? + content: > +

    Tags er rett og slett + nøkkelord, s som du fører + opp idet du oppretter en artikkel et + verk eller en fil.

    + updated_at: 2008-08-22 10:07:10 + updated_by: 1 + article_type: 3 + article_order: 0 + status: 2 + is_sticky: 0 + frontpage: 0 + Article_8: + created_at: 2008-08-22 10:08:35 + author_id: sfGuardUser_1 + base_title: Om Reaktor + permalink: Om_Reaktor + content: | +

    +

    REAKTOR - DITT EGET DIGITALE BIBLIOTEK!

    +

    +

    Reaktor er et nettsted der alle kan publisere egenproduserte verk i en rekke forskjellige formater: film, foto, animasjon, musikk, tegneserier, illustrasjon og tekst. Reaktor er et nettsamfunn der brukerne kan få tilbakemelding på det de lager, og få tips fra andre om hvordan de kan utvikle seg videre.

    Reaktor gir alle mulighet til å oppleve publisert materiale som er vurdert og kategorisert av en fagredaksjon. Nettstedet har enkle og intuitive brukergrensesnitt og gode hjelpeverktøy for egenproduksjon.

    +

    HVA KAN REAKTOR BRUKES TIL?

    +
    Publisere

    Brukerne kan selv laste opp egne verk: filmer, foto, animasjoner, musikk, tegneserier, illustrasjoner og tekster.

    Verkene godkjennes av en fagredaksjon før de blir publisert for å hindre misbruk og for å sikre at innholdet ikke bryter norsk lov.

    Få hjelp til å produsere

    Gjennom gode hjelperessurser får brukerne hjelp til å produsere egne verk. Hjelperessursene består også av teoretisk stoff som gir brukeren et grunnlag for å gå mer i dybden.

    Brukere med erfaring og kunnskap kan veilede andre ved å gi gode råd og tips.

    Oppleve

    Reaktor tilbyr et vidt spekter av multimedialt innhold som er organisert slik at verkene er lette å finne på tvers av innhold og form. Utvalgte verk fremheves spesielt.

    Gi og få tilbakemelding

    Brukerne kan gi kommentarer til verkene i Reaktor. Slik kan man få konstruktive tilbakemeldinger og gode råd. Brukerne kan også gi karakter til andres verk. De verkene som er best likt vies ekstra oppmerksomhet

    + updated_at: 2008-08-22 10:09:06 + updated_by: 1 + article_type: 4 + article_order: 2 + status: 2 + is_sticky: 0 + frontpage: 0 + Article_9: + created_at: 2008-08-22 10:12:10 + author_id: sfGuardUser_1 + base_title: Kontakt oss hvis du har spørsmål + permalink: Kontakt_oss_hvis_du_har_spoersmaal + ingress: > + Velkommen til Reaktor, dette er et + relativt nytt system, og du er invitert + til å teste systemet. + content: > +

    Hvis du finner feil kan du ta kontakt + med oss på you@yourhost.no.

    + updated_at: 2008-08-22 10:12:38 + updated_by: 1 + article_type: 4 + article_order: 4 + status: 2 + is_sticky: 0 + frontpage: 0 + Article_10: + created_at: 2008-08-22 10:12:10 + author_id: sfGuardUser_1 + base_title: Login help + permalink: login_help + ingress: > + Dette er en login help artikkel. + content: > + Dette er en login help artikkel som ikke har noen hjelp enda.. + updated_at: 2008-08-22 10:12:38 + updated_by: 1 + article_type: 4 + article_order: 1 + status: 2 + is_sticky: 0 + frontpage: 0 + Article_11: + created_at: 2008-08-22 10:12:10 + author_id: sfGuardUser_1 + base_title: Vilkår for publisering + permalink: terms_and_conditions + ingress: + content: | +

    VILKÅR FOR PUBLISERING I REAKTOR

    +
      +
    • Ved å publisere det jeg har laget i Reaktor, tillater jeg Deichmanske Bibliotek å gi andre Reaktorbrukere lesetilgang til mitt arbeid.
    • +
    • Når andre Reaktorbrukere får lesetilgang til mitt arbeid, betyr dette også at andre Reaktorbrukere har mulighet til å kopiere mitt arbeid, elektronisk eller analogt, til privat bruk.
    • +
    • Jeg er kjent med at jeg bare kan publisere det jeg selv lager i Reaktor. Jeg kan også bruke arbeid som allerede finnes i Reaktor med kopirettigheten "Jeg tillater andre Reaktorbrukere fri kopiering av mitt arbeid" som grunnlag for mitt eget arbeid, men da må jeg oppgi kilden jeg bruker.
    • +
    +

     

    +

    FORKLARING

    +

    +

    Å legge ut noe på Internett tilhører opphavsmannens enerett. Å legge ut noe på Internett regnes som "offentlig fremføring" i juridisk forstand, jfr Åndsverkloven § 2,3 ledd. Det er bare opphavsmannen, eller den som har fått godkjennelse av opphavsmannen, som kan legge ut noe på Internett.

    +

    Selv om et dokument allerede ligger på Internett, er det likevel bare opphavsmannen, eller den som har fått godkjennelse fra opphavsmannen, som kan legge ut dokumentet på en annen nettside.

    +

    At et dokument ligger på Internett med opphavsmannens samtykke, betyr heller ikke at dokumentet fritt kan kopieres - uavhengig om dokumentet kopieres elektronisk, eller om det tas utskrift av dokumentet.

    +

    Derimot kan alle dokument som ligger på Internett, kopieres innenfor åvl. §12 - regelen om privatkopiering. Privatpersoner kan ta kopier eller skrive ut det de finner på Internett, men altså ikke legge ut disse dokumentene på egen hjemmeside eller redigere dem og legge dem ut.

    +

    + updated_at: 2008-08-28 09:47:50 + updated_by: 1 + article_type: 4 + article_order: 3 + status: 2 + is_sticky: 0 + frontpage: 0 +ArticleCategory: + ArticleCategory_1: + article_id: Article_1 + category_id: Category_1 + ArticleCategory_2: + article_id: Article_2 + category_id: Category_54 + ArticleCategory_3: + article_id: Article_6 + category_id: Category_3 +ArticleSubreaktor: + ArticleSubreaktor_1: + article_id: Article_6 + subreaktor_id: Subreaktor_1 + ArticleSubreaktor_2: + article_id: Article_5 + subreaktor_id: Subreaktor_1 + ArticleSubreaktor_3: + article_id: Article_1 + subreaktor_id: Subreaktor_1 + +ArticleI18n: + ArticleI18n_1_no: + id: Article_1 + culture: 'no' + title: Lorem Ipsum + ArticleI18n_2_no: + id: Article_2 + culture: 'no' + title: What is Lorem Ipsum? + ArticleI18n_3_no: + id: Article_3 + culture: 'no' + title: What is up in the tech world? + ArticleI18n_4_no: + id: Article_4 + culture: 'no' + title: Talenter i tusj + ArticleI18n_5_no: + id: Article_5 + culture: 'no' + title: Fotoeditering i GIMP + ArticleI18n_6_no: + id: Article_6 + culture: 'no' + title: Hvordan ta dyrebilder + ArticleI18n_7_no: + id: Article_7 + culture: 'no' + title: Forskjellen på tags og kategorier + ArticleI18n_8_no: + id: Article_8 + culture: 'no' + title: Om Reaktor + ArticleI18n_9_no: + id: Article_9 + culture: 'no' + title: Kontakt + ArticleI18n_10_no: + id: Article_10 + culture: 'no' + title: Hjelp + ArticleI18n_11_no: + id: Article_11 + culture: 'no' + title: Vilkår for bruk + ArticleI18n_1_nn: + id: Article_1 + culture: 'nn' + title: Lorem Ipsum + ArticleI18n_2_nn: + id: Article_2 + culture: 'nn' + title: What is Lorem Ipsum? + ArticleI18n_3_nn: + id: Article_3 + culture: 'nn' + title: What is up in the tech world? + ArticleI18n_4_nn: + id: Article_4 + culture: 'nn' + title: Talenter i tusj + ArticleI18n_5_nn: + id: Article_5 + culture: 'nn' + title: Fotoeditering i GIMP + ArticleI18n_6_nn: + id: Article_6 + culture: 'nn' + title: Hvordan ta dyrebilder + ArticleI18n_7_nn: + id: Article_7 + culture: 'nn' + title: Forskjellen på tags og kategorier + ArticleI18n_8_nn: + id: Article_8 + culture: 'nn' + title: Om Reaktor + ArticleI18n_9_nn: + id: Article_9 + culture: 'nn' + title: Kontakt + ArticleI18n_10_nn: + id: Article_10 + culture: 'nn' + title: Hjelp + ArticleI18n_11_nn: + id: Article_11 + culture: 'nn' + title: Vilkår for bruk + ArticleI18n_1_en: + id: Article_1 + culture: 'en' + title: Lorem Ipsum + ArticleI18n_2_en: + id: Article_2 + culture: 'en' + title: What is Lorem Ipsum? + ArticleI18n_3_en: + id: Article_3 + culture: 'en' + title: What is up in the tech world? + ArticleI18n_4_en: + id: Article_4 + culture: 'en' + title: Tusj-talents + ArticleI18n_5_en: + id: Article_5 + culture: 'en' + title: Editing photos in GIMP + ArticleI18n_6_en: + id: Article_6 + culture: 'en' + title: How to take animal pictures + ArticleI18n_7_en: + id: Article_7 + culture: 'en' + title: Tags and categories - what's the difference + ArticleI18n_8_en: + id: Article_8 + culture: 'en' + title: About Reaktor + ArticleI18n_9_en: + id: Article_9 + culture: 'en' + title: Contact us + ArticleI18n_10_en: + id: Article_10 + culture: 'en' + title: Help + ArticleI18n_11_en: + id: Article_11 + culture: 'en' + title: Terms and conditions + +ArticleAttachment: + ArticleAttachment_2: + article_id: Article_6 + file_id: ArticleFile_2 diff --git a/data/fixtures/14History.yml b/data/fixtures/14History.yml new file mode 100644 index 0000000..8795b4e --- /dev/null +++ b/data/fixtures/14History.yml @@ -0,0 +1,7 @@ +History: + History_1: + created_at: 2008-07-11 19:10:15 + action_id: HistoryAction_8 + user_id: sfGuardUser_2 + object_id: 2 + extra_details: reaktorArtwork \ No newline at end of file diff --git a/data/fixtures/99fixtures.yml b/data/fixtures/99fixtures.yml new file mode 100644 index 0000000..e104e73 --- /dev/null +++ b/data/fixtures/99fixtures.yml @@ -0,0 +1,21 @@ +sfGuardUser: + sfGuardUser_1337: + username: superadmin + password: 1337admin + culture: 'no' + created_at: 2008-03-05 18:30:37 + last_login: 2008-03-05 23:16:00 + is_active: 1 + is_verified: 1 + is_super_admin: 1 + show_content: 1 + email: reaktor-test@linpro.no + email_private: 1 + name: admin + name_private: 0 + dob: 1980-01-01 00:00:00 + sex: 2 + description: Hest er best + msn: reaktor@msn.no + icq: 54321 + homepage: http://reaktor.lab.linpro.no diff --git a/data/sql/lib.model.schema.sql b/data/sql/lib.model.schema.sql new file mode 100644 index 0000000..6afc9db --- /dev/null +++ b/data/sql/lib.model.schema.sql @@ -0,0 +1,1071 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +#----------------------------------------------------------------------------- +#-- file_mimetype +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `file_mimetype`; + + +CREATE TABLE `file_mimetype` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `mimetype` VARCHAR(100) NOT NULL, + `identifier` VARCHAR(20) NOT NULL, + PRIMARY KEY (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- subreaktor_artwork +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `subreaktor_artwork`; + + +CREATE TABLE `subreaktor_artwork` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `subreaktor_id` INTEGER NOT NULL, + `artwork_id` INTEGER NOT NULL, + PRIMARY KEY (`id`), + INDEX `subreaktor_artwork_FI_1` (`subreaktor_id`), + CONSTRAINT `subreaktor_artwork_FK_1` + FOREIGN KEY (`subreaktor_id`) + REFERENCES `subreaktor` (`id`), + INDEX `subreaktor_artwork_FI_2` (`artwork_id`), + CONSTRAINT `subreaktor_artwork_FK_2` + FOREIGN KEY (`artwork_id`) + REFERENCES `reaktor_artwork` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- messages +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `messages`; + + +CREATE TABLE `messages` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `to_user_id` INTEGER NOT NULL, + `from_user_id` INTEGER NOT NULL, + `subject` VARCHAR(255), + `message` TEXT, + `timestamp` DATETIME NOT NULL, + `deleted_by_from` INTEGER default 0 NOT NULL, + `deleted_by_to` INTEGER default 0 NOT NULL, + `is_read` INTEGER default 0 NOT NULL, + `is_ignored` INTEGER default 0 NOT NULL, + `is_archived` INTEGER default 0 NOT NULL, + `reply_to` INTEGER default 0, + PRIMARY KEY (`id`), + INDEX `messages_FI_1` (`to_user_id`), + CONSTRAINT `messages_FK_1` + FOREIGN KEY (`to_user_id`) + REFERENCES `sf_guard_user` (`id`), + INDEX `messages_FI_2` (`from_user_id`), + CONSTRAINT `messages_FK_2` + FOREIGN KEY (`from_user_id`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- messages_ignored_user +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `messages_ignored_user`; + + +CREATE TABLE `messages_ignored_user` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `user_id` INTEGER NOT NULL, + `ignores_user_id` INTEGER NOT NULL, + PRIMARY KEY (`id`), + INDEX `messages_ignored_user_FI_1` (`user_id`), + CONSTRAINT `messages_ignored_user_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`), + INDEX `messages_ignored_user_FI_2` (`ignores_user_id`), + CONSTRAINT `messages_ignored_user_FK_2` + FOREIGN KEY (`ignores_user_id`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- admin_message +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `admin_message`; + + +CREATE TABLE `admin_message` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `subject` VARCHAR(255), + `message` TEXT NOT NULL, + `author` INTEGER NOT NULL, + `updated_at` DATETIME, + `expires_at` DATETIME NOT NULL, + `is_deleted` INTEGER default 0, + PRIMARY KEY (`id`), + INDEX `admin_message_FI_1` (`author`), + CONSTRAINT `admin_message_FK_1` + FOREIGN KEY (`author`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- recommended_artwork +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `recommended_artwork`; + + +CREATE TABLE `recommended_artwork` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `artwork` INTEGER NOT NULL, + `subreaktor` INTEGER NOT NULL, + `localsubreaktor` INTEGER, + `updated_by` INTEGER NOT NULL, + `updated_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `recommended_artwork_FI_1` (`artwork`), + CONSTRAINT `recommended_artwork_FK_1` + FOREIGN KEY (`artwork`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `recommended_artwork_FI_2` (`subreaktor`), + CONSTRAINT `recommended_artwork_FK_2` + FOREIGN KEY (`subreaktor`) + REFERENCES `subreaktor` (`id`), + INDEX `recommended_artwork_FI_3` (`localsubreaktor`), + CONSTRAINT `recommended_artwork_FK_3` + FOREIGN KEY (`localsubreaktor`) + REFERENCES `subreaktor` (`id`), + INDEX `recommended_artwork_FI_4` (`updated_by`), + CONSTRAINT `recommended_artwork_FK_4` + FOREIGN KEY (`updated_by`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- report_bookmark +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `report_bookmark`; + + +CREATE TABLE `report_bookmark` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `title` VARCHAR(255) NOT NULL, + `description` TEXT NOT NULL, + `args` TEXT NOT NULL, + `type` VARCHAR(10) default 'artwork' NOT NULL, + `list_order` INTEGER default 0, + PRIMARY KEY (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- reaktor_artwork +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `reaktor_artwork`; + + +CREATE TABLE `reaktor_artwork` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `user_id` INTEGER NOT NULL, + `artwork_identifier` VARCHAR(20) NOT NULL, + `created_at` DATETIME NOT NULL, + `submitted_at` DATETIME, + `actioned_at` DATETIME, + `modified_flag` DATETIME, + `title` VARCHAR(255) NOT NULL, + `actioned_by` INTEGER NOT NULL, + `status` INTEGER NOT NULL, + `description` TEXT, + `modified_note` TEXT, + `artwork_order` INTEGER default 0, + `average_rating` FLOAT default 0, + `team_id` INTEGER NOT NULL, + `under_discussion` INTEGER(1) default 0 NOT NULL, + `multi_user` INTEGER(1) default 0 NOT NULL, + `first_file_id` INTEGER, + `deleted` INTEGER default 0, + PRIMARY KEY (`id`), + INDEX `reaktor_artwork_FI_1` (`user_id`), + CONSTRAINT `reaktor_artwork_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`), + INDEX `reaktor_artwork_FI_2` (`status`), + CONSTRAINT `reaktor_artwork_FK_2` + FOREIGN KEY (`status`) + REFERENCES `artwork_status` (`id`) + ON DELETE RESTRICT, + INDEX `reaktor_artwork_FI_3` (`team_id`), + CONSTRAINT `reaktor_artwork_FK_3` + FOREIGN KEY (`team_id`) + REFERENCES `sf_guard_group` (`id`), + INDEX `reaktor_artwork_FI_4` (`first_file_id`), + CONSTRAINT `reaktor_artwork_FK_4` + FOREIGN KEY (`first_file_id`) + REFERENCES `reaktor_file` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- reaktor_artwork_file +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `reaktor_artwork_file`; + + +CREATE TABLE `reaktor_artwork_file` +( + `artwork_id` INTEGER NOT NULL, + `file_id` INTEGER NOT NULL, + `file_order` INTEGER default 1, + PRIMARY KEY (`artwork_id`,`file_id`), + CONSTRAINT `reaktor_artwork_file_FK_1` + FOREIGN KEY (`artwork_id`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `reaktor_artwork_file_FI_2` (`file_id`), + CONSTRAINT `reaktor_artwork_file_FK_2` + FOREIGN KEY (`file_id`) + REFERENCES `reaktor_file` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- user_interest +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `user_interest`; + + +CREATE TABLE `user_interest` +( + `user_id` INTEGER NOT NULL, + `subreaktor_id` INTEGER NOT NULL, + PRIMARY KEY (`user_id`,`subreaktor_id`), + CONSTRAINT `user_interest_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`) + ON DELETE CASCADE, + INDEX `user_interest_FI_2` (`subreaktor_id`), + CONSTRAINT `user_interest_FK_2` + FOREIGN KEY (`subreaktor_id`) + REFERENCES `subreaktor` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- artwork_status +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `artwork_status`; + + +CREATE TABLE `artwork_status` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL, + PRIMARY KEY (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- artwork_status_i18n +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `artwork_status_i18n`; + + +CREATE TABLE `artwork_status_i18n` +( + `id` INTEGER NOT NULL, + `description` VARCHAR(30) NOT NULL, + `culture` VARCHAR(7) NOT NULL, + PRIMARY KEY (`id`,`culture`), + CONSTRAINT `artwork_status_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `artwork_status` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- residence_level +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `residence_level`; + + +CREATE TABLE `residence_level` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `levelname` VARCHAR(255) NOT NULL, + `listorder` INTEGER(2), + PRIMARY KEY (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- residence_level_i18n +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `residence_level_i18n`; + + +CREATE TABLE `residence_level_i18n` +( + `name` VARCHAR(255) NOT NULL, + `id` INTEGER NOT NULL, + `culture` VARCHAR(7) NOT NULL, + PRIMARY KEY (`id`,`culture`), + CONSTRAINT `residence_level_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `residence_level` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- residence +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `residence`; + + +CREATE TABLE `residence` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `level` INTEGER NOT NULL, + `parent` INTEGER, + PRIMARY KEY (`id`), + INDEX `residence_FI_1` (`level`), + CONSTRAINT `residence_FK_1` + FOREIGN KEY (`level`) + REFERENCES `residence_level` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- lokalreaktor_artwork +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `lokalreaktor_artwork`; + + +CREATE TABLE `lokalreaktor_artwork` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `subreaktor_id` INTEGER NOT NULL, + `artwork_id` INTEGER NOT NULL, + PRIMARY KEY (`id`), + INDEX `lokalreaktor_artwork_FI_1` (`subreaktor_id`), + CONSTRAINT `lokalreaktor_artwork_FK_1` + FOREIGN KEY (`subreaktor_id`) + REFERENCES `subreaktor` (`id`), + INDEX `lokalreaktor_artwork_FI_2` (`artwork_id`), + CONSTRAINT `lokalreaktor_artwork_FK_2` + FOREIGN KEY (`artwork_id`) + REFERENCES `reaktor_artwork` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- lokalreaktor_residence +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `lokalreaktor_residence`; + + +CREATE TABLE `lokalreaktor_residence` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `created_at` DATETIME, + `subreaktor_id` INTEGER NOT NULL, + `residence_id` INTEGER NOT NULL, + PRIMARY KEY (`id`), + INDEX `lokalreaktor_residence_FI_1` (`subreaktor_id`), + CONSTRAINT `lokalreaktor_residence_FK_1` + FOREIGN KEY (`subreaktor_id`) + REFERENCES `subreaktor` (`id`), + INDEX `lokalreaktor_residence_FI_2` (`residence_id`), + CONSTRAINT `lokalreaktor_residence_FK_2` + FOREIGN KEY (`residence_id`) + REFERENCES `residence` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- user_resource +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `user_resource`; + + +CREATE TABLE `user_resource` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `user_id` INTEGER NOT NULL, + `url` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`,`user_id`), + INDEX `user_resource_FI_1` (`user_id`), + CONSTRAINT `user_resource_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- reaktor_file +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `reaktor_file`; + + +CREATE TABLE `reaktor_file` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `filename` VARCHAR(200) NOT NULL, + `user_id` INTEGER NOT NULL, + `realpath` VARCHAR(300) NOT NULL, + `thumbpath` VARCHAR(300) NOT NULL, + `originalpath` VARCHAR(300) NOT NULL, + `original_mimetype_id` INTEGER NOT NULL, + `converted_mimetype_id` INTEGER NOT NULL, + `thumbnail_mimetype_id` INTEGER NOT NULL, + `uploaded_at` DATETIME NOT NULL, + `modified_at` DATETIME NOT NULL, + `reported_at` DATETIME, + `reported` INTEGER(8) default 0 NOT NULL, + `total_reported_ever` INTEGER(8) default 0 NOT NULL, + `marked_unsuitable` INTEGER(1) default 0 NOT NULL, + `under_discussion` INTEGER(1) default 0 NOT NULL, + `identifier` VARCHAR(20) NOT NULL, + `hidden` INTEGER(1) default 0 NOT NULL, + `deleted` INTEGER default 0, + PRIMARY KEY (`id`), + INDEX `reaktor_file_FI_1` (`user_id`), + CONSTRAINT `reaktor_file_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- subreaktor +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `subreaktor`; + + +CREATE TABLE `subreaktor` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `reference` VARCHAR(15) NOT NULL, + `lokalreaktor` INTEGER default 0 NOT NULL, + `live` INTEGER default 0 NOT NULL, + `subreaktor_order` INTEGER default 0, + PRIMARY KEY (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- subreaktor_i18n +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `subreaktor_i18n`; + + +CREATE TABLE `subreaktor_i18n` +( + `name` VARCHAR(255) NOT NULL, + `id` INTEGER NOT NULL, + `culture` VARCHAR(7) NOT NULL, + PRIMARY KEY (`id`,`culture`), + CONSTRAINT `subreaktor_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `subreaktor` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- rejection_type +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `rejection_type`; + + +CREATE TABLE `rejection_type` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `basename` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- rejection_type_i18n +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `rejection_type_i18n`; + + +CREATE TABLE `rejection_type_i18n` +( + `id` INTEGER NOT NULL, + `name` VARCHAR(255) NOT NULL, + `description` TEXT NOT NULL, + `culture` VARCHAR(7) NOT NULL, + PRIMARY KEY (`id`,`culture`), + CONSTRAINT `rejection_type_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `rejection_type` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- related_artwork +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `related_artwork`; + + +CREATE TABLE `related_artwork` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `first_artwork` INTEGER NOT NULL, + `second_artwork` INTEGER NOT NULL, + `created_at` DATETIME NOT NULL, + `created_by` INTEGER NOT NULL, + `order_by` INTEGER default 0, + PRIMARY KEY (`id`), + INDEX `related_artwork_FI_1` (`first_artwork`), + CONSTRAINT `related_artwork_FK_1` + FOREIGN KEY (`first_artwork`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `related_artwork_FI_2` (`second_artwork`), + CONSTRAINT `related_artwork_FK_2` + FOREIGN KEY (`second_artwork`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `related_artwork_FI_3` (`created_by`), + CONSTRAINT `related_artwork_FK_3` + FOREIGN KEY (`created_by`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- reaktor_artwork_history +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `reaktor_artwork_history`; + + +CREATE TABLE `reaktor_artwork_history` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `artwork_id` INTEGER, + `file_id` INTEGER, + `created_at` DATETIME, + `modified_flag` DATETIME, + `user_id` INTEGER NOT NULL, + `status` INTEGER NOT NULL, + `comment` TEXT, + PRIMARY KEY (`id`), + INDEX `reaktor_artwork_history_FI_1` (`artwork_id`), + CONSTRAINT `reaktor_artwork_history_FK_1` + FOREIGN KEY (`artwork_id`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `reaktor_artwork_history_FI_2` (`file_id`), + CONSTRAINT `reaktor_artwork_history_FK_2` + FOREIGN KEY (`file_id`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `reaktor_artwork_history_FI_3` (`user_id`), + CONSTRAINT `reaktor_artwork_history_FK_3` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`), + INDEX `reaktor_artwork_history_FI_4` (`status`), + CONSTRAINT `reaktor_artwork_history_FK_4` + FOREIGN KEY (`status`) + REFERENCES `artwork_status` (`id`) + ON DELETE RESTRICT +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- category +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `category`; + + +CREATE TABLE `category` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `basename` VARCHAR(75) NOT NULL, + PRIMARY KEY (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- category_i18n +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `category_i18n`; + + +CREATE TABLE `category_i18n` +( + `name` VARCHAR(75) NOT NULL, + `id` INTEGER NOT NULL, + `culture` VARCHAR(7) NOT NULL, + PRIMARY KEY (`id`,`culture`), + CONSTRAINT `category_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `category` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- category_artwork +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `category_artwork`; + + +CREATE TABLE `category_artwork` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `category_id` INTEGER, + `artwork_id` INTEGER, + `added_by` INTEGER, + `created_at` DATETIME, + PRIMARY KEY (`id`), + INDEX `category_artwork_FI_1` (`category_id`), + CONSTRAINT `category_artwork_FK_1` + FOREIGN KEY (`category_id`) + REFERENCES `category` (`id`), + INDEX `category_artwork_FI_2` (`artwork_id`), + CONSTRAINT `category_artwork_FK_2` + FOREIGN KEY (`artwork_id`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `category_artwork_FI_3` (`added_by`), + CONSTRAINT `category_artwork_FK_3` + FOREIGN KEY (`added_by`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- category_subreaktor +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `category_subreaktor`; + + +CREATE TABLE `category_subreaktor` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `category_id` INTEGER, + `subreaktor_id` INTEGER, + PRIMARY KEY (`id`), + INDEX `category_subreaktor_FI_1` (`category_id`), + CONSTRAINT `category_subreaktor_FK_1` + FOREIGN KEY (`category_id`) + REFERENCES `category` (`id`), + INDEX `category_subreaktor_FI_2` (`subreaktor_id`), + CONSTRAINT `category_subreaktor_FK_2` + FOREIGN KEY (`subreaktor_id`) + REFERENCES `subreaktor` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- article +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `article`; + + +CREATE TABLE `article` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `created_at` DATETIME, + `author_id` INTEGER NOT NULL, + `base_title` VARCHAR(255) NOT NULL, + `permalink` VARCHAR(255) NOT NULL, + `ingress` TEXT, + `content` TEXT NOT NULL, + `updated_at` DATETIME, + `updated_by` INTEGER default 0 NOT NULL, + `article_type` INTEGER NOT NULL, + `article_order` INTEGER NOT NULL, + `expires_at` DATETIME, + `status` INTEGER NOT NULL, + `published_at` DATETIME, + `banner_file_id` INTEGER default 0, + `is_sticky` INTEGER default 0, + `frontpage` INTEGER default 0, + PRIMARY KEY (`id`), + INDEX `article_FI_1` (`author_id`), + CONSTRAINT `article_FK_1` + FOREIGN KEY (`author_id`) + REFERENCES `sf_guard_user` (`id`), + INDEX `article_FI_2` (`banner_file_id`), + CONSTRAINT `article_FK_2` + FOREIGN KEY (`banner_file_id`) + REFERENCES `article_file` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- article_i18n +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `article_i18n`; + + +CREATE TABLE `article_i18n` +( + `title` VARCHAR(255) NOT NULL, + `id` INTEGER NOT NULL, + `culture` VARCHAR(7) NOT NULL, + PRIMARY KEY (`id`,`culture`), + CONSTRAINT `article_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `article` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- article_article_relation +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `article_article_relation`; + + +CREATE TABLE `article_article_relation` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `created_at` DATETIME, + `first_article` INTEGER NOT NULL, + `second_article` INTEGER NOT NULL, + `created_by` INTEGER NOT NULL, + PRIMARY KEY (`id`), + INDEX `article_article_relation_FI_1` (`first_article`), + CONSTRAINT `article_article_relation_FK_1` + FOREIGN KEY (`first_article`) + REFERENCES `article` (`id`), + INDEX `article_article_relation_FI_2` (`second_article`), + CONSTRAINT `article_article_relation_FK_2` + FOREIGN KEY (`second_article`) + REFERENCES `article` (`id`), + INDEX `article_article_relation_FI_3` (`created_by`), + CONSTRAINT `article_article_relation_FK_3` + FOREIGN KEY (`created_by`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- article_artwork_relation +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `article_artwork_relation`; + + +CREATE TABLE `article_artwork_relation` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `created_at` DATETIME, + `article_id` INTEGER NOT NULL, + `artwork_id` INTEGER NOT NULL, + `created_by` INTEGER NOT NULL, + PRIMARY KEY (`id`), + INDEX `article_artwork_relation_FI_1` (`article_id`), + CONSTRAINT `article_artwork_relation_FK_1` + FOREIGN KEY (`article_id`) + REFERENCES `article` (`id`), + INDEX `article_artwork_relation_FI_2` (`artwork_id`), + CONSTRAINT `article_artwork_relation_FK_2` + FOREIGN KEY (`artwork_id`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `article_artwork_relation_FI_3` (`created_by`), + CONSTRAINT `article_artwork_relation_FK_3` + FOREIGN KEY (`created_by`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- article_file +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `article_file`; + + +CREATE TABLE `article_file` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `filename` VARCHAR(255) NOT NULL, + `path` VARCHAR(255) NOT NULL, + `uploaded_by` INTEGER NOT NULL, + `uploaded_at` DATETIME NOT NULL, + `description` VARCHAR(255), + `file_mimetype_id` INTEGER NOT NULL, + PRIMARY KEY (`id`), + INDEX `article_file_FI_1` (`uploaded_by`), + CONSTRAINT `article_file_FK_1` + FOREIGN KEY (`uploaded_by`) + REFERENCES `sf_guard_user` (`id`), + INDEX `article_file_FI_2` (`file_mimetype_id`), + CONSTRAINT `article_file_FK_2` + FOREIGN KEY (`file_mimetype_id`) + REFERENCES `file_mimetype` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- article_category +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `article_category`; + + +CREATE TABLE `article_category` +( + `article_id` INTEGER NOT NULL, + `category_id` INTEGER NOT NULL, + `id` INTEGER NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`), + INDEX `article_category_FI_1` (`article_id`), + CONSTRAINT `article_category_FK_1` + FOREIGN KEY (`article_id`) + REFERENCES `article` (`id`), + INDEX `article_category_FI_2` (`category_id`), + CONSTRAINT `article_category_FK_2` + FOREIGN KEY (`category_id`) + REFERENCES `category` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- article_subreaktor +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `article_subreaktor`; + + +CREATE TABLE `article_subreaktor` +( + `article_id` INTEGER NOT NULL, + `subreaktor_id` INTEGER NOT NULL, + `id` INTEGER NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`), + INDEX `article_subreaktor_FI_1` (`article_id`), + CONSTRAINT `article_subreaktor_FK_1` + FOREIGN KEY (`article_id`) + REFERENCES `article` (`id`), + INDEX `article_subreaktor_FI_2` (`subreaktor_id`), + CONSTRAINT `article_subreaktor_FK_2` + FOREIGN KEY (`subreaktor_id`) + REFERENCES `subreaktor` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- article_attachment +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `article_attachment`; + + +CREATE TABLE `article_attachment` +( + `article_id` INTEGER NOT NULL, + `file_id` INTEGER NOT NULL, + `id` INTEGER NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`id`), + INDEX `article_attachment_FI_1` (`article_id`), + CONSTRAINT `article_attachment_FK_1` + FOREIGN KEY (`article_id`) + REFERENCES `article` (`id`), + INDEX `article_attachment_FI_2` (`file_id`), + CONSTRAINT `article_attachment_FK_2` + FOREIGN KEY (`file_id`) + REFERENCES `article_file` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- subreaktor_identifier +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `subreaktor_identifier`; + + +CREATE TABLE `subreaktor_identifier` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `subreaktor_id` INTEGER NOT NULL, + `identifier` VARCHAR(20) NOT NULL, + PRIMARY KEY (`id`), + INDEX `subreaktor_identifier_FI_1` (`subreaktor_id`), + CONSTRAINT `subreaktor_identifier_FK_1` + FOREIGN KEY (`subreaktor_id`) + REFERENCES `subreaktor` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- favourite +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `favourite`; + + +CREATE TABLE `favourite` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `user_id` INTEGER NOT NULL, + `artwork_id` INTEGER NOT NULL, + `article_id` INTEGER NOT NULL, + `friend_id` INTEGER NOT NULL, + `fav_type` VARCHAR(8) NOT NULL, + PRIMARY KEY (`id`), + INDEX `favourite_FI_1` (`user_id`), + CONSTRAINT `favourite_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`), + INDEX `favourite_FI_2` (`artwork_id`), + CONSTRAINT `favourite_FK_2` + FOREIGN KEY (`artwork_id`) + REFERENCES `reaktor_artwork` (`id`), + INDEX `favourite_FI_3` (`article_id`), + CONSTRAINT `favourite_FK_3` + FOREIGN KEY (`article_id`) + REFERENCES `article` (`id`), + INDEX `favourite_FI_4` (`friend_id`), + CONSTRAINT `favourite_FK_4` + FOREIGN KEY (`friend_id`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- catalogue +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `catalogue`; + + +CREATE TABLE `catalogue` +( + `cat_id` INTEGER(11) NOT NULL AUTO_INCREMENT, + `name` VARCHAR(100) default '' NOT NULL, + `source_lang` VARCHAR(100) default '' NOT NULL, + `target_lang` VARCHAR(100) default '' NOT NULL, + `date_created` INTEGER(11) default 0 NOT NULL, + `date_modified` INTEGER(11) default 0 NOT NULL, + `author` VARCHAR(255) default '' NOT NULL, + `description` VARCHAR(255) default '' NOT NULL, + PRIMARY KEY (`cat_id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- trans_unit +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `trans_unit`; + + +CREATE TABLE `trans_unit` +( + `msg_id` INTEGER(11) NOT NULL AUTO_INCREMENT, + `cat_id` INTEGER(11) default 1 NOT NULL, + `id` VARCHAR(255) default '', + `source` TEXT NOT NULL, + `target` TEXT NOT NULL, + `module` VARCHAR(255) default '', + `filename` VARCHAR(255) default '', + `comments` TEXT, + `date_added` INTEGER(11) default 0 NOT NULL, + `date_modified` INTEGER(11) default 0 NOT NULL, + `author` VARCHAR(255) default '' NOT NULL, + `translated` INTEGER(1) default 0 NOT NULL, + PRIMARY KEY (`msg_id`), + INDEX `trans_unit_FI_1` (`cat_id`), + CONSTRAINT `trans_unit_FK_1` + FOREIGN KEY (`cat_id`) + REFERENCES `catalogue` (`cat_id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- history +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `history`; + + +CREATE TABLE `history` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `created_at` DATETIME, + `action_id` INTEGER NOT NULL, + `user_id` INTEGER NOT NULL, + `object_id` INTEGER, + `extra_details` TEXT, + PRIMARY KEY (`id`), + INDEX `history_FI_1` (`action_id`), + CONSTRAINT `history_FK_1` + FOREIGN KEY (`action_id`) + REFERENCES `history_action` (`id`), + INDEX `history_FI_2` (`user_id`), + CONSTRAINT `history_FK_2` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- history_action +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `history_action`; + + +CREATE TABLE `history_action` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(50), + PRIMARY KEY (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- history_action_i18n +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `history_action_i18n`; + + +CREATE TABLE `history_action_i18n` +( + `description` TEXT NOT NULL, + `id` INTEGER NOT NULL, + `culture` VARCHAR(7) NOT NULL, + PRIMARY KEY (`id`,`culture`), + CONSTRAINT `history_action_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `history_action` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- file_metadata +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `file_metadata`; + + +CREATE TABLE `file_metadata` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `file` INTEGER NOT NULL, + `meta_element` VARCHAR(100) NOT NULL, + `meta_qualifier` VARCHAR(100) NOT NULL, + `meta_value` TEXT NOT NULL, + PRIMARY KEY (`id`), + INDEX `file_metadata_FI_1` (`file`), + CONSTRAINT `file_metadata_FK_1` + FOREIGN KEY (`file`) + REFERENCES `reaktor_file` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/data/sql/plugins.sfGuardPlugin.lib.model.schema.sql b/data/sql/plugins.sfGuardPlugin.lib.model.schema.sql new file mode 100644 index 0000000..337efaf --- /dev/null +++ b/data/sql/plugins.sfGuardPlugin.lib.model.schema.sql @@ -0,0 +1,202 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +#----------------------------------------------------------------------------- +#-- sf_guard_group +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_guard_group`; + + +CREATE TABLE `sf_guard_group` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `description` TEXT, + `is_editorial_team` INTEGER default 0, + `is_enabled` INTEGER default 0, + PRIMARY KEY (`id`), + UNIQUE KEY `sf_guard_group_name_unique` (`name`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- sf_guard_permission +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_guard_permission`; + + +CREATE TABLE `sf_guard_permission` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `sf_guard_permission_name_unique` (`name`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- sf_guard_group_permission +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_guard_group_permission`; + + +CREATE TABLE `sf_guard_group_permission` +( + `group_id` INTEGER NOT NULL, + `permission_id` INTEGER NOT NULL, + PRIMARY KEY (`group_id`,`permission_id`), + CONSTRAINT `sf_guard_group_permission_FK_1` + FOREIGN KEY (`group_id`) + REFERENCES `sf_guard_group` (`id`) + ON DELETE CASCADE, + INDEX `sf_guard_group_permission_FI_2` (`permission_id`), + CONSTRAINT `sf_guard_group_permission_FK_2` + FOREIGN KEY (`permission_id`) + REFERENCES `sf_guard_permission` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- sf_guard_user +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_guard_user`; + + +CREATE TABLE `sf_guard_user` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `username` VARCHAR(128) NOT NULL, + `algorithm` VARCHAR(128) default 'sha1' NOT NULL, + `salt` VARCHAR(128) NOT NULL, + `password` VARCHAR(128) NOT NULL, + `created_at` DATETIME, + `last_login` DATETIME, + `is_active` INTEGER default 1 NOT NULL, + `is_super_admin` INTEGER default 0 NOT NULL, + `is_verified` INTEGER default 0, + `show_content` INTEGER default 0, + `culture` VARCHAR(10) default 'no', + `email` VARCHAR(128) NOT NULL, + `email_private` INTEGER default 1, + `new_email` VARCHAR(128), + `new_email_key` VARCHAR(128), + `new_password_key` VARCHAR(128), + `key_expires` DATETIME, + `name` VARCHAR(128), + `name_private` INTEGER default 0, + `dob` DATE NOT NULL, + `sex` INTEGER(1) NOT NULL, + `description` TEXT, + `residence_id` INTEGER NOT NULL, + `avatar` VARCHAR(255), + `msn` VARCHAR(128), + `icq` INTEGER, + `homepage` VARCHAR(256), + `phone` VARCHAR(32), + `opt_in` INTEGER default 0, + `editorial_notification` INTEGER default 0, + `show_login_status` INTEGER default 1, + `last_active` DATETIME, + `dob_is_derived` INTEGER default 0 NOT NULL, + `need_profile_check` INTEGER(1) default 0 NOT NULL, + `first_reaktor_login` DATETIME, + PRIMARY KEY (`id`), + UNIQUE KEY `sf_guard_user_username_unique` (`username`), + INDEX `sf_guard_user_FI_1` (`residence_id`), + CONSTRAINT `sf_guard_user_FK_1` + FOREIGN KEY (`residence_id`) + REFERENCES `residence` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- sf_guard_user_permission +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_guard_user_permission`; + + +CREATE TABLE `sf_guard_user_permission` +( + `user_id` INTEGER NOT NULL, + `permission_id` INTEGER NOT NULL, + `exclude` INTEGER default 0, + PRIMARY KEY (`user_id`,`permission_id`), + CONSTRAINT `sf_guard_user_permission_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`) + ON DELETE CASCADE, + INDEX `sf_guard_user_permission_FI_2` (`permission_id`), + CONSTRAINT `sf_guard_user_permission_FK_2` + FOREIGN KEY (`permission_id`) + REFERENCES `sf_guard_permission` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- sf_guard_user_group +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_guard_user_group`; + + +CREATE TABLE `sf_guard_user_group` +( + `user_id` INTEGER NOT NULL, + `group_id` INTEGER NOT NULL, + PRIMARY KEY (`user_id`,`group_id`), + CONSTRAINT `sf_guard_user_group_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`) + ON DELETE CASCADE, + INDEX `sf_guard_user_group_FI_2` (`group_id`), + CONSTRAINT `sf_guard_user_group_FK_2` + FOREIGN KEY (`group_id`) + REFERENCES `sf_guard_group` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- sf_guard_remember_key +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_guard_remember_key`; + + +CREATE TABLE `sf_guard_remember_key` +( + `user_id` INTEGER NOT NULL, + `remember_key` VARCHAR(32), + `ip_address` VARCHAR(15) NOT NULL, + `created_at` DATETIME, + PRIMARY KEY (`user_id`,`ip_address`), + CONSTRAINT `sf_guard_remember_key_FK_1` + FOREIGN KEY (`user_id`) + REFERENCES `sf_guard_user` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- sf_guard_permission_i18n +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_guard_permission_i18n`; + + +CREATE TABLE `sf_guard_permission_i18n` +( + `description` TEXT NOT NULL, + `id` INTEGER NOT NULL, + `culture` VARCHAR(7) NOT NULL, + PRIMARY KEY (`id`,`culture`), + CONSTRAINT `sf_guard_permission_i18n_FK_1` + FOREIGN KEY (`id`) + REFERENCES `sf_guard_permission` (`id`) + ON DELETE CASCADE +)Type=MyISAM; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/data/sql/plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model.schema.sql b/data/sql/plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model.schema.sql new file mode 100644 index 0000000..3076447 --- /dev/null +++ b/data/sql/plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model.schema.sql @@ -0,0 +1,38 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +#----------------------------------------------------------------------------- +#-- sf_comment +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_comment`; + + +CREATE TABLE `sf_comment` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `parent_id` INTEGER, + `commentable_model` VARCHAR(30), + `commentable_id` INTEGER, + `namespace` VARCHAR(50), + `title` TEXT, + `text` TEXT, + `author_id` INTEGER NOT NULL, + `author_name` VARCHAR(50), + `author_email` VARCHAR(100), + `created_at` DATETIME, + `unsuitable` INTEGER default 0 NOT NULL, + `email_notify` INTEGER default 0 NOT NULL, + PRIMARY KEY (`id`), + KEY `comments_index`(`namespace`, `commentable_model`, `commentable_id`), + KEY `object_index`(`commentable_model`, `commentable_id`), + KEY `author_index`(`author_id`), + CONSTRAINT `sf_comment_FK_1` + FOREIGN KEY (`author_id`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/data/sql/plugins.sfPropelActAsRatableBehaviorPlugin.lib.model.schema.sql b/data/sql/plugins.sfPropelActAsRatableBehaviorPlugin.lib.model.schema.sql new file mode 100644 index 0000000..3fd4f40 --- /dev/null +++ b/data/sql/plugins.sfPropelActAsRatableBehaviorPlugin.lib.model.schema.sql @@ -0,0 +1,26 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +#----------------------------------------------------------------------------- +#-- sf_ratings +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `sf_ratings`; + + +CREATE TABLE `sf_ratings` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `ratable_model` VARCHAR(50) NOT NULL, + `ratable_id` INTEGER NOT NULL, + `user_id` INTEGER, + `rating` INTEGER default 1 NOT NULL, + `rated_at` DATETIME NOT NULL, + PRIMARY KEY (`id`), + KEY `ratable_index`(`ratable_model`, `ratable_id`, `user_id`) +)Type=MyISAM; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/data/sql/plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model.schema.sql b/data/sql/plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model.schema.sql new file mode 100644 index 0000000..6fe69d1 --- /dev/null +++ b/data/sql/plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model.schema.sql @@ -0,0 +1,57 @@ + +# This is a fix for InnoDB in MySQL >= 4.1.x +# It "suspends judgement" for fkey relationships until are tables are set. +SET FOREIGN_KEY_CHECKS = 0; + +#----------------------------------------------------------------------------- +#-- tag +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `tag`; + + +CREATE TABLE `tag` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `name` VARCHAR(100), + `approved` TINYINT default 0 NOT NULL, + `approved_by` INTEGER, + `approved_at` DATETIME, + `width` INTEGER, + PRIMARY KEY (`id`), + KEY `name`(`name`), + INDEX `tag_FI_1` (`approved_by`), + CONSTRAINT `tag_FK_1` + FOREIGN KEY (`approved_by`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +#----------------------------------------------------------------------------- +#-- tagging +#----------------------------------------------------------------------------- + +DROP TABLE IF EXISTS `tagging`; + + +CREATE TABLE `tagging` +( + `id` INTEGER NOT NULL AUTO_INCREMENT, + `tag_id` INTEGER NOT NULL, + `taggable_model` VARCHAR(30), + `taggable_id` INTEGER, + `parent_approved` TINYINT default 0 NOT NULL, + `parent_user_id` INTEGER NOT NULL, + PRIMARY KEY (`id`), + KEY `tag`(`tag_id`), + KEY `taggable`(`taggable_model`, `taggable_id`), + CONSTRAINT `tagging_FK_1` + FOREIGN KEY (`tag_id`) + REFERENCES `tag` (`id`), + INDEX `tagging_FI_2` (`parent_user_id`), + CONSTRAINT `tagging_FK_2` + FOREIGN KEY (`parent_user_id`) + REFERENCES `sf_guard_user` (`id`) +)Type=MyISAM; + +# This restores the fkey checks, after having unset them earlier +SET FOREIGN_KEY_CHECKS = 1; diff --git a/data/sql/sqldb.map b/data/sql/sqldb.map new file mode 100644 index 0000000..748b498 --- /dev/null +++ b/data/sql/sqldb.map @@ -0,0 +1,6 @@ +# Sqlfile -> Database map +lib.model.schema.sql=propel +plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model.schema.sql=propel +plugins.sfPropelActAsRatableBehaviorPlugin.lib.model.schema.sql=propel +plugins.sfGuardPlugin.lib.model.schema.sql=propel +plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model.schema.sql=propel diff --git a/doc/DatabaseDocumentation.odt b/doc/DatabaseDocumentation.odt new file mode 100644 index 0000000..7527305 Binary files /dev/null and b/doc/DatabaseDocumentation.odt differ diff --git a/doc/Dokumentasjon av brukersystemet.odt b/doc/Dokumentasjon av brukersystemet.odt new file mode 100644 index 0000000..202bd51 Binary files /dev/null and b/doc/Dokumentasjon av brukersystemet.odt differ diff --git a/doc/SystemDocumentation.odt b/doc/SystemDocumentation.odt new file mode 100644 index 0000000..598e9e0 Binary files /dev/null and b/doc/SystemDocumentation.odt differ diff --git a/doc/Technical_installdoc.odt b/doc/Technical_installdoc.odt new file mode 100644 index 0000000..85ada4c Binary files /dev/null and b/doc/Technical_installdoc.odt differ diff --git a/doc/TemplateDocumentation.odt b/doc/TemplateDocumentation.odt new file mode 100644 index 0000000..f643402 Binary files /dev/null and b/doc/TemplateDocumentation.odt differ diff --git a/doc/components.html b/doc/components.html new file mode 100644 index 0000000..6edf537 --- /dev/null +++ b/doc/components.html @@ -0,0 +1,3 @@ +

    Components

    sfComment: _commentForm.php:


    To be able to comment on each artwork, a user needs to enter the title, and the comment in a form.
    This template provides that form. To use it, you must at least send the object and the namespace. See an example below.
    get_component('sfComment', 'commentForm', array('object' => $object, 'namespace' => $namespace, 'parentId' => $comment['Id']))
    - $object The article object the comment should be added to
    - $namespace This is either 'frontend' or 'admin', comments can be added by users, but an artwork can also be discussed by admin users.
    - $parentId The comments can be nested, in a list, if replying to a thread, the parent Id is needed
    The controller has the possibility to pass the following information:
    The following are configuration data from REAKTOR_ROOT/apps/reaktor/config/app.yml (which fields are required, how to get userinfo etc)
    - $config_user
    - $config_anonymous
    Depending on whether the user is logged in or not these are either user or anonymous
    - $config_used: set to either $config_used or $config_anonymous
    - $action: which action to run when submitting form (authenticatedComment or anonymousComment)

    sfComment: _commentList.php:


    In Reaktor some objects like f.ex artwork can be commented/discussed. This template lists either all comments
    within a namespace for an objecttype, or it displays the comments within a namespace for a particular object.
    To use it:
    include_component('sfComment', 'commentList', array('object' => $object, 'namespace' => $namespace)
    The following parameters can be passed when using the component:
    $object - Usually artwork or file
    $namespace - In Reaktor the two namespaces used are 'frontend' for user comments and 'administration' for discussion
    $limit - How many comments should be displayed in the list
    $order - Order comments by date (desc/asc)
    $unsuitable - Include only comments with the unsuitable flag set to this
    $adminlist - Is this an adminlist or not
    $comment_pager - Which page, if using a pager
    $overview - Boolean, if list is an overview, and not possible to add comments to
    This template can be used in an administration list as a partial:
    include_partial('sfComment/commentList', array(
    'comments' => $comments,
    'adminlist' => true,
    'unsuitable' => 2,
    "comment_pager" => $comment_pager))
    The $comment_pager helps make the the list paginated.
    The controller passes the following information:
    $comments - An array of sfComment objects

    sfComment: _commentTitleList.php:


    Component to display latest comments a user has written.

    messaging: _sendMessageForm.php:


    Send message form

    messaging: _messagesSummary.php:


    template for messages

    artwork: _lastArtworks.php:


    One of the important ways of achieving a dynamic site, includes having lists like these
    which are continously updated. This component template lists a reaktors latest
    approved artworks. To include this
    component, see the example below:
    include_component('artwork','lastArtworks', array(
    'image' => 'mini',
    'limit' => 6,
    'subreaktor' => $subreaktor,
    'lokalreaktor' => $lokalreaktor,
    'random' => true,
    'exclude_first' => 1))
    None of these parameters are required. The default limit is retrieved from configuration,
    exclude_first will exclude the n latest artworks from the list (say you've displayed the
    latest artwork as a thumbnail on top of the page, and you want a list of smaller thumbnails
    on a different part of the page, you don't want the latest artwork to be displayed again, so
    exclude_first = 1). If $image (thumb|subreaktorthumb|mini) isn't passed then text is
    used. $subreaktor and $lokalreaktor are only needed if they should display something
    from a different reaktor than the site belongs to. For instance, on the frontpage of
    groruddalenreaktor, you might want to show a list of the most popular reaktors in foto:
    include_component('artwork', 'lastArtworks', array('subreaktor' => 'foto')
    The information passed from the controller are the following:
    - $last : If not passed from a lokalreaktor: An array of artwork objects
    - $last : If passed from a lokalreaktor: An array with:
    'last' => an array of artworks,
    'subreaktor' = the subreaktor object for the subreaktor it was passed from
    The image type "subreaktorthumb" and "subreaktorlist" can only be called from a lokalreaktor
    frontpage. This is used when this list is called more than once on the same page, to make sure
    the same image doesn't appear more than once.

    artwork: _listPresentation.php:


    One of the important ways of achieving a dynamic site, includes having lists like these
    which are continously updated. This component template lists a reaktors latest
    approved artworks. To include this
    component, see the example below:
    include_component('artwork','lastArtworks', array(
    'image' => 'mini',
    'limit' => 6,
    'subreaktor' => $subreaktor,
    'lokalreaktor' => $lokalreaktor,
    'random' => true,
    'exclude_first' => 1))
    None of these parameters are required. The default limit is retrieved from configuration,
    exclude_first will exclude the n latest artworks from the list (say you've displayed the
    latest artwork as a thumbnail on top of the page, and you want a list of smaller thumbnails
    on a different part of the page, you don't want the latest artwork to be displayed again, so
    exclude_first = 1). If $image (thumb|subreaktorthumb|mini) isn't passed then text is
    used(??). $subreaktor and $lokalreaktor are only needed if they should display something
    from a different reaktor than the site belongs to. For instance, on the frontpage of
    groruddalenreaktor, you might want to show a list of the most popular reaktors in foto:
    include_component('artwork', 'lastArtworks', array('subreaktor' => 'foto')
    The information passed from the controller are the following:
    - $artworks : If not passed from a lokalreaktor: An array of artwork objects
    - $artworks : If passed from a lokalreaktor: An array with:
    'last' => an array of artworks,
    'subreaktor' = the subreaktor object for the subreaktor it was passed from
    The image type "subreaktorthumb" and "subreaktorlist" can only be called from a lokalreaktor
    frontpage. This is used when this list is called more than once on the same page, to make sure
    the same image doesn't appear more than once.

    artwork: _latestCommented.php:


    In order for any user of the Reaktor site to be able to easily browse interesting artworks, preferrably with active content,
    dynamic lists are provided. This template displays a list of links to artworks which last received comments. It's actually
    a container, it calles another template with the correct paramters to print the list. To use this template:
    include_component("artwork","latestCommented");
    It isn't mandatory, but the following parameters can be passed when including the component:
    $lokalreaktor: Limit the list to only use comments given to articles in this lokalreaktor
    $subreaktor : Limit the list to only use comments given to articles in this subreaktor
    The controller passes the following information:
    $latest_commented : An array of comments

    artwork: _lastArtworksFromUser.php:


    Component template to print image links of a users latest approved artworks. Used in portfolio and mypage.
    Example of use:
    include_component('artwork','lastArtworksFromUser',array(
    'id' => $userid,
    'portfolio' => true,
    'user' => $user,
    'orderBy' => $orderBy,
    ))
    Component can pass:
    $id : The id of the user who owns the portfolio page
    $user : sfGuardUser object, (used to set title of page)
    $portfolio : If set then this template is used in portfolio
    $mypage : If set then this template is used in mypage
    $orderby : What to order/filter by (title, date, rating or format)

    artwork: _listUsersPopularArtworks.php:


    Component template to print a users most popular (approved) artworks

    artwork: _listReaktorsLatestArtworks.php:


    Component template to print a reaktors most popular (approved) artworks

    artwork: _listReaktorsPopularArtworks.php:


    One of the important ways of achieving a dynamic site, includes having lists like these
    which are continously updated. This component template list a reaktors most popular
    approved artworks. They can be displayed both in text and image format. To include this
    component, see the example below:
    include_component('artwork','listReaktorsPopularArtworks', array(
    'image' => 'thumb',
    'limit' => 1,
    'subreaktor' => $subreaktor,
    'lokalreaktor' => $lokalreaktor))
    None of these parameters are needed. The default limit is retrived from configuration,
    if $image isn't passed then text is used. $subreaktor and lokal reaktor are only needed if they should display something
    from a different reaktor than the site belongs to. For instance, on the frontpage of groruddalenreaktor, you might want to show
    a list of the most popular reaktors in foto:
    include_component('artwork', 'listReaktorsPopularArtworks', array('subreaktor' => 'foto')
    The information passed from the controller are the following:
    - $artworks : An array of artwork objects

    artwork: _seeAlso.php:


    The related artwork list to be displayed on the show artwork page
    Also known as "see also". Example of use:
    include_component('artwork', 'seeAlso', array(
    'artwork' => $artwork,
    'update' => 'relate_artwork_tag',
    'editmode' => $editmode,
    'usercanedit' => $usercanedit));
    $artwork: genericArtwork object, the artwork currently viewed
    $update: the div that should be updated
    $editmode: the artwork view mode (show|edit)
    $usercanedit: the user has proper credentials? (true|false)
    The controller passes the following information:
    $relatedArtworks: array of genericArtwork objects
    $otherpeoplelike: array of genericArtwork objects
    otherArtworks: array of genericArtwork objects

    artwork: _linkRelated.php:


    Partial for linking related artwork

    artwork: _recommended.php:


    The staff of Reaktor can recommend an artwork in a Subreaktor, or in a Subreaktor within a Lokalreaktor.
    This template displays the current recommended artwork depending on the template where this component is
    used, typically the homepage, or a subreaktor frontpage. To include it in a template:
    include_component("artwork","recommended");
    This component is 'smart', when it is included in the filmreaktor template (filmReaktorSuccess.php) it will
    display the latest recommended film artwork. This default behavior is possible to override by passing an instance
    of a suberaktor, or an ignore as the subreaktor and/or lokalreaktor parameter. The following example will always
    display the latest recommended photo artwork in the entire reaktor, regardless of the template it's included in:
    include_component("artwork", "recommended", array('lokalreaktor' => 'ignore', 'subreaktor' => Subreaktor::getByReference('foto'));
    To display only the latest recommended photo artwork in groruddalen, use the above code, but leave out the lokalreaktor parameter.
    To get an instance of a reaktor you use the following piece of code: Subreaktor::getByReference('foto'), where foto is the name
    of the subreaktor. Other alteratives to foto are: tegning, film, lyd, tegneserier and tekst. To get an instance
    of a lokalreaktor the same piece of code is used, but the name of the lokalreaktor is used instead (groruddalen etc.).
    The component's controller passes the following information:
    $artwork - An artwork object

    artwork: _categorySelect.php:


    Component for "main" category selection, as well as Subreaktor selection.
    This component is used on the artwork edit page, displays a list of Subreaktors, and
    allows you to check/uncheck which subreaktor you want your artwork to be in. It also
    includes the categoryList component, which lets you select categories for the artwork.
    This component can be called with
    include_component("artwork", "categorySelect", array(
    "artwork" => $artwork));
    Where $artwork is the artwork you want to edit.

    artwork: _categoryList.php:


    Component for "main" category selection
    This component is used on the artwork edit page, and shows you a list of available categories,
    which you can click to select. Selected categories are marked with green, bold text.
    If you are not allowed to edit the information, the artworks categories are just listed.
    Include the component like this:
    include_component("artwork", "categoryList", array(
    "artwork" => $artwork));
    Takes an $artwork as a parameter, and that's all it needs.

    artwork: _recommendArtwork.php:


    The staff of Reaktor can recommend an artwork in a Subreaktor, or in a Subreaktor within a Lokalreaktor. This
    template displays which Subreaktors the artwork can be recommended in, and which Subreaktors it's the latest
    recommended in. To use it:
    include_component('artwork', 'recommendArtwork' , array('artwork' => $artwork))
    Parameters passed:
    $artwork - Object of an artwork
    From the controller the following information is passed:
    $recommendations - Array of recommendation objects
    $subreaktor_array - An array of the subreaktors the artwork can be recommended in

    artwork: _embedLink.php:


    embed link for artwork page

    artwork: _userArtworkListElement.php:


    Display a wide format single artwork row, for use in generic lists or info areas where artwork summary is required
    This view is useful for normal users - admin users should use displayArtworkInList.php as this contains information
    more suited to administration purposes.
    Variables this partial requires:
    - $artwork : The artwork object to show
    - $thisUser : The current user object (if we are here as an admin user)

    admin: _adminArtworkList.php:


    Artworks and files are on Reaktor sometimes presented in lists. The reaktor backend has most of these lists:
    rejected, approved, unapproved, under discussion etc. To keep a more or less similar look on all
    lists, a single template is used, this one.
    Ex.: include_partial('admin/adminArtworkList', array('files' => $files))
    Ex.: include_component('admin', 'adminArtworkList', array('artworks' => $artworks, 'show_recommended' => true))
    This template gets all of its information from the parameters passed
    - $files : An array of files
    - $artworks : Array of artworks
    - $show_recommended : If this is passed, the subreaktors this file is recommended are displayed

    admin: _adminSummary.php:


    This component displays summary information for logged in admin users, it is currently displayed in
    the sidebar when an admin user is logged in.
    Variables passed from the component action
    - $editorialteams : An array of editorial teams (as objects) that this user belongs to

    reports: _resultGraph.php:


    Graphs for reports
    Requires parameters: $graphData, $dateData

    reports: _savedReportsFloatBox.php:


    Used on report pages - shows a list of popular saved/bookmarked reports
    Required parameter - report type ($type = 'artwork' or 'user') which corresponds to the type of report
    as stored when saving a report bookmark.
    The reports displayed by this partial have two links - one will show the report as a count, the other as a list
    The component class will send back an array of bookmark objects which can be iterated below
    The variable $savedReport will be false if the current report is unsaved, or will contain the report object

    subreaktors: _categoriesList.php:


    A template to display a list of categories that are connected to a given subReaktor. Example of use:
    get_component('subreaktors', 'categoriesList', array('subreaktor' => $this->subreaktor))
    The controller does not pass any information.

    subreaktors: _listSubcategories.php:


    List subreaktor categories and number of artworks in each

    subreaktors: _listLokalReaktorSubcategories.php:


    List subreaktor categories and number of artworks in each

    subreaktors: _newCategoryField.php:


    When new Reaktors are created, subReaktors in particular, they should have a set of categories
    connected to them. This template provides a category dropdown, it should show currently unnasigned
    categories, but also a link for adding new categories. Example of use:
    include_component("subreaktors", "newCategoryField")
    The controller passes the following information:
    $categories

    profile: _lastUsers.php:


    Component template that prints the 5 last registered users
    Query is created and executed from profileComponents class,
    function executeLastUsers()

    profile: _resources.php:


    A user can add and remove resources - links to other web sites they think are useful. This
    template consist of a list of resources, a form to add it, and links to remove as well.
    Example of usage:
    include_component('profile','resources' ,array('user' => $user->getId()))
    The paramters needed:
    $user - the id of the user
    The controller passes the following information:
    $resources - The already added resources belonging to this user

    profile: _matchingInterests.php:


    User's can browse other user's content by viewing user's with the same interests on themselves.
    This component template prints the 5 last registered users with the same interests as a given user.
    Example of use:
    include_component('profile', 'matchingInterests', array(
    'user_id' => $user->getId(),
    'username' => $user->getUsername(),
    'all' => false,
    ))
    $user_id : Integer Match interest with this user
    $username: String Name of the same user
    $all : Boolean If false use config to decide length of list
    The controller passes the following information:
    $users - array of sfGuardUser objects

    profile: _portfolioUserinfo.php:


    Display user information in sidebar on portfoliopage

    sidebar: _sidebar.php:


    The layout of the reaktor page includes a footer, a header, the main content and a sidebar. The sidebar
    is the right hand bar on every page which has login and user information, links, the messages box etc.
    This is the template for the sidebar, and its component is called only once, and that's from layout.php:
    include_component('sidebar', 'sidebar')
    Since its included in the layout, it is displayed on every single reaktor page, and the content of it will
    change according to which page is loaded, if the user is logged in, and if he/she has administration
    credentials.
    The caller of the sidebar component do not have to pass any parameters.
    The controller passes the following information:
    - $artwork_count : The number of approved artworks on the reaktor site
    - $articles : The articles that should be listed in the sidebar, this is changes according to the page

    sidebar: _sidebarArticles.php:


    Sidebar articles are displayed using component slots. Unless a module has set the sidebararticles slot in its config/view.yml
    file to point to a component it will display this template.

    favourite: _listFavourites.php:


    template for listing favourites

    favourite: _favouriteActions.php:


    favourite action links

    favourite: _artworkListFavourites.php:


    template for listing favourites

    sfTransUnit: _langLinks.php:


    Language links for top right of header

    sfTransUnit: _newTranslationForm.php:


    Form for adding a new database item to translate, based on passed object name
    See admin/newCategorySuccess for example useage
    Must pass translateObject and translateField
    Preferable to pass redirect value also to send user somewhere sensible after success

    articles: _articleRelations.php:


    The reaktor site's main functionality is uploading artworks, but also providing useful articles for
    the regular users and staff. These articles can sometimes cover the same topic, and this template
    provide a way of relating articles to each other and displays a list of articles that have been
    related to each other
    To use the component:
    include_component('articles', 'articleRelations', array('article' => $article));
    The component needs to pass the following:
    $article- An article object
    The controller passes the following
    $related_articles - an array of article objects

    articles: _expirationDate.php:


    Expiry date partial. Included in article edit page to show and edit theme article expiry date

    articles: _articleCalendar.php:


    Article calendar left-hand sidebar
    Included in article edit page and on article list page

    articles: _listCreators.php:


    Component for dispaying the creator and last modifier of an article
    Expects:
    - $article : The article object
    Available to the template:
    - $created_by : The username of the creator
    - $created_at : The time of the last update (mysql datetime)
    - $updated_by : The username of the user who last modified the article
    - $updated_at : The time of the last update (mysql datetime)

    articles: _myPageArticles.php:


    Shows the my page articles

    articles: _frontPageArticles.php:


    Front page article partial. Can be included on any frontpage, and will show general articles
    not restricted to a subreaktor, and articles that are available only in the subreaktor you're
    watching.
    Does not take any parameters.

    +Warning: fopen(/opt/reaktor/apps/reaktor/modules/articles/templates/_articleBanner.php): failed to open stream: No such file or directory in /opt/reaktor/doc/scripts/components_and_partials.php on line 34 +

    adminmessage: _nextMessageDueToExpire.php:


    Component to display the next system admin message to expire.
    Should be used for delivering important messages for the user,
    i.e when the system is about to be taken down.

    tags: _tagEditList.php:


    Tag edit list component, used to display a list of tags with editing features appropriate to user priveledges.
    It is used when adding/removing tags from objects (files, artworks etc) but also when editing tags in general
    (for example as an administrator approving tags). For this reason there are a few combinations of parameters which can be sent
    to this component, with differing results.
    - $tagObject : The object that has been tagged - actions carried out on this page will reflect on this object (artwork/article etc)
    - $tags : The tag objects that we are listing - they could have come from the object (above) or from a generic list
    - $unapproved : Used by the component. Set true to return only unapproved tags in the response.
    - $taglength_error: Returned by the ajax action - set if we need to display a message to the user.
    - $page : Returned by the ajax action - the current page we are viewing (possibly redundant now)
    - $options : An array of options to send to the component, the following are available:
    - $noicons : Whether to show icons next to tags (effectively turns the list into a red/green list)
    - rowLimit : If set will insert a
    tag every time this limit is reached when listing tags
    - artworkList : Tells the component that this is an artwork list, overrides the use of extra file id
    - nomargin : If set removes the left margin from the ul element
    - extraId : File id or artwork id that will be appended
    - tageditor : True or false, includes a tag editor partial to handle normalisation - should only be used on vertical lists
    - completeFuncs : Javascript functions to be called when ajax requests have completed, seperate with semi-colon.
    - commas : Show commas next to tags in list view
    This template may be rendered by a calling (parent) template or an ajax call.

    tags: _tagSearchBox.php:


    This partial contains the search box which can be found in the sidebar, also covering user searches
    No parameters are required, simply include this partial and you will have a working search box

    tags: _showintellitags.php:


    Component for showing intelligent tags that are related in some way to a tagged object
    - $tags : The tags with which to base the relations (for example a set of tags from an artwork)
    The above variable is used by the component action to generate related tags and display a tag cloud.

    tags: _viewTagsWithStatus.php:


    Print a comma seperated list of tags with colouring to show status
    Required parameters are detailed below:
    - $artwork : The artwork object that we need to list the tags for
    Variables passed back from the component
    - $tagStatusArray : The array of tags with inside status arrays (1 is approved, 0 is not)

    upload: _tinymce.php:


    TinyMCE plugin for creating a text artwork online
    This template is included on the upload/edit page when creating or editing a text artwork - all TinyMCE options
    for this process are configured here in the javascript block below.
    - $mce_data : The contents of the text field, if set it will be prefilled - if not an empty textarea will be loaded

    feed: _foreignReader.php:


    Component to parse and display a feed from a foreign website (could of course also parse reaktor
    feeds ;) ) Displays header + short section of the ingress + "read more".
    Needs the following parameters:
    'feedurl' - The url of the foreign feed. Must be a valid Atom/RSS feed
    Optional parameters:
    'title' - If you want to display a title above the items
    'items' - If you want to display more than/fewer than 5 news items
    'ingresslength' - If you want to display a longer/shorter ingress
    'showreadmore' - If you don't want to display the 'Read more'-link, set this to false
    'headerlink' - If you want to make the item headers into links, set this to true

    userContent: _artworkCompositeSelect.php:


    Select dropdown for picking a composite artwork to add this file to
    Will show a list of artworks of the same type
    - $artworks : The eligible artworks for this addition
    - $thisUser : The user object that we are working with

    userContent: _contentManagerSidebarAjaxblock.php:


    This needs to be outside the containing
    so it can be updated via an ajax call

    \ No newline at end of file diff --git a/doc/editorial_team_assignment.dia b/doc/editorial_team_assignment.dia new file mode 100644 index 0000000..6a05504 Binary files /dev/null and b/doc/editorial_team_assignment.dia differ diff --git a/doc/editorial_team_assignment.jpeg b/doc/editorial_team_assignment.jpeg new file mode 100644 index 0000000..aca86ae Binary files /dev/null and b/doc/editorial_team_assignment.jpeg differ diff --git a/doc/layouttemplates.html b/doc/layouttemplates.html new file mode 100644 index 0000000..1c01a4e --- /dev/null +++ b/doc/layouttemplates.html @@ -0,0 +1 @@ +

    Layout Templates

    Layout template: adminmenubar:

    Admin menu bar partial
    This partial is included in the main page header and shows the admin menu options instead of the usual site menu
    The decision whether this menu is displayed is taken elsewhere (in the including template) however, each of the
    individual admin menu items will only be shown to users with appropriate credentials

    Layout template: bottom_menu:

    Bottom menu partial included in home/index
    This partial includes links to the articles that are marked as type "footer article", or traditionally "about reaktor"
    for example: about, help, privacy, contact, etc. The links to RSS feeds are also shown on the right side.

    Layout template: footer:

    Footer template just to keep the main layout template a bit cleaner
    This file should include anything that will appear on the bottom of
    each page, such as copyright notices and links to privacy policy, faq

    Layout template: header:

    Main page header partial
    This template is the first to be rendered, so it's output always appear at the very beginning of the generated
    html file. The first line after the closing php tag ( ?> ) should be the doctype declaration. Technically layout.php
    is rendered before this one, but this file should be the first one that layout.php includes.
    Header file mainly contains the content of the head tags and any opening
    Tags such as body, html and the wrapper div which are all closed in _footer.php
    Also in the header template is anything that should appear at the top of every page, such as the font resizer
    and language links.

    Layout template: logo:

    The page logos and image maps which appear on top left of every page in the page header
    Admin mode and the admin logo are set in the admin filter which is run on every page load, so the configuration
    option "app_admin_logo" is dynamic (currently it will be set to administrator or redaksjon)

    Layout template: menubar:

    Menu bar partial containing all the main site links that the users will use to navigate the site from a top level
    Subreaktors are automatically iterated here across the menu bar, and lokalreaktors are automatically appended
    to the lokalreaktor list.
    Currently selected menu items will be designated the class "selected" which can be modified in the main css file,
    Add more menu items by using the subreaktor administartion section

    \ No newline at end of file diff --git a/doc/manuals/reaktor_brukere_tilganger.odt b/doc/manuals/reaktor_brukere_tilganger.odt new file mode 100644 index 0000000..8d9c8a8 Binary files /dev/null and b/doc/manuals/reaktor_brukere_tilganger.odt differ diff --git a/doc/manuals/reaktor_install_and_maintenance.odt b/doc/manuals/reaktor_install_and_maintenance.odt new file mode 100644 index 0000000..f1a4791 Binary files /dev/null and b/doc/manuals/reaktor_install_and_maintenance.odt differ diff --git a/doc/manuals/reaktor_system_documentation.odt b/doc/manuals/reaktor_system_documentation.odt new file mode 100644 index 0000000..127100e Binary files /dev/null and b/doc/manuals/reaktor_system_documentation.odt differ diff --git a/doc/partials.html b/doc/partials.html new file mode 100644 index 0000000..90fab91 --- /dev/null +++ b/doc/partials.html @@ -0,0 +1,3 @@ + +Warning: fopen(/opt/reaktor/apps/reaktor/modules/articles/templates/_articleBanner.php): failed to open stream: No such file or directory in /opt/reaktor/doc/scripts/components_and_partials.php on line 34 +find /opt/reaktor/apps/reaktor/modules -name _*|grep -v svn

    Partials

    sfComment: _commentView.php:

    $class = $user_config['class'];
    $toString = $user_config['toString'];
    $peer = sprintf('%sPeer', $class);
    $author = call_user_func(array($peer, 'retrieveByPk'), $comment['AuthorId']);

    sfComment: _adminButtons.php:

    Admin buttons for comment administration

    messaging: _messageContent.php:

    message content helper

    messaging: _messagesWrapper.php:

    template for messages

    artwork: _displayComments.php:

    In Reaktor some objects like f.ex artwork can be commented/discussed. This template provides a list, and a
    possibility to add comments to that list.
    Example of usage:
    include_partial('artwork/displayComments', array('object' => $artwork->getBaseObject(), 'namespace' => 'frontend')
    Parameters passed:
    $object - The object to attach comments to
    $namespace - Which namespace the comments belong to (administrator|frontend)

    artwork: _statusButtons.php:

    Status buttons for artwork
    These buttons provide the ability to switch hidden status and remove an artwork completely
    Variable required:
    - $artwork : The artwork object

    artwork: _metadataList.php:

    Show a nice metadata box for use on the artwork show page
    Add elements by listing them below in the arrays, following the examples given.
    This method of listing is used to aid with translation of the element titles.
    Refer to metaMap.yml for the list of available metadata elements
    - $artwork: The artwork object (just in case we want to show some artwork values too
    - $file: The file object that contains the metadata

    artwork: _adminButtons.php:

    In most the artwork administration lists you can perform actions on each of the
    artworks. This admin buttons are not always the same, for instance you do not need to reject artworks
    that are already rejected. This template prints out the respective buttons for one artwork.
    Ex.:include_partial("artwork/adminButtons", array('artwork' => $artwork))
    The parameters passed are:
    $artwork - A reaktorArtwork object

    artwork: _displayArtworkInList.php:

    Many of the administration tasks have a list as a starting point, some of them look quite similar with only
    the buttons differing from list to list.
    This is a partial to display an artwork in an admin list, which buttons to display is passed as a parameter.
    Example on how to use it:
    include_partial('artwork','displayArtworkInList', array(
    'artwork' => $artwork,
    'buttonPartial' => 'admin/discussButtons'))
    The possible buttonPartials are
    - admin/discussButtons
    - artwork/adminButtons

    artwork: _editmetadata.php:

    Partial to edit metadata

    artwork: _slideshow.php:

    Slideshow helper

    artwork: _displayFileInList.php:

    Many of the administration tasks have a list of files as a starting point, some of them look quite similar with only
    the buttons differing from list to list.
    This is a partial to display a file in an admin list, which buttons to display is passed as a parameter.
    Example on how to use it:
    include_partial('artwork','displayArtworkInList', array(
    'file' => $file,
    'buttonPartial' => 'admin/discussButtons'))
    The possible buttonPartials are
    - admin/discussButtons

    artwork: _draganddropartworklist.php:

    List artwork as a draggable list so the user can prioritise them
    Includes a generic artwork list view partial which can be reused when not using draggable lists
    Variables this partial requires:
    - $artworks : The array of artwork objects to list
    - $thisUser : The user object we are working with

    artwork: _draganddroplist.php:

    AJAX drag and drop list to use with an artwork

    artwork: _displayPlayer.php:

    Partial for displaying flash media players

    artwork: _socialBookmarks.php:

    Links to Facebook, digg etc

    artwork: _moderatorlinks.php:

    Partial displaying a list of a user's moderator links

    artwork: _artworkDisplay.php:

    displays the artwork / file

    artwork: _artworkRating.php:

    Rating partial
    Do not add html newlines (echo everything) as this breaks the tooltip when used in mouseover
    This partial takes the following arguments:
    - $artwork *required* - The artwork to retrieve rating info about
    - $login [optional] - Print the login note, if user is not logged in
    - $noedit [optional] - Do not make it rateable
    $sf_user is automatically populated by Symfony

    artwork: _artworkNavLinks.php:

    Navigation links for artworks, for navigation to next, previous, first and last files
    Will display active links or greyed out links as necessary
    - $artwork: The artwork object that we need links for
    - $thefile: The file object of the current file
    - $class: The optional class of the container div (default "artwork_nav_links")

    artwork: _transcoderOptions.php:

    Partial to show transcoder options on the artwork page for admin users to be able to re-trigger the process
    This will display when the file has not finished transcoding, or when the file does not exist at all
    Expects:
    - $file : The file object that we are checking the transcoding status of

    artwork: _statusRow.php:

    Shows the artwork status in a simple row format
    - $artwork : The artwork object
    - $break : If set, breaks the status up into two lines

    artwork: _fileAdminButtons.php:

    Admin buttons for artwork administration

    artwork: _licenseinfo.php:

    When viewing an artwork it should be possible to easily find out which license it has. This template displays
    the license according to the file given as a parameter. This is included in the artwork show template. Example of use:
    include_partial("licenseinfo", array('thefile' => $thefile))
    $file : ReaktorFile object.

    artwork: _reportunsuitable.php:

    Helper to add a "report unsuitable content" link

    artwork: _removeFileButtons.php:

    The sliding div that appears when remove/unlink file is clicked

    admin: _discussButtons.php:

    Many of the administration tasks have a list as a starting point, some of them look quite similar with only
    the buttons differing from list to list. This template displays buttons related to disussing artwork and files.
    Example on usage:
    include_partial($buttonPartial, array('object' => $artwork))
    The paramenters sent are:
    - $object : a genericArtwork or a ReaktorFile
    - $type : file or artwork
    - $update_div : the div that should be updated when a button has carried out its action

    admin: _renameComponent.php:

    This partial contains a (usually hidden until toggled) div containing options for editing and normalising a category
    Variables that should be passed:
    - $category : The tag object that we want to provide editing options for

    reports: _userActivityReportsQuery.php:

    This template displays the report results for user activity queries
    Requires parameter: $res

    reports: _savedReportBlock.php:

    Partial for showing the current bookmarked report or the form for saving a new one
    In a partial so we can use it to update the ajax response
    Expected parameters: $savedReport and $type - loaded and passed from the calling template

    reports: _userReportsQuery.php:

    This template displays the report results for user queries
    Requires parameter: $resultset

    profile: _userProfile.php:

    One of the most important features of a community, is to be able to mark yourself as a member of it. After all, if you're not a member
    how will the system know it's you, so as to be able to group your artworks, send you messages, etc. To become a member, you need to
    register, this is the template displaying the form where the user enters information about him- or herself. This file is included in
    profile/registerSuccess.php and profile/editSuccess.php to avoid repeating code. The forms' start tags are in these templates.
    Example on how to use it
    include_partial('userProfile', array(
    'sf_guard_user' => $sf_guard_user,
    'profile' =>'create',
    'residence_array' => $residence_array))
    The following parameters need to be passed:
    sf_guard_user - A sf_guard_user object of the user whose profile is to be either created or edited
    profile - Not mandatory, if not set its assumed to be edit, if set set to create the mode is assumed to be create
    residence_array - An array of arrays, which city, municipal or county can the user choose between in the residence drop down.

    profile: _passRequest.php:

    Password request partial to be shown when user clicks forgotten password link

    sidebar: _login.php:

    Login partial called from sidebar
    This page appears in the sidebar when a user is not logged in

    sidebar: _user_summary.php:

    User summary block, called from sidebar when a user is logged in
    Contains simple user details and user specific links, such as link
    to edit profile.

    sidebar: _send_in.php:

    Send in-partial

    sfTransUnit: _edit_form.php:

    auto-generated by sfPropelAdmin
    date: 2008/08/18 10:00:20
    Example of use:
    include_partial('sfTransUnit/edit_form', array('trans_unit' => $trans_unit, 'labels' => $labels))
    $trans_unit - The object describing what is about to be translated
    $labels - The form labels

    sfTransUnit: _target.php:

    Each string in Reaktor can be translated. This template is used in the adminportal to display how a string
    has been translated. The string in the code is the source, usually plain english and can be used directly as
    an English version. Other times, the source is just a placeholder and must be translated to english as well.
    This template holds the target forms, all the form to translate into the languages offered by the Reaktor site.
    Example of use:
    get_partial('target', array('type' => 'edit', 'trans_unit' => $trans_unit))
    $type - This variable is not used, but it does indicate that the form is used in edit mote
    $trans_unit - The object describing what is about to be translated

    articles: _articleList.php:

    Partial that lists an array of articles. Can be included anywhere, just by passing an
    array of Article objects + list style (defaults to title+intro+read more)
    $articles: An array of articles
    $mode: Display mode - "short" for clickable title only, "full" for title+intro+link (default)
    NOTE: This partial will NOT list more articles than the max count of articles
    to be shown for the first article type

    articles: _editarticlecontents.php:

    The Reaktor site provides the readers with useful information from its editorial staff through articles.
    This template displays the form for editing such articles, it's an article content editor (title, ingress,
    content) partial. Used on the artwork edit page, can be included on custom
    article edit pages. To use:
    include_partial('editarticlecontents', array(
    'article' => $article,
    'buttons' => $show_attachments_edit));
    $article : Article Object - The article to be edited
    $buttons : boolean - If true, display the attach artwork to this article button in tinymce

    tags: _tagWarningMessage.php:

    Tag warning message for if no tags are yet supplied
    No parameters are required
    Only edit the text below if you need to significantly change the layout
    otherwise you can edit the text by modifying the translations. Editing the text below will only alter the "fallback" English text
    which is used when no translation is found.

    tags: _viewTagsWithLinks.php:

    Print a comma seperated list of tags
    Required parameters are detailed below:
    - $tags : The list of tags

    tags: _tagKey.php:

    A key to the symbols used in tag administration
    Displayed in the filter box on the tag list/administration page

    tags: _showtags.php:

    Basic tag cloud, used on home page
    No parameters required, this partial will automatically generate a list of all tags used by the site with correct
    filtering based on subreaktors.
    You can pass the option 'cloud_type' to this partial to make it display a nice tag cloud instead
    of the one with numbers in it:
    $cloud_type: 'pretty' (no counts) or 'fugly' (with counts)
    The size of the tag cloud can be controlled by altering the following values in app.yml
    ~ home / max_tag_length : This is the total number of characters that the tag cloud can consume
    ~ home / max_tags : This is the number of tags that should be shown (up to the limit set in max_tag_length)

    tags: _showMini.php:

    Show a mini thumbnail for an artwork object with or without mouseover
    Include this partial with the artwork object as a parameter and the "mini" thumb will automatically be displayed
    along with a link to the artwork and a mouseover with title, username and current rating.
    - $nomouseover : Set true to disable the mouseover effect which is on by default
    - $artwork : The artwork object - everything is automatically derived from this
    - $nolink : Set true to do not display the link, only the thumbnail

    tags: _alphaPager.php:

    Alphabetical pager for tag lists
    This partial when included in a template provides a convenient list of links based on an array of letters.
    Required parameters are detailed below:
    - $letters : The array of letters (typically A to Å for example) which should be included in the menu
    - $thisPage : The current page letter (will print directly without a link)
    The partial will check the request parameters to see if we are looking just at unapproved tags and adjust the
    links accordingly.

    tags: _sortlinks.php:

    Sort tag results
    This partial is used on the tag find (search results) page to sort the results
    - $mode : "tag" or "category" depending on the type of results we are sorting
    - $sortmode : "date", "title", "username" or "rating" - the sort option that has been clicked
    - $sortdirection : "asc" or "desc" - the sort direction that has been applied
    - $tags : The original search parameters (tags we are searching for) - only useful when $mode = "tag"
    - $categories : The original search parameters (categories we are searching for) - only useful when $mode = "category"
    - $results : The result set which we can use to inspect and decide whether to show certain links

    tags: _addTag.php:

    Provides an ajax interface to quickly add an approved tag
    Displayed in the filter box on the tag list/administration page

    tags: _newTagField.php:

    Partial for New tags text field with autocomplete
    This partial contains the text area which is used by the new tag process, it shows an autocomplete dropdown when the user
    enters a new tag, or list of tags seperated by commas.
    - $taggableModel : The taggable model which this tagging is affecting (for example reaktorFile or reaktorArtwork)
    - $id : The id of the taggable object that we are tagging

    tags: _tagWrapper.php:

    Wrapper for tag partials and components - just include this one to get the functionality from the tag list and new tag box.
    The reason for this wrapper is that some of the partials that are included here are updated via ajax calls, so they are re-parsed
    by the ajax action individually.
    - $completeFuncs : Javascript functions to run onComplete. For example update another area of the page
    - $thisObject : The taggable object that these tags relate to

    tags: _tageditor.php:

    This partial contains a (usually hidden until toggled) div containing options for editing and normalising a tag
    Variables that should be passed:
    - $tag : The tag object that we want to provide editing options for

    upload: _saveAndAttach.php:

    Div block for save and attach to previous artwork
    Created to provide flexibility with placement on page as this option is placed near the top if a user has selected
    an artowrk to link to, or at the bottom of the page if not. This partial is thus used only on the upload/edit page
    and is unlikely to be reused.
    This partial will not be displayed at all (decision made on the upload page) if there are no eligible artworks that can
    be linked to this one. ($artworkArray is empty)
    - $artworkArray : Passed from the action to the calling template and then on to this partial, this is the array of
    artworks that are eligible for linking.

    upload: _inlineUpload.php:

    Partial for handling inline uploads in an iframe
    Needs prototype (available by default) and inlineupload js (configured in view.yml)
    The image tag is passed to this partial as it is updated and rendered again by the remote script
    The partial can handle normal image uploads for files, or avatars depending on the parameters passed.
    - $imgTag : The full html image tag that will display the current and new image
    - $fileId or $avatarUserId depending on which type of object Is being updated.
    Partial must not be loaded inside
    tags as this will create a nested form
    and break the script. Must also be placed AFTER existing page forms or Symfony
    messes something up with the params.

    contentServer: _showMini.php:

    Show a mini thumbnail for an artwork object with or without mouseover
    Include this partial with the artwork object as a parameter and the "mini" thumb will automatically be displayed
    along with a link to the artwork and a mouseover with title, username and current rating.
    - $nomouseover : Set true to disable the mouseover effect which is on by default
    - $artwork : The artwork object - everything is automatically derived from this
    - $nolink : Set true to do not display the link, only the thumbnail

    feed: _rssLink.php:

    Display rss Image and correct link in any positioned element
    Default positioning is inside top right, but a custom class can be passed to this partial if desired
    This partial should always be used when adding the Orange RSS icon on the page for a specific list, as it
    automatically handles the RSS headers in the browser, and show/hide link in the footer menu.
    When mousing over a "feed block", which is the element containing this partial, the "rss_hover" class will be temporarily
    applied. By default, this gives the element (normally a list) a light yellow background to indicate which list
    the feed icon is related to.
    Arguments that can be passed to this template:
    - $class : The css class to use, if not set then "rss_link_top_tight" is used
    - $route : The route from routing.yml that will be used in the feed link, if not set "artworkfeed" is used
    - $description : Adds text to the tooltip following - "Subscribe to ". If not set, "this list" is used
    - $url : If set, is used instead of route (supply a relative url with a leading slash) for the feed url
    - $caption : If set, this text will appear before the orange RSS icon
    - $slug : The unique identifier for this feed, which relates to the action and appears in the feed url

    userContent: _userFileInList.php:

    Display a wide format single file row, for use in generic lists or info areas where file summary is required
    This view is useful for normal users - admin users should use *** as this contains information
    more suited to administration purposes.
    Variables this partial requires:
    - $file : The artwork object to show

    userContent: _sideMenu.php:

    The grey menu sidebar for the content management section

    userContent: _simpleFileListForAjax.php:

    Simple file list partial, for updating ajax responses
    - $allowOrdering : If true the top list is draggable for ordering files in the artwork
    - $linkArtwork : The artwork object
    - $thisUser : The user object we are working with

    userContent: _listArtworks.php:

    Simple list of artworks for use on file lists and ajax callbacks
    - $file : The file object that we are generating the list from

    sfGuardUser: _dob.php:

    Date of birth partial

    sfGuardUser: _alphaPager.php:

    Alphabetical pager for displaying tags

    sfGuardUser: _edit_footer.php:

    Footer for the edit view

    sfGuardUser: _sex.php:

    Sex partial

    sfGuardUser: _edit_header.php:

    The administration backend templates for users are made by a generator. These templates can however be overridden.
    This is a partial used in the template that displays the form, where users can be edited, but this template is also
    used when users are created. This template is the header for the edit view of the sfGuardUser object.

    sfGuardGroup: _edit_header.php:

    Header for the edit view

    sfGuardPermission: _edit_header.php:

    Header for the edit view

    \ No newline at end of file diff --git a/doc/patches/README b/doc/patches/README new file mode 100644 index 0000000..be3fd5b --- /dev/null +++ b/doc/patches/README @@ -0,0 +1,55 @@ +1. Generators, and filtering on many-to-many relations +Generators in Symfony 1.0X does not support filtering on many-to-many +relations. Patching the following file in the symfony core with their +respective patch files will fix this problem: + +/usr/share/php/data/symfony/generator/sfPropelAdmin/default/template/actions/actions.class.php +/usr/share/php/symfony/generator/sfAdminGenerator.class.php + +Note! The location of your core Symfony files might be in a different +location. +Note! Once you've patched the files, you have to clear the cache so the +generator can create the new correct files. + + +2. Routing problem +Patch for sfRouting which fixes several issues when retrieving the "internal +URI": + +- urlencode()s request keys and values + Protect against key/value corruption +- Loop over arrays + Otherwise we wind up with /Array/ in the paths +- Skip empty values + Protect against seemingly random bogus auto fill-ins + +The file to patch is: +/usr/share/php/symfony/controller/sfRouting.class.php + +Note! The location of your core Symfony files might be in a different +location. + + +3. Translation, and extracting text for translation from code + + +The extraction process has problems with the mysql connection. This patch +fixes this. + +The file to patch is: +/usr/share/php/symfony/i18n/sfMessageSource_MySQL.class.php + +4. utf8 encoding problem of translated text + + +Patch file: sfMessageSource_MySQL.class.php +file to patch: symfonycodebase/i18n/sfMessageSource_MySQL.class.php + +NOTE! Patch 3 and 4 are merged and are now just one patch. + +5. Google analytics patch + +Changes the google analytics code in app.yml + +file to patch: apps/reaktor/config/app-yml + \ No newline at end of file diff --git a/doc/patches/app_google_analytics.patch b/doc/patches/app_google_analytics.patch new file mode 100644 index 0000000..9f5fd73 --- /dev/null +++ b/doc/patches/app_google_analytics.patch @@ -0,0 +1,22 @@ +Index: app.yml +=================================================================== +--- app.yml (revision 2632) ++++ app.yml (working copy) +@@ -35,7 +35,7 @@ + + sf_google_analytics_plugin: + enabled: on +- profile_id: UA-4885488-1 ++ profile_id: UA-5811483-1 + tracker: google + + recaptcha: +@@ -47,7 +47,7 @@ + opt_in_email_blocks: 20 #set this to 0 to not use any blocks + pma_readonly_user: pma_user #PHPMyAdmin user + pma_password: R3ak+0rpmA +- ga_tracker_number: UA-4885488-1 #The google analytics tracker number - currently reaktor.lab.linpro.no ++ ga_tracker_number: UA-5811483-1 #The google analytics tracker number - currently reaktor.lab.linpro.no + + ### Remember if you change anything in this file you need to clear the cache! ### + diff --git a/doc/patches/apply_patches.sh b/doc/patches/apply_patches.sh new file mode 100755 index 0000000..07b5b15 --- /dev/null +++ b/doc/patches/apply_patches.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# apply the patches: +# Global patches 4 symfony + +SYMFONY_DATA_DIR="/usr/share/php/data/symfony" +SYMFONY_LIB_DIR="/usr/share/php/symfony" + +#SYMFONY_LIB_DIR="/opt/symfony-1.0/lib" +#SYMFONY_DATA_DIR="/opt/symfony-1.0/data" + +REAKTOR_DIR="/opt/reaktor" + +patch ${SYMFONY_DATA_DIR}/generator/sfPropelAdmin/default/template/actions/actions.class.php < sfPropelAdmin.patch +patch ${SYMFONY_LIB_DIR}/generator/sfAdminGenerator.class.php < sfAdminGenerator.class.php.patch +patch ${SYMFONY_LIB_DIR}/controller/sfRouting.class.php < sfRouting.patch +patch ${SYMFONY_LIB_DIR}/i18n/sfMessageSource_MySQL.class.php < sfMessageSource_MySQL.class.php.patch +patch ${SYMFONY_LIB_DIR}/i18n/sfMessageSource_MySQL.class.php < sfMessageSource_MySQL.class.php.utf8.patch + +# Local patches +patch ${REAKTOR_DIR}/apps/reaktor/config/app.yml < app_google_analytics.patch +patch ${REAKTOR_DIR}/apps/reaktor/config/app.yml < recapcha.patch \ No newline at end of file diff --git a/doc/patches/listoptinuseremails.20220.sql b/doc/patches/listoptinuseremails.20220.sql new file mode 100644 index 0000000..6b4feb1 --- /dev/null +++ b/doc/patches/listoptinuseremails.20220.sql @@ -0,0 +1,4 @@ +# Add permision listoptinuseremails - Ticket 20220 +INSERT INTO `reaktor`.`sf_guard_permission` (`id`, `name`) VALUES ('58', 'listoptinuseremails'); +insert into sf_guard_group_permission(`group_id`,`permission_id`) values('3','58'); +insert into `reaktor`.`sf_guard_permission_i18n` values('Can list opt-in user e-mails','58', 'en' ); \ No newline at end of file diff --git a/doc/patches/recapcha.patch b/doc/patches/recapcha.patch new file mode 100644 index 0000000..2af6b3b --- /dev/null +++ b/doc/patches/recapcha.patch @@ -0,0 +1,15 @@ +Index: apps/reaktor/config/app.yml +=================================================================== +--- apps/reaktor/config/app.yml (revision 1813) ++++ apps/reaktor/config/app.yml (working copy) +@@ -38,8 +38,8 @@ + tracker: google + + recaptcha: +- publickey: 6Lf7mQIAAAAAAG0NGOQMemqzYMViFHl4Egu0qHH- +- privatekey: 6Lf7mQIAAAAAAO26Xy8xoRmfqKvteF_v7oohruog ++ publickey: 6Lc8qwIAAAAAAPg7-iBn4ruTwax1LQG4v3pgWlyO ++ privatekey: 6Lc8qwIAAAAAALcqJDd2E32AjekpoZGOywwe1R1W + + admin: + commentlistmax: 10 diff --git a/doc/patches/sfAdminGenerator.class.php.patch b/doc/patches/sfAdminGenerator.class.php.patch new file mode 100644 index 0000000..7e2571c --- /dev/null +++ b/doc/patches/sfAdminGenerator.class.php.patch @@ -0,0 +1,17 @@ +--- sfAdminGenerator.class.php 2008-08-05 10:16:54.000000000 +0200 ++++ /tmp/sfAdminGenerator.class.php 2008-08-05 10:34:25.000000000 +0200 +@@ -671,6 +671,14 @@ + $params = $this->getObjectTagParams($params, array('size' => 7)); + return "input_tag($name, $default_value, $params)"; + } ++ /* Many-to-many relations, if through-class is set, use it to populate drop-down */ ++ else if ($params['through_class']) ++ { ++ $array_options = "_get_options_from_objects(sfPropelManyToMany::getAllObjects(new " .$this->getClassName(). ", '" .$params['through_class'] . "', NULL, 'doSelect'))"; ++ $options = "options_for_select($array_options, $default_value , array('include_blank'=>true))"; ++ ++ return "select_tag($name, $options);"; ++ } + else + { + $params = $this->getObjectTagParams($params, array('disabled' => true)); diff --git a/doc/patches/sfMessageSource_MySQL.class.php.patch b/doc/patches/sfMessageSource_MySQL.class.php.patch new file mode 100644 index 0000000..71f4b04 --- /dev/null +++ b/doc/patches/sfMessageSource_MySQL.class.php.patch @@ -0,0 +1,40 @@ +--- sfMessageSource_MySQL.class.php_old 2008-06-11 13:35:00.000000000 +0200 ++++ sfMessageSource_MySQL.class.php 2008-06-11 12:34:29.000000000 +0200 +@@ -133,7 +133,7 @@ + */ + function __destruct() + { +- @mysql_close($this->db); ++ //@mysql_close($this->db); + } + + /** +@@ -366,7 +366,7 @@ + * @param string the catalogue to add to + * @return boolean true if saved successfuly, false otherwise. + */ +- function save($catalogue = 'messages') ++ function save($catalogue = 'messages', $locations = array()) + { + $messages = $this->untranslated; + +@@ -402,6 +402,19 @@ + ({$cat_id}, {$count},'{$message}',$time)"; + mysql_query($statement, $this->db); + } ++ foreach ($locations as $location) ++ { ++ $message = mysql_real_escape_string($location['message'], $this->db); ++ $module = $location['file']; ++ $file = substr($module, strripos($module, DIRECTORY_SEPARATOR) + 1); ++ $module = str_replace('/' . $file, '', substr($module, strripos($module, 'apps/reaktor') + 13)); ++ ++ $statement = "UPDATE trans_unit set ++ filename = '{$file}', ++ module = '{$module}' ++ where source = '${message}'"; ++ mysql_query($statement, $this->db); ++ } + if ($inserted > 0) + { + $this->updateCatalogueTime($cat_id, $variant); diff --git a/doc/patches/sfMessageSource_MySQL.class.php.utf8.patch b/doc/patches/sfMessageSource_MySQL.class.php.utf8.patch new file mode 100644 index 0000000..48ae0b8 --- /dev/null +++ b/doc/patches/sfMessageSource_MySQL.class.php.utf8.patch @@ -0,0 +1,13 @@ +Index: sfMessageSource_MySQL.class.php +=================================================================== +--- sfMessageSource_MySQL.class.php (revision 11922) ++++ sfMessageSource_MySQL.class.php (working copy) +@@ -220,6 +220,8 @@ + { + $variant = mysql_real_escape_string($variant, $this->db); + ++ mysql_set_charset(sfConfig::get("sf_encoding", "utf8"), $this->db); ++ + $statement = + "SELECT t.id, t.source, t.target, t.comments + FROM trans_unit t, catalogue c diff --git a/doc/patches/sfPropelAdmin.patch b/doc/patches/sfPropelAdmin.patch new file mode 100644 index 0000000..ff2fc9c --- /dev/null +++ b/doc/patches/sfPropelAdmin.patch @@ -0,0 +1,37 @@ +--- actions.class.php~ 2008-08-05 09:06:45.000000000 +0200 ++++ actions.class.php 2008-08-05 09:14:11.000000000 +0200 +@@ -349,6 +349,13 @@ + { + getParameterValue('list.filters')): ?> + getColumns('list.filters') as $column): $type = $column->getCreoleType() ?> ++getParameterValue('edit.fields.'.$column->getName().'.params'); ++ $user_params = is_array($user_params) ? $user_params : sfToolkit::stringToArray($user_params); ++ $through_class = isset($user_params['through_class']) ? $user_params['through_class'] : ''; ++?> ++ + isPartial() || $column->isComponent()) && $this->getParameterValue('list.fields.'.$column->getName().'.filter_criteria_disabled')) continue ?> + if (isset($this->filters['getName() ?>_is_empty'])) + { +@@ -397,6 +404,20 @@ + { + + $c->add(getPeerClassName() ?>::getName()) ?>, strtr($this->filters['getName() ?>'], '*', '%'), Criteria::LIKE); ++ ++getClassName(); ++ $related_column = sfPropelManyToMany::getRelatedColumn($class, $through_class); ++ $this_column = sfPropelManyToMany::getColumn($class, $through_class); ++ $pka = $this->getPrimaryKey(); ++ $pk_column = $this->getPeerClassName() . '::' . $pka[0]->getColumnName(); ++ $middlecolumn_this = $through_class . 'Peer::' . strtoupper($this_column->getColumnName()); ++ $middlecolumn_related = $through_class . 'Peer::' . strtoupper($related_column->getColumnName()); ++?> ++ $c->addJoin(, ); ++ $c->add(, $this->filters['getName() ?>']); ++ + + $c->add(getPeerClassName() ?>::getName()) ?>, $this->filters['getName() ?>']); + diff --git a/doc/patches/sfRouting.patch b/doc/patches/sfRouting.patch new file mode 100644 index 0000000..c692951 --- /dev/null +++ b/doc/patches/sfRouting.patch @@ -0,0 +1,48 @@ +Index: controller/sfRouting.class.php +=================================================================== +--- controller/sfRouting.class.php (revision 9827) ++++ controller/sfRouting.class.php (working copy) +@@ -106,12 +106,22 @@ + { + foreach ($request->getParameterHolder()->getAll() as $key => $value) + { ++ if (is_array($value)) ++ { ++ $retval = $this->_loopParameters(urlencode($key), $value, $names); ++ $params = array_merge($params, $retval); ++ continue; ++ } + if ($key == 'module' || $key == 'action' || in_array($key, $names)) + { + continue; + } ++ if (empty($value)) ++ { ++ continue; ++ } + +- $params[] = $key.'='.$value; ++ $params[] = urlencode($key).'='.urlencode($value); + } + } + +@@ -121,6 +131,19 @@ + return $internal_uri.($params ? '?'.implode('&', $params) : ''); + } + } ++ private function _loopParameters($prefix, $parameters, $skiplist) ++ { ++ $params = array(); ++ foreach($parameters as $key => $value) ++ { ++ if (in_array($value, $skiplist) || empty($value)) ++ { ++ continue; ++ } ++ $params[] = $prefix. '[' .urlencode($key). ']='.urlencode($value); ++ } ++ return $params; ++ } + + /** + * Gets the current compiled route array. diff --git a/doc/pre-production b/doc/pre-production new file mode 100644 index 0000000..da06746 --- /dev/null +++ b/doc/pre-production @@ -0,0 +1,28 @@ +Pre production notes: + +Files to be removed before production: + +* /doc/pre-production (this file) +* /cache and /log should be cleared +* /modules/home/templates/phpinfoSuccess.php +* web/images/reaktor_windows.jpg + +Files to be modified before production: + +* /modules/home/actions/actions.class.php - remove phpinfo class +* /config/propel.ini - Should be modified to suit server settings if needed +* /config/databases.yml - Should be modified to suit server settings if needed +* ALL /fixtures contents sitewide should have no test data, just production-ready data +* /test - should be appropriate for production environment +* Front controllers should be cleared +* Windows specific config files (winconfig) to be removed +* _header.php - remove revision information + +Database actions + +* All tables should be rebuilt and then appropriate fixtures loaded if necessary + +Production server pre-requisites + +* imagemagick +* Check PHP is compiled with exif support \ No newline at end of file diff --git a/doc/scripts/README.txt b/doc/scripts/README.txt new file mode 100644 index 0000000..edbf3d1 --- /dev/null +++ b/doc/scripts/README.txt @@ -0,0 +1,8 @@ +To get the latest updated documentation, run the components and partials script: + +user$: php components_and_partials.php + +This will update the SystemDocumentation file with the latest documentation from the files: components.html, partials.html and templates.html +and layouttemplates.html. + +The files are linked to in SystemDocumentation.odt. \ No newline at end of file diff --git a/doc/scripts/components_and_partials.php b/doc/scripts/components_and_partials.php new file mode 100644 index 0000000..98d29f7 --- /dev/null +++ b/doc/scripts/components_and_partials.php @@ -0,0 +1,297 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +//CONSTANTS +define('REAKTOR_ROOT', '/opt/reaktor'); +define('REAKTOR_APPLICATION_ROOT', REAKTOR_ROOT.'/apps/reaktor'); +define('MODULE_ROOT', '/apps/reaktor/modules'); +define('DOC_ROOT', REAKTOR_ROOT.'/doc'); +define('MODULE_ROOT_PATH', REAKTOR_ROOT.MODULE_ROOT); +define('TEMPLATE_ROOT', '/templates'); + +/** + * Extract from the comment block of a file. + * + * @param string $file Name of file to extract comments from + * + */ +function getCommentBlock($file, $format) +{ + try + { + $fh = fopen($file, 'r'); + } + catch(Exception $e) + { + return ''; + } + if($fh) + { + $comment_start = 0; + $comment_block = ''; + + while (true) + { + $line = fgets($fh); + if ($line == null)break; + + if(!$comment_start) //Check for comment start tag, and flip comment_start to true if found + { + preg_match('|(/\*)+|', $line, $php_comment); + + $comment_start = $php_comment ? true : false; + + } + else //Comment start was found extract comment + { + //look for comment end tag + preg_match('|(\*/)+|', $line, $php_end); + + preg_match('/PHP Version 5/i', $line, $comment_end); + if($php_end||$comment_end) + { + break; + } + else //php end tag not found check what the line actually contains + { + $php_comment = trim(substr($line, strpos($line, '*')+1)); + $comment_block .= $php_comment; + + //Don't add empty lines + if(!empty($php_comment)) + { + $comment_block .= $format == 'html'? '
    ' : '\n'; + } + + } + } + } + //Close the template + fclose($fh); + } + return trim($comment_block); +} + +/** + * Get comments from components + * + * @return void + */ +function getComponentComments($format = 'html') +{ + //Get all components + exec("grep -nir 'function execute' /opt/reaktor/apps/reaktor |grep -v svn|grep -i components", $path_to_component); + + $components = array(); + if($format == 'html') + { + echo '

    Components

    '; + } + + foreach($path_to_component as $key => $value) + { + //get name of module component is in + preg_match('|modules/([^/]*)/|', $value, $module_path); + preg_match('@^(?:modules/)?([^/]+)@i', $module_path[0], $module); + + //get component template + preg_match('@(execute)+([^(]*)@', $value, $function_name); + + //get name of component template + $function_name_stripped = $function_name[2]; + $function_name_stripped[0] = strtolower($function_name_stripped[0]); + $template = '_'.$function_name_stripped.'.php'; + + //Open template + $template_file = MODULE_ROOT_PATH.'/'.$module[1].TEMPLATE_ROOT.'/'.$template; + + $comment = getCommentBlock($template_file, $format); + //Save non empty commentblocks + if(!empty($comment)) + { + $components[$module[1]][$template]= $comment; + + //Print to file if requested + if($format == 'html') + { + echo '

    '.$module[1].': '.$template.':


    '; + echo $components[$module[1]][$template].'
    '; + } + } + } + return $components; +} + +/** + * Get comments from components + * + * @return void + */ +function getPartialComments($format = 'html') +{ + //First we get all components (we need them to eliminate all component templates ) + $components = getComponentComments('nodisplay'); + echo 'find '.MODULE_ROOT_PATH.' -name _*|grep -v svn'; + exec('find '.MODULE_ROOT_PATH.' -name _*|grep -v svn', $templates); + + //Print header + if($format == 'html') + { + echo '

    Partials

    '; + } + + //Extract template name and the module it's in + $partials = array(); + foreach ($templates as $key => $value) + { + //get module name template is in + preg_match('|modules/([^/]*)/|', $value, $module_name); + preg_match('@^(?:modules/)?([^/]+)@i', $module_name[0], $module); + + //get template + preg_match('/_(.*)$/', $value, $template); + if(!isset($components[$module[1]][$template[0]])) + { + $comment = getCommentBlock($value, $format); + if(!empty($comment)) + { + $partials[$module[1]][$template[0]] = $comment; + + //Print if requested + if($format == 'html') + { + echo '

    '.$module[1].': '.$template[0].':

    '; + echo $partials[$module[1]][$template[0]].'
    '; + } + } + } + } + + return $partials; +} + +/** + * Get comments from templates + * + * @return void + */ +function getTemplateComments($format = 'html') +{ + exec('find '.REAKTOR_APPLICATION_ROOT.' -name *Success.php|grep -vi .svn', $template_paths); + + //Print header + if($format == 'html') + { + echo '

    Templates

    '; + } + + //Extract template name and the module it's in + $templates = array(); + foreach ($template_paths as $key => $value) + { + //get module name template is in + preg_match('|modules/([^/]*)/|', $value, $module_name); + preg_match('@^(?:modules/)?([^/]+)@i', $module_name[0], $module); + + //get template + preg_match('|[^/]*Success.php|', $value, $template_name); + + //'Get comments' + $comment = getCommentBlock($value, $format); + if(!empty($comment)) + { + $templates[$module[1]][$template_name[0]] = $comment; + + //Print if requested + if($format == 'html') + { + echo '

    '.$module[1].': '.$template_name[0].':

    '; + echo $templates[$module[1]][$template_name[0]].'
    '; + } + } + + } + return $templates; +} + +function getLayoutTemplateComments($format = 'html') +{ + exec('find '.REAKTOR_APPLICATION_ROOT.'/templates/_*.php|grep -vi .svn', $template_paths); + + //Print header + if($format == 'html') + { + echo '

    Layout Templates

    '; + } + + //Extract template name and the module it's in + $templates = array(); + foreach ($template_paths as $key => $value) + { + //get template name + preg_match_all('/\/_([^.]*).php/i', $value, $result); + + $template_name = $result[1][0]; + //'Get comments' + $comment = getCommentBlock($value, $format); + if(!empty($comment)) + { + $templates[$module[1]][$template_name] = $comment; + + //Print if requested + if($format == 'html') + { + echo '

    Layout template: '.$template_name.':

    '; + echo $templates[$module[1]][$template_name].'
    '; + } + } + } + return $templates; + +} + +//Get components and write to file +ob_start(); +getComponentComments(); +$output = ob_get_clean(); +//print $output; +file_put_contents(DOC_ROOT.'/components.html', $output); + + +//Get partials and write to file +ob_start(); +getPartialComments(); +$output = ob_get_clean(); +//echo $output; +file_put_contents(DOC_ROOT.'/partials.html', $output); + +//Get templates and write to file +ob_start(); +getTemplateComments(); +$output = ob_get_clean(); +//echo $output; +file_put_contents(DOC_ROOT.'/templates.html', $output); + +//Get layout templates and write to file +ob_start(); +getLayoutTemplateComments(); +$output = ob_get_clean(); +//echo $output; +file_put_contents(DOC_ROOT.'/layouttemplates.html', $output); + + + + +?> \ No newline at end of file diff --git a/doc/scripts/run_webalizer_reaktor b/doc/scripts/run_webalizer_reaktor new file mode 100755 index 0000000..e885548 --- /dev/null +++ b/doc/scripts/run_webalizer_reaktor @@ -0,0 +1,7 @@ +#/bin/sh + +if [ ! -d "/var/www/webalizer/`date +%Y`" ] +then +mkdir /var/www/webalizer/`date +%Y` +fi +webalizer -p -o /var/www/webalizer/`date +%Y` diff --git a/doc/templates.html b/doc/templates.html new file mode 100644 index 0000000..82d9f56 --- /dev/null +++ b/doc/templates.html @@ -0,0 +1 @@ +

    Templates

    sfComment: listReportedCommentsSuccess.php:

    For easier administration of reported comments this template displays a list of reported or unsuitable comments, within
    a time period of a month.
    The controller passes the following information:
    $namespace - Which namespace are the comments in, either frontend or administrator
    $comments - An array of comments
    $date - The date requested
    $prev_month - Previous month from requested date
    $next_month - Next month from requested date
    $comment_pager - The pager
    $route -

    sfComment: listCommentsSuccess.php:

    Display list of comments within a time period

    sfComment: commentsCalendarSuccess.php:

    Display a calendar with information and how many comments where made that day, with link to it.

    sfComment: listUnsuitableCommentsSuccess.php:

    Display list of unsuitable comments within a time period

    messaging: messageInboxSuccess.php:

    template for message inbox

    messaging: markMessageReadSuccess.php:

    template for messages

    messaging: getNewMessagesSuccess.php:

    Send message form

    messaging: updateMessageCounterSuccess.php:

    Send message form

    artwork: metadataSuccess.php:

    Metadata overview for an artwork

    artwork: discussSuccess.php:

    Before an artwork is displayed on the Reaktor site, it has to be evaluated by a staff member,
    who either approves or rejects the artwork. In order to help with this decision making the
    staff has the opportunity to invite other members to discuss the artwork.
    This template displays an artwork's discussion so far, and a form to add comments to the discussion.
    The controller passes the following information:
    $type - The object type of object discussed
    $object - The object dicussed, either a genericArtwork or a ReaktorFile

    artwork: listDiscussionSuccess.php:

    Before an artwork is displayed on the Reaktor site, it has to be evaluated by a staff member,
    who either approves or rejects the artwork. In order to help with this decision making the
    staff has the opportunity to invite other members to discuss an artwork. The individual files
    on each approved artwork can be reported by users. Before removing a file from the site,
    these files can be discussed in the same way artworks can.
    This template provides a list of all artworks and files flagged for discussion.
    The controller passes the following information:
    $artworks - an array of genericArtworks
    $files - an array of artworkFiles

    artwork: recommendationsSuccess.php:

    This template is a dummy needed to be able to display validation errors in a component. All it does is
    include a component.
    Passed from the controller:
    $artwork - a genericArtwork object

    artwork: listModifiedSuccess.php:

    Component template that displays rejected artworks.

    artwork: removeFileMessageSuccess.php:

    Admin buttons for artwork administration

    artwork: transcoderLogSuccess.php:

    Show the transcoder log for a particular transcoded file

    artwork: xspfOutputSuccess.php:

    $title = str_replace('ø', 'oe', $title);
    $title = str_replace('Ø', 'OE', $title);
    $title = str_replace('å', 'aa', $title);

    artwork: editSuccess.php:

    Artworks are what the Reaktor site is all about, and this template is one of the most important
    relating to artworks - it is the template to edit an artwork.
    Once a file is submitted, the user/admin user gets a streamlined view of the artwork page
    with the necessary fields for editing their artwork, assigning categories, etc.
    The controller passes the following information:
    $artwork - A genericArtwork object
    $firstfile - Artworks with more than one file can decide which file to be displayed on the artwork page
    $objectToTag - Which object to tag, either a file or an artwork

    artwork: listUnapprovedSuccess.php:

    template for listing unapproved artworks

    artwork: listRejectedFilesSuccess.php:

    This template generates a list of all files marked as unsuitable. It does so by including another partial.
    Passed from the controller:
    $files - An array of artworkfile objects, with the rejected file message set.

    artwork: rejectArtworkSuccess.php:

    Component template that prints the 5 last registered users
    Query is created and executed from profileComponents class,
    function executeLastUsers()

    artwork: showSuccess.php:

    Artworks are what the Reaktor site is all about, and this template is one of the most important
    relating to artworks - it is the template to view an artwork.
    The controller passes the following information:
    $artwork - A genericArtwork object
    $thefile - Artworks with more than one file can decide which file to be displayed on the artwork page
    $usercanedit - Passed to partials/components to inform about the logged in users credentials
    $editmode - Passed to partials/components that need to know if in editmode or not

    artwork: listRejectedSuccess.php:

    Component template that displays rejected artworks. It does this by including a partial.
    The controller passes the following information:
    $arts - An array of reaktorArtwork objects
    $pager - Provides paging when the list of artworks is getting longer.

    artwork: lastArtworksFromUserActionSuccess.php:

    This template is used to change the order and filter images on a user's portfoliopage. The controller
    passes the following information:
    $userid : The id of the user who owns the portfolio page
    $orderby: What to order/filter by (title, date, rating or format)
    $user : sfGuardUser object, (used to set title of page)

    artwork: listReportedContentSuccess.php:

    Component template that prints the 5 last registered users
    Query is created and executed from profileComponents class,
    function executeLastUsers()

    artwork: updateSuccess.php:

    Update dummy file

    admin: listApprovedSuccess.php:

    template for listing unapproved artworks

    admin: indexSuccess.php:

    When a user with administration credentials log in, they will be redirected to this page. It provides
    an overview over administration tasks, an acts as a portal to reaktor's backend.
    The controller/action passes the following information:
    Information on editorial teams
    - $editorialteams - which teams is the logged in user a member of
    - $othereditorialteams - the rest of the teams
    The following are integers with the amount of artworks/files/comments/tags in the respected areas
    - $editorialteamartworks
    - $othereditorialteamartworks
    - $discussionFiles
    - $discussionArtworks
    - $reportedfiles
    - $reportedcomments
    - $unapprovedtags

    admin: newCategorySuccess.php:

    Page for adding a new category with translations

    admin: artworkStatusEditSuccess.php:

    Generated (Crud) file for translating artwork statuses
    Variables passed by the action:
    - $artwork_status : The artwork status object, based on the passed ID in the query string

    admin: categoryListSuccess.php:

    Category list admin page
    This template displays all the current categories with a link to translate each one
    Variables passed by the action:
    - $categories : An array of category objects, containing all the categories the site is currently using

    admin: listCompositeSuccess.php:

    The staff of Reaktor can make composite artworks, combining work from many users into one artwork
    This template displays a list of the such artworks
    From the controller the following information is passed:
    - $artworks : an array of all the artworks on the site that are composite/multi-user

    admin: editorialTeamsSuccess.php:

    Template to show all editorial teams and their members

    admin: listIgnoredUsersSuccess.php:

    Lists the users that are ignored often

    admin: listRecommendedSuccess.php:

    The staff of Reaktor can recommend an artwork in a Subreaktor, or in a Subreaktor within a Lokalreaktor.
    This template displays a list of the latest recommended artworks across the site.
    From the controller the following information is passed:
    $artworks - a list of recommended artworks and where they are recommended
    $artworks[x]['artwork']= genericArtwork Object
    $artworks[x]['subreaktor'] = Subreaktor Object
    $artworks[x]['lokalreaktor'] = Subreaktor Object

    admin: listPromotionalEmailRecipientsSuccess.php:

    List all emails from users with the opt-in flag set.

    admin: onlineNowSuccess.php:

    This is for test purposes so the testers can see where the online now count is being derived from
    As such this page is unstyled, but may be expanded in future.
    It is only available to admin users by clicking the online now link
    Variables passed from the action:
    - $usersOnline : The array of user objects that are contributing to the count

    admin: categoryEditSuccess.php:

    Generated (Crud) file for editing category translations
    Variables passed by the action:
    - $edit_category : The category object based on the id passed in the query string

    admin: adminFunctionsSuccess.php:

    Special admin functions for users with the "adminfunctions" credential

    reports: userReportsSuccess.php:

    This file defines the user report panel
    Takes parameters:
    $residences
    $interests
    $report_types

    reports: showBookmarksSuccess.php:

    Administrative users are able to document the success of the site, as well as work out how the site is used by it's visitors
    and members, by using the reports section in the backend. This template contains a list of bookmarked reports.
    The controller passes the following information:
    - $groupedReports - Array of reports, dividied by groups (array of arrays)

    reports: artworkReportsSuccess.php:

    Artwork report page

    subreaktors: tegningReaktorSuccess.php:

    The reaktor site divides it's content into sections called subReaktors and lokalReaktors, each subReaktor
    corresponds to a format or category. The lokalReaktors are mini Reaktor sites filtered by location. They
    have the same subreaktors as the Reaktor sites.
    This template is the frontpage for the tegning/drawing subReaktor: tegningReaktor
    The controller, a common controller for all the subreaktor templates, passes the following information.
    $subreaktor - which subreaktor (not needed in this particular template)
    $lokalreaktor - which lokalreaktor (not needed in this particular template)
    $bannerfarge - string, randomly chosen colour to display banner.

    subreaktors: fotoReaktorSuccess.php:

    The reaktor site divides it's content into sections called subReaktors and lokalReaktors, each subReaktor
    corresponds to a format or category. The lokalReaktors are mini Reaktor sites filtered by location. They
    have the same subreaktors as the Reaktor sites.
    This template is the frontpage for the foto subReaktor: fotoReaktor.
    The controller, a common controller for all the subreaktor templates, passes the following information.
    $subreaktor - which subreaktor (not needed in this particular template)
    $lokalreaktor - which lokalreaktor (not needed in this particular template)
    $bannerfarge - string, randomly chosen colour to display banner.

    subreaktors: tegneserierReaktorSuccess.php:

    The reaktor site divides it's content into sections called subReaktors and lokalReaktors, each subReaktor
    corresponds to a format or category. The lokalReaktors are mini Reaktor sites filtered by location. They
    have the same subreaktors as the Reaktor sites.
    This template is the frontpage for the cartoon/tegneserier subReaktor: tegneserierReaktor
    The controller, a common controller for all the subreaktor templates, passes the following information.
    $subreaktor - which subreaktor (not needed in this particular template)
    $lokalreaktor - which lokalreaktor (not needed in this particular template)
    $bannerfarge - string, randomly chosen colour to display banner.

    subreaktors: lydReaktorSuccess.php:

    The reaktor site divides it's content into sections called subReaktors and lokalReaktors, each subReaktor
    corresponds to a format or category. The lokalReaktors are mini Reaktor sites filtered by location. They
    have the same subreaktors as the Reaktor sites.
    This template is the frontpage for the sound/lyd subReaktor: lydReaktor
    The controller, a common controller for all the subreaktor templates, passes the following information.
    $subreaktor - which subreaktor (not needed in this particular template)
    $lokalreaktor - which lokalreaktor (not needed in this particular template)
    $bannerfarge - string, randomly chosen colour to display banner.

    subreaktors: filmReaktorSuccess.php:

    The reaktor site divides it's content into sections called subReaktors and lokalReaktors, each subReaktor
    corresponds to a format or category. The lokalReaktors are mini Reaktor sites filtered by location. They
    have the same subreaktors as the Reaktor sites.
    This template is the frontpage for the film subReaktor: filmReaktor
    The controller, a common controller for all the subreaktor templates, passes the following information.
    $subreaktor - which subreaktor (not needed in this particular template)
    $lokalreaktor - which lokalreaktor (not needed in this particular template)
    $bannerfarge - string, randomly chosen colour to display banner.

    subreaktors: listSuccess.php:

    subReaktors filter the content of Reaktor either on location or content. This template lets the user change
    the order the subReaktors appear in, and an interface to add new Reaktors.
    The controller passes the following information:
    $subreaktors - Array of Subreaktors

    subreaktors: editSuccess.php:

    The Reaktor site divides its content into sections according to nature of the artwork, these sections are the subReaktors
    and lokalReaktors. For flexibility reasons, it is possible to add more, and edit the existing ones. This is the template for
    editing a subReaktor or lokalReaktor.
    The controller passes the following information:
    $lokalresidences - an array of the residences to choose from, needed for drop down
    $logo_filename - the filename of the sub- or lokalReaktors logo
    $logo_path - the path to the sub- or lokalReaktors logo
    $template_filename - the filename of the sub- lokalReaktor template
    $template_path - the path to the sub- lokalReaktor template

    subreaktors: groruddalenReaktorSuccess.php:

    The reaktor site divides it's content into sections called subReaktors and lokalReaktors, each subReaktor
    corresponds to a format or category. The lokalReaktors are mini Reaktor sites filtered by location. They
    have the same subreaktors as the Reaktor sites.
    This template is the frontpage for the groruddalen lokalReaktor: groruddalenReaktor
    The controller, a common controller for all the subreaktor templates, passes the following information.
    $subreaktor - which subreaktor (not needed in this particular template)
    $lokalreaktor - which lokalreaktor
    $bannerfarge - string, randomly chosen colour to display banner.

    subreaktors: tekstReaktorSuccess.php:

    The reaktor site divides it's content into sections called subReaktors and lokalReaktors, each subReaktor
    corresponds to a format or category. The lokalReaktors are mini Reaktor sites filtered by location. They
    have the same subreaktors as the Reaktor sites.
    This template is the frontpage for the tekst/text subReaktor: tekstReaktor
    The controller, a common controller for all the subreaktor templates, passes the following information.
    $subreaktor - which subreaktor (not needed in this particular template)
    $lokalreaktor - which lokalreaktor (not needed in this particular template)
    $bannerfarge - string, randomly chosen colour to display banner.

    profile: changePasswordSuccess.php:

    change password

    profile: registerSuccess.php:

    Users who want to interact with the Reaktor site, need to be logged in. To be able to log
    in they need to register first, which is what this template provides, a form for users to
    register. The form itself is retrived from a partial.
    From the action the following information is given:
    $sf_guard_user - an empty sfGuardUser object, the object will be populated when the form i posted
    $residence_array - the possible residences a user can choose from in the residence drop down

    profile: resourcesSuccess.php:

    A user can store resources he/she uses often.
    This is really just a component, but we need to validate the form, which is why this dummy template
    is needed.
    The controller passes the following information:
    $user - The id of the user

    profile: activateSuccess.php:

    User activation success, shown when a user follows the activation link in their email after registering.
    This page will only be visible to users who provide a correct key, and are not already verified
    Variables avalilable to this template:
    - $newUser : The user object of the user who just activated

    profile: portfolioSuccess.php:

    template for user portifolio

    profile: editSuccess.php:

    Started out as a file auto-generated by sfPropelCrud
    date: 2008/02/07 11:25:21

    profile: createSuccess.php:

    This template assures the reader that the registration was successful.
    It is only possible to load this page on a successful registration, it can not be accessed directly
    Available variables:
    - $newUser : The user object of the user that just registered

    profile: changeemailSuccess.php:

    Started out as a test file for secure actions

    profile: myPageSuccess.php:

    Every registered user of Reaktor have their own page they can call 'home'. That's the myPage,
    and this is the template for it. The template mostly includes other components.
    The controller passes the following information:
    $user - An sfGuardUser object

    favourite: listAllSuccess.php:

    helper template for listing all favourites

    favourite: listLastSuccess.php:

    helper template for listing all favourites

    favourite: addSuccess.php:

    helper template for adding favourite

    favourite: removeSuccess.php:

    helper template for adding favourite

    sfTransUnit: editSuccess.php:

    Each string in Reaktor can be translated. This template is used in the adminportal to display how a string
    has been translated. The string in the code is the source, usually plain english and can be used directly as
    an English version. Other times, the source is just a placeholder and must be translated to english as well.
    This template is the main template for the edit view of a string translation. The controller passes the following information:
    $trans_unit - Trans unit object, which contains the source string to be translated
    $labels - The form labels
    auto-generated by sfPropelAdmin
    date: 2008/08/14 12:20:44

    articles: editSuccess.php:

    The reaktor site's main functionality is uploading artworks, but also providing useful articles for
    the regular users and staff. This template lets staff users create and edit an article. It does this
    by using compoments and partials. The controller passes the following information:
    $article - an article object

    articles: articleRelationsSuccess.php:

    The reaktor site's main functionality is uploading artworks, but also providing useful articles for
    the regular users and staff. These articles can sometimes cover the same topic, and this template
    provide a way of relating articles to each other and displays a list of articles that have been
    related to each other
    This is really just a component, but we need to validate the form, which is why this dummy template
    is needed.
    The controller passes the following information:
    $article - An article object

    articles: viewSuccess.php:

    The reaktor site's main functionality is uploading artworks, but also providing useful articles for
    users and staff, where they can learn more about artworks, the system, etc. This template is for viewing an article.
    The controller passes the following information:
    $article - The article object to be viewed

    articles: orderArticlesSuccess.php:

    To determine which articles should be on top of lists, this template provides the possibility to
    drag and drop a list of articles with the same type. The action does not pass any parameters.
    The controller passes the following information:
    $article_type : ArticlePeer::{type}_ARTICLE
    $articles : Article array

    sfGuardAuth: secureSuccess.php:

    Default secure template for accessing restricted action

    sfGuardAuth: signinSuccess.php:

    Shows message to non-authed user
    This template replaces the sfGuardAuth standard template for the login form
    It is shown when a user attempts to access a restricted page before logging in
    The login box follows the user on the sidebar, so there is no need to repeat it
    here, we will simply inform the user that they must login or register.

    tags: listTagsSuccess.php:

    List all the tags for administration purposes

    tags: findSuccess.php:

    Page to list results of searches
    Values to search can be passed directly on the URL, triggered via the search box in the sidebar,
    or through clicks on tags and categories. It is possible to get results from tags or categories.
    User searches can also be dealt with via this page, if the form is posted with "findype" = "user"
    The following parameters are sent to the template by the action:
    - $mode : this is the search mode (tag or category)
    - $tags : These are the individual tags that are being searched
    - $categories : These are the individual categories that are being searched
    - $sortmode : This is the current sort mode (date, title, rating, username)
    - $sortdirection : The current sort direction (asc, desc)

    upload: showFilesSuccess.php:

    Show the user's uploaded files, and whether they are attached to artwork or not
    If admin give the opportunity to see any files
    Very basic for now as this is NOT covered in the current task, I just needed something
    to work with when testing the upload process
    Possibly to be updated when workfolow issues are resolved

    upload: thumbnailCropSuccess.php:

    Thumbnail editing page for a selected file, based on crop area
    Styles for this are contained in cropper.css, as defined in view.yml
    Variables passed from the action are:
    - $file : The file object this thumbnail is connected to

    upload: editSuccess.php:

    Edit page for uploaded files and text editing
    This is the template loaded when the user has uploaded a file, chosen to edit a file, or selected to
    create/edit a text artwork. This is NOT for editing artworks, however this page does have the necessary buttons
    for creating new artworks and linking artworks.
    Variables available to this template provided by the action:
    - $thisFile : The file object that we are editing - it will always exist, either as an existing file or a new one
    - $successful : This is set as true if the save was successful
    - $mce_data : If set, contains the contents of the TinyMCE field (for text artworks)
    - $artworkArray : Contains an array of eligible artworks that this file can link to (or an empty array if none)

    upload: uploadSuccess.php:

    The main file upload page, where content is added to Reaktor
    When linking files files to existing artwork (for example in galleries) there is extra checking to ensure matching file type.
    If the file type of the upload does not match, a special error (link_error) is returned which contains the file type
    that was mistakenly uploaded.
    Variables passed from the action to this template:
    - $artwork : The artwork object if one has been passed for artwork linking, if set the user will see additional information
    regarding the artwork linking, if not set then it will continue as a normal upload

    contentServer: contentServerSuccess.php:

    The content server is used to display all protected content on the site. Credentials and
    availability are checked before anything is sent to the browser for rendering, should anything fail,
    a failure image is displayed. All the logic is carried out in the action file, there is no template output
    as the content is effectively streamed directly to the browser.
    This template is only used for testing when debug output is required
    Normally this template should never load as the action ends with a redirect or die()/exit()

    feed: feedSuccess.php:

    Render an RSS feed
    This file should not need to be modified, and any extra output in here could cause the feed to fail.
    It takes the feed from the action and renders an xml file from it.
    - $feed : The feed object containing the entire feed

    feed: listSuccess.php:

    Present a list of common/popular RSS Feeds which will be displayed when the user clicks the link in the footer menu.
    Lokal reaktor is automagically added to the route, not normal subreaktors as
    they are already looped through.
    To add feeds to the page, you simply need
    to add items to the array below this comment block, following the examples.
    The slugs are the identifiers that point to the action that will control how the feed is rendered. Refer to the documentation
    for a list of slugs, or check the switch($slug) block in feed/actions.class.php for a list of available slugs.
    The routes refer to the routing.yml file, and will generally be "artworkfeed" or "articlefeed".
    The descriptions will be the actual link text on the page, and also in the browser RSS headers.

    userContent: manageSuccess.php:

    Template for managing user content, either by the user or an admin user
    Users have access to all their uplaoded files, artworks and whether things are approved, awaiting approval etc.
    Variables available to this template provided by the action:
    - $thisUser : The user object of the owner of this work - either the logged in user or if in admin mode could be a different user
    - $route : The route to use for the various modes, will change based on if whether we are admin or not editing this user content
    - $allArtworkCount : The count of all this user's artwork
    - $draftArtworkCount : The count of all this user's artwork still in draft status
    - $rejectedArtworkCount : The count of all this user's artwork that has been rejected
    - $uploadedCount : The count of all this user's files that they have uploaded in total
    - $orphanedCount : The count of all this user's files that are not attached to artworks yet

    userContent: fileListSuccess.php:

    Template for showing all the files a user has ever uploaded
    Variables available to this template provided by the action:
    - $thisUser : The user object of the owner of this work - either the logged in user or if in admin mode could be a different user
    - $files : Array of file objects

    userContent: artworkListSuccess.php:

    Template for showing all the user's artwork
    Variables available to this template provided by the action:
    - $thisUser : The user object of the owner of this work - either the logged in user or if in admin mode could be a different user
    - $artworks : Array of artwork objects
    - $titleFilter : An extra descriptive word such as "submitted" that shows the page we are looking at

    userContent: collectionSuccess.php:

    Wrapper for dragging and dropping from one file list to another as an easy way to make galleries from uploaded files

    home: phpinfoSuccess.php:

    PHP Info page - MUST BE DELETED BEFORE PRODUCTION

    home: indexSuccess.php:

    When users first arrive at the reaktor site their first meeting will be with this page.
    This is the front page template for the main home page of reaktor. Many components on
    the home page will be derived from the main layout.php file and from various blocks and
    modules. So many in facts, that there are no information being passed from the controller.

    home: error404Success.php:

    Custom error 404 page

    sfGuardUser: newuserSuccess.php:

    This template ensures the reader that the registration is successful.

    sfGuardUser: listUsersSuccess.php:

    User list template, used for listing users by username

    \ No newline at end of file diff --git a/lib/model/AdminMessage.php b/lib/model/AdminMessage.php new file mode 100644 index 0000000..07603bc --- /dev/null +++ b/lib/model/AdminMessage.php @@ -0,0 +1,21 @@ +getsfGuardUser()->getUsername(); + } +} diff --git a/lib/model/AdminMessagePeer.php b/lib/model/AdminMessagePeer.php new file mode 100644 index 0000000..52be43d --- /dev/null +++ b/lib/model/AdminMessagePeer.php @@ -0,0 +1,29 @@ +add(parent::EXPIRES_AT, strtotime('now'), Criteria::GREATER_THAN); + + $c->addAscendingOrderByColumn(parent::EXPIRES_AT); + + return parent::doSelectOne($c); + } + +} diff --git a/lib/model/Article.php b/lib/model/Article.php new file mode 100644 index 0000000..d82f053 --- /dev/null +++ b/lib/model/Article.php @@ -0,0 +1,687 @@ +getId(), $pub); + } + + public function getParsedContent() + { + $content = $this->getContent(); + $content = preg_replace('/(? '\\1', 'items' => '\\2', 'source' => 'article'))", + $content); + return $content; + } + + /** + * Returns the ingress/intro text + * + * @return string + */ + public function getIntro() + { + return $this->getIngress(); + } + + public function getParsedIngress() + { + $ingress = parent::getIngress(); + $ingress = preg_replace('/(? '\\1', 'items' => '\\2', 'source' => 'article'))", + $ingress); + return $ingress; + } + + /** + * Returns the number of tags + * + * @param bool $include_unapproved + * @return int + */ + public function countTags() + { + return count($this->getTags()); + } + + /** + * Create an array of arrays + */ + public function getUnrelatedArticles() + { + //Find the related articles + $related_articles = $this->getRelatedArticles(); + + //Get the id's of the related artworks + $related = array(); + $related_help_articles = array(); + foreach($related_articles as $related_article) + { + + $related_help_articles = array(); + } + + //Include the artwork itself + $related[] = $this->getId(); + + //Get the unrelated artworks + $c = new Criteria(); + $c->add(ArticlePeer::ID, $related, Criteria::NOT_IN); + + // Not all article types can relate to mypage and internal articles + switch($this->getArticleType()) + { + case ArticlePeer::HELP_ARTICLE: + case ArticlePeer::REGULAR_ARTICLE: + case ArticlePeer::THEME_ARTICLE: + case ArticlePeer::FOOTER_ARTICLE: + case ArticlePeer::SPECIAL_ARTICLE: + $critA = $c->getNewCriterion(ArticlePeer::ARTICLE_TYPE, ArticlePeer::MY_PAGE_ARTICLE, Criteria::NOT_EQUAL); + $critB = $c->getNewCriterion(ArticlePeer::ARTICLE_TYPE, ArticlePeer::INTERNAL_ARTICLE, Criteria::NOT_EQUAL); + $critA->addAnd($critB); + $c->add($critA); + break; + case ArticlePeer::MY_PAGE_ARTICLE: + $c->add(ArticlePeer::ARTICLE_TYPE, ArticlePeer::INTERNAL_ARTICLE, Criteria::NOT_EQUAL); + break; + } + +// List only published articles - Ticket 22105 + $c->add(ArticlePeer::STATUS, ArticlePeer::PUBLISHED); + $articles = ArticlePeer::doSelect($c); + + $c->add(ArticlePeer::ARTICLE_TYPE,ArticlePeer::HELP_ARTICLE); + $c->addJoin(ArticlePeer::ID, ArticleSubreaktorPeer::ARTICLE_ID); + $c->addAscendingOrderByColumn(ArticlePeer::BASE_TITLE); + + $help_articles = ArticlePeer::doSelect($c); + + + $article_types = ArticlePeer::getArticleTypes(); + + $unrelated_articles = array(); + + foreach($articles as $article) + { + if ($article->getArticleType() ) + { + + if($article->getArticleType()!=ArticlePeer::HELP_ARTICLE) { + $unrelated_articles[$article_types[$article->getArticleType()]][$article->getId()] = $article->getTitle(); + } else { + + + + } + } + } + + $related_help_articles = array(); + +if(is_array($help_articles)) + foreach($help_articles as $article){ + +$sb=$article->getSubReaktors(true,true); + $unrelated_articles[$article_types[ArticlePeer::HELP_ARTICLE].' - '.current ( $sb) ][$article->getId()] = $article->getTitle(); + + +} + return $unrelated_articles; + + } + + /** + * Publishes an article + * + * @return void + */ + public function publish() + { + $this->setStatus(ArticlePeer::PUBLISHED); + } + + /** + * Link to article's view page + * + * @return Link to article's view page + */ + public function getLink() + { + if(sfConfig::get("admin_mode")){ + return '@article_admin?permalink='.urlencode($this->getPermalink()); +} else { + return '@article?permalink='.urlencode($this->getPermalink()) ; + } + + } + + /** + * Relates the article to an artwork + * + * @param genericArtwork|reaktorArtwork|integer $artwork + */ + public function relateToArtwork($artwork) + { + $artwork_id = null; + if (!is_int($artwork)) + { + $artwork_id = $artwork->getId(); + } + else + { + $artwork_id = $artwork; + } + $crit = new Criteria(); + $crit->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId()); + $crit->add(ArticleArtworkRelationPeer::ARTWORK_ID, $artwork_id); + ArticleArtworkRelationPeer::doInsert($crit); + } + + /** + * Returns an array of related artworks + * + * @return array|genericArtwork + */ + public function getRelatedArtwork() + { + $artwork = array(); + foreach ($this->getArticleArtworkRelations() as $anAARelation) + { + $artwork[$anAARelation->getReaktorArtwork()->getId()] = new genericArtwork($anAARelation->getReaktorArtwork()); + } + return $artwork; + } + + /** + * Removes an artwork from the list of related artworks + * + * @param genericArtwork|reaktorArtwork|integer $artwork + */ + public function removeRelatedArtwork($artwork) + { + $artwork_id = null; + if (!is_int($artwork)) + { + $artwork_id = $artwork->getId(); + } + else + { + $artwork_id = $artwork; + } + $crit = new Criteria(); + $crit->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId()); + $crit->add(ArticleArtworkRelationPeer::ARTWORK_ID, $artwork_id); + ArticleArtworkRelationPeer::doDelete($crit); + } + + /** + + * Return the taggable model string to use in the tagging table + * + * @return string + */ + public function getTaggableModel() + { + return "Article"; + } + + /** + * Get all the articles a subreaktor is connected to. + * + * @param boolean $reference Return reference if true, id if false + * @return array Of either subreaktor references (string) or id's (integer) + */ + public function getSubreaktors($reference = false,$name=false) + { + $crit = new Criteria(); + $crit->add(ArticleSubreaktorPeer::ARTICLE_ID, $this->getId()); + + $subreaktors = array(); + if($reference) + { + $res = ArticleSubreaktorPeer::doSelectJoinSubreaktor($crit); + foreach ($res as $row) + { + if($name){ + $subreaktors[$row->getSubreaktorId()] = $row->getSubreaktor()->getName(); + }else{ + $subreaktors[$row->getSubreaktorId()] = $row->getSubreaktor()->getReference(); + } + } + } + else + { + $res = ArticleSubreaktorPeer::doSelect($crit); + foreach ($res as $row) + { + $subreaktors[$row->getSubreaktorId()] = $row->getSubreaktorId(); + } + } + return $subreaktors; + } + + public function getLokalReaktors() + { + $retarr = array(); + foreach ($this->getSubreaktors() as $subreaktor_id => $subreaktor) + { + if (Subreaktor::getById($subreaktor)->isLokalReaktor()) + { + $retarr[$subreaktor_id] = $subreaktor; + } + } + return $retarr; + } + + public function getCategories() + { + $crit = new Criteria(); + $crit->add(ArticleCategoryPeer::ARTICLE_ID, $this->getId()); + $res = ArticleCategoryPeer::doSelectJoinCategory($crit); + $categories = array(); + foreach ($res as $row) + { + $categories[$row->getCategory()->getId()] = $row->getCategory()->getName(); + } + return $categories; + } + + protected function _addSubreaktor($subreaktor) + { + $as = new ArticleSubreaktor(); + $as->setArticle($this); + $as->setSubreaktor($subreaktor); + $as->save(); + } + + /** + * Add subreaktor to the article + * + * @param integer|string $subreaktor ID or reference string + */ + function addSubreaktor($subreaktor) + { + if (is_numeric($subreaktor)) + { + $subreaktor = Subreaktor::getById($subreaktor); + } + else + { + $subreaktor = Subreaktor::getByName($subreaktor); + } + + $this->_addSubreaktor($subreaktor); + } + + /** + * Compare the new list of subreaktors to the old one, if there are differences, + * add or delete to make sure the database is updated. + * + * This is useful when using checkboxes in forms to keep score. + * + * @param array $newSubreaktors + * @param array $oldSubreaktors + */ + function updateSubreaktors($newSubreaktors, $oldSubreaktors) + { + //Add all new subreaktors that haven't already been added + foreach($newSubreaktors as $subreaktor) + { + if (!in_array($subreaktor, $oldSubreaktors)) + { + $this->addSubreaktor($subreaktor); + } + } + //Remove all old subreaktors that aren't in the new list + foreach($oldSubreaktors as $subreaktor) + { + if (!in_array($subreaktor, $newSubreaktors)) + { + $this->removeSubreaktor($subreaktor); + } + } + } + + /** + * Remove subreaktor from the article + * + * @param integer $subreaktor_id + */ + function removeSubreaktor($subreaktor_id) + { + $c = new Criteria(); + $c->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, $subreaktor_id); + $c->add(ArticleSubreaktorPeer::ARTICLE_ID, $this->getId()); + ArticleSubreaktorPeer::doDelete($c); + + ArticleCategoryPeer::removeAllInSubreaktor($this, $subreaktor_id); + } + + /** + * Adds a category to the article + * + * @param integer $categoryId + */ + function addCategory($categoryId) + { + $ac = new ArticleCategory(); + $ac->setArticle($this); + $ac->setCategoryId($categoryId); + $ac->save(); + } + + /** + * Removes a category from the article + * + * @param integer $categoryId + */ + function removeCategory($categoryId) + { + $crit = new Criteria(); + $crit->add(ArticleCategoryPeer::CATEGORY_ID, $categoryId); + $crit->add(ArticleCategoryPeer::ARTICLE_ID, $this->getId()); + $res = ArticleCategoryPeer::doDelete($crit); + } + + public function getBannerFile() + { + return ArticleFilePeer::retrieveByPK($this->getBannerFileId()); + } + + /** + * Returns a article teaser of $max length + * + * @param int $max Default to app_articles_teaser_len + * @param int &$txt_len Will be set to the entire article length + * @param int &$cut_len Will be set to the teaser length + * @return string The html tag stripped teaser + */ + public function getTeaser($max = 0, &$txt_len = 0, &$cut_len = 0, $introOrContent = ArticlePeer::CONTENT) + { + if ($introOrContent == ArticlePeer::INGRESS) + { + $txt = $this->getIngress(); + } + else//if($introOrContent == ArticlePeer::CONTENT) + { + $txt = $this->getContent(); + } + if (!$max) + { + $max = sfConfig::get('app_articles_teaser_len', 80); + } + + $txt = strip_tags($txt); + $txt_len = strlen($txt); + + return stringMagick::chop($txt, $max, $txt_len, $cut_len); + } + + public function setCustom($row) + { + self::setID($row[3]); + self::setDate($row[0], $row[1]); + self::setArticleType($row[2]); + self::setPermalink($row[5]); + if (!is_null($row[6]) && in_array($row[2], ArticlePeer::getTranslatableTypes())) + { + self::setTitle($row[6]); + } + else + { + self::setTitle($row[4]); + } + } + private function setDate($year, $month) + { + $this->_year = $year; + $this->_month = $month; + } + public function getYear() + { + return $this->_year ? $this->_year : date("Y", strtotime(self::getCreatedAt())); + } + public function getMonth() + { + return $this->_month ? $this->_month : date("n", strtotime(self::getCreatedAt())); + } + public function getId() + { + $id = parent::getId(); + return $id ? $id : 0; + } + + /** + * Required by the Feed plugin to generate routes automatically + * + * @return string The culture in question, "no" if none specified + */ + public function getFeedSfCulture() + { + return sfContext::getInstance()->getRequest()->getParameter('sf_culture', 'no'); + } + + /** + * Returns whether or not the article is in draft stage + * + * @return bool + */ + public function isDraft() + { + return parent::getStatus() == ArticlePeer::DRAFT; + } + + /** + * Returns whether or not the article has been published + * + * @return boolean + */ + + public function isPublished() + { + return parent::getStatus() == ArticlePeer::PUBLISHED; + } + + /** + * Returns whether or not the article has been archived + * + * @return bool + */ + public function isArchived() + { + return parent::getStatus() == ArticlePeer::ARCHIVED; + } + + /** + * Returns whether or not the article has been archived + * + * @return void + */ + public function isDeleted() + { + return parent::getStatus() == ArticlePeer::DELETED; + } + + /** + * Changes the status of the article to be in draft mode + * + * @return $this + */ + public function setDraft() + { + $this->setStatus(ArticlePeer::DRAFT); + return $this; + } + + /** + * Changes the status of the article to be published + * + * @return $this + */ + public function setPublished() + { + $this->setStatus(ArticlePeer::PUBLISHED); + parent::setStatus(ArticlePeer::PUBLISHED); + TaggingPeer::setAllTaggingsApproved($this); + + return $this; + } + + /** + * Changes the status of the article to be archived + * + * @return $this + */ + public function setArchived() + { + $this->setStatus(ArticlePeer::ARCHIVED); + return $this; + } + + /** + * FAIL. Propel owns this method name so we have to take argument. + * Just pass anything, it will be ignored. + * + * @param mixed $arg + * @return void + */ + public function setDeleted($arg) + { + $this->setStatus(ArticlePeer::DELETED); + return $this; + } + + /** + * Return translated title for footer articles or base title for the others + * + * @return string the title + */ + public function getTitle($lang = null) + { + if (!$lang && (!$this->hasTranslatableTitle() || !parent::getTitle())) + { + return $this->getBaseTitle() != "" ? $this->getBaseTitle() : sfContext::getInstance()->getI18n()->__("No title"); + } + else + { + if ($lang) + { + $this->setCulture($lang); + } + return parent::getTitle(); + } + $this->setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + + /** + * Set the non-translated (backup) title + * + * @param unknown_type $title + */ + public function setTitle($title) + { + $this->setBaseTitle($title); + } + + /** + * Set the translated titles + * + * @param array $titles an array of culture=>title pairs + */ + public function setI18nTitles($titles = array()) + { + foreach ($titles as $culture => $title) + { + $this->setCulture($culture); + parent::setTitle($title); + } + $this->setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + + /** + * Check if an article has a translatable title or not + * Moved this here so new ones can be added/removed from a single location + * + * @return boolean true if article is one of the allowed translatable types + */ + public function hasTranslatableTitle() + { + if (in_array($this->getArticleType(), ArticlePeer::getTranslatableTypes())) + { + return true; + } + return false; + } + + public function getStatus() + { + + $status_types = ArticlePeer::getStatusTypes(); + return parent::getStatus() ? $status_types[parent::getStatus()] : $status_types[ArticlePeer::DRAFT]; + //return $status_types[parent::getStatus()]; + } + + /** + * Return the integer status value + * + * @return void + */ + public function getArticleStatus() + { + return parent::getStatus(); + } + + /** + * Overriding the hydrate method so we don't need to set the culture before calling getters + * + * @param ResultSet $rs + * @param integer $startcol + */ + public function hydrate(ResultSet $rs, $startcol = 1) + { + parent::hydrate($rs, $startcol); + $this->setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + + /** + * Returns the author id + * + * @return int + */ + public function getUserId() + { + return $this->getAuthorId(); + } + + + public function getFeedPermalink() + { + return $this->getLink(); + } + + public function getCustomFeedTitle() + { + return $this->getTitle(); + } +} + +sfPropelBehavior::add('Article', array('sfPropelActAsTaggableBehavior')); + diff --git a/lib/model/ArticleArticleRelation.php b/lib/model/ArticleArticleRelation.php new file mode 100644 index 0000000..acbfef1 --- /dev/null +++ b/lib/model/ArticleArticleRelation.php @@ -0,0 +1,12 @@ +getId() : $article; + $article = $article instanceof Article ? $article : ArticlePeer::retrieveByPK($article_id); + $c = new Criteria(); + // Bug #611, 603, 434 Customer doesn't want this, they want one way only + /* + // First lets get the IDs of the related objects - we can't do a mega join here with Propel because of + // The double foreign key (Propel does not support table aliases yet) + + $critA = $c->getNewCriterion(parent::FIRST_ARTICLE, $article); + $critB = $c->getNewCriterion(parent::SECOND_ARTICLE, $article); + $critA->addOr($critB); + + $c->add($critA); + */ + $c->add(parent::FIRST_ARTICLE, $article_id, Criteria::EQUAL); + + $relatedRows = parent::doSelect($c); + + if (!$relatedRows) + { + return array(); + } + foreach($relatedRows as $relatedRow) + { + $relatedIds[] = $relatedRow->getSecondarticle(); + // ($relatedRow->getFirstArticle() != $article) ? $relatedRow->getFirstArticle() : $relatedRow->getSecondarticle(); + } + + // Now we have all the article IDs, we just need to retreive them + $c = new Criteria(); + $c->setDistinct(); + $c->add(ArticlePeer::ID, $relatedIds, Criteria::IN); + $c->addJoin(ArticlePeer::ID, parent::FIRST_ARTICLE, Criteria::LEFT_JOIN); + + if ($published) + { + $c->add(ArticlePeer::STATUS, ArticlePeer::PUBLISHED); + } + + //In case some articles have changed article_type make sure no relations that aren't allowed are shown + switch($article->getArticleType()) + { + case ArticlePeer::HELP_ARTICLE: + case ArticlePeer::REGULAR_ARTICLE: + case ArticlePeer::THEME_ARTICLE: + case ArticlePeer::FOOTER_ARTICLE: + case ArticlePeer::SPECIAL_ARTICLE: + $critA = $c->getNewCriterion(ArticlePeer::ARTICLE_TYPE, ArticlePeer::MY_PAGE_ARTICLE, Criteria::NOT_EQUAL); + $critB = $c->getNewCriterion(ArticlePeer::ARTICLE_TYPE, ArticlePeer::INTERNAL_ARTICLE, Criteria::NOT_EQUAL); + $critA->addAnd($critB); + $c->add($critA); + break; + case ArticlePeer::MY_PAGE_ARTICLE: + $c->add(ArticlePeer::ARTICLE_TYPE, ArticlePeer::INTERNAL_ARTICLE, Criteria::NOT_EQUAL); + break; + + } + return ArticlePeer::doSelect($c); + } + + /** + * Get the relation given two articles + * + * @param unknown_type $first_article + * @param unknown_type $second_article + * @return unknown + */ + public static function getRelation($first_article, $second_article) + { + $first_article = $first_article instanceof Article ? $first_article->getId() : $first_article; + $second_article = $second_article instanceof Article ? $second_article->getId() : $second_article; + + $c = new Criteria(); + + // Bug #611, 603, 434 Customer doesn't want this, they want one way only + /*$critA = $c->getNewCriterion(parent::FIRST_ARTICLE, $first_article); + $critB = $c->getNewCriterion(parent::SECOND_ARTICLE, $second_article); + $critA->addAnd($critB); + + $critC = $c->getNewCriterion(parent::FIRST_ARTICLE, $second_article); + $critD = $c->getNewCriterion(parent::SECOND_ARTICLE, $first_article); + $critC->addAnd($critD); + + $critA->addOr($critC); + $c->add($critA);*/ + $c->add(parent::FIRST_ARTICLE, $first_article); + $c->add(parent::SECOND_ARTICLE, $second_article); + + $c->addDescendingOrderByColumn(parent::CREATED_AT); + + return parent::doSelectOne($c); + } + + /** + * Delete a relation given two articles + * + * @param unknown_type $first_article + * @param unknown_type $second_article + */ + public static function deleteRelation($first_article, $second_article) + { + $relation = ArticleArticleRelationPeer::getRelation($first_article, $second_article); + if ($relation) + { + //delete relation + //$c = new Criteria(); + //$c->add(parent::ID, $relation->getId()); + //parent::doDelete($c); + parent::doDelete($relation->getId()); + } + + } + + /** + * Add a relation between to articles, where relations work both ways (i.e there is no hierarchical structure) + * + * @param int $first_article Article to relate to + * @param int $second_article Article to relate to + * @param int $user sfGuardUser User creating the relation + */ + public static function addRelatedArticle($first_article, $second_article, $user) + { + //Get id's if necessary + $first_article = $first_article instanceof Article ? $first_article->getId() : $first_article; + $second_article = $second_article instanceof Article ? $second_article->getId() : $second_article; + $user = $user instanceof sfGuardUser ? $user->getId() : $user ; + + //We don't want more than one relation between two given articles, so we delete in case it already exist + //even though this should never happen + ArticleArticleRelationPeer::deleteRelation($first_article, $second_article); + + //Create and save a new relation between articles + $relatedarticle = new ArticleArticleRelation(); + $relatedarticle->setFirstarticle($first_article); + $relatedarticle->setSecondarticle($second_article); + $relatedarticle->setCreatedBy($user); + $relatedarticle->save(); + + } +} + diff --git a/lib/model/ArticleArtworkRelation.php b/lib/model/ArticleArtworkRelation.php new file mode 100644 index 0000000..09fe6ef --- /dev/null +++ b/lib/model/ArticleArtworkRelation.php @@ -0,0 +1,12 @@ +add(ArticleAttachmentPeer::ID, $id); + return parent::doSelectOne($c); + } +} diff --git a/lib/model/ArticleCategory.php b/lib/model/ArticleCategory.php new file mode 100644 index 0000000..1c941c7 --- /dev/null +++ b/lib/model/ArticleCategory.php @@ -0,0 +1,12 @@ +add(self::ARTICLE_ID, $article->getId()); + $crit->addjoin(self::CATEGORY_ID, CategorySubreaktorPeer::CATEGORY_ID); + $res = self::doDelete($crit); + } + + /** + * Get all the article objects that are in the specified category + * + * @return array of artciles + */ + public static function getArticlesInCategory($category, $published = true) + { + $resultsArray = array(); + $c = new Criteria(); + + $c->add(CategoryI18nPeer::NAME, $category); + $c->addJoin(CategoryI18nPeer::ID, self::CATEGORY_ID); + $c->addGroupByColumn(self::ARTICLE_ID); + + if ($published) + { + $c->add(ArticlePeer::STATUS, ArticlePeer::PUBLISHED); + } + + $c->addJoin(ArticlePeer::AUTHOR_ID, sfGuardUserPeer::ID, Criteria::LEFT_JOIN); + $c->addJoin(self::ARTICLE_ID, ArticlePeer::ID); + + if (!sfContext::getInstance()->getUser()->hasCredential('viewallcontent')) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + } + + $results = self::doSelectJoinAll($c); + + foreach ($results as $result) + { + $resultsArray[$result->getId()] = $result->getArticle(); + } + return $resultsArray; + } +} diff --git a/lib/model/ArticleFile.php b/lib/model/ArticleFile.php new file mode 100644 index 0000000..30c31d0 --- /dev/null +++ b/lib/model/ArticleFile.php @@ -0,0 +1,55 @@ +getPath(). parent::getFilename())) + { + throw new Exception("Cannot moved the uploaded file"); + } + } + public function getFilename() + { + // Remove the path + $fn = basename(parent::getFilename()); + // Remove the first two underscores + if (substr_count($fn, "_") < 2) + { + return; + } + list($a, $b, $fn) = explode("_", $fn, 3); + $prefix = $a. "_" . $b; + + return $fn; + } + + public function getRealFilename() + { + return parent::getFilename(); + } + + public function getDirectLink() + { + return sfConfig::get("app_upload_attachment_dir", "attachment") . "/" . parent::getFilename(); + } + + public function getFullPath() + { + return $this->getPath() . parent::getFilename(); + } + + public function __toString() + { + return $this->getFilename(); + } + +} + diff --git a/lib/model/ArticleFilePeer.php b/lib/model/ArticleFilePeer.php new file mode 100644 index 0000000..49a0c24 --- /dev/null +++ b/lib/model/ArticleFilePeer.php @@ -0,0 +1,18 @@ +getI18N(); + $article_types = array( + self::HELP_ARTICLE => $i18n->__('Help articles'), + self::THEME_ARTICLE => $i18n->__('Theme articles'), + self::INTERNAL_ARTICLE => $i18n->__('Internal articles'), + self::FOOTER_ARTICLE => $i18n->__('Footer articles'), + self::MY_PAGE_ARTICLE => $i18n->__('My page articles'), + self::REGULAR_ARTICLE => $i18n->__('Regular articles'), + self::SPECIAL_ARTICLE => $i18n->__('Special articles'), + ); + + return $article_types; + } + + public static function getStatusTypes() + { + $i18n = sfContext::getInstance()->getI18N(); + $status_types = array( + self::DRAFT => $i18n->__('Kladd'), + self::PUBLISHED => $i18n->__('Publisert'), + self::ARCHIVED => $i18n->__('Arkivert'), + self::DELETED => $i18n->__('Slettet'), + ); + + return $status_types; + } + + /** + * Returns the article type name of an article type, translated + * + * @param integer $article_type + * + * @return string + */ + public static function getArticleTypeName($article_type) + { + $article_types = self::getArticleTypes(); + return $article_types[$article_type]; + } + + public static function getArticleTypesByPermission($user) + { + $permission_map = array( + self::HELP_ARTICLE => "createhelparticle", + self::THEME_ARTICLE => "createthemearticle", + self::INTERNAL_ARTICLE => "createinternalarticle", + self::FOOTER_ARTICLE => "createfooterarticle", + self::MY_PAGE_ARTICLE => "createmypagearticle", + self::REGULAR_ARTICLE => "createregulararticle", + self::SPECIAL_ARTICLE => "createspecialarticle", + ); + + $types = self::getArticleTypes(); + foreach($types as $type => $text) + { + if (!$user->hasCredential($permission_map[$type])) + { + unset($types[$type]); + } + } + return $types; + } + + /** + * Retrieves all articles of a given type (see constants in ArticlePeer for list of types) + * and date + * + * @param integer $article_type + * @param integer $year + * @param integer $month + * @param boolean $published + * @param integer $num + * @param string $page If set, then then this list if for the frontpage + * @return object theme article + */ + public static function getByFieldAndOrType($article_type, $field, $year = null, $month = null, $status = false, $num = null, $page = null) + { + $crit = new Criteria(); + $crit->setDistinct(); + if ($article_type != self::FOOTER_ARTICLE) + { + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor || + Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + + + { + + if($page == 'frontpage') + { + $crit->add(self::FRONTPAGE, array(self::REAKTOR_FRONTPAGE,0), Criteria::NOT_IN); + } + + if ($article_type != ArticlePeer::INTERNAL_ARTICLE) + { + $crit->addJoin(self::ID, ArticleSubreaktorPeer::ARTICLE_ID); + } + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $crit->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, array(Subreaktor::getProvidedSubreaktor()->getId(), Subreaktor::getProvidedSubreaktor()->getId()), Criteria::IN); + } + else + { + $crit->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, Subreaktor::getProvidedSubreaktor()->getId()); + } + } + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $crit->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, Subreaktor::getProvidedLokalreaktor()->getId()); + } + } + + else { + if($page == 'frontpage') + { + $crit->add(self::FRONTPAGE, array(self::SUBREAKTOR_FRONTPAGE,0), Criteria::NOT_IN); + } + + + + } + + + + } + + + + + + if ($field == 'date') + { + if ($year !== null && $month !== null) + { + $startdate = mktime(null, null, null, $month, 1, $year); + $enddate = mktime(null, null, null, $month, date('t', mktime(null, null, null, $month, 1, $year)), $year); + + $ctn = $crit->getNewCriterion(self::CREATED_AT, $startdate, Criteria::GREATER_EQUAL); + $ctn2 = $crit->getNewCriterion(self::CREATED_AT, $enddate, Criteria::LESS_EQUAL); + + $ctn->addAnd($ctn2); + $crit->add($ctn); + } + } + + $crit->add(self::ARTICLE_TYPE, $article_type, Criteria::IN); + self::resolveAndAddStatus($status, $crit); + + if ($num) + { + $crit->setLimit($num); + } + + //Order by article_order then date + if ( $article_type == self::FOOTER_ARTICLE || + $article_type == self::INTERNAL_ARTICLE || + $article_type == self::REGULAR_ARTICLE || + $article_type == self::MY_PAGE_ARTICLE || + $article_type == self::SPECIAL_ARTICLE) + { + $crit->addAscendingOrderByColumn( self::ARTICLE_ORDER); + $crit->addDescendingOrderByColumn(self::CREATED_AT); //If no order, use creation date + if (in_array($article_type, self::getTranslatableTypes())) + { + $res = self::doSelectWithI18n($crit); + } + else + { + $res = self::doSelect($crit); + } + } + else if ( $field == 'date' ) //only order by date + { + $crit->addDescendingOrderByColumn(self::CREATED_AT); + $res = self::doSelectWithI18n($crit); + } + else //order by title + { + $crit->addAscendingOrderByColumn(ArticleI18nPeer::TITLE); + $res = self::doSelectWithI18n($crit); + } + return $res; + } + + /** + * Return a ordered list of all articles within an article type. Useful for + * sorting lists. + * + * @param integer $article_type + * @return array Article objects + */ + public static function getAllByOrder($article_type = ArticlePeer::REGULAR_ARTICLE) + { + $c = new Criteria(); + + $c->add(self::ARTICLE_TYPE, $article_type, Criteria::EQUAL); + $c->add(self::STATUS, ArticlePeer::DELETED, Criteria::NOT_EQUAL); + + $c->addAscendingOrderByColumn(self::ARTICLE_ORDER); + $c->addDescendingOrderByColumn(self::CREATED_AT); + + return self::doSelect($c); + + } + + public static function resolveAndAddStatus($status, Criteria $crit) + { + if ($status) + { + if (!is_numeric($status)) + { + switch(strtolower($status)) + { + case "draft": + $status = ArticlePeer::DRAFT; + break; + case "published": + $status = ArticlePeer::PUBLISHED; + break; + case "archived": + $status = ArticlePeer::ARCHIVED; + break; + case "all": + // All + default: + $status = 0; + } + } + } + if ($status) + { + $crit->add(self::STATUS, sfContext::getInstance()->getUser()->hasCredential('staff') ? $status : ArticlePeer::PUBLISHED); + } + elseif(!sfContext::getInstance()->getUser()->hasCredential('staff')) + { + $crit->add(self::STATUS, ArticlePeer::PUBLISHED); + } + + } + + + /** + * Retrieves an article by its permalink + * + * @param string $permalink + * + * @return Article + */ + public static function retrieveByPermalink($permalink, $draft = false) + { + $c = new Criteria(); + $c->add(self::PERMALINK, $permalink); + if (!$draft) + { + $c->add(self::STATUS, ArticlePeer::PUBLISHED); + } + return self::doSelectOne($c); + } + + /** + * Retrieve the latest article of a particular type + * + * @param $type The type ID or string + * @param $published Only return published articles + * + * @return article An article object + */ + public static function retrieveLatestByType($type, $published = true) + { + if (is_integer($type)) + { + $typeId = $type; + } + else + { + $type = strtoupper($type); + if (defined("ArticlePeer::{$type}_ARTICLE")) + { + $typeId = constant("ArticlePeer::{$type}_ARTICLE"); + } + else + { + throw new Exception("Article type does not exist"); + } + } + + $c = new Criteria(); + $c->add(self::ARTICLE_TYPE, $typeId); + + if ($published) + { + $c->add(self::STATUS, self::PUBLISHED); + } + + $c->addDescendingOrderByColumn(self::PUBLISHED_AT); + + return self::doSelectOne($c); + } + + public static function getThemeArticle($page) + { + $crit = new Criteria(); + $crit->add(self::ARTICLE_TYPE, self::THEME_ARTICLE); + $crit->add(self::EXPIRES_AT, time(), Criteria::GREATER_EQUAL); + $crit->add(self::STATUS, ArticlePeer::PUBLISHED); + + + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor || + Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + + if($page == 'frontpage') + { + $crit->add(self::FRONTPAGE, array(self::REAKTOR_FRONTPAGE,0), Criteria::NOT_IN); + } + + $crit->addJoin(self::ID, ArticleSubreaktorPeer::ARTICLE_ID); + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $crit->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, array(Subreaktor::getProvidedSubreaktor()->getId(), Subreaktor::getProvidedSubreaktor()->getId()), Criteria::IN); + } + else + { + $crit->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, Subreaktor::getProvidedSubreaktor()->getId()); + } + } + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $crit->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, Subreaktor::getProvidedLokalreaktor()->getId()); + } + } else { + if($page == 'frontpage') + { + $crit->add(self::FRONTPAGE, array(self::SUBREAKTOR_FRONTPAGE,0), Criteria::NOT_IN); + } + + } + $crit->addDescendingOrderByColumn(self::PUBLISHED_AT); + $crit->setLimit(5); + return self::doSelectJoinAll($crit); + } + + /** + * Enter description here... + * + * @param unknown_type $type + * @return unknown + */ + public static function retrieveAllSortedByTypeYearAndMonth($type = null, $status = 0) + { + /*SELECT YEAR(`created_at`) AS year, MONTH(`created_at`) AS month, `article_type`, `permalink` FROM `article` ORDER BY article_type, year, month */ + $c = new Criteria; + $c->clearSelectColumns(); + $c->addSelectColumn('YEAR(' .self::CREATED_AT. ') AS year'); # 0 + $c->addSelectColumn('MONTH(' .self::CREATED_AT. ') AS month'); # 1 + + $c->addSelectColumn(self::ARTICLE_TYPE); # 2 + $c->addSelectColumn(self::ID); # 3 + $c->addSelectColumn(ArticlePeer::BASE_TITLE); # 4 + $c->addSelectColumn(self::PERMALINK); # 5 + $c->addSelectColumn(ArticleI18nPeer::TITLE); # 6 + + $c->addJoin(self::ID, ArticleI18nPeer::ID.' AND '.ArticleI18nPeer::CULTURE." = '".sfContext::getInstance()->getUser()->getCulture()."'", Criteria::LEFT_JOIN); + + if ($type) + { + $c->add(self::ARTICLE_TYPE, $type, Criteria::IN); + } + self::resolveAndAddStatus($status, $c); + + $c->addDescendingOrderByColumn(self::ARTICLE_TYPE); + $c->addDescendingOrderByColumn('year'); + $c->addDescendingOrderByColumn('month'); + + $retval = array_fill(0, 10, array()); + foreach(parent::doSelectRs($c) as $row) + { + $a = new Article(); + $a->setCustom($row); + $retval[$row[2]][$row[0]][$row[1]][] = $a; + } + return $retval; + } + + /** + * Returns the YML settings for how many articles should be shown in the list + * of articles for that specific type + * + * @param int $type Article type + * @return int Max char count + */ + public static function getShowCountFor($type) + { + $fallback_count = 5; + switch($type) { + case self::HELP_ARTICLE: + return sfConfig::get('app_articles_help_max_count', $fallback_count); + + case self::INTERNAL_ARTICLE: + return sfConfig::get('app_articles_internal_max_count', $fallback_count); + + case self::FOOTER_ARTICLE: + return sfConfig::get('app_articles_footer_max_count', $fallback_count); + + case self::MY_PAGE_ARTICLE: + return sfConfig::get('app_articles_my_page_max_count', $fallback_count); + + case self::REGULAR_ARTICLE: + return sfConfig::get('app_articles_regular_max_count', $fallback_count); + } + return $fallback_count; + } + + /** + * Retrieves help articles in the same category as $artwork_id + * + * @param int $artwork_id The artwork ID + * @return array Articles + */ + public static function getByCategoryFromArtworkID($artwork_id) + { + $c = new Criteria; + $c->setDistinct(); + $c->addJoin(ArticleCategoryPeer::ARTICLE_ID, ArticlePeer::ID); + $c->addJoin(CategoryArtworkPeer::CATEGORY_ID, ArticleCategoryPeer::CATEGORY_ID); + $c->add(CategoryArtworkPeer::ARTWORK_ID, $artwork_id); + $c->add(ArticlePeer::ARTICLE_TYPE, ArticlePeer::HELP_ARTICLE); + return parent::doSelect($c); + } + + /** + * Sanitizes the permanent link + * + * @param string $title + * @return string + */ + public static function sanitizePermlink($title) + { + $permalink = strtr($title, array("ø" => "oe", "å" => "aa", "æ" => "ae", "Ø" => "OE", "Å" => "AA", "Æ" => "AE")); + $permalink = preg_replace('/[^a-zA-Z0-9\-]/i', '_' , $permalink); + return $permalink; + } + + public static function setArticleOrder($order, $article) + { + if ($article instanceof Article) + { + $article = $article->getId(); + } + + $c = new Criteria(); + $c->add(self::ID, $article); + $res = self::doSelectOne($c); + + if ($res) + { + $res->setArticleOrder($order); + $res->save(); + } + } + + /** + * Count articles of the same type. + * + * @param integer $article_type + * @return integer The number of article of type $article_type + */ + public static function articleCount($article_type) + { + $c = new Criteria(); + $c->add(parent::ARTICLE_TYPE, $article_type, Criteria::EQUAL); + return parent::doCount($c); + } + +} + diff --git a/lib/model/ArticleSubreaktor.php b/lib/model/ArticleSubreaktor.php new file mode 100644 index 0000000..3315e7d --- /dev/null +++ b/lib/model/ArticleSubreaktor.php @@ -0,0 +1,12 @@ +add(ArticlePeer::ARTICLE_TYPE, ArticlePeer::HELP_ARTICLE, Criteria::EQUAL); + $c->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, Subreaktor::getByReference($subreaktor)->getId()); + ArticlePeer::resolveAndAddStatus($status, $c); + $c->addDescendingOrderByColumn(ArticlePeer::BASE_TITLE); + $c->setDistinct(); + + $article_subreaktors = ArticleSubreaktorPeer::doSelectJoinAll($c); + + $result = array(); + foreach ($article_subreaktors as $article_subreaktor) + { + $result[] = $article_subreaktor->getArticle(); + } + return $result; + } +} diff --git a/lib/model/ArtworkStatus.php b/lib/model/ArtworkStatus.php new file mode 100644 index 0000000..a01ed8d --- /dev/null +++ b/lib/model/ArtworkStatus.php @@ -0,0 +1,23 @@ +setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + + public function __toString() + { + return $this->getDescription(); + } +} diff --git a/lib/model/ArtworkStatusI18n.php b/lib/model/ArtworkStatusI18n.php new file mode 100644 index 0000000..f0dfa1e --- /dev/null +++ b/lib/model/ArtworkStatusI18n.php @@ -0,0 +1,12 @@ +getDescription(); + } + +} diff --git a/lib/model/CataloguePeer.php b/lib/model/CataloguePeer.php new file mode 100644 index 0000000..bf11d07 --- /dev/null +++ b/lib/model/CataloguePeer.php @@ -0,0 +1,42 @@ +getTargetLang()] = $result->getDescription(); + } + return $resultArray; + } + else + { + return $results; + } + } + + public static function getSelectArr() + { + $tmp = array(); + $cat = self::getCatalogues(); + foreach ($cat as $acat) + { + $tmp[$acat->getTargetLang()] = $acat->getDescription(); + } + return $tmp; + } +} diff --git a/lib/model/Category.php b/lib/model/Category.php new file mode 100644 index 0000000..ade802b --- /dev/null +++ b/lib/model/Category.php @@ -0,0 +1,27 @@ +add(CategoryPeer::BASENAME,$baseName); + return CategoryPeer::doSelectOne($c); + } + + public static function getByBasenameLike($baseName) + { + $c = new Criteria(); + $c->add(CategoryPeer::BASENAME,$baseName.'%',Criteria::LIKE); + return CategoryPeer::doSelect($c); + } + +} diff --git a/lib/model/CategoryArtwork.php b/lib/model/CategoryArtwork.php new file mode 100644 index 0000000..55a6233 --- /dev/null +++ b/lib/model/CategoryArtwork.php @@ -0,0 +1,22 @@ +add(CategoryArtworkPeer::CATEGORY_ID,$id); + return CategoryArtworkPeer::doSelect($c); + } +} diff --git a/lib/model/CategoryArtworkPeer.php b/lib/model/CategoryArtworkPeer.php new file mode 100644 index 0000000..150d61b --- /dev/null +++ b/lib/model/CategoryArtworkPeer.php @@ -0,0 +1,217 @@ +add(CategoryI18nPeer::NAME, $category); + $c->addJoin(CategoryI18nPeer::ID, CategoryArtworkPeer::CATEGORY_ID); + $c->addGroupByColumn(CategoryArtworkPeer::ARTWORK_ID); + if ($approved) + { + $c->add(ReaktorArtworkPeer::STATUS, 3); + } + + if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor || + Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor || + isset($options['subreaktor']) || + isset($options['lokalreaktor'])) + { + $c->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID, Criteria::LEFT_JOIN); + } + + if (isset($options['subreaktor'])) + { + $c->addJoin(ReaktorArtworkPeer::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $options['subreaktor']->getId()); + } + elseif (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + $c->addJoin(ReaktorArtworkPeer::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedSubreaktor()->getId()); + } + + if (isset($options['lokalreaktor'])) + { + $c->addJoin(ReaktorArtworkPeer::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $options['lokalreaktor']->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $options['lokalreaktor']->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + elseif (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $c->addJoin(ReaktorArtworkPeer::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedLokalreaktor()->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, Subreaktor::getProvidedLokalreaktor()->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + + $c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID, Criteria::LEFT_JOIN); + if (!sfContext::getInstance()->getUser()->hasCredential('viewallcontent')) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + } + + foreach (CategoryArtworkPeer::doSelectJoinReaktorArtwork($c) as $resultObject) + { + $resultsArray[] = new genericArtwork($resultObject->getReaktorArtwork(), null, array()); + } + + return $resultsArray; + } + + /** + * Return all the categories an artwork is attached to + * + * @param genericArtwork|integer $artwork object or id + * + * @return array of categories with id as key and the name (using i18n) + */ + public static function getCategoriesFromArtwork($artwork) + { + if ($artwork instanceof genericArtwork ) + { + $artwork = $artwork->getId(); + } + + $categories = array(); + + $c = new Criteria(); + $c->add(CategoryArtworkPeer::ARTWORK_ID, $artwork); + $c->addJoin(CategoryPeer::ID, CategoryArtworkPeer::CATEGORY_ID); + + $categoryObjects = CategoryPeer::doSelectWithI18n($c); + + foreach ($categoryObjects as $categoryObject) + { + $categories[$categoryObject->getId()] = $categoryObject->getName(); + } + return $categories; + + } + + /** + * Add a new artwork/category relationship + * + * @param genericArtwork|integer $artwork The artwork object or ID + * @param integer $category The category ID + * @param sfGuardUser|integer $user User object or ID + * + * @return void updates the DB + */ + public static function addArtworkCategory($artwork, $categoryId, $user) + { + if ($artwork instanceof genericArtwork ) + { + $artwork = $artwork->getId(); + } + if ($user instanceof myUser ) + { + $user = $user->getGuardUser()->getId(); + } + elseif ($user instanceof sfGuardUser ) + { + $user = $user->getId(); + } + + // Lets check it doesn't already exist + $c = new Criteria(); + $c->add(self::CATEGORY_ID, $categoryId); + $c->add(self::ARTWORK_ID, $artwork); + + $thisCAP = self::doSelectOne($c); + + if (!$thisCAP) + { + $newCAP = new CategoryArtwork(); + $newCAP->setCategoryId($categoryId); + $newCAP->setArtworkId($artwork); + $newCAP->setAddedBy($user); + $newCAP->save(); + } + } + + /** + * Remove a category/artwork link + * + * @param genericArtwork|integer $artwork The artwork object or ID + * @param integer $category The category ID + * + * @return void + */ + public static function removeArtworkCategory($artwork, $categoryId) + { + if ($artwork instanceof genericArtwork ) + { + $artwork = $artwork->getId(); + } + + $c = new Criteria(); + $c->add(self::CATEGORY_ID, $categoryId); + $c->add(self::ARTWORK_ID, $artwork); + + $thisCAP = self::doSelectOne($c); + if ($thisCAP) + { + $thisCAP->delete(); + return true; + } + else + { + return false; + } + } + + /** + * Removes all categories from the artwork which are linked to a subreaktor + * + * @param genericArtwork|integer $artwork The artwork object or ID + * @param subreaktor|integer $subreaktor The subreaktor object or ID + * + * @return void + */ + public static function removeAllInSubreaktor($artwork, $subreaktor) + { + if ($artwork instanceof genericArtwork ) + { + $artwork = $artwork->getId(); + } + if ($subreaktor instanceof Subreaktor ) + { + $subreaktor = $subreaktor->getId(); + } + + $c = new criteria(); + $c->add(self::ARTWORK_ID, $artwork); + $c->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $subreaktor); + $c->addjoin(self::CATEGORY_ID, CategorySubreaktorPeer::CATEGORY_ID); + + $rowsToDelete = self::doSelect($c); + foreach ($rowsToDelete as $row) + { + $row->delete(); + } + } +} diff --git a/lib/model/CategoryI18n.php b/lib/model/CategoryI18n.php new file mode 100644 index 0000000..711cd89 --- /dev/null +++ b/lib/model/CategoryI18n.php @@ -0,0 +1,12 @@ +setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + + static public function getAll() + { + $crit = new Criteria(); + $crit->addAscendingOrderByColumn(CategoryI18nPeer::NAME); + return self::doSelectWithI18n($crit); + } + + static public function getAllAsIndexedArray() + { + $categories = self::getAll(); + $arr = array(); + foreach ($categories as $category) + { + $arr[$category->getId()] = $category->getName(); + } + return $arr; + } + +} diff --git a/lib/model/CategorySubreaktor.php b/lib/model/CategorySubreaktor.php new file mode 100644 index 0000000..8c7b2c0 --- /dev/null +++ b/lib/model/CategorySubreaktor.php @@ -0,0 +1,12 @@ +getId(); + } + elseif (is_array($subreaktor)) + { + foreach($subreaktor as $thisItem) + { + if ($thisItem instanceof Subreaktor ) + { + $subreaktors[] = $thisItem->getId(); + } + else + { + $subreaktors[] = $thisItem; + } + } + } + + $categoryArray = array(); + $c = new Criteria(); + + if ($exclude) //Exclude categories used by subreaktor(s) + { + $d = new criteria(); + if($subreaktor) //exclude categories used by a given subreaktor + { + $d->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $subreaktors, Criteria::IN); + } + else //exlude categories used by any of the subreaktors + { + $d->setDistinct(); + } + $excludeResults = CategorySubreaktorPeer::doSelect($d); + $excludeArray = array(); + foreach ($excludeResults as $excludeResult) + { + $excludeArray[] = $excludeResult->getCategoryId(); + } + $c->add(CategoryPeer::ID, $excludeArray, Criteria::NOT_IN); + } + else //Get categories that belong to subReaktor + { + if ($byReference) + { + $c->add(SubreaktorPeer::REFERENCE, $subreaktors, Criteria::IN); + $c->addJoin(SubreaktorPeer::ID, CategorySubreaktorPeer::SUBREAKTOR_ID); + } + else + { + $c->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $subreaktors, Criteria::IN); + } + } + + if (!$exclude) + { + $c->addJoin(CategoryPeer::ID, CategorySubreaktorPeer::CATEGORY_ID); + } + + $c->addAscendingOrderByColumn(CategoryI18nPeer::NAME); + + $categories = CategoryPeer::doSelectWithI18n($c); + + foreach ($categories as $category) //Arrange result into an array to be used in drop-down + { + $categoryArray[$category->getId()] = $category->getName(); + } + + return $categoryArray; + } +} diff --git a/lib/model/Favourite.php b/lib/model/Favourite.php new file mode 100644 index 0000000..32c1516 --- /dev/null +++ b/lib/model/Favourite.php @@ -0,0 +1,319 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @package lib.model + */ + + +class Favourite extends BaseFavourite +{ + /** + * Searching for my favourites or my friend favourites + * + * @var mixed + * @access public + */ + static $myfavs = false; + + /** + * Searching for friends or artworks + * + * @var string + * @access public + */ + static $type = ""; + + + function getLastFavs($type,$artwork_or_user,$limit=null) + { + self::$myfavs = false; + self::$type = $type; + + $c = new Criteria(); + //$c->addJoin(FavouritePeer::USER_ID,sfGuardUserPeer::ID); + $c->add(FavouritePeer::FAV_TYPE,$type); + if ($type == "artwork") + { + $type_const = FavouritePeer::ARTWORK_ID; + } + elseif($type == "user") + { + $type_const = FavouritePeer::FRIEND_ID; + } + elseif($type == "article") + { + $type_const = FavouritePeer::ARTICLE_ID; + } + $c->add($type_const,$artwork_or_user); + $c->addDescendingOrderByColumn(FavouritePeer::ID); + if ($limit) + $c->setLimit($limit); + switch ($type) + { + case 'artwork': + //$c->addJoin(FavouritePeer::ARTWORK_ID,ReaktorArtworkPeer::ID); + $c->add(ReaktorArtworkPeer::STATUS, 3); + return FavouritePeer::doSelectJoinReaktorArtwork($c); + break; + case 'user': + return FavouritePeer::doSelectJoinsfGuardUserRelatedByUserId($c); + break; + case 'article': + $c->add(ArticlePeer::STATUS, ArticlePeer::PUBLISHED); + return FavouritePeer::doSelectJoinArticle($c); + default: + break; + } + return FavouritePeer::doSelect($c); + } + + /** + * List of latest artworks or user + * + * @param string $type + * @param int $artwork_or_user + * @param int $limit + * @return array Favourite + */ + function getMyLastFavs($type,$artwork_or_user,$limit=null) + { + self::$myfavs = true; + self::$type = $type; + + $c = new Criteria(); + //$c->addJoin(FavouritePeer::USER_ID,sfGuardUserPeer::ID); + $c->add(FavouritePeer::FAV_TYPE,$type); + $c->add(FavouritePeer::USER_ID,$artwork_or_user); + $c->addDescendingOrderByColumn(FavouritePeer::ID); + if ($limit) + { + $c->setLimit($limit); + } + switch ($type) + { + case 'artwork': + //$c->addJoin(FavouritePeer::ARTWORK_ID,ReaktorArtworkPeer::ID); + $c->add(ReaktorArtworkPeer::STATUS, 3); + return FavouritePeer::doSelectJoinReaktorArtwork($c); + break; + case 'user': + return FavouritePeer::doSelectJoinsfGuardUserRelatedByFriendId($c); + //$c->addJoin(FavouritePeer::FRIEND_ID,SfGuardUserPeer::ID); + break; + case 'article': + $c->add(ArticlePeer::STATUS, ArticlePeer::PUBLISHED); + return FavouritePeer::doSelectJoinArticle($c); + default: + break; + } + return FavouritePeer::doSelect($c); + } + + + function getIsFavourite($user_id,$artwork_or_userid,$fav_type) + { + if ($fav_type == "artwork") + { + $type_const = FavouritePeer::ARTWORK_ID; + } + elseif($fav_type == "user") + { + $type_const = FavouritePeer::FRIEND_ID; + } + elseif($fav_type == "article") + { + $type_const = FavouritePeer::ARTICLE_ID; + } + + $c = new Criteria(); + $c->add($type_const,$artwork_or_userid); + $c->add(FavouritePeer::USER_ID,$user_id); + $c->add(FavouritePeer::FAV_TYPE,$fav_type); + return count(FavouritePeer::doSelect($c)); + + } + + static function deleteFavourite($artwork_or_user_id,$type,$userId) + { + if ($type == "artwork") + { + $type_const = FavouritePeer::ARTWORK_ID; + } + elseif($type == "user") + { + $type_const = FavouritePeer::FRIEND_ID; + } + elseif($type == "article") + { + $type_const = FavouritePeer::ARTICLE_ID; + } + + $c = new Criteria(); + $c->add(FavouritePeer::USER_ID,$userId); + $c->add($type_const,$artwork_or_user_id); + $c->add(FavouritePeer::FAV_TYPE,$type); + $fav_obj = FavouritePeer::doSelectOne($c); + if ($fav_obj) + { + $fav_obj->delete(); + } + } + + static function addFavourite($artwork_or_user_id,$type,$userId) + { + $fav_obj = new Favourite(); + $fav_obj->setUserId($userId); + $c = new Criteria(); + $c->add(FavouritePeer::USER_ID,$userId); + if ($type == "artwork") + { + $c->add(FavouritePeer::ARTWORK_ID,$artwork_or_user_id); + $fav_obj->setArtworkId($artwork_or_user_id); + } + elseif ($type == "user") + { + $c->add(FavouritePeer::FRIEND_ID,$artwork_or_user_id); + $fav_obj->setFriendId($artwork_or_user_id); + } + elseif ($type == "article") + { + $c->add(FavouritePeer::ARTICLE_ID,$artwork_or_user_id); + $fav_obj->setArticleId($artwork_or_user_id); + } + $c->add(FavouritePeer::FAV_TYPE,$type); + $fav_obj->setFavType($type); + if (!FavouritePeer::doSelectOne($c)) + { + $fav_obj->save(); + } + + //Update logged in user's last active flag + sfContext::getInstance()->getUser()->getGuardUser()->setLastActive(date('Y-m-d H:i:s')); + sfContext::getInstance()->getUser()->getGuardUser()->save(); + + } + /** + * Required by the Feed plugin to generate routes automatically + * + * @return string The culture in question, "no" if none specified + */ + public function getFeedsfCulture() + { + return sfContext::getInstance()->getRequest()->getParameter('sf_culture', 'no'); + } + + public function getCustomFeedTitle() + { + return $this->getFeedTitle(); + } + + /** + * Required by the Feed plugin to generate routes automatically + * Returns the favourite artwork title/username + * + * @return string the title for the feed element + */ + public function getFeedTitle() + { + switch($this->getFavType()) + { + case "user": + return $this->getFeedUser(); + case "artwork": + return $this->getReaktorArtwork()->getTitle(); + case "article": + return $this->getArticle()->getTitle(); + } + } + + public function getFeedPermalink() + { + switch ($this->getFavType()) + { + case 'article': + return $this->getArticle()->getLink(); + } + } + public function getArtworkLink() { + return sprintf('@show_artwork?id=%d&title=%s', $this->getReaktorArtwork()->getId(), $this->getReaktorArtwork()->getTitle()); + } + + /** + * Returns instance of the user object in question + * + * @return sfGuardUser + */ + public function getUserObject() + { + switch(self::$myfavs) { + case 0: + return $this->getSfGuardUserRelatedByUserId(); + case 1: + return $this->getSfGuardUserRelatedByFriendId(); + } + } + + /** + * Required by the Feed plugin to generate routes automatically + * + * @return string the username of the friend + */ + public function getFeedUser() + { + if (self::$type != "user") + { + return null; + } + + return $this->getUserObject()->getUsername(); + } + + /** + * Get the provided subreaktor for Feed generator + * + * @return subreaktor|null + */ + public function getFeedSubreaktor() + { + if (subreaktor::isValid()) + { + return Subreaktor::getProvided(); + } + } + + public function getFeedUniqueId() + { + return sfContext::getInstance()->getController()->genUrl("@portfolio?user={$this->getFeedUser()}", true); + } + public function getFeedDescription() + { + if (self::$type == 'article') + { + return $this->getArticle()->getTitle(); + } + elseif (self::$type != "user") + { + return $this->getReaktorArtwork()->getDescription(); + } + + $user = $this->getUserObject(); + $desc = $user->getDescription(); + + // If we have description, then return it + if (trim($desc)) + { + return $desc; + } + // Otherwise say "member since.." to make sure the feed is valid + return "Member since: " . $user->getCreatedAt(); + + } +} + diff --git a/lib/model/FavouritePeer.php b/lib/model/FavouritePeer.php new file mode 100644 index 0000000..3eca96e --- /dev/null +++ b/lib/model/FavouritePeer.php @@ -0,0 +1,12 @@ +add(FileMimetypePeer::MIMETYPE, $type); + return parent::doSelectOne($c); + } +} + diff --git a/lib/model/History.php b/lib/model/History.php new file mode 100644 index 0000000..022a3b2 --- /dev/null +++ b/lib/model/History.php @@ -0,0 +1,13 @@ +setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + +} diff --git a/lib/model/HistoryActionI18n.php b/lib/model/HistoryActionI18n.php new file mode 100644 index 0000000..085dd64 --- /dev/null +++ b/lib/model/HistoryActionI18n.php @@ -0,0 +1,12 @@ +add(self::ACTION_ID, $action_id); + $c->add(self::OBJECT_ID, $object->getId()); + $c->addDescendingOrderByColumn(self::CREATED_AT); + + $c->setLimit(1); + $history_array = parent::doSelectJoinAll($c); + if($history_array) + { + return $history_array[0]; + } + else + { + return $history_array; + } + } + + /** + * Get the number of times an object has been reported + * + * @param object $obj + * + * @return integer + */ + public static function countTimesReported($obj) + { + $c = new Criteria(); + $c->add(self::ACTION_ID,1); //File reported + $c->add(self::OBJECT_ID, $obj->getId()); + $hist = self::doSelect($c); + + return count($hist); + } + + /** + * Get the history objects related to a particular object and action + * + * @param object $object The object + * @param integer $actionId The action id (optional) + * @param integer $limit Limit number of results (optional) + */ + public static function getByObjectAndAction($object, $actionId = 0, $limit = 0) + { + $c = new Criteria(); + $c->add(self::OBJECT_ID, $object->getId()); + $c->add(self::EXTRA_DETAILS, $object->getTableName()); + $c->addDescendingOrderByColumn(self::CREATED_AT); + + if ($actionId) + { + $c->add(self::ACTION_ID, $actionId); + } + + if ($limit) + { + $c->setLimit($limit); + } + + return self::doSelectJoinAll($c); + } + + /** + * Logs an action of any type using action id from history_action table. + * Example: $action was done to $object in table $extra_details by $user. + * + * @param int $action Id in history action table + * @param int|sfGuardUser $user Id in sf_guard_user table or user object + * @param object $object The object if we are actioning one + * @param string $extraDetails Useful extra info, automatically set when object provided + * + * @return void + */ + public static function logAction($action, $user, $object = null, $extraDetails = NULL) + { + if ($user instanceof sfGuardUser) + { + $user = $user->getId(); + } + $history_row = new History(); + + if (is_object($object)) + { + $history_row->setObjectId($object->getId()); + $extraDetails = method_exists($object, "getTableName") ? $object->getTableName() : stringMagick::camelCaseToUnderscores(get_class($object)); + } + + $history_row->setActionId($action); + $history_row->setUserId($user); + + $history_row->setExtraDetails($extraDetails); + $history_row->save(); + + } +} diff --git a/lib/model/LokalreaktorArtwork.php b/lib/model/LokalreaktorArtwork.php new file mode 100644 index 0000000..62b07e1 --- /dev/null +++ b/lib/model/LokalreaktorArtwork.php @@ -0,0 +1,12 @@ +add(parent::ARTWORK_ID, $id); + + return parent::doSelectJoinAllExceptReaktorArtwork($c); + } + +} diff --git a/lib/model/LokalreaktorResidence.php b/lib/model/LokalreaktorResidence.php new file mode 100644 index 0000000..8dfa3f7 --- /dev/null +++ b/lib/model/LokalreaktorResidence.php @@ -0,0 +1,12 @@ +add(parent::SUBREAKTOR_ID, $subreaktor->getPrimaryKey()); + return parent::doSelectJoinResidence($c); + } + + public static function getSubreaktorsByResidence($ResidenceId) + { + +if(is_numeric($ResidenceId)){ + $c = new Criteria(); + $c->add(parent::RESIDENCE_ID, $ResidenceId); + return parent::doSelectJoinResidence($c); + } + + } + + +} diff --git a/lib/model/Messages.php b/lib/model/Messages.php new file mode 100644 index 0000000..9f380c5 --- /dev/null +++ b/lib/model/Messages.php @@ -0,0 +1,73 @@ +getUser()->getGuardUser(); + $c = new Criteria(); + $c->add(MessagesIgnoredUserPeer::IGNORES_USER_ID,$this->getFromUserId()); + $c->add(MessagesIgnoredUserPeer::USER_ID,$user->getId()); + return MessagesIgnoredUserPeer::doCount($c); + + } + + /** + * Retrieves the message length (bytes) + * + * @return int + */ + public function getMessageLength() + { + return strlen($this->getMessage()); + } + + /** + * Return the message up to $maxlen bytes + * + * @param int $maxlen The maximum length of the message to return + * @param bool &$cropped Set to true when message was cropped + * @return string The message + */ + public function getPartialMessage($maxlen = 0, &$cropped = false) + { + $len = $this->getMessageLength(); + if ($maxlen && $len > $maxlen) + { + $cropped = true; + return substr($this->getMessage(), 0, $maxlen); + } + return $this->getMessage(); + } + + public function markAsDeletedByFrom() + { + parent::setDeletedByFrom($this->getFromUserId()); + } + + public function markAsDeletedByTo() + { + parent::setDeletedByTo($this->getToUserId()); + } + + public function getIsDeleted($user_id) + { + return $this->getDeletedByTo() == $user_id || $this->getDeletedByFrom() == $user_id; + } + +} + diff --git a/lib/model/MessagesIgnoredUser.php b/lib/model/MessagesIgnoredUser.php new file mode 100644 index 0000000..684b275 --- /dev/null +++ b/lib/model/MessagesIgnoredUser.php @@ -0,0 +1,13 @@ +setToUserId($to_id); + $message->setFromUserId($from_id); + $message->setSubject($subject); + $message->setMessage($body); + $message->setTimestamp(time()); + $message->setReplyTo($reply); + + // check if the recipient has blocked the sender - if so, + // just set the ignored flag on the message + $c = new Criteria(); + $c->add(MessagesIgnoredUserPeer::IGNORES_USER_ID, $from_id); + $c->add(MessagesIgnoredUserPeer::USER_ID, $to_id); + $res = MessagesIgnoredUserPeer::doCount($c); + if ($res > 0) + { + $message->setIsIgnored(true); + } + $message->save(); + } + + public static function getMessagesByAge($time,$to_id=null,$from_id=null) + { + $c = new Criteria(); + $c->add(MessagesPeer::TIMESTAMP,time()-$time,Criteria::GREATER_THAN); + return self::doSelect($c); + + } + + public static function getAllMessages($user_id) + { + $c = new Criteria(); + $crit0 = $c->getNewCriterion(MessagesPeer::TO_USER_ID, $user_id); + + $crit2 = $c->getNewCriterion(MessagesPeer::DELETED_BY_FROM, $user_id, Criteria::ALT_NOT_EQUAL); + $crit3 = $c->getNewCriterion(MessagesPeer::DELETED_BY_TO, $user_id, Criteria::ALT_NOT_EQUAL); + + $crit0->addAnd($crit2); + $crit0->addAnd($crit3); + + $c->add($crit0); + + // Ignore "ignored" messages + $c->add(self::IS_IGNORED, 0); + + $c->addDescendingOrderByColumn(MessagesPeer::TIMESTAMP); + return self::doSelectJoinsfGuardUserRelatedByFromUserId($c); + } + + public static function markAsRead($message_id) + { + $msg = self::retrieveByPK($message_id); + $msg->setIsRead(1); + $msg->save(); + } + + /* + public static function markAsDeleted($message_id) + { + $msg = self::retrieveByPK($message_id); + //$msg->setIsDeleted(1); + $msg->save(); + } + */ + + /* + public static function markAsRestored($message_id) + { + $msg = self::retrieveByPK($message_id); + //$msg->setIsDeleted(0); + $msg->save(); + } + */ + + public static function getMessagesPaginated($user_id) + { + $c = new Criteria(); + $crit0 = $c->getNewCriterion(MessagesPeer::TO_USER_ID, $user_id); + $crit1 = $c->getNewCriterion(MessagesPeer::FROM_USER_ID, $user_id); + + // Perform OR at level 1 ($crit0 $crit1 ) + $crit0->addOr($crit1); + $crit2 = $c->getNewCriterion(MessagesPeer::DELETED_BY_FROM, $user_id, Criteria::ALT_NOT_EQUAL); + $crit3 = $c->getNewCriterion(MessagesPeer::DELETED_BY_TO, $user_id, Criteria::ALT_NOT_EQUAL); + + // Perform AND at level 0 ($crit0 $crit2 $crit3 ) + $crit0->addAnd($crit2); + $crit0->addAnd($crit3); + + $c->add($crit0); + + $c->addDescendingOrderByColumn(MessagesPeer::TIMESTAMP); + $pager = new sfPropelPager('Messages', 10); + $pager->setCriteria($c); + return $pager; + + } + + + public static function getMySentMessages($user_id) + { + $c = new Criteria(); + $c->add(MessagesPeer::FROM_USER_ID, $user_id); + $c->addDescendingOrderByColumn(MessagesPeer::TIMESTAMP); + return MessagesPeer::doSelect($c); + + } + +} diff --git a/lib/model/ReaktorArtwork.php b/lib/model/ReaktorArtwork.php new file mode 100644 index 0000000..d161d61 --- /dev/null +++ b/lib/model/ReaktorArtwork.php @@ -0,0 +1,200 @@ +getId().$param_key; + if ($mode != 'xml') + { + if ($file_id) $linkstring .= $file_id; + $linkstring .= '&title='.$this->getTitle(); + } + } + else + { + $linkstring = '/'.sfContext::getInstance()->getUser()->getCulture().'/artwork/'.$mode.'/'.$this->getId(); + if ($mode != 'xml') + { + if ($file_id) $linkstring .= '/'.$file_id; + $linkstring .= '/'.$this->getTitle(); + } + } + /*$linkstring = !$external ? + '@'.$modestring.$file.'?id='.$this->getId().$param_key.'&title='.$this->getTitle() : + '/'.sfContext::getInstance()->getUser()->getCulture().'/artwork/'.$mode.'/'.$this->getId().'/'.$file_id.$this->getTitle(); + */ + return $linkstring; + + //return Subreaktor::addProvidedLinkIfValid($linkstring); + } + + public function getFirstFile() + { + $tmp = $this->getReaktorArtworkFiles(); + return $tmp; + } + + public function __toString() + { + return ''; + } + + /** + * Required by the Feed plugin to generate routes automatically + * + * @return string The culture in question, "no" if none specified + */ + public function getFeedSfCulture() + { + return sfContext::getInstance()->getRequest()->getParameter('sf_culture', 'no'); + } + + // Let the Feed plugin generate the ID + public function getUniqueId() { + return null; + } + + /** + * Get the number of comments an artwork has in an environment + * + * @return int Number of comments + */ + public function getCommentCount($namespace) + { + $c = new Criteria(); + + $c->add(sfCommentPeer::COMMENTABLE_MODEL, get_class($this)); + $c->add(sfCommentPeer::COMMENTABLE_ID, $this->getId()); + $c->add(sfCommentPeer::NAMESPACE, $namespace); + $c->addJoin(sfCommentPeer::AUTHOR_ID, sfGuardUserPeer::ID); + + return sfCommentPeer::doCount($c); + } + + /** + * Update logged in user's last active flag after adding comment + * + * @param array $comment + * @return result from parent in plugin + */ + public function addComment($comment) + { + + //We want to call the current function's parent, but since that addComment function is in a propel behaviour class + //in the plugin sfactsascommentablebehaviour it cannot be done conventionally by inheriting. So we call it directly + //instead. + $behaviour = new sfPropelActAsCommentableBehavior(); + $ret = $behaviour->addComment($this, $comment); + + if ($comment['namespace'] == 'frontend') + { + sfContext::getInstance()->getUser()->getGuardUser()->setLastActive(date('Y-m-d H:i:s')); + sfContext::getInstance()->getUser()->getGuardUser()->save(); + } + + return $ret; + } + + /** + * Get list of relevant help articles by matching article and artwork's categories and subreaktors. + * + * @param array $subreaktors The artwork belongs to these subreaktors + * @param array $categories The categories this artwork is marked with + * @return array Article objects + */ + public function getHelpArticles($subreaktors, $categories = null) + { + $crit = new Criteria(); + $crit->addSelectColumn('article.*'); + $crit->addSelectColumn('if(article_category.category_id is null, 1,0) as isnull'); + + $crit->add(ArticlePeer::ARTICLE_TYPE, ArticlePeer::HELP_ARTICLE, Criteria::EQUAL); + $crit->setLimit(sfConfig::get('app_articles_my_page_max_count', 5)); + + $crit->addJoin(ArticlePeer::ID, ArticleCategoryPeer::ARTICLE_ID, Criteria::LEFT_JOIN); + $crit->addJoin(ArticlePeer::ID, ArticleSubreaktorPeer::ARTICLE_ID, Criteria::LEFT_JOIN); + + //Only select articles which are marked with the same subreaktor as the artwork, and if article has a category it has to match + //one of the artwork's categories + $crit->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, array_keys($subreaktors), Criteria::IN); + if($categories) + { + $cton1 = $crit->getNewCriterion(ArticleCategoryPeer::CATEGORY_ID, null , Criteria::EQUAL); + $cton2 = $crit->getNewCriterion(ArticleCategoryPeer::CATEGORY_ID, array_keys($categories), Criteria::IN); + $cton1->addOr($cton2); + + $crit->add($cton1); + } + else //The artwork has no categories, get articles with no categories + { + $crit->add(ArticleCategoryPeer::CATEGORY_ID, null , Criteria::EQUAL); + } + + //$crit->addDescendingOrderByColumn(ArticlePeer::IS_STICKY); + + $crit->add(ArticlePeer::STATUS,2); + $crit->addAscendingOrderByColumn('isnull'); + $crit->addDescendingOrderByColumn(ArticlePeer::UPDATED_AT); + + //This query works because distinct seeds out the multiple entries created from the left joins. If select is altered + //to include other objects/tables (i.e by using doselectjoin), this query will not work as intended. + $crit->setDistinct(); + return ArticlePeer::doSelect($crit); + } + + public function getShortTitle($max = 0) + { + return stringMagick::chop($this->getTitle(), $max ? $max : sfConfig::get("app_artwork_teaser_len", 40)); + } +} + +sfPropelBehavior::add('ReaktorArtwork', array('sfPropelActAsTaggableBehavior')); +sfPropelBehavior::add('ReaktorArtwork', array('sfPropelActAsCommentableBehavior')); +sfPropelBehavior::add('ReaktorArtwork', array('sfPropelActAsRatableBehavior' => + array('max_rating' => 6, + 'rating_field' => 'AverageRating'))); diff --git a/lib/model/ReaktorArtworkFile.php b/lib/model/ReaktorArtworkFile.php new file mode 100644 index 0000000..70e135e --- /dev/null +++ b/lib/model/ReaktorArtworkFile.php @@ -0,0 +1,13 @@ +getId(); + } + + if ($fileId instanceof artworkFile ) + { + $fileId = $fileId->getId(); + } + + $crit = new Criteria(); + $crit->add(self::ARTWORK_ID, $artworkId); + $crit->add(self::FILE_ID, $fileId); + $res = self::doSelectOne($crit); + + if ($res) + { + $res->setFileOrder($fileorder); + $res->save(); + } + else + { + // throw new exception ("Cannot set order as no artwork_file relationship exists"); + // Changed mind about this one - some ajax functions have items dynamically removed, + // safe just ignore this if the relationship doesn't exist for now. + } + + } + + /** + * Return an array of files in a certain artwork + * + * @param genericArtwork $artwork The artwork object + */ + public static function getFilesInArtwork($artwork) + { + $c = new Criteria(); + $c->add(self::ARTWORK_ID, $artwork->getId()); + + $rows = self::doSelectJoinAll($c); + $results = array(); + foreach ($rows as $row) + { + $results[$row->getReaktorFile()->getId()] = new artworkFile($row->getReaktorFile()->getId(), null, $rows); + } + return $results; + } +} diff --git a/lib/model/ReaktorArtworkHistory.php b/lib/model/ReaktorArtworkHistory.php new file mode 100644 index 0000000..812c6ec --- /dev/null +++ b/lib/model/ReaktorArtworkHistory.php @@ -0,0 +1,49 @@ +getId(); + } + + $history_row = new ReaktorArtworkHistory(); + if($is_file) + { + $history_row->setFileId($id); + } + else + { + $history_row->setArtworkId($id); + } +// $history_row->setApprovedAt(time("Y-m-d H:i:s")); + $history_row->setUserId($user); + $history_row->setComment($comment); + $history_row->setStatus($status); + if ($modified_flag) + { + $history_row->setModifiedFlag($modified_flag); + } + $history_row->save(); + } +} diff --git a/lib/model/ReaktorArtworkHistoryPeer.php b/lib/model/ReaktorArtworkHistoryPeer.php new file mode 100644 index 0000000..d512134 --- /dev/null +++ b/lib/model/ReaktorArtworkHistoryPeer.php @@ -0,0 +1,47 @@ +add(self::FILE_ID, $id, Criteria::EQUAL); + } + else + { + $c->add(self::ARTWORK_ID, $id, Criteria::EQUAL); + } + + $c->addDescendingOrderByColumn(self::CREATED_AT); + $history_entry = self::doSelectOne($c); + if($message_only&&$history_entry) + { + return $history_entry->getComment(); + } + else + { + return $history_entry; + } + } + +} diff --git a/lib/model/ReaktorArtworkPeer.php b/lib/model/ReaktorArtworkPeer.php new file mode 100644 index 0000000..9d3cbe6 --- /dev/null +++ b/lib/model/ReaktorArtworkPeer.php @@ -0,0 +1,993 @@ +setDistinct(); + $c->add(self::STATUS, $status); + + // Only show valid content - unless I have the permission to view blocked + // and explicitly ask for it + if (!(sfContext::getInstance()->getUser()->hasCredential('viewallcontent') && !$show_content_flag)) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + } + if($do_select_one) + { + $c->setLimit(1); + } + if($orderby) + { + $c->addDescendingOrderByColumn($orderby); + } + if ($count) + { + return self::doCount($c); + } + foreach (self::doSelectJoinsfGuardUser($c) as $artwork) + { + try + { + $artworks[] = new genericArtwork($artwork); + } + catch (Exception $e) + { + // ignore artwork with errors + } + } + if(!$artworks) + { + //if no match return null + return null; + } + if($do_select_one) + { + return $artworks[0]; + } + else + { + return $artworks; + } + } + + /** + * Returns the number of artworks with the selected status + * + * @param string $status + * + * @return integer + */ + public static function getNumberofArtworksByStatus($status) + { + return self::getArtworkByStatus($status, '', false, true); + } + + /** + * Returns the number of artworks with the selected status + * + * @param string $teams + * @param integer $status Status ID of the artworks + * @param boolean $hideDiscussion Whether to exclude artworks under discussion + * + * @return integer + */ + public static function getNumberofArtworksByEditorialTeam($teams, $status = null, $hideDiscussion = false) + { + return self::getArtworksByEditorialTeam($teams, true, $status, $hideDiscussion); + } + + /** + * Returns the number of artworks with the selected status + * + * @param string $status + * @param boolean $hideDiscussion Whether to exclude artworks under discussion + * + * @return integer + */ + public static function getArtworksByEditorialTeam($teams, $docount = false, $status = null, $hideDiscussion = false) + { + $artworks = array(); + $c = new Criteria(); + $c->setDistinct(); + $editorialteams = array(); + if (is_array($teams)) + { + foreach ($teams as $key => $val) + { + $editorialteams[] = $key; + } + } + else + { + $editorialteams[] = $teams; + } + if ($status) + { + $c->add(self::STATUS, $status); + } + + if ($hideDiscussion) + { + $c->add(self::UNDER_DISCUSSION, ''); + } + + $c->add(self::TEAM_ID, $editorialteams, Criteria::IN); + $c->addAscendingOrderByColumn(self::SUBMITTED_AT); + if ($docount) + { + return self::doCount($c); + } + foreach (self::doSelectJoinAllExceptsfGuardGroup($c) as $artwork) + { + try + { + $artworks[] = new genericArtwork($artwork); + } + catch (Exception $e) + { + // ignore artwork with errors + } + } + if(!$artworks) + { + //if no match return null + return null; + } + return $artworks; + } + + /** + * count all artworks with a certain status in an array. + * + * @param string $status The staus ID to filter on + * @param array $credentials An array of credentials to filter on (from the user accessing this function) + * @param integer $userId A user ID to filter on if required + * @param array $teams Array of editorial teams + * @param boolean $only_modified Whether to only return artwork that has been modified + * @param boolean $hideDiscussions Whether to hide artworks under discussion + * + * @return integer the count + */ + public static function getNumberOfArtworkByStatusAndCredentials($status, $credentials, $userId = null, $teams = null, $only_modified = false, $hideDiscussions = false) + { + return self::getArtworkByStatusAndCredentialsPaginated($status, $credentials, $userId, $teams, $only_modified, $hideDiscussions, true); + } + + /** + * Collect all artworks with a certain status in an array. + * + * @param string $status The staus ID to filter on + * @param array $credentials An array of credentials to filter on (from the user accessing this function) + * @param integer $userId A user ID to filter on if required + * @param array $teams Array of editorial teams + * @param boolean $only_modified Whether to only return artwork that has been modified + * @param boolean $hideDiscussions Whether to hide artworks under discussion + * + * @return sfPager the pager object containing the results + */ + public static function getArtworkByStatusAndCredentialsPaginated($status, $credentials, $userId = null, $teams = null, $only_modified = false, $hideDiscussions = false, $returncount = false) + { + $artworks = array(); + $c = new Criteria(); + + if ($hideDiscussions) + { + $c->add(self::UNDER_DISCUSSION, 0); + } + + if ($userId) + { + $c->add(self::USER_ID,$userId); + } + elseif($teams) + { + $c->add(self::TEAM_ID, $teams, Criteria::IN); + //$c->add(self::STATUS, $status); + } + if ($only_modified) + { + $c->add(ReaktorArtworkPeer::MODIFIED_FLAG, '', Criteria::NOT_EQUAL); + //$c->add(self::STATUS, $status); + } + if ($status) + { + $c->add(self::STATUS, $status); + } + if ($returncount) + { + return ReaktorArtworkPeer::doCount($c); + } + $pager = new sfPropelPager('ReaktorArtwork', SfConfig::get('app_artwork_pagination',10)); + $pager->setCriteria($c); + return $pager; + + } + + /** + * Return an array of unapproved genericArtworks that belong to the subreaktors + * the (logged in) user belongs to. + * + * @param sfGuardUser $user + * + * @return array + */ + public static function getUnapprovedArtworksByUser($user) + { + $artworks = array(); + $c = new Criteria(); + $c->add(ArtworkStatusPeer::NAME, 'Ready for approval'); + $c->setLimit(1); + $ready = ArtworkStatusPeer::doSelect($c); + + $crit = new Criteria(); + $crit->add(self::STATUS, $ready[0]->getId() ); //ready + if (!$user->hasCredential('approveartwork')) + { + $crit->add(self::USER_ID, $user->getGuardUser()->getId()); + foreach (self::doSelect($crit) as $artwork) + { + $artworks[] = new genericArtwork($artwork); + } + } else + { + foreach (self::doSelect($crit) as $artwork) + { + try + { + $tmp = new genericArtwork($artwork); + $subreaktors = $tmp->getSubreaktors(); + foreach ($subreaktors as $subreaktor) + { + if ($user->hasCredential('approve'.$subreaktor.'artwork')) + { + $artworks[] = $tmp; + break; + } + } + } + catch (Exception $e) + { + // ignore artwork with errors + } + } + } + return $artworks; + } + + /** + * Get artwork statys by description + * + * @param string $desc + * @return mixed false if artwork id + */ + public static function getStatusIdByDescription($desc) + { + $c = new Criteria(); + $c->add(ArtworkStatusPeer::NAME, $desc); + $c->setLimit(1); + $id = ArtworkStatusPeer::doSelect($c); + return (isset($id[0]))?$id[0]->getId():0; + } + + /** + * Return an array of latest commented reaktorArtworks. + * + * @param integer $count + * @return array reaktorArtworkObjects + */ + public static function getLatestCommented($count = 5) + { + if (Subreaktor::isValid()) + { + // FIXME: uhh? + //echo Subreaktor::getProvided(); + } + $c = new Criteria(); + $c->clearSelectColumns(); + self::addSelectColumns($c); + $c->addSelectColumn(sfCommentPeer::COMMENTABLE_ID); + $c->addSelectColumn('max('.sfCommentPeer::CREATED_AT.') as max_date'); + $c->add(sfCommentPeer::COMMENTABLE_MODEL, 'ReaktorArtwork', Criteria::LIKE); + $c->add(sfCommentPeer::NAMESPACE, 'frontend', Criteria::LIKE); + $c->add(sfCommentPeer::UNSUITABLE, false); + $c->addGroupByColumn(sfCommentPeer::COMMENTABLE_ID); + $c->addJoin(self::ID, sfCommentPeer::COMMENTABLE_ID, Criteria::LEFT_JOIN); + $c->addJoin(self::USER_ID, sfGuardUserPeer::ID, Criteria::LEFT_JOIN); + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + + $c->add(self::STATUS, 3); + $c->addDescendingOrderByColumn('max_date'); + $c->setLimit($count); + + $artworkObjects = self::doSelect($c); + $returnArray = array(); + $tmpArray = array(); + + + + foreach ($artworkObjects as $artworkObject) + { + $tmpArray[$artworkObject->getArtworkIdentifier()][$artworkObject->getId()] = new genericArtwork($artworkObject); + } + + foreach ($tmpArray as $item) + { + $returnArray=array_merge($returnArray,$item); + } + + + return $returnArray; + } + + /** + * Get the latests artworks from user, subreaktor, or entire reaktor + * + * @param integer $count Return $count number of artworks + * @param integer $filter Userid to get user's artwork, + * @param boolean $random Instead of latest approved, get random + * @param mixed $subreaktor Filter on artworks belonging to a subreaktor + * @param mixed $lokalreaktor Filter on artworks belonging to lokalreaktor + * @param boolean $show_blocked_content Should the artwork display blocked artworks or not + * @param boolean $reaktor_filter if true filter on subreaktors, if false turn filters off + * @return array + */ + public static function getLatestSubmittedApproved($count = 5, $filter = null, $random = null, $subreaktor = null, $lokalreaktor = null, $show_blocked_content = null, $reaktor_filter = true) + { + $c = new Criteria(); + if($random) + { + //TODO: This is not a good way to do it if the table grows.. + $c->addDescendingOrderByColumn('rand(now())'); + } + else + { + $c->addDescendingOrderByColumn(parent::ACTIONED_AT); + } + $c->add(parent::STATUS, 3); + $c->addJoin(parent::ID, ReaktorArtworkFilePeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID, Criteria::LEFT_JOIN); + $c->addJoin(parent::USER_ID, sfGuardUserPeer::ID, Criteria::LEFT_JOIN); + $c->setDistinct(); + + if(is_int($filter)) + { + $c->add(parent::USER_ID, $filter); + } + + if ($reaktor_filter) + { + if ($subreaktor instanceof Subreaktor) + { + $c->addJoin(parent::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $subreaktor->getId()); + } + elseif (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + $c->addJoin(parent::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedSubreaktor()->getId()); + } + + if ($lokalreaktor instanceof Subreaktor) + { + $c->addJoin(parent::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokalreaktor->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $lokalreaktor->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + elseif (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $c->addJoin(parent::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedLokalreaktor()->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, Subreaktor::getProvidedLokalreaktor()->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + } + + $c->setLimit($count); + if (!$show_blocked_content) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + } + + $res = parent::doSelect($c); + $artworks = array(); + foreach ($res as $r) + { + $artworks[] = new genericArtwork($r); + } + return $artworks; + + } + + public static function getArtworkById($id) + { + $c = new Criteria(); + $c->add(self::ID, $id); + return self::doSelect($c); + + } + + protected static function getLatestSubmittedApprovedCriteria($user = 0, $sortBy = null) + { + $c = new Criteria(); + + $c->add(parent::STATUS, 3); + $c->addJoin(self::ID,ReaktorArtworkFilePeer::ARTWORK_ID); + $c->addJoin(ReaktorFilePeer::ID,ReaktorArtworkFilePeer::FILE_ID); + + $c->setDistinct(); + + $c->addAscendingOrderByColumn(self::ARTWORK_ORDER); + + if($user) + { + $c->add(parent::USER_ID, $user); + } + switch ($sortBy) + { + case $sortBy == 'date': + $c->addDescendingOrderByColumn(self::CREATED_AT); + break; + case $sortBy == 'rating': + $c->addDescendingOrderByColumn(self::AVERAGE_RATING); + break; + case $sortBy == 'title': + $c->addAscendingOrderByColumn(self::TITLE); + break; + case $sortBy == 'format': + $c->addDescendingOrderByColumn(self::ARTWORK_IDENTIFIER); + break; + case in_array($sortBy, Subreaktor::getAllAsReferences()): + $c->addJoin(ReaktorArtworkPeer::ID, SubreaktorArtworkPeer::ARTWORK_ID); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getByReference($sortBy)->getId()); + break; + case is_numeric($sortBy): + $c->addJoin(ReaktorArtworkPeer::ID, SubreaktorArtworkPeer::ARTWORK_ID); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, (int)$sortBy); + default: + $c->addDescendingOrderByColumn(parent::ACTIONED_AT); + break; + } + return $c; + } + + public static function getLatestSubmittedApprovedNotPaginated($count = 5, $user = 0, $sortBy = null) + { + $c = self::getLatestSubmittedApprovedCriteria($user, $sortBy); + if ($count) + { + $c->setLimit($count); + } + return parent::doSelectJoinAll($c); + } + + public static function getLatestSubmittedApprovedPaginated($count = 5, $user = 0, $sortBy = null) + { + $c = self::getLatestSubmittedApprovedCriteria($user, $sortBy); + $pager = new sfPropelPager('ReaktorArtwork', $count); + $pager->setCriteria($c); + return $pager; + } + + /** + * Get most popular artworks, using current ratings, (falls back on rating_average column), + * either filter by user or reaktor. + * + * @param mixed $filter_id String if reaktor int if user + * @param integer $count + * @return array + */ + public static function mostPopularArtworks($subreaktor = '', $count = 5, $lokalreaktor = null, $user = null) + { + $c = new Criteria(); + $c->setDistinct(); + $c->addJoin(parent::ID, ReaktorArtworkFilePeer::ARTWORK_ID, Criteria::LEFT_JOIN); + if ($user) + { + $c->add(parent::USER_ID, $user); + } + elseif (is_object($subreaktor)) + { + $c->addJoin(parent::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $subreaktor->getId()); + } + elseif (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + $c->addJoin(parent::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedSubreaktor()->getId()); + } + + if ($lokalreaktor instanceof Subreaktor) + { + $c->addJoin(parent::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokalreaktor->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $lokalreaktor->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + elseif (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $c->addJoin(parent::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedLokalreaktor()->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, Subreaktor::getProvidedLokalreaktor()->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + + $c->add(parent::STATUS, 3); + $c->setLimit($count); + //if (!sfContext::getInstance()->getUser()->hasCredential('viewallcontent')) + //{ + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + //} + //$c2 = clone $c; + $c->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, sfRatingPeer::RATABLE_ID); + $c->addAsColumn('sumrating', 'AVG(' . sfRatingPeer::RATING . ')'); + $c->addAsColumn('numvotes', 'COUNT(' . sfRatingPeer::ID . ')'); + $c->add(sfRatingPeer::RATABLE_MODEL, 'ReaktorArtwork'); + $c->addDescendingOrderByColumn('sumrating'); + $c->addDescendingOrderByColumn('numvotes'); + $c->addGroupByColumn(ReaktorArtworkFilePeer::ARTWORK_ID); + + $c2 = clone $c; + $c->add(sfRatingPeer::RATED_AT, time() - (60*86400), Criteria::GREATER_EQUAL); + $reaktorartworks = parent::doSelectJoinsfGuardUser($c); + + $returnval = array(); + if (empty($reaktorartworks)) + { + sfContext::getInstance()->getLogger()->info("Could not find any ratings for last two months in this subreaktor"); + sfContext::getInstance()->getLogger()->info("PEBKAC!"); + sfContext::getInstance()->getLogger()->info("Falling back to retrieving artworks by average rating"); + //$c2->addDescendingOrderByColumn(self::AVERAGE_RATING); + $reaktorartworks = parent::doSelectJoinsfGuardUser($c2); + } + foreach ($reaktorartworks as $aReaktorArtwork) + { + $returnval[] = new genericArtwork($aReaktorArtwork); + } + return $returnval; + } + + /** + * Get a selection of artworks based on user/user id + * + * @param sfGuardUser|int $user User ID or object + * @param int $limit Limit for resultset + * @param boolean $random True to return random results, default is date order + * @param array $exclude array of artworks/ids to exclude from results + * @param integer|array $status Status to filter on (default is 3 (approved)) + * @param array $statusExclude Array of statuses not to return in results + * @param Criteria $criteria Extra criteria if needed + * + * @return array Of generic artwork objects + */ + public static function getArtworksByUser($user, $limit = 0, $random = false, $exclude = array(), $status = 3, $statusExclude = array(), $c = null) + { + if ($user instanceof sfGuardUser) + { + $user = $user->getId(); + } + $resultArray = array(); + + if (!$c) + { + $c = new Criteria(); + } + + $c->add(self::USER_ID, $user); + + if ($limit > 0) + { + $c->setLimit($limit); + } + + if ($random) + { + $c->addAscendingOrderByColumn('RAND()'); + } + else + { + $c->addAscendingOrderByColumn(self::ARTWORK_ORDER); + $c->addAscendingOrderByColumn(self::CREATED_AT); + } + + foreach ($exclude as $item) + { + if ($item instanceof genericArtwork) + { + $item = $item->getId(); + } + $c->add(self::ID, $item, Criteria::NOT_EQUAL); + } + + if (!is_null($status)) + { + if (is_array($status)) + { + $c->add(self::STATUS, $status, Criteria::IN); + } + else + { + $c->add(self::STATUS, $status); + } + } + elseif (!empty($statusExclude)) + { + $c->add(self::STATUS, $statusExclude, Criteria::NOT_IN); + } + + if (!sfContext::getInstance()->getUser()->hasCredential('viewallcontent')) + { + if (sfContext::getInstance()->getUser()->getGuardUser()) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT,"(sf_guard_user.SHOW_CONTENT=1 OR reaktor_artwork.USER_ID=" . sfContext::getInstance()->getUser()->getGuardUser()->getId() . ")", Criteria::CUSTOM); + } + } + sfContext::getInstance()->getLogger()->info("foo1"); + $artworkArray = self::doSelectJoinAll($c); + sfContext::getInstance()->getLogger()->info("foo2"); + foreach ($artworkArray as $artworkObject) + { + sfContext::getInstance()->getLogger()->info("getting related artwork with id ".$artworkObject->getId()); + $resultArray[] = new genericArtwork($artworkObject); + } + + return $resultArray; + + } + + /** + * Given an artwork, get title and id of artworks not already related to it. Designed to be used in dropdowns. + * + * @param int $user_id + * @param int $artwork_id + * @param array $related + * @param boolean $onlyApproved Whether to return just approved artworks + * + * @return array $artworks + */ + public static function getUnrelatedArtworks($userId = null, $artworkId = null, $related, $onlyApproved = true, $max = -1) + { + $c = new Criteria(); + $c->clearSelectColumns(); + $c->addSelectColumn(parent::ID); + $c->addSelectColumn(parent::TITLE); + $c->addJoin(self::USER_ID, sfGuardUserPeer::ID); + $c->addSelectColumn(sfGuardUserPeer::USERNAME); + $c->addSelectColumn(self::ARTWORK_IDENTIFIER); + + if ($onlyApproved) + { + $c->add(parent::STATUS, 3); + } + if ($userId) + { + $c->add(parent::USER_ID, $userId); + } + if ($artworkId) + { + $c->add(parent::ID, $artworkId, Criteria::NOT_EQUAL); + } + + $c->add(parent::ID, $related, Criteria::NOT_IN); + if ($max > 0) + { + $c->setLimit($max); + } + + $rs = parent::doSelectRS($c); + $artworks = array(); + + while($rs->next()) + { + $artworks[$rs->getInt(1)] = $rs->getString(2); + if (is_null($artworkId)) + { + $artworks[$rs->getInt(1)] = $rs->getString(2)." (".$rs->getString(4).") - ".$rs->getString(3); + } + } + + return $artworks; + + } + + /** + * Count the number of artworks in the database that a user has submitted + * + * @param sfGuardUser|myUser|id $user id or user object + * @param string $type The type of artwork to count + * @param integer $statusId The status to filter on, or all if not set + * @param criteria $c Criteria object if custom criteria are needed + * @param boolean $groupByStatus Return an array of counts by status + * + * @return integer|array a count or array of counts grouped by status + */ + public static function countUserArtworks($user, $type = null, $statusId = null, $groupByStatus = false, $c = null) + { + if ($user instanceof myUser) + { + $user = $user->getGuardUser()->getId(); + } + elseif ($user instanceof sfGuardUser ) + { + $user = $user->getId(); + } + else + { + $user = intval($user); + } + + if (!$c) + { + $c = new Criteria(); + } + + $c->add(self::USER_ID, $user); + + if ($statusId) + { + $c->add(self::STATUS, $statusId); + } + + if ($type) + { + $c->add(self::ARTWORK_IDENTIFIER, $type); + } + + if ($groupByStatus) + { + $c->clearSelectColumns(); + $c->addSelectColumn(self::STATUS); + $c->addSelectColumn(self::ACTIONED_AT); + + $results = self::doSelectRS($c); + $resultArray = array(1 => array(), 2 => array(), 3 => array(), 4 => array(), 5 => array()); + while ($results->next()) + { + $year = $results->getString(2); + if ($year) + { + $year = date("Y", strtotime($year)); + } + else + { + $year = 0; + } + + if (!isset($resultArray[$results->getInt(1)][$year])) + { + $resultArray[$results->getInt(1)][$year] = 0; + } + $resultArray[$results->getInt(1)][$year]++; + } + return $resultArray; + } + + return self::doCount($c); + } + + /** + * Get a count of the artworks by year and month + * + * @param integer $year The year to check + * @param integer $month The month (optional) + * + * @return integer the requested count + */ + public static function countArtworksByDateAndStatus($status, $year, $month = 0) + { + $c = new Criteria(); + if ($month != 0) + { + $ctn = $c->getNewCriterion(self::ACTIONED_AT, mktime(null, null, null, $month, 1, $year), Criteria::GREATER_EQUAL); + $ctn2 = $c->getNewCriterion(self::ACTIONED_AT, mktime(null, null, null, $month + 1, 1, $year), Criteria::LESS_THAN); + } + else + { + $ctn = $c->getNewCriterion(self::ACTIONED_AT, mktime(null, null, null, 1, 1, $year), Criteria::GREATER_EQUAL); + $ctn2 = $c->getNewCriterion(self::ACTIONED_AT, mktime(null, null, null, 12, 31, $year), Criteria::LESS_THAN); + } + $ctn->addAnd($ctn2); + $c->add($ctn); + + $c->add(self::STATUS, $status); + return self::doCount($c); + } + + /** + * Get artworks by date (year and month) + * + * @param integer $year The year to check + * @param integer $month The month (optional) + * + * @return sfPropelPager + */ + public static function getArtworksByDateAndStatus($status, $year, $month = 0) + { + $c = new Criteria(); + if ($month != 0) + { + $ctn = $c->getNewCriterion(self::ACTIONED_AT, mktime(null, null, null, $month, 1, $year), Criteria::GREATER_EQUAL); + $ctn2 = $c->getNewCriterion(self::ACTIONED_AT, mktime(null, null, null, $month + 1, 1, $year), Criteria::LESS_THAN); + } + else + { + $ctn = $c->getNewCriterion(self::ACTIONED_AT, mktime(null, null, null, 1, 1, $year), Criteria::GREATER_EQUAL); + $ctn2 = $c->getNewCriterion(self::ACTIONED_AT, mktime(null, null, null, 12, 31, $year), Criteria::LESS_THAN); + } + + $ctn->addAnd($ctn2); + $c->addDescendingOrderByColumn(self::ACTIONED_AT); + $c->add($ctn); + + $c->add(self::STATUS, $status); + + $pager = new sfPropelPager('ReaktorArtwork', SfConfig::get('app_artwork_pagination',10)); + $pager->setCriteria($c); + return $pager; + + //return self::doSelectJoinAll($c); + } + + /** + * Return a count for the number of artworks currently under discussion + * + * @return integer the count + */ + public static function getNumberOfArtworksUnderDiscussion() + { + $c = new Criteria(); + $c->add(self::UNDER_DISCUSSION, 1); + + return self::doCount($c); + } + + /** + * Get the artworks that are marked for discussion + * + * @return array the artworks + */ + public static function getArtworksUnderDiscussion() + { + $c = new Criteria(); + $c->add(self::UNDER_DISCUSSION, 1); + + $result = self::doSelectJoinAll($c); + + $returnArray = array(); + foreach ($result as $artworkObject) + { + $returnArray[$artworkObject->getId()] = new genericArtwork($artworkObject); + } + return $returnArray; + } + + /** + * Get an array of artwork objects based on type + * + * @param integer $type The type of artwork we are after + * @param integer $status status to filter on, or null not to apply it + * @param boolean $multiUserOnly Whether to show results from multi_user artworks only + * @param boolean $indexedArray Whether to return an indexed array instead of array of objects + * @param array $excludeArray An array of artwork ids to exclude from the results + * + * @return array + */ + public static function getArtworksByType($type, $status = null, $multiUserOnly = false, $indexedArray = false, $excludeArray = array()) + { + $c = new criteria(); + $c->add(self::ARTWORK_IDENTIFIER, $type); + $c->addDescendingOrderByColumn(self::CREATED_AT); + + if ($status) + { + $c->add(self::STATUS, $status); + } + + if ($multiUserOnly) + { + $c->add(self::MULTI_USER, 1); + } + + if (!empty($excludeArray)) + { + $c->add(self::ID, $excludeArray, Criteria::NOT_IN); + } + + $rows = self::doSelectJoinsfGuardUser($c); + + if ($indexedArray) + { + $resultArray = array(); + foreach ($rows as $row) + { + $resultArray[$row->getId()] = $row->getTitle();; + } + return $resultArray; + } + else + { + return $rows; + } + + } + + /** + * Get all the multi user/composite/admin created galleries + * + * @return array of artwork objects + */ + public static function getCompositeArtworks() + { + $c = new Criteria(); + $c->add(self::MULTI_USER, true); + + $result = self::doSelectJoinAll($c); + + $returnArray = array(); + foreach ($result as $artworkObject) + { + $returnArray[$artworkObject->getId()] = new genericArtwork($artworkObject); + } + return $returnArray; + } + + /** + * Show artworks that are possible to link to this file, based on a file object + * + * @param artworkFile $file + * + * @return array of artworks + */ + public static function getLinkableArtworks($file) + { + $alreadyLinked = $file->getParentArtworks(true); + + $c = new Criteria(); + $c->add(self::STATUS, 5, Criteria::NOT_EQUAL); // Don't show deleted artworks + + $allowedTypes = array($file->getIdentifier()); + + // See if we have any defined additional types other than the one for this file + $additionalTypesArray = sfConfig::get("app_artwork_additional_file_types", array()); + if (isset($additionalTypesArray[$file->getIdentifier()])) + { + $allowedTypes = array_merge($allowedTypes, $additionalTypesArray[$file->getIdentifier()]); + } + + $c->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, $allowedTypes, Criteria::IN); + + $c->add(ReaktorArtworkPeer::USER_ID, $file->getUserId()); + if (!empty($alreadyLinked)) + { + $c->add(ReaktorArtworkPeer::ID, $alreadyLinked, Criteria::NOT_IN); + } + return ReaktorArtworkPeer::doSelect($c); + } +} diff --git a/lib/model/ReaktorFile.php b/lib/model/ReaktorFile.php new file mode 100644 index 0000000..6744301 --- /dev/null +++ b/lib/model/ReaktorFile.php @@ -0,0 +1,36 @@ +getRequest()->getHost() . contentPath($artworkfile, 'normal'); + } + + /** + * Get the number of comments a file has in an environment + * + * @return int Number of comments + */ + public function getCommentCount($namespace) + { + $c = new Criteria(); + + $c->add(sfCommentPeer::COMMENTABLE_MODEL, get_class($this)); + $c->add(sfCommentPeer::COMMENTABLE_ID, $this->getId()); + $c->add(sfCommentPeer::NAMESPACE, $namespace); + + return sfCommentPeer::doCount($c); + } +} + +sfPropelBehavior::add('ReaktorFile', array('sfPropelActAsTaggableBehavior')); +sfPropelBehavior::add('ReaktorFile', array('sfPropelActAsCommentableBehavior')); \ No newline at end of file diff --git a/lib/model/ReaktorFilePeer.php b/lib/model/ReaktorFilePeer.php new file mode 100644 index 0000000..66a0635 --- /dev/null +++ b/lib/model/ReaktorFilePeer.php @@ -0,0 +1,274 @@ +add(self::REPORTED, 0, Criteria::GREATER_THAN); + $c->add(self::MARKED_UNSUITABLE, 0, Criteria::EQUAL); + + $pager = new sfPropelPager('ReaktorFile', SfConfig::get('app_artwork_pagination',10)); + $pager->setCriteria($c); + return $pager; + } + + /** + * Get a count of reported files + * + * @return integer The count + */ + public static function getNumberofReportedFiles() + { + $c = new Criteria(); + + $c->add(self::REPORTED, 0, Criteria::GREATER_THAN); + $c->add(self::MARKED_UNSUITABLE, 0, Criteria::EQUAL); + + return self::doCount($c); + } + + /** + * Return files that have been marked unsuitable + * + * @return sfPager the pager object with the unsuitable files + */ + public static function getMarkedUnsuitableFilesPaginated() + { + $c = new Criteria(); + $c->add(self::MARKED_UNSUITABLE, 1); + $c->add(FileMetadataPeer::META_ELEMENT, 'title'); + $c->addJoin(self::ID, FileMetadataPeer::FILE); + + $pager = new sfPropelPager('ReaktorFile', SfConfig::get('app_artwork_pagination', 10)); + $pager->setPeerMethod('doSelectJoinSfGuardUser'); + $pager->setCriteria($c); + return $pager; + + } + + /** + * Get a count of files under discussion + * + * @return integer The count + */ + public static function getNumberofFilesUnderDiscussion() + { + $c = new Criteria(); + + $c->add(self::UNDER_DISCUSSION, 1); + + return self::doCount($c); + } + + /** + * Get all the files that are under discussion + * + * @return array of artwork files + */ + public static function getFilesUnderDiscussion() + { + $c = new Criteria(); + $c->add(self::UNDER_DISCUSSION, 1); + + $result = self::doSelectJoinAll($c); + $returnArray = array(); + + foreach ($result as $reaktorFile) + { + $returnArray[$reaktorFile->getId()] = new artworkFile($reaktorFile); + } + + return $returnArray; + } + + /** + * Returns all files by date + * + * @param timestamp $from_date + * @param timestamp $to_date + */ + public static function getByDate($from_date, $to_date) + { + $crit = new Criteria(); + $crit->add(self::DELETED, false); + $ctn = $crit->getNewCriterion(self::UPLOADED_AT, $from_date, Criteria::GREATER_EQUAL); + $ctn2 = $crit->getNewCriterion(self::UPLOADED_AT, $to_date, Criteria::LESS_EQUAL); + $ctn->addAnd($ctn2); + $crit->add($ctn); + + $returnfiles = array(); + foreach (self::doSelectJoinAll($crit) as $reaktorfile) + { + $returnfiles[] = new artworkFile($reaktorfile); + } + + return $returnfiles; + } + + /** + * Return a count of the number of files a user has uploaded in total + * + * @param sfGuardUser|integer $user The user object or ID + * @param string $type The type of file (file identifier) + * @param boolean $orphaned Whether to return only orphaned files (not in artworks) + * @param boolean $includeHidden Whether to return hidden files ("deleted" by user) + * @param boolean $unsuitable Whether to filter on unsuitability flag + * + * @return integer the count + */ + public static function countFilesByUser($user, $type = null, $orphaned = false, $includeHidden = false, $unsuitable = null) + { + return self::getFilesByUser($user, $type, $orphaned, true, false, array(), $includeHidden, $unsuitable); + } + + /** + * Return the files that are connected to a particular user + * + * @param sfGuardUser|integer $user The user object or ID + * @param string|array $type The type of file (file identifier) or array of types + * @param boolean $orphaned Whether to return only orphaned files (not in artworks) + * @param boolean $count Whether to just return a count, instead of the array of files + * @param boolean $dontGetParents Set true to choose not to populate parent artworks (saves queries if they are not going to be used) + * @param array $excludeIds An array of IDs to exclude from the results + * @param boolean $includeHidden Whether to include hidden files + * @param boolean $unsuitable Whether to filter on unsuitability + * + * @return integer|array count or array of files + */ + public static function getFilesByUser($user, $type = null, $orphaned = false, $count = false, $dontGetParents = false, $excludeIds = array(), $includeHidden = false, $unsuitable = false) + { + if ($user instanceof sfGuardUser || $user instanceof myUser ) + { + $user = $user->getId(); + } + $c = new Criteria(); + $c->add(self::USER_ID, $user); + + if (!$includeHidden) + { + $c->add(self::HIDDEN, 0); + } + + if (!is_null($unsuitable)) + { + $c->add(self::MARKED_UNSUITABLE, $unsuitable); + } + + if ($type) + { + if (is_array($type)) + { + $c->add(self::IDENTIFIER, $type, Criteria::IN); + } + else + { + $c->add(self::IDENTIFIER, $type); + } + } + + if ($orphaned) + { + $c->addJoin(self::ID, ReaktorArtworkFilePeer::FILE_ID, Criteria::LEFT_JOIN); + $c->add(ReaktorArtworkFilePeer::ARTWORK_ID, null); + } + + if (!empty($excludeIds)) + { + $c->add(self::ID, $excludeIds, Criteria::NOT_IN); + } + + if ($count) + { + return self::doCount($c); + } + else + { + + $rows = self::doSelectJoinAll($c); + $resultArray = array(); + + foreach($rows as $row) + { + $resultArray[$row->getId()] = new artworkFile($row->getId(), null, $rows, $dontGetParents); + } + return $resultArray; + } + } + + /** + * Overriding the retrieve by PK class so we can get artworkFile objects back + * + * @param integer $pk The ID of the file we want + * @param connection $con Database connection + * @param boolean $artworkFile Whether to return an artworkFile object + */ + public static function retrieveByPK($pk, $con = null, $artworkFile = false) + { + $fileObject = parent::retrieveByPK($pk); + + if ($fileObject && $artworkFile) + { + return new artworkFile($fileObject); + } + else + { + return $fileObject; + } + } + + /** + * Get an array of files based on an artwork type + * + * @param string $type for example "image" or "video" from the mimetype table + * @param array $excludeIds an array of file ids not to include in the results + * @param boolean $includeHidden Whether to include hidden files in results + * + * @return array of artworkfile objects + */ + public static function getFilesByType($type, $excludeIds = array(), $includeHidden = false, $unsuitable = null) + { + $c = new Criteria(); + + $c->add(FileMimetypePeer::IDENTIFIER, $type); + $c->addJoin(self::CONVERTED_MIMETYPE_ID, FileMimetypePeer::ID); + + if (!empty($excludeIds)) + { + $c->add(self::ID, $excludeIds, Criteria::NOT_IN); + } + if (!$includeHidden) + { + $c->add(self::HIDDEN, 0); + } + if (!is_null($unsuitable)) + { + $c->add(self::MARKED_UNSUITABLE); + } + + $rows = self::doSelectJoinAll($c); + + $resultArray = array(); + + foreach($rows as $row) + { + $resultArray[$row->getId()] = new artworkFile($row->getId(), null, $rows); + } + return $resultArray; + } + +} diff --git a/lib/model/RecommendedArtwork.php b/lib/model/RecommendedArtwork.php new file mode 100644 index 0000000..3171914 --- /dev/null +++ b/lib/model/RecommendedArtwork.php @@ -0,0 +1,12 @@ +addAlias('ra2', parent::TABLE_NAME); + + //Muliple conditions when joining must be hacked in propel... + $c2->addJoin(parent::SUBREAKTOR, parent::alias('ra2', parent::SUBREAKTOR). + ' AND '.parent::UPDATED_AT.' < '.parent::alias('ra2', parent::UPDATED_AT). + ' AND ('.parent::LOCALSUBREAKTOR.' = '.parent::alias('ra2', parent::LOCALSUBREAKTOR). + ' OR ('.parent::LOCALSUBREAKTOR .' is null AND '. + parent::alias('ra2', parent::LOCALSUBREAKTOR). ' is NULL ))', Criteria::LEFT_JOIN); + + $c2->add(parent::alias('ra2', parent::UPDATED_AT), null , Criteria::EQUAL); + + $recommended_artworks = parent::doSelect($c2); + $recommended_ids = array(); + $results = array(); + //We need the id's + foreach ($recommended_artworks as $ra) + { + $recommended_ids[] = $ra->getId(); + } + + if ($c->getDbName() == Propel::getDefaultDB()) + { + $c->setDbName(self::DATABASE_NAME); + } + + /* We need to manually join all the tables, and later hydrate them to get the object, + * because two of the columns (subreaktor, localreaktor) have the same table as foreign key. + * The next steps are done to calculate the hydration. + * + * Add all (normal) columns of each table to the query and calculate positions in the result set. + * Since all colums are numered in the result set, we have to calculate the offset for each table. + * Assuming Table1 has 2 columns, Table2 5 and Table3 4, the first Table1 column is at result_column 0, + * the first Table2 column is located 2 columns later and the first Table3 column is located + * at offset 2+5=7. + */ + + // First: Table Trade. Offset is not calculated because it is always 0. There is also no need for a + //join since we start with this table. + + if (!empty($recommended_ids)) + { + parent::addSelectColumns($c); + $c->add(parent::ID, $recommended_ids, Criteria::IN); + $c->add(ReaktorArtworkPeer::STATUS, 3, Criteria::EQUAL); + $c->add(sfGuardUserPeer::SHOW_CONTENT, true, Criteria::EQUAL); + + //Seond table - artworks + ReaktorArtworkPeer::addSelectColumns($c); + $startcol_reaktorartwork = (parent::NUM_COLUMNS - parent::NUM_LAZY_LOAD_COLUMNS) + 1; + $c->addJoin(parent::ARTWORK, ReaktorArtworkPeer::ID, Criteria::LEFT_JOIN); + + //Third table - subreaktor + SubreaktorPeer::addSelectColumns($c); + $startcol_subreaktor = $startcol_reaktorartwork + ReaktorArtworkPeer::NUM_COLUMNS; + $c->addJoin(parent::SUBREAKTOR, SubreaktorPeer::ID, Criteria::LEFT_JOIN); + + //Fourth table localsubreaktor (second join with subreaktor) + $c->addAlias('local_subreaktor', SubreaktorPeer::TABLE_NAME); + SubreaktorPeer::addAliasSelectColumns('local_subreaktor',$c); + $startcol_local_subreaktor = $startcol_subreaktor + SubreaktorPeer::NUM_COLUMNS; + $c->addJoin(parent::LOCALSUBREAKTOR, SubreaktorPeer::alias('local_subreaktor', SubreaktorPeer::ID), Criteria::LEFT_JOIN); + + //Fifth table - user + sfGuardUserPeer::addSelectColumns($c); + $startcol_user = $startcol_local_subreaktor + SubreaktorPeer::alias('local_subreaktor', SubreaktorPeer::NUM_COLUMNS); + $c->addJoin(parent::UPDATED_BY, sfGuardUserPeer::ID, Criteria::LEFT_JOIN); + if (!sfContext::getInstance()->getUser()->hasCredential('viewallcontent')) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + } + + $rs = BasePeer::doSelect($c, $con); + + while($rs->next()) + { + // Hydrate the sfComment object + $omClass = RecommendedArtworkPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + // Hydrate the Artwork object + $omClass = ReaktorArtworkPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol_reaktorartwork); + + // Hydrate the subreaktor object + $omClass = SubreaktorPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj3 = new $cls(); + $obj3->hydrate($rs, $startcol_subreaktor); + + // Hydrate the localsubreaktor object + $omClass = SubreaktorPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj4 = new $cls(); + $obj4->hydrate($rs, $startcol_local_subreaktor); + + // Hydrate the sfGuardUser object + $omClass = sfGuardUserPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj5 = new $cls(); + $obj5->hydrate($rs, $startcol_user); + + //Update main object with external objects + $obj1->setArtwork($obj2); + $obj1->setSubreaktor($obj3); + $obj1->setLocalsubreaktor($obj4); + $obj1->setUpdatedBy($obj5); + $results[] = $obj1; + } + } + + return $results; + + } + + /** + * Get the recommended artwork in a specific subreaktor + * + * @param integer $subreaktor + */ + public static function getRecommendedArtwork($subreaktor = null, $lokalreaktor = null, $show_content_flag = true, $limit = 0) + { + $c = new Criteria(); + $c->addDescendingOrderByColumn(parent::UPDATED_AT); + $c->add(ReaktorArtworkPeer::STATUS, 3, Criteria::EQUAL); + $c->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID, Criteria::LEFT_JOIN); + $c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID, Criteria::LEFT_JOIN); + + // Only show valid content - unless I have the permission to view blocked + // and explicitly ask for it + // ZOID: This logic should not really be here + if (!(sfContext::getInstance()->getUser()->hasCredential('viewallcontent') && !$show_content_flag)) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + } + + /* + * An artwork belonging to a subreaktor(ex. photo) and a lokalreaktor (ex. Groruddalen) can be recommended in each of them, but also + * in a combination of them. The following list describes the combinations and how they are stored in the recommended artwork table: + * Recommended in photo - subreaktor is set to photo + * Recommended in groruddalen - subreaktor is set to groruddalen + * Recommended in groruddalen:photo - subreaktor is set to groruddalen and localsubreaktor to photo + */ + //Check if lokalreaktor is set + $lokalreaktor_id = $lokalreaktor instanceof Subreaktor ? $lokalreaktor->getId() : null; + $lokalreaktor_id = (!$lokalreaktor_id && Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) ? + Subreaktor::getProvidedLokalreaktor()->getId() : null; + + if ($lokalreaktor_id && $lokalreaktor != 'ignore')// Lokalreaktor is set + { + $c->add(parent::SUBREAKTOR, $lokalreaktor_id); + + //Look for subreaktor, and add as local subreaktor. A user shouldn't be able to recommended an artwork in a lokalreaktor + //alone so a subreaktor should always be found here + if ($subreaktor instanceof Subreaktor) + { + $c->add(parent::LOCALSUBREAKTOR, $subreaktor->getId()); + } + elseif (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + $c->add(parent::LOCALSUBREAKTOR, Subreaktor::getProvidedSubreaktor()->getId()); + } + } + elseif($subreaktor != 'ignore') //Lokalreaktor isn't set, which means we're trying to get the recommendation for a subreaktor + { + if ($subreaktor instanceof Subreaktor) + { + $c->add(parent::SUBREAKTOR, $subreaktor->getId()); + } + elseif (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor) + { + $c->add(parent::SUBREAKTOR, Subreaktor::getProvidedSubreaktor()->getId()); + } + } + + if ($limit) + { + $c->setLimit($limit); + $hash = spl_object_hash($c) . 'sub' .Subreaktor::getProvidedSubreaktorReference() . 'lok' .Subreaktor::getProvidedLokalReference(); + $cache = reaktorCache::singleton($hash); + $retval = $cache->get(); + + if (!$retval || is_null(current($retval))) + { + $retval = self::doSelectJoinReaktorArtwork($c); + $cache->set($retval); + } + return $retval; + } + else + { + $c->setLimit(1); + + $hash = spl_object_hash($c) . 'sub' .Subreaktor::getProvidedSubreaktorReference() . 'lok' .Subreaktor::getProvidedLokalReference(); + $cache = reaktorCache::singleton($hash); + $retval = $cache->get(); + + if (!$retval || is_null(current($retval))) + { + $retval = current(self::doSelectJoinReaktorArtwork($c)); + $cache->set($retval); + } + return $retval; + } + } + + /** + * Get an artworks recommendations + * + * @param integer $id + * @return array RecommendedArtwork + */ + public static function getArtworkRecommendations($id) + { + + $c = new Criteria(); + + $c->add(parent::ARTWORK, $id); + + return RecommendedArtworkPeer::doSelectAllRecommendedArtwork($c); + + } + + /** + * Get a subreaktor's recommendation + * (should only be one per subreaktor, and lokalreaktor/subreaktor combination ) + * And it has to be approved + * + * @param int $subreaktor + * @param int $localsubreaktor + * @return array RecommendedArtwork + */ + public static function getSubreaktorRecommendation($subreaktor, $localsubreaktor = null) + { + $c = new Criteria(); + + $c->add(ReaktorArtworkPeer::STATUS, 3, Criteria::EQUAL); + $c->add(sfGuardUserPeer::SHOW_CONTENT, true, Criteria::EQUAL); + $c->add(parent::SUBREAKTOR, $subreaktor); + if($localsubreaktor) + { + $c->add(parent::LOCALSUBREAKTOR, $localsubreaktor); + } + return parent::doSelectJoinAll($c); + + } + + /** + * Add/update an artwork recommendation + * + * @param int $id + * @param int $subreaktor + * @param int $localsubreaktor + */ + public static function addRecommendation($user, $artwork, $subreaktor, $localsubreaktor = null) + { + //Create the new recommendation + $recommendation = new RecommendedArtwork(); + + $recommendation->setUpdatedBy($user); + $recommendation->setArtwork($artwork); + $recommendation->setSubreaktor($subreaktor); + $recommendation->setLocalsubreaktor($localsubreaktor); + $recommendation->save(); + + } + +} diff --git a/lib/model/RejectionType.php b/lib/model/RejectionType.php new file mode 100644 index 0000000..45089bf --- /dev/null +++ b/lib/model/RejectionType.php @@ -0,0 +1,23 @@ +setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + + /*public function __toString() + { + return $this->getName(); + }*/ +} diff --git a/lib/model/RejectionTypeI18n.php b/lib/model/RejectionTypeI18n.php new file mode 100644 index 0000000..2cb8dec --- /dev/null +++ b/lib/model/RejectionTypeI18n.php @@ -0,0 +1,12 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * + * @package lib.model + */ +class RelatedArtworkPeer extends BaseRelatedArtworkPeer +{ + /** + * Get Artworks related to an artwork + * + * @param genericArtwork|integer $artwork the artwork object or id + * @param integer $limit limit max results + * @param boolean $approved Whether to limit to approved only + * + * @return array Artwork objects + */ + public static function getRelatedArtworkObjects($artwork, $limit = 6, $approved = true) + { + if ($artwork instanceof genericArtwork || $artwork instanceof ReaktorArtwork ) + { + $artworkId = $artwork->getId(); + } + else + { + $artworkId = $artwork; + } + + $resultArray = array(); + + // First lets get the IDs of the related objects - we can't do a mega join here with Propel because of + // The double foreign key (Propel does not support table aliases yet) + $c = new Criteria(); + $critA = $c->getNewCriterion(RelatedArtworkPeer::FIRST_ARTWORK, $artworkId); + $critB = $c->getNewCriterion(RelatedArtworkPeer::SECOND_ARTWORK, $artworkId); + $critA->addOr($critB); + + $c->add($critA); + $relatedRows = RelatedArtworkPeer::doSelect($c); + + if (!$relatedRows) + { + return $resultArray; + } + + foreach($relatedRows as $relatedRow) + { + if ($relatedRow->getFirstArtwork() != $artworkId) + { + $relatedIds[] = $relatedRow->getFirstArtwork(); + } + else + { + $relatedIds[] = $relatedRow->getSecondArtwork(); + } + } + + // Now we have all the artwork IDs, we just need to retreive them + $c = new Criteria(); + $c->add(ReaktorArtworkPeer::ID, $relatedIds, Criteria::IN); + if ($limit !== null) + { + $c->setLimit($limit); + } + if ($approved) + { + $c->add(ReaktorArtworkPeer::STATUS, 3); + } + + $artworksArray = ReaktorArtworkPeer::doSelectJoinAll($c); + + sfContext::getInstance()->getLogger()->info("constructing a bunch of related artworks"); + foreach($artworksArray as $artwork) + { + $resultArray[] = new genericArtwork($artwork, null, array()); + } + return $resultArray; + } + + /** + * Returns $limit amount of artworks that other people who like $artworkId + * like too + * + * @param int $artworkId + * @param int $limit + * @return array(genericArtwork) + */ + public static function getOtherRelatedArtworkObjects($artworkId, $limit = 5) + { + $retval = $artworkIds = array(); + $favusers = new Favourite(); + + // Get the users who like the $artwork artwork + $favs = $favusers->getLastFavs("artwork", $artworkId, $limit); + + foreach($favs as $fav) + { + // This shouldn't actually ever not happen + if ($fav->getFavType() == 'artwork') + { + $userid = $fav->getSfGuardUserRelatedByUserId()->getId(); + // And then figure out which artworks $userid likes + foreach((array)$fav->getMyLastFavs("artwork", $userid, $limit) as $artwork) + { + $artworkIds[] = $artwork->getArtworkId(); + } + } + } + + // Nuke duped favourites + $artworkIds = array_unique($artworkIds); + + // _other_ related artworks does not include ourself + $k = array_search($artworkId, $artworkIds); + unset($artworkIds[$k]); + + $count = count($artworkIds); + if ($count == 0) + { + return $retval; + } + + // Do a little dance and get a random artworks + foreach((array)array_rand($artworkIds, $count > $limit ? $limit : $count) as $key) { + $retval[] = new genericArtwork($artworkIds[$key], null, array()); + } + + return $retval; + } + + /** + * Check if two artworks are related already + * + * @param int $artwork_id_1 + * @param int $artwork_id_2 + * @return boolean $relations True if they are related false if not + */ + public static function isRelated($artwork_id_1, $artwork_id_2) + { + if($artwork_id_1 == $artwork_id_2) //They are related if they are the same artwork + { + $is_related = true; + } + else + { + $relations = RelatedArtworkPeer::getRelation($artwork_id_1, $artwork_id_2); + + $is_related = $relations ? true : false; + } + return $is_related; + + } + + /** + * Get artwork relation given two id's + * + * @param int $artwork_id_1 + * @param int $artwork_id_2 + * + * @return array of related artwork objects + */ + public static function getRelation($artwork_id_1, $artwork_id_2) + { + $c = new Criteria(); + + $critA = $c->getNewCriterion(RelatedArtworkPeer::FIRST_ARTWORK, $artwork_id_1); + $critB = $c->getNewCriterion(RelatedArtworkPeer::SECOND_ARTWORK, $artwork_id_2); + $critA->addAnd($critB); + + $critC = $c->getNewCriterion(RelatedArtworkPeer::FIRST_ARTWORK, $artwork_id_2); + $critD = $c->getNewCriterion(RelatedArtworkPeer::SECOND_ARTWORK, $artwork_id_1); + $critC->addAnd($critD); + + $critA->addOr($critC); + $c->add($critA); + + return parent::doSelect($c); + } + + /** + * Delete relation(s) between two artworks, there should always + * be only one, but just in case.. + * + * @param int $artwork_id_1 + * @param int $artwork_id_2 + */ + public static function deleteRelation($artwork_id_1, $artwork_id_2) + { + $relations = RelatedArtworkPeer::getRelation($artwork_id_1, $artwork_id_2); + + foreach ($relations as $relation) + { + //delete relation + $c = new Criteria(); + $c->add(parent::ID, $relation->getId()); + UserResourcePeer::doDelete($c); + } + + } + + /** + * Add a relation between to artworks + * + * @param int $first_artwork reaktor_artwork.id + * @param int $second_artwork reaktor_artwork.id + * @param int $user sfGuardUser id + */ + public static function addRelatedArtwork($first_artwork, $second_artwork, $user) + { + $relatedartwork = new RelatedArtwork(); + $relatedartwork->setFirstArtwork($first_artwork); + $relatedartwork->setSecondArtwork($second_artwork); + $relatedartwork->setCreatedBy($user); + $relatedartwork->save(); + + } + + + +} diff --git a/lib/model/ReportBookmark.php b/lib/model/ReportBookmark.php new file mode 100644 index 0000000..0b0b1f0 --- /dev/null +++ b/lib/model/ReportBookmark.php @@ -0,0 +1,12 @@ +addAscendingOrderByColumn(self::LIST_ORDER); + $reports = self::doSelect($c); + $resultArray = array(); + + foreach ($reports as $report) + { + $resultArray[$report->getType()][$report->getId()] = $report; + } + + return $resultArray; + } +} diff --git a/lib/model/Residence.php b/lib/model/Residence.php new file mode 100644 index 0000000..4710854 --- /dev/null +++ b/lib/model/Residence.php @@ -0,0 +1,18 @@ +getName(); + } + +} diff --git a/lib/model/ResidenceLevel.php b/lib/model/ResidenceLevel.php new file mode 100644 index 0000000..eef48ca --- /dev/null +++ b/lib/model/ResidenceLevel.php @@ -0,0 +1,32 @@ +setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + + public function __toString() + { + return $this->getName(); + } +} diff --git a/lib/model/ResidenceLevelI18n.php b/lib/model/ResidenceLevelI18n.php new file mode 100644 index 0000000..85949f0 --- /dev/null +++ b/lib/model/ResidenceLevelI18n.php @@ -0,0 +1,12 @@ +addAscendingOrderByColumn(ResidenceLevelPeer::LISTORDER); + $c->addAscendingOrderByColumn(parent::NAME); + + $residences = parent::doSelectJoinAll($c); + + //Create nested array + $residence_array = array(); + foreach($residences as $residence) + { + $residence_array[$residence->getResidenceLevel()->getName()][$residence->getId()] = $residence->getName(); + } + return $residence_array; + + + } +} diff --git a/lib/model/Subreaktor.php b/lib/model/Subreaktor.php new file mode 100644 index 0000000..f892ee1 --- /dev/null +++ b/lib/model/Subreaktor.php @@ -0,0 +1,757 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +/** + * Helpful model functions for the subreaktor. + * + * PHP version 5 + * + * @author juneih + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ +class Subreaktor extends BaseSubreaktor +{ + /** + * List of subreaktors + * + * @var array + */ + static protected $_subreaktors = null; + + /** + * List of categories + * + * @var array + */ + protected $_categories = null; + + /** + * List of residences for this lokalreaktor + * + * @var array + */ + protected $_residences = null; + + /** + * List of filetypes to autodetect + * + * @var array + */ + protected $_filetypes = null; + + static protected $_lokalreaktor = null; + static protected $_subreaktor = null; + + public function hydrate(ResultSet $rs, $startcol = 1) + { + parent::hydrate($rs, $startcol); + $this->setCulture(sfContext::getInstance()->getUser()->getCulture()); + } + + /** + * To string returns the name of the subreaktor. + * + * @return void + */ + public function __toString() + { + return $this->getName(); + } + + static public function getAll() + { + if (self::$_subreaktors === null) + { + self::_populateSubReaktors(); + } + return self::$_subreaktors; + } + + static public function getAllAsReferences() + { + $retarr = array(); + foreach (self::getAll() as $areaktor) + { + $retarr[] = $areaktor->getReference(); + } + return $retarr; + } + + static public function getAllAsIndexedArray() + { + $subreaktors = self::getAll(); + $arr = array(); + foreach ($subreaktors as $subreaktor) + { + $arr[$subreaktor->getId()] = $subreaktor->getName(); + } + return $arr; + } + + static public function getByReference($reference) + { + if (self::$_subreaktors === null) + { + self::_populateSubReaktors(); + } + if (isset(self::$_subreaktors[$reference])) + { + return self::$_subreaktors[$reference]; + } + else + { + throw new Exception ("Trying to get a subreaktor that does not exist"); + } + } + + /** + * Returns a subreaktor by id + * + * @param integer $id + * + * @return Subreaktor + */ + static public function getById($id) + { + if (self::$_subreaktors === null) + { + self::_populateSubReaktors(); + } + foreach (self::$_subreaktors as $aSubreaktor) + { + if ($aSubreaktor->getId() == $id) + { + return $aSubreaktor; + } + } + } + + static public function _populateSubReaktors() + { + self::$_subreaktors = array(); + $c = new Criteria(); + $c->addAscendingOrderByColumn(SubreaktorPeer::SUBREAKTOR_ORDER); + $res = SubreaktorPeer::doSelectWithI18n($c); + foreach ($res as $r) + { + self::$_subreaktors[$r->getReference()] = $r; + } + } + + static public function isProvided() + { + if (self::$_subreaktor !== null || self::$_lokalreaktor !== null) + { + return true; + } + else + { + if (sfContext::getInstance()->getRequest()->getParameter('subreaktor') != '') + { + $providedreaktor = sfContext::getInstance()->getRequest()->getParameter('subreaktor'); + if (stristr($providedreaktor, '-') != '') + { + $providedreaktors = split('-', sfContext::getInstance()->getRequest()->getParameter('subreaktor')); + self::$_subreaktor = $providedreaktors[1]; + self::$_lokalreaktor = $providedreaktors[0]; + } + else + { + self::$_subreaktor = $providedreaktor; + } + return true; + } + else + { + return false; + } + } + } + + /** + * Adds the current subreaktor to route (if any). Does not return any value, just + * modifies the string directly. + * + * @param string $internal_uri + * + * @return void + */ + static public function addSubreaktorToRoute($internal_uri) + { + if (self::isValid()) + { + $internal_uri = substr($internal_uri, 1); + $internal_uri = '@subreaktor'.$internal_uri; + if (!stristr($internal_uri, '&subreaktor=')) + { + if (stristr($internal_uri, '#')) + { + $mark = substr($internal_uri, stripos($internal_uri, '#')); + $internal_uri = substr($internal_uri, 0, stripos($internal_uri, '#')); + $internal_uri .= (stristr($internal_uri, '?')) ? '&' : '?'; + $internal_uri .= 'subreaktor='.self::getProvided(); + $internal_uri .= $mark; + } + else + { + $internal_uri .= (stristr($internal_uri, '?')) ? '&' : '?'; + $internal_uri .= 'subreaktor='.self::getProvided(); + } + } + } + return $internal_uri; + } + + static public function isValid() + { + $retval = false; + if (self::isProvided()) + { + if (self::$_subreaktors === null) + { + self::_populateSubReaktors(); + } + if (self::$_lokalreaktor !== null && isset(self::$_subreaktors[self::$_lokalreaktor])) + { + if (!self::$_subreaktors[self::$_lokalreaktor]->getLokalReaktor()) + { + self::$_lokalreaktor = null; + } + $retval = true; + } + if (isset(self::$_subreaktors[self::$_subreaktor])) + { + if (self::$_subreaktors[self::$_subreaktor]->getLokalReaktor()) + { + self::$_lokalreaktor = self::$_subreaktor; + } + $retval = true; + } + } + return $retval; + } + + static public function getProvidedIfValid() + { + if (self::isValid()) + { + return self::getProvided(); + } + } + + static public function addProvidedLinkIfValid($url) + { + if (self::isValid()) + { + $url .= (stristr($url, '?')) ? '&' : '?'; + $url .= 'subreaktor='.self::getProvided(); + } + return $url; + } + + static function hasProvidedValidLokal() + { + if (self::isValid()) + { + if (self::$_lokalreaktor !== null) + { + return true; + } + } + return false; + } + + static function getProvidedLokalReference() + { + if (self::isValid() && self::$_lokalreaktor !== null) + { + return self::$_lokalreaktor; + } + } + + public function isLokalReaktor() + { + return $this->getLokalreaktor(); + } + /** + * Returns the provided lokalreaktor if it is valid + * + * @return Subreaktor + */ + static function getProvidedLokalreaktor() + { + if (self::isValid() && self::$_lokalreaktor !== null) + { + if (isset(self::$_subreaktors[self::$_lokalreaktor])) { + return self::$_subreaktors[self::$_lokalreaktor]; + } + } + return null; + } + + function getResidences() + { + if (self::isValid() && self::$_lokalreaktor !== null) + { + //return self::$_subreaktors[self::$_lokalreaktor]; + if ($this->_residences === null) + { + $this->_residences = array(); + foreach (self::$_subreaktors[self::$_lokalreaktor]->getLokalreaktorResidences() as $aResidence) + { + $this->_residences[] = $aResidence->getResidenceId(); + } + } + return $this->_residences; + } + } + + static function getProvidedSubreaktorReference() + { + if (self::isValid() && self::$_subreaktor !== null && self::$_subreaktor != self::$_lokalreaktor) + { + return self::$_subreaktor; + } + } + + /** + * Returns the provided subreaktor if it is valid + * + * @return Subreaktor + */ + static function getProvidedSubreaktor() + { + if (self::isValid() && self::$_subreaktor !== null) + { + if (self::$_subreaktor != self::$_lokalreaktor) + { + return self::$_subreaktors[self::$_subreaktor]; + } + } + return null; + } + + static public function getProvided() + { + if (self::isProvided()) + { + return sfContext::getInstance()->getRequest()->getParameter('subreaktor'); + } + else + { + return ''; + } + } + + /** + * Get categories + * + * @return array The categories + */ + public function getCategories() + { + if ($this->_categories === null) + { + $this->_populateCategories(); + } + return $this->_categories; + } + + public static function clear() + { + self::$_lokalreaktor = null; + self::$_subreaktor = null; + self::$_subreaktors = null; + } + + protected function _populateLokalReaktorCategories() + { + $c = new Criteria(); + + } + + protected function _populateCategories() + { + if ($this->_categories === null) + { + $this->_categories = array(); + } + + $this->_categories = CategorySubreaktorPeer::getCategoriesUsedBySubreaktor($this); + } + + public function getFiletypes() + { + if ($this->_filetypes === null) + { + $this->_populateFiletypes(); + } + return $this->_filetypes; + } + + protected function _populateFiletypes() + { + $this->_filetypes = array(); + $c = new Criteria(); + $c->add(SubreaktorIdentifierPeer::SUBREAKTOR_ID, $this->getId()); + $res = SubreaktorIdentifierPeer::doSelect($c); + foreach ($res as $r) + { + $this->_filetypes[$r->getIdentifier()] = $r->getIdentifier(); + } + } + + static protected function _preCreateCheck() + { + $template_path = SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'apps/reaktor/modules/subreaktors/templates/'; + $logo_path = sfConfig::get('sf_web_dir').'/images/'; + if (!file_exists($template_path.'subreaktorTemplate.php')) + { + throw new exception('Cannot find the template file for new subreaktors.'); + } + if (!file_exists($logo_path.'logoForside.gif')) + { + throw new exception('Cannot find the frontpage header.'); + } + return true; + } + + static protected function _createFiles($name, $reference) + { + $template_path = SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'apps/reaktor/modules/subreaktors/templates/'; + $logo_path = sfConfig::get('sf_web_dir').'/images/'; + if (!@copy($template_path.'subreaktorTemplate.php', $template_path.$reference.'ReaktorSuccess.php')) + { + throw new Exception("No write access to template folder"); + } + if (!@copy($logo_path.'logoForside.gif', $logo_path.'logo'.ucfirst($reference).'.gif')) + { + throw new Exception("No write access to logo folder"); + } + return true; + } + + static protected function _renameFiles($from, $to) + { + $template_path = SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'apps/reaktor/modules/subreaktors/templates/'; + $logo_path = sfConfig::get('sf_web_dir').'/images/'; + + $sprintf_file_path = $template_path.'%sReaktorSuccess.php'; + if (!@rename(sprintf($sprintf_file_path, $from), sprintf($sprintf_file_path, $to))) + { + throw new Exception("Can't rename in template folder"); + } + $sprintf_logo_path = $logo_path.'logo%s.gif'; + if (!@rename(sprintf($sprintf_logo_path, ucfirst($from)), sprintf($sprintf_logo_path, ucfirst($to)))) + { + throw new Exception("Can't rename in logo folder"); + } + return true; + } + + static protected function _postCreateCheck($name, $reference) + { + $template_path = SF_ROOT_DIR . DIRECTORY_SEPARATOR . 'apps/reaktor/modules/subreaktors/templates/'; + $logo_path = sfConfig::get('sf_web_dir').'/images/'; + if (!file_exists($template_path.$reference.'ReaktorSuccess.php')) + { + throw new exception('Cannot find the new template file for the subreaktor.'); + } + if (!file_exists($logo_path.'logo'.ucfirst($reference).'.gif')) + { + throw new exception('Cannot find the subreaktor header.'); + } + return true; + } + + public static function createNew($name, $reference) + { + try + { + self::_preCreateCheck(); + self::_createFiles($name, $reference); + self::_postCreateCheck($name, $reference); + } + catch (Exception $e) + { + throw $e; + } + $subreaktor = new Subreaktor(); + $subreaktor->setReference($reference); + $subreaktor->save(); + foreach (CataloguePeer::getCatalogues() as $aCatalogue) + { + $subreaktorname = new SubreaktorI18n(); + $subreaktorname->setName($name); + $subreaktorname->setSubreaktor($subreaktor); + $subreaktorname->setCulture($aCatalogue->getTargetLang()); + $subreaktorname->save(); + } + return $subreaktor; + } + + public function editReference($newreference) + { + try + { + self::_preCreateCheck(); + self::_renameFiles($this->getReference(), $newreference); + self::_postCreateCheck(null, $newreference); + $this->setReference($newreference); + } + catch (Exception $e) + { + throw $e; + } + return $this; + } + + /** + * List all subcategories per reaktor with number of artworks belonging + * to each subcategory. + * + * @param Subreaktor $subreaktor Subreaktor object + * @param int $count List count + * + * @return array $categories List of Categories and artwork count + */ + public static function listSubcategories($subreaktor, $count = null, &$categories = null, $lokalreaktor = null) + { + $c = new Criteria(); + $c->clearSelectColumns(); + $c->addSelectColumn(CategoryI18nPeer::NAME); + $c->addSelectColumn('count(distinct '.CategoryArtworkPeer::ARTWORK_ID.') as artworkcount'); + $c->add(CategoryI18nPeer::CULTURE, sfContext::getInstance()->getUser()->getCulture()); + + $c->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryI18nPeer::ID); + $c->addJoin(ReaktorArtworkPeer::ID, CategoryArtworkPeer::ARTWORK_ID); + $c->addjoin(CategorySubreaktorPeer::CATEGORY_ID, CategoryI18nPeer::ID); + $c->add(ReaktorArtworkPeer::STATUS, 3); + + if (!$subreaktor instanceof Subreaktor) + { + throw new Exception('Needs subreaktor object. If this is a lokalreaktor, + change the reference in the template to reference the $lokalreaktor variable, instead of $subreaktor'); + } + + $c->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $subreaktor->getId()); + $c->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID, Criteria::LEFT_JOIN); + + $c->addJoin(ReaktorArtworkPeer::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $subreaktor->getId()); + + if ($lokalreaktor !== null) + { + $c->addJoin(ReaktorArtworkPeer::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokalreaktor->getId()); + } + + if (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor || isset($options['lokalreaktor'])) + { + //$c->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID, Criteria::LEFT_JOIN); + + if (isset($options['lokalreaktor'])) + { + $c->addJoin(ReaktorArtworkPeer::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $options['lokalreaktor']->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $options['lokalreaktor']->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + elseif (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor) + { + $c->addJoin(ReaktorArtworkPeer::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedLokalreaktor()->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, Subreaktor::getProvidedLokalreaktor()->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + } + + } + + if ($count && is_int($count)) + { + $c->setLimit($count); + } + + $c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID, Criteria::LEFT_JOIN); + if (!sfContext::getInstance()->getUser()->hasCredential('viewallcontent')) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + } + + $c->addGroupByColumn(CategoryI18nPeer::ID); + $c->addDescendingOrderByColumn('artworkcount'); + $c->setDistinct(); + + $rs = CategoryArtworkPeer::doSelectRS($c); + + if ($categories === null) + { + $categories = array(); + } + + while($rs->next()) + { + $categories[$rs->getString(1)] = $rs->getInt(2); + } + + return $categories; + } + + /** + * List all subcategories per reaktor with number of artworks belonging + * to each subcategory. + * + * @param string $subreaktor Subreaktor name + * @param int $count List count + * + * @return array $categories List of Categories and artwork count + */ + public static function listLokalReaktorSubcategories($lokalreaktor, $count = null) + { + if (self::$_subreaktors === null) + { + self::_populateSubReaktors(); + } + //$lokalreaktor_id = self::getProvidedSubreaktorTagId($lokalreaktor); + $categories = array(); + + foreach (self::$_subreaktors as $aSubreaktor) + { + if (!$aSubreaktor->getLokalReaktor()) + { + //$resultset = array(); + $c = new Criteria(); + $c->clearSelectColumns(); + //$c->addSelectColumn('count('.SubreaktorArtworkPeer::ID.') as count_artworks'); + $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $aSubreaktor->getId()); + $c->addJoin(SubreaktorArtworkPeer::ARTWORK_ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN); + $c->addJoin(SubreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID); + $c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID, Criteria::LEFT_JOIN); + $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokalreaktor->getId()); + $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $lokalreaktor->getResidences(), Criteria::IN); + $ctn->addOr($ctn2); + $c->add($ctn); + //$c->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokalreaktor->getId()); + $c->add(ReaktorArtworkPeer::STATUS, 3); + if (!sfContext::getInstance()->getUser()->hasCredential('viewallcontent')) + { + $c->add(sfGuardUserPeer::SHOW_CONTENT, true); + } + + //$c->addGroupByColumn('count_artworks'); + $c->setDistinct(); + $artworksinsubreaktorandlokalreaktor = SubreaktorArtworkPeer::doCount($c); + //while ($resultset->next()) + //{ + if ($artworksinsubreaktorandlokalreaktor > 0) + { + $categories[$aSubreaktor->getName()] = array('reference' => $aSubreaktor->getReference(), 'count' => $artworksinsubreaktorandlokalreaktor); + } + } + } + //self::listSubcategories($lokalreaktor, $count, $categories); + return $categories; + } + + /** + * Delete a category + * + * @param integer $category The ID of the category + */ + function deleteCategory($category) + { + //echo "
    ";var_dump($this->getCategories());die(); 
    +    if (isset($this->_categories[$category]))
    +    {
    +      unset($this->_categories[$category]);
    +    }
    +    
    +    $c = new Criteria();
    +    $c->add(CategorySubreaktorPeer::CATEGORY_ID, $category);
    +    $c->add(CategorySubreaktorPeer::SUBREAKTOR_ID, self::getId());
    +    CategorySubreaktorPeer::doDelete($c);
    +  }
    +  
    +  /**
    +   * Add a category to this subreaktor
    +   *
    +   * @param category|integer $category The category to add
    +   */
    +  function addCategory($category = 0)
    +  {
    +    // Set up the category -> subreaktor relation
    +    $newcategorysubreaktorrelation = new CategorySubreaktor();
    +    if ($category instanceof Category )
    +    {
    +      $newcategorysubreaktorrelation->setCategory($category);
    +      $categoryId = $category->getId();  
    +    }
    +    elseif ($category > 0)
    +    {
    +      $newcategorysubreaktorrelation->setCategoryId($category);
    +      $categoryId = $category;
    +    }
    +    else
    +    {
    +      return false;    
    +    }
    +    
    +    // Check for existence of this category relationship already
    +    $c = new Criteria();
    +    $c->add(CategorySubreaktorPeer::CATEGORY_ID, $categoryId);
    +    $c->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +    
    +    sfLogger::getInstance()->debug('About to check for existing link');
    +    $existing = CategorySubreaktorPeer::doSelectOne($c);
    +       
    +    if (!$existing)
    +    {
    +      sfLogger::getInstance()->debug('Adding new relationship');
    +      $newcategorysubreaktorrelation->setSubreaktor($this);
    +      $newcategorysubreaktorrelation->save();
    +    }
    +  }
    +  
    +  /**
    +   * Delete a file type from the subreaktor identifiers table
    +   *
    +   * @param string $identifier The identifier (image, pdf etc)
    +   */
    +  public function deleteFileType($identifier)
    +  {
    +    $c = new Criteria();
    +    $c->add(SubreaktorIdentifierPeer::IDENTIFIER, $identifier);
    +    $c->add(SubreaktorIdentifierPeer::SUBREAKTOR_ID, $this->getId());
    +    SubreaktorIdentifierPeer::doDelete($c);
    +  }
    +  
    +  /**
    +   * Add a file type/identifier relationship
    +   *
    +   * @param string $identifier The identifier to add (image, pdf etc)
    +   */
    +  public function addFileType($identifier)
    +  {
    +    $c = new Criteria();
    +    $c->add(SubreaktorIdentifierPeer::IDENTIFIER, $identifier);
    +    $c->add(SubreaktorIdentifierPeer::SUBREAKTOR_ID, $this->getId());
    +    $res = SubreaktorIdentifierPeer::doSelect($c);
    +    if (empty($res))
    +    {
    +      SubreaktorIdentifierPeer::doInsert($c);
    +    }
    +  }
    +}
    diff --git a/lib/model/SubreaktorArtwork.php b/lib/model/SubreaktorArtwork.php
    new file mode 100644
    index 0000000..48a78e9
    --- /dev/null
    +++ b/lib/model/SubreaktorArtwork.php
    @@ -0,0 +1,12 @@
    +getId();
    +    }
    +    if ($artwork instanceof genericArtwork or $artwork instanceof ReaktorArtwork )
    +    {
    +      $artwork = $artwork->getId();
    +    }
    +    
    +    if (intval($artwork) < 1)
    +    {
    +      throw new exception ("Need an artwork ID");
    +    }
    +    
    +    
    +    $c = new Criteria();
    +    $c->add(self::SUBREAKTOR_ID, $subreaktor);
    +    $c->add(self::ARTWORK_ID, $artwork);
    +    
    +    if (!self::doSelectOne($c))
    +    {
    +      $subreaktorartworkitem = new SubreaktorArtwork();
    +      $subreaktorartworkitem->setArtworkId($artwork);
    +      $subreaktorartworkitem->setSubreaktorId($subreaktor);
    +      $subreaktorartworkitem->save();
    +    }
    +  }
    +
    +
    +   /**
    +   * Get all subreaktors an artwork belongs to
    +   *
    +   * @param integer $id
    +   * @return array SubreaktorArtwork
    +   */
    +  public static function getSubreaktorsByArtwork($id)
    +  {
    +    $c = new Criteria();
    +
    +    $c->add(parent::ARTWORK_ID, $id);
    +
    +    return parent::doSelectJoinAll($c);
    +  }
    +  
    +  
    +}
    diff --git a/lib/model/SubreaktorI18n.php b/lib/model/SubreaktorI18n.php
    new file mode 100644
    index 0000000..00d4c44
    --- /dev/null
    +++ b/lib/model/SubreaktorI18n.php
    @@ -0,0 +1,12 @@
    +getFiles();
    +      if (empty($files))
    +      {
    +        throw new exception ("Somehow this artwork has no files");
    +      }
    +    }
    +    else
    +    {
    +      if (is_object($artwork))
    +      {
    +        throw new Exception ("Unsupported: ".get_class($artwork));
    +      }
    +      throw new Exception ("Unsupported: ".$artwork);
    +    }
    +    
    +    $identifiers = array();
    +    
    +    // Check all the file types in this artwork
    +    foreach ($files as $file)
    +    {
    +      if (!in_array($file->getIdentifier(), $identifiers))
    +      {
    +        $identifiers[] = $file->getIdentifier();
    +      }
    +    }
    +    $c = new Criteria();
    +    $c->addJoin(SubreaktorIdentifierPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +// Exception for animated gifs 
    +if(($file->getMimetype() == "image/gif") ){
    +    $c1=$c->getNewCriterion(SubreaktorIdentifierPeer::IDENTIFIER, $identifiers, Criteria::IN);
    +    $c2=$c->getNewCriterion(SubreaktorPeer::REFERENCE, 'film');
    +
    +    $c1->addOr($c2);
    +    $c->add($c1);
    +
    +    } else {
    +    $c->add(SubreaktorIdentifierPeer::IDENTIFIER, $identifiers, Criteria::IN);
    +    
    +    }
    +
    +    $c->setDistinct();
    +    $c->add(SubreaktorPeer::LOKALREAKTOR, false);
    +    $c->add(SubreaktorPeer::LIVE, true);
    +
    +    $subreaktors = SubreaktorPeer::doSelectWithI18n($c);
    +
    +    if ($returnReferences)
    +    {
    +      $referencesResult = array();
    +      foreach ($subreaktors as $subreaktor)
    +      {
    +        $referencesResult[$subreaktor->getId()] = $subreaktor->getReference();  
    +      }
    +      return $referencesResult;
    +    }
    +   
    +    return $subreaktors; 
    +  }
    +}
    diff --git a/lib/model/SubreaktorPeer.php b/lib/model/SubreaktorPeer.php
    new file mode 100644
    index 0000000..54f4c5e
    --- /dev/null
    +++ b/lib/model/SubreaktorPeer.php
    @@ -0,0 +1,211 @@
    +add(SubreaktorPeer::REFERENCE, $reference);
    +    return parent::doSelectOne($c);
    +  }
    +
    +  /**
    +   * Add all of a table's columns to a query, using the given alias as table name.
    +   *
    +   * @param string $alias
    +   * @param Criteria $criteria
    +   */
    +  public static function addAliasSelectColumns( $alias, Criteria $criteria)
    +  {
    +    $criteria->addSelectColumn($alias.'.ID');
    +
    +    $criteria->addSelectColumn($alias.'.REFERENCE');
    +
    +    $criteria->addSelectColumn($alias.'.LOKALREAKTOR');
    +
    +    $criteria->addSelectColumn($alias.'.LIVE');
    +
    +    $criteria->addSelectColumn($alias.'.SUBREAKTOR_ORDER');
    +  }
    +
    +
    +
    +
    +  /**
    +   * Get all the local and sub Reaktors
    +   *
    +   * @param boolean $referenceArray if true return array of references not objects
    +   */
    +  public static function getAllReaktors($referenceArray = false,$active_only=false)
    +  {
    +    $c = new Criteria();
    +
    +
    +     if ($active_only)
    +    {
    +      $c->add(SubreaktorPeer::LIVE,1);
    +    }
    +
    +    $result = self::doSelect($c);
    +    if ($referenceArray)
    +    {
    +      $returnArray = array();
    +      foreach ($result as $resultRow)
    +      {
    +        $returnArray[$resultRow->getId()] = $resultRow->getReference();
    +      }
    +      return $returnArray;
    +    }
    +
    +    return $result;
    +  }
    +
    +
    +
    +
    +
    +
    +  /**
    +   * Get all the local Reaktors
    +   *
    +   * @param boolean $referenceArray if true return array of references not objects
    +   */
    +  public static function getLokalReaktors($referenceArray = false,$active_only=false)
    +  {
    +    $c = new Criteria();
    +    $c->add(self::LOKALREAKTOR, 1);
    +    
    +
    +     if ($active_only)
    +    {
    +      $c->add(SubreaktorPeer::LIVE,1);
    +    }
    +
    +    $result = self::doSelect($c);
    +    if ($referenceArray)
    +    {
    +      $returnArray = array();
    +      foreach ($result as $resultRow)
    +      {
    +        $returnArray[$resultRow->getId()] = $resultRow->getReference();
    +      }
    +      return $returnArray;
    +    }
    +    
    +    return $result;
    +  }
    +
    +  /**
    +   * Get all the local Reaktors
    +   *
    +   * @param boolean $referenceArray if true return array of references not objects
    +   */
    +  public static function getSubReaktors($referenceArray = false,$active_only=false)
    +  {
    +    $c = new Criteria();
    +    $c->add(self::LOKALREAKTOR, 0);
    +    $c->addAscendingOrderByColumn(parent::SUBREAKTOR_ORDER);
    +    if ($active_only)
    +    {
    +      $c->add(SubreaktorPeer::LIVE,1);
    +    }
    +    $result = self::doSelect($c);
    +    
    +    if ($referenceArray)
    +    {
    +      $returnArray = array();
    +      foreach ($result as $resultRow)
    +      {
    +        $returnArray[$resultRow->getId()] = $resultRow->getReference();
    +      }
    +      return $returnArray;
    +    }
    +    
    +    return $result;
    +  }
    +
    +  
    +  /**
    +   * Get eligable the local Reaktors
    +   *
    +   * @param boolean $referenceArray if true return array of references not objects
    +   */
    +  public static function getEligibleLokalReaktors($artwork)
    +  {
    +    $c = new Criteria();
    +    $c->add(self::LOKALREAKTOR, 1);
    +    $c->addJoin(LokalreaktorResidencePeer::SUBREAKTOR_ID,self::ID);
    +    $c->add(LokalreaktorResidencePeer::RESIDENCE_ID, $artwork->getUser()->getResidenceId());
    +    $result = self::doSelect($c);
    +    
    +    return $result;
    +  }
    +  
    +  public static function doSelectLokalReaktors()                         
    +  {
    +    $c = new Criteria();
    +    $c->add(self::LOKALREAKTOR, 1);
    +    
    +    return parent::doSelect($c);
    +  }
    +
    +  /**
    +   * Get live reaktors
    +   *
    +   * @param string $mode all|LokalReaktor|subReaktor
    +   * @return array SubReaktor Objects - Query result
    +   */
    +  public static function getLiveReaktors($mode = 'all',$order = 'asc')
    +  {
    +    $c = new Criteria();
    +    
    +    $c->add(parent::LIVE, 1, Criteria::EQUAL);
    +    
    +    if ($mode == 'LokalReaktor')
    +    {
    +      $c->add(parent::LOKALREAKTOR, 1, Criteria::EQUAL);
    +    }
    +    elseif ( $mode == 'subReaktor')
    +    {
    +      $c->add(parent::LOKALREAKTOR, 0, Criteria::EQUAL);
    +    }
    +    if ( $order == 'asc' )
    +    {
    +      $c->addAscendingOrderByColumn(parent::SUBREAKTOR_ORDER);
    +    } else 
    +    {
    +      $c->addDescendingOrderByColumn(parent::SUBREAKTOR_ORDER);
    +    }
    +    return parent::doSelect($c);
    +  }
    +  
    +  /**
    +   * Get live reaktors
    +   *
    +   * @param string $mode all|LokalReaktor|subReaktor
    +   * @return array SubReaktor Objects - Query result
    +   */
    +  public static function getNotLiveReaktors($mode = 'all')
    +  {
    +    $c = new Criteria();
    +    
    +    $c->add(parent::LIVE, 0, Criteria::EQUAL);
    +    
    +    if ($mode == 'LokalReaktor')
    +    {
    +      $c->add(parent::LOKALREAKTOR, 1, Criteria::EQUAL);
    +    }
    +    elseif ( $mode == 'subReaktor')
    +    {
    +      $c->add(parent::LOKALREAKTOR, 0, Criteria::EQUAL);
    +    }
    +    return parent::doSelect($c);
    +  }
    +}
    diff --git a/lib/model/TagPeer.php b/lib/model/TagPeer.php
    new file mode 100644
    index 0000000..1a6ef12
    --- /dev/null
    +++ b/lib/model/TagPeer.php
    @@ -0,0 +1,966 @@
    +
    + * 
    + * For the full copyright and license information, please view the LICENSE
    + * file that was distributed with this source code.
    + */
    +
    +/**
    + * Subclass for performing query and update operations on the 'tag' table.
    + * 
    + * @package plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model
    + */ 
    +class TagPeer extends BaseTagPeer
    +{ 
    +  /**
    +   * Returns all tags, eventually with a limit option.
    +   * The first optional parameter permits to add some restrictions on the 
    +   * objects the selected tags are related to.
    +   * The second optionnal parameter permits to restrict the tag selection with
    +   * different criterias
    +   * 
    +   * @param      Criteria    $c
    +   * @param      array       $options
    +   * @return     array
    +   */
    +  public static function getAll(Criteria $c = null, $options = array())
    +  {
    +    if ($c == null)
    +    {
    +      $c = new Criteria();
    +    }
    +
    +    if (isset($options['limit']))
    +    {
    +      $c->setLimit($options['limit']);
    +    }
    +
    +    if (isset($options['like']))
    +    {
    +      $c->add(TagPeer::NAME, $options['like'], Criteria::LIKE);
    +    }
    +
    +    self::addReaktorsToCriteria($c);
    +    
    +    return TagPeer::doSelect($c);
    +  }
    +  
    +  /**
    +   * Returns weighted popular tags with number of hits
    +   *
    +   * @return array
    +   */
    +  public static function getPopularTagsWithCount($limit = 50, $maxchars = 2000)
    +  {
    +    $c = new Criteria();
    +    $c->setLimit($limit);
    +    $popular_tags = array();
    +    
    +    $popular_tags_with_widths = TagPeer::getAllWithCount($c, array("return_widths" => true));
    +
    +    /**
    +     * Since we added widths to this, it breaks the normalisation function, so we need to strip them out first
    +     */ 
    +    foreach ($popular_tags_with_widths as $tagName => $valuesArray)
    +    {
    +      $popular_tags[$tagName] = $valuesArray["count"];
    +    }
    +    
    +    $normalized_popular_tags = sfPropelActAsTaggableToolkit::normalize($popular_tags);
    +    
    +    $poptags   = array();
    +    $charCount = 0; 
    +    
    +    foreach ($normalized_popular_tags as $poptag => $value)
    +    {
    +      $charCount += $popular_tags_with_widths[$poptag]["width"];
    +      if ($charCount > $maxchars)
    +      {
    +        break;
    +      }
    +
    +      $displayName = $poptag;
    +
    +      $poptags[$poptag] = array('emphasisValue' => $value, 'count' => $popular_tags[$poptag], 'displayName' => $displayName);
    +    }
    +    
    +    return $poptags;
    +  }
    +  
    +  /**
    +   * Returns all tags, sorted by name, with their number of occurencies.
    +   * The first optionnal parameter permits to add some restrictions on the 
    +   * objects the selected tags are related to.
    +   * The second optionnal parameter permits to restrict the tag selection with
    +   * different criterias
    +   * 
    +   * @param      Criteria    $c
    +   * @param      array       $options
    +   * @return     array
    +   */
    +  public static function getAllWithCount(Criteria $c = null, $options = array())
    +  {
    +    $tags = array();
    +
    +    foreach(array('ReaktorArtwork', 'ReaktorFile', 'Article') as $taggable_obj)
    +    {
    +	    $c = new Criteria();
    +	
    +	    $c->addJoin(TagPeer::ID, TaggingPeer::TAG_ID);
    +	    $c->add(TagPeer::APPROVED, 1);
    +	    $c->add(TaggingPeer::PARENT_APPROVED, 1);
    +
    +	    $c->add(TaggingPeer::TAGGABLE_MODEL, $taggable_obj);
    +	    
    +	    if (isset($options['like']))
    +	    {
    +	      $c->add(TagPeer::NAME, $options['like'], Criteria::LIKE);
    +	    }
    +	    self::addReaktorsToCriteria($c, $taggable_obj, $options);
    +    
    +	    $c->addSelectColumn(TagPeer::NAME);
    +	    $c->addSelectColumn(TagPeer::WIDTH);
    +	    $c->addSelectColumn(TaggingPeer::COUNT);
    +			
    +	    $c->addGroupByColumn(TaggingPeer::TAG_ID);
    +	    $c->addDescendingOrderByColumn(TaggingPeer::COUNT);
    +	    $c->addAscendingOrderByColumn(TagPeer::NAME);
    +	
    +	    $c->addJoin(TaggingPeer::PARENT_USER_ID, sfGuardUserPeer::ID, Criteria::JOIN);
    +	    if (!sfContext::getInstance()->getUser()->hasCredential('viewallcontent'))
    +	    {
    +	      $c->add(sfGuardUserPeer::SHOW_CONTENT, true);
    +	    }
    +	    
    +	    $rs = TagPeer::doSelectRS($c);
    +	 
    +	    while ($rs->next())
    +	    {
    +	      if (isset($options["return_widths"]))
    +	      {
    +	        //$tags[$rs->getString(1)]["count"]        += $rs->getInt(3);
    +	        (isset($tags[$rs->getString(1)]["count"])) ? $tags[$rs->getString(1)]["count"] += $rs->getInt(3) : $tags[$rs->getString(1)]["count"] = $rs->getInt(3);
    +	        $tags[$rs->getString(1)]["width"]        = $rs->getInt(2);
    +				}
    +	      else
    +	      {
    +	        (isset($tags[$rs->getString(1)])) ? $tags[$rs->getString(1)] += $rs->getInt(3) : $tags[$rs->getString(1)] = $rs->getInt(3);
    +	      }
    +	    }
    +    }
    +    
    +    arsort($tags);
    +    if (count($tags) > 30)
    +    {
    +    	$tags = array_slice($tags, 0, 30);
    +    }
    +    
    +    $ret_tags = array();
    +    
    +    while (count($ret_tags) <= 30 && count($tags) > 0)
    +    {
    +    	$rand_key = array_rand($tags);
    +    	$ret_tags[$rand_key] = $tags[$rand_key];
    +    	unset($tags[$rand_key]);
    +    }
    +    
    +    return $ret_tags;
    +  }
    +
    +  /**
    +   * Returns the names of the models that have instances tagged with one or 
    +   * several tags. The optionnal parameter might be a string, an array, or a 
    +   * comma separated string
    +   * 
    +   * @param      mixed       $tags
    +   * @return     array
    +   */
    +  public static function getModelsTaggedWith($tags = array())
    +  {
    +    if (is_string($tags))
    +    {
    +      if (false !== strpos($tags, ','))
    +      {
    +        $tags = explode(',', $tags);
    +      }
    +      else
    +      {
    +        $tags = array($tags);
    +      }
    +    }
    +
    +    $c = new Criteria();
    +    $c->addJoin(TagPeer::ID, TaggingPeer::TAG_ID);
    +    $crit0 = $c->add(TagPeer::NAME, $tags, Criteria::IN);
    +  
    +    $crit0->addOr($crit0);
    +    $c->add($crit0);
    +   
    +    $c->addGroupByColumn(TaggingPeer::TAGGABLE_ID);
    +    $having = $c->getNewCriterion(TagPeer::COUNT, count($tags), Criteria::GREATER_EQUAL);
    +    $c->addHaving($having);
    +    $c->clearSelectColumns();
    +    $c->addSelectColumn(TaggingPeer::TAGGABLE_MODEL);
    +    $c->addSelectColumn(TaggingPeer::TAGGABLE_ID);
    +
    +    $sql = BasePeer::createSelectSql($c, array());
    +    $con = Propel::getConnection();
    +    $stmt = $con->prepareStatement($sql);
    +    $position = 1;
    +
    +    foreach ($tags as $tag)
    +    {
    +      $stmt->setString($position, $tag);
    +      $position++;
    +    }
    +
    +    $stmt->setString($position, count($tags));
    +    $rs = $stmt->executeQuery(ResultSet::FETCHMODE_NUM);
    +    $models = array();
    +
    +    while ($rs->next())
    +    {
    +      $models[] = $rs->getString(1);
    +    }
    +
    +    return $models;
    +  }
    +
    +  /**
    +   * Returns the most popular tags with their associated weight. See 
    +   * sfPropelActAsTaggableToolkit::normalize for more details.
    +   * 
    +   * The first optionnal parameter permits to add some restrictions on the 
    +   * objects the selected tags are related to.
    +   * The second optionnal parameter permits to restrict the tag selection with
    +   * different criterias
    +   * 
    +   * @param      Criteria    $c
    +   * @param      array       $options
    +   * @return     array
    +   */
    +  public static function getPopulars($c = null, $options = array())
    +  {
    +    if ($c == null)
    +    {
    +      $c = new Criteria();
    +    }
    +
    +    if (!$c->getLimit())
    +    {
    +      $c->setLimit(sfConfig::get('app_home_max_tags', 100));
    +    }
    +
    +    $all_tags = TagPeer::getAllWithCount($c, $options);
    +    return sfPropelActAsTaggableToolkit::normalize($all_tags);
    +  }
    +
    +  /**
    +   * Returns the tags that are related to one or more other tags, with their 
    +   * associated weight (see sfPropelActAsTaggableToolkit::normalize for more 
    +   * details).
    +   * The "related tags" of one tag are the ones which have at least one 
    +   * taggable object in common.
    +   * 
    +   * The first optionnal parameter permits to add some restrictions on the 
    +   * objects the selected tags are related to.
    +   * The second optionnal parameter permits to restrict the tag selection with
    +   * different criterias
    +   * 
    +   * @param      mixed       $tags
    +   * @param      array       $options
    +   * @return     array
    +   */
    +  public static function getRelatedTags($tags = array(), $options = array())
    +  {
    +  	$tags = sfPropelActAsTaggableToolkit::explodeTagString($tags);
    +
    +    if (is_string($tags))
    +    {
    +      $tags = array($tags);
    +    }
    +
    +    $tagging_options = $options;
    +
    +    if (isset($tagging_options['limit']))
    +    {
    +      unset($tagging_options['limit']);
    +    }
    +
    +    $taggings = self::getTaggings($tags, $tagging_options);
    +    $result = array();
    +
    +    foreach ($taggings as $key => $tagging)
    +    {
    +      $c = new Criteria();
    +      $c->add(TagPeer::NAME, $tags, Criteria::NOT_IN);
    +      $c->add(TagPeer::APPROVED, 1);
    +      $c->add(TaggingPeer::TAGGABLE_ID, $tagging, Criteria::IN);
    +      $c->add(TaggingPeer::TAGGABLE_MODEL, $key);
    +      $c->addJoin(TaggingPeer::TAG_ID, TagPeer::ID);
    +      
    +      if (isset($options['parent_approved']))
    +      {
    +      	$c->add(TaggingPeer::PARENT_APPROVED, $options['parent_approved']);
    +      }
    +
    +      self::addReaktorsToCriteria($c, $key);
    +      
    +      $tags = TagPeer::doSelect($c);
    +
    +      foreach ($tags as $tag)
    +      {
    +        if (!isset($result[$tag->getName()]))
    +        {
    +          $result[$tag->getName()] = 0;
    +        }
    +
    +        $result[$tag->getName()]++;
    +      }
    +    }
    +
    +    if (isset($options['limit']))
    +    {
    +      arsort($result);
    +      $result = array_slice($result, 0, $options['limit'], true);
    +    }
    +
    +    ksort($result);
    +    return sfPropelActAsTaggableToolkit::normalize($result);
    +  }
    +
    +  /**
    +   * Retrieves the objects tagged with one or several tags.
    +   * 
    +   * The second optionnal parameter permits to restrict the tag selection with
    +   * different criterias
    +   * 
    +   * @param      mixed       $tags
    +   * @param      array       $options
    +   * @return     array
    +   */
    +  public static function getTaggedWith($tags = array(), $options = array())
    +  {
    +  	$taggings = self::getTaggings($tags, $options);
    +    $result = array();
    +
    +    foreach ($taggings as $key => $tagging)
    +    {
    +      $c = new Criteria();
    +      $peer = get_class(call_user_func(array(new $key, 'getPeer')));
    +      $objects = call_user_func(array($peer, 'retrieveByPKs'), $tagging);
    +
    +      foreach ($objects as $object)
    +      { 
    +        if ($object instanceof ReaktorArtwork )
    +        {
    +          $tmp_artwork = new genericArtwork($object);
    +          if ($tmp_artwork->isViewable())
    +          {
    +          	$result[] = $tmp_artwork;
    +          }
    +        }
    +        elseif ($object instanceof ReaktorFile )
    +        {
    +          $result[] = new artworkFile($object);
    +        }
    +        elseif ($object instanceof Article )
    +        {
    +          $result[] = $object;
    +        }
    +        else
    +        {
    +          throw new Exception("Unhandled object type: ".get_class($object));
    +        }
    +      }
    +    }
    +
    +    return $result;
    +  }
    +  
    +  public static function getObjectsTaggedWith($tags = array(), $options = array(), $artworks_only = false)
    +  {
    +  	$taggings    = self::getTaggings($tags, $options);
    +  	$result      = array();
    +  	$artworks    = false;
    +    $artwork_ids = array();
    +    $ids         = array();
    +
    +    foreach ($taggings as $key => $tagging)
    +    {
    +      if ($key == "ReaktorFile" || $key == "ReaktorArtwork")
    +      {
    +	      if ($key == "ReaktorFile")
    +	      {
    +	        $objects = genericArtwork::getResultsetFromIDs($tagging, array('isfileid' => true));
    +	      }
    +	      else
    +	      {
    +	      	$objects = genericArtwork::getResultsetFromIDs($tagging);
    +	      }
    +      	foreach ($objects as $object)
    +	    	{
    +          try
    +          {
    +            $artwork = new genericArtwork($object);
    +            if ($artwork->isViewable())
    +            {
    +              $artwork_ids[$artwork->getId()] = $artwork->getId();
    +              $result[$artwork->getId()] = $artwork;
    +            }
    +          }
    +          catch (Exception $e) { } // ignore artwork if exception thrown
    +	    	}
    +      }
    +      elseif(!$artworks_only)
    +      {
    +        try
    +    	  {
    +  	      // We can try to get the object anyway - this works for articles, and should work for future things
    +	  	     foreach ($tagging as $id) 
    +	  	     {
    +	      	      $object = call_user_func($key . 'Peer::retrieveByPk', $id); 
    +	              $result[$object->getId()] = $object;
    +	  	     }
    +    	 }
    +    	  catch (exception $e) { print_r($e);} // We can't process this tag for whatever reason, so we wont
    +      }
    +    }
    +
    +  	if (isset($options['return_ids']))
    +  	{
    +  		return $artwork_ids;
    +  	}
    +  	else
    +  	{
    +  		return $result;
    +  	}
    +  }
    +
    +  public static function addReaktorsToCriteria(&$c, $model = null, $options = array())
    +  {
    +      $taggable_obj = $model;
    +      $subr_value = null;
    +      $lokr_value = null;
    +      
    +  	  if (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor || 
    +          Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor ||
    +          isset($options['subreaktor']) ||
    +          isset($options['lokalreaktor']))
    +      {
    +        if ($taggable_obj == 'ReaktorFile')
    +        {
    +          $c->addJoin(TaggingPeer::TAGGABLE_ID, ReaktorArtworkFilePeer::FILE_ID, Criteria::LEFT_JOIN);
    +        }
    +      }
    +
    +      if (isset($options['subreaktor']))
    +      {
    +        $subr_value = $options['subreaktor']->getId();
    +      }
    +      elseif (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor)
    +      {
    +        $subr_value = Subreaktor::getProvidedSubreaktor()->getId();
    +      }
    +      if ($subr_value !== null)
    +      {
    +        switch ($taggable_obj)
    +        {
    +          case 'ReaktorArtwork':
    +            $c->addJoin(TaggingPeer::TAGGABLE_ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN);
    +            $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $subr_value);
    +            break;
    +          case 'ReaktorFile':
    +            $c->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN);
    +            $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $subr_value);
    +            break;
    +          case 'Article':
    +            $c->addJoin(TaggingPeer::TAGGABLE_ID, ArticleSubreaktorPeer::ARTICLE_ID, Criteria::LEFT_JOIN);
    +            $c->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, $subr_value);
    +            break;
    +        }
    +      }
    +      
    +      if (isset($options['lokalreaktor']))
    +      {
    +        $lokr_value = $options['lokalreaktor']->getId();
    +        $lokr_residences = $options['lokalreaktor']->getResidences();
    +      }
    +      elseif (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor)
    +      {
    +        $lokr_value = Subreaktor::getProvidedLokalreaktor()->getId();
    +        $lokr_residences = Subreaktor::getProvidedLokalreaktor()->getResidences();
    +      }
    +      if ($lokr_value !== null)
    +      {
    +        switch ($taggable_obj)
    +        {
    +          case 'ReaktorArtwork':
    +            $c->addJoin(TaggingPeer::TAGGABLE_ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN);
    +            $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN);
    +            $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokr_value);
    +//        Ticket 25014 - Limited search result
    +//            $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $lokr_residences, Criteria::IN);
    +//            $ctn->addOr($ctn2);
    +            $c->add($ctn);
    +            break;
    +          case 'ReaktorFile':
    +            $c->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN);
    +            $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN);
    +            $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokr_value);
    +//        Ticket 25014 - Limited search result
    +//            $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $lokr_residences, Criteria::IN);
    +//            $ctn->addOr($ctn2);
    +            $c->add($ctn);
    +            break;
    +        }
    +      }
    +  	return $c;
    +  }
    +  
    +  /**
    +   * Returns the taggings associated to one tag or a set of tags.
    +   * 
    +   * The second optionnal parameter permits to restrict the results with
    +   * different criterias
    +   * 
    +   * @param      mixed       $tags
    +   * @param      array       $options
    +   * @return     array
    +   */
    +  private static function getTaggings($tags = array(), $options = array())
    +  {
    +    $tags = sfPropelActAsTaggableToolkit::explodeTagString($tags);
    +    
    +    $vals = array();
    +    if (is_string($tags))
    +    {
    +      $tags = array($tags);
    +    }
    +     
    +    $taggings = array();
    +  
    +    foreach(array('ReaktorArtwork', 'ReaktorFile', 'Article') as $taggable_obj)
    +    {
    +    	
    +	    $c = new Criteria();
    +	    $c->addJoin(TagPeer::ID, TaggingPeer::TAG_ID);
    +	    $c->add(TagPeer::NAME, $tags, Criteria::IN);
    +	    
    +	    /**
    +	     * loop through the different options
    +	     */
    +      if (isset($options['parent_approved']) && $taggable_obj !== 'Article' )
    +      {
    +        // Users should see their own unapproved artworks too
    +        if ($user = sfContext::getInstance()->getUser())
    +        {
    +          $approved = $c->getNewCriterion(TaggingPeer::PARENT_APPROVED, $options['parent_approved']);
    +          $mytags = $c->getNewCriterion(TaggingPeer::PARENT_USER_ID, $user->getId());
    +          $approved->addOr($mytags);
    +          $c->add($approved);
    +        }
    +        else
    +        {
    +          $c->add(TaggingPeer::PARENT_APPROVED, $options['parent_approved']);
    +        }
    +      }
    +	    
    +      $c->add(TaggingPeer::TAGGABLE_MODEL, $taggable_obj);
    +      
    +	    if (isset($options["approved"]))
    +	    {
    +	      $c->add(TagPeer::APPROVED, 1);
    +	    }
    +	    
    +	    self::addReaktorsToCriteria($c, $taggable_obj, $options);
    +	    $c->add(TaggingPeer::TAGGABLE_MODEL, $taggable_obj);
    +	    $c->addGroupByColumn(TaggingPeer::TAGGABLE_ID);
    +	    $having = $c->getNewCriterion(TagPeer::ID, ' COUNT(tag.ID) >= ' . 1, Criteria::CUSTOM);
    +	    $c->addHaving($having);
    +	    
    +	    $c->addDescendingOrderByColumn(TaggingPeer::TAGGABLE_ID);
    +	    
    +	    $res = TaggingPeer::doSelect($c);
    +	    foreach ($res as $row)
    +	    {
    +	    	$model = $row->getTaggableModel();
    +	
    +	      if (!isset($taggings[$model]))
    +	      {
    +	        $taggings[$model] = array();
    +	      }
    +	
    +	      $taggings[$model][] = $row->getTaggableId();
    +	    }
    +    }
    +   
    +   return $taggings;
    +  }
    +
    +  /**
    +   * Retrives a tag object by it's name.
    +   * 
    +   * @param      String      $tagname
    +   * @return     Tag
    +   */
    +  public static function retrieveByTagname($tagname,$binary=false)
    +  {
    +    $c = new Criteria();
    +    if ($binary)
    +    {
    +    	$c->add(TagPeer::NAME, "BINARY CONVERT(name USING utf8)='$tagname'",Criteria::CUSTOM);
    +    } else
    +    {
    +    	$c->add(TagPeer::NAME, $tagname);
    +    }
    +    return TagPeer::doSelectOne($c);
    +  }
    +  
    +  /**
    +   * Approve a tag
    +   *
    +   * @param string  $tagname The tag to approve
    +   * @param integer $userId  The id of the user approving 
    +   */
    +  public static function approveTagByName($tagname, $userId)
    +  {
    +    $tagObject = TagPeer::retrieveByTagname($tagname);
    +    
    +    $tagObject->setApproved(1);
    +    $tagObject->setApprovedAt(time());
    +    $tagObject->setApprovedBy($userId);
    +    $tagObject->save();
    +
    +    // We also need to approve any links between files and tags
    +    $taggedObjects = self::getTaggedWith(array($tagname));
    +    
    +    foreach($taggedObjects as $taggedObject)
    +    {
    +      $model = false;
    +      
    +      if ($taggedObject instanceof genericArtwork )
    +      {
    +        reaktorCache::delete("artwork_tag_list_".$taggedObject->getId());
    +        if ($taggedObject->getStatus() == 3)
    +        {
    +          TaggingPeer::setTaggingApproved($tagObject, "ReaktorArtwork", $taggedObject->getId());
    +        }
    +      }
    +      elseif ($taggedObject instanceof artworkFile )
    +      {
    +        if ($taggedObject->hasArtwork())
    +        {
    +          foreach($taggedObject->getParentArtworks() as $artwork)
    +          {
    +            reaktorCache::delete("artwork_tag_list_".$artwork->getId());
    +            if ($artwork->getStatus() == 3)
    +            {
    +              TaggingPeer::setTaggingApproved($tagObject, "ReaktorFile", $taggedObject->getId());
    +            }
    +          }
    +        }
    +        $taggedObject->updateTagMetaData();
    +      }
    +      elseif ($taggedObject instanceof Article )
    +      {
    +        if ($taggedObject->isPublished())
    +        {
    +          TaggingPeer::setTaggingApproved($tagObject, "Article", $taggedObject->getId());
    +        }
    +      }
    +      else
    +      {
    +        sfContext::getInstance()->getLogger()->info("Unsupported object passed in tagpeer: ".get_class($taggedObject));
    +        continue;
    +      }
    +    }
    +  }
    +  
    +  public static function getNumberofTagsByApprovedStatus($status = 0)
    +  {
    +    $c = new Criteria();
    +    $c->add(TagPeer::APPROVED, $status);
    +    return TagPeer::doCount($c);
    +  }
    +  
    +  /**
    +   * Set the tag width for speedier checking of tag clouds
    +   *
    +   * @param string $tagname
    +   */
    +  public static function setTagWidthByName($tagname)
    +  {
    +    $tagObject = TagPeer::retrieveByTagname($tagname);
    +    
    +    if ($tagObject)
    +    {
    +      $tagObject->setWidth(mb_strlen($tagname, 'UTF-8'));
    +      $tagObject->save();
    +    }
    +  }
    +
    +  /**
    +   * Set the tag status
    +   *
    +   * @param string  $tagname The name of the tag
    +   * @param integer $status  The group id to set
    +   */
    +  public static function setTagGroupByName($tagname, $groupId)
    +  {
    +    $tagObject = TagPeer::retrieveByTagname($tagname);
    +    
    +    $tagObject->setTagGroupId($groupId);
    +    $tagObject->save(); 
    +  }
    +  
    +   /** Unapprove a tag (effectively deletes it)
    +   *
    +   * @param string  $tagname The tag to unapprove
    +   * 
    +   * @return null
    +   */
    +  public static function unapproveTagByName($tagname)
    +  {
    +    // We need to remove the tag from Dublin Core metadata in all the files that have it
    +    $taggedObjects = self::getTaggedWith($tagname);
    +    
    +    $tagObject = TagPeer::retrieveByTagname($tagname);
    +    TaggingPeer::deleteLinks($tagObject->getId());
    +    $tagObject->delete();
    +    
    +    foreach ($taggedObjects as $taggedObject)
    +    {
    +      if ($taggedObject instanceof artworkFile )
    +      {
    +        $taggedObject->updateTagMetaData();
    +        foreach ($taggedObject->getParentArtworks() as $parent)
    +        {
    +          reaktorCache::delete("artwork_tag_list_".$parent->getId());
    +        }
    +      }
    +      elseif ($taggedObject instanceof genericArtwork )
    +      {
    +        reaktorCache::delete("artwork_tag_list_".$taggedObject->getId());
    +      }
    +    }
    +  }
    +  
    +  /**
    +   * Retrieves a tag by his name. If it does not exist, creates it (but does not
    +   * save it)
    +   * 
    +   * @param      String      $tagname
    +   * @return     Tag
    +    */
    +  public static function retrieveOrCreateByTagname($tagname)
    +  {
    +    // retrieve or create the tag
    +    $tag = TagPeer::retrieveByTagName($tagname);
    +
    +    if (!$tag)
    +    {
    +      $tag = new Tag();
    +      $tag->setName($tagname);
    +    }
    +
    +    return $tag;
    +  }
    +
    +  /**
    +   * Adds a new, approved, normal tag
    +   *
    +   * @param string  $name       tag to add
    +   * @param integer $approvedby Id of the sf_guard_user who approved it
    +   */
    +  public static function addNewApprovedTag($name, $approvedby = null)
    +  {
    +    $c = new Criteria();
    +    $c->add(TagPeer::NAME, $name);
    +    $tag = TagPeer::doSelect($c);
    +    if (!$tag)
    +    {
    +      $tag = new Tag();
    +      if ($approvedby !== null)
    +      {
    +        $tag->setApproved(true);
    +        $tag->setApprovedBy($approvedby);
    +        $tag->setApprovedAt(time());
    +      }
    +      $tag->setName($name);
    +      $tag->setWidth(strlen($name));
    +      $tag->save();
    +
    +      return $tag;
    +    }
    +    else
    +    {
    +      return true;
    +    }
    +  }
    +  
    +/**
    +   * Get tags 
    +   *
    +   * @param object   $object tagged object
    +   * @param boolean  $list   whether to return an array of tag names instead of array of objects 
    +   * @param criteria $c      criteria to use if needed
    +   */
    +  public static function getTagsByObject($object, $list = false, $c = null)
    +  {
    +    if (is_null($c))
    +    {
    +      $c = new Criteria();
    +    }
    +    
    +    if ($object instanceof genericArtwork )
    +    {
    +      $taggable = "ReaktorArtwork";
    +    }
    +    elseif ($object instanceof artworkFile )
    +    {
    +      $taggable = "ReaktorFile";
    +    }
    +    else
    +    {
    +      $taggable = get_class($object);
    +    }
    +    
    +    $objectId = $object->getId();
    +    
    +    $c->add(TaggingPeer::TAGGABLE_MODEL, $taggable);
    +    $c->add(TaggingPeer::TAGGABLE_ID, $objectId);
    +    $c->addJoin(self::ID, TaggingPeer::TAG_ID);
    +    
    +    $tags = self::doSelect($c);
    +    
    +    if (!$list)
    +    {
    +      return $tags;
    +    }
    +    else
    +    {
    +      $returnArray = array();
    +      foreach($tags as $tag)
    +      {
    +        $returnArray[$tag->getId()] = $tag->getName();
    +      }
    +      return $returnArray;
    +    }
    +  }
    +
    +/**
    + * Get tags for ajax drop down list
    + *
    + * @param string  $tagStart The  entered characters for filtering
    + * @param array   $files         Files to exclude from the results (existing tags on the files)
    + * @param string  $taggableModel The taggable model of the above files/artworks/etc
    + * @param integer $approved      The approval status, or null to ignore
    + * @param integer $limit         limit on rows to return
    + */
    +  public static function getTagsStartingwithStringExludingTaggables($tagStart, $files = array(), $taggableModel = "ReaktorFile", $approved = 1, $limit = 10)
    +  {
    +    $c = new Criteria();
    +    
    +    if (!is_null($approved))
    +    {
    +      $c->add(TagPeer::APPROVED, $approved);
    +    }
    +    $c->add(self::NAME, "$tagStart%", Criteria::LIKE);
    +    
    +    $approved = $c->getNewCriterion(self::APPROVED, 1);
    +    $mytags = $c->getNewCriterion(TaggingPeer::PARENT_USER_ID, sfContext::getInstance()->getUser()->getId());
    +    $approved->addOr($mytags);
    +    $c->add($approved);
    +    $c->addJoin(self::ID, TaggingPeer::TAG_ID, Criteria::LEFT_JOIN);
    +
    +    $c->add(TagPeer::ID, TagPeer::ID. " NOT IN (
    +      SELECT tag_id
    +      FROM tagging
    +      WHERE (taggable_id IN (".implode(",", $files) . ")
    +      AND taggable_model = '".$taggableModel ."'))", Criteria::CUSTOM);
    +
    +    $c->setLimit($limit);
    +    $c->setDistinct();
    +    return self::getAll($c); 
    +  }
    +
    +  /**
    +   * Get all $approved tags starting with $tagStart
    +   * 
    +   * @param string $tagStart 
    +   * @param int $approved 
    +   * @return Tags
    +   */
    +  public static function getTagsStartingWithString($tagStart, $approved = 1, $user = false)
    +  {
    +    $c = new Criteria();
    +    
    +    $c->add(self::NAME, "$tagStart%", Criteria::LIKE);
    +    if ($user !== false && !$user->hasCredential("createcompositeartwork"))
    +    {
    +		
    +    	$c->addJoin(TaggingPeer::TAG_ID,TagPeer::ID);
    +		$c->add(TaggingPeer::TAGGABLE_MODEL,'ReaktorArtwork');
    +		$c->add(TaggingPeer::PARENT_USER_ID,$user->getId());
    +    } else 
    +    {
    +    	$c->add(TagPeer::APPROVED, $approved);
    +    }
    +    $c->setLimit(10);
    +    return self::getAll($c); 
    +  }
    +  
    +  public static function getFilesTaggedWith($tags)
    +  {
    +  	// ZOID: Somebody has changed this function to return all types of object - the "model" option is ignored
    +    $objects = self::getTaggedWith($tags, array('model' => 'ReaktorFile'));
    +  	return $objects;
    +  }
    +  
    +  /**
    +   * Function for normalising tags, will rename a tag or merge it if the new tag already exists
    +   * Effectively all objects lose the old tag and gain the new one
    +   *
    +   * @param string|Tag $oldTag The original tag name or object that will be removed/renamed
    +   * @param string|Tag $newTag The new tag name or object that will be the replacement
    +   * 
    +   * @return boolean true on success, exception on errors or null on no result
    +   */
    +  public static function renameOrMergeTag($oldTag, $newTag)
    +  {
    +   if (!$oldTag instanceof Tag)
    +   {
    +     $oldTag = self::retrieveByTagname($oldTag);
    +   }
    +   $originalNewTag = $newTag;
    +   // Lets see if the new one already exists, then we are merging
    +   if ($newTag instanceof Tag || $newTag = self::retrieveByTagname($newTag,true))
    +   {
    +   	$taggedObjects = self::getTaggedWith($oldTag);
    +   	
    +     foreach ($taggedObjects as $taggedObject)
    +     {
    +       $taggedObject->addTag($newTag->getName());
    +       $taggedObject->save();
    +       if ($taggedObject instanceof artworkFile )
    +       {
    +         $taggedObject->updateTagMetadata();
    +       }
    +     }
    +     $oldTag->delete();
    +   }
    +   // If the new tag didn't exist, this is a simple rename operation
    +   else
    +   {
    +
    +     $oldTag->setName($originalNewTag);
    +     $oldTag->Save();
    +   }
    +   return true;
    +  }
    +}
    +
    diff --git a/lib/model/Tagging.php b/lib/model/Tagging.php
    new file mode 100644
    index 0000000..3725b9c
    --- /dev/null
    +++ b/lib/model/Tagging.php
    @@ -0,0 +1,13 @@
    +setParentApproved(1);
    +      if ($tag->getParentUserId() == 0)
    +      {
    +        $tag->setParentUserId(sfContext::getInstance()->getUser()->getId());
    +      }
    +      $tag->save();
    +      return;
    +    }
    +    elseif ($tag instanceof Tag)
    +    {
    +      $tagId = $tag->getID();
    +    }
    +    elseif (is_numeric($tag) && $tag != 0)
    +    {
    +      $tagId = $tag;     
    +    }
    +    elseif (!is_null($tag))
    +    {
    +      $tagObject = TagPeer::retrieveByTagname($tag);
    +      $tagId     = $tagObject->getID();
    +    }
    +  
    +    
    +    
    +    if (is_object($taggable))
    +    {
    +      $taggableId = $taggable->getId();
    +    }
    +    elseif (!is_int($taggable))
    +    {
    +      throw new Exception ("Not a valid object or ID");
    +    }
    +    else
    +    {
    +      $taggableId = $taggable;
    +    }
    +    
    +    $c = new Criteria();
    +    
    +    if ($tagId > 0)
    +    {
    +      $c->add(TaggingPeer::TAG_ID, $tagId);
    +    }
    +    $c->add(TaggingPeer::TAGGABLE_MODEL, $model);
    +    $c->add(TaggingPeer::TAGGABLE_ID, $taggableId);
    +    
    +    $taggingObjects = TaggingPeer::doSelect($c);
    +    foreach ($taggingObjects as $taggingObject)
    +    {
    +      $taggingObject->setParentApproved($approved);
    +      if ($taggingObject->getParentUserId() == 0)
    +      {
    +        $taggingObject->setParentUserId(sfContext::getInstance()->getUser()->getId());
    +      }
    +      $taggingObject->save(); 
    +    }
    +  }
    +
    +  public static function setAllTaggingsApproved($taggable, $approved = 1)
    +  {
    +    $tags = TagPeer::getTagsByObject($taggable);
    +    foreach($tags as $tag)
    +    {
    +      TaggingPeer::setTaggingApproved($tag, "Article", $taggable);
    +    }
    +  }
    +
    +  /**
    +   * Set the User ID of the parent tagged object in the tagging table
    +   *
    +   * @param string|tag  $tag      the tag name or object
    +   * @param string  $model    the taggable model
    +   * @param integer $taggable the taggable id
    +   * @param integer $userId   the user id to set
    +   */
    +  public static function setParentUserId($tag, $model, $taggable, $userId)
    +  {
    +    if ($tag instanceof tag)
    +    {
    +      $tag = $tag->getName();
    +    }
    +    
    +    $c = new Criteria();
    +    $c->add(self::TAGGABLE_MODEL, $model);
    +    $c->add(self::TAGGABLE_ID, $taggable);
    +    $c->add(TagPeer::NAME, $tag);
    +    $c->addJoin(self::TAG_ID, TagPeer::ID);
    +    
    +    $taggableObject = self::doSelectOne($c);
    +    
    +    if ($taggableObject)
    +    {
    +      $taggableObject->setParentUserId($userId);
    +      $taggableObject->save();
    +    }
    +    else
    +    {
    +      throw new exception ("Couldn't find that tagging instance");
    +    }
    +  }
    +  /**
    +   * Remove tagged rows based on a tag ID
    +   *
    +   * @param integer $tagId The tag id to use when deleting
    +   */
    +  public static function deleteLinks($tagId)
    +  {
    +    $c = new Criteria();
    +    $c->add(TaggingPeer::TAG_ID, $tagId);
    +    TaggingPeer::doDelete($c);
    +  }
    +}
    diff --git a/lib/model/TransUnit.php b/lib/model/TransUnit.php
    new file mode 100644
    index 0000000..5435f56
    --- /dev/null
    +++ b/lib/model/TransUnit.php
    @@ -0,0 +1,12 @@
    +getCatId();
    +      $cat[$cat_id] = $catalogue->getTargetLang();
    +  }
    +  return $cat;
    +}
    +}
    diff --git a/lib/model/UserInterest.php b/lib/model/UserInterest.php
    new file mode 100644
    index 0000000..168b36b
    --- /dev/null
    +++ b/lib/model/UserInterest.php
    @@ -0,0 +1,12 @@
    +add(UserInterestPeer::USER_ID, $user_id);
    +    //$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $subreaktor_id);
    +    $v = UserInterestPeer::doSelect($criteria, $con);
    +
    +    return !empty($v) ? $v : null;
    +  }
    +  public static function retrieveUsersIdLiking($interest)
    +  {
    +    $criteria = new Criteria();
    +    $criteria->add(UserInterestPeer::SUBREAKTOR_ID, $interest);
    +    return UserInterestPeer::doSelect($criteria);
    +  }
    +	
    +  public static function deleteByUser($user_id, $con=null)
    +  {
    +  	if ($con === null) {
    +      $con = Propel::getConnection(self::DATABASE_NAME);
    +    }
    + 
    +    $criteria = new Criteria(self::DATABASE_NAME);
    +
    +    $criteria->add(UserInterestPeer::USER_ID, $user_id, Criteria::IN);
    +    $criteria->setDbName(self::DATABASE_NAME);
    +
    +    $affectedRows = 0; 
    +    try {
    +                  $con->begin();
    +      
    +      $affectedRows += BasePeer::doDelete($criteria, $con);
    +      $con->commit();
    +      return $affectedRows;
    +    } catch (PropelException $e) {
    +      $con->rollback();
    +      throw $e;
    +    }
    +/*
    +    $criteria = new Criteria();
    +    $criteria->add(UserInterestPeer::USER_ID, $user_id);
    +    //$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $subreaktor_id);
    +    $v = UserInterestPeer::doSelect($criteria, $con);
    +
    +    return !empty($v) ? $v : null;
    +    */
    +  }
    +}
    diff --git a/lib/model/UserResource.php b/lib/model/UserResource.php
    new file mode 100644
    index 0000000..79bdeb8
    --- /dev/null
    +++ b/lib/model/UserResource.php
    @@ -0,0 +1,12 @@
    +setUserId($user);
    +    $resource->setUrl($url);
    +    $resource->save();
    +       
    +  }
    +    
    +}
    diff --git a/lib/model/map/AdminMessageMapBuilder.php b/lib/model/map/AdminMessageMapBuilder.php
    new file mode 100644
    index 0000000..62e28d6
    --- /dev/null
    +++ b/lib/model/map/AdminMessageMapBuilder.php
    @@ -0,0 +1,50 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('admin_message');
    +		$tMap->setPhpName('AdminMessage');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('SUBJECT', 'Subject', 'string', CreoleTypes::VARCHAR, false, 255);
    +
    +		$tMap->addColumn('MESSAGE', 'Message', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +		$tMap->addForeignKey('AUTHOR', 'Author', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('UPDATED_AT', 'UpdatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addColumn('EXPIRES_AT', 'ExpiresAt', 'int', CreoleTypes::TIMESTAMP, true, null);
    +
    +		$tMap->addColumn('IS_DELETED', 'IsDeleted', 'boolean', CreoleTypes::BOOLEAN, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArticleArticleRelationMapBuilder.php b/lib/model/map/ArticleArticleRelationMapBuilder.php
    new file mode 100644
    index 0000000..7e31dde
    --- /dev/null
    +++ b/lib/model/map/ArticleArticleRelationMapBuilder.php
    @@ -0,0 +1,46 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('article_article_relation');
    +		$tMap->setPhpName('ArticleArticleRelation');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addForeignKey('FIRST_ARTICLE', 'FirstArticle', 'int', CreoleTypes::INTEGER, 'article', 'ID', true, null);
    +
    +		$tMap->addForeignKey('SECOND_ARTICLE', 'SecondArticle', 'int', CreoleTypes::INTEGER, 'article', 'ID', true, null);
    +
    +		$tMap->addForeignKey('CREATED_BY', 'CreatedBy', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArticleArtworkRelationMapBuilder.php b/lib/model/map/ArticleArtworkRelationMapBuilder.php
    new file mode 100644
    index 0000000..3e3eda7
    --- /dev/null
    +++ b/lib/model/map/ArticleArtworkRelationMapBuilder.php
    @@ -0,0 +1,46 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('article_artwork_relation');
    +		$tMap->setPhpName('ArticleArtworkRelation');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addForeignKey('ARTICLE_ID', 'ArticleId', 'int', CreoleTypes::INTEGER, 'article', 'ID', true, null);
    +
    +		$tMap->addForeignKey('ARTWORK_ID', 'ArtworkId', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', true, null);
    +
    +		$tMap->addForeignKey('CREATED_BY', 'CreatedBy', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArticleAttachmentMapBuilder.php b/lib/model/map/ArticleAttachmentMapBuilder.php
    new file mode 100644
    index 0000000..ddfadb3
    --- /dev/null
    +++ b/lib/model/map/ArticleAttachmentMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('article_attachment');
    +		$tMap->setPhpName('ArticleAttachment');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addForeignKey('ARTICLE_ID', 'ArticleId', 'int', CreoleTypes::INTEGER, 'article', 'ID', true, null);
    +
    +		$tMap->addForeignKey('FILE_ID', 'FileId', 'int', CreoleTypes::INTEGER, 'article_file', 'ID', true, null);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArticleCategoryMapBuilder.php b/lib/model/map/ArticleCategoryMapBuilder.php
    new file mode 100644
    index 0000000..dd3aaf4
    --- /dev/null
    +++ b/lib/model/map/ArticleCategoryMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('article_category');
    +		$tMap->setPhpName('ArticleCategory');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addForeignKey('ARTICLE_ID', 'ArticleId', 'int', CreoleTypes::INTEGER, 'article', 'ID', true, null);
    +
    +		$tMap->addForeignKey('CATEGORY_ID', 'CategoryId', 'int', CreoleTypes::INTEGER, 'category', 'ID', true, null);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArticleFileMapBuilder.php b/lib/model/map/ArticleFileMapBuilder.php
    new file mode 100644
    index 0000000..c4642e7
    --- /dev/null
    +++ b/lib/model/map/ArticleFileMapBuilder.php
    @@ -0,0 +1,50 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('article_file');
    +		$tMap->setPhpName('ArticleFile');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('FILENAME', 'Filename', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('PATH', 'Path', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addForeignKey('UPLOADED_BY', 'UploadedBy', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('UPLOADED_AT', 'UploadedAt', 'int', CreoleTypes::TIMESTAMP, true, null);
    +
    +		$tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::VARCHAR, false, 255);
    +
    +		$tMap->addForeignKey('FILE_MIMETYPE_ID', 'FileMimetypeId', 'int', CreoleTypes::INTEGER, 'file_mimetype', 'ID', true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArticleI18nMapBuilder.php b/lib/model/map/ArticleI18nMapBuilder.php
    new file mode 100644
    index 0000000..e4c7cde
    --- /dev/null
    +++ b/lib/model/map/ArticleI18nMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('article_i18n');
    +		$tMap->setPhpName('ArticleI18n');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addColumn('TITLE', 'Title', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addForeignPrimaryKey('ID', 'Id', 'int' , CreoleTypes::INTEGER, 'article', 'ID', true, null);
    +
    +		$tMap->addPrimaryKey('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, true, 7);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArticleMapBuilder.php b/lib/model/map/ArticleMapBuilder.php
    new file mode 100644
    index 0000000..2dac053
    --- /dev/null
    +++ b/lib/model/map/ArticleMapBuilder.php
    @@ -0,0 +1,70 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('article');
    +		$tMap->setPhpName('Article');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addForeignKey('AUTHOR_ID', 'AuthorId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('BASE_TITLE', 'BaseTitle', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('PERMALINK', 'Permalink', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('INGRESS', 'Ingress', 'string', CreoleTypes::LONGVARCHAR, false, null);
    +
    +		$tMap->addColumn('CONTENT', 'Content', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +		$tMap->addColumn('UPDATED_AT', 'UpdatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addColumn('UPDATED_BY', 'UpdatedBy', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('ARTICLE_TYPE', 'ArticleType', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('ARTICLE_ORDER', 'ArticleOrder', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('EXPIRES_AT', 'ExpiresAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addColumn('STATUS', 'Status', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('PUBLISHED_AT', 'PublishedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addForeignKey('BANNER_FILE_ID', 'BannerFileId', 'int', CreoleTypes::INTEGER, 'article_file', 'ID', false, null);
    +
    +		$tMap->addColumn('IS_STICKY', 'IsSticky', 'boolean', CreoleTypes::BOOLEAN, false, null);
    +
    +		$tMap->addColumn('FRONTPAGE', 'Frontpage', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArticleSubreaktorMapBuilder.php b/lib/model/map/ArticleSubreaktorMapBuilder.php
    new file mode 100644
    index 0000000..a0c207e
    --- /dev/null
    +++ b/lib/model/map/ArticleSubreaktorMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('article_subreaktor');
    +		$tMap->setPhpName('ArticleSubreaktor');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addForeignKey('ARTICLE_ID', 'ArticleId', 'int', CreoleTypes::INTEGER, 'article', 'ID', true, null);
    +
    +		$tMap->addForeignKey('SUBREAKTOR_ID', 'SubreaktorId', 'int', CreoleTypes::INTEGER, 'subreaktor', 'ID', true, null);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArtworkStatusI18nMapBuilder.php b/lib/model/map/ArtworkStatusI18nMapBuilder.php
    new file mode 100644
    index 0000000..b24d52e
    --- /dev/null
    +++ b/lib/model/map/ArtworkStatusI18nMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('artwork_status_i18n');
    +		$tMap->setPhpName('ArtworkStatusI18n');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addForeignPrimaryKey('ID', 'Id', 'int' , CreoleTypes::INTEGER, 'artwork_status', 'ID', true, null);
    +
    +		$tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::VARCHAR, true, 30);
    +
    +		$tMap->addPrimaryKey('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, true, 7);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ArtworkStatusMapBuilder.php b/lib/model/map/ArtworkStatusMapBuilder.php
    new file mode 100644
    index 0000000..5565fc6
    --- /dev/null
    +++ b/lib/model/map/ArtworkStatusMapBuilder.php
    @@ -0,0 +1,40 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('artwork_status');
    +		$tMap->setPhpName('ArtworkStatus');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 30);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/CatalogueMapBuilder.php b/lib/model/map/CatalogueMapBuilder.php
    new file mode 100644
    index 0000000..5af2e2b
    --- /dev/null
    +++ b/lib/model/map/CatalogueMapBuilder.php
    @@ -0,0 +1,52 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('catalogue');
    +		$tMap->setPhpName('Catalogue');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('CAT_ID', 'CatId', 'int', CreoleTypes::INTEGER, true, 11);
    +
    +		$tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 100);
    +
    +		$tMap->addColumn('SOURCE_LANG', 'SourceLang', 'string', CreoleTypes::VARCHAR, true, 100);
    +
    +		$tMap->addColumn('TARGET_LANG', 'TargetLang', 'string', CreoleTypes::VARCHAR, true, 100);
    +
    +		$tMap->addColumn('DATE_CREATED', 'DateCreated', 'int', CreoleTypes::INTEGER, true, 11);
    +
    +		$tMap->addColumn('DATE_MODIFIED', 'DateModified', 'int', CreoleTypes::INTEGER, true, 11);
    +
    +		$tMap->addColumn('AUTHOR', 'Author', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/CategoryArtworkMapBuilder.php b/lib/model/map/CategoryArtworkMapBuilder.php
    new file mode 100644
    index 0000000..3c9e25d
    --- /dev/null
    +++ b/lib/model/map/CategoryArtworkMapBuilder.php
    @@ -0,0 +1,46 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('category_artwork');
    +		$tMap->setPhpName('CategoryArtwork');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('CATEGORY_ID', 'CategoryId', 'int', CreoleTypes::INTEGER, 'category', 'ID', false, null);
    +
    +		$tMap->addForeignKey('ARTWORK_ID', 'ArtworkId', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', false, null);
    +
    +		$tMap->addForeignKey('ADDED_BY', 'AddedBy', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', false, null);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/CategoryI18nMapBuilder.php b/lib/model/map/CategoryI18nMapBuilder.php
    new file mode 100644
    index 0000000..2259c53
    --- /dev/null
    +++ b/lib/model/map/CategoryI18nMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('category_i18n');
    +		$tMap->setPhpName('CategoryI18n');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 75);
    +
    +		$tMap->addForeignPrimaryKey('ID', 'Id', 'int' , CreoleTypes::INTEGER, 'category', 'ID', true, null);
    +
    +		$tMap->addPrimaryKey('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, true, 7);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/CategoryMapBuilder.php b/lib/model/map/CategoryMapBuilder.php
    new file mode 100644
    index 0000000..55c60ed
    --- /dev/null
    +++ b/lib/model/map/CategoryMapBuilder.php
    @@ -0,0 +1,40 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('category');
    +		$tMap->setPhpName('Category');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('BASENAME', 'Basename', 'string', CreoleTypes::VARCHAR, true, 75);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/CategorySubreaktorMapBuilder.php b/lib/model/map/CategorySubreaktorMapBuilder.php
    new file mode 100644
    index 0000000..ccb38c0
    --- /dev/null
    +++ b/lib/model/map/CategorySubreaktorMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('category_subreaktor');
    +		$tMap->setPhpName('CategorySubreaktor');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('CATEGORY_ID', 'CategoryId', 'int', CreoleTypes::INTEGER, 'category', 'ID', false, null);
    +
    +		$tMap->addForeignKey('SUBREAKTOR_ID', 'SubreaktorId', 'int', CreoleTypes::INTEGER, 'subreaktor', 'ID', false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/FavouriteMapBuilder.php b/lib/model/map/FavouriteMapBuilder.php
    new file mode 100644
    index 0000000..e8a4e2e
    --- /dev/null
    +++ b/lib/model/map/FavouriteMapBuilder.php
    @@ -0,0 +1,48 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('favourite');
    +		$tMap->setPhpName('Favourite');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('USER_ID', 'UserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addForeignKey('ARTWORK_ID', 'ArtworkId', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', true, null);
    +
    +		$tMap->addForeignKey('ARTICLE_ID', 'ArticleId', 'int', CreoleTypes::INTEGER, 'article', 'ID', true, null);
    +
    +		$tMap->addForeignKey('FRIEND_ID', 'FriendId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('FAV_TYPE', 'FavType', 'string', CreoleTypes::VARCHAR, true, 8);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/FileMetadataMapBuilder.php b/lib/model/map/FileMetadataMapBuilder.php
    new file mode 100644
    index 0000000..b61b551
    --- /dev/null
    +++ b/lib/model/map/FileMetadataMapBuilder.php
    @@ -0,0 +1,46 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('file_metadata');
    +		$tMap->setPhpName('FileMetadata');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('FILE', 'File', 'int', CreoleTypes::INTEGER, 'reaktor_file', 'ID', true, null);
    +
    +		$tMap->addColumn('META_ELEMENT', 'MetaElement', 'string', CreoleTypes::VARCHAR, true, 100);
    +
    +		$tMap->addColumn('META_QUALIFIER', 'MetaQualifier', 'string', CreoleTypes::VARCHAR, true, 100);
    +
    +		$tMap->addColumn('META_VALUE', 'MetaValue', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/FileMimetypeMapBuilder.php b/lib/model/map/FileMimetypeMapBuilder.php
    new file mode 100644
    index 0000000..d7aca1e
    --- /dev/null
    +++ b/lib/model/map/FileMimetypeMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('file_mimetype');
    +		$tMap->setPhpName('FileMimetype');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('MIMETYPE', 'Mimetype', 'string', CreoleTypes::VARCHAR, true, 100);
    +
    +		$tMap->addColumn('IDENTIFIER', 'Identifier', 'string', CreoleTypes::VARCHAR, true, 20);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/HistoryActionI18nMapBuilder.php b/lib/model/map/HistoryActionI18nMapBuilder.php
    new file mode 100644
    index 0000000..8d3cef6
    --- /dev/null
    +++ b/lib/model/map/HistoryActionI18nMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('history_action_i18n');
    +		$tMap->setPhpName('HistoryActionI18n');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +		$tMap->addForeignPrimaryKey('ID', 'Id', 'int' , CreoleTypes::INTEGER, 'history_action', 'ID', true, null);
    +
    +		$tMap->addPrimaryKey('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, true, 7);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/HistoryActionMapBuilder.php b/lib/model/map/HistoryActionMapBuilder.php
    new file mode 100644
    index 0000000..42dc22f
    --- /dev/null
    +++ b/lib/model/map/HistoryActionMapBuilder.php
    @@ -0,0 +1,40 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('history_action');
    +		$tMap->setPhpName('HistoryAction');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, false, 50);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/HistoryMapBuilder.php b/lib/model/map/HistoryMapBuilder.php
    new file mode 100644
    index 0000000..c6fb61b
    --- /dev/null
    +++ b/lib/model/map/HistoryMapBuilder.php
    @@ -0,0 +1,48 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('history');
    +		$tMap->setPhpName('History');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addForeignKey('ACTION_ID', 'ActionId', 'int', CreoleTypes::INTEGER, 'history_action', 'ID', true, null);
    +
    +		$tMap->addForeignKey('USER_ID', 'UserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('OBJECT_ID', 'ObjectId', 'int', CreoleTypes::INTEGER, false, null);
    +
    +		$tMap->addColumn('EXTRA_DETAILS', 'ExtraDetails', 'string', CreoleTypes::LONGVARCHAR, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/LokalreaktorArtworkMapBuilder.php b/lib/model/map/LokalreaktorArtworkMapBuilder.php
    new file mode 100644
    index 0000000..1822cb2
    --- /dev/null
    +++ b/lib/model/map/LokalreaktorArtworkMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('lokalreaktor_artwork');
    +		$tMap->setPhpName('LokalreaktorArtwork');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('SUBREAKTOR_ID', 'SubreaktorId', 'int', CreoleTypes::INTEGER, 'subreaktor', 'ID', true, null);
    +
    +		$tMap->addForeignKey('ARTWORK_ID', 'ArtworkId', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/LokalreaktorResidenceMapBuilder.php b/lib/model/map/LokalreaktorResidenceMapBuilder.php
    new file mode 100644
    index 0000000..7b51da1
    --- /dev/null
    +++ b/lib/model/map/LokalreaktorResidenceMapBuilder.php
    @@ -0,0 +1,44 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('lokalreaktor_residence');
    +		$tMap->setPhpName('LokalreaktorResidence');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addForeignKey('SUBREAKTOR_ID', 'SubreaktorId', 'int', CreoleTypes::INTEGER, 'subreaktor', 'ID', true, null);
    +
    +		$tMap->addForeignKey('RESIDENCE_ID', 'ResidenceId', 'int', CreoleTypes::INTEGER, 'residence', 'ID', true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/MessagesIgnoredUserMapBuilder.php b/lib/model/map/MessagesIgnoredUserMapBuilder.php
    new file mode 100644
    index 0000000..ad9320a
    --- /dev/null
    +++ b/lib/model/map/MessagesIgnoredUserMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('messages_ignored_user');
    +		$tMap->setPhpName('MessagesIgnoredUser');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('USER_ID', 'UserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addForeignKey('IGNORES_USER_ID', 'IgnoresUserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/MessagesMapBuilder.php b/lib/model/map/MessagesMapBuilder.php
    new file mode 100644
    index 0000000..1a22858
    --- /dev/null
    +++ b/lib/model/map/MessagesMapBuilder.php
    @@ -0,0 +1,60 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('messages');
    +		$tMap->setPhpName('Messages');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('TO_USER_ID', 'ToUserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addForeignKey('FROM_USER_ID', 'FromUserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('SUBJECT', 'Subject', 'string', CreoleTypes::VARCHAR, false, 255);
    +
    +		$tMap->addColumn('MESSAGE', 'Message', 'string', CreoleTypes::LONGVARCHAR, false, null);
    +
    +		$tMap->addColumn('TIMESTAMP', 'Timestamp', 'int', CreoleTypes::TIMESTAMP, true, null);
    +
    +		$tMap->addColumn('DELETED_BY_FROM', 'DeletedByFrom', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('DELETED_BY_TO', 'DeletedByTo', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('IS_READ', 'IsRead', 'boolean', CreoleTypes::BOOLEAN, true, null);
    +
    +		$tMap->addColumn('IS_IGNORED', 'IsIgnored', 'boolean', CreoleTypes::BOOLEAN, true, null);
    +
    +		$tMap->addColumn('IS_ARCHIVED', 'IsArchived', 'boolean', CreoleTypes::BOOLEAN, true, null);
    +
    +		$tMap->addColumn('REPLY_TO', 'ReplyTo', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ReaktorArtworkFileMapBuilder.php b/lib/model/map/ReaktorArtworkFileMapBuilder.php
    new file mode 100644
    index 0000000..7ae828d
    --- /dev/null
    +++ b/lib/model/map/ReaktorArtworkFileMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('reaktor_artwork_file');
    +		$tMap->setPhpName('ReaktorArtworkFile');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addForeignPrimaryKey('ARTWORK_ID', 'ArtworkId', 'int' , CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', true, null);
    +
    +		$tMap->addForeignPrimaryKey('FILE_ID', 'FileId', 'int' , CreoleTypes::INTEGER, 'reaktor_file', 'ID', true, null);
    +
    +		$tMap->addColumn('FILE_ORDER', 'FileOrder', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ReaktorArtworkHistoryMapBuilder.php b/lib/model/map/ReaktorArtworkHistoryMapBuilder.php
    new file mode 100644
    index 0000000..f2057b1
    --- /dev/null
    +++ b/lib/model/map/ReaktorArtworkHistoryMapBuilder.php
    @@ -0,0 +1,52 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('reaktor_artwork_history');
    +		$tMap->setPhpName('ReaktorArtworkHistory');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('ARTWORK_ID', 'ArtworkId', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', false, null);
    +
    +		$tMap->addForeignKey('FILE_ID', 'FileId', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', false, null);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addColumn('MODIFIED_FLAG', 'ModifiedFlag', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addForeignKey('USER_ID', 'UserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addForeignKey('STATUS', 'Status', 'int', CreoleTypes::INTEGER, 'artwork_status', 'ID', true, null);
    +
    +		$tMap->addColumn('COMMENT', 'Comment', 'string', CreoleTypes::LONGVARCHAR, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ReaktorArtworkMapBuilder.php b/lib/model/map/ReaktorArtworkMapBuilder.php
    new file mode 100644
    index 0000000..56208f8
    --- /dev/null
    +++ b/lib/model/map/ReaktorArtworkMapBuilder.php
    @@ -0,0 +1,74 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('reaktor_artwork');
    +		$tMap->setPhpName('ReaktorArtwork');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('USER_ID', 'UserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('ARTWORK_IDENTIFIER', 'ArtworkIdentifier', 'string', CreoleTypes::VARCHAR, true, 20);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, true, null);
    +
    +		$tMap->addColumn('SUBMITTED_AT', 'SubmittedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addColumn('ACTIONED_AT', 'ActionedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addColumn('MODIFIED_FLAG', 'ModifiedFlag', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addColumn('TITLE', 'Title', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('ACTIONED_BY', 'ActionedBy', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('STATUS', 'Status', 'int', CreoleTypes::INTEGER, 'artwork_status', 'ID', true, null);
    +
    +		$tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::LONGVARCHAR, false, null);
    +
    +		$tMap->addColumn('MODIFIED_NOTE', 'ModifiedNote', 'string', CreoleTypes::LONGVARCHAR, false, null);
    +
    +		$tMap->addColumn('ARTWORK_ORDER', 'ArtworkOrder', 'int', CreoleTypes::INTEGER, false, null);
    +
    +		$tMap->addColumn('AVERAGE_RATING', 'AverageRating', 'double', CreoleTypes::FLOAT, false, null);
    +
    +		$tMap->addForeignKey('TEAM_ID', 'TeamId', 'int', CreoleTypes::INTEGER, 'sf_guard_group', 'ID', true, null);
    +
    +		$tMap->addColumn('UNDER_DISCUSSION', 'UnderDiscussion', 'int', CreoleTypes::INTEGER, true, 1);
    +
    +		$tMap->addColumn('MULTI_USER', 'MultiUser', 'int', CreoleTypes::INTEGER, true, 1);
    +
    +		$tMap->addForeignKey('FIRST_FILE_ID', 'FirstFileId', 'int', CreoleTypes::INTEGER, 'reaktor_file', 'ID', false, null);
    +
    +		$tMap->addColumn('DELETED', 'Deleted', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ReaktorFileMapBuilder.php b/lib/model/map/ReaktorFileMapBuilder.php
    new file mode 100644
    index 0000000..6c647bf
    --- /dev/null
    +++ b/lib/model/map/ReaktorFileMapBuilder.php
    @@ -0,0 +1,74 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('reaktor_file');
    +		$tMap->setPhpName('ReaktorFile');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('FILENAME', 'Filename', 'string', CreoleTypes::VARCHAR, true, 200);
    +
    +		$tMap->addForeignKey('USER_ID', 'UserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('REALPATH', 'Realpath', 'string', CreoleTypes::VARCHAR, true, 300);
    +
    +		$tMap->addColumn('THUMBPATH', 'Thumbpath', 'string', CreoleTypes::VARCHAR, true, 300);
    +
    +		$tMap->addColumn('ORIGINALPATH', 'Originalpath', 'string', CreoleTypes::VARCHAR, true, 300);
    +
    +		$tMap->addColumn('ORIGINAL_MIMETYPE_ID', 'OriginalMimetypeId', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('CONVERTED_MIMETYPE_ID', 'ConvertedMimetypeId', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('THUMBNAIL_MIMETYPE_ID', 'ThumbnailMimetypeId', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('UPLOADED_AT', 'UploadedAt', 'int', CreoleTypes::TIMESTAMP, true, null);
    +
    +		$tMap->addColumn('MODIFIED_AT', 'ModifiedAt', 'int', CreoleTypes::TIMESTAMP, true, null);
    +
    +		$tMap->addColumn('REPORTED_AT', 'ReportedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +		$tMap->addColumn('REPORTED', 'Reported', 'int', CreoleTypes::INTEGER, true, 8);
    +
    +		$tMap->addColumn('TOTAL_REPORTED_EVER', 'TotalReportedEver', 'int', CreoleTypes::INTEGER, true, 8);
    +
    +		$tMap->addColumn('MARKED_UNSUITABLE', 'MarkedUnsuitable', 'int', CreoleTypes::INTEGER, true, 1);
    +
    +		$tMap->addColumn('UNDER_DISCUSSION', 'UnderDiscussion', 'int', CreoleTypes::INTEGER, true, 1);
    +
    +		$tMap->addColumn('IDENTIFIER', 'Identifier', 'string', CreoleTypes::VARCHAR, true, 20);
    +
    +		$tMap->addColumn('HIDDEN', 'Hidden', 'int', CreoleTypes::INTEGER, true, 1);
    +
    +		$tMap->addColumn('DELETED', 'Deleted', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/RecommendedArtworkMapBuilder.php b/lib/model/map/RecommendedArtworkMapBuilder.php
    new file mode 100644
    index 0000000..0231aa3
    --- /dev/null
    +++ b/lib/model/map/RecommendedArtworkMapBuilder.php
    @@ -0,0 +1,48 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('recommended_artwork');
    +		$tMap->setPhpName('RecommendedArtwork');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('ARTWORK', 'Artwork', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', true, null);
    +
    +		$tMap->addForeignKey('SUBREAKTOR', 'Subreaktor', 'int', CreoleTypes::INTEGER, 'subreaktor', 'ID', true, null);
    +
    +		$tMap->addForeignKey('LOCALSUBREAKTOR', 'Localsubreaktor', 'int', CreoleTypes::INTEGER, 'subreaktor', 'ID', false, null);
    +
    +		$tMap->addForeignKey('UPDATED_BY', 'UpdatedBy', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('UPDATED_AT', 'UpdatedAt', 'int', CreoleTypes::TIMESTAMP, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/RejectionTypeI18nMapBuilder.php b/lib/model/map/RejectionTypeI18nMapBuilder.php
    new file mode 100644
    index 0000000..5df2a73
    --- /dev/null
    +++ b/lib/model/map/RejectionTypeI18nMapBuilder.php
    @@ -0,0 +1,44 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('rejection_type_i18n');
    +		$tMap->setPhpName('RejectionTypeI18n');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addForeignPrimaryKey('ID', 'Id', 'int' , CreoleTypes::INTEGER, 'rejection_type', 'ID', true, null);
    +
    +		$tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +		$tMap->addPrimaryKey('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, true, 7);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/RejectionTypeMapBuilder.php b/lib/model/map/RejectionTypeMapBuilder.php
    new file mode 100644
    index 0000000..6592caa
    --- /dev/null
    +++ b/lib/model/map/RejectionTypeMapBuilder.php
    @@ -0,0 +1,40 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('rejection_type');
    +		$tMap->setPhpName('RejectionType');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('BASENAME', 'Basename', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/RelatedArtworkMapBuilder.php b/lib/model/map/RelatedArtworkMapBuilder.php
    new file mode 100644
    index 0000000..12533e2
    --- /dev/null
    +++ b/lib/model/map/RelatedArtworkMapBuilder.php
    @@ -0,0 +1,48 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('related_artwork');
    +		$tMap->setPhpName('RelatedArtwork');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('FIRST_ARTWORK', 'FirstArtwork', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', true, null);
    +
    +		$tMap->addForeignKey('SECOND_ARTWORK', 'SecondArtwork', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', true, null);
    +
    +		$tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, true, null);
    +
    +		$tMap->addForeignKey('CREATED_BY', 'CreatedBy', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('ORDER_BY', 'OrderBy', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ReportBookmarkMapBuilder.php b/lib/model/map/ReportBookmarkMapBuilder.php
    new file mode 100644
    index 0000000..b6f3ad6
    --- /dev/null
    +++ b/lib/model/map/ReportBookmarkMapBuilder.php
    @@ -0,0 +1,48 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('report_bookmark');
    +		$tMap->setPhpName('ReportBookmark');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('TITLE', 'Title', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +		$tMap->addColumn('ARGS', 'Args', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +		$tMap->addColumn('TYPE', 'Type', 'string', CreoleTypes::VARCHAR, true, 10);
    +
    +		$tMap->addColumn('LIST_ORDER', 'ListOrder', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ResidenceLevelI18nMapBuilder.php b/lib/model/map/ResidenceLevelI18nMapBuilder.php
    new file mode 100644
    index 0000000..6253cc1
    --- /dev/null
    +++ b/lib/model/map/ResidenceLevelI18nMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('residence_level_i18n');
    +		$tMap->setPhpName('ResidenceLevelI18n');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addForeignPrimaryKey('ID', 'Id', 'int' , CreoleTypes::INTEGER, 'residence_level', 'ID', true, null);
    +
    +		$tMap->addPrimaryKey('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, true, 7);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ResidenceLevelMapBuilder.php b/lib/model/map/ResidenceLevelMapBuilder.php
    new file mode 100644
    index 0000000..b3f739f
    --- /dev/null
    +++ b/lib/model/map/ResidenceLevelMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('residence_level');
    +		$tMap->setPhpName('ResidenceLevel');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('LEVELNAME', 'Levelname', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('LISTORDER', 'Listorder', 'int', CreoleTypes::INTEGER, false, 2);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/ResidenceMapBuilder.php b/lib/model/map/ResidenceMapBuilder.php
    new file mode 100644
    index 0000000..dce14b7
    --- /dev/null
    +++ b/lib/model/map/ResidenceMapBuilder.php
    @@ -0,0 +1,44 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('residence');
    +		$tMap->setPhpName('Residence');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addForeignKey('LEVEL', 'Level', 'int', CreoleTypes::INTEGER, 'residence_level', 'ID', true, null);
    +
    +		$tMap->addColumn('PARENT', 'Parent', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/SubreaktorArtworkMapBuilder.php b/lib/model/map/SubreaktorArtworkMapBuilder.php
    new file mode 100644
    index 0000000..2b17183
    --- /dev/null
    +++ b/lib/model/map/SubreaktorArtworkMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('subreaktor_artwork');
    +		$tMap->setPhpName('SubreaktorArtwork');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('SUBREAKTOR_ID', 'SubreaktorId', 'int', CreoleTypes::INTEGER, 'subreaktor', 'ID', true, null);
    +
    +		$tMap->addForeignKey('ARTWORK_ID', 'ArtworkId', 'int', CreoleTypes::INTEGER, 'reaktor_artwork', 'ID', true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/SubreaktorI18nMapBuilder.php b/lib/model/map/SubreaktorI18nMapBuilder.php
    new file mode 100644
    index 0000000..c38e756
    --- /dev/null
    +++ b/lib/model/map/SubreaktorI18nMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('subreaktor_i18n');
    +		$tMap->setPhpName('SubreaktorI18n');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addForeignPrimaryKey('ID', 'Id', 'int' , CreoleTypes::INTEGER, 'subreaktor', 'ID', true, null);
    +
    +		$tMap->addPrimaryKey('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, true, 7);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/SubreaktorIdentifierMapBuilder.php b/lib/model/map/SubreaktorIdentifierMapBuilder.php
    new file mode 100644
    index 0000000..2f120e8
    --- /dev/null
    +++ b/lib/model/map/SubreaktorIdentifierMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('subreaktor_identifier');
    +		$tMap->setPhpName('SubreaktorIdentifier');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignKey('SUBREAKTOR_ID', 'SubreaktorId', 'int', CreoleTypes::INTEGER, 'subreaktor', 'ID', true, null);
    +
    +		$tMap->addColumn('IDENTIFIER', 'Identifier', 'string', CreoleTypes::VARCHAR, true, 20);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/SubreaktorMapBuilder.php b/lib/model/map/SubreaktorMapBuilder.php
    new file mode 100644
    index 0000000..638d867
    --- /dev/null
    +++ b/lib/model/map/SubreaktorMapBuilder.php
    @@ -0,0 +1,46 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('subreaktor');
    +		$tMap->setPhpName('Subreaktor');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addColumn('REFERENCE', 'Reference', 'string', CreoleTypes::VARCHAR, true, 15);
    +
    +		$tMap->addColumn('LOKALREAKTOR', 'Lokalreaktor', 'boolean', CreoleTypes::BOOLEAN, true, null);
    +
    +		$tMap->addColumn('LIVE', 'Live', 'boolean', CreoleTypes::BOOLEAN, true, null);
    +
    +		$tMap->addColumn('SUBREAKTOR_ORDER', 'SubreaktorOrder', 'int', CreoleTypes::INTEGER, false, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/TransUnitMapBuilder.php b/lib/model/map/TransUnitMapBuilder.php
    new file mode 100644
    index 0000000..ca0b635
    --- /dev/null
    +++ b/lib/model/map/TransUnitMapBuilder.php
    @@ -0,0 +1,60 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('trans_unit');
    +		$tMap->setPhpName('TransUnit');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('MSG_ID', 'MsgId', 'int', CreoleTypes::INTEGER, true, 11);
    +
    +		$tMap->addForeignKey('CAT_ID', 'CatId', 'int', CreoleTypes::INTEGER, 'catalogue', 'CAT_ID', true, 11);
    +
    +		$tMap->addColumn('ID', 'Id', 'string', CreoleTypes::VARCHAR, false, 255);
    +
    +		$tMap->addColumn('SOURCE', 'Source', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +		$tMap->addColumn('TARGET', 'Target', 'string', CreoleTypes::LONGVARCHAR, true, null);
    +
    +		$tMap->addColumn('MODULE', 'Module', 'string', CreoleTypes::VARCHAR, false, 255);
    +
    +		$tMap->addColumn('FILENAME', 'Filename', 'string', CreoleTypes::VARCHAR, false, 255);
    +
    +		$tMap->addColumn('COMMENTS', 'Comments', 'string', CreoleTypes::LONGVARCHAR, false, null);
    +
    +		$tMap->addColumn('DATE_ADDED', 'DateAdded', 'int', CreoleTypes::INTEGER, true, 11);
    +
    +		$tMap->addColumn('DATE_MODIFIED', 'DateModified', 'int', CreoleTypes::INTEGER, true, 11);
    +
    +		$tMap->addColumn('AUTHOR', 'Author', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +		$tMap->addColumn('TRANSLATED', 'Translated', 'boolean', CreoleTypes::BOOLEAN, true, 1);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/UserInterestMapBuilder.php b/lib/model/map/UserInterestMapBuilder.php
    new file mode 100644
    index 0000000..d287328
    --- /dev/null
    +++ b/lib/model/map/UserInterestMapBuilder.php
    @@ -0,0 +1,40 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('user_interest');
    +		$tMap->setPhpName('UserInterest');
    +
    +		$tMap->setUseIdGenerator(false);
    +
    +		$tMap->addForeignPrimaryKey('USER_ID', 'UserId', 'int' , CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addForeignPrimaryKey('SUBREAKTOR_ID', 'SubreaktorId', 'int' , CreoleTypes::INTEGER, 'subreaktor', 'ID', true, null);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/map/UserResourceMapBuilder.php b/lib/model/map/UserResourceMapBuilder.php
    new file mode 100644
    index 0000000..c6672da
    --- /dev/null
    +++ b/lib/model/map/UserResourceMapBuilder.php
    @@ -0,0 +1,42 @@
    +dbMap !== null);
    +	}
    +
    +	
    +	public function getDatabaseMap()
    +	{
    +		return $this->dbMap;
    +	}
    +
    +	
    +	public function doBuild()
    +	{
    +		$this->dbMap = Propel::getDatabaseMap('propel');
    +
    +		$tMap = $this->dbMap->addTable('user_resource');
    +		$tMap->setPhpName('UserResource');
    +
    +		$tMap->setUseIdGenerator(true);
    +
    +		$tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null);
    +
    +		$tMap->addForeignPrimaryKey('USER_ID', 'UserId', 'int' , CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null);
    +
    +		$tMap->addColumn('URL', 'Url', 'string', CreoleTypes::VARCHAR, true, 255);
    +
    +	} 
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseAdminMessage.php b/lib/model/om/BaseAdminMessage.php
    new file mode 100644
    index 0000000..ec80952
    --- /dev/null
    +++ b/lib/model/om/BaseAdminMessage.php
    @@ -0,0 +1,654 @@
    +id;
    +	}
    +
    +	
    +	public function getSubject()
    +	{
    +
    +		return $this->subject;
    +	}
    +
    +	
    +	public function getMessage()
    +	{
    +
    +		return $this->message;
    +	}
    +
    +	
    +	public function getAuthor()
    +	{
    +
    +		return $this->author;
    +	}
    +
    +	
    +	public function getUpdatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->updated_at === null || $this->updated_at === '') {
    +			return null;
    +		} elseif (!is_int($this->updated_at)) {
    +						$ts = strtotime($this->updated_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [updated_at] as date/time value: " . var_export($this->updated_at, true));
    +			}
    +		} else {
    +			$ts = $this->updated_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getExpiresAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->expires_at === null || $this->expires_at === '') {
    +			return null;
    +		} elseif (!is_int($this->expires_at)) {
    +						$ts = strtotime($this->expires_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [expires_at] as date/time value: " . var_export($this->expires_at, true));
    +			}
    +		} else {
    +			$ts = $this->expires_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getIsDeleted()
    +	{
    +
    +		return $this->is_deleted;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = AdminMessagePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setSubject($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->subject !== $v) {
    +			$this->subject = $v;
    +			$this->modifiedColumns[] = AdminMessagePeer::SUBJECT;
    +		}
    +
    +	} 
    +	
    +	public function setMessage($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->message !== $v) {
    +			$this->message = $v;
    +			$this->modifiedColumns[] = AdminMessagePeer::MESSAGE;
    +		}
    +
    +	} 
    +	
    +	public function setAuthor($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->author !== $v) {
    +			$this->author = $v;
    +			$this->modifiedColumns[] = AdminMessagePeer::AUTHOR;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setUpdatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [updated_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->updated_at !== $ts) {
    +			$this->updated_at = $ts;
    +			$this->modifiedColumns[] = AdminMessagePeer::UPDATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setExpiresAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [expires_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->expires_at !== $ts) {
    +			$this->expires_at = $ts;
    +			$this->modifiedColumns[] = AdminMessagePeer::EXPIRES_AT;
    +		}
    +
    +	} 
    +	
    +	public function setIsDeleted($v)
    +	{
    +
    +		if ($this->is_deleted !== $v || $v === false) {
    +			$this->is_deleted = $v;
    +			$this->modifiedColumns[] = AdminMessagePeer::IS_DELETED;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->subject = $rs->getString($startcol + 1);
    +
    +			$this->message = $rs->getString($startcol + 2);
    +
    +			$this->author = $rs->getInt($startcol + 3);
    +
    +			$this->updated_at = $rs->getTimestamp($startcol + 4, null);
    +
    +			$this->expires_at = $rs->getTimestamp($startcol + 5, null);
    +
    +			$this->is_deleted = $rs->getBoolean($startcol + 6);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 7; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating AdminMessage object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseAdminMessage:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(AdminMessagePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			AdminMessagePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseAdminMessage:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseAdminMessage:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isModified() && !$this->isColumnModified(AdminMessagePeer::UPDATED_AT))
    +    {
    +      $this->setUpdatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(AdminMessagePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseAdminMessage:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = AdminMessagePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += AdminMessagePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = AdminMessagePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = AdminMessagePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getSubject();
    +				break;
    +			case 2:
    +				return $this->getMessage();
    +				break;
    +			case 3:
    +				return $this->getAuthor();
    +				break;
    +			case 4:
    +				return $this->getUpdatedAt();
    +				break;
    +			case 5:
    +				return $this->getExpiresAt();
    +				break;
    +			case 6:
    +				return $this->getIsDeleted();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = AdminMessagePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getSubject(),
    +			$keys[2] => $this->getMessage(),
    +			$keys[3] => $this->getAuthor(),
    +			$keys[4] => $this->getUpdatedAt(),
    +			$keys[5] => $this->getExpiresAt(),
    +			$keys[6] => $this->getIsDeleted(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = AdminMessagePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setSubject($value);
    +				break;
    +			case 2:
    +				$this->setMessage($value);
    +				break;
    +			case 3:
    +				$this->setAuthor($value);
    +				break;
    +			case 4:
    +				$this->setUpdatedAt($value);
    +				break;
    +			case 5:
    +				$this->setExpiresAt($value);
    +				break;
    +			case 6:
    +				$this->setIsDeleted($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = AdminMessagePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setSubject($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setMessage($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setAuthor($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setUpdatedAt($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setExpiresAt($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setIsDeleted($arr[$keys[6]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(AdminMessagePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(AdminMessagePeer::ID)) $criteria->add(AdminMessagePeer::ID, $this->id);
    +		if ($this->isColumnModified(AdminMessagePeer::SUBJECT)) $criteria->add(AdminMessagePeer::SUBJECT, $this->subject);
    +		if ($this->isColumnModified(AdminMessagePeer::MESSAGE)) $criteria->add(AdminMessagePeer::MESSAGE, $this->message);
    +		if ($this->isColumnModified(AdminMessagePeer::AUTHOR)) $criteria->add(AdminMessagePeer::AUTHOR, $this->author);
    +		if ($this->isColumnModified(AdminMessagePeer::UPDATED_AT)) $criteria->add(AdminMessagePeer::UPDATED_AT, $this->updated_at);
    +		if ($this->isColumnModified(AdminMessagePeer::EXPIRES_AT)) $criteria->add(AdminMessagePeer::EXPIRES_AT, $this->expires_at);
    +		if ($this->isColumnModified(AdminMessagePeer::IS_DELETED)) $criteria->add(AdminMessagePeer::IS_DELETED, $this->is_deleted);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(AdminMessagePeer::DATABASE_NAME);
    +
    +		$criteria->add(AdminMessagePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setSubject($this->subject);
    +
    +		$copyObj->setMessage($this->message);
    +
    +		$copyObj->setAuthor($this->author);
    +
    +		$copyObj->setUpdatedAt($this->updated_at);
    +
    +		$copyObj->setExpiresAt($this->expires_at);
    +
    +		$copyObj->setIsDeleted($this->is_deleted);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new AdminMessagePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setAuthor(NULL);
    +		} else {
    +			$this->setAuthor($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->author !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->author, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseAdminMessage:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseAdminMessage::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseAdminMessagePeer.php b/lib/model/om/BaseAdminMessagePeer.php
    new file mode 100644
    index 0000000..b543c85
    --- /dev/null
    +++ b/lib/model/om/BaseAdminMessagePeer.php
    @@ -0,0 +1,597 @@
    + array ('Id', 'Subject', 'Message', 'Author', 'UpdatedAt', 'ExpiresAt', 'IsDeleted', ),
    +		BasePeer::TYPE_COLNAME => array (AdminMessagePeer::ID, AdminMessagePeer::SUBJECT, AdminMessagePeer::MESSAGE, AdminMessagePeer::AUTHOR, AdminMessagePeer::UPDATED_AT, AdminMessagePeer::EXPIRES_AT, AdminMessagePeer::IS_DELETED, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'subject', 'message', 'author', 'updated_at', 'expires_at', 'is_deleted', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Subject' => 1, 'Message' => 2, 'Author' => 3, 'UpdatedAt' => 4, 'ExpiresAt' => 5, 'IsDeleted' => 6, ),
    +		BasePeer::TYPE_COLNAME => array (AdminMessagePeer::ID => 0, AdminMessagePeer::SUBJECT => 1, AdminMessagePeer::MESSAGE => 2, AdminMessagePeer::AUTHOR => 3, AdminMessagePeer::UPDATED_AT => 4, AdminMessagePeer::EXPIRES_AT => 5, AdminMessagePeer::IS_DELETED => 6, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'subject' => 1, 'message' => 2, 'author' => 3, 'updated_at' => 4, 'expires_at' => 5, 'is_deleted' => 6, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/AdminMessageMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.AdminMessageMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = AdminMessagePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(AdminMessagePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(AdminMessagePeer::ID);
    +
    +		$criteria->addSelectColumn(AdminMessagePeer::SUBJECT);
    +
    +		$criteria->addSelectColumn(AdminMessagePeer::MESSAGE);
    +
    +		$criteria->addSelectColumn(AdminMessagePeer::AUTHOR);
    +
    +		$criteria->addSelectColumn(AdminMessagePeer::UPDATED_AT);
    +
    +		$criteria->addSelectColumn(AdminMessagePeer::EXPIRES_AT);
    +
    +		$criteria->addSelectColumn(AdminMessagePeer::IS_DELETED);
    +
    +	}
    +
    +	const COUNT = 'COUNT(admin_message.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT admin_message.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(AdminMessagePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(AdminMessagePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = AdminMessagePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = AdminMessagePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return AdminMessagePeer::populateObjects(AdminMessagePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseAdminMessagePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseAdminMessagePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			AdminMessagePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = AdminMessagePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(AdminMessagePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(AdminMessagePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(AdminMessagePeer::AUTHOR, sfGuardUserPeer::ID);
    +
    +		$rs = AdminMessagePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		AdminMessagePeer::addSelectColumns($c);
    +		$startcol = (AdminMessagePeer::NUM_COLUMNS - AdminMessagePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(AdminMessagePeer::AUTHOR, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = AdminMessagePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addAdminMessage($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initAdminMessages();
    +				$obj2->addAdminMessage($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(AdminMessagePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(AdminMessagePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(AdminMessagePeer::AUTHOR, sfGuardUserPeer::ID);
    +
    +		$rs = AdminMessagePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		AdminMessagePeer::addSelectColumns($c);
    +		$startcol2 = (AdminMessagePeer::NUM_COLUMNS - AdminMessagePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(AdminMessagePeer::AUTHOR, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = AdminMessagePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addAdminMessage($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initAdminMessages();
    +				$obj2->addAdminMessage($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return AdminMessagePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseAdminMessagePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseAdminMessagePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(AdminMessagePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseAdminMessagePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseAdminMessagePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseAdminMessagePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseAdminMessagePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(AdminMessagePeer::ID);
    +			$selectCriteria->add(AdminMessagePeer::ID, $criteria->remove(AdminMessagePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseAdminMessagePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseAdminMessagePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(AdminMessagePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(AdminMessagePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof AdminMessage) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(AdminMessagePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(AdminMessage $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(AdminMessagePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(AdminMessagePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(AdminMessagePeer::DATABASE_NAME, AdminMessagePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = AdminMessagePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(AdminMessagePeer::DATABASE_NAME);
    +
    +		$criteria->add(AdminMessagePeer::ID, $pk);
    +
    +
    +		$v = AdminMessagePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(AdminMessagePeer::ID, $pks, Criteria::IN);
    +			$objs = AdminMessagePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseAdminMessagePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/AdminMessageMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.AdminMessageMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArticle.php b/lib/model/om/BaseArticle.php
    new file mode 100644
    index 0000000..0495506
    --- /dev/null
    +++ b/lib/model/om/BaseArticle.php
    @@ -0,0 +1,2315 @@
    +id;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getAuthorId()
    +	{
    +
    +		return $this->author_id;
    +	}
    +
    +	
    +	public function getBaseTitle()
    +	{
    +
    +		return $this->base_title;
    +	}
    +
    +	
    +	public function getPermalink()
    +	{
    +
    +		return $this->permalink;
    +	}
    +
    +	
    +	public function getIngress()
    +	{
    +
    +		return $this->ingress;
    +	}
    +
    +	
    +	public function getContent()
    +	{
    +
    +		return $this->content;
    +	}
    +
    +	
    +	public function getUpdatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->updated_at === null || $this->updated_at === '') {
    +			return null;
    +		} elseif (!is_int($this->updated_at)) {
    +						$ts = strtotime($this->updated_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [updated_at] as date/time value: " . var_export($this->updated_at, true));
    +			}
    +		} else {
    +			$ts = $this->updated_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getUpdatedBy()
    +	{
    +
    +		return $this->updated_by;
    +	}
    +
    +	
    +	public function getArticleType()
    +	{
    +
    +		return $this->article_type;
    +	}
    +
    +	
    +	public function getArticleOrder()
    +	{
    +
    +		return $this->article_order;
    +	}
    +
    +	
    +	public function getExpiresAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->expires_at === null || $this->expires_at === '') {
    +			return null;
    +		} elseif (!is_int($this->expires_at)) {
    +						$ts = strtotime($this->expires_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [expires_at] as date/time value: " . var_export($this->expires_at, true));
    +			}
    +		} else {
    +			$ts = $this->expires_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getStatus()
    +	{
    +
    +		return $this->status;
    +	}
    +
    +	
    +	public function getPublishedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->published_at === null || $this->published_at === '') {
    +			return null;
    +		} elseif (!is_int($this->published_at)) {
    +						$ts = strtotime($this->published_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [published_at] as date/time value: " . var_export($this->published_at, true));
    +			}
    +		} else {
    +			$ts = $this->published_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getBannerFileId()
    +	{
    +
    +		return $this->banner_file_id;
    +	}
    +
    +	
    +	public function getIsSticky()
    +	{
    +
    +		return $this->is_sticky;
    +	}
    +
    +	
    +	public function getFrontpage()
    +	{
    +
    +		return $this->frontpage;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArticlePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = ArticlePeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setAuthorId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->author_id !== $v) {
    +			$this->author_id = $v;
    +			$this->modifiedColumns[] = ArticlePeer::AUTHOR_ID;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setBaseTitle($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->base_title !== $v) {
    +			$this->base_title = $v;
    +			$this->modifiedColumns[] = ArticlePeer::BASE_TITLE;
    +		}
    +
    +	} 
    +	
    +	public function setPermalink($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->permalink !== $v) {
    +			$this->permalink = $v;
    +			$this->modifiedColumns[] = ArticlePeer::PERMALINK;
    +		}
    +
    +	} 
    +	
    +	public function setIngress($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->ingress !== $v) {
    +			$this->ingress = $v;
    +			$this->modifiedColumns[] = ArticlePeer::INGRESS;
    +		}
    +
    +	} 
    +	
    +	public function setContent($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->content !== $v) {
    +			$this->content = $v;
    +			$this->modifiedColumns[] = ArticlePeer::CONTENT;
    +		}
    +
    +	} 
    +	
    +	public function setUpdatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [updated_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->updated_at !== $ts) {
    +			$this->updated_at = $ts;
    +			$this->modifiedColumns[] = ArticlePeer::UPDATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setUpdatedBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->updated_by !== $v || $v === 0) {
    +			$this->updated_by = $v;
    +			$this->modifiedColumns[] = ArticlePeer::UPDATED_BY;
    +		}
    +
    +	} 
    +	
    +	public function setArticleType($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->article_type !== $v) {
    +			$this->article_type = $v;
    +			$this->modifiedColumns[] = ArticlePeer::ARTICLE_TYPE;
    +		}
    +
    +	} 
    +	
    +	public function setArticleOrder($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->article_order !== $v) {
    +			$this->article_order = $v;
    +			$this->modifiedColumns[] = ArticlePeer::ARTICLE_ORDER;
    +		}
    +
    +	} 
    +	
    +	public function setExpiresAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [expires_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->expires_at !== $ts) {
    +			$this->expires_at = $ts;
    +			$this->modifiedColumns[] = ArticlePeer::EXPIRES_AT;
    +		}
    +
    +	} 
    +	
    +	public function setStatus($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->status !== $v) {
    +			$this->status = $v;
    +			$this->modifiedColumns[] = ArticlePeer::STATUS;
    +		}
    +
    +	} 
    +	
    +	public function setPublishedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [published_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->published_at !== $ts) {
    +			$this->published_at = $ts;
    +			$this->modifiedColumns[] = ArticlePeer::PUBLISHED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setBannerFileId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->banner_file_id !== $v || $v === 0) {
    +			$this->banner_file_id = $v;
    +			$this->modifiedColumns[] = ArticlePeer::BANNER_FILE_ID;
    +		}
    +
    +		if ($this->aArticleFile !== null && $this->aArticleFile->getId() !== $v) {
    +			$this->aArticleFile = null;
    +		}
    +
    +	} 
    +	
    +	public function setIsSticky($v)
    +	{
    +
    +		if ($this->is_sticky !== $v || $v === false) {
    +			$this->is_sticky = $v;
    +			$this->modifiedColumns[] = ArticlePeer::IS_STICKY;
    +		}
    +
    +	} 
    +	
    +	public function setFrontpage($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->frontpage !== $v || $v === 0) {
    +			$this->frontpage = $v;
    +			$this->modifiedColumns[] = ArticlePeer::FRONTPAGE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 1, null);
    +
    +			$this->author_id = $rs->getInt($startcol + 2);
    +
    +			$this->base_title = $rs->getString($startcol + 3);
    +
    +			$this->permalink = $rs->getString($startcol + 4);
    +
    +			$this->ingress = $rs->getString($startcol + 5);
    +
    +			$this->content = $rs->getString($startcol + 6);
    +
    +			$this->updated_at = $rs->getTimestamp($startcol + 7, null);
    +
    +			$this->updated_by = $rs->getInt($startcol + 8);
    +
    +			$this->article_type = $rs->getInt($startcol + 9);
    +
    +			$this->article_order = $rs->getInt($startcol + 10);
    +
    +			$this->expires_at = $rs->getTimestamp($startcol + 11, null);
    +
    +			$this->status = $rs->getInt($startcol + 12);
    +
    +			$this->published_at = $rs->getTimestamp($startcol + 13, null);
    +
    +			$this->banner_file_id = $rs->getInt($startcol + 14);
    +
    +			$this->is_sticky = $rs->getBoolean($startcol + 15);
    +
    +			$this->frontpage = $rs->getInt($startcol + 16);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 17; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating Article object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticle:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticlePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArticlePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticle:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticle:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(ArticlePeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +    if ($this->isModified() && !$this->isColumnModified(ArticlePeer::UPDATED_AT))
    +    {
    +      $this->setUpdatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticlePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArticle:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +			if ($this->aArticleFile !== null) {
    +				if ($this->aArticleFile->isModified()) {
    +					$affectedRows += $this->aArticleFile->save($con);
    +				}
    +				$this->setArticleFile($this->aArticleFile);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArticlePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArticlePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collArticleI18ns !== null) {
    +				foreach($this->collArticleI18ns as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleArticleRelationsRelatedByFirstArticle !== null) {
    +				foreach($this->collArticleArticleRelationsRelatedByFirstArticle as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleArticleRelationsRelatedBySecondArticle !== null) {
    +				foreach($this->collArticleArticleRelationsRelatedBySecondArticle as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleArtworkRelations !== null) {
    +				foreach($this->collArticleArtworkRelations as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleCategorys !== null) {
    +				foreach($this->collArticleCategorys as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleSubreaktors !== null) {
    +				foreach($this->collArticleSubreaktors as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleAttachments !== null) {
    +				foreach($this->collArticleAttachments as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collFavourites !== null) {
    +				foreach($this->collFavourites as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aArticleFile !== null) {
    +				if (!$this->aArticleFile->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticleFile->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArticlePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collArticleI18ns !== null) {
    +					foreach($this->collArticleI18ns as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleArticleRelationsRelatedByFirstArticle !== null) {
    +					foreach($this->collArticleArticleRelationsRelatedByFirstArticle as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleArticleRelationsRelatedBySecondArticle !== null) {
    +					foreach($this->collArticleArticleRelationsRelatedBySecondArticle as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleArtworkRelations !== null) {
    +					foreach($this->collArticleArtworkRelations as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleCategorys !== null) {
    +					foreach($this->collArticleCategorys as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleSubreaktors !== null) {
    +					foreach($this->collArticleSubreaktors as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleAttachments !== null) {
    +					foreach($this->collArticleAttachments as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collFavourites !== null) {
    +					foreach($this->collFavourites as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticlePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getCreatedAt();
    +				break;
    +			case 2:
    +				return $this->getAuthorId();
    +				break;
    +			case 3:
    +				return $this->getBaseTitle();
    +				break;
    +			case 4:
    +				return $this->getPermalink();
    +				break;
    +			case 5:
    +				return $this->getIngress();
    +				break;
    +			case 6:
    +				return $this->getContent();
    +				break;
    +			case 7:
    +				return $this->getUpdatedAt();
    +				break;
    +			case 8:
    +				return $this->getUpdatedBy();
    +				break;
    +			case 9:
    +				return $this->getArticleType();
    +				break;
    +			case 10:
    +				return $this->getArticleOrder();
    +				break;
    +			case 11:
    +				return $this->getExpiresAt();
    +				break;
    +			case 12:
    +				return $this->getStatus();
    +				break;
    +			case 13:
    +				return $this->getPublishedAt();
    +				break;
    +			case 14:
    +				return $this->getBannerFileId();
    +				break;
    +			case 15:
    +				return $this->getIsSticky();
    +				break;
    +			case 16:
    +				return $this->getFrontpage();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticlePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getCreatedAt(),
    +			$keys[2] => $this->getAuthorId(),
    +			$keys[3] => $this->getBaseTitle(),
    +			$keys[4] => $this->getPermalink(),
    +			$keys[5] => $this->getIngress(),
    +			$keys[6] => $this->getContent(),
    +			$keys[7] => $this->getUpdatedAt(),
    +			$keys[8] => $this->getUpdatedBy(),
    +			$keys[9] => $this->getArticleType(),
    +			$keys[10] => $this->getArticleOrder(),
    +			$keys[11] => $this->getExpiresAt(),
    +			$keys[12] => $this->getStatus(),
    +			$keys[13] => $this->getPublishedAt(),
    +			$keys[14] => $this->getBannerFileId(),
    +			$keys[15] => $this->getIsSticky(),
    +			$keys[16] => $this->getFrontpage(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticlePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setCreatedAt($value);
    +				break;
    +			case 2:
    +				$this->setAuthorId($value);
    +				break;
    +			case 3:
    +				$this->setBaseTitle($value);
    +				break;
    +			case 4:
    +				$this->setPermalink($value);
    +				break;
    +			case 5:
    +				$this->setIngress($value);
    +				break;
    +			case 6:
    +				$this->setContent($value);
    +				break;
    +			case 7:
    +				$this->setUpdatedAt($value);
    +				break;
    +			case 8:
    +				$this->setUpdatedBy($value);
    +				break;
    +			case 9:
    +				$this->setArticleType($value);
    +				break;
    +			case 10:
    +				$this->setArticleOrder($value);
    +				break;
    +			case 11:
    +				$this->setExpiresAt($value);
    +				break;
    +			case 12:
    +				$this->setStatus($value);
    +				break;
    +			case 13:
    +				$this->setPublishedAt($value);
    +				break;
    +			case 14:
    +				$this->setBannerFileId($value);
    +				break;
    +			case 15:
    +				$this->setIsSticky($value);
    +				break;
    +			case 16:
    +				$this->setFrontpage($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticlePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCreatedAt($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setAuthorId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setBaseTitle($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setPermalink($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setIngress($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setContent($arr[$keys[6]]);
    +		if (array_key_exists($keys[7], $arr)) $this->setUpdatedAt($arr[$keys[7]]);
    +		if (array_key_exists($keys[8], $arr)) $this->setUpdatedBy($arr[$keys[8]]);
    +		if (array_key_exists($keys[9], $arr)) $this->setArticleType($arr[$keys[9]]);
    +		if (array_key_exists($keys[10], $arr)) $this->setArticleOrder($arr[$keys[10]]);
    +		if (array_key_exists($keys[11], $arr)) $this->setExpiresAt($arr[$keys[11]]);
    +		if (array_key_exists($keys[12], $arr)) $this->setStatus($arr[$keys[12]]);
    +		if (array_key_exists($keys[13], $arr)) $this->setPublishedAt($arr[$keys[13]]);
    +		if (array_key_exists($keys[14], $arr)) $this->setBannerFileId($arr[$keys[14]]);
    +		if (array_key_exists($keys[15], $arr)) $this->setIsSticky($arr[$keys[15]]);
    +		if (array_key_exists($keys[16], $arr)) $this->setFrontpage($arr[$keys[16]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArticlePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArticlePeer::ID)) $criteria->add(ArticlePeer::ID, $this->id);
    +		if ($this->isColumnModified(ArticlePeer::CREATED_AT)) $criteria->add(ArticlePeer::CREATED_AT, $this->created_at);
    +		if ($this->isColumnModified(ArticlePeer::AUTHOR_ID)) $criteria->add(ArticlePeer::AUTHOR_ID, $this->author_id);
    +		if ($this->isColumnModified(ArticlePeer::BASE_TITLE)) $criteria->add(ArticlePeer::BASE_TITLE, $this->base_title);
    +		if ($this->isColumnModified(ArticlePeer::PERMALINK)) $criteria->add(ArticlePeer::PERMALINK, $this->permalink);
    +		if ($this->isColumnModified(ArticlePeer::INGRESS)) $criteria->add(ArticlePeer::INGRESS, $this->ingress);
    +		if ($this->isColumnModified(ArticlePeer::CONTENT)) $criteria->add(ArticlePeer::CONTENT, $this->content);
    +		if ($this->isColumnModified(ArticlePeer::UPDATED_AT)) $criteria->add(ArticlePeer::UPDATED_AT, $this->updated_at);
    +		if ($this->isColumnModified(ArticlePeer::UPDATED_BY)) $criteria->add(ArticlePeer::UPDATED_BY, $this->updated_by);
    +		if ($this->isColumnModified(ArticlePeer::ARTICLE_TYPE)) $criteria->add(ArticlePeer::ARTICLE_TYPE, $this->article_type);
    +		if ($this->isColumnModified(ArticlePeer::ARTICLE_ORDER)) $criteria->add(ArticlePeer::ARTICLE_ORDER, $this->article_order);
    +		if ($this->isColumnModified(ArticlePeer::EXPIRES_AT)) $criteria->add(ArticlePeer::EXPIRES_AT, $this->expires_at);
    +		if ($this->isColumnModified(ArticlePeer::STATUS)) $criteria->add(ArticlePeer::STATUS, $this->status);
    +		if ($this->isColumnModified(ArticlePeer::PUBLISHED_AT)) $criteria->add(ArticlePeer::PUBLISHED_AT, $this->published_at);
    +		if ($this->isColumnModified(ArticlePeer::BANNER_FILE_ID)) $criteria->add(ArticlePeer::BANNER_FILE_ID, $this->banner_file_id);
    +		if ($this->isColumnModified(ArticlePeer::IS_STICKY)) $criteria->add(ArticlePeer::IS_STICKY, $this->is_sticky);
    +		if ($this->isColumnModified(ArticlePeer::FRONTPAGE)) $criteria->add(ArticlePeer::FRONTPAGE, $this->frontpage);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArticlePeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticlePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +		$copyObj->setAuthorId($this->author_id);
    +
    +		$copyObj->setBaseTitle($this->base_title);
    +
    +		$copyObj->setPermalink($this->permalink);
    +
    +		$copyObj->setIngress($this->ingress);
    +
    +		$copyObj->setContent($this->content);
    +
    +		$copyObj->setUpdatedAt($this->updated_at);
    +
    +		$copyObj->setUpdatedBy($this->updated_by);
    +
    +		$copyObj->setArticleType($this->article_type);
    +
    +		$copyObj->setArticleOrder($this->article_order);
    +
    +		$copyObj->setExpiresAt($this->expires_at);
    +
    +		$copyObj->setStatus($this->status);
    +
    +		$copyObj->setPublishedAt($this->published_at);
    +
    +		$copyObj->setBannerFileId($this->banner_file_id);
    +
    +		$copyObj->setIsSticky($this->is_sticky);
    +
    +		$copyObj->setFrontpage($this->frontpage);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getArticleI18ns() as $relObj) {
    +				$copyObj->addArticleI18n($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleArticleRelationsRelatedByFirstArticle() as $relObj) {
    +				$copyObj->addArticleArticleRelationRelatedByFirstArticle($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleArticleRelationsRelatedBySecondArticle() as $relObj) {
    +				$copyObj->addArticleArticleRelationRelatedBySecondArticle($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleArtworkRelations() as $relObj) {
    +				$copyObj->addArticleArtworkRelation($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleCategorys() as $relObj) {
    +				$copyObj->addArticleCategory($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleSubreaktors() as $relObj) {
    +				$copyObj->addArticleSubreaktor($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleAttachments() as $relObj) {
    +				$copyObj->addArticleAttachment($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getFavourites() as $relObj) {
    +				$copyObj->addFavourite($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArticlePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setAuthorId(NULL);
    +		} else {
    +			$this->setAuthorId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->author_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->author_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +	
    +	public function setArticleFile($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setBannerFileId('0');
    +		} else {
    +			$this->setBannerFileId($v->getId());
    +		}
    +
    +
    +		$this->aArticleFile = $v;
    +	}
    +
    +
    +	
    +	public function getArticleFile($con = null)
    +	{
    +		if ($this->aArticleFile === null && ($this->banner_file_id !== null)) {
    +						include_once 'lib/model/om/BaseArticleFilePeer.php';
    +
    +			$this->aArticleFile = ArticleFilePeer::retrieveByPK($this->banner_file_id, $con);
    +
    +			
    +		}
    +		return $this->aArticleFile;
    +	}
    +
    +	
    +	public function initArticleI18ns()
    +	{
    +		if ($this->collArticleI18ns === null) {
    +			$this->collArticleI18ns = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleI18ns($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleI18ns === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleI18ns = array();
    +			} else {
    +
    +				$criteria->add(ArticleI18nPeer::ID, $this->getId());
    +
    +				ArticleI18nPeer::addSelectColumns($criteria);
    +				$this->collArticleI18ns = ArticleI18nPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleI18nPeer::ID, $this->getId());
    +
    +				ArticleI18nPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleI18nCriteria) || !$this->lastArticleI18nCriteria->equals($criteria)) {
    +					$this->collArticleI18ns = ArticleI18nPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleI18nCriteria = $criteria;
    +		return $this->collArticleI18ns;
    +	}
    +
    +	
    +	public function countArticleI18ns($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleI18nPeer::ID, $this->getId());
    +
    +		return ArticleI18nPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleI18n(ArticleI18n $l)
    +	{
    +		$this->collArticleI18ns[] = $l;
    +		$l->setArticle($this);
    +	}
    +
    +	
    +	public function initArticleArticleRelationsRelatedByFirstArticle()
    +	{
    +		if ($this->collArticleArticleRelationsRelatedByFirstArticle === null) {
    +			$this->collArticleArticleRelationsRelatedByFirstArticle = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleArticleRelationsRelatedByFirstArticle($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArticleRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArticleRelationsRelatedByFirstArticle === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleArticleRelationsRelatedByFirstArticle = array();
    +			} else {
    +
    +				$criteria->add(ArticleArticleRelationPeer::FIRST_ARTICLE, $this->getId());
    +
    +				ArticleArticleRelationPeer::addSelectColumns($criteria);
    +				$this->collArticleArticleRelationsRelatedByFirstArticle = ArticleArticleRelationPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleArticleRelationPeer::FIRST_ARTICLE, $this->getId());
    +
    +				ArticleArticleRelationPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleArticleRelationRelatedByFirstArticleCriteria) || !$this->lastArticleArticleRelationRelatedByFirstArticleCriteria->equals($criteria)) {
    +					$this->collArticleArticleRelationsRelatedByFirstArticle = ArticleArticleRelationPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleArticleRelationRelatedByFirstArticleCriteria = $criteria;
    +		return $this->collArticleArticleRelationsRelatedByFirstArticle;
    +	}
    +
    +	
    +	public function countArticleArticleRelationsRelatedByFirstArticle($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArticleRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleArticleRelationPeer::FIRST_ARTICLE, $this->getId());
    +
    +		return ArticleArticleRelationPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleArticleRelationRelatedByFirstArticle(ArticleArticleRelation $l)
    +	{
    +		$this->collArticleArticleRelationsRelatedByFirstArticle[] = $l;
    +		$l->setArticleRelatedByFirstArticle($this);
    +	}
    +
    +
    +	
    +	public function getArticleArticleRelationsRelatedByFirstArticleJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArticleRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArticleRelationsRelatedByFirstArticle === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleArticleRelationsRelatedByFirstArticle = array();
    +			} else {
    +
    +				$criteria->add(ArticleArticleRelationPeer::FIRST_ARTICLE, $this->getId());
    +
    +				$this->collArticleArticleRelationsRelatedByFirstArticle = ArticleArticleRelationPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleArticleRelationPeer::FIRST_ARTICLE, $this->getId());
    +
    +			if (!isset($this->lastArticleArticleRelationRelatedByFirstArticleCriteria) || !$this->lastArticleArticleRelationRelatedByFirstArticleCriteria->equals($criteria)) {
    +				$this->collArticleArticleRelationsRelatedByFirstArticle = ArticleArticleRelationPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleArticleRelationRelatedByFirstArticleCriteria = $criteria;
    +
    +		return $this->collArticleArticleRelationsRelatedByFirstArticle;
    +	}
    +
    +	
    +	public function initArticleArticleRelationsRelatedBySecondArticle()
    +	{
    +		if ($this->collArticleArticleRelationsRelatedBySecondArticle === null) {
    +			$this->collArticleArticleRelationsRelatedBySecondArticle = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleArticleRelationsRelatedBySecondArticle($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArticleRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArticleRelationsRelatedBySecondArticle === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleArticleRelationsRelatedBySecondArticle = array();
    +			} else {
    +
    +				$criteria->add(ArticleArticleRelationPeer::SECOND_ARTICLE, $this->getId());
    +
    +				ArticleArticleRelationPeer::addSelectColumns($criteria);
    +				$this->collArticleArticleRelationsRelatedBySecondArticle = ArticleArticleRelationPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleArticleRelationPeer::SECOND_ARTICLE, $this->getId());
    +
    +				ArticleArticleRelationPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleArticleRelationRelatedBySecondArticleCriteria) || !$this->lastArticleArticleRelationRelatedBySecondArticleCriteria->equals($criteria)) {
    +					$this->collArticleArticleRelationsRelatedBySecondArticle = ArticleArticleRelationPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleArticleRelationRelatedBySecondArticleCriteria = $criteria;
    +		return $this->collArticleArticleRelationsRelatedBySecondArticle;
    +	}
    +
    +	
    +	public function countArticleArticleRelationsRelatedBySecondArticle($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArticleRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleArticleRelationPeer::SECOND_ARTICLE, $this->getId());
    +
    +		return ArticleArticleRelationPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleArticleRelationRelatedBySecondArticle(ArticleArticleRelation $l)
    +	{
    +		$this->collArticleArticleRelationsRelatedBySecondArticle[] = $l;
    +		$l->setArticleRelatedBySecondArticle($this);
    +	}
    +
    +
    +	
    +	public function getArticleArticleRelationsRelatedBySecondArticleJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArticleRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArticleRelationsRelatedBySecondArticle === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleArticleRelationsRelatedBySecondArticle = array();
    +			} else {
    +
    +				$criteria->add(ArticleArticleRelationPeer::SECOND_ARTICLE, $this->getId());
    +
    +				$this->collArticleArticleRelationsRelatedBySecondArticle = ArticleArticleRelationPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleArticleRelationPeer::SECOND_ARTICLE, $this->getId());
    +
    +			if (!isset($this->lastArticleArticleRelationRelatedBySecondArticleCriteria) || !$this->lastArticleArticleRelationRelatedBySecondArticleCriteria->equals($criteria)) {
    +				$this->collArticleArticleRelationsRelatedBySecondArticle = ArticleArticleRelationPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleArticleRelationRelatedBySecondArticleCriteria = $criteria;
    +
    +		return $this->collArticleArticleRelationsRelatedBySecondArticle;
    +	}
    +
    +	
    +	public function initArticleArtworkRelations()
    +	{
    +		if ($this->collArticleArtworkRelations === null) {
    +			$this->collArticleArtworkRelations = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleArtworkRelations($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArtworkRelations === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleArtworkRelations = array();
    +			} else {
    +
    +				$criteria->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId());
    +
    +				ArticleArtworkRelationPeer::addSelectColumns($criteria);
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId());
    +
    +				ArticleArtworkRelationPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) {
    +					$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleArtworkRelationCriteria = $criteria;
    +		return $this->collArticleArtworkRelations;
    +	}
    +
    +	
    +	public function countArticleArtworkRelations($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId());
    +
    +		return ArticleArtworkRelationPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleArtworkRelation(ArticleArtworkRelation $l)
    +	{
    +		$this->collArticleArtworkRelations[] = $l;
    +		$l->setArticle($this);
    +	}
    +
    +
    +	
    +	public function getArticleArtworkRelationsJoinReaktorArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArtworkRelations === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleArtworkRelations = array();
    +			} else {
    +
    +				$criteria->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId());
    +
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) {
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleArtworkRelationCriteria = $criteria;
    +
    +		return $this->collArticleArtworkRelations;
    +	}
    +
    +
    +	
    +	public function getArticleArtworkRelationsJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArtworkRelations === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleArtworkRelations = array();
    +			} else {
    +
    +				$criteria->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId());
    +
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) {
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleArtworkRelationCriteria = $criteria;
    +
    +		return $this->collArticleArtworkRelations;
    +	}
    +
    +	
    +	public function initArticleCategorys()
    +	{
    +		if ($this->collArticleCategorys === null) {
    +			$this->collArticleCategorys = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleCategorys($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleCategoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleCategorys === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleCategorys = array();
    +			} else {
    +
    +				$criteria->add(ArticleCategoryPeer::ARTICLE_ID, $this->getId());
    +
    +				ArticleCategoryPeer::addSelectColumns($criteria);
    +				$this->collArticleCategorys = ArticleCategoryPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleCategoryPeer::ARTICLE_ID, $this->getId());
    +
    +				ArticleCategoryPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleCategoryCriteria) || !$this->lastArticleCategoryCriteria->equals($criteria)) {
    +					$this->collArticleCategorys = ArticleCategoryPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleCategoryCriteria = $criteria;
    +		return $this->collArticleCategorys;
    +	}
    +
    +	
    +	public function countArticleCategorys($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleCategoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleCategoryPeer::ARTICLE_ID, $this->getId());
    +
    +		return ArticleCategoryPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleCategory(ArticleCategory $l)
    +	{
    +		$this->collArticleCategorys[] = $l;
    +		$l->setArticle($this);
    +	}
    +
    +
    +	
    +	public function getArticleCategorysJoinCategory($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleCategoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleCategorys === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleCategorys = array();
    +			} else {
    +
    +				$criteria->add(ArticleCategoryPeer::ARTICLE_ID, $this->getId());
    +
    +				$this->collArticleCategorys = ArticleCategoryPeer::doSelectJoinCategory($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleCategoryPeer::ARTICLE_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleCategoryCriteria) || !$this->lastArticleCategoryCriteria->equals($criteria)) {
    +				$this->collArticleCategorys = ArticleCategoryPeer::doSelectJoinCategory($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleCategoryCriteria = $criteria;
    +
    +		return $this->collArticleCategorys;
    +	}
    +
    +	
    +	public function initArticleSubreaktors()
    +	{
    +		if ($this->collArticleSubreaktors === null) {
    +			$this->collArticleSubreaktors = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleSubreaktors($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleSubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleSubreaktors === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleSubreaktors = array();
    +			} else {
    +
    +				$criteria->add(ArticleSubreaktorPeer::ARTICLE_ID, $this->getId());
    +
    +				ArticleSubreaktorPeer::addSelectColumns($criteria);
    +				$this->collArticleSubreaktors = ArticleSubreaktorPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleSubreaktorPeer::ARTICLE_ID, $this->getId());
    +
    +				ArticleSubreaktorPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleSubreaktorCriteria) || !$this->lastArticleSubreaktorCriteria->equals($criteria)) {
    +					$this->collArticleSubreaktors = ArticleSubreaktorPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleSubreaktorCriteria = $criteria;
    +		return $this->collArticleSubreaktors;
    +	}
    +
    +	
    +	public function countArticleSubreaktors($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleSubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleSubreaktorPeer::ARTICLE_ID, $this->getId());
    +
    +		return ArticleSubreaktorPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleSubreaktor(ArticleSubreaktor $l)
    +	{
    +		$this->collArticleSubreaktors[] = $l;
    +		$l->setArticle($this);
    +	}
    +
    +
    +	
    +	public function getArticleSubreaktorsJoinSubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleSubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleSubreaktors === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleSubreaktors = array();
    +			} else {
    +
    +				$criteria->add(ArticleSubreaktorPeer::ARTICLE_ID, $this->getId());
    +
    +				$this->collArticleSubreaktors = ArticleSubreaktorPeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleSubreaktorPeer::ARTICLE_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleSubreaktorCriteria) || !$this->lastArticleSubreaktorCriteria->equals($criteria)) {
    +				$this->collArticleSubreaktors = ArticleSubreaktorPeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleSubreaktorCriteria = $criteria;
    +
    +		return $this->collArticleSubreaktors;
    +	}
    +
    +	
    +	public function initArticleAttachments()
    +	{
    +		if ($this->collArticleAttachments === null) {
    +			$this->collArticleAttachments = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleAttachments($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleAttachmentPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleAttachments === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleAttachments = array();
    +			} else {
    +
    +				$criteria->add(ArticleAttachmentPeer::ARTICLE_ID, $this->getId());
    +
    +				ArticleAttachmentPeer::addSelectColumns($criteria);
    +				$this->collArticleAttachments = ArticleAttachmentPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleAttachmentPeer::ARTICLE_ID, $this->getId());
    +
    +				ArticleAttachmentPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleAttachmentCriteria) || !$this->lastArticleAttachmentCriteria->equals($criteria)) {
    +					$this->collArticleAttachments = ArticleAttachmentPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleAttachmentCriteria = $criteria;
    +		return $this->collArticleAttachments;
    +	}
    +
    +	
    +	public function countArticleAttachments($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleAttachmentPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleAttachmentPeer::ARTICLE_ID, $this->getId());
    +
    +		return ArticleAttachmentPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleAttachment(ArticleAttachment $l)
    +	{
    +		$this->collArticleAttachments[] = $l;
    +		$l->setArticle($this);
    +	}
    +
    +
    +	
    +	public function getArticleAttachmentsJoinArticleFile($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleAttachmentPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleAttachments === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleAttachments = array();
    +			} else {
    +
    +				$criteria->add(ArticleAttachmentPeer::ARTICLE_ID, $this->getId());
    +
    +				$this->collArticleAttachments = ArticleAttachmentPeer::doSelectJoinArticleFile($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleAttachmentPeer::ARTICLE_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleAttachmentCriteria) || !$this->lastArticleAttachmentCriteria->equals($criteria)) {
    +				$this->collArticleAttachments = ArticleAttachmentPeer::doSelectJoinArticleFile($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleAttachmentCriteria = $criteria;
    +
    +		return $this->collArticleAttachments;
    +	}
    +
    +	
    +	public function initFavourites()
    +	{
    +		if ($this->collFavourites === null) {
    +			$this->collFavourites = array();
    +		}
    +	}
    +
    +	
    +	public function getFavourites($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFavourites === null) {
    +			if ($this->isNew()) {
    +			   $this->collFavourites = array();
    +			} else {
    +
    +				$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +				FavouritePeer::addSelectColumns($criteria);
    +				$this->collFavourites = FavouritePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +				FavouritePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastFavouriteCriteria) || !$this->lastFavouriteCriteria->equals($criteria)) {
    +					$this->collFavourites = FavouritePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastFavouriteCriteria = $criteria;
    +		return $this->collFavourites;
    +	}
    +
    +	
    +	public function countFavourites($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +		return FavouritePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addFavourite(Favourite $l)
    +	{
    +		$this->collFavourites[] = $l;
    +		$l->setArticle($this);
    +	}
    +
    +
    +	
    +	public function getFavouritesJoinsfGuardUserRelatedByUserId($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFavourites === null) {
    +			if ($this->isNew()) {
    +				$this->collFavourites = array();
    +			} else {
    +
    +				$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +				$this->collFavourites = FavouritePeer::doSelectJoinsfGuardUserRelatedByUserId($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +			if (!isset($this->lastFavouriteCriteria) || !$this->lastFavouriteCriteria->equals($criteria)) {
    +				$this->collFavourites = FavouritePeer::doSelectJoinsfGuardUserRelatedByUserId($criteria, $con);
    +			}
    +		}
    +		$this->lastFavouriteCriteria = $criteria;
    +
    +		return $this->collFavourites;
    +	}
    +
    +
    +	
    +	public function getFavouritesJoinReaktorArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFavourites === null) {
    +			if ($this->isNew()) {
    +				$this->collFavourites = array();
    +			} else {
    +
    +				$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +				$this->collFavourites = FavouritePeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +			if (!isset($this->lastFavouriteCriteria) || !$this->lastFavouriteCriteria->equals($criteria)) {
    +				$this->collFavourites = FavouritePeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		}
    +		$this->lastFavouriteCriteria = $criteria;
    +
    +		return $this->collFavourites;
    +	}
    +
    +
    +	
    +	public function getFavouritesJoinsfGuardUserRelatedByFriendId($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFavourites === null) {
    +			if ($this->isNew()) {
    +				$this->collFavourites = array();
    +			} else {
    +
    +				$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +				$this->collFavourites = FavouritePeer::doSelectJoinsfGuardUserRelatedByFriendId($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(FavouritePeer::ARTICLE_ID, $this->getId());
    +
    +			if (!isset($this->lastFavouriteCriteria) || !$this->lastFavouriteCriteria->equals($criteria)) {
    +				$this->collFavourites = FavouritePeer::doSelectJoinsfGuardUserRelatedByFriendId($criteria, $con);
    +			}
    +		}
    +		$this->lastFavouriteCriteria = $criteria;
    +
    +		return $this->collFavourites;
    +	}
    +
    +  public function getCulture()
    +  {
    +    return $this->culture;
    +  }
    +
    +  public function setCulture($culture)
    +  {
    +    $this->culture = $culture;
    +  }
    +
    +  public function getTitle()
    +  {
    +    $obj = $this->getCurrentArticleI18n();
    +
    +    return ($obj ? $obj->getTitle() : null);
    +  }
    +
    +  public function setTitle($value)
    +  {
    +    $this->getCurrentArticleI18n()->setTitle($value);
    +  }
    +
    +  protected $current_i18n = array();
    +
    +  public function getCurrentArticleI18n()
    +  {
    +    if (!isset($this->current_i18n[$this->culture]))
    +    {
    +      $obj = ArticleI18nPeer::retrieveByPK($this->getId(), $this->culture);
    +      if ($obj)
    +      {
    +        $this->setArticleI18nForCulture($obj, $this->culture);
    +      }
    +      else
    +      {
    +        $this->setArticleI18nForCulture(new ArticleI18n(), $this->culture);
    +        $this->current_i18n[$this->culture]->setCulture($this->culture);
    +      }
    +    }
    +
    +    return $this->current_i18n[$this->culture];
    +  }
    +
    +  public function setArticleI18nForCulture($object, $culture)
    +  {
    +    $this->current_i18n[$culture] = $object;
    +    $this->addArticleI18n($object);
    +  }
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArticle:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArticle::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArticleArticleRelation.php b/lib/model/om/BaseArticleArticleRelation.php
    new file mode 100644
    index 0000000..45771ee
    --- /dev/null
    +++ b/lib/model/om/BaseArticleArticleRelation.php
    @@ -0,0 +1,662 @@
    +id;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getFirstArticle()
    +	{
    +
    +		return $this->first_article;
    +	}
    +
    +	
    +	public function getSecondArticle()
    +	{
    +
    +		return $this->second_article;
    +	}
    +
    +	
    +	public function getCreatedBy()
    +	{
    +
    +		return $this->created_by;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArticleArticleRelationPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = ArticleArticleRelationPeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setFirstArticle($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->first_article !== $v) {
    +			$this->first_article = $v;
    +			$this->modifiedColumns[] = ArticleArticleRelationPeer::FIRST_ARTICLE;
    +		}
    +
    +		if ($this->aArticleRelatedByFirstArticle !== null && $this->aArticleRelatedByFirstArticle->getId() !== $v) {
    +			$this->aArticleRelatedByFirstArticle = null;
    +		}
    +
    +	} 
    +	
    +	public function setSecondArticle($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->second_article !== $v) {
    +			$this->second_article = $v;
    +			$this->modifiedColumns[] = ArticleArticleRelationPeer::SECOND_ARTICLE;
    +		}
    +
    +		if ($this->aArticleRelatedBySecondArticle !== null && $this->aArticleRelatedBySecondArticle->getId() !== $v) {
    +			$this->aArticleRelatedBySecondArticle = null;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->created_by !== $v) {
    +			$this->created_by = $v;
    +			$this->modifiedColumns[] = ArticleArticleRelationPeer::CREATED_BY;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 1, null);
    +
    +			$this->first_article = $rs->getInt($startcol + 2);
    +
    +			$this->second_article = $rs->getInt($startcol + 3);
    +
    +			$this->created_by = $rs->getInt($startcol + 4);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 5; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArticleArticleRelation object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelation:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleArticleRelationPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArticleArticleRelationPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelation:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelation:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(ArticleArticleRelationPeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleArticleRelationPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelation:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aArticleRelatedByFirstArticle !== null) {
    +				if ($this->aArticleRelatedByFirstArticle->isModified() || $this->aArticleRelatedByFirstArticle->getCurrentArticleI18n()->isModified()) {
    +					$affectedRows += $this->aArticleRelatedByFirstArticle->save($con);
    +				}
    +				$this->setArticleRelatedByFirstArticle($this->aArticleRelatedByFirstArticle);
    +			}
    +
    +			if ($this->aArticleRelatedBySecondArticle !== null) {
    +				if ($this->aArticleRelatedBySecondArticle->isModified() || $this->aArticleRelatedBySecondArticle->getCurrentArticleI18n()->isModified()) {
    +					$affectedRows += $this->aArticleRelatedBySecondArticle->save($con);
    +				}
    +				$this->setArticleRelatedBySecondArticle($this->aArticleRelatedBySecondArticle);
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArticleArticleRelationPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArticleArticleRelationPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aArticleRelatedByFirstArticle !== null) {
    +				if (!$this->aArticleRelatedByFirstArticle->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticleRelatedByFirstArticle->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aArticleRelatedBySecondArticle !== null) {
    +				if (!$this->aArticleRelatedBySecondArticle->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticleRelatedBySecondArticle->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArticleArticleRelationPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleArticleRelationPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getCreatedAt();
    +				break;
    +			case 2:
    +				return $this->getFirstArticle();
    +				break;
    +			case 3:
    +				return $this->getSecondArticle();
    +				break;
    +			case 4:
    +				return $this->getCreatedBy();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleArticleRelationPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getCreatedAt(),
    +			$keys[2] => $this->getFirstArticle(),
    +			$keys[3] => $this->getSecondArticle(),
    +			$keys[4] => $this->getCreatedBy(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleArticleRelationPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setCreatedAt($value);
    +				break;
    +			case 2:
    +				$this->setFirstArticle($value);
    +				break;
    +			case 3:
    +				$this->setSecondArticle($value);
    +				break;
    +			case 4:
    +				$this->setCreatedBy($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleArticleRelationPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCreatedAt($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setFirstArticle($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setSecondArticle($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setCreatedBy($arr[$keys[4]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArticleArticleRelationPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArticleArticleRelationPeer::ID)) $criteria->add(ArticleArticleRelationPeer::ID, $this->id);
    +		if ($this->isColumnModified(ArticleArticleRelationPeer::CREATED_AT)) $criteria->add(ArticleArticleRelationPeer::CREATED_AT, $this->created_at);
    +		if ($this->isColumnModified(ArticleArticleRelationPeer::FIRST_ARTICLE)) $criteria->add(ArticleArticleRelationPeer::FIRST_ARTICLE, $this->first_article);
    +		if ($this->isColumnModified(ArticleArticleRelationPeer::SECOND_ARTICLE)) $criteria->add(ArticleArticleRelationPeer::SECOND_ARTICLE, $this->second_article);
    +		if ($this->isColumnModified(ArticleArticleRelationPeer::CREATED_BY)) $criteria->add(ArticleArticleRelationPeer::CREATED_BY, $this->created_by);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArticleArticleRelationPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleArticleRelationPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +		$copyObj->setFirstArticle($this->first_article);
    +
    +		$copyObj->setSecondArticle($this->second_article);
    +
    +		$copyObj->setCreatedBy($this->created_by);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArticleArticleRelationPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setArticleRelatedByFirstArticle($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFirstArticle(NULL);
    +		} else {
    +			$this->setFirstArticle($v->getId());
    +		}
    +
    +
    +		$this->aArticleRelatedByFirstArticle = $v;
    +	}
    +
    +
    +	
    +	public function getArticleRelatedByFirstArticle($con = null)
    +	{
    +		if ($this->aArticleRelatedByFirstArticle === null && ($this->first_article !== null)) {
    +						include_once 'lib/model/om/BaseArticlePeer.php';
    +
    +			$this->aArticleRelatedByFirstArticle = ArticlePeer::retrieveByPK($this->first_article, $con);
    +
    +			
    +		}
    +		return $this->aArticleRelatedByFirstArticle;
    +	}
    +
    +	
    +	public function setArticleRelatedBySecondArticle($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSecondArticle(NULL);
    +		} else {
    +			$this->setSecondArticle($v->getId());
    +		}
    +
    +
    +		$this->aArticleRelatedBySecondArticle = $v;
    +	}
    +
    +
    +	
    +	public function getArticleRelatedBySecondArticle($con = null)
    +	{
    +		if ($this->aArticleRelatedBySecondArticle === null && ($this->second_article !== null)) {
    +						include_once 'lib/model/om/BaseArticlePeer.php';
    +
    +			$this->aArticleRelatedBySecondArticle = ArticlePeer::retrieveByPK($this->second_article, $con);
    +
    +			
    +		}
    +		return $this->aArticleRelatedBySecondArticle;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setCreatedBy(NULL);
    +		} else {
    +			$this->setCreatedBy($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->created_by !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->created_by, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArticleArticleRelation:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArticleArticleRelation::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArticleArticleRelationPeer.php b/lib/model/om/BaseArticleArticleRelationPeer.php
    new file mode 100644
    index 0000000..fcc13fc
    --- /dev/null
    +++ b/lib/model/om/BaseArticleArticleRelationPeer.php
    @@ -0,0 +1,1081 @@
    + array ('Id', 'CreatedAt', 'FirstArticle', 'SecondArticle', 'CreatedBy', ),
    +		BasePeer::TYPE_COLNAME => array (ArticleArticleRelationPeer::ID, ArticleArticleRelationPeer::CREATED_AT, ArticleArticleRelationPeer::FIRST_ARTICLE, ArticleArticleRelationPeer::SECOND_ARTICLE, ArticleArticleRelationPeer::CREATED_BY, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'created_at', 'first_article', 'second_article', 'created_by', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'CreatedAt' => 1, 'FirstArticle' => 2, 'SecondArticle' => 3, 'CreatedBy' => 4, ),
    +		BasePeer::TYPE_COLNAME => array (ArticleArticleRelationPeer::ID => 0, ArticleArticleRelationPeer::CREATED_AT => 1, ArticleArticleRelationPeer::FIRST_ARTICLE => 2, ArticleArticleRelationPeer::SECOND_ARTICLE => 3, ArticleArticleRelationPeer::CREATED_BY => 4, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'created_at' => 1, 'first_article' => 2, 'second_article' => 3, 'created_by' => 4, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArticleArticleRelationMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArticleArticleRelationMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArticleArticleRelationPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArticleArticleRelationPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArticleArticleRelationPeer::ID);
    +
    +		$criteria->addSelectColumn(ArticleArticleRelationPeer::CREATED_AT);
    +
    +		$criteria->addSelectColumn(ArticleArticleRelationPeer::FIRST_ARTICLE);
    +
    +		$criteria->addSelectColumn(ArticleArticleRelationPeer::SECOND_ARTICLE);
    +
    +		$criteria->addSelectColumn(ArticleArticleRelationPeer::CREATED_BY);
    +
    +	}
    +
    +	const COUNT = 'COUNT(article_article_relation.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT article_article_relation.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArticleArticleRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArticleArticleRelationPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArticleArticleRelationPeer::populateObjects(ArticleArticleRelationPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelationPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleArticleRelationPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArticleArticleRelationPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArticleArticleRelationPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinArticleRelatedByFirstArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::FIRST_ARTICLE, ArticlePeer::ID);
    +
    +		$rs = ArticleArticleRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinArticleRelatedBySecondArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::SECOND_ARTICLE, ArticlePeer::ID);
    +
    +		$rs = ArticleArticleRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleArticleRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticleRelatedByFirstArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArticleRelationPeer::addSelectColumns($c);
    +		$startcol = (ArticleArticleRelationPeer::NUM_COLUMNS - ArticleArticleRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticlePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleArticleRelationPeer::FIRST_ARTICLE, ArticlePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArticleRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticleRelatedByFirstArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleArticleRelationRelatedByFirstArticle($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleArticleRelationsRelatedByFirstArticle();
    +				$obj2->addArticleArticleRelationRelatedByFirstArticle($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticleRelatedBySecondArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArticleRelationPeer::addSelectColumns($c);
    +		$startcol = (ArticleArticleRelationPeer::NUM_COLUMNS - ArticleArticleRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticlePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleArticleRelationPeer::SECOND_ARTICLE, ArticlePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArticleRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticleRelatedBySecondArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleArticleRelationRelatedBySecondArticle($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleArticleRelationsRelatedBySecondArticle();
    +				$obj2->addArticleArticleRelationRelatedBySecondArticle($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArticleRelationPeer::addSelectColumns($c);
    +		$startcol = (ArticleArticleRelationPeer::NUM_COLUMNS - ArticleArticleRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleArticleRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArticleRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleArticleRelation($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleArticleRelations();
    +				$obj2->addArticleArticleRelation($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::FIRST_ARTICLE, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::SECOND_ARTICLE, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleArticleRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArticleRelationPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleArticleRelationPeer::NUM_COLUMNS - ArticleArticleRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArticlePeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleArticleRelationPeer::FIRST_ARTICLE, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleArticleRelationPeer::SECOND_ARTICLE, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleArticleRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArticleRelationPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticleRelatedByFirstArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleArticleRelationRelatedByFirstArticle($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleArticleRelationsRelatedByFirstArticle();
    +				$obj2->addArticleArticleRelationRelatedByFirstArticle($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArticleRelatedBySecondArticle(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleArticleRelationRelatedBySecondArticle($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleArticleRelationsRelatedBySecondArticle();
    +				$obj3->addArticleArticleRelationRelatedBySecondArticle($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4 = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addArticleArticleRelation($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initArticleArticleRelations();
    +				$obj4->addArticleArticleRelation($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticleRelatedByFirstArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleArticleRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticleRelatedBySecondArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleArticleRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArticleRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::FIRST_ARTICLE, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleArticleRelationPeer::SECOND_ARTICLE, ArticlePeer::ID);
    +
    +		$rs = ArticleArticleRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticleRelatedByFirstArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArticleRelationPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleArticleRelationPeer::NUM_COLUMNS - ArticleArticleRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleArticleRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArticleRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleArticleRelation($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleArticleRelations();
    +				$obj2->addArticleArticleRelation($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticleRelatedBySecondArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArticleRelationPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleArticleRelationPeer::NUM_COLUMNS - ArticleArticleRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleArticleRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArticleRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleArticleRelation($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleArticleRelations();
    +				$obj2->addArticleArticleRelation($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArticleRelationPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleArticleRelationPeer::NUM_COLUMNS - ArticleArticleRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArticlePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleArticleRelationPeer::FIRST_ARTICLE, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleArticleRelationPeer::SECOND_ARTICLE, ArticlePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArticleRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticleRelatedByFirstArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleArticleRelationRelatedByFirstArticle($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleArticleRelationsRelatedByFirstArticle();
    +				$obj2->addArticleArticleRelationRelatedByFirstArticle($obj1);
    +			}
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArticleRelatedBySecondArticle(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleArticleRelationRelatedBySecondArticle($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleArticleRelationsRelatedBySecondArticle();
    +				$obj3->addArticleArticleRelationRelatedBySecondArticle($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArticleArticleRelationPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelationPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleArticleRelationPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ArticleArticleRelationPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelationPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleArticleRelationPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelationPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleArticleRelationPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArticleArticleRelationPeer::ID);
    +			$selectCriteria->add(ArticleArticleRelationPeer::ID, $criteria->remove(ArticleArticleRelationPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleArticleRelationPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleArticleRelationPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ArticleArticleRelationPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleArticleRelationPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArticleArticleRelation) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ArticleArticleRelationPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ArticleArticleRelation $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArticleArticleRelationPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArticleArticleRelationPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArticleArticleRelationPeer::DATABASE_NAME, ArticleArticleRelationPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArticleArticleRelationPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ArticleArticleRelationPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleArticleRelationPeer::ID, $pk);
    +
    +
    +		$v = ArticleArticleRelationPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ArticleArticleRelationPeer::ID, $pks, Criteria::IN);
    +			$objs = ArticleArticleRelationPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArticleArticleRelationPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArticleArticleRelationMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArticleArticleRelationMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArticleArtworkRelation.php b/lib/model/om/BaseArticleArtworkRelation.php
    new file mode 100644
    index 0000000..b7412cc
    --- /dev/null
    +++ b/lib/model/om/BaseArticleArtworkRelation.php
    @@ -0,0 +1,662 @@
    +id;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getArticleId()
    +	{
    +
    +		return $this->article_id;
    +	}
    +
    +	
    +	public function getArtworkId()
    +	{
    +
    +		return $this->artwork_id;
    +	}
    +
    +	
    +	public function getCreatedBy()
    +	{
    +
    +		return $this->created_by;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArticleArtworkRelationPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = ArticleArtworkRelationPeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setArticleId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->article_id !== $v) {
    +			$this->article_id = $v;
    +			$this->modifiedColumns[] = ArticleArtworkRelationPeer::ARTICLE_ID;
    +		}
    +
    +		if ($this->aArticle !== null && $this->aArticle->getId() !== $v) {
    +			$this->aArticle = null;
    +		}
    +
    +	} 
    +	
    +	public function setArtworkId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork_id !== $v) {
    +			$this->artwork_id = $v;
    +			$this->modifiedColumns[] = ArticleArtworkRelationPeer::ARTWORK_ID;
    +		}
    +
    +		if ($this->aReaktorArtwork !== null && $this->aReaktorArtwork->getId() !== $v) {
    +			$this->aReaktorArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->created_by !== $v) {
    +			$this->created_by = $v;
    +			$this->modifiedColumns[] = ArticleArtworkRelationPeer::CREATED_BY;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 1, null);
    +
    +			$this->article_id = $rs->getInt($startcol + 2);
    +
    +			$this->artwork_id = $rs->getInt($startcol + 3);
    +
    +			$this->created_by = $rs->getInt($startcol + 4);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 5; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArticleArtworkRelation object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelation:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleArtworkRelationPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArticleArtworkRelationPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelation:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelation:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(ArticleArtworkRelationPeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleArtworkRelationPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelation:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if ($this->aArticle->isModified() || $this->aArticle->getCurrentArticleI18n()->isModified()) {
    +					$affectedRows += $this->aArticle->save($con);
    +				}
    +				$this->setArticle($this->aArticle);
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if ($this->aReaktorArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtwork->save($con);
    +				}
    +				$this->setReaktorArtwork($this->aReaktorArtwork);
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArticleArtworkRelationPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArticleArtworkRelationPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if (!$this->aArticle->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticle->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if (!$this->aReaktorArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtwork->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArticleArtworkRelationPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleArtworkRelationPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getCreatedAt();
    +				break;
    +			case 2:
    +				return $this->getArticleId();
    +				break;
    +			case 3:
    +				return $this->getArtworkId();
    +				break;
    +			case 4:
    +				return $this->getCreatedBy();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleArtworkRelationPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getCreatedAt(),
    +			$keys[2] => $this->getArticleId(),
    +			$keys[3] => $this->getArtworkId(),
    +			$keys[4] => $this->getCreatedBy(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleArtworkRelationPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setCreatedAt($value);
    +				break;
    +			case 2:
    +				$this->setArticleId($value);
    +				break;
    +			case 3:
    +				$this->setArtworkId($value);
    +				break;
    +			case 4:
    +				$this->setCreatedBy($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleArtworkRelationPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCreatedAt($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setArticleId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setArtworkId($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setCreatedBy($arr[$keys[4]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArticleArtworkRelationPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArticleArtworkRelationPeer::ID)) $criteria->add(ArticleArtworkRelationPeer::ID, $this->id);
    +		if ($this->isColumnModified(ArticleArtworkRelationPeer::CREATED_AT)) $criteria->add(ArticleArtworkRelationPeer::CREATED_AT, $this->created_at);
    +		if ($this->isColumnModified(ArticleArtworkRelationPeer::ARTICLE_ID)) $criteria->add(ArticleArtworkRelationPeer::ARTICLE_ID, $this->article_id);
    +		if ($this->isColumnModified(ArticleArtworkRelationPeer::ARTWORK_ID)) $criteria->add(ArticleArtworkRelationPeer::ARTWORK_ID, $this->artwork_id);
    +		if ($this->isColumnModified(ArticleArtworkRelationPeer::CREATED_BY)) $criteria->add(ArticleArtworkRelationPeer::CREATED_BY, $this->created_by);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArticleArtworkRelationPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleArtworkRelationPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +		$copyObj->setArticleId($this->article_id);
    +
    +		$copyObj->setArtworkId($this->artwork_id);
    +
    +		$copyObj->setCreatedBy($this->created_by);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArticleArtworkRelationPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setArticle($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArticleId(NULL);
    +		} else {
    +			$this->setArticleId($v->getId());
    +		}
    +
    +
    +		$this->aArticle = $v;
    +	}
    +
    +
    +	
    +	public function getArticle($con = null)
    +	{
    +		if ($this->aArticle === null && ($this->article_id !== null)) {
    +						include_once 'lib/model/om/BaseArticlePeer.php';
    +
    +			$this->aArticle = ArticlePeer::retrieveByPK($this->article_id, $con);
    +
    +			
    +		}
    +		return $this->aArticle;
    +	}
    +
    +	
    +	public function setReaktorArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArtworkId(NULL);
    +		} else {
    +			$this->setArtworkId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtwork === null && ($this->artwork_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtwork = ReaktorArtworkPeer::retrieveByPK($this->artwork_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtwork;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setCreatedBy(NULL);
    +		} else {
    +			$this->setCreatedBy($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->created_by !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->created_by, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArticleArtworkRelation:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArticleArtworkRelation::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArticleArtworkRelationPeer.php b/lib/model/om/BaseArticleArtworkRelationPeer.php
    new file mode 100644
    index 0000000..bf3d4cd
    --- /dev/null
    +++ b/lib/model/om/BaseArticleArtworkRelationPeer.php
    @@ -0,0 +1,1139 @@
    + array ('Id', 'CreatedAt', 'ArticleId', 'ArtworkId', 'CreatedBy', ),
    +		BasePeer::TYPE_COLNAME => array (ArticleArtworkRelationPeer::ID, ArticleArtworkRelationPeer::CREATED_AT, ArticleArtworkRelationPeer::ARTICLE_ID, ArticleArtworkRelationPeer::ARTWORK_ID, ArticleArtworkRelationPeer::CREATED_BY, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'created_at', 'article_id', 'artwork_id', 'created_by', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'CreatedAt' => 1, 'ArticleId' => 2, 'ArtworkId' => 3, 'CreatedBy' => 4, ),
    +		BasePeer::TYPE_COLNAME => array (ArticleArtworkRelationPeer::ID => 0, ArticleArtworkRelationPeer::CREATED_AT => 1, ArticleArtworkRelationPeer::ARTICLE_ID => 2, ArticleArtworkRelationPeer::ARTWORK_ID => 3, ArticleArtworkRelationPeer::CREATED_BY => 4, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'created_at' => 1, 'article_id' => 2, 'artwork_id' => 3, 'created_by' => 4, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArticleArtworkRelationMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArticleArtworkRelationMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArticleArtworkRelationPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArticleArtworkRelationPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArticleArtworkRelationPeer::ID);
    +
    +		$criteria->addSelectColumn(ArticleArtworkRelationPeer::CREATED_AT);
    +
    +		$criteria->addSelectColumn(ArticleArtworkRelationPeer::ARTICLE_ID);
    +
    +		$criteria->addSelectColumn(ArticleArtworkRelationPeer::ARTWORK_ID);
    +
    +		$criteria->addSelectColumn(ArticleArtworkRelationPeer::CREATED_BY);
    +
    +	}
    +
    +	const COUNT = 'COUNT(article_artwork_relation.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT article_artwork_relation.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArticleArtworkRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArticleArtworkRelationPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArticleArtworkRelationPeer::populateObjects(ArticleArtworkRelationPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelationPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleArtworkRelationPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArticleArtworkRelationPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArticleArtworkRelationPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = ArticleArtworkRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = ArticleArtworkRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleArtworkRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArtworkRelationPeer::addSelectColumns($c);
    +		$startcol = (ArticleArtworkRelationPeer::NUM_COLUMNS - ArticleArtworkRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticlePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::ARTICLE_ID, ArticlePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArtworkRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleArtworkRelation($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleArtworkRelations();
    +				$obj2->addArticleArtworkRelation($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArtworkRelationPeer::addSelectColumns($c);
    +		$startcol = (ArticleArtworkRelationPeer::NUM_COLUMNS - ArticleArtworkRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArtworkRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleArtworkRelation($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleArtworkRelations();
    +				$obj2->addArticleArtworkRelation($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArtworkRelationPeer::addSelectColumns($c);
    +		$startcol = (ArticleArtworkRelationPeer::NUM_COLUMNS - ArticleArtworkRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArtworkRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleArtworkRelation($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleArtworkRelations();
    +				$obj2->addArticleArtworkRelation($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleArtworkRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArtworkRelationPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleArtworkRelationPeer::NUM_COLUMNS - ArticleArtworkRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArtworkRelationPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleArtworkRelation($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleArtworkRelations();
    +				$obj2->addArticleArtworkRelation($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleArtworkRelation($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleArtworkRelations();
    +				$obj3->addArticleArtworkRelation($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4 = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addArticleArtworkRelation($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initArticleArtworkRelations();
    +				$obj4->addArticleArtworkRelation($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleArtworkRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleArtworkRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleArtworkRelationPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleArtworkRelationPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = ArticleArtworkRelationPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArtworkRelationPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleArtworkRelationPeer::NUM_COLUMNS - ArticleArtworkRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArtworkRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleArtworkRelation($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleArtworkRelations();
    +				$obj2->addArticleArtworkRelation($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleArtworkRelation($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleArtworkRelations();
    +				$obj3->addArticleArtworkRelation($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArtworkRelationPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleArtworkRelationPeer::NUM_COLUMNS - ArticleArtworkRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArtworkRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleArtworkRelation($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleArtworkRelations();
    +				$obj2->addArticleArtworkRelation($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleArtworkRelation($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleArtworkRelations();
    +				$obj3->addArticleArtworkRelation($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleArtworkRelationPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleArtworkRelationPeer::NUM_COLUMNS - ArticleArtworkRelationPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleArtworkRelationPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleArtworkRelationPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleArtworkRelation($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleArtworkRelations();
    +				$obj2->addArticleArtworkRelation($obj1);
    +			}
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleArtworkRelation($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleArtworkRelations();
    +				$obj3->addArticleArtworkRelation($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArticleArtworkRelationPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelationPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleArtworkRelationPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ArticleArtworkRelationPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelationPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleArtworkRelationPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelationPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleArtworkRelationPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArticleArtworkRelationPeer::ID);
    +			$selectCriteria->add(ArticleArtworkRelationPeer::ID, $criteria->remove(ArticleArtworkRelationPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleArtworkRelationPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleArtworkRelationPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ArticleArtworkRelationPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleArtworkRelationPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArticleArtworkRelation) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ArticleArtworkRelationPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ArticleArtworkRelation $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArticleArtworkRelationPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArticleArtworkRelationPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArticleArtworkRelationPeer::DATABASE_NAME, ArticleArtworkRelationPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArticleArtworkRelationPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ArticleArtworkRelationPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleArtworkRelationPeer::ID, $pk);
    +
    +
    +		$v = ArticleArtworkRelationPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ArticleArtworkRelationPeer::ID, $pks, Criteria::IN);
    +			$objs = ArticleArtworkRelationPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArticleArtworkRelationPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArticleArtworkRelationMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArticleArtworkRelationMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArticleAttachment.php b/lib/model/om/BaseArticleAttachment.php
    new file mode 100644
    index 0000000..e5bec24
    --- /dev/null
    +++ b/lib/model/om/BaseArticleAttachment.php
    @@ -0,0 +1,512 @@
    +article_id;
    +	}
    +
    +	
    +	public function getFileId()
    +	{
    +
    +		return $this->file_id;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function setArticleId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->article_id !== $v) {
    +			$this->article_id = $v;
    +			$this->modifiedColumns[] = ArticleAttachmentPeer::ARTICLE_ID;
    +		}
    +
    +		if ($this->aArticle !== null && $this->aArticle->getId() !== $v) {
    +			$this->aArticle = null;
    +		}
    +
    +	} 
    +	
    +	public function setFileId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->file_id !== $v) {
    +			$this->file_id = $v;
    +			$this->modifiedColumns[] = ArticleAttachmentPeer::FILE_ID;
    +		}
    +
    +		if ($this->aArticleFile !== null && $this->aArticleFile->getId() !== $v) {
    +			$this->aArticleFile = null;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArticleAttachmentPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->article_id = $rs->getInt($startcol + 0);
    +
    +			$this->file_id = $rs->getInt($startcol + 1);
    +
    +			$this->id = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArticleAttachment object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleAttachment:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleAttachmentPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArticleAttachmentPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleAttachment:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleAttachment:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleAttachmentPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArticleAttachment:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if ($this->aArticle->isModified() || $this->aArticle->getCurrentArticleI18n()->isModified()) {
    +					$affectedRows += $this->aArticle->save($con);
    +				}
    +				$this->setArticle($this->aArticle);
    +			}
    +
    +			if ($this->aArticleFile !== null) {
    +				if ($this->aArticleFile->isModified()) {
    +					$affectedRows += $this->aArticleFile->save($con);
    +				}
    +				$this->setArticleFile($this->aArticleFile);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArticleAttachmentPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArticleAttachmentPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if (!$this->aArticle->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticle->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aArticleFile !== null) {
    +				if (!$this->aArticleFile->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticleFile->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArticleAttachmentPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleAttachmentPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getArticleId();
    +				break;
    +			case 1:
    +				return $this->getFileId();
    +				break;
    +			case 2:
    +				return $this->getId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleAttachmentPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getArticleId(),
    +			$keys[1] => $this->getFileId(),
    +			$keys[2] => $this->getId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleAttachmentPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setArticleId($value);
    +				break;
    +			case 1:
    +				$this->setFileId($value);
    +				break;
    +			case 2:
    +				$this->setId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleAttachmentPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setArticleId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setFileId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setId($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArticleAttachmentPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArticleAttachmentPeer::ARTICLE_ID)) $criteria->add(ArticleAttachmentPeer::ARTICLE_ID, $this->article_id);
    +		if ($this->isColumnModified(ArticleAttachmentPeer::FILE_ID)) $criteria->add(ArticleAttachmentPeer::FILE_ID, $this->file_id);
    +		if ($this->isColumnModified(ArticleAttachmentPeer::ID)) $criteria->add(ArticleAttachmentPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArticleAttachmentPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleAttachmentPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setArticleId($this->article_id);
    +
    +		$copyObj->setFileId($this->file_id);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArticleAttachmentPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setArticle($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArticleId(NULL);
    +		} else {
    +			$this->setArticleId($v->getId());
    +		}
    +
    +
    +		$this->aArticle = $v;
    +	}
    +
    +
    +	
    +	public function getArticle($con = null)
    +	{
    +		if ($this->aArticle === null && ($this->article_id !== null)) {
    +						include_once 'lib/model/om/BaseArticlePeer.php';
    +
    +			$this->aArticle = ArticlePeer::retrieveByPK($this->article_id, $con);
    +
    +			
    +		}
    +		return $this->aArticle;
    +	}
    +
    +	
    +	public function setArticleFile($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFileId(NULL);
    +		} else {
    +			$this->setFileId($v->getId());
    +		}
    +
    +
    +		$this->aArticleFile = $v;
    +	}
    +
    +
    +	
    +	public function getArticleFile($con = null)
    +	{
    +		if ($this->aArticleFile === null && ($this->file_id !== null)) {
    +						include_once 'lib/model/om/BaseArticleFilePeer.php';
    +
    +			$this->aArticleFile = ArticleFilePeer::retrieveByPK($this->file_id, $con);
    +
    +			
    +		}
    +		return $this->aArticleFile;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArticleAttachment:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArticleAttachment::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArticleAttachmentPeer.php b/lib/model/om/BaseArticleAttachmentPeer.php
    new file mode 100644
    index 0000000..98d848b
    --- /dev/null
    +++ b/lib/model/om/BaseArticleAttachmentPeer.php
    @@ -0,0 +1,852 @@
    + array ('ArticleId', 'FileId', 'Id', ),
    +		BasePeer::TYPE_COLNAME => array (ArticleAttachmentPeer::ARTICLE_ID, ArticleAttachmentPeer::FILE_ID, ArticleAttachmentPeer::ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('article_id', 'file_id', 'id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('ArticleId' => 0, 'FileId' => 1, 'Id' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (ArticleAttachmentPeer::ARTICLE_ID => 0, ArticleAttachmentPeer::FILE_ID => 1, ArticleAttachmentPeer::ID => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('article_id' => 0, 'file_id' => 1, 'id' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArticleAttachmentMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArticleAttachmentMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArticleAttachmentPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArticleAttachmentPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArticleAttachmentPeer::ARTICLE_ID);
    +
    +		$criteria->addSelectColumn(ArticleAttachmentPeer::FILE_ID);
    +
    +		$criteria->addSelectColumn(ArticleAttachmentPeer::ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(article_attachment.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT article_attachment.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArticleAttachmentPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArticleAttachmentPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArticleAttachmentPeer::populateObjects(ArticleAttachmentPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleAttachmentPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleAttachmentPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArticleAttachmentPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArticleAttachmentPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleAttachmentPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = ArticleAttachmentPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinArticleFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleAttachmentPeer::FILE_ID, ArticleFilePeer::ID);
    +
    +		$rs = ArticleAttachmentPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleAttachmentPeer::addSelectColumns($c);
    +		$startcol = (ArticleAttachmentPeer::NUM_COLUMNS - ArticleAttachmentPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticlePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleAttachmentPeer::ARTICLE_ID, ArticlePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleAttachmentPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleAttachment($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleAttachments();
    +				$obj2->addArticleAttachment($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticleFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleAttachmentPeer::addSelectColumns($c);
    +		$startcol = (ArticleAttachmentPeer::NUM_COLUMNS - ArticleAttachmentPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticleFilePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleAttachmentPeer::FILE_ID, ArticleFilePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleAttachmentPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticleFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleAttachment($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleAttachments();
    +				$obj2->addArticleAttachment($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleAttachmentPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleAttachmentPeer::FILE_ID, ArticleFilePeer::ID);
    +
    +		$rs = ArticleAttachmentPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleAttachmentPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleAttachmentPeer::NUM_COLUMNS - ArticleAttachmentPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArticleFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleAttachmentPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleAttachmentPeer::FILE_ID, ArticleFilePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleAttachmentPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleAttachment($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleAttachments();
    +				$obj2->addArticleAttachment($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArticleFile(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleAttachment($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleAttachments();
    +				$obj3->addArticleAttachment($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleAttachmentPeer::FILE_ID, ArticleFilePeer::ID);
    +
    +		$rs = ArticleAttachmentPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticleFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleAttachmentPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleAttachmentPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = ArticleAttachmentPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleAttachmentPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleAttachmentPeer::NUM_COLUMNS - ArticleAttachmentPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticleFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleAttachmentPeer::FILE_ID, ArticleFilePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleAttachmentPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticleFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleAttachment($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleAttachments();
    +				$obj2->addArticleAttachment($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticleFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleAttachmentPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleAttachmentPeer::NUM_COLUMNS - ArticleAttachmentPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleAttachmentPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleAttachmentPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleAttachment($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleAttachments();
    +				$obj2->addArticleAttachment($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArticleAttachmentPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleAttachmentPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleAttachmentPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ArticleAttachmentPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArticleAttachmentPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleAttachmentPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleAttachmentPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleAttachmentPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArticleAttachmentPeer::ID);
    +			$selectCriteria->add(ArticleAttachmentPeer::ID, $criteria->remove(ArticleAttachmentPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleAttachmentPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleAttachmentPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ArticleAttachmentPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleAttachmentPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArticleAttachment) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ArticleAttachmentPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ArticleAttachment $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArticleAttachmentPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArticleAttachmentPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArticleAttachmentPeer::DATABASE_NAME, ArticleAttachmentPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArticleAttachmentPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ArticleAttachmentPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleAttachmentPeer::ID, $pk);
    +
    +
    +		$v = ArticleAttachmentPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ArticleAttachmentPeer::ID, $pks, Criteria::IN);
    +			$objs = ArticleAttachmentPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArticleAttachmentPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArticleAttachmentMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArticleAttachmentMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArticleCategory.php b/lib/model/om/BaseArticleCategory.php
    new file mode 100644
    index 0000000..bd12395
    --- /dev/null
    +++ b/lib/model/om/BaseArticleCategory.php
    @@ -0,0 +1,512 @@
    +article_id;
    +	}
    +
    +	
    +	public function getCategoryId()
    +	{
    +
    +		return $this->category_id;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function setArticleId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->article_id !== $v) {
    +			$this->article_id = $v;
    +			$this->modifiedColumns[] = ArticleCategoryPeer::ARTICLE_ID;
    +		}
    +
    +		if ($this->aArticle !== null && $this->aArticle->getId() !== $v) {
    +			$this->aArticle = null;
    +		}
    +
    +	} 
    +	
    +	public function setCategoryId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->category_id !== $v) {
    +			$this->category_id = $v;
    +			$this->modifiedColumns[] = ArticleCategoryPeer::CATEGORY_ID;
    +		}
    +
    +		if ($this->aCategory !== null && $this->aCategory->getId() !== $v) {
    +			$this->aCategory = null;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArticleCategoryPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->article_id = $rs->getInt($startcol + 0);
    +
    +			$this->category_id = $rs->getInt($startcol + 1);
    +
    +			$this->id = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArticleCategory object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleCategory:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleCategoryPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArticleCategoryPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleCategory:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleCategory:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleCategoryPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArticleCategory:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if ($this->aArticle->isModified() || $this->aArticle->getCurrentArticleI18n()->isModified()) {
    +					$affectedRows += $this->aArticle->save($con);
    +				}
    +				$this->setArticle($this->aArticle);
    +			}
    +
    +			if ($this->aCategory !== null) {
    +				if ($this->aCategory->isModified() || $this->aCategory->getCurrentCategoryI18n()->isModified()) {
    +					$affectedRows += $this->aCategory->save($con);
    +				}
    +				$this->setCategory($this->aCategory);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArticleCategoryPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArticleCategoryPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if (!$this->aArticle->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticle->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aCategory !== null) {
    +				if (!$this->aCategory->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aCategory->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArticleCategoryPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleCategoryPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getArticleId();
    +				break;
    +			case 1:
    +				return $this->getCategoryId();
    +				break;
    +			case 2:
    +				return $this->getId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleCategoryPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getArticleId(),
    +			$keys[1] => $this->getCategoryId(),
    +			$keys[2] => $this->getId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleCategoryPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setArticleId($value);
    +				break;
    +			case 1:
    +				$this->setCategoryId($value);
    +				break;
    +			case 2:
    +				$this->setId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleCategoryPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setArticleId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCategoryId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setId($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArticleCategoryPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArticleCategoryPeer::ARTICLE_ID)) $criteria->add(ArticleCategoryPeer::ARTICLE_ID, $this->article_id);
    +		if ($this->isColumnModified(ArticleCategoryPeer::CATEGORY_ID)) $criteria->add(ArticleCategoryPeer::CATEGORY_ID, $this->category_id);
    +		if ($this->isColumnModified(ArticleCategoryPeer::ID)) $criteria->add(ArticleCategoryPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArticleCategoryPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleCategoryPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setArticleId($this->article_id);
    +
    +		$copyObj->setCategoryId($this->category_id);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArticleCategoryPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setArticle($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArticleId(NULL);
    +		} else {
    +			$this->setArticleId($v->getId());
    +		}
    +
    +
    +		$this->aArticle = $v;
    +	}
    +
    +
    +	
    +	public function getArticle($con = null)
    +	{
    +		if ($this->aArticle === null && ($this->article_id !== null)) {
    +						include_once 'lib/model/om/BaseArticlePeer.php';
    +
    +			$this->aArticle = ArticlePeer::retrieveByPK($this->article_id, $con);
    +
    +			
    +		}
    +		return $this->aArticle;
    +	}
    +
    +	
    +	public function setCategory($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setCategoryId(NULL);
    +		} else {
    +			$this->setCategoryId($v->getId());
    +		}
    +
    +
    +		$this->aCategory = $v;
    +	}
    +
    +
    +	
    +	public function getCategory($con = null)
    +	{
    +		if ($this->aCategory === null && ($this->category_id !== null)) {
    +						include_once 'lib/model/om/BaseCategoryPeer.php';
    +
    +			$this->aCategory = CategoryPeer::retrieveByPK($this->category_id, $con);
    +
    +			
    +		}
    +		return $this->aCategory;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArticleCategory:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArticleCategory::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArticleCategoryPeer.php b/lib/model/om/BaseArticleCategoryPeer.php
    new file mode 100644
    index 0000000..1307613
    --- /dev/null
    +++ b/lib/model/om/BaseArticleCategoryPeer.php
    @@ -0,0 +1,852 @@
    + array ('ArticleId', 'CategoryId', 'Id', ),
    +		BasePeer::TYPE_COLNAME => array (ArticleCategoryPeer::ARTICLE_ID, ArticleCategoryPeer::CATEGORY_ID, ArticleCategoryPeer::ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('article_id', 'category_id', 'id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('ArticleId' => 0, 'CategoryId' => 1, 'Id' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (ArticleCategoryPeer::ARTICLE_ID => 0, ArticleCategoryPeer::CATEGORY_ID => 1, ArticleCategoryPeer::ID => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('article_id' => 0, 'category_id' => 1, 'id' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArticleCategoryMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArticleCategoryMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArticleCategoryPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArticleCategoryPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArticleCategoryPeer::ARTICLE_ID);
    +
    +		$criteria->addSelectColumn(ArticleCategoryPeer::CATEGORY_ID);
    +
    +		$criteria->addSelectColumn(ArticleCategoryPeer::ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(article_category.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT article_category.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArticleCategoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArticleCategoryPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArticleCategoryPeer::populateObjects(ArticleCategoryPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleCategoryPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleCategoryPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArticleCategoryPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArticleCategoryPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleCategoryPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = ArticleCategoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinCategory(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleCategoryPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$rs = ArticleCategoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleCategoryPeer::addSelectColumns($c);
    +		$startcol = (ArticleCategoryPeer::NUM_COLUMNS - ArticleCategoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticlePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleCategoryPeer::ARTICLE_ID, ArticlePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleCategoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleCategory($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleCategorys();
    +				$obj2->addArticleCategory($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinCategory(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleCategoryPeer::addSelectColumns($c);
    +		$startcol = (ArticleCategoryPeer::NUM_COLUMNS - ArticleCategoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		CategoryPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleCategoryPeer::CATEGORY_ID, CategoryPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleCategoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CategoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleCategory($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleCategorys();
    +				$obj2->addArticleCategory($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleCategoryPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleCategoryPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$rs = ArticleCategoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleCategoryPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleCategoryPeer::NUM_COLUMNS - ArticleCategoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		CategoryPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + CategoryPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleCategoryPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleCategoryPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleCategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleCategory($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleCategorys();
    +				$obj2->addArticleCategory($obj1);
    +			}
    +
    +
    +					
    +			$omClass = CategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getCategory(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleCategory($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleCategorys();
    +				$obj3->addArticleCategory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleCategoryPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$rs = ArticleCategoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptCategory(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleCategoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleCategoryPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = ArticleCategoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleCategoryPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleCategoryPeer::NUM_COLUMNS - ArticleCategoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		CategoryPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + CategoryPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleCategoryPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleCategoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleCategory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleCategorys();
    +				$obj2->addArticleCategory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptCategory(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleCategoryPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleCategoryPeer::NUM_COLUMNS - ArticleCategoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleCategoryPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleCategoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleCategory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleCategorys();
    +				$obj2->addArticleCategory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArticleCategoryPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleCategoryPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleCategoryPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ArticleCategoryPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArticleCategoryPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleCategoryPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleCategoryPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleCategoryPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArticleCategoryPeer::ID);
    +			$selectCriteria->add(ArticleCategoryPeer::ID, $criteria->remove(ArticleCategoryPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleCategoryPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleCategoryPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ArticleCategoryPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleCategoryPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArticleCategory) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ArticleCategoryPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ArticleCategory $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArticleCategoryPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArticleCategoryPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArticleCategoryPeer::DATABASE_NAME, ArticleCategoryPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArticleCategoryPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ArticleCategoryPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleCategoryPeer::ID, $pk);
    +
    +
    +		$v = ArticleCategoryPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ArticleCategoryPeer::ID, $pks, Criteria::IN);
    +			$objs = ArticleCategoryPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArticleCategoryPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArticleCategoryMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArticleCategoryMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArticleFile.php b/lib/model/om/BaseArticleFile.php
    new file mode 100644
    index 0000000..1c8e0e5
    --- /dev/null
    +++ b/lib/model/om/BaseArticleFile.php
    @@ -0,0 +1,955 @@
    +id;
    +	}
    +
    +	
    +	public function getFilename()
    +	{
    +
    +		return $this->filename;
    +	}
    +
    +	
    +	public function getPath()
    +	{
    +
    +		return $this->path;
    +	}
    +
    +	
    +	public function getUploadedBy()
    +	{
    +
    +		return $this->uploaded_by;
    +	}
    +
    +	
    +	public function getUploadedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->uploaded_at === null || $this->uploaded_at === '') {
    +			return null;
    +		} elseif (!is_int($this->uploaded_at)) {
    +						$ts = strtotime($this->uploaded_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [uploaded_at] as date/time value: " . var_export($this->uploaded_at, true));
    +			}
    +		} else {
    +			$ts = $this->uploaded_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getDescription()
    +	{
    +
    +		return $this->description;
    +	}
    +
    +	
    +	public function getFileMimetypeId()
    +	{
    +
    +		return $this->file_mimetype_id;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArticleFilePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setFilename($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->filename !== $v) {
    +			$this->filename = $v;
    +			$this->modifiedColumns[] = ArticleFilePeer::FILENAME;
    +		}
    +
    +	} 
    +	
    +	public function setPath($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->path !== $v) {
    +			$this->path = $v;
    +			$this->modifiedColumns[] = ArticleFilePeer::PATH;
    +		}
    +
    +	} 
    +	
    +	public function setUploadedBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->uploaded_by !== $v) {
    +			$this->uploaded_by = $v;
    +			$this->modifiedColumns[] = ArticleFilePeer::UPLOADED_BY;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setUploadedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [uploaded_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->uploaded_at !== $ts) {
    +			$this->uploaded_at = $ts;
    +			$this->modifiedColumns[] = ArticleFilePeer::UPLOADED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setDescription($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->description !== $v) {
    +			$this->description = $v;
    +			$this->modifiedColumns[] = ArticleFilePeer::DESCRIPTION;
    +		}
    +
    +	} 
    +	
    +	public function setFileMimetypeId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->file_mimetype_id !== $v) {
    +			$this->file_mimetype_id = $v;
    +			$this->modifiedColumns[] = ArticleFilePeer::FILE_MIMETYPE_ID;
    +		}
    +
    +		if ($this->aFileMimetype !== null && $this->aFileMimetype->getId() !== $v) {
    +			$this->aFileMimetype = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->filename = $rs->getString($startcol + 1);
    +
    +			$this->path = $rs->getString($startcol + 2);
    +
    +			$this->uploaded_by = $rs->getInt($startcol + 3);
    +
    +			$this->uploaded_at = $rs->getTimestamp($startcol + 4, null);
    +
    +			$this->description = $rs->getString($startcol + 5);
    +
    +			$this->file_mimetype_id = $rs->getInt($startcol + 6);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 7; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArticleFile object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleFile:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleFilePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArticleFilePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleFile:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleFile:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleFilePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArticleFile:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +			if ($this->aFileMimetype !== null) {
    +				if ($this->aFileMimetype->isModified()) {
    +					$affectedRows += $this->aFileMimetype->save($con);
    +				}
    +				$this->setFileMimetype($this->aFileMimetype);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArticleFilePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArticleFilePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collArticles !== null) {
    +				foreach($this->collArticles as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleAttachments !== null) {
    +				foreach($this->collArticleAttachments as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aFileMimetype !== null) {
    +				if (!$this->aFileMimetype->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aFileMimetype->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArticleFilePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collArticles !== null) {
    +					foreach($this->collArticles as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleAttachments !== null) {
    +					foreach($this->collArticleAttachments as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleFilePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getFilename();
    +				break;
    +			case 2:
    +				return $this->getPath();
    +				break;
    +			case 3:
    +				return $this->getUploadedBy();
    +				break;
    +			case 4:
    +				return $this->getUploadedAt();
    +				break;
    +			case 5:
    +				return $this->getDescription();
    +				break;
    +			case 6:
    +				return $this->getFileMimetypeId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleFilePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getFilename(),
    +			$keys[2] => $this->getPath(),
    +			$keys[3] => $this->getUploadedBy(),
    +			$keys[4] => $this->getUploadedAt(),
    +			$keys[5] => $this->getDescription(),
    +			$keys[6] => $this->getFileMimetypeId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleFilePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setFilename($value);
    +				break;
    +			case 2:
    +				$this->setPath($value);
    +				break;
    +			case 3:
    +				$this->setUploadedBy($value);
    +				break;
    +			case 4:
    +				$this->setUploadedAt($value);
    +				break;
    +			case 5:
    +				$this->setDescription($value);
    +				break;
    +			case 6:
    +				$this->setFileMimetypeId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleFilePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setFilename($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setPath($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setUploadedBy($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setUploadedAt($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setDescription($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setFileMimetypeId($arr[$keys[6]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArticleFilePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArticleFilePeer::ID)) $criteria->add(ArticleFilePeer::ID, $this->id);
    +		if ($this->isColumnModified(ArticleFilePeer::FILENAME)) $criteria->add(ArticleFilePeer::FILENAME, $this->filename);
    +		if ($this->isColumnModified(ArticleFilePeer::PATH)) $criteria->add(ArticleFilePeer::PATH, $this->path);
    +		if ($this->isColumnModified(ArticleFilePeer::UPLOADED_BY)) $criteria->add(ArticleFilePeer::UPLOADED_BY, $this->uploaded_by);
    +		if ($this->isColumnModified(ArticleFilePeer::UPLOADED_AT)) $criteria->add(ArticleFilePeer::UPLOADED_AT, $this->uploaded_at);
    +		if ($this->isColumnModified(ArticleFilePeer::DESCRIPTION)) $criteria->add(ArticleFilePeer::DESCRIPTION, $this->description);
    +		if ($this->isColumnModified(ArticleFilePeer::FILE_MIMETYPE_ID)) $criteria->add(ArticleFilePeer::FILE_MIMETYPE_ID, $this->file_mimetype_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArticleFilePeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleFilePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setFilename($this->filename);
    +
    +		$copyObj->setPath($this->path);
    +
    +		$copyObj->setUploadedBy($this->uploaded_by);
    +
    +		$copyObj->setUploadedAt($this->uploaded_at);
    +
    +		$copyObj->setDescription($this->description);
    +
    +		$copyObj->setFileMimetypeId($this->file_mimetype_id);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getArticles() as $relObj) {
    +				$copyObj->addArticle($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleAttachments() as $relObj) {
    +				$copyObj->addArticleAttachment($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArticleFilePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUploadedBy(NULL);
    +		} else {
    +			$this->setUploadedBy($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->uploaded_by !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->uploaded_by, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +	
    +	public function setFileMimetype($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFileMimetypeId(NULL);
    +		} else {
    +			$this->setFileMimetypeId($v->getId());
    +		}
    +
    +
    +		$this->aFileMimetype = $v;
    +	}
    +
    +
    +	
    +	public function getFileMimetype($con = null)
    +	{
    +		if ($this->aFileMimetype === null && ($this->file_mimetype_id !== null)) {
    +						include_once 'lib/model/om/BaseFileMimetypePeer.php';
    +
    +			$this->aFileMimetype = FileMimetypePeer::retrieveByPK($this->file_mimetype_id, $con);
    +
    +			
    +		}
    +		return $this->aFileMimetype;
    +	}
    +
    +	
    +	public function initArticles()
    +	{
    +		if ($this->collArticles === null) {
    +			$this->collArticles = array();
    +		}
    +	}
    +
    +	
    +	public function getArticles($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticlePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticles === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticles = array();
    +			} else {
    +
    +				$criteria->add(ArticlePeer::BANNER_FILE_ID, $this->getId());
    +
    +				ArticlePeer::addSelectColumns($criteria);
    +				$this->collArticles = ArticlePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticlePeer::BANNER_FILE_ID, $this->getId());
    +
    +				ArticlePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleCriteria) || !$this->lastArticleCriteria->equals($criteria)) {
    +					$this->collArticles = ArticlePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleCriteria = $criteria;
    +		return $this->collArticles;
    +	}
    +
    +	
    +	public function countArticles($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticlePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticlePeer::BANNER_FILE_ID, $this->getId());
    +
    +		return ArticlePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticle(Article $l)
    +	{
    +		$this->collArticles[] = $l;
    +		$l->setArticleFile($this);
    +	}
    +
    +
    +	
    +	public function getArticlesJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticlePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticles === null) {
    +			if ($this->isNew()) {
    +				$this->collArticles = array();
    +			} else {
    +
    +				$criteria->add(ArticlePeer::BANNER_FILE_ID, $this->getId());
    +
    +				$this->collArticles = ArticlePeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticlePeer::BANNER_FILE_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleCriteria) || !$this->lastArticleCriteria->equals($criteria)) {
    +				$this->collArticles = ArticlePeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleCriteria = $criteria;
    +
    +		return $this->collArticles;
    +	}
    +
    +	
    +	public function initArticleAttachments()
    +	{
    +		if ($this->collArticleAttachments === null) {
    +			$this->collArticleAttachments = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleAttachments($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleAttachmentPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleAttachments === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleAttachments = array();
    +			} else {
    +
    +				$criteria->add(ArticleAttachmentPeer::FILE_ID, $this->getId());
    +
    +				ArticleAttachmentPeer::addSelectColumns($criteria);
    +				$this->collArticleAttachments = ArticleAttachmentPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleAttachmentPeer::FILE_ID, $this->getId());
    +
    +				ArticleAttachmentPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleAttachmentCriteria) || !$this->lastArticleAttachmentCriteria->equals($criteria)) {
    +					$this->collArticleAttachments = ArticleAttachmentPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleAttachmentCriteria = $criteria;
    +		return $this->collArticleAttachments;
    +	}
    +
    +	
    +	public function countArticleAttachments($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleAttachmentPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleAttachmentPeer::FILE_ID, $this->getId());
    +
    +		return ArticleAttachmentPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleAttachment(ArticleAttachment $l)
    +	{
    +		$this->collArticleAttachments[] = $l;
    +		$l->setArticleFile($this);
    +	}
    +
    +
    +	
    +	public function getArticleAttachmentsJoinArticle($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleAttachmentPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleAttachments === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleAttachments = array();
    +			} else {
    +
    +				$criteria->add(ArticleAttachmentPeer::FILE_ID, $this->getId());
    +
    +				$this->collArticleAttachments = ArticleAttachmentPeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleAttachmentPeer::FILE_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleAttachmentCriteria) || !$this->lastArticleAttachmentCriteria->equals($criteria)) {
    +				$this->collArticleAttachments = ArticleAttachmentPeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleAttachmentCriteria = $criteria;
    +
    +		return $this->collArticleAttachments;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArticleFile:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArticleFile::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArticleFilePeer.php b/lib/model/om/BaseArticleFilePeer.php
    new file mode 100644
    index 0000000..3347e8f
    --- /dev/null
    +++ b/lib/model/om/BaseArticleFilePeer.php
    @@ -0,0 +1,872 @@
    + array ('Id', 'Filename', 'Path', 'UploadedBy', 'UploadedAt', 'Description', 'FileMimetypeId', ),
    +		BasePeer::TYPE_COLNAME => array (ArticleFilePeer::ID, ArticleFilePeer::FILENAME, ArticleFilePeer::PATH, ArticleFilePeer::UPLOADED_BY, ArticleFilePeer::UPLOADED_AT, ArticleFilePeer::DESCRIPTION, ArticleFilePeer::FILE_MIMETYPE_ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'filename', 'path', 'uploaded_by', 'uploaded_at', 'description', 'file_mimetype_id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Filename' => 1, 'Path' => 2, 'UploadedBy' => 3, 'UploadedAt' => 4, 'Description' => 5, 'FileMimetypeId' => 6, ),
    +		BasePeer::TYPE_COLNAME => array (ArticleFilePeer::ID => 0, ArticleFilePeer::FILENAME => 1, ArticleFilePeer::PATH => 2, ArticleFilePeer::UPLOADED_BY => 3, ArticleFilePeer::UPLOADED_AT => 4, ArticleFilePeer::DESCRIPTION => 5, ArticleFilePeer::FILE_MIMETYPE_ID => 6, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'filename' => 1, 'path' => 2, 'uploaded_by' => 3, 'uploaded_at' => 4, 'description' => 5, 'file_mimetype_id' => 6, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArticleFileMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArticleFileMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArticleFilePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArticleFilePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArticleFilePeer::ID);
    +
    +		$criteria->addSelectColumn(ArticleFilePeer::FILENAME);
    +
    +		$criteria->addSelectColumn(ArticleFilePeer::PATH);
    +
    +		$criteria->addSelectColumn(ArticleFilePeer::UPLOADED_BY);
    +
    +		$criteria->addSelectColumn(ArticleFilePeer::UPLOADED_AT);
    +
    +		$criteria->addSelectColumn(ArticleFilePeer::DESCRIPTION);
    +
    +		$criteria->addSelectColumn(ArticleFilePeer::FILE_MIMETYPE_ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(article_file.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT article_file.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArticleFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArticleFilePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArticleFilePeer::populateObjects(ArticleFilePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleFilePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleFilePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArticleFilePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArticleFilePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleFilePeer::UPLOADED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinFileMimetype(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleFilePeer::FILE_MIMETYPE_ID, FileMimetypePeer::ID);
    +
    +		$rs = ArticleFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol = (ArticleFilePeer::NUM_COLUMNS - ArticleFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleFilePeer::UPLOADED_BY, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleFile($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleFiles();
    +				$obj2->addArticleFile($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinFileMimetype(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol = (ArticleFilePeer::NUM_COLUMNS - ArticleFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		FileMimetypePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleFilePeer::FILE_MIMETYPE_ID, FileMimetypePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = FileMimetypePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getFileMimetype(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleFile($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleFiles();
    +				$obj2->addArticleFile($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleFilePeer::UPLOADED_BY, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ArticleFilePeer::FILE_MIMETYPE_ID, FileMimetypePeer::ID);
    +
    +		$rs = ArticleFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol2 = (ArticleFilePeer::NUM_COLUMNS - ArticleFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		FileMimetypePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + FileMimetypePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleFilePeer::UPLOADED_BY, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ArticleFilePeer::FILE_MIMETYPE_ID, FileMimetypePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleFile($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleFiles();
    +				$obj2->addArticleFile($obj1);
    +			}
    +
    +
    +					
    +			$omClass = FileMimetypePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getFileMimetype(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleFile($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleFiles();
    +				$obj3->addArticleFile($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleFilePeer::FILE_MIMETYPE_ID, FileMimetypePeer::ID);
    +
    +		$rs = ArticleFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptFileMimetype(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleFilePeer::UPLOADED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = ArticleFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol2 = (ArticleFilePeer::NUM_COLUMNS - ArticleFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		FileMimetypePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + FileMimetypePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleFilePeer::FILE_MIMETYPE_ID, FileMimetypePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = FileMimetypePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getFileMimetype(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleFile($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleFiles();
    +				$obj2->addArticleFile($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptFileMimetype(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol2 = (ArticleFilePeer::NUM_COLUMNS - ArticleFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleFilePeer::UPLOADED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleFile($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleFiles();
    +				$obj2->addArticleFile($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArticleFilePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleFilePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleFilePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ArticleFilePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArticleFilePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleFilePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleFilePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleFilePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArticleFilePeer::ID);
    +			$selectCriteria->add(ArticleFilePeer::ID, $criteria->remove(ArticleFilePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleFilePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleFilePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ArticleFilePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleFilePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArticleFile) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ArticleFilePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ArticleFile $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArticleFilePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArticleFilePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArticleFilePeer::DATABASE_NAME, ArticleFilePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArticleFilePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ArticleFilePeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleFilePeer::ID, $pk);
    +
    +
    +		$v = ArticleFilePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ArticleFilePeer::ID, $pks, Criteria::IN);
    +			$objs = ArticleFilePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArticleFilePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArticleFileMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArticleFileMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArticleI18n.php b/lib/model/om/BaseArticleI18n.php
    new file mode 100644
    index 0000000..20a0f62
    --- /dev/null
    +++ b/lib/model/om/BaseArticleI18n.php
    @@ -0,0 +1,472 @@
    +title;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function getCulture()
    +	{
    +
    +		return $this->culture;
    +	}
    +
    +	
    +	public function setTitle($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->title !== $v) {
    +			$this->title = $v;
    +			$this->modifiedColumns[] = ArticleI18nPeer::TITLE;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArticleI18nPeer::ID;
    +		}
    +
    +		if ($this->aArticle !== null && $this->aArticle->getId() !== $v) {
    +			$this->aArticle = null;
    +		}
    +
    +	} 
    +	
    +	public function setCulture($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->culture !== $v) {
    +			$this->culture = $v;
    +			$this->modifiedColumns[] = ArticleI18nPeer::CULTURE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->title = $rs->getString($startcol + 0);
    +
    +			$this->id = $rs->getInt($startcol + 1);
    +
    +			$this->culture = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArticleI18n object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleI18n:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArticleI18nPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleI18n:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleI18n:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArticleI18n:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if ($this->aArticle->isModified() || $this->aArticle->getCurrentArticleI18n()->isModified()) {
    +					$affectedRows += $this->aArticle->save($con);
    +				}
    +				$this->setArticle($this->aArticle);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArticleI18nPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArticleI18nPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if (!$this->aArticle->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticle->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArticleI18nPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getTitle();
    +				break;
    +			case 1:
    +				return $this->getId();
    +				break;
    +			case 2:
    +				return $this->getCulture();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleI18nPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getTitle(),
    +			$keys[1] => $this->getId(),
    +			$keys[2] => $this->getCulture(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setTitle($value);
    +				break;
    +			case 1:
    +				$this->setId($value);
    +				break;
    +			case 2:
    +				$this->setCulture($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleI18nPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setTitle($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setCulture($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArticleI18nPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArticleI18nPeer::TITLE)) $criteria->add(ArticleI18nPeer::TITLE, $this->title);
    +		if ($this->isColumnModified(ArticleI18nPeer::ID)) $criteria->add(ArticleI18nPeer::ID, $this->id);
    +		if ($this->isColumnModified(ArticleI18nPeer::CULTURE)) $criteria->add(ArticleI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArticleI18nPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleI18nPeer::ID, $this->id);
    +		$criteria->add(ArticleI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getId();
    +
    +		$pks[1] = $this->getCulture();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setId($keys[0]);
    +
    +		$this->setCulture($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setTitle($this->title);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +		$copyObj->setCulture(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArticleI18nPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setArticle($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setId(NULL);
    +		} else {
    +			$this->setId($v->getId());
    +		}
    +
    +
    +		$this->aArticle = $v;
    +	}
    +
    +
    +	
    +	public function getArticle($con = null)
    +	{
    +		if ($this->aArticle === null && ($this->id !== null)) {
    +						include_once 'lib/model/om/BaseArticlePeer.php';
    +
    +			$this->aArticle = ArticlePeer::retrieveByPK($this->id, $con);
    +
    +			
    +		}
    +		return $this->aArticle;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArticleI18n:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArticleI18n::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArticleI18nPeer.php b/lib/model/om/BaseArticleI18nPeer.php
    new file mode 100644
    index 0000000..cf396f9
    --- /dev/null
    +++ b/lib/model/om/BaseArticleI18nPeer.php
    @@ -0,0 +1,569 @@
    + array ('Title', 'Id', 'Culture', ),
    +		BasePeer::TYPE_COLNAME => array (ArticleI18nPeer::TITLE, ArticleI18nPeer::ID, ArticleI18nPeer::CULTURE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('title', 'id', 'culture', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Title' => 0, 'Id' => 1, 'Culture' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (ArticleI18nPeer::TITLE => 0, ArticleI18nPeer::ID => 1, ArticleI18nPeer::CULTURE => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('title' => 0, 'id' => 1, 'culture' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArticleI18nMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArticleI18nMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArticleI18nPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArticleI18nPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArticleI18nPeer::TITLE);
    +
    +		$criteria->addSelectColumn(ArticleI18nPeer::ID);
    +
    +		$criteria->addSelectColumn(ArticleI18nPeer::CULTURE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(article_i18n.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT article_i18n.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArticleI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArticleI18nPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArticleI18nPeer::populateObjects(ArticleI18nPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleI18nPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleI18nPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArticleI18nPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArticleI18nPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleI18nPeer::ID, ArticlePeer::ID);
    +
    +		$rs = ArticleI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleI18nPeer::addSelectColumns($c);
    +		$startcol = (ArticleI18nPeer::NUM_COLUMNS - ArticleI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticlePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleI18nPeer::ID, ArticlePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleI18nPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleI18n($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleI18ns();
    +				$obj2->addArticleI18n($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleI18nPeer::ID, ArticlePeer::ID);
    +
    +		$rs = ArticleI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleI18nPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleI18nPeer::NUM_COLUMNS - ArticleI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleI18nPeer::ID, ArticlePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleI18nPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleI18n($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleI18ns();
    +				$obj2->addArticleI18n($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArticleI18nPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleI18nPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArticleI18nPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleI18nPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleI18nPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArticleI18nPeer::ID);
    +			$selectCriteria->add(ArticleI18nPeer::ID, $criteria->remove(ArticleI18nPeer::ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(ArticleI18nPeer::CULTURE);
    +			$selectCriteria->add(ArticleI18nPeer::CULTURE, $criteria->remove(ArticleI18nPeer::CULTURE), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleI18nPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleI18nPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ArticleI18nPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleI18nPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArticleI18n) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(ArticleI18nPeer::ID, $vals[0], Criteria::IN);
    +			$criteria->add(ArticleI18nPeer::CULTURE, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ArticleI18n $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArticleI18nPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArticleI18nPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArticleI18nPeer::DATABASE_NAME, ArticleI18nPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArticleI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $id, $culture, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(ArticleI18nPeer::ID, $id);
    +		$criteria->add(ArticleI18nPeer::CULTURE, $culture);
    +		$v = ArticleI18nPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArticleI18nPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArticleI18nMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArticleI18nMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArticlePeer.php b/lib/model/om/BaseArticlePeer.php
    new file mode 100644
    index 0000000..c37151a
    --- /dev/null
    +++ b/lib/model/om/BaseArticlePeer.php
    @@ -0,0 +1,990 @@
    + array ('Id', 'CreatedAt', 'AuthorId', 'BaseTitle', 'Permalink', 'Ingress', 'Content', 'UpdatedAt', 'UpdatedBy', 'ArticleType', 'ArticleOrder', 'ExpiresAt', 'Status', 'PublishedAt', 'BannerFileId', 'IsSticky', 'Frontpage', ),
    +		BasePeer::TYPE_COLNAME => array (ArticlePeer::ID, ArticlePeer::CREATED_AT, ArticlePeer::AUTHOR_ID, ArticlePeer::BASE_TITLE, ArticlePeer::PERMALINK, ArticlePeer::INGRESS, ArticlePeer::CONTENT, ArticlePeer::UPDATED_AT, ArticlePeer::UPDATED_BY, ArticlePeer::ARTICLE_TYPE, ArticlePeer::ARTICLE_ORDER, ArticlePeer::EXPIRES_AT, ArticlePeer::STATUS, ArticlePeer::PUBLISHED_AT, ArticlePeer::BANNER_FILE_ID, ArticlePeer::IS_STICKY, ArticlePeer::FRONTPAGE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'created_at', 'author_id', 'base_title', 'permalink', 'ingress', 'content', 'updated_at', 'updated_by', 'article_type', 'article_order', 'expires_at', 'status', 'published_at', 'banner_file_id', 'is_sticky', 'frontpage', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'CreatedAt' => 1, 'AuthorId' => 2, 'BaseTitle' => 3, 'Permalink' => 4, 'Ingress' => 5, 'Content' => 6, 'UpdatedAt' => 7, 'UpdatedBy' => 8, 'ArticleType' => 9, 'ArticleOrder' => 10, 'ExpiresAt' => 11, 'Status' => 12, 'PublishedAt' => 13, 'BannerFileId' => 14, 'IsSticky' => 15, 'Frontpage' => 16, ),
    +		BasePeer::TYPE_COLNAME => array (ArticlePeer::ID => 0, ArticlePeer::CREATED_AT => 1, ArticlePeer::AUTHOR_ID => 2, ArticlePeer::BASE_TITLE => 3, ArticlePeer::PERMALINK => 4, ArticlePeer::INGRESS => 5, ArticlePeer::CONTENT => 6, ArticlePeer::UPDATED_AT => 7, ArticlePeer::UPDATED_BY => 8, ArticlePeer::ARTICLE_TYPE => 9, ArticlePeer::ARTICLE_ORDER => 10, ArticlePeer::EXPIRES_AT => 11, ArticlePeer::STATUS => 12, ArticlePeer::PUBLISHED_AT => 13, ArticlePeer::BANNER_FILE_ID => 14, ArticlePeer::IS_STICKY => 15, ArticlePeer::FRONTPAGE => 16, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'created_at' => 1, 'author_id' => 2, 'base_title' => 3, 'permalink' => 4, 'ingress' => 5, 'content' => 6, 'updated_at' => 7, 'updated_by' => 8, 'article_type' => 9, 'article_order' => 10, 'expires_at' => 11, 'status' => 12, 'published_at' => 13, 'banner_file_id' => 14, 'is_sticky' => 15, 'frontpage' => 16, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArticleMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArticleMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArticlePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArticlePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArticlePeer::ID);
    +
    +		$criteria->addSelectColumn(ArticlePeer::CREATED_AT);
    +
    +		$criteria->addSelectColumn(ArticlePeer::AUTHOR_ID);
    +
    +		$criteria->addSelectColumn(ArticlePeer::BASE_TITLE);
    +
    +		$criteria->addSelectColumn(ArticlePeer::PERMALINK);
    +
    +		$criteria->addSelectColumn(ArticlePeer::INGRESS);
    +
    +		$criteria->addSelectColumn(ArticlePeer::CONTENT);
    +
    +		$criteria->addSelectColumn(ArticlePeer::UPDATED_AT);
    +
    +		$criteria->addSelectColumn(ArticlePeer::UPDATED_BY);
    +
    +		$criteria->addSelectColumn(ArticlePeer::ARTICLE_TYPE);
    +
    +		$criteria->addSelectColumn(ArticlePeer::ARTICLE_ORDER);
    +
    +		$criteria->addSelectColumn(ArticlePeer::EXPIRES_AT);
    +
    +		$criteria->addSelectColumn(ArticlePeer::STATUS);
    +
    +		$criteria->addSelectColumn(ArticlePeer::PUBLISHED_AT);
    +
    +		$criteria->addSelectColumn(ArticlePeer::BANNER_FILE_ID);
    +
    +		$criteria->addSelectColumn(ArticlePeer::IS_STICKY);
    +
    +		$criteria->addSelectColumn(ArticlePeer::FRONTPAGE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(article.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT article.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArticlePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArticlePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArticlePeer::populateObjects(ArticlePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticlePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticlePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArticlePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArticlePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticlePeer::AUTHOR_ID, sfGuardUserPeer::ID);
    +
    +		$rs = ArticlePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinArticleFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticlePeer::BANNER_FILE_ID, ArticleFilePeer::ID);
    +
    +		$rs = ArticlePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol = (ArticlePeer::NUM_COLUMNS - ArticlePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticlePeer::AUTHOR_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticle($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticles();
    +				$obj2->addArticle($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticleFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol = (ArticlePeer::NUM_COLUMNS - ArticlePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticleFilePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticlePeer::BANNER_FILE_ID, ArticleFilePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticleFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticle($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticles();
    +				$obj2->addArticle($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticlePeer::AUTHOR_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ArticlePeer::BANNER_FILE_ID, ArticleFilePeer::ID);
    +
    +		$rs = ArticlePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol2 = (ArticlePeer::NUM_COLUMNS - ArticlePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArticleFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticlePeer::AUTHOR_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ArticlePeer::BANNER_FILE_ID, ArticleFilePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticle($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticles();
    +				$obj2->addArticle($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArticleFile(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticle($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticles();
    +				$obj3->addArticle($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticlePeer::BANNER_FILE_ID, ArticleFilePeer::ID);
    +
    +		$rs = ArticlePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticleFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticlePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticlePeer::AUTHOR_ID, sfGuardUserPeer::ID);
    +
    +		$rs = ArticlePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol2 = (ArticlePeer::NUM_COLUMNS - ArticlePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticleFilePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticleFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticlePeer::BANNER_FILE_ID, ArticleFilePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticleFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticleFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticle($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticles();
    +				$obj2->addArticle($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticleFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol2 = (ArticlePeer::NUM_COLUMNS - ArticlePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticlePeer::AUTHOR_ID, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticle($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticles();
    +				$obj2->addArticle($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +  
    +  public static function doSelectWithI18n(Criteria $c, $culture = null, $con = null)
    +  {
    +    if ($culture === null)
    +    {
    +      $culture = sfContext::getInstance()->getUser()->getCulture();
    +    }
    +
    +        if ($c->getDbName() == Propel::getDefaultDB())
    +    {
    +      $c->setDbName(self::DATABASE_NAME);
    +    }
    +
    +    ArticlePeer::addSelectColumns($c);
    +    $startcol = (ArticlePeer::NUM_COLUMNS - ArticlePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +    ArticleI18nPeer::addSelectColumns($c);
    +
    +    $c->addJoin(ArticlePeer::ID, ArticleI18nPeer::ID);
    +    $c->add(ArticleI18nPeer::CULTURE, $culture);
    +
    +    $rs = BasePeer::doSelect($c, $con);
    +    $results = array();
    +
    +    while($rs->next()) {
    +
    +      $omClass = ArticlePeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj1 = new $cls();
    +      $obj1->hydrate($rs);
    +      $obj1->setCulture($culture);
    +
    +      $omClass = ArticleI18nPeer::getOMClass($rs, $startcol);
    +
    +      $cls = Propel::import($omClass);
    +      $obj2 = new $cls();
    +      $obj2->hydrate($rs, $startcol);
    +
    +      $obj1->setArticleI18nForCulture($obj2, $culture);
    +      $obj2->setArticle($obj1);
    +
    +      $results[] = $obj1;
    +    }
    +    return $results;
    +  }
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArticlePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticlePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticlePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ArticlePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArticlePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticlePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticlePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticlePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArticlePeer::ID);
    +			$selectCriteria->add(ArticlePeer::ID, $criteria->remove(ArticlePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticlePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticlePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += ArticlePeer::doOnDeleteCascade(new Criteria(), $con);
    +			$affectedRows += BasePeer::doDeleteAll(ArticlePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticlePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof Article) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ArticlePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			$affectedRows += ArticlePeer::doOnDeleteCascade($criteria, $con);
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected static function doOnDeleteCascade(Criteria $criteria, Connection $con)
    +	{
    +				$affectedRows = 0;
    +
    +				$objects = ArticlePeer::doSelect($criteria, $con);
    +		foreach($objects as $obj) {
    +
    +
    +			include_once 'lib/model/ArticleI18n.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(ArticleI18nPeer::ID, $obj->getId());
    +			$affectedRows += ArticleI18nPeer::doDelete($c, $con);
    +		}
    +		return $affectedRows;
    +	}
    +
    +	
    +	public static function doValidate(Article $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArticlePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArticlePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArticlePeer::DATABASE_NAME, ArticlePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArticlePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ArticlePeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticlePeer::ID, $pk);
    +
    +
    +		$v = ArticlePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ArticlePeer::ID, $pks, Criteria::IN);
    +			$objs = ArticlePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArticlePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArticleMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArticleMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArticleSubreaktor.php b/lib/model/om/BaseArticleSubreaktor.php
    new file mode 100644
    index 0000000..9299cb8
    --- /dev/null
    +++ b/lib/model/om/BaseArticleSubreaktor.php
    @@ -0,0 +1,512 @@
    +article_id;
    +	}
    +
    +	
    +	public function getSubreaktorId()
    +	{
    +
    +		return $this->subreaktor_id;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function setArticleId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->article_id !== $v) {
    +			$this->article_id = $v;
    +			$this->modifiedColumns[] = ArticleSubreaktorPeer::ARTICLE_ID;
    +		}
    +
    +		if ($this->aArticle !== null && $this->aArticle->getId() !== $v) {
    +			$this->aArticle = null;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktorId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor_id !== $v) {
    +			$this->subreaktor_id = $v;
    +			$this->modifiedColumns[] = ArticleSubreaktorPeer::SUBREAKTOR_ID;
    +		}
    +
    +		if ($this->aSubreaktor !== null && $this->aSubreaktor->getId() !== $v) {
    +			$this->aSubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArticleSubreaktorPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->article_id = $rs->getInt($startcol + 0);
    +
    +			$this->subreaktor_id = $rs->getInt($startcol + 1);
    +
    +			$this->id = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArticleSubreaktor object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktor:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleSubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArticleSubreaktorPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktor:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktor:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleSubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktor:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if ($this->aArticle->isModified() || $this->aArticle->getCurrentArticleI18n()->isModified()) {
    +					$affectedRows += $this->aArticle->save($con);
    +				}
    +				$this->setArticle($this->aArticle);
    +			}
    +
    +			if ($this->aSubreaktor !== null) {
    +				if ($this->aSubreaktor->isModified() || $this->aSubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktor->save($con);
    +				}
    +				$this->setSubreaktor($this->aSubreaktor);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArticleSubreaktorPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArticleSubreaktorPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aArticle !== null) {
    +				if (!$this->aArticle->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticle->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aSubreaktor !== null) {
    +				if (!$this->aSubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArticleSubreaktorPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleSubreaktorPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getArticleId();
    +				break;
    +			case 1:
    +				return $this->getSubreaktorId();
    +				break;
    +			case 2:
    +				return $this->getId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleSubreaktorPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getArticleId(),
    +			$keys[1] => $this->getSubreaktorId(),
    +			$keys[2] => $this->getId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArticleSubreaktorPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setArticleId($value);
    +				break;
    +			case 1:
    +				$this->setSubreaktorId($value);
    +				break;
    +			case 2:
    +				$this->setId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArticleSubreaktorPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setArticleId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setSubreaktorId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setId($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArticleSubreaktorPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArticleSubreaktorPeer::ARTICLE_ID)) $criteria->add(ArticleSubreaktorPeer::ARTICLE_ID, $this->article_id);
    +		if ($this->isColumnModified(ArticleSubreaktorPeer::SUBREAKTOR_ID)) $criteria->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, $this->subreaktor_id);
    +		if ($this->isColumnModified(ArticleSubreaktorPeer::ID)) $criteria->add(ArticleSubreaktorPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArticleSubreaktorPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleSubreaktorPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setArticleId($this->article_id);
    +
    +		$copyObj->setSubreaktorId($this->subreaktor_id);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArticleSubreaktorPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setArticle($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArticleId(NULL);
    +		} else {
    +			$this->setArticleId($v->getId());
    +		}
    +
    +
    +		$this->aArticle = $v;
    +	}
    +
    +
    +	
    +	public function getArticle($con = null)
    +	{
    +		if ($this->aArticle === null && ($this->article_id !== null)) {
    +						include_once 'lib/model/om/BaseArticlePeer.php';
    +
    +			$this->aArticle = ArticlePeer::retrieveByPK($this->article_id, $con);
    +
    +			
    +		}
    +		return $this->aArticle;
    +	}
    +
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSubreaktorId(NULL);
    +		} else {
    +			$this->setSubreaktorId($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktor === null && ($this->subreaktor_id !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktor = SubreaktorPeer::retrieveByPK($this->subreaktor_id, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktor;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArticleSubreaktor:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArticleSubreaktor::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArticleSubreaktorPeer.php b/lib/model/om/BaseArticleSubreaktorPeer.php
    new file mode 100644
    index 0000000..81a230f
    --- /dev/null
    +++ b/lib/model/om/BaseArticleSubreaktorPeer.php
    @@ -0,0 +1,852 @@
    + array ('ArticleId', 'SubreaktorId', 'Id', ),
    +		BasePeer::TYPE_COLNAME => array (ArticleSubreaktorPeer::ARTICLE_ID, ArticleSubreaktorPeer::SUBREAKTOR_ID, ArticleSubreaktorPeer::ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('article_id', 'subreaktor_id', 'id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('ArticleId' => 0, 'SubreaktorId' => 1, 'Id' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (ArticleSubreaktorPeer::ARTICLE_ID => 0, ArticleSubreaktorPeer::SUBREAKTOR_ID => 1, ArticleSubreaktorPeer::ID => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('article_id' => 0, 'subreaktor_id' => 1, 'id' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArticleSubreaktorMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArticleSubreaktorMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArticleSubreaktorPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArticleSubreaktorPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArticleSubreaktorPeer::ARTICLE_ID);
    +
    +		$criteria->addSelectColumn(ArticleSubreaktorPeer::SUBREAKTOR_ID);
    +
    +		$criteria->addSelectColumn(ArticleSubreaktorPeer::ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(article_subreaktor.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT article_subreaktor.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArticleSubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArticleSubreaktorPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArticleSubreaktorPeer::populateObjects(ArticleSubreaktorPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktorPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleSubreaktorPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArticleSubreaktorPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArticleSubreaktorPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleSubreaktorPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = ArticleSubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleSubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = ArticleSubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleSubreaktorPeer::addSelectColumns($c);
    +		$startcol = (ArticleSubreaktorPeer::NUM_COLUMNS - ArticleSubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticlePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleSubreaktorPeer::ARTICLE_ID, ArticlePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleSubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleSubreaktor($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleSubreaktors();
    +				$obj2->addArticleSubreaktor($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleSubreaktorPeer::addSelectColumns($c);
    +		$startcol = (ArticleSubreaktorPeer::NUM_COLUMNS - ArticleSubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArticleSubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleSubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArticleSubreaktor($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArticleSubreaktors();
    +				$obj2->addArticleSubreaktor($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleSubreaktorPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$criteria->addJoin(ArticleSubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = ArticleSubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleSubreaktorPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleSubreaktorPeer::NUM_COLUMNS - ArticleSubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleSubreaktorPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$c->addJoin(ArticleSubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleSubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleSubreaktor($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleSubreaktors();
    +				$obj2->addArticleSubreaktor($obj1);
    +			}
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getSubreaktor(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addArticleSubreaktor($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initArticleSubreaktors();
    +				$obj3->addArticleSubreaktor($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleSubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = ArticleSubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArticleSubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArticleSubreaktorPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = ArticleSubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleSubreaktorPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleSubreaktorPeer::NUM_COLUMNS - ArticleSubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleSubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleSubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleSubreaktor($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleSubreaktors();
    +				$obj2->addArticleSubreaktor($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArticleSubreaktorPeer::addSelectColumns($c);
    +		$startcol2 = (ArticleSubreaktorPeer::NUM_COLUMNS - ArticleSubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArticlePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArticleSubreaktorPeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArticleSubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArticleSubreaktor($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArticleSubreaktors();
    +				$obj2->addArticleSubreaktor($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArticleSubreaktorPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktorPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleSubreaktorPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ArticleSubreaktorPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktorPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleSubreaktorPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktorPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArticleSubreaktorPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArticleSubreaktorPeer::ID);
    +			$selectCriteria->add(ArticleSubreaktorPeer::ID, $criteria->remove(ArticleSubreaktorPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArticleSubreaktorPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArticleSubreaktorPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ArticleSubreaktorPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArticleSubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArticleSubreaktor) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ArticleSubreaktorPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ArticleSubreaktor $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArticleSubreaktorPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArticleSubreaktorPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArticleSubreaktorPeer::DATABASE_NAME, ArticleSubreaktorPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArticleSubreaktorPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ArticleSubreaktorPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArticleSubreaktorPeer::ID, $pk);
    +
    +
    +		$v = ArticleSubreaktorPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ArticleSubreaktorPeer::ID, $pks, Criteria::IN);
    +			$objs = ArticleSubreaktorPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArticleSubreaktorPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArticleSubreaktorMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArticleSubreaktorMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArtworkStatus.php b/lib/model/om/BaseArtworkStatus.php
    new file mode 100644
    index 0000000..43470b9
    --- /dev/null
    +++ b/lib/model/om/BaseArtworkStatus.php
    @@ -0,0 +1,925 @@
    +id;
    +	}
    +
    +	
    +	public function getName()
    +	{
    +
    +		return $this->name;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArtworkStatusPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setName($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->name !== $v) {
    +			$this->name = $v;
    +			$this->modifiedColumns[] = ArtworkStatusPeer::NAME;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->name = $rs->getString($startcol + 1);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 2; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArtworkStatus object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatus:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArtworkStatusPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArtworkStatusPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatus:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatus:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArtworkStatusPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArtworkStatus:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArtworkStatusPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArtworkStatusPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collReaktorArtworks !== null) {
    +				foreach($this->collReaktorArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArtworkStatusI18ns !== null) {
    +				foreach($this->collArtworkStatusI18ns as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collReaktorArtworkHistorys !== null) {
    +				foreach($this->collReaktorArtworkHistorys as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = ArtworkStatusPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collReaktorArtworks !== null) {
    +					foreach($this->collReaktorArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArtworkStatusI18ns !== null) {
    +					foreach($this->collArtworkStatusI18ns as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collReaktorArtworkHistorys !== null) {
    +					foreach($this->collReaktorArtworkHistorys as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArtworkStatusPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getName();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArtworkStatusPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getName(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArtworkStatusPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setName($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArtworkStatusPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setName($arr[$keys[1]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArtworkStatusPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArtworkStatusPeer::ID)) $criteria->add(ArtworkStatusPeer::ID, $this->id);
    +		if ($this->isColumnModified(ArtworkStatusPeer::NAME)) $criteria->add(ArtworkStatusPeer::NAME, $this->name);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArtworkStatusPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArtworkStatusPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setName($this->name);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getReaktorArtworks() as $relObj) {
    +				$copyObj->addReaktorArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArtworkStatusI18ns() as $relObj) {
    +				$copyObj->addArtworkStatusI18n($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getReaktorArtworkHistorys() as $relObj) {
    +				$copyObj->addReaktorArtworkHistory($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArtworkStatusPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function initReaktorArtworks()
    +	{
    +		if ($this->collReaktorArtworks === null) {
    +			$this->collReaktorArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getReaktorArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collReaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +				ReaktorArtworkPeer::addSelectColumns($criteria);
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +				ReaktorArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) {
    +					$this->collReaktorArtworks = ReaktorArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastReaktorArtworkCriteria = $criteria;
    +		return $this->collReaktorArtworks;
    +	}
    +
    +	
    +	public function countReaktorArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +		return ReaktorArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addReaktorArtwork(ReaktorArtwork $l)
    +	{
    +		$this->collReaktorArtworks[] = $l;
    +		$l->setArtworkStatus($this);
    +	}
    +
    +
    +	
    +	public function getReaktorArtworksJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) {
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkCriteria = $criteria;
    +
    +		return $this->collReaktorArtworks;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworksJoinsfGuardGroup($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardGroup($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) {
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardGroup($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkCriteria = $criteria;
    +
    +		return $this->collReaktorArtworks;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworksJoinReaktorFile($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinReaktorFile($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkPeer::STATUS, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) {
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinReaktorFile($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkCriteria = $criteria;
    +
    +		return $this->collReaktorArtworks;
    +	}
    +
    +	
    +	public function initArtworkStatusI18ns()
    +	{
    +		if ($this->collArtworkStatusI18ns === null) {
    +			$this->collArtworkStatusI18ns = array();
    +		}
    +	}
    +
    +	
    +	public function getArtworkStatusI18ns($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArtworkStatusI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArtworkStatusI18ns === null) {
    +			if ($this->isNew()) {
    +			   $this->collArtworkStatusI18ns = array();
    +			} else {
    +
    +				$criteria->add(ArtworkStatusI18nPeer::ID, $this->getId());
    +
    +				ArtworkStatusI18nPeer::addSelectColumns($criteria);
    +				$this->collArtworkStatusI18ns = ArtworkStatusI18nPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArtworkStatusI18nPeer::ID, $this->getId());
    +
    +				ArtworkStatusI18nPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArtworkStatusI18nCriteria) || !$this->lastArtworkStatusI18nCriteria->equals($criteria)) {
    +					$this->collArtworkStatusI18ns = ArtworkStatusI18nPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArtworkStatusI18nCriteria = $criteria;
    +		return $this->collArtworkStatusI18ns;
    +	}
    +
    +	
    +	public function countArtworkStatusI18ns($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArtworkStatusI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArtworkStatusI18nPeer::ID, $this->getId());
    +
    +		return ArtworkStatusI18nPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArtworkStatusI18n(ArtworkStatusI18n $l)
    +	{
    +		$this->collArtworkStatusI18ns[] = $l;
    +		$l->setArtworkStatus($this);
    +	}
    +
    +	
    +	public function initReaktorArtworkHistorys()
    +	{
    +		if ($this->collReaktorArtworkHistorys === null) {
    +			$this->collReaktorArtworkHistorys = array();
    +		}
    +	}
    +
    +	
    +	public function getReaktorArtworkHistorys($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorys === null) {
    +			if ($this->isNew()) {
    +			   $this->collReaktorArtworkHistorys = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +				ReaktorArtworkHistoryPeer::addSelectColumns($criteria);
    +				$this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +				ReaktorArtworkHistoryPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastReaktorArtworkHistoryCriteria) || !$this->lastReaktorArtworkHistoryCriteria->equals($criteria)) {
    +					$this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryCriteria = $criteria;
    +		return $this->collReaktorArtworkHistorys;
    +	}
    +
    +	
    +	public function countReaktorArtworkHistorys($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +		return ReaktorArtworkHistoryPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addReaktorArtworkHistory(ReaktorArtworkHistory $l)
    +	{
    +		$this->collReaktorArtworkHistorys[] = $l;
    +		$l->setArtworkStatus($this);
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkHistorysJoinReaktorArtworkRelatedByArtworkId($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorys === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkHistorys = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +				$this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinReaktorArtworkRelatedByArtworkId($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkHistoryCriteria) || !$this->lastReaktorArtworkHistoryCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinReaktorArtworkRelatedByArtworkId($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkHistorys;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkHistorysJoinReaktorArtworkRelatedByFileId($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorys === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkHistorys = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +				$this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinReaktorArtworkRelatedByFileId($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkHistoryCriteria) || !$this->lastReaktorArtworkHistoryCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinReaktorArtworkRelatedByFileId($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkHistorys;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkHistorysJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorys === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkHistorys = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +				$this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkHistoryCriteria) || !$this->lastReaktorArtworkHistoryCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkHistorys;
    +	}
    +
    +  public function getCulture()
    +  {
    +    return $this->culture;
    +  }
    +
    +  public function setCulture($culture)
    +  {
    +    $this->culture = $culture;
    +  }
    +
    +  public function getDescription()
    +  {
    +    $obj = $this->getCurrentArtworkStatusI18n();
    +
    +    return ($obj ? $obj->getDescription() : null);
    +  }
    +
    +  public function setDescription($value)
    +  {
    +    $this->getCurrentArtworkStatusI18n()->setDescription($value);
    +  }
    +
    +  protected $current_i18n = array();
    +
    +  public function getCurrentArtworkStatusI18n()
    +  {
    +    if (!isset($this->current_i18n[$this->culture]))
    +    {
    +      $obj = ArtworkStatusI18nPeer::retrieveByPK($this->getId(), $this->culture);
    +      if ($obj)
    +      {
    +        $this->setArtworkStatusI18nForCulture($obj, $this->culture);
    +      }
    +      else
    +      {
    +        $this->setArtworkStatusI18nForCulture(new ArtworkStatusI18n(), $this->culture);
    +        $this->current_i18n[$this->culture]->setCulture($this->culture);
    +      }
    +    }
    +
    +    return $this->current_i18n[$this->culture];
    +  }
    +
    +  public function setArtworkStatusI18nForCulture($object, $culture)
    +  {
    +    $this->current_i18n[$culture] = $object;
    +    $this->addArtworkStatusI18n($object);
    +  }
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArtworkStatus:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArtworkStatus::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArtworkStatusI18n.php b/lib/model/om/BaseArtworkStatusI18n.php
    new file mode 100644
    index 0000000..278647e
    --- /dev/null
    +++ b/lib/model/om/BaseArtworkStatusI18n.php
    @@ -0,0 +1,472 @@
    +id;
    +	}
    +
    +	
    +	public function getDescription()
    +	{
    +
    +		return $this->description;
    +	}
    +
    +	
    +	public function getCulture()
    +	{
    +
    +		return $this->culture;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ArtworkStatusI18nPeer::ID;
    +		}
    +
    +		if ($this->aArtworkStatus !== null && $this->aArtworkStatus->getId() !== $v) {
    +			$this->aArtworkStatus = null;
    +		}
    +
    +	} 
    +	
    +	public function setDescription($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->description !== $v) {
    +			$this->description = $v;
    +			$this->modifiedColumns[] = ArtworkStatusI18nPeer::DESCRIPTION;
    +		}
    +
    +	} 
    +	
    +	public function setCulture($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->culture !== $v) {
    +			$this->culture = $v;
    +			$this->modifiedColumns[] = ArtworkStatusI18nPeer::CULTURE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->description = $rs->getString($startcol + 1);
    +
    +			$this->culture = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ArtworkStatusI18n object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18n:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArtworkStatusI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ArtworkStatusI18nPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18n:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18n:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArtworkStatusI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18n:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aArtworkStatus !== null) {
    +				if ($this->aArtworkStatus->isModified() || $this->aArtworkStatus->getCurrentArtworkStatusI18n()->isModified()) {
    +					$affectedRows += $this->aArtworkStatus->save($con);
    +				}
    +				$this->setArtworkStatus($this->aArtworkStatus);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ArtworkStatusI18nPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ArtworkStatusI18nPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aArtworkStatus !== null) {
    +				if (!$this->aArtworkStatus->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArtworkStatus->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ArtworkStatusI18nPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArtworkStatusI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getDescription();
    +				break;
    +			case 2:
    +				return $this->getCulture();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArtworkStatusI18nPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getDescription(),
    +			$keys[2] => $this->getCulture(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ArtworkStatusI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setDescription($value);
    +				break;
    +			case 2:
    +				$this->setCulture($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ArtworkStatusI18nPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setDescription($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setCulture($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ArtworkStatusI18nPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ArtworkStatusI18nPeer::ID)) $criteria->add(ArtworkStatusI18nPeer::ID, $this->id);
    +		if ($this->isColumnModified(ArtworkStatusI18nPeer::DESCRIPTION)) $criteria->add(ArtworkStatusI18nPeer::DESCRIPTION, $this->description);
    +		if ($this->isColumnModified(ArtworkStatusI18nPeer::CULTURE)) $criteria->add(ArtworkStatusI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ArtworkStatusI18nPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArtworkStatusI18nPeer::ID, $this->id);
    +		$criteria->add(ArtworkStatusI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getId();
    +
    +		$pks[1] = $this->getCulture();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setId($keys[0]);
    +
    +		$this->setCulture($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setDescription($this->description);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +		$copyObj->setCulture(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ArtworkStatusI18nPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setArtworkStatus($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setId(NULL);
    +		} else {
    +			$this->setId($v->getId());
    +		}
    +
    +
    +		$this->aArtworkStatus = $v;
    +	}
    +
    +
    +	
    +	public function getArtworkStatus($con = null)
    +	{
    +		if ($this->aArtworkStatus === null && ($this->id !== null)) {
    +						include_once 'lib/model/om/BaseArtworkStatusPeer.php';
    +
    +			$this->aArtworkStatus = ArtworkStatusPeer::retrieveByPK($this->id, $con);
    +
    +			
    +		}
    +		return $this->aArtworkStatus;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseArtworkStatusI18n:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseArtworkStatusI18n::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseArtworkStatusI18nPeer.php b/lib/model/om/BaseArtworkStatusI18nPeer.php
    new file mode 100644
    index 0000000..739d544
    --- /dev/null
    +++ b/lib/model/om/BaseArtworkStatusI18nPeer.php
    @@ -0,0 +1,569 @@
    + array ('Id', 'Description', 'Culture', ),
    +		BasePeer::TYPE_COLNAME => array (ArtworkStatusI18nPeer::ID, ArtworkStatusI18nPeer::DESCRIPTION, ArtworkStatusI18nPeer::CULTURE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'description', 'culture', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Description' => 1, 'Culture' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (ArtworkStatusI18nPeer::ID => 0, ArtworkStatusI18nPeer::DESCRIPTION => 1, ArtworkStatusI18nPeer::CULTURE => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'description' => 1, 'culture' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArtworkStatusI18nMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArtworkStatusI18nMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArtworkStatusI18nPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArtworkStatusI18nPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArtworkStatusI18nPeer::ID);
    +
    +		$criteria->addSelectColumn(ArtworkStatusI18nPeer::DESCRIPTION);
    +
    +		$criteria->addSelectColumn(ArtworkStatusI18nPeer::CULTURE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(artwork_status_i18n.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT artwork_status_i18n.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArtworkStatusI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArtworkStatusI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArtworkStatusI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArtworkStatusI18nPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArtworkStatusI18nPeer::populateObjects(ArtworkStatusI18nPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18nPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArtworkStatusI18nPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArtworkStatusI18nPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArtworkStatusI18nPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinArtworkStatus(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArtworkStatusI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArtworkStatusI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArtworkStatusI18nPeer::ID, ArtworkStatusPeer::ID);
    +
    +		$rs = ArtworkStatusI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArtworkStatus(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArtworkStatusI18nPeer::addSelectColumns($c);
    +		$startcol = (ArtworkStatusI18nPeer::NUM_COLUMNS - ArtworkStatusI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArtworkStatusPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ArtworkStatusI18nPeer::ID, ArtworkStatusPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArtworkStatusI18nPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addArtworkStatusI18n($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initArtworkStatusI18ns();
    +				$obj2->addArtworkStatusI18n($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArtworkStatusI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArtworkStatusI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ArtworkStatusI18nPeer::ID, ArtworkStatusPeer::ID);
    +
    +		$rs = ArtworkStatusI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ArtworkStatusI18nPeer::addSelectColumns($c);
    +		$startcol2 = (ArtworkStatusI18nPeer::NUM_COLUMNS - ArtworkStatusI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ArtworkStatusI18nPeer::ID, ArtworkStatusPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ArtworkStatusI18nPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addArtworkStatusI18n($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initArtworkStatusI18ns();
    +				$obj2->addArtworkStatusI18n($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArtworkStatusI18nPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18nPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArtworkStatusI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18nPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArtworkStatusI18nPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18nPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArtworkStatusI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArtworkStatusI18nPeer::ID);
    +			$selectCriteria->add(ArtworkStatusI18nPeer::ID, $criteria->remove(ArtworkStatusI18nPeer::ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(ArtworkStatusI18nPeer::CULTURE);
    +			$selectCriteria->add(ArtworkStatusI18nPeer::CULTURE, $criteria->remove(ArtworkStatusI18nPeer::CULTURE), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusI18nPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArtworkStatusI18nPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ArtworkStatusI18nPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArtworkStatusI18nPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArtworkStatusI18n) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(ArtworkStatusI18nPeer::ID, $vals[0], Criteria::IN);
    +			$criteria->add(ArtworkStatusI18nPeer::CULTURE, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ArtworkStatusI18n $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArtworkStatusI18nPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArtworkStatusI18nPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArtworkStatusI18nPeer::DATABASE_NAME, ArtworkStatusI18nPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArtworkStatusI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $id, $culture, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(ArtworkStatusI18nPeer::ID, $id);
    +		$criteria->add(ArtworkStatusI18nPeer::CULTURE, $culture);
    +		$v = ArtworkStatusI18nPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArtworkStatusI18nPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArtworkStatusI18nMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArtworkStatusI18nMapBuilder');
    +}
    diff --git a/lib/model/om/BaseArtworkStatusPeer.php b/lib/model/om/BaseArtworkStatusPeer.php
    new file mode 100644
    index 0000000..ae350b1
    --- /dev/null
    +++ b/lib/model/om/BaseArtworkStatusPeer.php
    @@ -0,0 +1,479 @@
    + array ('Id', 'Name', ),
    +		BasePeer::TYPE_COLNAME => array (ArtworkStatusPeer::ID, ArtworkStatusPeer::NAME, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'name', ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Name' => 1, ),
    +		BasePeer::TYPE_COLNAME => array (ArtworkStatusPeer::ID => 0, ArtworkStatusPeer::NAME => 1, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ArtworkStatusMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ArtworkStatusMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ArtworkStatusPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ArtworkStatusPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ArtworkStatusPeer::ID);
    +
    +		$criteria->addSelectColumn(ArtworkStatusPeer::NAME);
    +
    +	}
    +
    +	const COUNT = 'COUNT(artwork_status.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT artwork_status.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ArtworkStatusPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ArtworkStatusPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ArtworkStatusPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ArtworkStatusPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ArtworkStatusPeer::populateObjects(ArtworkStatusPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArtworkStatusPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ArtworkStatusPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ArtworkStatusPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +  
    +  public static function doSelectWithI18n(Criteria $c, $culture = null, $con = null)
    +  {
    +    if ($culture === null)
    +    {
    +      $culture = sfContext::getInstance()->getUser()->getCulture();
    +    }
    +
    +        if ($c->getDbName() == Propel::getDefaultDB())
    +    {
    +      $c->setDbName(self::DATABASE_NAME);
    +    }
    +
    +    ArtworkStatusPeer::addSelectColumns($c);
    +    $startcol = (ArtworkStatusPeer::NUM_COLUMNS - ArtworkStatusPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +    ArtworkStatusI18nPeer::addSelectColumns($c);
    +
    +    $c->addJoin(ArtworkStatusPeer::ID, ArtworkStatusI18nPeer::ID);
    +    $c->add(ArtworkStatusI18nPeer::CULTURE, $culture);
    +
    +    $rs = BasePeer::doSelect($c, $con);
    +    $results = array();
    +
    +    while($rs->next()) {
    +
    +      $omClass = ArtworkStatusPeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj1 = new $cls();
    +      $obj1->hydrate($rs);
    +      $obj1->setCulture($culture);
    +
    +      $omClass = ArtworkStatusI18nPeer::getOMClass($rs, $startcol);
    +
    +      $cls = Propel::import($omClass);
    +      $obj2 = new $cls();
    +      $obj2->hydrate($rs, $startcol);
    +
    +      $obj1->setArtworkStatusI18nForCulture($obj2, $culture);
    +      $obj2->setArtworkStatus($obj1);
    +
    +      $results[] = $obj1;
    +    }
    +    return $results;
    +  }
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ArtworkStatusPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArtworkStatusPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ArtworkStatusPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseArtworkStatusPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArtworkStatusPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseArtworkStatusPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ArtworkStatusPeer::ID);
    +			$selectCriteria->add(ArtworkStatusPeer::ID, $criteria->remove(ArtworkStatusPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseArtworkStatusPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseArtworkStatusPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += ArtworkStatusPeer::doOnDeleteCascade(new Criteria(), $con);
    +			$affectedRows += BasePeer::doDeleteAll(ArtworkStatusPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ArtworkStatusPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ArtworkStatus) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ArtworkStatusPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			$affectedRows += ArtworkStatusPeer::doOnDeleteCascade($criteria, $con);
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected static function doOnDeleteCascade(Criteria $criteria, Connection $con)
    +	{
    +				$affectedRows = 0;
    +
    +				$objects = ArtworkStatusPeer::doSelect($criteria, $con);
    +		foreach($objects as $obj) {
    +
    +
    +			include_once 'lib/model/ArtworkStatusI18n.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(ArtworkStatusI18nPeer::ID, $obj->getId());
    +			$affectedRows += ArtworkStatusI18nPeer::doDelete($c, $con);
    +		}
    +		return $affectedRows;
    +	}
    +
    +	
    +	public static function doValidate(ArtworkStatus $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ArtworkStatusPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ArtworkStatusPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ArtworkStatusPeer::DATABASE_NAME, ArtworkStatusPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ArtworkStatusPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ArtworkStatusPeer::DATABASE_NAME);
    +
    +		$criteria->add(ArtworkStatusPeer::ID, $pk);
    +
    +
    +		$v = ArtworkStatusPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ArtworkStatusPeer::ID, $pks, Criteria::IN);
    +			$objs = ArtworkStatusPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseArtworkStatusPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ArtworkStatusMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ArtworkStatusMapBuilder');
    +}
    diff --git a/lib/model/om/BaseCatalogue.php b/lib/model/om/BaseCatalogue.php
    new file mode 100644
    index 0000000..1b39a98
    --- /dev/null
    +++ b/lib/model/om/BaseCatalogue.php
    @@ -0,0 +1,711 @@
    +cat_id;
    +	}
    +
    +	
    +	public function getName()
    +	{
    +
    +		return $this->name;
    +	}
    +
    +	
    +	public function getSourceLang()
    +	{
    +
    +		return $this->source_lang;
    +	}
    +
    +	
    +	public function getTargetLang()
    +	{
    +
    +		return $this->target_lang;
    +	}
    +
    +	
    +	public function getDateCreated()
    +	{
    +
    +		return $this->date_created;
    +	}
    +
    +	
    +	public function getDateModified()
    +	{
    +
    +		return $this->date_modified;
    +	}
    +
    +	
    +	public function getAuthor()
    +	{
    +
    +		return $this->author;
    +	}
    +
    +	
    +	public function getDescription()
    +	{
    +
    +		return $this->description;
    +	}
    +
    +	
    +	public function setCatId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->cat_id !== $v) {
    +			$this->cat_id = $v;
    +			$this->modifiedColumns[] = CataloguePeer::CAT_ID;
    +		}
    +
    +	} 
    +	
    +	public function setName($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->name !== $v || $v === '') {
    +			$this->name = $v;
    +			$this->modifiedColumns[] = CataloguePeer::NAME;
    +		}
    +
    +	} 
    +	
    +	public function setSourceLang($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->source_lang !== $v || $v === '') {
    +			$this->source_lang = $v;
    +			$this->modifiedColumns[] = CataloguePeer::SOURCE_LANG;
    +		}
    +
    +	} 
    +	
    +	public function setTargetLang($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->target_lang !== $v || $v === '') {
    +			$this->target_lang = $v;
    +			$this->modifiedColumns[] = CataloguePeer::TARGET_LANG;
    +		}
    +
    +	} 
    +	
    +	public function setDateCreated($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->date_created !== $v || $v === 0) {
    +			$this->date_created = $v;
    +			$this->modifiedColumns[] = CataloguePeer::DATE_CREATED;
    +		}
    +
    +	} 
    +	
    +	public function setDateModified($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->date_modified !== $v || $v === 0) {
    +			$this->date_modified = $v;
    +			$this->modifiedColumns[] = CataloguePeer::DATE_MODIFIED;
    +		}
    +
    +	} 
    +	
    +	public function setAuthor($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->author !== $v || $v === '') {
    +			$this->author = $v;
    +			$this->modifiedColumns[] = CataloguePeer::AUTHOR;
    +		}
    +
    +	} 
    +	
    +	public function setDescription($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->description !== $v || $v === '') {
    +			$this->description = $v;
    +			$this->modifiedColumns[] = CataloguePeer::DESCRIPTION;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->cat_id = $rs->getInt($startcol + 0);
    +
    +			$this->name = $rs->getString($startcol + 1);
    +
    +			$this->source_lang = $rs->getString($startcol + 2);
    +
    +			$this->target_lang = $rs->getString($startcol + 3);
    +
    +			$this->date_created = $rs->getInt($startcol + 4);
    +
    +			$this->date_modified = $rs->getInt($startcol + 5);
    +
    +			$this->author = $rs->getString($startcol + 6);
    +
    +			$this->description = $rs->getString($startcol + 7);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 8; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating Catalogue object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCatalogue:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CataloguePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			CataloguePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCatalogue:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCatalogue:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CataloguePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseCatalogue:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = CataloguePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setCatId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += CataloguePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collTransUnits !== null) {
    +				foreach($this->collTransUnits as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = CataloguePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collTransUnits !== null) {
    +					foreach($this->collTransUnits as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CataloguePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getCatId();
    +				break;
    +			case 1:
    +				return $this->getName();
    +				break;
    +			case 2:
    +				return $this->getSourceLang();
    +				break;
    +			case 3:
    +				return $this->getTargetLang();
    +				break;
    +			case 4:
    +				return $this->getDateCreated();
    +				break;
    +			case 5:
    +				return $this->getDateModified();
    +				break;
    +			case 6:
    +				return $this->getAuthor();
    +				break;
    +			case 7:
    +				return $this->getDescription();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CataloguePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getCatId(),
    +			$keys[1] => $this->getName(),
    +			$keys[2] => $this->getSourceLang(),
    +			$keys[3] => $this->getTargetLang(),
    +			$keys[4] => $this->getDateCreated(),
    +			$keys[5] => $this->getDateModified(),
    +			$keys[6] => $this->getAuthor(),
    +			$keys[7] => $this->getDescription(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CataloguePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setCatId($value);
    +				break;
    +			case 1:
    +				$this->setName($value);
    +				break;
    +			case 2:
    +				$this->setSourceLang($value);
    +				break;
    +			case 3:
    +				$this->setTargetLang($value);
    +				break;
    +			case 4:
    +				$this->setDateCreated($value);
    +				break;
    +			case 5:
    +				$this->setDateModified($value);
    +				break;
    +			case 6:
    +				$this->setAuthor($value);
    +				break;
    +			case 7:
    +				$this->setDescription($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CataloguePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setCatId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setName($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setSourceLang($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setTargetLang($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setDateCreated($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setDateModified($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setAuthor($arr[$keys[6]]);
    +		if (array_key_exists($keys[7], $arr)) $this->setDescription($arr[$keys[7]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(CataloguePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(CataloguePeer::CAT_ID)) $criteria->add(CataloguePeer::CAT_ID, $this->cat_id);
    +		if ($this->isColumnModified(CataloguePeer::NAME)) $criteria->add(CataloguePeer::NAME, $this->name);
    +		if ($this->isColumnModified(CataloguePeer::SOURCE_LANG)) $criteria->add(CataloguePeer::SOURCE_LANG, $this->source_lang);
    +		if ($this->isColumnModified(CataloguePeer::TARGET_LANG)) $criteria->add(CataloguePeer::TARGET_LANG, $this->target_lang);
    +		if ($this->isColumnModified(CataloguePeer::DATE_CREATED)) $criteria->add(CataloguePeer::DATE_CREATED, $this->date_created);
    +		if ($this->isColumnModified(CataloguePeer::DATE_MODIFIED)) $criteria->add(CataloguePeer::DATE_MODIFIED, $this->date_modified);
    +		if ($this->isColumnModified(CataloguePeer::AUTHOR)) $criteria->add(CataloguePeer::AUTHOR, $this->author);
    +		if ($this->isColumnModified(CataloguePeer::DESCRIPTION)) $criteria->add(CataloguePeer::DESCRIPTION, $this->description);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(CataloguePeer::DATABASE_NAME);
    +
    +		$criteria->add(CataloguePeer::CAT_ID, $this->cat_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getCatId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setCatId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setName($this->name);
    +
    +		$copyObj->setSourceLang($this->source_lang);
    +
    +		$copyObj->setTargetLang($this->target_lang);
    +
    +		$copyObj->setDateCreated($this->date_created);
    +
    +		$copyObj->setDateModified($this->date_modified);
    +
    +		$copyObj->setAuthor($this->author);
    +
    +		$copyObj->setDescription($this->description);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getTransUnits() as $relObj) {
    +				$copyObj->addTransUnit($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setCatId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new CataloguePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function initTransUnits()
    +	{
    +		if ($this->collTransUnits === null) {
    +			$this->collTransUnits = array();
    +		}
    +	}
    +
    +	
    +	public function getTransUnits($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseTransUnitPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collTransUnits === null) {
    +			if ($this->isNew()) {
    +			   $this->collTransUnits = array();
    +			} else {
    +
    +				$criteria->add(TransUnitPeer::CAT_ID, $this->getCatId());
    +
    +				TransUnitPeer::addSelectColumns($criteria);
    +				$this->collTransUnits = TransUnitPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(TransUnitPeer::CAT_ID, $this->getCatId());
    +
    +				TransUnitPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastTransUnitCriteria) || !$this->lastTransUnitCriteria->equals($criteria)) {
    +					$this->collTransUnits = TransUnitPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastTransUnitCriteria = $criteria;
    +		return $this->collTransUnits;
    +	}
    +
    +	
    +	public function countTransUnits($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseTransUnitPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(TransUnitPeer::CAT_ID, $this->getCatId());
    +
    +		return TransUnitPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addTransUnit(TransUnit $l)
    +	{
    +		$this->collTransUnits[] = $l;
    +		$l->setCatalogue($this);
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseCatalogue:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseCatalogue::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseCataloguePeer.php b/lib/model/om/BaseCataloguePeer.php
    new file mode 100644
    index 0000000..d7811ba
    --- /dev/null
    +++ b/lib/model/om/BaseCataloguePeer.php
    @@ -0,0 +1,441 @@
    + array ('CatId', 'Name', 'SourceLang', 'TargetLang', 'DateCreated', 'DateModified', 'Author', 'Description', ),
    +		BasePeer::TYPE_COLNAME => array (CataloguePeer::CAT_ID, CataloguePeer::NAME, CataloguePeer::SOURCE_LANG, CataloguePeer::TARGET_LANG, CataloguePeer::DATE_CREATED, CataloguePeer::DATE_MODIFIED, CataloguePeer::AUTHOR, CataloguePeer::DESCRIPTION, ),
    +		BasePeer::TYPE_FIELDNAME => array ('cat_id', 'name', 'source_lang', 'target_lang', 'date_created', 'date_modified', 'author', 'description', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('CatId' => 0, 'Name' => 1, 'SourceLang' => 2, 'TargetLang' => 3, 'DateCreated' => 4, 'DateModified' => 5, 'Author' => 6, 'Description' => 7, ),
    +		BasePeer::TYPE_COLNAME => array (CataloguePeer::CAT_ID => 0, CataloguePeer::NAME => 1, CataloguePeer::SOURCE_LANG => 2, CataloguePeer::TARGET_LANG => 3, CataloguePeer::DATE_CREATED => 4, CataloguePeer::DATE_MODIFIED => 5, CataloguePeer::AUTHOR => 6, CataloguePeer::DESCRIPTION => 7, ),
    +		BasePeer::TYPE_FIELDNAME => array ('cat_id' => 0, 'name' => 1, 'source_lang' => 2, 'target_lang' => 3, 'date_created' => 4, 'date_modified' => 5, 'author' => 6, 'description' => 7, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/CatalogueMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.CatalogueMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = CataloguePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(CataloguePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(CataloguePeer::CAT_ID);
    +
    +		$criteria->addSelectColumn(CataloguePeer::NAME);
    +
    +		$criteria->addSelectColumn(CataloguePeer::SOURCE_LANG);
    +
    +		$criteria->addSelectColumn(CataloguePeer::TARGET_LANG);
    +
    +		$criteria->addSelectColumn(CataloguePeer::DATE_CREATED);
    +
    +		$criteria->addSelectColumn(CataloguePeer::DATE_MODIFIED);
    +
    +		$criteria->addSelectColumn(CataloguePeer::AUTHOR);
    +
    +		$criteria->addSelectColumn(CataloguePeer::DESCRIPTION);
    +
    +	}
    +
    +	const COUNT = 'COUNT(catalogue.CAT_ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT catalogue.CAT_ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CataloguePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CataloguePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = CataloguePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = CataloguePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return CataloguePeer::populateObjects(CataloguePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCataloguePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCataloguePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			CataloguePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = CataloguePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return CataloguePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCataloguePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCataloguePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(CataloguePeer::CAT_ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseCataloguePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCataloguePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCataloguePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCataloguePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(CataloguePeer::CAT_ID);
    +			$selectCriteria->add(CataloguePeer::CAT_ID, $criteria->remove(CataloguePeer::CAT_ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCataloguePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCataloguePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(CataloguePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(CataloguePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof Catalogue) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(CataloguePeer::CAT_ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(Catalogue $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(CataloguePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(CataloguePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(CataloguePeer::DATABASE_NAME, CataloguePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = CataloguePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(CataloguePeer::DATABASE_NAME);
    +
    +		$criteria->add(CataloguePeer::CAT_ID, $pk);
    +
    +
    +		$v = CataloguePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(CataloguePeer::CAT_ID, $pks, Criteria::IN);
    +			$objs = CataloguePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseCataloguePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/CatalogueMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.CatalogueMapBuilder');
    +}
    diff --git a/lib/model/om/BaseCategory.php b/lib/model/om/BaseCategory.php
    new file mode 100644
    index 0000000..78f73ec
    --- /dev/null
    +++ b/lib/model/om/BaseCategory.php
    @@ -0,0 +1,951 @@
    +id;
    +	}
    +
    +	
    +	public function getBasename()
    +	{
    +
    +		return $this->basename;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = CategoryPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setBasename($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->basename !== $v) {
    +			$this->basename = $v;
    +			$this->modifiedColumns[] = CategoryPeer::BASENAME;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->basename = $rs->getString($startcol + 1);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 2; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating Category object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategory:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			CategoryPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCategory:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategory:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseCategory:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = CategoryPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += CategoryPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collCategoryI18ns !== null) {
    +				foreach($this->collCategoryI18ns as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collCategoryArtworks !== null) {
    +				foreach($this->collCategoryArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collCategorySubreaktors !== null) {
    +				foreach($this->collCategorySubreaktors as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleCategorys !== null) {
    +				foreach($this->collArticleCategorys as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = CategoryPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collCategoryI18ns !== null) {
    +					foreach($this->collCategoryI18ns as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collCategoryArtworks !== null) {
    +					foreach($this->collCategoryArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collCategorySubreaktors !== null) {
    +					foreach($this->collCategorySubreaktors as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleCategorys !== null) {
    +					foreach($this->collArticleCategorys as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CategoryPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getBasename();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CategoryPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getBasename(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CategoryPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setBasename($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CategoryPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setBasename($arr[$keys[1]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(CategoryPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(CategoryPeer::ID)) $criteria->add(CategoryPeer::ID, $this->id);
    +		if ($this->isColumnModified(CategoryPeer::BASENAME)) $criteria->add(CategoryPeer::BASENAME, $this->basename);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(CategoryPeer::DATABASE_NAME);
    +
    +		$criteria->add(CategoryPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setBasename($this->basename);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getCategoryI18ns() as $relObj) {
    +				$copyObj->addCategoryI18n($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getCategoryArtworks() as $relObj) {
    +				$copyObj->addCategoryArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getCategorySubreaktors() as $relObj) {
    +				$copyObj->addCategorySubreaktor($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleCategorys() as $relObj) {
    +				$copyObj->addArticleCategory($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new CategoryPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function initCategoryI18ns()
    +	{
    +		if ($this->collCategoryI18ns === null) {
    +			$this->collCategoryI18ns = array();
    +		}
    +	}
    +
    +	
    +	public function getCategoryI18ns($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategoryI18ns === null) {
    +			if ($this->isNew()) {
    +			   $this->collCategoryI18ns = array();
    +			} else {
    +
    +				$criteria->add(CategoryI18nPeer::ID, $this->getId());
    +
    +				CategoryI18nPeer::addSelectColumns($criteria);
    +				$this->collCategoryI18ns = CategoryI18nPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(CategoryI18nPeer::ID, $this->getId());
    +
    +				CategoryI18nPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastCategoryI18nCriteria) || !$this->lastCategoryI18nCriteria->equals($criteria)) {
    +					$this->collCategoryI18ns = CategoryI18nPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastCategoryI18nCriteria = $criteria;
    +		return $this->collCategoryI18ns;
    +	}
    +
    +	
    +	public function countCategoryI18ns($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(CategoryI18nPeer::ID, $this->getId());
    +
    +		return CategoryI18nPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addCategoryI18n(CategoryI18n $l)
    +	{
    +		$this->collCategoryI18ns[] = $l;
    +		$l->setCategory($this);
    +	}
    +
    +	
    +	public function initCategoryArtworks()
    +	{
    +		if ($this->collCategoryArtworks === null) {
    +			$this->collCategoryArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getCategoryArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategoryArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collCategoryArtworks = array();
    +			} else {
    +
    +				$criteria->add(CategoryArtworkPeer::CATEGORY_ID, $this->getId());
    +
    +				CategoryArtworkPeer::addSelectColumns($criteria);
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(CategoryArtworkPeer::CATEGORY_ID, $this->getId());
    +
    +				CategoryArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) {
    +					$this->collCategoryArtworks = CategoryArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastCategoryArtworkCriteria = $criteria;
    +		return $this->collCategoryArtworks;
    +	}
    +
    +	
    +	public function countCategoryArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(CategoryArtworkPeer::CATEGORY_ID, $this->getId());
    +
    +		return CategoryArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addCategoryArtwork(CategoryArtwork $l)
    +	{
    +		$this->collCategoryArtworks[] = $l;
    +		$l->setCategory($this);
    +	}
    +
    +
    +	
    +	public function getCategoryArtworksJoinReaktorArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategoryArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collCategoryArtworks = array();
    +			} else {
    +
    +				$criteria->add(CategoryArtworkPeer::CATEGORY_ID, $this->getId());
    +
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(CategoryArtworkPeer::CATEGORY_ID, $this->getId());
    +
    +			if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) {
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		}
    +		$this->lastCategoryArtworkCriteria = $criteria;
    +
    +		return $this->collCategoryArtworks;
    +	}
    +
    +
    +	
    +	public function getCategoryArtworksJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategoryArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collCategoryArtworks = array();
    +			} else {
    +
    +				$criteria->add(CategoryArtworkPeer::CATEGORY_ID, $this->getId());
    +
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(CategoryArtworkPeer::CATEGORY_ID, $this->getId());
    +
    +			if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) {
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastCategoryArtworkCriteria = $criteria;
    +
    +		return $this->collCategoryArtworks;
    +	}
    +
    +	
    +	public function initCategorySubreaktors()
    +	{
    +		if ($this->collCategorySubreaktors === null) {
    +			$this->collCategorySubreaktors = array();
    +		}
    +	}
    +
    +	
    +	public function getCategorySubreaktors($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategorySubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategorySubreaktors === null) {
    +			if ($this->isNew()) {
    +			   $this->collCategorySubreaktors = array();
    +			} else {
    +
    +				$criteria->add(CategorySubreaktorPeer::CATEGORY_ID, $this->getId());
    +
    +				CategorySubreaktorPeer::addSelectColumns($criteria);
    +				$this->collCategorySubreaktors = CategorySubreaktorPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(CategorySubreaktorPeer::CATEGORY_ID, $this->getId());
    +
    +				CategorySubreaktorPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastCategorySubreaktorCriteria) || !$this->lastCategorySubreaktorCriteria->equals($criteria)) {
    +					$this->collCategorySubreaktors = CategorySubreaktorPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastCategorySubreaktorCriteria = $criteria;
    +		return $this->collCategorySubreaktors;
    +	}
    +
    +	
    +	public function countCategorySubreaktors($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategorySubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(CategorySubreaktorPeer::CATEGORY_ID, $this->getId());
    +
    +		return CategorySubreaktorPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addCategorySubreaktor(CategorySubreaktor $l)
    +	{
    +		$this->collCategorySubreaktors[] = $l;
    +		$l->setCategory($this);
    +	}
    +
    +
    +	
    +	public function getCategorySubreaktorsJoinSubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategorySubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategorySubreaktors === null) {
    +			if ($this->isNew()) {
    +				$this->collCategorySubreaktors = array();
    +			} else {
    +
    +				$criteria->add(CategorySubreaktorPeer::CATEGORY_ID, $this->getId());
    +
    +				$this->collCategorySubreaktors = CategorySubreaktorPeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(CategorySubreaktorPeer::CATEGORY_ID, $this->getId());
    +
    +			if (!isset($this->lastCategorySubreaktorCriteria) || !$this->lastCategorySubreaktorCriteria->equals($criteria)) {
    +				$this->collCategorySubreaktors = CategorySubreaktorPeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		}
    +		$this->lastCategorySubreaktorCriteria = $criteria;
    +
    +		return $this->collCategorySubreaktors;
    +	}
    +
    +	
    +	public function initArticleCategorys()
    +	{
    +		if ($this->collArticleCategorys === null) {
    +			$this->collArticleCategorys = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleCategorys($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleCategoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleCategorys === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleCategorys = array();
    +			} else {
    +
    +				$criteria->add(ArticleCategoryPeer::CATEGORY_ID, $this->getId());
    +
    +				ArticleCategoryPeer::addSelectColumns($criteria);
    +				$this->collArticleCategorys = ArticleCategoryPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleCategoryPeer::CATEGORY_ID, $this->getId());
    +
    +				ArticleCategoryPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleCategoryCriteria) || !$this->lastArticleCategoryCriteria->equals($criteria)) {
    +					$this->collArticleCategorys = ArticleCategoryPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleCategoryCriteria = $criteria;
    +		return $this->collArticleCategorys;
    +	}
    +
    +	
    +	public function countArticleCategorys($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleCategoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleCategoryPeer::CATEGORY_ID, $this->getId());
    +
    +		return ArticleCategoryPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleCategory(ArticleCategory $l)
    +	{
    +		$this->collArticleCategorys[] = $l;
    +		$l->setCategory($this);
    +	}
    +
    +
    +	
    +	public function getArticleCategorysJoinArticle($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleCategoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleCategorys === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleCategorys = array();
    +			} else {
    +
    +				$criteria->add(ArticleCategoryPeer::CATEGORY_ID, $this->getId());
    +
    +				$this->collArticleCategorys = ArticleCategoryPeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleCategoryPeer::CATEGORY_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleCategoryCriteria) || !$this->lastArticleCategoryCriteria->equals($criteria)) {
    +				$this->collArticleCategorys = ArticleCategoryPeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleCategoryCriteria = $criteria;
    +
    +		return $this->collArticleCategorys;
    +	}
    +
    +  public function getCulture()
    +  {
    +    return $this->culture;
    +  }
    +
    +  public function setCulture($culture)
    +  {
    +    $this->culture = $culture;
    +  }
    +
    +  public function getName()
    +  {
    +    $obj = $this->getCurrentCategoryI18n();
    +
    +    return ($obj ? $obj->getName() : null);
    +  }
    +
    +  public function setName($value)
    +  {
    +    $this->getCurrentCategoryI18n()->setName($value);
    +  }
    +
    +  protected $current_i18n = array();
    +
    +  public function getCurrentCategoryI18n()
    +  {
    +    if (!isset($this->current_i18n[$this->culture]))
    +    {
    +      $obj = CategoryI18nPeer::retrieveByPK($this->getId(), $this->culture);
    +      if ($obj)
    +      {
    +        $this->setCategoryI18nForCulture($obj, $this->culture);
    +      }
    +      else
    +      {
    +        $this->setCategoryI18nForCulture(new CategoryI18n(), $this->culture);
    +        $this->current_i18n[$this->culture]->setCulture($this->culture);
    +      }
    +    }
    +
    +    return $this->current_i18n[$this->culture];
    +  }
    +
    +  public function setCategoryI18nForCulture($object, $culture)
    +  {
    +    $this->current_i18n[$culture] = $object;
    +    $this->addCategoryI18n($object);
    +  }
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseCategory:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseCategory::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseCategoryArtwork.php b/lib/model/om/BaseCategoryArtwork.php
    new file mode 100644
    index 0000000..1d69b66
    --- /dev/null
    +++ b/lib/model/om/BaseCategoryArtwork.php
    @@ -0,0 +1,662 @@
    +id;
    +	}
    +
    +	
    +	public function getCategoryId()
    +	{
    +
    +		return $this->category_id;
    +	}
    +
    +	
    +	public function getArtworkId()
    +	{
    +
    +		return $this->artwork_id;
    +	}
    +
    +	
    +	public function getAddedBy()
    +	{
    +
    +		return $this->added_by;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = CategoryArtworkPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setCategoryId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->category_id !== $v) {
    +			$this->category_id = $v;
    +			$this->modifiedColumns[] = CategoryArtworkPeer::CATEGORY_ID;
    +		}
    +
    +		if ($this->aCategory !== null && $this->aCategory->getId() !== $v) {
    +			$this->aCategory = null;
    +		}
    +
    +	} 
    +	
    +	public function setArtworkId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork_id !== $v) {
    +			$this->artwork_id = $v;
    +			$this->modifiedColumns[] = CategoryArtworkPeer::ARTWORK_ID;
    +		}
    +
    +		if ($this->aReaktorArtwork !== null && $this->aReaktorArtwork->getId() !== $v) {
    +			$this->aReaktorArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function setAddedBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->added_by !== $v) {
    +			$this->added_by = $v;
    +			$this->modifiedColumns[] = CategoryArtworkPeer::ADDED_BY;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = CategoryArtworkPeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->category_id = $rs->getInt($startcol + 1);
    +
    +			$this->artwork_id = $rs->getInt($startcol + 2);
    +
    +			$this->added_by = $rs->getInt($startcol + 3);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 4, null);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 5; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating CategoryArtwork object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryArtwork:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			CategoryArtworkPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCategoryArtwork:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryArtwork:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(CategoryArtworkPeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseCategoryArtwork:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aCategory !== null) {
    +				if ($this->aCategory->isModified() || $this->aCategory->getCurrentCategoryI18n()->isModified()) {
    +					$affectedRows += $this->aCategory->save($con);
    +				}
    +				$this->setCategory($this->aCategory);
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if ($this->aReaktorArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtwork->save($con);
    +				}
    +				$this->setReaktorArtwork($this->aReaktorArtwork);
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = CategoryArtworkPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += CategoryArtworkPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aCategory !== null) {
    +				if (!$this->aCategory->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aCategory->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if (!$this->aReaktorArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtwork->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = CategoryArtworkPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CategoryArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getCategoryId();
    +				break;
    +			case 2:
    +				return $this->getArtworkId();
    +				break;
    +			case 3:
    +				return $this->getAddedBy();
    +				break;
    +			case 4:
    +				return $this->getCreatedAt();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CategoryArtworkPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getCategoryId(),
    +			$keys[2] => $this->getArtworkId(),
    +			$keys[3] => $this->getAddedBy(),
    +			$keys[4] => $this->getCreatedAt(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CategoryArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setCategoryId($value);
    +				break;
    +			case 2:
    +				$this->setArtworkId($value);
    +				break;
    +			case 3:
    +				$this->setAddedBy($value);
    +				break;
    +			case 4:
    +				$this->setCreatedAt($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CategoryArtworkPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCategoryId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setArtworkId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setAddedBy($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setCreatedAt($arr[$keys[4]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(CategoryArtworkPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(CategoryArtworkPeer::ID)) $criteria->add(CategoryArtworkPeer::ID, $this->id);
    +		if ($this->isColumnModified(CategoryArtworkPeer::CATEGORY_ID)) $criteria->add(CategoryArtworkPeer::CATEGORY_ID, $this->category_id);
    +		if ($this->isColumnModified(CategoryArtworkPeer::ARTWORK_ID)) $criteria->add(CategoryArtworkPeer::ARTWORK_ID, $this->artwork_id);
    +		if ($this->isColumnModified(CategoryArtworkPeer::ADDED_BY)) $criteria->add(CategoryArtworkPeer::ADDED_BY, $this->added_by);
    +		if ($this->isColumnModified(CategoryArtworkPeer::CREATED_AT)) $criteria->add(CategoryArtworkPeer::CREATED_AT, $this->created_at);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(CategoryArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(CategoryArtworkPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setCategoryId($this->category_id);
    +
    +		$copyObj->setArtworkId($this->artwork_id);
    +
    +		$copyObj->setAddedBy($this->added_by);
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new CategoryArtworkPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setCategory($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setCategoryId(NULL);
    +		} else {
    +			$this->setCategoryId($v->getId());
    +		}
    +
    +
    +		$this->aCategory = $v;
    +	}
    +
    +
    +	
    +	public function getCategory($con = null)
    +	{
    +		if ($this->aCategory === null && ($this->category_id !== null)) {
    +						include_once 'lib/model/om/BaseCategoryPeer.php';
    +
    +			$this->aCategory = CategoryPeer::retrieveByPK($this->category_id, $con);
    +
    +			
    +		}
    +		return $this->aCategory;
    +	}
    +
    +	
    +	public function setReaktorArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArtworkId(NULL);
    +		} else {
    +			$this->setArtworkId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtwork === null && ($this->artwork_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtwork = ReaktorArtworkPeer::retrieveByPK($this->artwork_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtwork;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setAddedBy(NULL);
    +		} else {
    +			$this->setAddedBy($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->added_by !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->added_by, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseCategoryArtwork:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseCategoryArtwork::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseCategoryArtworkPeer.php b/lib/model/om/BaseCategoryArtworkPeer.php
    new file mode 100644
    index 0000000..a37d3db
    --- /dev/null
    +++ b/lib/model/om/BaseCategoryArtworkPeer.php
    @@ -0,0 +1,1139 @@
    + array ('Id', 'CategoryId', 'ArtworkId', 'AddedBy', 'CreatedAt', ),
    +		BasePeer::TYPE_COLNAME => array (CategoryArtworkPeer::ID, CategoryArtworkPeer::CATEGORY_ID, CategoryArtworkPeer::ARTWORK_ID, CategoryArtworkPeer::ADDED_BY, CategoryArtworkPeer::CREATED_AT, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'category_id', 'artwork_id', 'added_by', 'created_at', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'CategoryId' => 1, 'ArtworkId' => 2, 'AddedBy' => 3, 'CreatedAt' => 4, ),
    +		BasePeer::TYPE_COLNAME => array (CategoryArtworkPeer::ID => 0, CategoryArtworkPeer::CATEGORY_ID => 1, CategoryArtworkPeer::ARTWORK_ID => 2, CategoryArtworkPeer::ADDED_BY => 3, CategoryArtworkPeer::CREATED_AT => 4, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'category_id' => 1, 'artwork_id' => 2, 'added_by' => 3, 'created_at' => 4, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/CategoryArtworkMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.CategoryArtworkMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = CategoryArtworkPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(CategoryArtworkPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(CategoryArtworkPeer::ID);
    +
    +		$criteria->addSelectColumn(CategoryArtworkPeer::CATEGORY_ID);
    +
    +		$criteria->addSelectColumn(CategoryArtworkPeer::ARTWORK_ID);
    +
    +		$criteria->addSelectColumn(CategoryArtworkPeer::ADDED_BY);
    +
    +		$criteria->addSelectColumn(CategoryArtworkPeer::CREATED_AT);
    +
    +	}
    +
    +	const COUNT = 'COUNT(category_artwork.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT category_artwork.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = CategoryArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = CategoryArtworkPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return CategoryArtworkPeer::populateObjects(CategoryArtworkPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryArtworkPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryArtworkPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			CategoryArtworkPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = CategoryArtworkPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinCategory(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$rs = CategoryArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = CategoryArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryArtworkPeer::ADDED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = CategoryArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinCategory(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryArtworkPeer::addSelectColumns($c);
    +		$startcol = (CategoryArtworkPeer::NUM_COLUMNS - CategoryArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		CategoryPeer::addSelectColumns($c);
    +
    +		$c->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CategoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addCategoryArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initCategoryArtworks();
    +				$obj2->addCategoryArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryArtworkPeer::addSelectColumns($c);
    +		$startcol = (CategoryArtworkPeer::NUM_COLUMNS - CategoryArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addCategoryArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initCategoryArtworks();
    +				$obj2->addCategoryArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryArtworkPeer::addSelectColumns($c);
    +		$startcol = (CategoryArtworkPeer::NUM_COLUMNS - CategoryArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(CategoryArtworkPeer::ADDED_BY, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addCategoryArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initCategoryArtworks();
    +				$obj2->addCategoryArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$criteria->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(CategoryArtworkPeer::ADDED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = CategoryArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (CategoryArtworkPeer::NUM_COLUMNS - CategoryArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		CategoryPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + CategoryPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$c->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(CategoryArtworkPeer::ADDED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = CategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addCategoryArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initCategoryArtworks();
    +				$obj2->addCategoryArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addCategoryArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initCategoryArtworks();
    +				$obj3->addCategoryArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4 = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addCategoryArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initCategoryArtworks();
    +				$obj4->addCategoryArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptCategory(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(CategoryArtworkPeer::ADDED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = CategoryArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$criteria->addJoin(CategoryArtworkPeer::ADDED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = CategoryArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$criteria->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = CategoryArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptCategory(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (CategoryArtworkPeer::NUM_COLUMNS - CategoryArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(CategoryArtworkPeer::ADDED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addCategoryArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initCategoryArtworks();
    +				$obj2->addCategoryArtwork($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addCategoryArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initCategoryArtworks();
    +				$obj3->addCategoryArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (CategoryArtworkPeer::NUM_COLUMNS - CategoryArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		CategoryPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + CategoryPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$c->addJoin(CategoryArtworkPeer::ADDED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addCategoryArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initCategoryArtworks();
    +				$obj2->addCategoryArtwork($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addCategoryArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initCategoryArtworks();
    +				$obj3->addCategoryArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (CategoryArtworkPeer::NUM_COLUMNS - CategoryArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		CategoryPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + CategoryPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(CategoryArtworkPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$c->addJoin(CategoryArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addCategoryArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initCategoryArtworks();
    +				$obj2->addCategoryArtwork($obj1);
    +			}
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addCategoryArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initCategoryArtworks();
    +				$obj3->addCategoryArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return CategoryArtworkPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryArtworkPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCategoryArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(CategoryArtworkPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseCategoryArtworkPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryArtworkPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryArtworkPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCategoryArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(CategoryArtworkPeer::ID);
    +			$selectCriteria->add(CategoryArtworkPeer::ID, $criteria->remove(CategoryArtworkPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCategoryArtworkPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryArtworkPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(CategoryArtworkPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof CategoryArtwork) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(CategoryArtworkPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(CategoryArtwork $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(CategoryArtworkPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(CategoryArtworkPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(CategoryArtworkPeer::DATABASE_NAME, CategoryArtworkPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = CategoryArtworkPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(CategoryArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(CategoryArtworkPeer::ID, $pk);
    +
    +
    +		$v = CategoryArtworkPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(CategoryArtworkPeer::ID, $pks, Criteria::IN);
    +			$objs = CategoryArtworkPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseCategoryArtworkPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/CategoryArtworkMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.CategoryArtworkMapBuilder');
    +}
    diff --git a/lib/model/om/BaseCategoryI18n.php b/lib/model/om/BaseCategoryI18n.php
    new file mode 100644
    index 0000000..f220d43
    --- /dev/null
    +++ b/lib/model/om/BaseCategoryI18n.php
    @@ -0,0 +1,472 @@
    +name;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function getCulture()
    +	{
    +
    +		return $this->culture;
    +	}
    +
    +	
    +	public function setName($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->name !== $v) {
    +			$this->name = $v;
    +			$this->modifiedColumns[] = CategoryI18nPeer::NAME;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = CategoryI18nPeer::ID;
    +		}
    +
    +		if ($this->aCategory !== null && $this->aCategory->getId() !== $v) {
    +			$this->aCategory = null;
    +		}
    +
    +	} 
    +	
    +	public function setCulture($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->culture !== $v) {
    +			$this->culture = $v;
    +			$this->modifiedColumns[] = CategoryI18nPeer::CULTURE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->name = $rs->getString($startcol + 0);
    +
    +			$this->id = $rs->getInt($startcol + 1);
    +
    +			$this->culture = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating CategoryI18n object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryI18n:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			CategoryI18nPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCategoryI18n:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryI18n:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseCategoryI18n:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aCategory !== null) {
    +				if ($this->aCategory->isModified() || $this->aCategory->getCurrentCategoryI18n()->isModified()) {
    +					$affectedRows += $this->aCategory->save($con);
    +				}
    +				$this->setCategory($this->aCategory);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = CategoryI18nPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += CategoryI18nPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aCategory !== null) {
    +				if (!$this->aCategory->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aCategory->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = CategoryI18nPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CategoryI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getName();
    +				break;
    +			case 1:
    +				return $this->getId();
    +				break;
    +			case 2:
    +				return $this->getCulture();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CategoryI18nPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getName(),
    +			$keys[1] => $this->getId(),
    +			$keys[2] => $this->getCulture(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CategoryI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setName($value);
    +				break;
    +			case 1:
    +				$this->setId($value);
    +				break;
    +			case 2:
    +				$this->setCulture($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CategoryI18nPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setName($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setCulture($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(CategoryI18nPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(CategoryI18nPeer::NAME)) $criteria->add(CategoryI18nPeer::NAME, $this->name);
    +		if ($this->isColumnModified(CategoryI18nPeer::ID)) $criteria->add(CategoryI18nPeer::ID, $this->id);
    +		if ($this->isColumnModified(CategoryI18nPeer::CULTURE)) $criteria->add(CategoryI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(CategoryI18nPeer::DATABASE_NAME);
    +
    +		$criteria->add(CategoryI18nPeer::ID, $this->id);
    +		$criteria->add(CategoryI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getId();
    +
    +		$pks[1] = $this->getCulture();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setId($keys[0]);
    +
    +		$this->setCulture($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setName($this->name);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +		$copyObj->setCulture(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new CategoryI18nPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setCategory($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setId(NULL);
    +		} else {
    +			$this->setId($v->getId());
    +		}
    +
    +
    +		$this->aCategory = $v;
    +	}
    +
    +
    +	
    +	public function getCategory($con = null)
    +	{
    +		if ($this->aCategory === null && ($this->id !== null)) {
    +						include_once 'lib/model/om/BaseCategoryPeer.php';
    +
    +			$this->aCategory = CategoryPeer::retrieveByPK($this->id, $con);
    +
    +			
    +		}
    +		return $this->aCategory;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseCategoryI18n:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseCategoryI18n::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseCategoryI18nPeer.php b/lib/model/om/BaseCategoryI18nPeer.php
    new file mode 100644
    index 0000000..2512189
    --- /dev/null
    +++ b/lib/model/om/BaseCategoryI18nPeer.php
    @@ -0,0 +1,569 @@
    + array ('Name', 'Id', 'Culture', ),
    +		BasePeer::TYPE_COLNAME => array (CategoryI18nPeer::NAME, CategoryI18nPeer::ID, CategoryI18nPeer::CULTURE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('name', 'id', 'culture', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Name' => 0, 'Id' => 1, 'Culture' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (CategoryI18nPeer::NAME => 0, CategoryI18nPeer::ID => 1, CategoryI18nPeer::CULTURE => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('name' => 0, 'id' => 1, 'culture' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/CategoryI18nMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.CategoryI18nMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = CategoryI18nPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(CategoryI18nPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(CategoryI18nPeer::NAME);
    +
    +		$criteria->addSelectColumn(CategoryI18nPeer::ID);
    +
    +		$criteria->addSelectColumn(CategoryI18nPeer::CULTURE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(category_i18n.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT category_i18n.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = CategoryI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = CategoryI18nPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return CategoryI18nPeer::populateObjects(CategoryI18nPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryI18nPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryI18nPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			CategoryI18nPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = CategoryI18nPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinCategory(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryI18nPeer::ID, CategoryPeer::ID);
    +
    +		$rs = CategoryI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinCategory(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryI18nPeer::addSelectColumns($c);
    +		$startcol = (CategoryI18nPeer::NUM_COLUMNS - CategoryI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		CategoryPeer::addSelectColumns($c);
    +
    +		$c->addJoin(CategoryI18nPeer::ID, CategoryPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryI18nPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CategoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addCategoryI18n($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initCategoryI18ns();
    +				$obj2->addCategoryI18n($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategoryI18nPeer::ID, CategoryPeer::ID);
    +
    +		$rs = CategoryI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategoryI18nPeer::addSelectColumns($c);
    +		$startcol2 = (CategoryI18nPeer::NUM_COLUMNS - CategoryI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		CategoryPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + CategoryPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(CategoryI18nPeer::ID, CategoryPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategoryI18nPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = CategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addCategoryI18n($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initCategoryI18ns();
    +				$obj2->addCategoryI18n($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return CategoryI18nPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryI18nPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCategoryI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseCategoryI18nPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryI18nPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryI18nPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCategoryI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(CategoryI18nPeer::ID);
    +			$selectCriteria->add(CategoryI18nPeer::ID, $criteria->remove(CategoryI18nPeer::ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(CategoryI18nPeer::CULTURE);
    +			$selectCriteria->add(CategoryI18nPeer::CULTURE, $criteria->remove(CategoryI18nPeer::CULTURE), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCategoryI18nPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryI18nPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(CategoryI18nPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryI18nPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof CategoryI18n) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(CategoryI18nPeer::ID, $vals[0], Criteria::IN);
    +			$criteria->add(CategoryI18nPeer::CULTURE, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(CategoryI18n $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(CategoryI18nPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(CategoryI18nPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(CategoryI18nPeer::DATABASE_NAME, CategoryI18nPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = CategoryI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $id, $culture, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(CategoryI18nPeer::ID, $id);
    +		$criteria->add(CategoryI18nPeer::CULTURE, $culture);
    +		$v = CategoryI18nPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseCategoryI18nPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/CategoryI18nMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.CategoryI18nMapBuilder');
    +}
    diff --git a/lib/model/om/BaseCategoryPeer.php b/lib/model/om/BaseCategoryPeer.php
    new file mode 100644
    index 0000000..fbeb5a8
    --- /dev/null
    +++ b/lib/model/om/BaseCategoryPeer.php
    @@ -0,0 +1,479 @@
    + array ('Id', 'Basename', ),
    +		BasePeer::TYPE_COLNAME => array (CategoryPeer::ID, CategoryPeer::BASENAME, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'basename', ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Basename' => 1, ),
    +		BasePeer::TYPE_COLNAME => array (CategoryPeer::ID => 0, CategoryPeer::BASENAME => 1, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'basename' => 1, ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/CategoryMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.CategoryMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = CategoryPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(CategoryPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(CategoryPeer::ID);
    +
    +		$criteria->addSelectColumn(CategoryPeer::BASENAME);
    +
    +	}
    +
    +	const COUNT = 'COUNT(category.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT category.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = CategoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = CategoryPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return CategoryPeer::populateObjects(CategoryPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			CategoryPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = CategoryPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +  
    +  public static function doSelectWithI18n(Criteria $c, $culture = null, $con = null)
    +  {
    +    if ($culture === null)
    +    {
    +      $culture = sfContext::getInstance()->getUser()->getCulture();
    +    }
    +
    +        if ($c->getDbName() == Propel::getDefaultDB())
    +    {
    +      $c->setDbName(self::DATABASE_NAME);
    +    }
    +
    +    CategoryPeer::addSelectColumns($c);
    +    $startcol = (CategoryPeer::NUM_COLUMNS - CategoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +    CategoryI18nPeer::addSelectColumns($c);
    +
    +    $c->addJoin(CategoryPeer::ID, CategoryI18nPeer::ID);
    +    $c->add(CategoryI18nPeer::CULTURE, $culture);
    +
    +    $rs = BasePeer::doSelect($c, $con);
    +    $results = array();
    +
    +    while($rs->next()) {
    +
    +      $omClass = CategoryPeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj1 = new $cls();
    +      $obj1->hydrate($rs);
    +      $obj1->setCulture($culture);
    +
    +      $omClass = CategoryI18nPeer::getOMClass($rs, $startcol);
    +
    +      $cls = Propel::import($omClass);
    +      $obj2 = new $cls();
    +      $obj2->hydrate($rs, $startcol);
    +
    +      $obj1->setCategoryI18nForCulture($obj2, $culture);
    +      $obj2->setCategory($obj1);
    +
    +      $results[] = $obj1;
    +    }
    +    return $results;
    +  }
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return CategoryPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCategoryPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(CategoryPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseCategoryPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategoryPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCategoryPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(CategoryPeer::ID);
    +			$selectCriteria->add(CategoryPeer::ID, $criteria->remove(CategoryPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCategoryPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategoryPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += CategoryPeer::doOnDeleteCascade(new Criteria(), $con);
    +			$affectedRows += BasePeer::doDeleteAll(CategoryPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategoryPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof Category) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(CategoryPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			$affectedRows += CategoryPeer::doOnDeleteCascade($criteria, $con);
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected static function doOnDeleteCascade(Criteria $criteria, Connection $con)
    +	{
    +				$affectedRows = 0;
    +
    +				$objects = CategoryPeer::doSelect($criteria, $con);
    +		foreach($objects as $obj) {
    +
    +
    +			include_once 'lib/model/CategoryI18n.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(CategoryI18nPeer::ID, $obj->getId());
    +			$affectedRows += CategoryI18nPeer::doDelete($c, $con);
    +		}
    +		return $affectedRows;
    +	}
    +
    +	
    +	public static function doValidate(Category $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(CategoryPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(CategoryPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(CategoryPeer::DATABASE_NAME, CategoryPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = CategoryPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(CategoryPeer::DATABASE_NAME);
    +
    +		$criteria->add(CategoryPeer::ID, $pk);
    +
    +
    +		$v = CategoryPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(CategoryPeer::ID, $pks, Criteria::IN);
    +			$objs = CategoryPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseCategoryPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/CategoryMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.CategoryMapBuilder');
    +}
    diff --git a/lib/model/om/BaseCategorySubreaktor.php b/lib/model/om/BaseCategorySubreaktor.php
    new file mode 100644
    index 0000000..212444e
    --- /dev/null
    +++ b/lib/model/om/BaseCategorySubreaktor.php
    @@ -0,0 +1,512 @@
    +id;
    +	}
    +
    +	
    +	public function getCategoryId()
    +	{
    +
    +		return $this->category_id;
    +	}
    +
    +	
    +	public function getSubreaktorId()
    +	{
    +
    +		return $this->subreaktor_id;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = CategorySubreaktorPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setCategoryId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->category_id !== $v) {
    +			$this->category_id = $v;
    +			$this->modifiedColumns[] = CategorySubreaktorPeer::CATEGORY_ID;
    +		}
    +
    +		if ($this->aCategory !== null && $this->aCategory->getId() !== $v) {
    +			$this->aCategory = null;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktorId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor_id !== $v) {
    +			$this->subreaktor_id = $v;
    +			$this->modifiedColumns[] = CategorySubreaktorPeer::SUBREAKTOR_ID;
    +		}
    +
    +		if ($this->aSubreaktor !== null && $this->aSubreaktor->getId() !== $v) {
    +			$this->aSubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->category_id = $rs->getInt($startcol + 1);
    +
    +			$this->subreaktor_id = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating CategorySubreaktor object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktor:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategorySubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			CategorySubreaktorPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktor:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktor:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategorySubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktor:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aCategory !== null) {
    +				if ($this->aCategory->isModified() || $this->aCategory->getCurrentCategoryI18n()->isModified()) {
    +					$affectedRows += $this->aCategory->save($con);
    +				}
    +				$this->setCategory($this->aCategory);
    +			}
    +
    +			if ($this->aSubreaktor !== null) {
    +				if ($this->aSubreaktor->isModified() || $this->aSubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktor->save($con);
    +				}
    +				$this->setSubreaktor($this->aSubreaktor);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = CategorySubreaktorPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += CategorySubreaktorPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aCategory !== null) {
    +				if (!$this->aCategory->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aCategory->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aSubreaktor !== null) {
    +				if (!$this->aSubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = CategorySubreaktorPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CategorySubreaktorPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getCategoryId();
    +				break;
    +			case 2:
    +				return $this->getSubreaktorId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CategorySubreaktorPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getCategoryId(),
    +			$keys[2] => $this->getSubreaktorId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = CategorySubreaktorPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setCategoryId($value);
    +				break;
    +			case 2:
    +				$this->setSubreaktorId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = CategorySubreaktorPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCategoryId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setSubreaktorId($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(CategorySubreaktorPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(CategorySubreaktorPeer::ID)) $criteria->add(CategorySubreaktorPeer::ID, $this->id);
    +		if ($this->isColumnModified(CategorySubreaktorPeer::CATEGORY_ID)) $criteria->add(CategorySubreaktorPeer::CATEGORY_ID, $this->category_id);
    +		if ($this->isColumnModified(CategorySubreaktorPeer::SUBREAKTOR_ID)) $criteria->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $this->subreaktor_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(CategorySubreaktorPeer::DATABASE_NAME);
    +
    +		$criteria->add(CategorySubreaktorPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setCategoryId($this->category_id);
    +
    +		$copyObj->setSubreaktorId($this->subreaktor_id);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new CategorySubreaktorPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setCategory($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setCategoryId(NULL);
    +		} else {
    +			$this->setCategoryId($v->getId());
    +		}
    +
    +
    +		$this->aCategory = $v;
    +	}
    +
    +
    +	
    +	public function getCategory($con = null)
    +	{
    +		if ($this->aCategory === null && ($this->category_id !== null)) {
    +						include_once 'lib/model/om/BaseCategoryPeer.php';
    +
    +			$this->aCategory = CategoryPeer::retrieveByPK($this->category_id, $con);
    +
    +			
    +		}
    +		return $this->aCategory;
    +	}
    +
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSubreaktorId(NULL);
    +		} else {
    +			$this->setSubreaktorId($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktor === null && ($this->subreaktor_id !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktor = SubreaktorPeer::retrieveByPK($this->subreaktor_id, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktor;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseCategorySubreaktor:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseCategorySubreaktor::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseCategorySubreaktorPeer.php b/lib/model/om/BaseCategorySubreaktorPeer.php
    new file mode 100644
    index 0000000..1435604
    --- /dev/null
    +++ b/lib/model/om/BaseCategorySubreaktorPeer.php
    @@ -0,0 +1,852 @@
    + array ('Id', 'CategoryId', 'SubreaktorId', ),
    +		BasePeer::TYPE_COLNAME => array (CategorySubreaktorPeer::ID, CategorySubreaktorPeer::CATEGORY_ID, CategorySubreaktorPeer::SUBREAKTOR_ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'category_id', 'subreaktor_id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'CategoryId' => 1, 'SubreaktorId' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (CategorySubreaktorPeer::ID => 0, CategorySubreaktorPeer::CATEGORY_ID => 1, CategorySubreaktorPeer::SUBREAKTOR_ID => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'category_id' => 1, 'subreaktor_id' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/CategorySubreaktorMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.CategorySubreaktorMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = CategorySubreaktorPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(CategorySubreaktorPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(CategorySubreaktorPeer::ID);
    +
    +		$criteria->addSelectColumn(CategorySubreaktorPeer::CATEGORY_ID);
    +
    +		$criteria->addSelectColumn(CategorySubreaktorPeer::SUBREAKTOR_ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(category_subreaktor.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT category_subreaktor.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = CategorySubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = CategorySubreaktorPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return CategorySubreaktorPeer::populateObjects(CategorySubreaktorPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktorPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategorySubreaktorPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			CategorySubreaktorPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = CategorySubreaktorPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinCategory(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategorySubreaktorPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$rs = CategorySubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategorySubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = CategorySubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinCategory(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategorySubreaktorPeer::addSelectColumns($c);
    +		$startcol = (CategorySubreaktorPeer::NUM_COLUMNS - CategorySubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		CategoryPeer::addSelectColumns($c);
    +
    +		$c->addJoin(CategorySubreaktorPeer::CATEGORY_ID, CategoryPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategorySubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CategoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addCategorySubreaktor($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initCategorySubreaktors();
    +				$obj2->addCategorySubreaktor($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategorySubreaktorPeer::addSelectColumns($c);
    +		$startcol = (CategorySubreaktorPeer::NUM_COLUMNS - CategorySubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(CategorySubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategorySubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addCategorySubreaktor($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initCategorySubreaktors();
    +				$obj2->addCategorySubreaktor($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategorySubreaktorPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$criteria->addJoin(CategorySubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = CategorySubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategorySubreaktorPeer::addSelectColumns($c);
    +		$startcol2 = (CategorySubreaktorPeer::NUM_COLUMNS - CategorySubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		CategoryPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + CategoryPeer::NUM_COLUMNS;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(CategorySubreaktorPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$c->addJoin(CategorySubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategorySubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = CategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addCategorySubreaktor($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initCategorySubreaktors();
    +				$obj2->addCategorySubreaktor($obj1);
    +			}
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getSubreaktor(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addCategorySubreaktor($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initCategorySubreaktors();
    +				$obj3->addCategorySubreaktor($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptCategory(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategorySubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = CategorySubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(CategorySubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(CategorySubreaktorPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +		$rs = CategorySubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptCategory(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategorySubreaktorPeer::addSelectColumns($c);
    +		$startcol2 = (CategorySubreaktorPeer::NUM_COLUMNS - CategorySubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(CategorySubreaktorPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategorySubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addCategorySubreaktor($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initCategorySubreaktors();
    +				$obj2->addCategorySubreaktor($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		CategorySubreaktorPeer::addSelectColumns($c);
    +		$startcol2 = (CategorySubreaktorPeer::NUM_COLUMNS - CategorySubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		CategoryPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + CategoryPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(CategorySubreaktorPeer::CATEGORY_ID, CategoryPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = CategorySubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CategoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getCategory(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addCategorySubreaktor($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initCategorySubreaktors();
    +				$obj2->addCategorySubreaktor($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return CategorySubreaktorPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktorPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCategorySubreaktorPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(CategorySubreaktorPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktorPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategorySubreaktorPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktorPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseCategorySubreaktorPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(CategorySubreaktorPeer::ID);
    +			$selectCriteria->add(CategorySubreaktorPeer::ID, $criteria->remove(CategorySubreaktorPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseCategorySubreaktorPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseCategorySubreaktorPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(CategorySubreaktorPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(CategorySubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof CategorySubreaktor) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(CategorySubreaktorPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(CategorySubreaktor $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(CategorySubreaktorPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(CategorySubreaktorPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(CategorySubreaktorPeer::DATABASE_NAME, CategorySubreaktorPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = CategorySubreaktorPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(CategorySubreaktorPeer::DATABASE_NAME);
    +
    +		$criteria->add(CategorySubreaktorPeer::ID, $pk);
    +
    +
    +		$v = CategorySubreaktorPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(CategorySubreaktorPeer::ID, $pks, Criteria::IN);
    +			$objs = CategorySubreaktorPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseCategorySubreaktorPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/CategorySubreaktorMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.CategorySubreaktorMapBuilder');
    +}
    diff --git a/lib/model/om/BaseFavourite.php b/lib/model/om/BaseFavourite.php
    new file mode 100644
    index 0000000..77818e3
    --- /dev/null
    +++ b/lib/model/om/BaseFavourite.php
    @@ -0,0 +1,730 @@
    +id;
    +	}
    +
    +	
    +	public function getUserId()
    +	{
    +
    +		return $this->user_id;
    +	}
    +
    +	
    +	public function getArtworkId()
    +	{
    +
    +		return $this->artwork_id;
    +	}
    +
    +	
    +	public function getArticleId()
    +	{
    +
    +		return $this->article_id;
    +	}
    +
    +	
    +	public function getFriendId()
    +	{
    +
    +		return $this->friend_id;
    +	}
    +
    +	
    +	public function getFavType()
    +	{
    +
    +		return $this->fav_type;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = FavouritePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->user_id !== $v) {
    +			$this->user_id = $v;
    +			$this->modifiedColumns[] = FavouritePeer::USER_ID;
    +		}
    +
    +		if ($this->asfGuardUserRelatedByUserId !== null && $this->asfGuardUserRelatedByUserId->getId() !== $v) {
    +			$this->asfGuardUserRelatedByUserId = null;
    +		}
    +
    +	} 
    +	
    +	public function setArtworkId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork_id !== $v) {
    +			$this->artwork_id = $v;
    +			$this->modifiedColumns[] = FavouritePeer::ARTWORK_ID;
    +		}
    +
    +		if ($this->aReaktorArtwork !== null && $this->aReaktorArtwork->getId() !== $v) {
    +			$this->aReaktorArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function setArticleId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->article_id !== $v) {
    +			$this->article_id = $v;
    +			$this->modifiedColumns[] = FavouritePeer::ARTICLE_ID;
    +		}
    +
    +		if ($this->aArticle !== null && $this->aArticle->getId() !== $v) {
    +			$this->aArticle = null;
    +		}
    +
    +	} 
    +	
    +	public function setFriendId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->friend_id !== $v) {
    +			$this->friend_id = $v;
    +			$this->modifiedColumns[] = FavouritePeer::FRIEND_ID;
    +		}
    +
    +		if ($this->asfGuardUserRelatedByFriendId !== null && $this->asfGuardUserRelatedByFriendId->getId() !== $v) {
    +			$this->asfGuardUserRelatedByFriendId = null;
    +		}
    +
    +	} 
    +	
    +	public function setFavType($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->fav_type !== $v) {
    +			$this->fav_type = $v;
    +			$this->modifiedColumns[] = FavouritePeer::FAV_TYPE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->user_id = $rs->getInt($startcol + 1);
    +
    +			$this->artwork_id = $rs->getInt($startcol + 2);
    +
    +			$this->article_id = $rs->getInt($startcol + 3);
    +
    +			$this->friend_id = $rs->getInt($startcol + 4);
    +
    +			$this->fav_type = $rs->getString($startcol + 5);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 6; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating Favourite object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFavourite:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(FavouritePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			FavouritePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseFavourite:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFavourite:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(FavouritePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseFavourite:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUserRelatedByUserId !== null) {
    +				if ($this->asfGuardUserRelatedByUserId->isModified()) {
    +					$affectedRows += $this->asfGuardUserRelatedByUserId->save($con);
    +				}
    +				$this->setsfGuardUserRelatedByUserId($this->asfGuardUserRelatedByUserId);
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if ($this->aReaktorArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtwork->save($con);
    +				}
    +				$this->setReaktorArtwork($this->aReaktorArtwork);
    +			}
    +
    +			if ($this->aArticle !== null) {
    +				if ($this->aArticle->isModified() || $this->aArticle->getCurrentArticleI18n()->isModified()) {
    +					$affectedRows += $this->aArticle->save($con);
    +				}
    +				$this->setArticle($this->aArticle);
    +			}
    +
    +			if ($this->asfGuardUserRelatedByFriendId !== null) {
    +				if ($this->asfGuardUserRelatedByFriendId->isModified()) {
    +					$affectedRows += $this->asfGuardUserRelatedByFriendId->save($con);
    +				}
    +				$this->setsfGuardUserRelatedByFriendId($this->asfGuardUserRelatedByFriendId);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = FavouritePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += FavouritePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUserRelatedByUserId !== null) {
    +				if (!$this->asfGuardUserRelatedByUserId->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUserRelatedByUserId->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if (!$this->aReaktorArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtwork->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aArticle !== null) {
    +				if (!$this->aArticle->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArticle->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUserRelatedByFriendId !== null) {
    +				if (!$this->asfGuardUserRelatedByFriendId->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUserRelatedByFriendId->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = FavouritePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = FavouritePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getUserId();
    +				break;
    +			case 2:
    +				return $this->getArtworkId();
    +				break;
    +			case 3:
    +				return $this->getArticleId();
    +				break;
    +			case 4:
    +				return $this->getFriendId();
    +				break;
    +			case 5:
    +				return $this->getFavType();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = FavouritePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getUserId(),
    +			$keys[2] => $this->getArtworkId(),
    +			$keys[3] => $this->getArticleId(),
    +			$keys[4] => $this->getFriendId(),
    +			$keys[5] => $this->getFavType(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = FavouritePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setUserId($value);
    +				break;
    +			case 2:
    +				$this->setArtworkId($value);
    +				break;
    +			case 3:
    +				$this->setArticleId($value);
    +				break;
    +			case 4:
    +				$this->setFriendId($value);
    +				break;
    +			case 5:
    +				$this->setFavType($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = FavouritePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setUserId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setArtworkId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setArticleId($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setFriendId($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setFavType($arr[$keys[5]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(FavouritePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(FavouritePeer::ID)) $criteria->add(FavouritePeer::ID, $this->id);
    +		if ($this->isColumnModified(FavouritePeer::USER_ID)) $criteria->add(FavouritePeer::USER_ID, $this->user_id);
    +		if ($this->isColumnModified(FavouritePeer::ARTWORK_ID)) $criteria->add(FavouritePeer::ARTWORK_ID, $this->artwork_id);
    +		if ($this->isColumnModified(FavouritePeer::ARTICLE_ID)) $criteria->add(FavouritePeer::ARTICLE_ID, $this->article_id);
    +		if ($this->isColumnModified(FavouritePeer::FRIEND_ID)) $criteria->add(FavouritePeer::FRIEND_ID, $this->friend_id);
    +		if ($this->isColumnModified(FavouritePeer::FAV_TYPE)) $criteria->add(FavouritePeer::FAV_TYPE, $this->fav_type);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(FavouritePeer::DATABASE_NAME);
    +
    +		$criteria->add(FavouritePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setUserId($this->user_id);
    +
    +		$copyObj->setArtworkId($this->artwork_id);
    +
    +		$copyObj->setArticleId($this->article_id);
    +
    +		$copyObj->setFriendId($this->friend_id);
    +
    +		$copyObj->setFavType($this->fav_type);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new FavouritePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUserRelatedByUserId($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUserId(NULL);
    +		} else {
    +			$this->setUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUserRelatedByUserId = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUserRelatedByUserId($con = null)
    +	{
    +		if ($this->asfGuardUserRelatedByUserId === null && ($this->user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUserRelatedByUserId = sfGuardUserPeer::retrieveByPK($this->user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUserRelatedByUserId;
    +	}
    +
    +	
    +	public function setReaktorArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArtworkId(NULL);
    +		} else {
    +			$this->setArtworkId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtwork === null && ($this->artwork_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtwork = ReaktorArtworkPeer::retrieveByPK($this->artwork_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtwork;
    +	}
    +
    +	
    +	public function setArticle($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArticleId(NULL);
    +		} else {
    +			$this->setArticleId($v->getId());
    +		}
    +
    +
    +		$this->aArticle = $v;
    +	}
    +
    +
    +	
    +	public function getArticle($con = null)
    +	{
    +		if ($this->aArticle === null && ($this->article_id !== null)) {
    +						include_once 'lib/model/om/BaseArticlePeer.php';
    +
    +			$this->aArticle = ArticlePeer::retrieveByPK($this->article_id, $con);
    +
    +			
    +		}
    +		return $this->aArticle;
    +	}
    +
    +	
    +	public function setsfGuardUserRelatedByFriendId($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFriendId(NULL);
    +		} else {
    +			$this->setFriendId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUserRelatedByFriendId = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUserRelatedByFriendId($con = null)
    +	{
    +		if ($this->asfGuardUserRelatedByFriendId === null && ($this->friend_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUserRelatedByFriendId = sfGuardUserPeer::retrieveByPK($this->friend_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUserRelatedByFriendId;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseFavourite:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseFavourite::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseFavouritePeer.php b/lib/model/om/BaseFavouritePeer.php
    new file mode 100644
    index 0000000..86cbf6e
    --- /dev/null
    +++ b/lib/model/om/BaseFavouritePeer.php
    @@ -0,0 +1,1421 @@
    + array ('Id', 'UserId', 'ArtworkId', 'ArticleId', 'FriendId', 'FavType', ),
    +		BasePeer::TYPE_COLNAME => array (FavouritePeer::ID, FavouritePeer::USER_ID, FavouritePeer::ARTWORK_ID, FavouritePeer::ARTICLE_ID, FavouritePeer::FRIEND_ID, FavouritePeer::FAV_TYPE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'user_id', 'artwork_id', 'article_id', 'friend_id', 'fav_type', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'UserId' => 1, 'ArtworkId' => 2, 'ArticleId' => 3, 'FriendId' => 4, 'FavType' => 5, ),
    +		BasePeer::TYPE_COLNAME => array (FavouritePeer::ID => 0, FavouritePeer::USER_ID => 1, FavouritePeer::ARTWORK_ID => 2, FavouritePeer::ARTICLE_ID => 3, FavouritePeer::FRIEND_ID => 4, FavouritePeer::FAV_TYPE => 5, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'user_id' => 1, 'artwork_id' => 2, 'article_id' => 3, 'friend_id' => 4, 'fav_type' => 5, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/FavouriteMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.FavouriteMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = FavouritePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(FavouritePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(FavouritePeer::ID);
    +
    +		$criteria->addSelectColumn(FavouritePeer::USER_ID);
    +
    +		$criteria->addSelectColumn(FavouritePeer::ARTWORK_ID);
    +
    +		$criteria->addSelectColumn(FavouritePeer::ARTICLE_ID);
    +
    +		$criteria->addSelectColumn(FavouritePeer::FRIEND_ID);
    +
    +		$criteria->addSelectColumn(FavouritePeer::FAV_TYPE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(favourite.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT favourite.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = FavouritePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return FavouritePeer::populateObjects(FavouritePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFavouritePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFavouritePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			FavouritePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = FavouritePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUserRelatedByUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUserRelatedByFriendId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::FRIEND_ID, sfGuardUserPeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUserRelatedByUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(FavouritePeer::USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addFavouriteRelatedByUserId($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initFavouritesRelatedByUserId();
    +				$obj2->addFavouriteRelatedByUserId($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addFavourite($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initFavourites();
    +				$obj2->addFavourite($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArticlePeer::addSelectColumns($c);
    +
    +		$c->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArticle(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addFavourite($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initFavourites();
    +				$obj2->addFavourite($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUserRelatedByFriendId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(FavouritePeer::FRIEND_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByFriendId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addFavouriteRelatedByFriendId($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initFavouritesRelatedByFriendId();
    +				$obj2->addFavouriteRelatedByFriendId($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::FRIEND_ID, sfGuardUserPeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol2 = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + ArticlePeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol6 = $startcol5 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(FavouritePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$c->addJoin(FavouritePeer::FRIEND_ID, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addFavouriteRelatedByUserId($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initFavouritesRelatedByUserId();
    +				$obj2->addFavouriteRelatedByUserId($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addFavourite($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initFavourites();
    +				$obj3->addFavourite($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4 = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getArticle(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addFavourite($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initFavourites();
    +				$obj4->addFavourite($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj5 = new $cls();
    +			$obj5->hydrate($rs, $startcol5);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj5 = $temp_obj1->getsfGuardUserRelatedByFriendId(); 				if ($temp_obj5->getPrimaryKey() === $obj5->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj5->addFavouriteRelatedByFriendId($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj5->initFavouritesRelatedByFriendId();
    +				$obj5->addFavouriteRelatedByFriendId($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUserRelatedByUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::FRIEND_ID, sfGuardUserPeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArticle(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::FRIEND_ID, sfGuardUserPeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUserRelatedByFriendId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FavouritePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$rs = FavouritePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUserRelatedByUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol2 = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArticlePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addFavourite($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initFavourites();
    +				$obj2->addFavourite($obj1);
    +			}
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArticle(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addFavourite($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initFavourites();
    +				$obj3->addFavourite($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol2 = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArticlePeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(FavouritePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +		$c->addJoin(FavouritePeer::FRIEND_ID, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addFavouriteRelatedByUserId($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initFavouritesRelatedByUserId();
    +				$obj2->addFavouriteRelatedByUserId($obj1);
    +			}
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArticle(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addFavourite($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initFavourites();
    +				$obj3->addFavourite($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUserRelatedByFriendId(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addFavouriteRelatedByFriendId($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initFavouritesRelatedByFriendId();
    +				$obj4->addFavouriteRelatedByFriendId($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArticle(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol2 = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(FavouritePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(FavouritePeer::FRIEND_ID, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addFavouriteRelatedByUserId($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initFavouritesRelatedByUserId();
    +				$obj2->addFavouriteRelatedByUserId($obj1);
    +			}
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addFavourite($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initFavourites();
    +				$obj3->addFavourite($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUserRelatedByFriendId(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addFavouriteRelatedByFriendId($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initFavouritesRelatedByFriendId();
    +				$obj4->addFavouriteRelatedByFriendId($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUserRelatedByFriendId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FavouritePeer::addSelectColumns($c);
    +		$startcol2 = (FavouritePeer::NUM_COLUMNS - FavouritePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ArticlePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArticlePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(FavouritePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(FavouritePeer::ARTICLE_ID, ArticlePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FavouritePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addFavourite($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initFavourites();
    +				$obj2->addFavourite($obj1);
    +			}
    +
    +			$omClass = ArticlePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArticle(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addFavourite($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initFavourites();
    +				$obj3->addFavourite($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return FavouritePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFavouritePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseFavouritePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(FavouritePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseFavouritePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFavouritePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFavouritePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseFavouritePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(FavouritePeer::ID);
    +			$selectCriteria->add(FavouritePeer::ID, $criteria->remove(FavouritePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseFavouritePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFavouritePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(FavouritePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(FavouritePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof Favourite) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(FavouritePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(Favourite $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(FavouritePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(FavouritePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(FavouritePeer::DATABASE_NAME, FavouritePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = FavouritePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(FavouritePeer::DATABASE_NAME);
    +
    +		$criteria->add(FavouritePeer::ID, $pk);
    +
    +
    +		$v = FavouritePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(FavouritePeer::ID, $pks, Criteria::IN);
    +			$objs = FavouritePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseFavouritePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/FavouriteMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.FavouriteMapBuilder');
    +}
    diff --git a/lib/model/om/BaseFileMetadata.php b/lib/model/om/BaseFileMetadata.php
    new file mode 100644
    index 0000000..611d356
    --- /dev/null
    +++ b/lib/model/om/BaseFileMetadata.php
    @@ -0,0 +1,543 @@
    +id;
    +	}
    +
    +	
    +	public function getFile()
    +	{
    +
    +		return $this->file;
    +	}
    +
    +	
    +	public function getMetaElement()
    +	{
    +
    +		return $this->meta_element;
    +	}
    +
    +	
    +	public function getMetaQualifier()
    +	{
    +
    +		return $this->meta_qualifier;
    +	}
    +
    +	
    +	public function getMetaValue()
    +	{
    +
    +		return $this->meta_value;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = FileMetadataPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setFile($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->file !== $v) {
    +			$this->file = $v;
    +			$this->modifiedColumns[] = FileMetadataPeer::FILE;
    +		}
    +
    +		if ($this->aReaktorFile !== null && $this->aReaktorFile->getId() !== $v) {
    +			$this->aReaktorFile = null;
    +		}
    +
    +	} 
    +	
    +	public function setMetaElement($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->meta_element !== $v) {
    +			$this->meta_element = $v;
    +			$this->modifiedColumns[] = FileMetadataPeer::META_ELEMENT;
    +		}
    +
    +	} 
    +	
    +	public function setMetaQualifier($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->meta_qualifier !== $v) {
    +			$this->meta_qualifier = $v;
    +			$this->modifiedColumns[] = FileMetadataPeer::META_QUALIFIER;
    +		}
    +
    +	} 
    +	
    +	public function setMetaValue($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->meta_value !== $v) {
    +			$this->meta_value = $v;
    +			$this->modifiedColumns[] = FileMetadataPeer::META_VALUE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->file = $rs->getInt($startcol + 1);
    +
    +			$this->meta_element = $rs->getString($startcol + 2);
    +
    +			$this->meta_qualifier = $rs->getString($startcol + 3);
    +
    +			$this->meta_value = $rs->getString($startcol + 4);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 5; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating FileMetadata object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMetadata:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(FileMetadataPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			FileMetadataPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseFileMetadata:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMetadata:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(FileMetadataPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseFileMetadata:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aReaktorFile !== null) {
    +				if ($this->aReaktorFile->isModified()) {
    +					$affectedRows += $this->aReaktorFile->save($con);
    +				}
    +				$this->setReaktorFile($this->aReaktorFile);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = FileMetadataPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += FileMetadataPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aReaktorFile !== null) {
    +				if (!$this->aReaktorFile->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorFile->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = FileMetadataPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = FileMetadataPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getFile();
    +				break;
    +			case 2:
    +				return $this->getMetaElement();
    +				break;
    +			case 3:
    +				return $this->getMetaQualifier();
    +				break;
    +			case 4:
    +				return $this->getMetaValue();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = FileMetadataPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getFile(),
    +			$keys[2] => $this->getMetaElement(),
    +			$keys[3] => $this->getMetaQualifier(),
    +			$keys[4] => $this->getMetaValue(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = FileMetadataPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setFile($value);
    +				break;
    +			case 2:
    +				$this->setMetaElement($value);
    +				break;
    +			case 3:
    +				$this->setMetaQualifier($value);
    +				break;
    +			case 4:
    +				$this->setMetaValue($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = FileMetadataPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setFile($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setMetaElement($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setMetaQualifier($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setMetaValue($arr[$keys[4]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(FileMetadataPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(FileMetadataPeer::ID)) $criteria->add(FileMetadataPeer::ID, $this->id);
    +		if ($this->isColumnModified(FileMetadataPeer::FILE)) $criteria->add(FileMetadataPeer::FILE, $this->file);
    +		if ($this->isColumnModified(FileMetadataPeer::META_ELEMENT)) $criteria->add(FileMetadataPeer::META_ELEMENT, $this->meta_element);
    +		if ($this->isColumnModified(FileMetadataPeer::META_QUALIFIER)) $criteria->add(FileMetadataPeer::META_QUALIFIER, $this->meta_qualifier);
    +		if ($this->isColumnModified(FileMetadataPeer::META_VALUE)) $criteria->add(FileMetadataPeer::META_VALUE, $this->meta_value);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(FileMetadataPeer::DATABASE_NAME);
    +
    +		$criteria->add(FileMetadataPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setFile($this->file);
    +
    +		$copyObj->setMetaElement($this->meta_element);
    +
    +		$copyObj->setMetaQualifier($this->meta_qualifier);
    +
    +		$copyObj->setMetaValue($this->meta_value);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new FileMetadataPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setReaktorFile($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFile(NULL);
    +		} else {
    +			$this->setFile($v->getId());
    +		}
    +
    +
    +		$this->aReaktorFile = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorFile($con = null)
    +	{
    +		if ($this->aReaktorFile === null && ($this->file !== null)) {
    +						include_once 'lib/model/om/BaseReaktorFilePeer.php';
    +
    +			$this->aReaktorFile = ReaktorFilePeer::retrieveByPK($this->file, $con);
    +
    +			
    +		}
    +		return $this->aReaktorFile;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseFileMetadata:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseFileMetadata::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseFileMetadataPeer.php b/lib/model/om/BaseFileMetadataPeer.php
    new file mode 100644
    index 0000000..76b28e0
    --- /dev/null
    +++ b/lib/model/om/BaseFileMetadataPeer.php
    @@ -0,0 +1,587 @@
    + array ('Id', 'File', 'MetaElement', 'MetaQualifier', 'MetaValue', ),
    +		BasePeer::TYPE_COLNAME => array (FileMetadataPeer::ID, FileMetadataPeer::FILE, FileMetadataPeer::META_ELEMENT, FileMetadataPeer::META_QUALIFIER, FileMetadataPeer::META_VALUE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'file', 'meta_element', 'meta_qualifier', 'meta_value', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'File' => 1, 'MetaElement' => 2, 'MetaQualifier' => 3, 'MetaValue' => 4, ),
    +		BasePeer::TYPE_COLNAME => array (FileMetadataPeer::ID => 0, FileMetadataPeer::FILE => 1, FileMetadataPeer::META_ELEMENT => 2, FileMetadataPeer::META_QUALIFIER => 3, FileMetadataPeer::META_VALUE => 4, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'file' => 1, 'meta_element' => 2, 'meta_qualifier' => 3, 'meta_value' => 4, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/FileMetadataMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.FileMetadataMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = FileMetadataPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(FileMetadataPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(FileMetadataPeer::ID);
    +
    +		$criteria->addSelectColumn(FileMetadataPeer::FILE);
    +
    +		$criteria->addSelectColumn(FileMetadataPeer::META_ELEMENT);
    +
    +		$criteria->addSelectColumn(FileMetadataPeer::META_QUALIFIER);
    +
    +		$criteria->addSelectColumn(FileMetadataPeer::META_VALUE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(file_metadata.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT file_metadata.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FileMetadataPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FileMetadataPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = FileMetadataPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = FileMetadataPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return FileMetadataPeer::populateObjects(FileMetadataPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMetadataPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFileMetadataPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			FileMetadataPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = FileMetadataPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinReaktorFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FileMetadataPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FileMetadataPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FileMetadataPeer::FILE, ReaktorFilePeer::ID);
    +
    +		$rs = FileMetadataPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FileMetadataPeer::addSelectColumns($c);
    +		$startcol = (FileMetadataPeer::NUM_COLUMNS - FileMetadataPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorFilePeer::addSelectColumns($c);
    +
    +		$c->addJoin(FileMetadataPeer::FILE, ReaktorFilePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FileMetadataPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addFileMetadata($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initFileMetadatas();
    +				$obj2->addFileMetadata($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FileMetadataPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FileMetadataPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(FileMetadataPeer::FILE, ReaktorFilePeer::ID);
    +
    +		$rs = FileMetadataPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		FileMetadataPeer::addSelectColumns($c);
    +		$startcol2 = (FileMetadataPeer::NUM_COLUMNS - FileMetadataPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(FileMetadataPeer::FILE, ReaktorFilePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = FileMetadataPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addFileMetadata($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initFileMetadatas();
    +				$obj2->addFileMetadata($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return FileMetadataPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMetadataPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseFileMetadataPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(FileMetadataPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseFileMetadataPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFileMetadataPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMetadataPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseFileMetadataPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(FileMetadataPeer::ID);
    +			$selectCriteria->add(FileMetadataPeer::ID, $criteria->remove(FileMetadataPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseFileMetadataPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFileMetadataPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(FileMetadataPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(FileMetadataPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof FileMetadata) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(FileMetadataPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(FileMetadata $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(FileMetadataPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(FileMetadataPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(FileMetadataPeer::DATABASE_NAME, FileMetadataPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = FileMetadataPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(FileMetadataPeer::DATABASE_NAME);
    +
    +		$criteria->add(FileMetadataPeer::ID, $pk);
    +
    +
    +		$v = FileMetadataPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(FileMetadataPeer::ID, $pks, Criteria::IN);
    +			$objs = FileMetadataPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseFileMetadataPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/FileMetadataMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.FileMetadataMapBuilder');
    +}
    diff --git a/lib/model/om/BaseFileMimetype.php b/lib/model/om/BaseFileMimetype.php
    new file mode 100644
    index 0000000..21a1678
    --- /dev/null
    +++ b/lib/model/om/BaseFileMimetype.php
    @@ -0,0 +1,546 @@
    +id;
    +	}
    +
    +	
    +	public function getMimetype()
    +	{
    +
    +		return $this->mimetype;
    +	}
    +
    +	
    +	public function getIdentifier()
    +	{
    +
    +		return $this->identifier;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = FileMimetypePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setMimetype($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->mimetype !== $v) {
    +			$this->mimetype = $v;
    +			$this->modifiedColumns[] = FileMimetypePeer::MIMETYPE;
    +		}
    +
    +	} 
    +	
    +	public function setIdentifier($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->identifier !== $v) {
    +			$this->identifier = $v;
    +			$this->modifiedColumns[] = FileMimetypePeer::IDENTIFIER;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->mimetype = $rs->getString($startcol + 1);
    +
    +			$this->identifier = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating FileMimetype object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMimetype:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(FileMimetypePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			FileMimetypePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseFileMimetype:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMimetype:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(FileMimetypePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseFileMimetype:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = FileMimetypePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += FileMimetypePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collArticleFiles !== null) {
    +				foreach($this->collArticleFiles as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = FileMimetypePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collArticleFiles !== null) {
    +					foreach($this->collArticleFiles as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = FileMimetypePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getMimetype();
    +				break;
    +			case 2:
    +				return $this->getIdentifier();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = FileMimetypePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getMimetype(),
    +			$keys[2] => $this->getIdentifier(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = FileMimetypePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setMimetype($value);
    +				break;
    +			case 2:
    +				$this->setIdentifier($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = FileMimetypePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setMimetype($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setIdentifier($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(FileMimetypePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(FileMimetypePeer::ID)) $criteria->add(FileMimetypePeer::ID, $this->id);
    +		if ($this->isColumnModified(FileMimetypePeer::MIMETYPE)) $criteria->add(FileMimetypePeer::MIMETYPE, $this->mimetype);
    +		if ($this->isColumnModified(FileMimetypePeer::IDENTIFIER)) $criteria->add(FileMimetypePeer::IDENTIFIER, $this->identifier);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(FileMimetypePeer::DATABASE_NAME);
    +
    +		$criteria->add(FileMimetypePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setMimetype($this->mimetype);
    +
    +		$copyObj->setIdentifier($this->identifier);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getArticleFiles() as $relObj) {
    +				$copyObj->addArticleFile($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new FileMimetypePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function initArticleFiles()
    +	{
    +		if ($this->collArticleFiles === null) {
    +			$this->collArticleFiles = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleFiles($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleFiles === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleFiles = array();
    +			} else {
    +
    +				$criteria->add(ArticleFilePeer::FILE_MIMETYPE_ID, $this->getId());
    +
    +				ArticleFilePeer::addSelectColumns($criteria);
    +				$this->collArticleFiles = ArticleFilePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleFilePeer::FILE_MIMETYPE_ID, $this->getId());
    +
    +				ArticleFilePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleFileCriteria) || !$this->lastArticleFileCriteria->equals($criteria)) {
    +					$this->collArticleFiles = ArticleFilePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleFileCriteria = $criteria;
    +		return $this->collArticleFiles;
    +	}
    +
    +	
    +	public function countArticleFiles($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleFilePeer::FILE_MIMETYPE_ID, $this->getId());
    +
    +		return ArticleFilePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleFile(ArticleFile $l)
    +	{
    +		$this->collArticleFiles[] = $l;
    +		$l->setFileMimetype($this);
    +	}
    +
    +
    +	
    +	public function getArticleFilesJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleFiles === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleFiles = array();
    +			} else {
    +
    +				$criteria->add(ArticleFilePeer::FILE_MIMETYPE_ID, $this->getId());
    +
    +				$this->collArticleFiles = ArticleFilePeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleFilePeer::FILE_MIMETYPE_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleFileCriteria) || !$this->lastArticleFileCriteria->equals($criteria)) {
    +				$this->collArticleFiles = ArticleFilePeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleFileCriteria = $criteria;
    +
    +		return $this->collArticleFiles;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseFileMimetype:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseFileMimetype::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseFileMimetypePeer.php b/lib/model/om/BaseFileMimetypePeer.php
    new file mode 100644
    index 0000000..7be4b4e
    --- /dev/null
    +++ b/lib/model/om/BaseFileMimetypePeer.php
    @@ -0,0 +1,416 @@
    + array ('Id', 'Mimetype', 'Identifier', ),
    +		BasePeer::TYPE_COLNAME => array (FileMimetypePeer::ID, FileMimetypePeer::MIMETYPE, FileMimetypePeer::IDENTIFIER, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'mimetype', 'identifier', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Mimetype' => 1, 'Identifier' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (FileMimetypePeer::ID => 0, FileMimetypePeer::MIMETYPE => 1, FileMimetypePeer::IDENTIFIER => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'mimetype' => 1, 'identifier' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/FileMimetypeMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.FileMimetypeMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = FileMimetypePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(FileMimetypePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(FileMimetypePeer::ID);
    +
    +		$criteria->addSelectColumn(FileMimetypePeer::MIMETYPE);
    +
    +		$criteria->addSelectColumn(FileMimetypePeer::IDENTIFIER);
    +
    +	}
    +
    +	const COUNT = 'COUNT(file_mimetype.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT file_mimetype.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(FileMimetypePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(FileMimetypePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = FileMimetypePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = FileMimetypePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return FileMimetypePeer::populateObjects(FileMimetypePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMimetypePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFileMimetypePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			FileMimetypePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = FileMimetypePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return FileMimetypePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMimetypePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseFileMimetypePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(FileMimetypePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseFileMimetypePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFileMimetypePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseFileMimetypePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseFileMimetypePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(FileMimetypePeer::ID);
    +			$selectCriteria->add(FileMimetypePeer::ID, $criteria->remove(FileMimetypePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseFileMimetypePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseFileMimetypePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(FileMimetypePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(FileMimetypePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof FileMimetype) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(FileMimetypePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(FileMimetype $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(FileMimetypePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(FileMimetypePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(FileMimetypePeer::DATABASE_NAME, FileMimetypePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = FileMimetypePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(FileMimetypePeer::DATABASE_NAME);
    +
    +		$criteria->add(FileMimetypePeer::ID, $pk);
    +
    +
    +		$v = FileMimetypePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(FileMimetypePeer::ID, $pks, Criteria::IN);
    +			$objs = FileMimetypePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseFileMimetypePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/FileMimetypeMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.FileMimetypeMapBuilder');
    +}
    diff --git a/lib/model/om/BaseHistory.php b/lib/model/om/BaseHistory.php
    new file mode 100644
    index 0000000..b473d4c
    --- /dev/null
    +++ b/lib/model/om/BaseHistory.php
    @@ -0,0 +1,653 @@
    +id;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getActionId()
    +	{
    +
    +		return $this->action_id;
    +	}
    +
    +	
    +	public function getUserId()
    +	{
    +
    +		return $this->user_id;
    +	}
    +
    +	
    +	public function getObjectId()
    +	{
    +
    +		return $this->object_id;
    +	}
    +
    +	
    +	public function getExtraDetails()
    +	{
    +
    +		return $this->extra_details;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = HistoryPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = HistoryPeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setActionId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->action_id !== $v) {
    +			$this->action_id = $v;
    +			$this->modifiedColumns[] = HistoryPeer::ACTION_ID;
    +		}
    +
    +		if ($this->aHistoryAction !== null && $this->aHistoryAction->getId() !== $v) {
    +			$this->aHistoryAction = null;
    +		}
    +
    +	} 
    +	
    +	public function setUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->user_id !== $v) {
    +			$this->user_id = $v;
    +			$this->modifiedColumns[] = HistoryPeer::USER_ID;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setObjectId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->object_id !== $v) {
    +			$this->object_id = $v;
    +			$this->modifiedColumns[] = HistoryPeer::OBJECT_ID;
    +		}
    +
    +	} 
    +	
    +	public function setExtraDetails($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->extra_details !== $v) {
    +			$this->extra_details = $v;
    +			$this->modifiedColumns[] = HistoryPeer::EXTRA_DETAILS;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 1, null);
    +
    +			$this->action_id = $rs->getInt($startcol + 2);
    +
    +			$this->user_id = $rs->getInt($startcol + 3);
    +
    +			$this->object_id = $rs->getInt($startcol + 4);
    +
    +			$this->extra_details = $rs->getString($startcol + 5);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 6; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating History object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistory:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			HistoryPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseHistory:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistory:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(HistoryPeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseHistory:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aHistoryAction !== null) {
    +				if ($this->aHistoryAction->isModified() || $this->aHistoryAction->getCurrentHistoryActionI18n()->isModified()) {
    +					$affectedRows += $this->aHistoryAction->save($con);
    +				}
    +				$this->setHistoryAction($this->aHistoryAction);
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = HistoryPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += HistoryPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aHistoryAction !== null) {
    +				if (!$this->aHistoryAction->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aHistoryAction->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = HistoryPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = HistoryPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getCreatedAt();
    +				break;
    +			case 2:
    +				return $this->getActionId();
    +				break;
    +			case 3:
    +				return $this->getUserId();
    +				break;
    +			case 4:
    +				return $this->getObjectId();
    +				break;
    +			case 5:
    +				return $this->getExtraDetails();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = HistoryPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getCreatedAt(),
    +			$keys[2] => $this->getActionId(),
    +			$keys[3] => $this->getUserId(),
    +			$keys[4] => $this->getObjectId(),
    +			$keys[5] => $this->getExtraDetails(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = HistoryPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setCreatedAt($value);
    +				break;
    +			case 2:
    +				$this->setActionId($value);
    +				break;
    +			case 3:
    +				$this->setUserId($value);
    +				break;
    +			case 4:
    +				$this->setObjectId($value);
    +				break;
    +			case 5:
    +				$this->setExtraDetails($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = HistoryPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCreatedAt($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setActionId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setUserId($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setObjectId($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setExtraDetails($arr[$keys[5]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(HistoryPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(HistoryPeer::ID)) $criteria->add(HistoryPeer::ID, $this->id);
    +		if ($this->isColumnModified(HistoryPeer::CREATED_AT)) $criteria->add(HistoryPeer::CREATED_AT, $this->created_at);
    +		if ($this->isColumnModified(HistoryPeer::ACTION_ID)) $criteria->add(HistoryPeer::ACTION_ID, $this->action_id);
    +		if ($this->isColumnModified(HistoryPeer::USER_ID)) $criteria->add(HistoryPeer::USER_ID, $this->user_id);
    +		if ($this->isColumnModified(HistoryPeer::OBJECT_ID)) $criteria->add(HistoryPeer::OBJECT_ID, $this->object_id);
    +		if ($this->isColumnModified(HistoryPeer::EXTRA_DETAILS)) $criteria->add(HistoryPeer::EXTRA_DETAILS, $this->extra_details);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(HistoryPeer::DATABASE_NAME);
    +
    +		$criteria->add(HistoryPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +		$copyObj->setActionId($this->action_id);
    +
    +		$copyObj->setUserId($this->user_id);
    +
    +		$copyObj->setObjectId($this->object_id);
    +
    +		$copyObj->setExtraDetails($this->extra_details);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new HistoryPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setHistoryAction($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setActionId(NULL);
    +		} else {
    +			$this->setActionId($v->getId());
    +		}
    +
    +
    +		$this->aHistoryAction = $v;
    +	}
    +
    +
    +	
    +	public function getHistoryAction($con = null)
    +	{
    +		if ($this->aHistoryAction === null && ($this->action_id !== null)) {
    +						include_once 'lib/model/om/BaseHistoryActionPeer.php';
    +
    +			$this->aHistoryAction = HistoryActionPeer::retrieveByPK($this->action_id, $con);
    +
    +			
    +		}
    +		return $this->aHistoryAction;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUserId(NULL);
    +		} else {
    +			$this->setUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseHistory:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseHistory::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseHistoryAction.php b/lib/model/om/BaseHistoryAction.php
    new file mode 100644
    index 0000000..3a7a3f8
    --- /dev/null
    +++ b/lib/model/om/BaseHistoryAction.php
    @@ -0,0 +1,654 @@
    +id;
    +	}
    +
    +	
    +	public function getName()
    +	{
    +
    +		return $this->name;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = HistoryActionPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setName($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->name !== $v) {
    +			$this->name = $v;
    +			$this->modifiedColumns[] = HistoryActionPeer::NAME;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->name = $rs->getString($startcol + 1);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 2; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating HistoryAction object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryAction:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryActionPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			HistoryActionPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseHistoryAction:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryAction:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryActionPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseHistoryAction:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = HistoryActionPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += HistoryActionPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collHistorys !== null) {
    +				foreach($this->collHistorys as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collHistoryActionI18ns !== null) {
    +				foreach($this->collHistoryActionI18ns as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = HistoryActionPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collHistorys !== null) {
    +					foreach($this->collHistorys as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collHistoryActionI18ns !== null) {
    +					foreach($this->collHistoryActionI18ns as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = HistoryActionPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getName();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = HistoryActionPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getName(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = HistoryActionPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setName($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = HistoryActionPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setName($arr[$keys[1]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(HistoryActionPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(HistoryActionPeer::ID)) $criteria->add(HistoryActionPeer::ID, $this->id);
    +		if ($this->isColumnModified(HistoryActionPeer::NAME)) $criteria->add(HistoryActionPeer::NAME, $this->name);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(HistoryActionPeer::DATABASE_NAME);
    +
    +		$criteria->add(HistoryActionPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setName($this->name);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getHistorys() as $relObj) {
    +				$copyObj->addHistory($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getHistoryActionI18ns() as $relObj) {
    +				$copyObj->addHistoryActionI18n($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new HistoryActionPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function initHistorys()
    +	{
    +		if ($this->collHistorys === null) {
    +			$this->collHistorys = array();
    +		}
    +	}
    +
    +	
    +	public function getHistorys($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collHistorys === null) {
    +			if ($this->isNew()) {
    +			   $this->collHistorys = array();
    +			} else {
    +
    +				$criteria->add(HistoryPeer::ACTION_ID, $this->getId());
    +
    +				HistoryPeer::addSelectColumns($criteria);
    +				$this->collHistorys = HistoryPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(HistoryPeer::ACTION_ID, $this->getId());
    +
    +				HistoryPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastHistoryCriteria) || !$this->lastHistoryCriteria->equals($criteria)) {
    +					$this->collHistorys = HistoryPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastHistoryCriteria = $criteria;
    +		return $this->collHistorys;
    +	}
    +
    +	
    +	public function countHistorys($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(HistoryPeer::ACTION_ID, $this->getId());
    +
    +		return HistoryPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addHistory(History $l)
    +	{
    +		$this->collHistorys[] = $l;
    +		$l->setHistoryAction($this);
    +	}
    +
    +
    +	
    +	public function getHistorysJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collHistorys === null) {
    +			if ($this->isNew()) {
    +				$this->collHistorys = array();
    +			} else {
    +
    +				$criteria->add(HistoryPeer::ACTION_ID, $this->getId());
    +
    +				$this->collHistorys = HistoryPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(HistoryPeer::ACTION_ID, $this->getId());
    +
    +			if (!isset($this->lastHistoryCriteria) || !$this->lastHistoryCriteria->equals($criteria)) {
    +				$this->collHistorys = HistoryPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastHistoryCriteria = $criteria;
    +
    +		return $this->collHistorys;
    +	}
    +
    +	
    +	public function initHistoryActionI18ns()
    +	{
    +		if ($this->collHistoryActionI18ns === null) {
    +			$this->collHistoryActionI18ns = array();
    +		}
    +	}
    +
    +	
    +	public function getHistoryActionI18ns($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseHistoryActionI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collHistoryActionI18ns === null) {
    +			if ($this->isNew()) {
    +			   $this->collHistoryActionI18ns = array();
    +			} else {
    +
    +				$criteria->add(HistoryActionI18nPeer::ID, $this->getId());
    +
    +				HistoryActionI18nPeer::addSelectColumns($criteria);
    +				$this->collHistoryActionI18ns = HistoryActionI18nPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(HistoryActionI18nPeer::ID, $this->getId());
    +
    +				HistoryActionI18nPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastHistoryActionI18nCriteria) || !$this->lastHistoryActionI18nCriteria->equals($criteria)) {
    +					$this->collHistoryActionI18ns = HistoryActionI18nPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastHistoryActionI18nCriteria = $criteria;
    +		return $this->collHistoryActionI18ns;
    +	}
    +
    +	
    +	public function countHistoryActionI18ns($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseHistoryActionI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(HistoryActionI18nPeer::ID, $this->getId());
    +
    +		return HistoryActionI18nPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addHistoryActionI18n(HistoryActionI18n $l)
    +	{
    +		$this->collHistoryActionI18ns[] = $l;
    +		$l->setHistoryAction($this);
    +	}
    +
    +  public function getCulture()
    +  {
    +    return $this->culture;
    +  }
    +
    +  public function setCulture($culture)
    +  {
    +    $this->culture = $culture;
    +  }
    +
    +  public function getDescription()
    +  {
    +    $obj = $this->getCurrentHistoryActionI18n();
    +
    +    return ($obj ? $obj->getDescription() : null);
    +  }
    +
    +  public function setDescription($value)
    +  {
    +    $this->getCurrentHistoryActionI18n()->setDescription($value);
    +  }
    +
    +  protected $current_i18n = array();
    +
    +  public function getCurrentHistoryActionI18n()
    +  {
    +    if (!isset($this->current_i18n[$this->culture]))
    +    {
    +      $obj = HistoryActionI18nPeer::retrieveByPK($this->getId(), $this->culture);
    +      if ($obj)
    +      {
    +        $this->setHistoryActionI18nForCulture($obj, $this->culture);
    +      }
    +      else
    +      {
    +        $this->setHistoryActionI18nForCulture(new HistoryActionI18n(), $this->culture);
    +        $this->current_i18n[$this->culture]->setCulture($this->culture);
    +      }
    +    }
    +
    +    return $this->current_i18n[$this->culture];
    +  }
    +
    +  public function setHistoryActionI18nForCulture($object, $culture)
    +  {
    +    $this->current_i18n[$culture] = $object;
    +    $this->addHistoryActionI18n($object);
    +  }
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseHistoryAction:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseHistoryAction::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseHistoryActionI18n.php b/lib/model/om/BaseHistoryActionI18n.php
    new file mode 100644
    index 0000000..4d1ebf4
    --- /dev/null
    +++ b/lib/model/om/BaseHistoryActionI18n.php
    @@ -0,0 +1,472 @@
    +description;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function getCulture()
    +	{
    +
    +		return $this->culture;
    +	}
    +
    +	
    +	public function setDescription($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->description !== $v) {
    +			$this->description = $v;
    +			$this->modifiedColumns[] = HistoryActionI18nPeer::DESCRIPTION;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = HistoryActionI18nPeer::ID;
    +		}
    +
    +		if ($this->aHistoryAction !== null && $this->aHistoryAction->getId() !== $v) {
    +			$this->aHistoryAction = null;
    +		}
    +
    +	} 
    +	
    +	public function setCulture($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->culture !== $v) {
    +			$this->culture = $v;
    +			$this->modifiedColumns[] = HistoryActionI18nPeer::CULTURE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->description = $rs->getString($startcol + 0);
    +
    +			$this->id = $rs->getInt($startcol + 1);
    +
    +			$this->culture = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating HistoryActionI18n object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18n:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryActionI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			HistoryActionI18nPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18n:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18n:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryActionI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18n:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aHistoryAction !== null) {
    +				if ($this->aHistoryAction->isModified() || $this->aHistoryAction->getCurrentHistoryActionI18n()->isModified()) {
    +					$affectedRows += $this->aHistoryAction->save($con);
    +				}
    +				$this->setHistoryAction($this->aHistoryAction);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = HistoryActionI18nPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += HistoryActionI18nPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aHistoryAction !== null) {
    +				if (!$this->aHistoryAction->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aHistoryAction->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = HistoryActionI18nPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = HistoryActionI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getDescription();
    +				break;
    +			case 1:
    +				return $this->getId();
    +				break;
    +			case 2:
    +				return $this->getCulture();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = HistoryActionI18nPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getDescription(),
    +			$keys[1] => $this->getId(),
    +			$keys[2] => $this->getCulture(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = HistoryActionI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setDescription($value);
    +				break;
    +			case 1:
    +				$this->setId($value);
    +				break;
    +			case 2:
    +				$this->setCulture($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = HistoryActionI18nPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setDescription($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setCulture($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(HistoryActionI18nPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(HistoryActionI18nPeer::DESCRIPTION)) $criteria->add(HistoryActionI18nPeer::DESCRIPTION, $this->description);
    +		if ($this->isColumnModified(HistoryActionI18nPeer::ID)) $criteria->add(HistoryActionI18nPeer::ID, $this->id);
    +		if ($this->isColumnModified(HistoryActionI18nPeer::CULTURE)) $criteria->add(HistoryActionI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(HistoryActionI18nPeer::DATABASE_NAME);
    +
    +		$criteria->add(HistoryActionI18nPeer::ID, $this->id);
    +		$criteria->add(HistoryActionI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getId();
    +
    +		$pks[1] = $this->getCulture();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setId($keys[0]);
    +
    +		$this->setCulture($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setDescription($this->description);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +		$copyObj->setCulture(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new HistoryActionI18nPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setHistoryAction($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setId(NULL);
    +		} else {
    +			$this->setId($v->getId());
    +		}
    +
    +
    +		$this->aHistoryAction = $v;
    +	}
    +
    +
    +	
    +	public function getHistoryAction($con = null)
    +	{
    +		if ($this->aHistoryAction === null && ($this->id !== null)) {
    +						include_once 'lib/model/om/BaseHistoryActionPeer.php';
    +
    +			$this->aHistoryAction = HistoryActionPeer::retrieveByPK($this->id, $con);
    +
    +			
    +		}
    +		return $this->aHistoryAction;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseHistoryActionI18n:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseHistoryActionI18n::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseHistoryActionI18nPeer.php b/lib/model/om/BaseHistoryActionI18nPeer.php
    new file mode 100644
    index 0000000..872cdc4
    --- /dev/null
    +++ b/lib/model/om/BaseHistoryActionI18nPeer.php
    @@ -0,0 +1,569 @@
    + array ('Description', 'Id', 'Culture', ),
    +		BasePeer::TYPE_COLNAME => array (HistoryActionI18nPeer::DESCRIPTION, HistoryActionI18nPeer::ID, HistoryActionI18nPeer::CULTURE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('description', 'id', 'culture', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Description' => 0, 'Id' => 1, 'Culture' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (HistoryActionI18nPeer::DESCRIPTION => 0, HistoryActionI18nPeer::ID => 1, HistoryActionI18nPeer::CULTURE => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('description' => 0, 'id' => 1, 'culture' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/HistoryActionI18nMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.HistoryActionI18nMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = HistoryActionI18nPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(HistoryActionI18nPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(HistoryActionI18nPeer::DESCRIPTION);
    +
    +		$criteria->addSelectColumn(HistoryActionI18nPeer::ID);
    +
    +		$criteria->addSelectColumn(HistoryActionI18nPeer::CULTURE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(history_action_i18n.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT history_action_i18n.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryActionI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryActionI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = HistoryActionI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = HistoryActionI18nPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return HistoryActionI18nPeer::populateObjects(HistoryActionI18nPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18nPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryActionI18nPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			HistoryActionI18nPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = HistoryActionI18nPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinHistoryAction(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryActionI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryActionI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(HistoryActionI18nPeer::ID, HistoryActionPeer::ID);
    +
    +		$rs = HistoryActionI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinHistoryAction(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		HistoryActionI18nPeer::addSelectColumns($c);
    +		$startcol = (HistoryActionI18nPeer::NUM_COLUMNS - HistoryActionI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		HistoryActionPeer::addSelectColumns($c);
    +
    +		$c->addJoin(HistoryActionI18nPeer::ID, HistoryActionPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = HistoryActionI18nPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = HistoryActionPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getHistoryAction(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addHistoryActionI18n($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initHistoryActionI18ns();
    +				$obj2->addHistoryActionI18n($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryActionI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryActionI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(HistoryActionI18nPeer::ID, HistoryActionPeer::ID);
    +
    +		$rs = HistoryActionI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		HistoryActionI18nPeer::addSelectColumns($c);
    +		$startcol2 = (HistoryActionI18nPeer::NUM_COLUMNS - HistoryActionI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		HistoryActionPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + HistoryActionPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(HistoryActionI18nPeer::ID, HistoryActionPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = HistoryActionI18nPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = HistoryActionPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getHistoryAction(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addHistoryActionI18n($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initHistoryActionI18ns();
    +				$obj2->addHistoryActionI18n($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return HistoryActionI18nPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18nPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseHistoryActionI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18nPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryActionI18nPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18nPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseHistoryActionI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(HistoryActionI18nPeer::ID);
    +			$selectCriteria->add(HistoryActionI18nPeer::ID, $criteria->remove(HistoryActionI18nPeer::ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(HistoryActionI18nPeer::CULTURE);
    +			$selectCriteria->add(HistoryActionI18nPeer::CULTURE, $criteria->remove(HistoryActionI18nPeer::CULTURE), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionI18nPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryActionI18nPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(HistoryActionI18nPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryActionI18nPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof HistoryActionI18n) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(HistoryActionI18nPeer::ID, $vals[0], Criteria::IN);
    +			$criteria->add(HistoryActionI18nPeer::CULTURE, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(HistoryActionI18n $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(HistoryActionI18nPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(HistoryActionI18nPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(HistoryActionI18nPeer::DATABASE_NAME, HistoryActionI18nPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = HistoryActionI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $id, $culture, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(HistoryActionI18nPeer::ID, $id);
    +		$criteria->add(HistoryActionI18nPeer::CULTURE, $culture);
    +		$v = HistoryActionI18nPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseHistoryActionI18nPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/HistoryActionI18nMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.HistoryActionI18nMapBuilder');
    +}
    diff --git a/lib/model/om/BaseHistoryActionPeer.php b/lib/model/om/BaseHistoryActionPeer.php
    new file mode 100644
    index 0000000..d5ff1d0
    --- /dev/null
    +++ b/lib/model/om/BaseHistoryActionPeer.php
    @@ -0,0 +1,479 @@
    + array ('Id', 'Name', ),
    +		BasePeer::TYPE_COLNAME => array (HistoryActionPeer::ID, HistoryActionPeer::NAME, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'name', ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Name' => 1, ),
    +		BasePeer::TYPE_COLNAME => array (HistoryActionPeer::ID => 0, HistoryActionPeer::NAME => 1, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/HistoryActionMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.HistoryActionMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = HistoryActionPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(HistoryActionPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(HistoryActionPeer::ID);
    +
    +		$criteria->addSelectColumn(HistoryActionPeer::NAME);
    +
    +	}
    +
    +	const COUNT = 'COUNT(history_action.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT history_action.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryActionPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryActionPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = HistoryActionPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = HistoryActionPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return HistoryActionPeer::populateObjects(HistoryActionPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryActionPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			HistoryActionPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = HistoryActionPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +  
    +  public static function doSelectWithI18n(Criteria $c, $culture = null, $con = null)
    +  {
    +    if ($culture === null)
    +    {
    +      $culture = sfContext::getInstance()->getUser()->getCulture();
    +    }
    +
    +        if ($c->getDbName() == Propel::getDefaultDB())
    +    {
    +      $c->setDbName(self::DATABASE_NAME);
    +    }
    +
    +    HistoryActionPeer::addSelectColumns($c);
    +    $startcol = (HistoryActionPeer::NUM_COLUMNS - HistoryActionPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +    HistoryActionI18nPeer::addSelectColumns($c);
    +
    +    $c->addJoin(HistoryActionPeer::ID, HistoryActionI18nPeer::ID);
    +    $c->add(HistoryActionI18nPeer::CULTURE, $culture);
    +
    +    $rs = BasePeer::doSelect($c, $con);
    +    $results = array();
    +
    +    while($rs->next()) {
    +
    +      $omClass = HistoryActionPeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj1 = new $cls();
    +      $obj1->hydrate($rs);
    +      $obj1->setCulture($culture);
    +
    +      $omClass = HistoryActionI18nPeer::getOMClass($rs, $startcol);
    +
    +      $cls = Propel::import($omClass);
    +      $obj2 = new $cls();
    +      $obj2->hydrate($rs, $startcol);
    +
    +      $obj1->setHistoryActionI18nForCulture($obj2, $culture);
    +      $obj2->setHistoryAction($obj1);
    +
    +      $results[] = $obj1;
    +    }
    +    return $results;
    +  }
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return HistoryActionPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseHistoryActionPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(HistoryActionPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseHistoryActionPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryActionPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseHistoryActionPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(HistoryActionPeer::ID);
    +			$selectCriteria->add(HistoryActionPeer::ID, $criteria->remove(HistoryActionPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseHistoryActionPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryActionPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += HistoryActionPeer::doOnDeleteCascade(new Criteria(), $con);
    +			$affectedRows += BasePeer::doDeleteAll(HistoryActionPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryActionPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof HistoryAction) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(HistoryActionPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			$affectedRows += HistoryActionPeer::doOnDeleteCascade($criteria, $con);
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected static function doOnDeleteCascade(Criteria $criteria, Connection $con)
    +	{
    +				$affectedRows = 0;
    +
    +				$objects = HistoryActionPeer::doSelect($criteria, $con);
    +		foreach($objects as $obj) {
    +
    +
    +			include_once 'lib/model/HistoryActionI18n.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(HistoryActionI18nPeer::ID, $obj->getId());
    +			$affectedRows += HistoryActionI18nPeer::doDelete($c, $con);
    +		}
    +		return $affectedRows;
    +	}
    +
    +	
    +	public static function doValidate(HistoryAction $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(HistoryActionPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(HistoryActionPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(HistoryActionPeer::DATABASE_NAME, HistoryActionPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = HistoryActionPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(HistoryActionPeer::DATABASE_NAME);
    +
    +		$criteria->add(HistoryActionPeer::ID, $pk);
    +
    +
    +		$v = HistoryActionPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(HistoryActionPeer::ID, $pks, Criteria::IN);
    +			$objs = HistoryActionPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseHistoryActionPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/HistoryActionMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.HistoryActionMapBuilder');
    +}
    diff --git a/lib/model/om/BaseHistoryPeer.php b/lib/model/om/BaseHistoryPeer.php
    new file mode 100644
    index 0000000..cff6d5d
    --- /dev/null
    +++ b/lib/model/om/BaseHistoryPeer.php
    @@ -0,0 +1,867 @@
    + array ('Id', 'CreatedAt', 'ActionId', 'UserId', 'ObjectId', 'ExtraDetails', ),
    +		BasePeer::TYPE_COLNAME => array (HistoryPeer::ID, HistoryPeer::CREATED_AT, HistoryPeer::ACTION_ID, HistoryPeer::USER_ID, HistoryPeer::OBJECT_ID, HistoryPeer::EXTRA_DETAILS, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'created_at', 'action_id', 'user_id', 'object_id', 'extra_details', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'CreatedAt' => 1, 'ActionId' => 2, 'UserId' => 3, 'ObjectId' => 4, 'ExtraDetails' => 5, ),
    +		BasePeer::TYPE_COLNAME => array (HistoryPeer::ID => 0, HistoryPeer::CREATED_AT => 1, HistoryPeer::ACTION_ID => 2, HistoryPeer::USER_ID => 3, HistoryPeer::OBJECT_ID => 4, HistoryPeer::EXTRA_DETAILS => 5, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'created_at' => 1, 'action_id' => 2, 'user_id' => 3, 'object_id' => 4, 'extra_details' => 5, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/HistoryMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.HistoryMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = HistoryPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(HistoryPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(HistoryPeer::ID);
    +
    +		$criteria->addSelectColumn(HistoryPeer::CREATED_AT);
    +
    +		$criteria->addSelectColumn(HistoryPeer::ACTION_ID);
    +
    +		$criteria->addSelectColumn(HistoryPeer::USER_ID);
    +
    +		$criteria->addSelectColumn(HistoryPeer::OBJECT_ID);
    +
    +		$criteria->addSelectColumn(HistoryPeer::EXTRA_DETAILS);
    +
    +	}
    +
    +	const COUNT = 'COUNT(history.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT history.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = HistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = HistoryPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return HistoryPeer::populateObjects(HistoryPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			HistoryPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = HistoryPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinHistoryAction(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(HistoryPeer::ACTION_ID, HistoryActionPeer::ID);
    +
    +		$rs = HistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(HistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = HistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinHistoryAction(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		HistoryPeer::addSelectColumns($c);
    +		$startcol = (HistoryPeer::NUM_COLUMNS - HistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		HistoryActionPeer::addSelectColumns($c);
    +
    +		$c->addJoin(HistoryPeer::ACTION_ID, HistoryActionPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = HistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = HistoryActionPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getHistoryAction(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addHistory($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initHistorys();
    +				$obj2->addHistory($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		HistoryPeer::addSelectColumns($c);
    +		$startcol = (HistoryPeer::NUM_COLUMNS - HistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(HistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = HistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addHistory($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initHistorys();
    +				$obj2->addHistory($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(HistoryPeer::ACTION_ID, HistoryActionPeer::ID);
    +
    +		$criteria->addJoin(HistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = HistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		HistoryPeer::addSelectColumns($c);
    +		$startcol2 = (HistoryPeer::NUM_COLUMNS - HistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		HistoryActionPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + HistoryActionPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(HistoryPeer::ACTION_ID, HistoryActionPeer::ID);
    +
    +		$c->addJoin(HistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = HistoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = HistoryActionPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getHistoryAction(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addHistory($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initHistorys();
    +				$obj2->addHistory($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addHistory($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initHistorys();
    +				$obj3->addHistory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptHistoryAction(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(HistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = HistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(HistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(HistoryPeer::ACTION_ID, HistoryActionPeer::ID);
    +
    +		$rs = HistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptHistoryAction(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		HistoryPeer::addSelectColumns($c);
    +		$startcol2 = (HistoryPeer::NUM_COLUMNS - HistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(HistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = HistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addHistory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initHistorys();
    +				$obj2->addHistory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		HistoryPeer::addSelectColumns($c);
    +		$startcol2 = (HistoryPeer::NUM_COLUMNS - HistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		HistoryActionPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + HistoryActionPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(HistoryPeer::ACTION_ID, HistoryActionPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = HistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = HistoryActionPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getHistoryAction(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addHistory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initHistorys();
    +				$obj2->addHistory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return HistoryPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseHistoryPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(HistoryPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseHistoryPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseHistoryPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseHistoryPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(HistoryPeer::ID);
    +			$selectCriteria->add(HistoryPeer::ID, $criteria->remove(HistoryPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseHistoryPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseHistoryPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(HistoryPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(HistoryPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof History) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(HistoryPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(History $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(HistoryPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(HistoryPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(HistoryPeer::DATABASE_NAME, HistoryPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = HistoryPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(HistoryPeer::DATABASE_NAME);
    +
    +		$criteria->add(HistoryPeer::ID, $pk);
    +
    +
    +		$v = HistoryPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(HistoryPeer::ID, $pks, Criteria::IN);
    +			$objs = HistoryPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseHistoryPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/HistoryMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.HistoryMapBuilder');
    +}
    diff --git a/lib/model/om/BaseLokalreaktorArtwork.php b/lib/model/om/BaseLokalreaktorArtwork.php
    new file mode 100644
    index 0000000..cc4eabf
    --- /dev/null
    +++ b/lib/model/om/BaseLokalreaktorArtwork.php
    @@ -0,0 +1,512 @@
    +id;
    +	}
    +
    +	
    +	public function getSubreaktorId()
    +	{
    +
    +		return $this->subreaktor_id;
    +	}
    +
    +	
    +	public function getArtworkId()
    +	{
    +
    +		return $this->artwork_id;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = LokalreaktorArtworkPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktorId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor_id !== $v) {
    +			$this->subreaktor_id = $v;
    +			$this->modifiedColumns[] = LokalreaktorArtworkPeer::SUBREAKTOR_ID;
    +		}
    +
    +		if ($this->aSubreaktor !== null && $this->aSubreaktor->getId() !== $v) {
    +			$this->aSubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function setArtworkId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork_id !== $v) {
    +			$this->artwork_id = $v;
    +			$this->modifiedColumns[] = LokalreaktorArtworkPeer::ARTWORK_ID;
    +		}
    +
    +		if ($this->aReaktorArtwork !== null && $this->aReaktorArtwork->getId() !== $v) {
    +			$this->aReaktorArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->subreaktor_id = $rs->getInt($startcol + 1);
    +
    +			$this->artwork_id = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating LokalreaktorArtwork object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtwork:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(LokalreaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			LokalreaktorArtworkPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtwork:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtwork:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(LokalreaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtwork:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if ($this->aSubreaktor->isModified() || $this->aSubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktor->save($con);
    +				}
    +				$this->setSubreaktor($this->aSubreaktor);
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if ($this->aReaktorArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtwork->save($con);
    +				}
    +				$this->setReaktorArtwork($this->aReaktorArtwork);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = LokalreaktorArtworkPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += LokalreaktorArtworkPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if (!$this->aSubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if (!$this->aReaktorArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtwork->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = LokalreaktorArtworkPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = LokalreaktorArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getSubreaktorId();
    +				break;
    +			case 2:
    +				return $this->getArtworkId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = LokalreaktorArtworkPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getSubreaktorId(),
    +			$keys[2] => $this->getArtworkId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = LokalreaktorArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setSubreaktorId($value);
    +				break;
    +			case 2:
    +				$this->setArtworkId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = LokalreaktorArtworkPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setSubreaktorId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setArtworkId($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(LokalreaktorArtworkPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(LokalreaktorArtworkPeer::ID)) $criteria->add(LokalreaktorArtworkPeer::ID, $this->id);
    +		if ($this->isColumnModified(LokalreaktorArtworkPeer::SUBREAKTOR_ID)) $criteria->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $this->subreaktor_id);
    +		if ($this->isColumnModified(LokalreaktorArtworkPeer::ARTWORK_ID)) $criteria->add(LokalreaktorArtworkPeer::ARTWORK_ID, $this->artwork_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(LokalreaktorArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(LokalreaktorArtworkPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setSubreaktorId($this->subreaktor_id);
    +
    +		$copyObj->setArtworkId($this->artwork_id);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new LokalreaktorArtworkPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSubreaktorId(NULL);
    +		} else {
    +			$this->setSubreaktorId($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktor === null && ($this->subreaktor_id !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktor = SubreaktorPeer::retrieveByPK($this->subreaktor_id, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktor;
    +	}
    +
    +	
    +	public function setReaktorArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArtworkId(NULL);
    +		} else {
    +			$this->setArtworkId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtwork === null && ($this->artwork_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtwork = ReaktorArtworkPeer::retrieveByPK($this->artwork_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtwork;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseLokalreaktorArtwork:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseLokalreaktorArtwork::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseLokalreaktorArtworkPeer.php b/lib/model/om/BaseLokalreaktorArtworkPeer.php
    new file mode 100644
    index 0000000..0223976
    --- /dev/null
    +++ b/lib/model/om/BaseLokalreaktorArtworkPeer.php
    @@ -0,0 +1,852 @@
    + array ('Id', 'SubreaktorId', 'ArtworkId', ),
    +		BasePeer::TYPE_COLNAME => array (LokalreaktorArtworkPeer::ID, LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorArtworkPeer::ARTWORK_ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'subreaktor_id', 'artwork_id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'SubreaktorId' => 1, 'ArtworkId' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (LokalreaktorArtworkPeer::ID => 0, LokalreaktorArtworkPeer::SUBREAKTOR_ID => 1, LokalreaktorArtworkPeer::ARTWORK_ID => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'subreaktor_id' => 1, 'artwork_id' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/LokalreaktorArtworkMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.LokalreaktorArtworkMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = LokalreaktorArtworkPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(LokalreaktorArtworkPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(LokalreaktorArtworkPeer::ID);
    +
    +		$criteria->addSelectColumn(LokalreaktorArtworkPeer::SUBREAKTOR_ID);
    +
    +		$criteria->addSelectColumn(LokalreaktorArtworkPeer::ARTWORK_ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(lokalreaktor_artwork.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT lokalreaktor_artwork.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = LokalreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = LokalreaktorArtworkPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return LokalreaktorArtworkPeer::populateObjects(LokalreaktorArtworkPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtworkPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseLokalreaktorArtworkPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			LokalreaktorArtworkPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = LokalreaktorArtworkPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = LokalreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = LokalreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol = (LokalreaktorArtworkPeer::NUM_COLUMNS - LokalreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addLokalreaktorArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initLokalreaktorArtworks();
    +				$obj2->addLokalreaktorArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol = (LokalreaktorArtworkPeer::NUM_COLUMNS - LokalreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(LokalreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addLokalreaktorArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initLokalreaktorArtworks();
    +				$obj2->addLokalreaktorArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$criteria->addJoin(LokalreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = LokalreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (LokalreaktorArtworkPeer::NUM_COLUMNS - LokalreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$c->addJoin(LokalreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addLokalreaktorArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initLokalreaktorArtworks();
    +				$obj2->addLokalreaktorArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addLokalreaktorArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initLokalreaktorArtworks();
    +				$obj3->addLokalreaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = LokalreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = LokalreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (LokalreaktorArtworkPeer::NUM_COLUMNS - LokalreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(LokalreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addLokalreaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initLokalreaktorArtworks();
    +				$obj2->addLokalreaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (LokalreaktorArtworkPeer::NUM_COLUMNS - LokalreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addLokalreaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initLokalreaktorArtworks();
    +				$obj2->addLokalreaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return LokalreaktorArtworkPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtworkPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseLokalreaktorArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(LokalreaktorArtworkPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtworkPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseLokalreaktorArtworkPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtworkPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseLokalreaktorArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(LokalreaktorArtworkPeer::ID);
    +			$selectCriteria->add(LokalreaktorArtworkPeer::ID, $criteria->remove(LokalreaktorArtworkPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorArtworkPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseLokalreaktorArtworkPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(LokalreaktorArtworkPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(LokalreaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof LokalreaktorArtwork) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(LokalreaktorArtworkPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(LokalreaktorArtwork $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(LokalreaktorArtworkPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(LokalreaktorArtworkPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(LokalreaktorArtworkPeer::DATABASE_NAME, LokalreaktorArtworkPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = LokalreaktorArtworkPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(LokalreaktorArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(LokalreaktorArtworkPeer::ID, $pk);
    +
    +
    +		$v = LokalreaktorArtworkPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(LokalreaktorArtworkPeer::ID, $pks, Criteria::IN);
    +			$objs = LokalreaktorArtworkPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseLokalreaktorArtworkPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/LokalreaktorArtworkMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.LokalreaktorArtworkMapBuilder');
    +}
    diff --git a/lib/model/om/BaseLokalreaktorResidence.php b/lib/model/om/BaseLokalreaktorResidence.php
    new file mode 100644
    index 0000000..f6fdb8d
    --- /dev/null
    +++ b/lib/model/om/BaseLokalreaktorResidence.php
    @@ -0,0 +1,573 @@
    +id;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getSubreaktorId()
    +	{
    +
    +		return $this->subreaktor_id;
    +	}
    +
    +	
    +	public function getResidenceId()
    +	{
    +
    +		return $this->residence_id;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = LokalreaktorResidencePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = LokalreaktorResidencePeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktorId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor_id !== $v) {
    +			$this->subreaktor_id = $v;
    +			$this->modifiedColumns[] = LokalreaktorResidencePeer::SUBREAKTOR_ID;
    +		}
    +
    +		if ($this->aSubreaktor !== null && $this->aSubreaktor->getId() !== $v) {
    +			$this->aSubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function setResidenceId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->residence_id !== $v) {
    +			$this->residence_id = $v;
    +			$this->modifiedColumns[] = LokalreaktorResidencePeer::RESIDENCE_ID;
    +		}
    +
    +		if ($this->aResidence !== null && $this->aResidence->getId() !== $v) {
    +			$this->aResidence = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 1, null);
    +
    +			$this->subreaktor_id = $rs->getInt($startcol + 2);
    +
    +			$this->residence_id = $rs->getInt($startcol + 3);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 4; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating LokalreaktorResidence object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidence:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(LokalreaktorResidencePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			LokalreaktorResidencePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidence:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidence:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(LokalreaktorResidencePeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(LokalreaktorResidencePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidence:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if ($this->aSubreaktor->isModified() || $this->aSubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktor->save($con);
    +				}
    +				$this->setSubreaktor($this->aSubreaktor);
    +			}
    +
    +			if ($this->aResidence !== null) {
    +				if ($this->aResidence->isModified()) {
    +					$affectedRows += $this->aResidence->save($con);
    +				}
    +				$this->setResidence($this->aResidence);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = LokalreaktorResidencePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += LokalreaktorResidencePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if (!$this->aSubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aResidence !== null) {
    +				if (!$this->aResidence->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aResidence->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = LokalreaktorResidencePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = LokalreaktorResidencePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getCreatedAt();
    +				break;
    +			case 2:
    +				return $this->getSubreaktorId();
    +				break;
    +			case 3:
    +				return $this->getResidenceId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = LokalreaktorResidencePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getCreatedAt(),
    +			$keys[2] => $this->getSubreaktorId(),
    +			$keys[3] => $this->getResidenceId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = LokalreaktorResidencePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setCreatedAt($value);
    +				break;
    +			case 2:
    +				$this->setSubreaktorId($value);
    +				break;
    +			case 3:
    +				$this->setResidenceId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = LokalreaktorResidencePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCreatedAt($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setSubreaktorId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setResidenceId($arr[$keys[3]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(LokalreaktorResidencePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(LokalreaktorResidencePeer::ID)) $criteria->add(LokalreaktorResidencePeer::ID, $this->id);
    +		if ($this->isColumnModified(LokalreaktorResidencePeer::CREATED_AT)) $criteria->add(LokalreaktorResidencePeer::CREATED_AT, $this->created_at);
    +		if ($this->isColumnModified(LokalreaktorResidencePeer::SUBREAKTOR_ID)) $criteria->add(LokalreaktorResidencePeer::SUBREAKTOR_ID, $this->subreaktor_id);
    +		if ($this->isColumnModified(LokalreaktorResidencePeer::RESIDENCE_ID)) $criteria->add(LokalreaktorResidencePeer::RESIDENCE_ID, $this->residence_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(LokalreaktorResidencePeer::DATABASE_NAME);
    +
    +		$criteria->add(LokalreaktorResidencePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +		$copyObj->setSubreaktorId($this->subreaktor_id);
    +
    +		$copyObj->setResidenceId($this->residence_id);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new LokalreaktorResidencePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSubreaktorId(NULL);
    +		} else {
    +			$this->setSubreaktorId($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktor === null && ($this->subreaktor_id !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktor = SubreaktorPeer::retrieveByPK($this->subreaktor_id, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktor;
    +	}
    +
    +	
    +	public function setResidence($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setResidenceId(NULL);
    +		} else {
    +			$this->setResidenceId($v->getId());
    +		}
    +
    +
    +		$this->aResidence = $v;
    +	}
    +
    +
    +	
    +	public function getResidence($con = null)
    +	{
    +		if ($this->aResidence === null && ($this->residence_id !== null)) {
    +						include_once 'lib/model/om/BaseResidencePeer.php';
    +
    +			$this->aResidence = ResidencePeer::retrieveByPK($this->residence_id, $con);
    +
    +			
    +		}
    +		return $this->aResidence;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseLokalreaktorResidence:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseLokalreaktorResidence::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseLokalreaktorResidencePeer.php b/lib/model/om/BaseLokalreaktorResidencePeer.php
    new file mode 100644
    index 0000000..23a69a3
    --- /dev/null
    +++ b/lib/model/om/BaseLokalreaktorResidencePeer.php
    @@ -0,0 +1,857 @@
    + array ('Id', 'CreatedAt', 'SubreaktorId', 'ResidenceId', ),
    +		BasePeer::TYPE_COLNAME => array (LokalreaktorResidencePeer::ID, LokalreaktorResidencePeer::CREATED_AT, LokalreaktorResidencePeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::RESIDENCE_ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'created_at', 'subreaktor_id', 'residence_id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'CreatedAt' => 1, 'SubreaktorId' => 2, 'ResidenceId' => 3, ),
    +		BasePeer::TYPE_COLNAME => array (LokalreaktorResidencePeer::ID => 0, LokalreaktorResidencePeer::CREATED_AT => 1, LokalreaktorResidencePeer::SUBREAKTOR_ID => 2, LokalreaktorResidencePeer::RESIDENCE_ID => 3, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'created_at' => 1, 'subreaktor_id' => 2, 'residence_id' => 3, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/LokalreaktorResidenceMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.LokalreaktorResidenceMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = LokalreaktorResidencePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(LokalreaktorResidencePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(LokalreaktorResidencePeer::ID);
    +
    +		$criteria->addSelectColumn(LokalreaktorResidencePeer::CREATED_AT);
    +
    +		$criteria->addSelectColumn(LokalreaktorResidencePeer::SUBREAKTOR_ID);
    +
    +		$criteria->addSelectColumn(LokalreaktorResidencePeer::RESIDENCE_ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(lokalreaktor_residence.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT lokalreaktor_residence.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = LokalreaktorResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = LokalreaktorResidencePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return LokalreaktorResidencePeer::populateObjects(LokalreaktorResidencePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidencePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseLokalreaktorResidencePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			LokalreaktorResidencePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = LokalreaktorResidencePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorResidencePeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = LokalreaktorResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinResidence(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorResidencePeer::RESIDENCE_ID, ResidencePeer::ID);
    +
    +		$rs = LokalreaktorResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorResidencePeer::addSelectColumns($c);
    +		$startcol = (LokalreaktorResidencePeer::NUM_COLUMNS - LokalreaktorResidencePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(LokalreaktorResidencePeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorResidencePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addLokalreaktorResidence($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initLokalreaktorResidences();
    +				$obj2->addLokalreaktorResidence($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinResidence(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorResidencePeer::addSelectColumns($c);
    +		$startcol = (LokalreaktorResidencePeer::NUM_COLUMNS - LokalreaktorResidencePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ResidencePeer::addSelectColumns($c);
    +
    +		$c->addJoin(LokalreaktorResidencePeer::RESIDENCE_ID, ResidencePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorResidencePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ResidencePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getResidence(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addLokalreaktorResidence($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initLokalreaktorResidences();
    +				$obj2->addLokalreaktorResidence($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorResidencePeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$criteria->addJoin(LokalreaktorResidencePeer::RESIDENCE_ID, ResidencePeer::ID);
    +
    +		$rs = LokalreaktorResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorResidencePeer::addSelectColumns($c);
    +		$startcol2 = (LokalreaktorResidencePeer::NUM_COLUMNS - LokalreaktorResidencePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		ResidencePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ResidencePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(LokalreaktorResidencePeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$c->addJoin(LokalreaktorResidencePeer::RESIDENCE_ID, ResidencePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorResidencePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addLokalreaktorResidence($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initLokalreaktorResidences();
    +				$obj2->addLokalreaktorResidence($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ResidencePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getResidence(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addLokalreaktorResidence($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initLokalreaktorResidences();
    +				$obj3->addLokalreaktorResidence($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorResidencePeer::RESIDENCE_ID, ResidencePeer::ID);
    +
    +		$rs = LokalreaktorResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptResidence(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(LokalreaktorResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(LokalreaktorResidencePeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = LokalreaktorResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorResidencePeer::addSelectColumns($c);
    +		$startcol2 = (LokalreaktorResidencePeer::NUM_COLUMNS - LokalreaktorResidencePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ResidencePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ResidencePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(LokalreaktorResidencePeer::RESIDENCE_ID, ResidencePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorResidencePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ResidencePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getResidence(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addLokalreaktorResidence($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initLokalreaktorResidences();
    +				$obj2->addLokalreaktorResidence($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptResidence(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		LokalreaktorResidencePeer::addSelectColumns($c);
    +		$startcol2 = (LokalreaktorResidencePeer::NUM_COLUMNS - LokalreaktorResidencePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(LokalreaktorResidencePeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = LokalreaktorResidencePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addLokalreaktorResidence($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initLokalreaktorResidences();
    +				$obj2->addLokalreaktorResidence($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return LokalreaktorResidencePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidencePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseLokalreaktorResidencePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(LokalreaktorResidencePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidencePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseLokalreaktorResidencePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidencePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseLokalreaktorResidencePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(LokalreaktorResidencePeer::ID);
    +			$selectCriteria->add(LokalreaktorResidencePeer::ID, $criteria->remove(LokalreaktorResidencePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseLokalreaktorResidencePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseLokalreaktorResidencePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(LokalreaktorResidencePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(LokalreaktorResidencePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof LokalreaktorResidence) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(LokalreaktorResidencePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(LokalreaktorResidence $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(LokalreaktorResidencePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(LokalreaktorResidencePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(LokalreaktorResidencePeer::DATABASE_NAME, LokalreaktorResidencePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = LokalreaktorResidencePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(LokalreaktorResidencePeer::DATABASE_NAME);
    +
    +		$criteria->add(LokalreaktorResidencePeer::ID, $pk);
    +
    +
    +		$v = LokalreaktorResidencePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(LokalreaktorResidencePeer::ID, $pks, Criteria::IN);
    +			$objs = LokalreaktorResidencePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseLokalreaktorResidencePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/LokalreaktorResidenceMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.LokalreaktorResidenceMapBuilder');
    +}
    diff --git a/lib/model/om/BaseMessages.php b/lib/model/om/BaseMessages.php
    new file mode 100644
    index 0000000..893084a
    --- /dev/null
    +++ b/lib/model/om/BaseMessages.php
    @@ -0,0 +1,870 @@
    +id;
    +	}
    +
    +	
    +	public function getToUserId()
    +	{
    +
    +		return $this->to_user_id;
    +	}
    +
    +	
    +	public function getFromUserId()
    +	{
    +
    +		return $this->from_user_id;
    +	}
    +
    +	
    +	public function getSubject()
    +	{
    +
    +		return $this->subject;
    +	}
    +
    +	
    +	public function getMessage()
    +	{
    +
    +		return $this->message;
    +	}
    +
    +	
    +	public function getTimestamp($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->timestamp === null || $this->timestamp === '') {
    +			return null;
    +		} elseif (!is_int($this->timestamp)) {
    +						$ts = strtotime($this->timestamp);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [timestamp] as date/time value: " . var_export($this->timestamp, true));
    +			}
    +		} else {
    +			$ts = $this->timestamp;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getDeletedByFrom()
    +	{
    +
    +		return $this->deleted_by_from;
    +	}
    +
    +	
    +	public function getDeletedByTo()
    +	{
    +
    +		return $this->deleted_by_to;
    +	}
    +
    +	
    +	public function getIsRead()
    +	{
    +
    +		return $this->is_read;
    +	}
    +
    +	
    +	public function getIsIgnored()
    +	{
    +
    +		return $this->is_ignored;
    +	}
    +
    +	
    +	public function getIsArchived()
    +	{
    +
    +		return $this->is_archived;
    +	}
    +
    +	
    +	public function getReplyTo()
    +	{
    +
    +		return $this->reply_to;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = MessagesPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setToUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->to_user_id !== $v) {
    +			$this->to_user_id = $v;
    +			$this->modifiedColumns[] = MessagesPeer::TO_USER_ID;
    +		}
    +
    +		if ($this->asfGuardUserRelatedByToUserId !== null && $this->asfGuardUserRelatedByToUserId->getId() !== $v) {
    +			$this->asfGuardUserRelatedByToUserId = null;
    +		}
    +
    +	} 
    +	
    +	public function setFromUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->from_user_id !== $v) {
    +			$this->from_user_id = $v;
    +			$this->modifiedColumns[] = MessagesPeer::FROM_USER_ID;
    +		}
    +
    +		if ($this->asfGuardUserRelatedByFromUserId !== null && $this->asfGuardUserRelatedByFromUserId->getId() !== $v) {
    +			$this->asfGuardUserRelatedByFromUserId = null;
    +		}
    +
    +	} 
    +	
    +	public function setSubject($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->subject !== $v) {
    +			$this->subject = $v;
    +			$this->modifiedColumns[] = MessagesPeer::SUBJECT;
    +		}
    +
    +	} 
    +	
    +	public function setMessage($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->message !== $v) {
    +			$this->message = $v;
    +			$this->modifiedColumns[] = MessagesPeer::MESSAGE;
    +		}
    +
    +	} 
    +	
    +	public function setTimestamp($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [timestamp] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->timestamp !== $ts) {
    +			$this->timestamp = $ts;
    +			$this->modifiedColumns[] = MessagesPeer::TIMESTAMP;
    +		}
    +
    +	} 
    +	
    +	public function setDeletedByFrom($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->deleted_by_from !== $v || $v === 0) {
    +			$this->deleted_by_from = $v;
    +			$this->modifiedColumns[] = MessagesPeer::DELETED_BY_FROM;
    +		}
    +
    +	} 
    +	
    +	public function setDeletedByTo($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->deleted_by_to !== $v || $v === 0) {
    +			$this->deleted_by_to = $v;
    +			$this->modifiedColumns[] = MessagesPeer::DELETED_BY_TO;
    +		}
    +
    +	} 
    +	
    +	public function setIsRead($v)
    +	{
    +
    +		if ($this->is_read !== $v || $v === false) {
    +			$this->is_read = $v;
    +			$this->modifiedColumns[] = MessagesPeer::IS_READ;
    +		}
    +
    +	} 
    +	
    +	public function setIsIgnored($v)
    +	{
    +
    +		if ($this->is_ignored !== $v || $v === false) {
    +			$this->is_ignored = $v;
    +			$this->modifiedColumns[] = MessagesPeer::IS_IGNORED;
    +		}
    +
    +	} 
    +	
    +	public function setIsArchived($v)
    +	{
    +
    +		if ($this->is_archived !== $v || $v === false) {
    +			$this->is_archived = $v;
    +			$this->modifiedColumns[] = MessagesPeer::IS_ARCHIVED;
    +		}
    +
    +	} 
    +	
    +	public function setReplyTo($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->reply_to !== $v || $v === 0) {
    +			$this->reply_to = $v;
    +			$this->modifiedColumns[] = MessagesPeer::REPLY_TO;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->to_user_id = $rs->getInt($startcol + 1);
    +
    +			$this->from_user_id = $rs->getInt($startcol + 2);
    +
    +			$this->subject = $rs->getString($startcol + 3);
    +
    +			$this->message = $rs->getString($startcol + 4);
    +
    +			$this->timestamp = $rs->getTimestamp($startcol + 5, null);
    +
    +			$this->deleted_by_from = $rs->getInt($startcol + 6);
    +
    +			$this->deleted_by_to = $rs->getInt($startcol + 7);
    +
    +			$this->is_read = $rs->getBoolean($startcol + 8);
    +
    +			$this->is_ignored = $rs->getBoolean($startcol + 9);
    +
    +			$this->is_archived = $rs->getBoolean($startcol + 10);
    +
    +			$this->reply_to = $rs->getInt($startcol + 11);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 12; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating Messages object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessages:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(MessagesPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			MessagesPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseMessages:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessages:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(MessagesPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseMessages:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUserRelatedByToUserId !== null) {
    +				if ($this->asfGuardUserRelatedByToUserId->isModified()) {
    +					$affectedRows += $this->asfGuardUserRelatedByToUserId->save($con);
    +				}
    +				$this->setsfGuardUserRelatedByToUserId($this->asfGuardUserRelatedByToUserId);
    +			}
    +
    +			if ($this->asfGuardUserRelatedByFromUserId !== null) {
    +				if ($this->asfGuardUserRelatedByFromUserId->isModified()) {
    +					$affectedRows += $this->asfGuardUserRelatedByFromUserId->save($con);
    +				}
    +				$this->setsfGuardUserRelatedByFromUserId($this->asfGuardUserRelatedByFromUserId);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = MessagesPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += MessagesPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUserRelatedByToUserId !== null) {
    +				if (!$this->asfGuardUserRelatedByToUserId->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUserRelatedByToUserId->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUserRelatedByFromUserId !== null) {
    +				if (!$this->asfGuardUserRelatedByFromUserId->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUserRelatedByFromUserId->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = MessagesPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = MessagesPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getToUserId();
    +				break;
    +			case 2:
    +				return $this->getFromUserId();
    +				break;
    +			case 3:
    +				return $this->getSubject();
    +				break;
    +			case 4:
    +				return $this->getMessage();
    +				break;
    +			case 5:
    +				return $this->getTimestamp();
    +				break;
    +			case 6:
    +				return $this->getDeletedByFrom();
    +				break;
    +			case 7:
    +				return $this->getDeletedByTo();
    +				break;
    +			case 8:
    +				return $this->getIsRead();
    +				break;
    +			case 9:
    +				return $this->getIsIgnored();
    +				break;
    +			case 10:
    +				return $this->getIsArchived();
    +				break;
    +			case 11:
    +				return $this->getReplyTo();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = MessagesPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getToUserId(),
    +			$keys[2] => $this->getFromUserId(),
    +			$keys[3] => $this->getSubject(),
    +			$keys[4] => $this->getMessage(),
    +			$keys[5] => $this->getTimestamp(),
    +			$keys[6] => $this->getDeletedByFrom(),
    +			$keys[7] => $this->getDeletedByTo(),
    +			$keys[8] => $this->getIsRead(),
    +			$keys[9] => $this->getIsIgnored(),
    +			$keys[10] => $this->getIsArchived(),
    +			$keys[11] => $this->getReplyTo(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = MessagesPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setToUserId($value);
    +				break;
    +			case 2:
    +				$this->setFromUserId($value);
    +				break;
    +			case 3:
    +				$this->setSubject($value);
    +				break;
    +			case 4:
    +				$this->setMessage($value);
    +				break;
    +			case 5:
    +				$this->setTimestamp($value);
    +				break;
    +			case 6:
    +				$this->setDeletedByFrom($value);
    +				break;
    +			case 7:
    +				$this->setDeletedByTo($value);
    +				break;
    +			case 8:
    +				$this->setIsRead($value);
    +				break;
    +			case 9:
    +				$this->setIsIgnored($value);
    +				break;
    +			case 10:
    +				$this->setIsArchived($value);
    +				break;
    +			case 11:
    +				$this->setReplyTo($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = MessagesPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setToUserId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setFromUserId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setSubject($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setMessage($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setTimestamp($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setDeletedByFrom($arr[$keys[6]]);
    +		if (array_key_exists($keys[7], $arr)) $this->setDeletedByTo($arr[$keys[7]]);
    +		if (array_key_exists($keys[8], $arr)) $this->setIsRead($arr[$keys[8]]);
    +		if (array_key_exists($keys[9], $arr)) $this->setIsIgnored($arr[$keys[9]]);
    +		if (array_key_exists($keys[10], $arr)) $this->setIsArchived($arr[$keys[10]]);
    +		if (array_key_exists($keys[11], $arr)) $this->setReplyTo($arr[$keys[11]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(MessagesPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(MessagesPeer::ID)) $criteria->add(MessagesPeer::ID, $this->id);
    +		if ($this->isColumnModified(MessagesPeer::TO_USER_ID)) $criteria->add(MessagesPeer::TO_USER_ID, $this->to_user_id);
    +		if ($this->isColumnModified(MessagesPeer::FROM_USER_ID)) $criteria->add(MessagesPeer::FROM_USER_ID, $this->from_user_id);
    +		if ($this->isColumnModified(MessagesPeer::SUBJECT)) $criteria->add(MessagesPeer::SUBJECT, $this->subject);
    +		if ($this->isColumnModified(MessagesPeer::MESSAGE)) $criteria->add(MessagesPeer::MESSAGE, $this->message);
    +		if ($this->isColumnModified(MessagesPeer::TIMESTAMP)) $criteria->add(MessagesPeer::TIMESTAMP, $this->timestamp);
    +		if ($this->isColumnModified(MessagesPeer::DELETED_BY_FROM)) $criteria->add(MessagesPeer::DELETED_BY_FROM, $this->deleted_by_from);
    +		if ($this->isColumnModified(MessagesPeer::DELETED_BY_TO)) $criteria->add(MessagesPeer::DELETED_BY_TO, $this->deleted_by_to);
    +		if ($this->isColumnModified(MessagesPeer::IS_READ)) $criteria->add(MessagesPeer::IS_READ, $this->is_read);
    +		if ($this->isColumnModified(MessagesPeer::IS_IGNORED)) $criteria->add(MessagesPeer::IS_IGNORED, $this->is_ignored);
    +		if ($this->isColumnModified(MessagesPeer::IS_ARCHIVED)) $criteria->add(MessagesPeer::IS_ARCHIVED, $this->is_archived);
    +		if ($this->isColumnModified(MessagesPeer::REPLY_TO)) $criteria->add(MessagesPeer::REPLY_TO, $this->reply_to);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(MessagesPeer::DATABASE_NAME);
    +
    +		$criteria->add(MessagesPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setToUserId($this->to_user_id);
    +
    +		$copyObj->setFromUserId($this->from_user_id);
    +
    +		$copyObj->setSubject($this->subject);
    +
    +		$copyObj->setMessage($this->message);
    +
    +		$copyObj->setTimestamp($this->timestamp);
    +
    +		$copyObj->setDeletedByFrom($this->deleted_by_from);
    +
    +		$copyObj->setDeletedByTo($this->deleted_by_to);
    +
    +		$copyObj->setIsRead($this->is_read);
    +
    +		$copyObj->setIsIgnored($this->is_ignored);
    +
    +		$copyObj->setIsArchived($this->is_archived);
    +
    +		$copyObj->setReplyTo($this->reply_to);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new MessagesPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUserRelatedByToUserId($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setToUserId(NULL);
    +		} else {
    +			$this->setToUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUserRelatedByToUserId = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUserRelatedByToUserId($con = null)
    +	{
    +		if ($this->asfGuardUserRelatedByToUserId === null && ($this->to_user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUserRelatedByToUserId = sfGuardUserPeer::retrieveByPK($this->to_user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUserRelatedByToUserId;
    +	}
    +
    +	
    +	public function setsfGuardUserRelatedByFromUserId($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFromUserId(NULL);
    +		} else {
    +			$this->setFromUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUserRelatedByFromUserId = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUserRelatedByFromUserId($con = null)
    +	{
    +		if ($this->asfGuardUserRelatedByFromUserId === null && ($this->from_user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUserRelatedByFromUserId = sfGuardUserPeer::retrieveByPK($this->from_user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUserRelatedByFromUserId;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseMessages:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseMessages::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseMessagesIgnoredUser.php b/lib/model/om/BaseMessagesIgnoredUser.php
    new file mode 100644
    index 0000000..cf6bfbd
    --- /dev/null
    +++ b/lib/model/om/BaseMessagesIgnoredUser.php
    @@ -0,0 +1,512 @@
    +id;
    +	}
    +
    +	
    +	public function getUserId()
    +	{
    +
    +		return $this->user_id;
    +	}
    +
    +	
    +	public function getIgnoresUserId()
    +	{
    +
    +		return $this->ignores_user_id;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = MessagesIgnoredUserPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->user_id !== $v) {
    +			$this->user_id = $v;
    +			$this->modifiedColumns[] = MessagesIgnoredUserPeer::USER_ID;
    +		}
    +
    +		if ($this->asfGuardUserRelatedByUserId !== null && $this->asfGuardUserRelatedByUserId->getId() !== $v) {
    +			$this->asfGuardUserRelatedByUserId = null;
    +		}
    +
    +	} 
    +	
    +	public function setIgnoresUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->ignores_user_id !== $v) {
    +			$this->ignores_user_id = $v;
    +			$this->modifiedColumns[] = MessagesIgnoredUserPeer::IGNORES_USER_ID;
    +		}
    +
    +		if ($this->asfGuardUserRelatedByIgnoresUserId !== null && $this->asfGuardUserRelatedByIgnoresUserId->getId() !== $v) {
    +			$this->asfGuardUserRelatedByIgnoresUserId = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->user_id = $rs->getInt($startcol + 1);
    +
    +			$this->ignores_user_id = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating MessagesIgnoredUser object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUser:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(MessagesIgnoredUserPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			MessagesIgnoredUserPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUser:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUser:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(MessagesIgnoredUserPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUser:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUserRelatedByUserId !== null) {
    +				if ($this->asfGuardUserRelatedByUserId->isModified()) {
    +					$affectedRows += $this->asfGuardUserRelatedByUserId->save($con);
    +				}
    +				$this->setsfGuardUserRelatedByUserId($this->asfGuardUserRelatedByUserId);
    +			}
    +
    +			if ($this->asfGuardUserRelatedByIgnoresUserId !== null) {
    +				if ($this->asfGuardUserRelatedByIgnoresUserId->isModified()) {
    +					$affectedRows += $this->asfGuardUserRelatedByIgnoresUserId->save($con);
    +				}
    +				$this->setsfGuardUserRelatedByIgnoresUserId($this->asfGuardUserRelatedByIgnoresUserId);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = MessagesIgnoredUserPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += MessagesIgnoredUserPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUserRelatedByUserId !== null) {
    +				if (!$this->asfGuardUserRelatedByUserId->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUserRelatedByUserId->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUserRelatedByIgnoresUserId !== null) {
    +				if (!$this->asfGuardUserRelatedByIgnoresUserId->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUserRelatedByIgnoresUserId->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = MessagesIgnoredUserPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = MessagesIgnoredUserPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getUserId();
    +				break;
    +			case 2:
    +				return $this->getIgnoresUserId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = MessagesIgnoredUserPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getUserId(),
    +			$keys[2] => $this->getIgnoresUserId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = MessagesIgnoredUserPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setUserId($value);
    +				break;
    +			case 2:
    +				$this->setIgnoresUserId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = MessagesIgnoredUserPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setUserId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setIgnoresUserId($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(MessagesIgnoredUserPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(MessagesIgnoredUserPeer::ID)) $criteria->add(MessagesIgnoredUserPeer::ID, $this->id);
    +		if ($this->isColumnModified(MessagesIgnoredUserPeer::USER_ID)) $criteria->add(MessagesIgnoredUserPeer::USER_ID, $this->user_id);
    +		if ($this->isColumnModified(MessagesIgnoredUserPeer::IGNORES_USER_ID)) $criteria->add(MessagesIgnoredUserPeer::IGNORES_USER_ID, $this->ignores_user_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(MessagesIgnoredUserPeer::DATABASE_NAME);
    +
    +		$criteria->add(MessagesIgnoredUserPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setUserId($this->user_id);
    +
    +		$copyObj->setIgnoresUserId($this->ignores_user_id);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new MessagesIgnoredUserPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUserRelatedByUserId($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUserId(NULL);
    +		} else {
    +			$this->setUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUserRelatedByUserId = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUserRelatedByUserId($con = null)
    +	{
    +		if ($this->asfGuardUserRelatedByUserId === null && ($this->user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUserRelatedByUserId = sfGuardUserPeer::retrieveByPK($this->user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUserRelatedByUserId;
    +	}
    +
    +	
    +	public function setsfGuardUserRelatedByIgnoresUserId($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setIgnoresUserId(NULL);
    +		} else {
    +			$this->setIgnoresUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUserRelatedByIgnoresUserId = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUserRelatedByIgnoresUserId($con = null)
    +	{
    +		if ($this->asfGuardUserRelatedByIgnoresUserId === null && ($this->ignores_user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUserRelatedByIgnoresUserId = sfGuardUserPeer::retrieveByPK($this->ignores_user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUserRelatedByIgnoresUserId;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseMessagesIgnoredUser:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseMessagesIgnoredUser::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseMessagesIgnoredUserPeer.php b/lib/model/om/BaseMessagesIgnoredUserPeer.php
    new file mode 100644
    index 0000000..cd096fa
    --- /dev/null
    +++ b/lib/model/om/BaseMessagesIgnoredUserPeer.php
    @@ -0,0 +1,794 @@
    + array ('Id', 'UserId', 'IgnoresUserId', ),
    +		BasePeer::TYPE_COLNAME => array (MessagesIgnoredUserPeer::ID, MessagesIgnoredUserPeer::USER_ID, MessagesIgnoredUserPeer::IGNORES_USER_ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'user_id', 'ignores_user_id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'UserId' => 1, 'IgnoresUserId' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (MessagesIgnoredUserPeer::ID => 0, MessagesIgnoredUserPeer::USER_ID => 1, MessagesIgnoredUserPeer::IGNORES_USER_ID => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'user_id' => 1, 'ignores_user_id' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/MessagesIgnoredUserMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.MessagesIgnoredUserMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = MessagesIgnoredUserPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(MessagesIgnoredUserPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(MessagesIgnoredUserPeer::ID);
    +
    +		$criteria->addSelectColumn(MessagesIgnoredUserPeer::USER_ID);
    +
    +		$criteria->addSelectColumn(MessagesIgnoredUserPeer::IGNORES_USER_ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(messages_ignored_user.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT messages_ignored_user.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = MessagesIgnoredUserPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = MessagesIgnoredUserPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return MessagesIgnoredUserPeer::populateObjects(MessagesIgnoredUserPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUserPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseMessagesIgnoredUserPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			MessagesIgnoredUserPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = MessagesIgnoredUserPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUserRelatedByUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(MessagesIgnoredUserPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = MessagesIgnoredUserPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUserRelatedByIgnoresUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(MessagesIgnoredUserPeer::IGNORES_USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = MessagesIgnoredUserPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUserRelatedByUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesIgnoredUserPeer::addSelectColumns($c);
    +		$startcol = (MessagesIgnoredUserPeer::NUM_COLUMNS - MessagesIgnoredUserPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(MessagesIgnoredUserPeer::USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesIgnoredUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addMessagesIgnoredUserRelatedByUserId($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initMessagesIgnoredUsersRelatedByUserId();
    +				$obj2->addMessagesIgnoredUserRelatedByUserId($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUserRelatedByIgnoresUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesIgnoredUserPeer::addSelectColumns($c);
    +		$startcol = (MessagesIgnoredUserPeer::NUM_COLUMNS - MessagesIgnoredUserPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(MessagesIgnoredUserPeer::IGNORES_USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesIgnoredUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByIgnoresUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addMessagesIgnoredUserRelatedByIgnoresUserId($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initMessagesIgnoredUsersRelatedByIgnoresUserId();
    +				$obj2->addMessagesIgnoredUserRelatedByIgnoresUserId($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(MessagesIgnoredUserPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(MessagesIgnoredUserPeer::IGNORES_USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = MessagesIgnoredUserPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesIgnoredUserPeer::addSelectColumns($c);
    +		$startcol2 = (MessagesIgnoredUserPeer::NUM_COLUMNS - MessagesIgnoredUserPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(MessagesIgnoredUserPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(MessagesIgnoredUserPeer::IGNORES_USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesIgnoredUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addMessagesIgnoredUserRelatedByUserId($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initMessagesIgnoredUsersRelatedByUserId();
    +				$obj2->addMessagesIgnoredUserRelatedByUserId($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUserRelatedByIgnoresUserId(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addMessagesIgnoredUserRelatedByIgnoresUserId($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initMessagesIgnoredUsersRelatedByIgnoresUserId();
    +				$obj3->addMessagesIgnoredUserRelatedByIgnoresUserId($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUserRelatedByUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = MessagesIgnoredUserPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUserRelatedByIgnoresUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesIgnoredUserPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = MessagesIgnoredUserPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUserRelatedByUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesIgnoredUserPeer::addSelectColumns($c);
    +		$startcol2 = (MessagesIgnoredUserPeer::NUM_COLUMNS - MessagesIgnoredUserPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesIgnoredUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUserRelatedByIgnoresUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesIgnoredUserPeer::addSelectColumns($c);
    +		$startcol2 = (MessagesIgnoredUserPeer::NUM_COLUMNS - MessagesIgnoredUserPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesIgnoredUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return MessagesIgnoredUserPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUserPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseMessagesIgnoredUserPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(MessagesIgnoredUserPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUserPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseMessagesIgnoredUserPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUserPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseMessagesIgnoredUserPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(MessagesIgnoredUserPeer::ID);
    +			$selectCriteria->add(MessagesIgnoredUserPeer::ID, $criteria->remove(MessagesIgnoredUserPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseMessagesIgnoredUserPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseMessagesIgnoredUserPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(MessagesIgnoredUserPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(MessagesIgnoredUserPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof MessagesIgnoredUser) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(MessagesIgnoredUserPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(MessagesIgnoredUser $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(MessagesIgnoredUserPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(MessagesIgnoredUserPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(MessagesIgnoredUserPeer::DATABASE_NAME, MessagesIgnoredUserPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = MessagesIgnoredUserPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(MessagesIgnoredUserPeer::DATABASE_NAME);
    +
    +		$criteria->add(MessagesIgnoredUserPeer::ID, $pk);
    +
    +
    +		$v = MessagesIgnoredUserPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(MessagesIgnoredUserPeer::ID, $pks, Criteria::IN);
    +			$objs = MessagesIgnoredUserPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseMessagesIgnoredUserPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/MessagesIgnoredUserMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.MessagesIgnoredUserMapBuilder');
    +}
    diff --git a/lib/model/om/BaseMessagesPeer.php b/lib/model/om/BaseMessagesPeer.php
    new file mode 100644
    index 0000000..fc537c8
    --- /dev/null
    +++ b/lib/model/om/BaseMessagesPeer.php
    @@ -0,0 +1,839 @@
    + array ('Id', 'ToUserId', 'FromUserId', 'Subject', 'Message', 'Timestamp', 'DeletedByFrom', 'DeletedByTo', 'IsRead', 'IsIgnored', 'IsArchived', 'ReplyTo', ),
    +		BasePeer::TYPE_COLNAME => array (MessagesPeer::ID, MessagesPeer::TO_USER_ID, MessagesPeer::FROM_USER_ID, MessagesPeer::SUBJECT, MessagesPeer::MESSAGE, MessagesPeer::TIMESTAMP, MessagesPeer::DELETED_BY_FROM, MessagesPeer::DELETED_BY_TO, MessagesPeer::IS_READ, MessagesPeer::IS_IGNORED, MessagesPeer::IS_ARCHIVED, MessagesPeer::REPLY_TO, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'to_user_id', 'from_user_id', 'subject', 'message', 'timestamp', 'deleted_by_from', 'deleted_by_to', 'is_read', 'is_ignored', 'is_archived', 'reply_to', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'ToUserId' => 1, 'FromUserId' => 2, 'Subject' => 3, 'Message' => 4, 'Timestamp' => 5, 'DeletedByFrom' => 6, 'DeletedByTo' => 7, 'IsRead' => 8, 'IsIgnored' => 9, 'IsArchived' => 10, 'ReplyTo' => 11, ),
    +		BasePeer::TYPE_COLNAME => array (MessagesPeer::ID => 0, MessagesPeer::TO_USER_ID => 1, MessagesPeer::FROM_USER_ID => 2, MessagesPeer::SUBJECT => 3, MessagesPeer::MESSAGE => 4, MessagesPeer::TIMESTAMP => 5, MessagesPeer::DELETED_BY_FROM => 6, MessagesPeer::DELETED_BY_TO => 7, MessagesPeer::IS_READ => 8, MessagesPeer::IS_IGNORED => 9, MessagesPeer::IS_ARCHIVED => 10, MessagesPeer::REPLY_TO => 11, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'to_user_id' => 1, 'from_user_id' => 2, 'subject' => 3, 'message' => 4, 'timestamp' => 5, 'deleted_by_from' => 6, 'deleted_by_to' => 7, 'is_read' => 8, 'is_ignored' => 9, 'is_archived' => 10, 'reply_to' => 11, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/MessagesMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.MessagesMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = MessagesPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(MessagesPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(MessagesPeer::ID);
    +
    +		$criteria->addSelectColumn(MessagesPeer::TO_USER_ID);
    +
    +		$criteria->addSelectColumn(MessagesPeer::FROM_USER_ID);
    +
    +		$criteria->addSelectColumn(MessagesPeer::SUBJECT);
    +
    +		$criteria->addSelectColumn(MessagesPeer::MESSAGE);
    +
    +		$criteria->addSelectColumn(MessagesPeer::TIMESTAMP);
    +
    +		$criteria->addSelectColumn(MessagesPeer::DELETED_BY_FROM);
    +
    +		$criteria->addSelectColumn(MessagesPeer::DELETED_BY_TO);
    +
    +		$criteria->addSelectColumn(MessagesPeer::IS_READ);
    +
    +		$criteria->addSelectColumn(MessagesPeer::IS_IGNORED);
    +
    +		$criteria->addSelectColumn(MessagesPeer::IS_ARCHIVED);
    +
    +		$criteria->addSelectColumn(MessagesPeer::REPLY_TO);
    +
    +	}
    +
    +	const COUNT = 'COUNT(messages.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT messages.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = MessagesPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = MessagesPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return MessagesPeer::populateObjects(MessagesPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessagesPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseMessagesPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			MessagesPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = MessagesPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUserRelatedByToUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(MessagesPeer::TO_USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = MessagesPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUserRelatedByFromUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(MessagesPeer::FROM_USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = MessagesPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUserRelatedByToUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesPeer::addSelectColumns($c);
    +		$startcol = (MessagesPeer::NUM_COLUMNS - MessagesPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(MessagesPeer::TO_USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByToUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addMessagesRelatedByToUserId($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initMessagessRelatedByToUserId();
    +				$obj2->addMessagesRelatedByToUserId($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUserRelatedByFromUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesPeer::addSelectColumns($c);
    +		$startcol = (MessagesPeer::NUM_COLUMNS - MessagesPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(MessagesPeer::FROM_USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByFromUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addMessagesRelatedByFromUserId($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initMessagessRelatedByFromUserId();
    +				$obj2->addMessagesRelatedByFromUserId($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(MessagesPeer::TO_USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(MessagesPeer::FROM_USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = MessagesPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesPeer::addSelectColumns($c);
    +		$startcol2 = (MessagesPeer::NUM_COLUMNS - MessagesPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(MessagesPeer::TO_USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(MessagesPeer::FROM_USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUserRelatedByToUserId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addMessagesRelatedByToUserId($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initMessagessRelatedByToUserId();
    +				$obj2->addMessagesRelatedByToUserId($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUserRelatedByFromUserId(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addMessagesRelatedByFromUserId($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initMessagessRelatedByFromUserId();
    +				$obj3->addMessagesRelatedByFromUserId($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUserRelatedByToUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = MessagesPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUserRelatedByFromUserId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(MessagesPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = MessagesPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUserRelatedByToUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesPeer::addSelectColumns($c);
    +		$startcol2 = (MessagesPeer::NUM_COLUMNS - MessagesPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUserRelatedByFromUserId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		MessagesPeer::addSelectColumns($c);
    +		$startcol2 = (MessagesPeer::NUM_COLUMNS - MessagesPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = MessagesPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return MessagesPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessagesPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseMessagesPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(MessagesPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseMessagesPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseMessagesPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseMessagesPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseMessagesPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(MessagesPeer::ID);
    +			$selectCriteria->add(MessagesPeer::ID, $criteria->remove(MessagesPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseMessagesPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseMessagesPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(MessagesPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(MessagesPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof Messages) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(MessagesPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(Messages $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(MessagesPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(MessagesPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(MessagesPeer::DATABASE_NAME, MessagesPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = MessagesPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(MessagesPeer::DATABASE_NAME);
    +
    +		$criteria->add(MessagesPeer::ID, $pk);
    +
    +
    +		$v = MessagesPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(MessagesPeer::ID, $pks, Criteria::IN);
    +			$objs = MessagesPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseMessagesPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/MessagesMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.MessagesMapBuilder');
    +}
    diff --git a/lib/model/om/BaseReaktorArtwork.php b/lib/model/om/BaseReaktorArtwork.php
    new file mode 100644
    index 0000000..6783ec0
    --- /dev/null
    +++ b/lib/model/om/BaseReaktorArtwork.php
    @@ -0,0 +1,3039 @@
    +id;
    +	}
    +
    +	
    +	public function getUserId()
    +	{
    +
    +		return $this->user_id;
    +	}
    +
    +	
    +	public function getArtworkIdentifier()
    +	{
    +
    +		return $this->artwork_identifier;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getSubmittedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->submitted_at === null || $this->submitted_at === '') {
    +			return null;
    +		} elseif (!is_int($this->submitted_at)) {
    +						$ts = strtotime($this->submitted_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [submitted_at] as date/time value: " . var_export($this->submitted_at, true));
    +			}
    +		} else {
    +			$ts = $this->submitted_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getActionedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->actioned_at === null || $this->actioned_at === '') {
    +			return null;
    +		} elseif (!is_int($this->actioned_at)) {
    +						$ts = strtotime($this->actioned_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [actioned_at] as date/time value: " . var_export($this->actioned_at, true));
    +			}
    +		} else {
    +			$ts = $this->actioned_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getModifiedFlag($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->modified_flag === null || $this->modified_flag === '') {
    +			return null;
    +		} elseif (!is_int($this->modified_flag)) {
    +						$ts = strtotime($this->modified_flag);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [modified_flag] as date/time value: " . var_export($this->modified_flag, true));
    +			}
    +		} else {
    +			$ts = $this->modified_flag;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getTitle()
    +	{
    +
    +		return $this->title;
    +	}
    +
    +	
    +	public function getActionedBy()
    +	{
    +
    +		return $this->actioned_by;
    +	}
    +
    +	
    +	public function getStatus()
    +	{
    +
    +		return $this->status;
    +	}
    +
    +	
    +	public function getDescription()
    +	{
    +
    +		return $this->description;
    +	}
    +
    +	
    +	public function getModifiedNote()
    +	{
    +
    +		return $this->modified_note;
    +	}
    +
    +	
    +	public function getArtworkOrder()
    +	{
    +
    +		return $this->artwork_order;
    +	}
    +
    +	
    +	public function getAverageRating()
    +	{
    +
    +		return $this->average_rating;
    +	}
    +
    +	
    +	public function getTeamId()
    +	{
    +
    +		return $this->team_id;
    +	}
    +
    +	
    +	public function getUnderDiscussion()
    +	{
    +
    +		return $this->under_discussion;
    +	}
    +
    +	
    +	public function getMultiUser()
    +	{
    +
    +		return $this->multi_user;
    +	}
    +
    +	
    +	public function getFirstFileId()
    +	{
    +
    +		return $this->first_file_id;
    +	}
    +
    +	
    +	public function getDeleted()
    +	{
    +
    +		return $this->deleted;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->user_id !== $v) {
    +			$this->user_id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::USER_ID;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setArtworkIdentifier($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->artwork_identifier !== $v) {
    +			$this->artwork_identifier = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::ARTWORK_IDENTIFIER;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setSubmittedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [submitted_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->submitted_at !== $ts) {
    +			$this->submitted_at = $ts;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::SUBMITTED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setActionedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [actioned_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->actioned_at !== $ts) {
    +			$this->actioned_at = $ts;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::ACTIONED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setModifiedFlag($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [modified_flag] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->modified_flag !== $ts) {
    +			$this->modified_flag = $ts;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::MODIFIED_FLAG;
    +		}
    +
    +	} 
    +	
    +	public function setTitle($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->title !== $v) {
    +			$this->title = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::TITLE;
    +		}
    +
    +	} 
    +	
    +	public function setActionedBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->actioned_by !== $v) {
    +			$this->actioned_by = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::ACTIONED_BY;
    +		}
    +
    +	} 
    +	
    +	public function setStatus($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->status !== $v) {
    +			$this->status = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::STATUS;
    +		}
    +
    +		if ($this->aArtworkStatus !== null && $this->aArtworkStatus->getId() !== $v) {
    +			$this->aArtworkStatus = null;
    +		}
    +
    +	} 
    +	
    +	public function setDescription($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->description !== $v) {
    +			$this->description = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::DESCRIPTION;
    +		}
    +
    +	} 
    +	
    +	public function setModifiedNote($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->modified_note !== $v) {
    +			$this->modified_note = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::MODIFIED_NOTE;
    +		}
    +
    +	} 
    +	
    +	public function setArtworkOrder($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork_order !== $v || $v === 0) {
    +			$this->artwork_order = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::ARTWORK_ORDER;
    +		}
    +
    +	} 
    +	
    +	public function setAverageRating($v)
    +	{
    +
    +		if ($this->average_rating !== $v || $v === 0) {
    +			$this->average_rating = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::AVERAGE_RATING;
    +		}
    +
    +	} 
    +	
    +	public function setTeamId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->team_id !== $v) {
    +			$this->team_id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::TEAM_ID;
    +		}
    +
    +		if ($this->asfGuardGroup !== null && $this->asfGuardGroup->getId() !== $v) {
    +			$this->asfGuardGroup = null;
    +		}
    +
    +	} 
    +	
    +	public function setUnderDiscussion($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->under_discussion !== $v || $v === 0) {
    +			$this->under_discussion = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::UNDER_DISCUSSION;
    +		}
    +
    +	} 
    +	
    +	public function setMultiUser($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->multi_user !== $v || $v === 0) {
    +			$this->multi_user = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::MULTI_USER;
    +		}
    +
    +	} 
    +	
    +	public function setFirstFileId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->first_file_id !== $v) {
    +			$this->first_file_id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::FIRST_FILE_ID;
    +		}
    +
    +		if ($this->aReaktorFile !== null && $this->aReaktorFile->getId() !== $v) {
    +			$this->aReaktorFile = null;
    +		}
    +
    +	} 
    +	
    +	public function setDeleted($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->deleted !== $v || $v === 0) {
    +			$this->deleted = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkPeer::DELETED;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->user_id = $rs->getInt($startcol + 1);
    +
    +			$this->artwork_identifier = $rs->getString($startcol + 2);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 3, null);
    +
    +			$this->submitted_at = $rs->getTimestamp($startcol + 4, null);
    +
    +			$this->actioned_at = $rs->getTimestamp($startcol + 5, null);
    +
    +			$this->modified_flag = $rs->getTimestamp($startcol + 6, null);
    +
    +			$this->title = $rs->getString($startcol + 7);
    +
    +			$this->actioned_by = $rs->getInt($startcol + 8);
    +
    +			$this->status = $rs->getInt($startcol + 9);
    +
    +			$this->description = $rs->getString($startcol + 10);
    +
    +			$this->modified_note = $rs->getString($startcol + 11);
    +
    +			$this->artwork_order = $rs->getInt($startcol + 12);
    +
    +			$this->average_rating = $rs->getFloat($startcol + 13);
    +
    +			$this->team_id = $rs->getInt($startcol + 14);
    +
    +			$this->under_discussion = $rs->getInt($startcol + 15);
    +
    +			$this->multi_user = $rs->getInt($startcol + 16);
    +
    +			$this->first_file_id = $rs->getInt($startcol + 17);
    +
    +			$this->deleted = $rs->getInt($startcol + 18);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 19; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ReaktorArtwork object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtwork:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ReaktorArtworkPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtwork:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtwork:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(ReaktorArtworkPeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseReaktorArtwork:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +			if ($this->aArtworkStatus !== null) {
    +				if ($this->aArtworkStatus->isModified() || $this->aArtworkStatus->getCurrentArtworkStatusI18n()->isModified()) {
    +					$affectedRows += $this->aArtworkStatus->save($con);
    +				}
    +				$this->setArtworkStatus($this->aArtworkStatus);
    +			}
    +
    +			if ($this->asfGuardGroup !== null) {
    +				if ($this->asfGuardGroup->isModified()) {
    +					$affectedRows += $this->asfGuardGroup->save($con);
    +				}
    +				$this->setsfGuardGroup($this->asfGuardGroup);
    +			}
    +
    +			if ($this->aReaktorFile !== null) {
    +				if ($this->aReaktorFile->isModified()) {
    +					$affectedRows += $this->aReaktorFile->save($con);
    +				}
    +				$this->setReaktorFile($this->aReaktorFile);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ReaktorArtworkPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ReaktorArtworkPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collSubreaktorArtworks !== null) {
    +				foreach($this->collSubreaktorArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collRecommendedArtworks !== null) {
    +				foreach($this->collRecommendedArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collReaktorArtworkFiles !== null) {
    +				foreach($this->collReaktorArtworkFiles as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collLokalreaktorArtworks !== null) {
    +				foreach($this->collLokalreaktorArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collRelatedArtworksRelatedByFirstArtwork !== null) {
    +				foreach($this->collRelatedArtworksRelatedByFirstArtwork as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collRelatedArtworksRelatedBySecondArtwork !== null) {
    +				foreach($this->collRelatedArtworksRelatedBySecondArtwork as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collReaktorArtworkHistorysRelatedByArtworkId !== null) {
    +				foreach($this->collReaktorArtworkHistorysRelatedByArtworkId as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collReaktorArtworkHistorysRelatedByFileId !== null) {
    +				foreach($this->collReaktorArtworkHistorysRelatedByFileId as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collCategoryArtworks !== null) {
    +				foreach($this->collCategoryArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleArtworkRelations !== null) {
    +				foreach($this->collArticleArtworkRelations as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collFavourites !== null) {
    +				foreach($this->collFavourites as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aArtworkStatus !== null) {
    +				if (!$this->aArtworkStatus->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArtworkStatus->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardGroup !== null) {
    +				if (!$this->asfGuardGroup->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardGroup->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorFile !== null) {
    +				if (!$this->aReaktorFile->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorFile->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ReaktorArtworkPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collSubreaktorArtworks !== null) {
    +					foreach($this->collSubreaktorArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collRecommendedArtworks !== null) {
    +					foreach($this->collRecommendedArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collReaktorArtworkFiles !== null) {
    +					foreach($this->collReaktorArtworkFiles as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collLokalreaktorArtworks !== null) {
    +					foreach($this->collLokalreaktorArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collRelatedArtworksRelatedByFirstArtwork !== null) {
    +					foreach($this->collRelatedArtworksRelatedByFirstArtwork as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collRelatedArtworksRelatedBySecondArtwork !== null) {
    +					foreach($this->collRelatedArtworksRelatedBySecondArtwork as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collReaktorArtworkHistorysRelatedByArtworkId !== null) {
    +					foreach($this->collReaktorArtworkHistorysRelatedByArtworkId as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collReaktorArtworkHistorysRelatedByFileId !== null) {
    +					foreach($this->collReaktorArtworkHistorysRelatedByFileId as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collCategoryArtworks !== null) {
    +					foreach($this->collCategoryArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleArtworkRelations !== null) {
    +					foreach($this->collArticleArtworkRelations as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collFavourites !== null) {
    +					foreach($this->collFavourites as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReaktorArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getUserId();
    +				break;
    +			case 2:
    +				return $this->getArtworkIdentifier();
    +				break;
    +			case 3:
    +				return $this->getCreatedAt();
    +				break;
    +			case 4:
    +				return $this->getSubmittedAt();
    +				break;
    +			case 5:
    +				return $this->getActionedAt();
    +				break;
    +			case 6:
    +				return $this->getModifiedFlag();
    +				break;
    +			case 7:
    +				return $this->getTitle();
    +				break;
    +			case 8:
    +				return $this->getActionedBy();
    +				break;
    +			case 9:
    +				return $this->getStatus();
    +				break;
    +			case 10:
    +				return $this->getDescription();
    +				break;
    +			case 11:
    +				return $this->getModifiedNote();
    +				break;
    +			case 12:
    +				return $this->getArtworkOrder();
    +				break;
    +			case 13:
    +				return $this->getAverageRating();
    +				break;
    +			case 14:
    +				return $this->getTeamId();
    +				break;
    +			case 15:
    +				return $this->getUnderDiscussion();
    +				break;
    +			case 16:
    +				return $this->getMultiUser();
    +				break;
    +			case 17:
    +				return $this->getFirstFileId();
    +				break;
    +			case 18:
    +				return $this->getDeleted();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReaktorArtworkPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getUserId(),
    +			$keys[2] => $this->getArtworkIdentifier(),
    +			$keys[3] => $this->getCreatedAt(),
    +			$keys[4] => $this->getSubmittedAt(),
    +			$keys[5] => $this->getActionedAt(),
    +			$keys[6] => $this->getModifiedFlag(),
    +			$keys[7] => $this->getTitle(),
    +			$keys[8] => $this->getActionedBy(),
    +			$keys[9] => $this->getStatus(),
    +			$keys[10] => $this->getDescription(),
    +			$keys[11] => $this->getModifiedNote(),
    +			$keys[12] => $this->getArtworkOrder(),
    +			$keys[13] => $this->getAverageRating(),
    +			$keys[14] => $this->getTeamId(),
    +			$keys[15] => $this->getUnderDiscussion(),
    +			$keys[16] => $this->getMultiUser(),
    +			$keys[17] => $this->getFirstFileId(),
    +			$keys[18] => $this->getDeleted(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReaktorArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setUserId($value);
    +				break;
    +			case 2:
    +				$this->setArtworkIdentifier($value);
    +				break;
    +			case 3:
    +				$this->setCreatedAt($value);
    +				break;
    +			case 4:
    +				$this->setSubmittedAt($value);
    +				break;
    +			case 5:
    +				$this->setActionedAt($value);
    +				break;
    +			case 6:
    +				$this->setModifiedFlag($value);
    +				break;
    +			case 7:
    +				$this->setTitle($value);
    +				break;
    +			case 8:
    +				$this->setActionedBy($value);
    +				break;
    +			case 9:
    +				$this->setStatus($value);
    +				break;
    +			case 10:
    +				$this->setDescription($value);
    +				break;
    +			case 11:
    +				$this->setModifiedNote($value);
    +				break;
    +			case 12:
    +				$this->setArtworkOrder($value);
    +				break;
    +			case 13:
    +				$this->setAverageRating($value);
    +				break;
    +			case 14:
    +				$this->setTeamId($value);
    +				break;
    +			case 15:
    +				$this->setUnderDiscussion($value);
    +				break;
    +			case 16:
    +				$this->setMultiUser($value);
    +				break;
    +			case 17:
    +				$this->setFirstFileId($value);
    +				break;
    +			case 18:
    +				$this->setDeleted($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReaktorArtworkPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setUserId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setArtworkIdentifier($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setCreatedAt($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setSubmittedAt($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setActionedAt($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setModifiedFlag($arr[$keys[6]]);
    +		if (array_key_exists($keys[7], $arr)) $this->setTitle($arr[$keys[7]]);
    +		if (array_key_exists($keys[8], $arr)) $this->setActionedBy($arr[$keys[8]]);
    +		if (array_key_exists($keys[9], $arr)) $this->setStatus($arr[$keys[9]]);
    +		if (array_key_exists($keys[10], $arr)) $this->setDescription($arr[$keys[10]]);
    +		if (array_key_exists($keys[11], $arr)) $this->setModifiedNote($arr[$keys[11]]);
    +		if (array_key_exists($keys[12], $arr)) $this->setArtworkOrder($arr[$keys[12]]);
    +		if (array_key_exists($keys[13], $arr)) $this->setAverageRating($arr[$keys[13]]);
    +		if (array_key_exists($keys[14], $arr)) $this->setTeamId($arr[$keys[14]]);
    +		if (array_key_exists($keys[15], $arr)) $this->setUnderDiscussion($arr[$keys[15]]);
    +		if (array_key_exists($keys[16], $arr)) $this->setMultiUser($arr[$keys[16]]);
    +		if (array_key_exists($keys[17], $arr)) $this->setFirstFileId($arr[$keys[17]]);
    +		if (array_key_exists($keys[18], $arr)) $this->setDeleted($arr[$keys[18]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ReaktorArtworkPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ReaktorArtworkPeer::ID)) $criteria->add(ReaktorArtworkPeer::ID, $this->id);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::USER_ID)) $criteria->add(ReaktorArtworkPeer::USER_ID, $this->user_id);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::ARTWORK_IDENTIFIER)) $criteria->add(ReaktorArtworkPeer::ARTWORK_IDENTIFIER, $this->artwork_identifier);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::CREATED_AT)) $criteria->add(ReaktorArtworkPeer::CREATED_AT, $this->created_at);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::SUBMITTED_AT)) $criteria->add(ReaktorArtworkPeer::SUBMITTED_AT, $this->submitted_at);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::ACTIONED_AT)) $criteria->add(ReaktorArtworkPeer::ACTIONED_AT, $this->actioned_at);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::MODIFIED_FLAG)) $criteria->add(ReaktorArtworkPeer::MODIFIED_FLAG, $this->modified_flag);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::TITLE)) $criteria->add(ReaktorArtworkPeer::TITLE, $this->title);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::ACTIONED_BY)) $criteria->add(ReaktorArtworkPeer::ACTIONED_BY, $this->actioned_by);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::STATUS)) $criteria->add(ReaktorArtworkPeer::STATUS, $this->status);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::DESCRIPTION)) $criteria->add(ReaktorArtworkPeer::DESCRIPTION, $this->description);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::MODIFIED_NOTE)) $criteria->add(ReaktorArtworkPeer::MODIFIED_NOTE, $this->modified_note);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::ARTWORK_ORDER)) $criteria->add(ReaktorArtworkPeer::ARTWORK_ORDER, $this->artwork_order);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::AVERAGE_RATING)) $criteria->add(ReaktorArtworkPeer::AVERAGE_RATING, $this->average_rating);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::TEAM_ID)) $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->team_id);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::UNDER_DISCUSSION)) $criteria->add(ReaktorArtworkPeer::UNDER_DISCUSSION, $this->under_discussion);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::MULTI_USER)) $criteria->add(ReaktorArtworkPeer::MULTI_USER, $this->multi_user);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::FIRST_FILE_ID)) $criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->first_file_id);
    +		if ($this->isColumnModified(ReaktorArtworkPeer::DELETED)) $criteria->add(ReaktorArtworkPeer::DELETED, $this->deleted);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ReaktorArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(ReaktorArtworkPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setUserId($this->user_id);
    +
    +		$copyObj->setArtworkIdentifier($this->artwork_identifier);
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +		$copyObj->setSubmittedAt($this->submitted_at);
    +
    +		$copyObj->setActionedAt($this->actioned_at);
    +
    +		$copyObj->setModifiedFlag($this->modified_flag);
    +
    +		$copyObj->setTitle($this->title);
    +
    +		$copyObj->setActionedBy($this->actioned_by);
    +
    +		$copyObj->setStatus($this->status);
    +
    +		$copyObj->setDescription($this->description);
    +
    +		$copyObj->setModifiedNote($this->modified_note);
    +
    +		$copyObj->setArtworkOrder($this->artwork_order);
    +
    +		$copyObj->setAverageRating($this->average_rating);
    +
    +		$copyObj->setTeamId($this->team_id);
    +
    +		$copyObj->setUnderDiscussion($this->under_discussion);
    +
    +		$copyObj->setMultiUser($this->multi_user);
    +
    +		$copyObj->setFirstFileId($this->first_file_id);
    +
    +		$copyObj->setDeleted($this->deleted);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getSubreaktorArtworks() as $relObj) {
    +				$copyObj->addSubreaktorArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getRecommendedArtworks() as $relObj) {
    +				$copyObj->addRecommendedArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getReaktorArtworkFiles() as $relObj) {
    +				$copyObj->addReaktorArtworkFile($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getLokalreaktorArtworks() as $relObj) {
    +				$copyObj->addLokalreaktorArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getRelatedArtworksRelatedByFirstArtwork() as $relObj) {
    +				$copyObj->addRelatedArtworkRelatedByFirstArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getRelatedArtworksRelatedBySecondArtwork() as $relObj) {
    +				$copyObj->addRelatedArtworkRelatedBySecondArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getReaktorArtworkHistorysRelatedByArtworkId() as $relObj) {
    +				$copyObj->addReaktorArtworkHistoryRelatedByArtworkId($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getReaktorArtworkHistorysRelatedByFileId() as $relObj) {
    +				$copyObj->addReaktorArtworkHistoryRelatedByFileId($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getCategoryArtworks() as $relObj) {
    +				$copyObj->addCategoryArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleArtworkRelations() as $relObj) {
    +				$copyObj->addArticleArtworkRelation($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getFavourites() as $relObj) {
    +				$copyObj->addFavourite($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ReaktorArtworkPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUserId(NULL);
    +		} else {
    +			$this->setUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +	
    +	public function setArtworkStatus($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setStatus(NULL);
    +		} else {
    +			$this->setStatus($v->getId());
    +		}
    +
    +
    +		$this->aArtworkStatus = $v;
    +	}
    +
    +
    +	
    +	public function getArtworkStatus($con = null)
    +	{
    +		if ($this->aArtworkStatus === null && ($this->status !== null)) {
    +						include_once 'lib/model/om/BaseArtworkStatusPeer.php';
    +
    +			$this->aArtworkStatus = ArtworkStatusPeer::retrieveByPK($this->status, $con);
    +
    +			
    +		}
    +		return $this->aArtworkStatus;
    +	}
    +
    +	
    +	public function setsfGuardGroup($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setTeamId(NULL);
    +		} else {
    +			$this->setTeamId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardGroup = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardGroup($con = null)
    +	{
    +		if ($this->asfGuardGroup === null && ($this->team_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPeer.php';
    +
    +			$this->asfGuardGroup = sfGuardGroupPeer::retrieveByPK($this->team_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardGroup;
    +	}
    +
    +	
    +	public function setReaktorFile($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFirstFileId(NULL);
    +		} else {
    +			$this->setFirstFileId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorFile = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorFile($con = null)
    +	{
    +		if ($this->aReaktorFile === null && ($this->first_file_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorFilePeer.php';
    +
    +			$this->aReaktorFile = ReaktorFilePeer::retrieveByPK($this->first_file_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorFile;
    +	}
    +
    +	
    +	public function initSubreaktorArtworks()
    +	{
    +		if ($this->collSubreaktorArtworks === null) {
    +			$this->collSubreaktorArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getSubreaktorArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collSubreaktorArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collSubreaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				SubreaktorArtworkPeer::addSelectColumns($criteria);
    +				$this->collSubreaktorArtworks = SubreaktorArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				SubreaktorArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastSubreaktorArtworkCriteria) || !$this->lastSubreaktorArtworkCriteria->equals($criteria)) {
    +					$this->collSubreaktorArtworks = SubreaktorArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastSubreaktorArtworkCriteria = $criteria;
    +		return $this->collSubreaktorArtworks;
    +	}
    +
    +	
    +	public function countSubreaktorArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +		return SubreaktorArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addSubreaktorArtwork(SubreaktorArtwork $l)
    +	{
    +		$this->collSubreaktorArtworks[] = $l;
    +		$l->setReaktorArtwork($this);
    +	}
    +
    +
    +	
    +	public function getSubreaktorArtworksJoinSubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collSubreaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collSubreaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collSubreaktorArtworks = SubreaktorArtworkPeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastSubreaktorArtworkCriteria) || !$this->lastSubreaktorArtworkCriteria->equals($criteria)) {
    +				$this->collSubreaktorArtworks = SubreaktorArtworkPeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		}
    +		$this->lastSubreaktorArtworkCriteria = $criteria;
    +
    +		return $this->collSubreaktorArtworks;
    +	}
    +
    +	
    +	public function initRecommendedArtworks()
    +	{
    +		if ($this->collRecommendedArtworks === null) {
    +			$this->collRecommendedArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getRecommendedArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collRecommendedArtworks = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +				RecommendedArtworkPeer::addSelectColumns($criteria);
    +				$this->collRecommendedArtworks = RecommendedArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +				RecommendedArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastRecommendedArtworkCriteria) || !$this->lastRecommendedArtworkCriteria->equals($criteria)) {
    +					$this->collRecommendedArtworks = RecommendedArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastRecommendedArtworkCriteria = $criteria;
    +		return $this->collRecommendedArtworks;
    +	}
    +
    +	
    +	public function countRecommendedArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +		return RecommendedArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addRecommendedArtwork(RecommendedArtwork $l)
    +	{
    +		$this->collRecommendedArtworks[] = $l;
    +		$l->setReaktorArtwork($this);
    +	}
    +
    +
    +	
    +	public function getRecommendedArtworksJoinSubreaktorRelatedBySubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collRecommendedArtworks = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +				$this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinSubreaktorRelatedBySubreaktor($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +			if (!isset($this->lastRecommendedArtworkCriteria) || !$this->lastRecommendedArtworkCriteria->equals($criteria)) {
    +				$this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinSubreaktorRelatedBySubreaktor($criteria, $con);
    +			}
    +		}
    +		$this->lastRecommendedArtworkCriteria = $criteria;
    +
    +		return $this->collRecommendedArtworks;
    +	}
    +
    +
    +	
    +	public function getRecommendedArtworksJoinSubreaktorRelatedByLocalsubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collRecommendedArtworks = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +				$this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinSubreaktorRelatedByLocalsubreaktor($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +			if (!isset($this->lastRecommendedArtworkCriteria) || !$this->lastRecommendedArtworkCriteria->equals($criteria)) {
    +				$this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinSubreaktorRelatedByLocalsubreaktor($criteria, $con);
    +			}
    +		}
    +		$this->lastRecommendedArtworkCriteria = $criteria;
    +
    +		return $this->collRecommendedArtworks;
    +	}
    +
    +
    +	
    +	public function getRecommendedArtworksJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collRecommendedArtworks = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +				$this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RecommendedArtworkPeer::ARTWORK, $this->getId());
    +
    +			if (!isset($this->lastRecommendedArtworkCriteria) || !$this->lastRecommendedArtworkCriteria->equals($criteria)) {
    +				$this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastRecommendedArtworkCriteria = $criteria;
    +
    +		return $this->collRecommendedArtworks;
    +	}
    +
    +	
    +	public function initReaktorArtworkFiles()
    +	{
    +		if ($this->collReaktorArtworkFiles === null) {
    +			$this->collReaktorArtworkFiles = array();
    +		}
    +	}
    +
    +	
    +	public function getReaktorArtworkFiles($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkFiles === null) {
    +			if ($this->isNew()) {
    +			   $this->collReaktorArtworkFiles = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $this->getId());
    +
    +				ReaktorArtworkFilePeer::addSelectColumns($criteria);
    +				$this->collReaktorArtworkFiles = ReaktorArtworkFilePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $this->getId());
    +
    +				ReaktorArtworkFilePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastReaktorArtworkFileCriteria) || !$this->lastReaktorArtworkFileCriteria->equals($criteria)) {
    +					$this->collReaktorArtworkFiles = ReaktorArtworkFilePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastReaktorArtworkFileCriteria = $criteria;
    +		return $this->collReaktorArtworkFiles;
    +	}
    +
    +	
    +	public function countReaktorArtworkFiles($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $this->getId());
    +
    +		return ReaktorArtworkFilePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addReaktorArtworkFile(ReaktorArtworkFile $l)
    +	{
    +		$this->collReaktorArtworkFiles[] = $l;
    +		$l->setReaktorArtwork($this);
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkFilesJoinReaktorFile($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkFiles === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkFiles = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collReaktorArtworkFiles = ReaktorArtworkFilePeer::doSelectJoinReaktorFile($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkFileCriteria) || !$this->lastReaktorArtworkFileCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkFiles = ReaktorArtworkFilePeer::doSelectJoinReaktorFile($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkFileCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkFiles;
    +	}
    +
    +	
    +	public function initLokalreaktorArtworks()
    +	{
    +		if ($this->collLokalreaktorArtworks === null) {
    +			$this->collLokalreaktorArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getLokalreaktorArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collLokalreaktorArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collLokalreaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(LokalreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				LokalreaktorArtworkPeer::addSelectColumns($criteria);
    +				$this->collLokalreaktorArtworks = LokalreaktorArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(LokalreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				LokalreaktorArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastLokalreaktorArtworkCriteria) || !$this->lastLokalreaktorArtworkCriteria->equals($criteria)) {
    +					$this->collLokalreaktorArtworks = LokalreaktorArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastLokalreaktorArtworkCriteria = $criteria;
    +		return $this->collLokalreaktorArtworks;
    +	}
    +
    +	
    +	public function countLokalreaktorArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(LokalreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +		return LokalreaktorArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addLokalreaktorArtwork(LokalreaktorArtwork $l)
    +	{
    +		$this->collLokalreaktorArtworks[] = $l;
    +		$l->setReaktorArtwork($this);
    +	}
    +
    +
    +	
    +	public function getLokalreaktorArtworksJoinSubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collLokalreaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collLokalreaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(LokalreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collLokalreaktorArtworks = LokalreaktorArtworkPeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(LokalreaktorArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastLokalreaktorArtworkCriteria) || !$this->lastLokalreaktorArtworkCriteria->equals($criteria)) {
    +				$this->collLokalreaktorArtworks = LokalreaktorArtworkPeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		}
    +		$this->lastLokalreaktorArtworkCriteria = $criteria;
    +
    +		return $this->collLokalreaktorArtworks;
    +	}
    +
    +	
    +	public function initRelatedArtworksRelatedByFirstArtwork()
    +	{
    +		if ($this->collRelatedArtworksRelatedByFirstArtwork === null) {
    +			$this->collRelatedArtworksRelatedByFirstArtwork = array();
    +		}
    +	}
    +
    +	
    +	public function getRelatedArtworksRelatedByFirstArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRelatedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRelatedArtworksRelatedByFirstArtwork === null) {
    +			if ($this->isNew()) {
    +			   $this->collRelatedArtworksRelatedByFirstArtwork = array();
    +			} else {
    +
    +				$criteria->add(RelatedArtworkPeer::FIRST_ARTWORK, $this->getId());
    +
    +				RelatedArtworkPeer::addSelectColumns($criteria);
    +				$this->collRelatedArtworksRelatedByFirstArtwork = RelatedArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(RelatedArtworkPeer::FIRST_ARTWORK, $this->getId());
    +
    +				RelatedArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastRelatedArtworkRelatedByFirstArtworkCriteria) || !$this->lastRelatedArtworkRelatedByFirstArtworkCriteria->equals($criteria)) {
    +					$this->collRelatedArtworksRelatedByFirstArtwork = RelatedArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastRelatedArtworkRelatedByFirstArtworkCriteria = $criteria;
    +		return $this->collRelatedArtworksRelatedByFirstArtwork;
    +	}
    +
    +	
    +	public function countRelatedArtworksRelatedByFirstArtwork($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRelatedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(RelatedArtworkPeer::FIRST_ARTWORK, $this->getId());
    +
    +		return RelatedArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addRelatedArtworkRelatedByFirstArtwork(RelatedArtwork $l)
    +	{
    +		$this->collRelatedArtworksRelatedByFirstArtwork[] = $l;
    +		$l->setReaktorArtworkRelatedByFirstArtwork($this);
    +	}
    +
    +
    +	
    +	public function getRelatedArtworksRelatedByFirstArtworkJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRelatedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRelatedArtworksRelatedByFirstArtwork === null) {
    +			if ($this->isNew()) {
    +				$this->collRelatedArtworksRelatedByFirstArtwork = array();
    +			} else {
    +
    +				$criteria->add(RelatedArtworkPeer::FIRST_ARTWORK, $this->getId());
    +
    +				$this->collRelatedArtworksRelatedByFirstArtwork = RelatedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RelatedArtworkPeer::FIRST_ARTWORK, $this->getId());
    +
    +			if (!isset($this->lastRelatedArtworkRelatedByFirstArtworkCriteria) || !$this->lastRelatedArtworkRelatedByFirstArtworkCriteria->equals($criteria)) {
    +				$this->collRelatedArtworksRelatedByFirstArtwork = RelatedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastRelatedArtworkRelatedByFirstArtworkCriteria = $criteria;
    +
    +		return $this->collRelatedArtworksRelatedByFirstArtwork;
    +	}
    +
    +	
    +	public function initRelatedArtworksRelatedBySecondArtwork()
    +	{
    +		if ($this->collRelatedArtworksRelatedBySecondArtwork === null) {
    +			$this->collRelatedArtworksRelatedBySecondArtwork = array();
    +		}
    +	}
    +
    +	
    +	public function getRelatedArtworksRelatedBySecondArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRelatedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRelatedArtworksRelatedBySecondArtwork === null) {
    +			if ($this->isNew()) {
    +			   $this->collRelatedArtworksRelatedBySecondArtwork = array();
    +			} else {
    +
    +				$criteria->add(RelatedArtworkPeer::SECOND_ARTWORK, $this->getId());
    +
    +				RelatedArtworkPeer::addSelectColumns($criteria);
    +				$this->collRelatedArtworksRelatedBySecondArtwork = RelatedArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(RelatedArtworkPeer::SECOND_ARTWORK, $this->getId());
    +
    +				RelatedArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastRelatedArtworkRelatedBySecondArtworkCriteria) || !$this->lastRelatedArtworkRelatedBySecondArtworkCriteria->equals($criteria)) {
    +					$this->collRelatedArtworksRelatedBySecondArtwork = RelatedArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastRelatedArtworkRelatedBySecondArtworkCriteria = $criteria;
    +		return $this->collRelatedArtworksRelatedBySecondArtwork;
    +	}
    +
    +	
    +	public function countRelatedArtworksRelatedBySecondArtwork($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRelatedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(RelatedArtworkPeer::SECOND_ARTWORK, $this->getId());
    +
    +		return RelatedArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addRelatedArtworkRelatedBySecondArtwork(RelatedArtwork $l)
    +	{
    +		$this->collRelatedArtworksRelatedBySecondArtwork[] = $l;
    +		$l->setReaktorArtworkRelatedBySecondArtwork($this);
    +	}
    +
    +
    +	
    +	public function getRelatedArtworksRelatedBySecondArtworkJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRelatedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRelatedArtworksRelatedBySecondArtwork === null) {
    +			if ($this->isNew()) {
    +				$this->collRelatedArtworksRelatedBySecondArtwork = array();
    +			} else {
    +
    +				$criteria->add(RelatedArtworkPeer::SECOND_ARTWORK, $this->getId());
    +
    +				$this->collRelatedArtworksRelatedBySecondArtwork = RelatedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RelatedArtworkPeer::SECOND_ARTWORK, $this->getId());
    +
    +			if (!isset($this->lastRelatedArtworkRelatedBySecondArtworkCriteria) || !$this->lastRelatedArtworkRelatedBySecondArtworkCriteria->equals($criteria)) {
    +				$this->collRelatedArtworksRelatedBySecondArtwork = RelatedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastRelatedArtworkRelatedBySecondArtworkCriteria = $criteria;
    +
    +		return $this->collRelatedArtworksRelatedBySecondArtwork;
    +	}
    +
    +	
    +	public function initReaktorArtworkHistorysRelatedByArtworkId()
    +	{
    +		if ($this->collReaktorArtworkHistorysRelatedByArtworkId === null) {
    +			$this->collReaktorArtworkHistorysRelatedByArtworkId = array();
    +		}
    +	}
    +
    +	
    +	public function getReaktorArtworkHistorysRelatedByArtworkId($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorysRelatedByArtworkId === null) {
    +			if ($this->isNew()) {
    +			   $this->collReaktorArtworkHistorysRelatedByArtworkId = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->getId());
    +
    +				ReaktorArtworkHistoryPeer::addSelectColumns($criteria);
    +				$this->collReaktorArtworkHistorysRelatedByArtworkId = ReaktorArtworkHistoryPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->getId());
    +
    +				ReaktorArtworkHistoryPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria) || !$this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria->equals($criteria)) {
    +					$this->collReaktorArtworkHistorysRelatedByArtworkId = ReaktorArtworkHistoryPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria = $criteria;
    +		return $this->collReaktorArtworkHistorysRelatedByArtworkId;
    +	}
    +
    +	
    +	public function countReaktorArtworkHistorysRelatedByArtworkId($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->getId());
    +
    +		return ReaktorArtworkHistoryPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addReaktorArtworkHistoryRelatedByArtworkId(ReaktorArtworkHistory $l)
    +	{
    +		$this->collReaktorArtworkHistorysRelatedByArtworkId[] = $l;
    +		$l->setReaktorArtworkRelatedByArtworkId($this);
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkHistorysRelatedByArtworkIdJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorysRelatedByArtworkId === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkHistorysRelatedByArtworkId = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collReaktorArtworkHistorysRelatedByArtworkId = ReaktorArtworkHistoryPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria) || !$this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkHistorysRelatedByArtworkId = ReaktorArtworkHistoryPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkHistorysRelatedByArtworkId;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkHistorysRelatedByArtworkIdJoinArtworkStatus($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorysRelatedByArtworkId === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkHistorysRelatedByArtworkId = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collReaktorArtworkHistorysRelatedByArtworkId = ReaktorArtworkHistoryPeer::doSelectJoinArtworkStatus($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria) || !$this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkHistorysRelatedByArtworkId = ReaktorArtworkHistoryPeer::doSelectJoinArtworkStatus($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryRelatedByArtworkIdCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkHistorysRelatedByArtworkId;
    +	}
    +
    +	
    +	public function initReaktorArtworkHistorysRelatedByFileId()
    +	{
    +		if ($this->collReaktorArtworkHistorysRelatedByFileId === null) {
    +			$this->collReaktorArtworkHistorysRelatedByFileId = array();
    +		}
    +	}
    +
    +	
    +	public function getReaktorArtworkHistorysRelatedByFileId($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorysRelatedByFileId === null) {
    +			if ($this->isNew()) {
    +			   $this->collReaktorArtworkHistorysRelatedByFileId = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::FILE_ID, $this->getId());
    +
    +				ReaktorArtworkHistoryPeer::addSelectColumns($criteria);
    +				$this->collReaktorArtworkHistorysRelatedByFileId = ReaktorArtworkHistoryPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::FILE_ID, $this->getId());
    +
    +				ReaktorArtworkHistoryPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastReaktorArtworkHistoryRelatedByFileIdCriteria) || !$this->lastReaktorArtworkHistoryRelatedByFileIdCriteria->equals($criteria)) {
    +					$this->collReaktorArtworkHistorysRelatedByFileId = ReaktorArtworkHistoryPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryRelatedByFileIdCriteria = $criteria;
    +		return $this->collReaktorArtworkHistorysRelatedByFileId;
    +	}
    +
    +	
    +	public function countReaktorArtworkHistorysRelatedByFileId($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ReaktorArtworkHistoryPeer::FILE_ID, $this->getId());
    +
    +		return ReaktorArtworkHistoryPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addReaktorArtworkHistoryRelatedByFileId(ReaktorArtworkHistory $l)
    +	{
    +		$this->collReaktorArtworkHistorysRelatedByFileId[] = $l;
    +		$l->setReaktorArtworkRelatedByFileId($this);
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkHistorysRelatedByFileIdJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorysRelatedByFileId === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkHistorysRelatedByFileId = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::FILE_ID, $this->getId());
    +
    +				$this->collReaktorArtworkHistorysRelatedByFileId = ReaktorArtworkHistoryPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkHistoryPeer::FILE_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkHistoryRelatedByFileIdCriteria) || !$this->lastReaktorArtworkHistoryRelatedByFileIdCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkHistorysRelatedByFileId = ReaktorArtworkHistoryPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryRelatedByFileIdCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkHistorysRelatedByFileId;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkHistorysRelatedByFileIdJoinArtworkStatus($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkHistorysRelatedByFileId === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkHistorysRelatedByFileId = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkHistoryPeer::FILE_ID, $this->getId());
    +
    +				$this->collReaktorArtworkHistorysRelatedByFileId = ReaktorArtworkHistoryPeer::doSelectJoinArtworkStatus($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkHistoryPeer::FILE_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkHistoryRelatedByFileIdCriteria) || !$this->lastReaktorArtworkHistoryRelatedByFileIdCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkHistorysRelatedByFileId = ReaktorArtworkHistoryPeer::doSelectJoinArtworkStatus($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkHistoryRelatedByFileIdCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkHistorysRelatedByFileId;
    +	}
    +
    +	
    +	public function initCategoryArtworks()
    +	{
    +		if ($this->collCategoryArtworks === null) {
    +			$this->collCategoryArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getCategoryArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategoryArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collCategoryArtworks = array();
    +			} else {
    +
    +				$criteria->add(CategoryArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				CategoryArtworkPeer::addSelectColumns($criteria);
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(CategoryArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				CategoryArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) {
    +					$this->collCategoryArtworks = CategoryArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastCategoryArtworkCriteria = $criteria;
    +		return $this->collCategoryArtworks;
    +	}
    +
    +	
    +	public function countCategoryArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(CategoryArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +		return CategoryArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addCategoryArtwork(CategoryArtwork $l)
    +	{
    +		$this->collCategoryArtworks[] = $l;
    +		$l->setReaktorArtwork($this);
    +	}
    +
    +
    +	
    +	public function getCategoryArtworksJoinCategory($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategoryArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collCategoryArtworks = array();
    +			} else {
    +
    +				$criteria->add(CategoryArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinCategory($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(CategoryArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) {
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinCategory($criteria, $con);
    +			}
    +		}
    +		$this->lastCategoryArtworkCriteria = $criteria;
    +
    +		return $this->collCategoryArtworks;
    +	}
    +
    +
    +	
    +	public function getCategoryArtworksJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategoryArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategoryArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collCategoryArtworks = array();
    +			} else {
    +
    +				$criteria->add(CategoryArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(CategoryArtworkPeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) {
    +				$this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastCategoryArtworkCriteria = $criteria;
    +
    +		return $this->collCategoryArtworks;
    +	}
    +
    +	
    +	public function initArticleArtworkRelations()
    +	{
    +		if ($this->collArticleArtworkRelations === null) {
    +			$this->collArticleArtworkRelations = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleArtworkRelations($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArtworkRelations === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleArtworkRelations = array();
    +			} else {
    +
    +				$criteria->add(ArticleArtworkRelationPeer::ARTWORK_ID, $this->getId());
    +
    +				ArticleArtworkRelationPeer::addSelectColumns($criteria);
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleArtworkRelationPeer::ARTWORK_ID, $this->getId());
    +
    +				ArticleArtworkRelationPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) {
    +					$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleArtworkRelationCriteria = $criteria;
    +		return $this->collArticleArtworkRelations;
    +	}
    +
    +	
    +	public function countArticleArtworkRelations($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleArtworkRelationPeer::ARTWORK_ID, $this->getId());
    +
    +		return ArticleArtworkRelationPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleArtworkRelation(ArticleArtworkRelation $l)
    +	{
    +		$this->collArticleArtworkRelations[] = $l;
    +		$l->setReaktorArtwork($this);
    +	}
    +
    +
    +	
    +	public function getArticleArtworkRelationsJoinArticle($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArtworkRelations === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleArtworkRelations = array();
    +			} else {
    +
    +				$criteria->add(ArticleArtworkRelationPeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleArtworkRelationPeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) {
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleArtworkRelationCriteria = $criteria;
    +
    +		return $this->collArticleArtworkRelations;
    +	}
    +
    +
    +	
    +	public function getArticleArtworkRelationsJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleArtworkRelations === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleArtworkRelations = array();
    +			} else {
    +
    +				$criteria->add(ArticleArtworkRelationPeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleArtworkRelationPeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) {
    +				$this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleArtworkRelationCriteria = $criteria;
    +
    +		return $this->collArticleArtworkRelations;
    +	}
    +
    +	
    +	public function initFavourites()
    +	{
    +		if ($this->collFavourites === null) {
    +			$this->collFavourites = array();
    +		}
    +	}
    +
    +	
    +	public function getFavourites($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFavourites === null) {
    +			if ($this->isNew()) {
    +			   $this->collFavourites = array();
    +			} else {
    +
    +				$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +				FavouritePeer::addSelectColumns($criteria);
    +				$this->collFavourites = FavouritePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +				FavouritePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastFavouriteCriteria) || !$this->lastFavouriteCriteria->equals($criteria)) {
    +					$this->collFavourites = FavouritePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastFavouriteCriteria = $criteria;
    +		return $this->collFavourites;
    +	}
    +
    +	
    +	public function countFavourites($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +		return FavouritePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addFavourite(Favourite $l)
    +	{
    +		$this->collFavourites[] = $l;
    +		$l->setReaktorArtwork($this);
    +	}
    +
    +
    +	
    +	public function getFavouritesJoinsfGuardUserRelatedByUserId($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFavourites === null) {
    +			if ($this->isNew()) {
    +				$this->collFavourites = array();
    +			} else {
    +
    +				$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collFavourites = FavouritePeer::doSelectJoinsfGuardUserRelatedByUserId($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastFavouriteCriteria) || !$this->lastFavouriteCriteria->equals($criteria)) {
    +				$this->collFavourites = FavouritePeer::doSelectJoinsfGuardUserRelatedByUserId($criteria, $con);
    +			}
    +		}
    +		$this->lastFavouriteCriteria = $criteria;
    +
    +		return $this->collFavourites;
    +	}
    +
    +
    +	
    +	public function getFavouritesJoinArticle($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFavourites === null) {
    +			if ($this->isNew()) {
    +				$this->collFavourites = array();
    +			} else {
    +
    +				$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collFavourites = FavouritePeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastFavouriteCriteria) || !$this->lastFavouriteCriteria->equals($criteria)) {
    +				$this->collFavourites = FavouritePeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		}
    +		$this->lastFavouriteCriteria = $criteria;
    +
    +		return $this->collFavourites;
    +	}
    +
    +
    +	
    +	public function getFavouritesJoinsfGuardUserRelatedByFriendId($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFavouritePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFavourites === null) {
    +			if ($this->isNew()) {
    +				$this->collFavourites = array();
    +			} else {
    +
    +				$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +				$this->collFavourites = FavouritePeer::doSelectJoinsfGuardUserRelatedByFriendId($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(FavouritePeer::ARTWORK_ID, $this->getId());
    +
    +			if (!isset($this->lastFavouriteCriteria) || !$this->lastFavouriteCriteria->equals($criteria)) {
    +				$this->collFavourites = FavouritePeer::doSelectJoinsfGuardUserRelatedByFriendId($criteria, $con);
    +			}
    +		}
    +		$this->lastFavouriteCriteria = $criteria;
    +
    +		return $this->collFavourites;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseReaktorArtwork:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseReaktorArtwork::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseReaktorArtworkFile.php b/lib/model/om/BaseReaktorArtworkFile.php
    new file mode 100644
    index 0000000..66684e7
    --- /dev/null
    +++ b/lib/model/om/BaseReaktorArtworkFile.php
    @@ -0,0 +1,521 @@
    +artwork_id;
    +	}
    +
    +	
    +	public function getFileId()
    +	{
    +
    +		return $this->file_id;
    +	}
    +
    +	
    +	public function getFileOrder()
    +	{
    +
    +		return $this->file_order;
    +	}
    +
    +	
    +	public function setArtworkId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork_id !== $v) {
    +			$this->artwork_id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkFilePeer::ARTWORK_ID;
    +		}
    +
    +		if ($this->aReaktorArtwork !== null && $this->aReaktorArtwork->getId() !== $v) {
    +			$this->aReaktorArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function setFileId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->file_id !== $v) {
    +			$this->file_id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkFilePeer::FILE_ID;
    +		}
    +
    +		if ($this->aReaktorFile !== null && $this->aReaktorFile->getId() !== $v) {
    +			$this->aReaktorFile = null;
    +		}
    +
    +	} 
    +	
    +	public function setFileOrder($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->file_order !== $v || $v === 1) {
    +			$this->file_order = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkFilePeer::FILE_ORDER;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->artwork_id = $rs->getInt($startcol + 0);
    +
    +			$this->file_id = $rs->getInt($startcol + 1);
    +
    +			$this->file_order = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ReaktorArtworkFile object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFile:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkFilePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ReaktorArtworkFilePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFile:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFile:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkFilePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFile:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aReaktorArtwork !== null) {
    +				if ($this->aReaktorArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtwork->save($con);
    +				}
    +				$this->setReaktorArtwork($this->aReaktorArtwork);
    +			}
    +
    +			if ($this->aReaktorFile !== null) {
    +				if ($this->aReaktorFile->isModified()) {
    +					$affectedRows += $this->aReaktorFile->save($con);
    +				}
    +				$this->setReaktorFile($this->aReaktorFile);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ReaktorArtworkFilePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ReaktorArtworkFilePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aReaktorArtwork !== null) {
    +				if (!$this->aReaktorArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtwork->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorFile !== null) {
    +				if (!$this->aReaktorFile->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorFile->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ReaktorArtworkFilePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReaktorArtworkFilePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getArtworkId();
    +				break;
    +			case 1:
    +				return $this->getFileId();
    +				break;
    +			case 2:
    +				return $this->getFileOrder();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReaktorArtworkFilePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getArtworkId(),
    +			$keys[1] => $this->getFileId(),
    +			$keys[2] => $this->getFileOrder(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReaktorArtworkFilePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setArtworkId($value);
    +				break;
    +			case 1:
    +				$this->setFileId($value);
    +				break;
    +			case 2:
    +				$this->setFileOrder($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReaktorArtworkFilePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setArtworkId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setFileId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setFileOrder($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ReaktorArtworkFilePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ReaktorArtworkFilePeer::ARTWORK_ID)) $criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $this->artwork_id);
    +		if ($this->isColumnModified(ReaktorArtworkFilePeer::FILE_ID)) $criteria->add(ReaktorArtworkFilePeer::FILE_ID, $this->file_id);
    +		if ($this->isColumnModified(ReaktorArtworkFilePeer::FILE_ORDER)) $criteria->add(ReaktorArtworkFilePeer::FILE_ORDER, $this->file_order);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ReaktorArtworkFilePeer::DATABASE_NAME);
    +
    +		$criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $this->artwork_id);
    +		$criteria->add(ReaktorArtworkFilePeer::FILE_ID, $this->file_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getArtworkId();
    +
    +		$pks[1] = $this->getFileId();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setArtworkId($keys[0]);
    +
    +		$this->setFileId($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setFileOrder($this->file_order);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setArtworkId(NULL); 
    +		$copyObj->setFileId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ReaktorArtworkFilePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setReaktorArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArtworkId(NULL);
    +		} else {
    +			$this->setArtworkId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtwork === null && ($this->artwork_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtwork = ReaktorArtworkPeer::retrieveByPK($this->artwork_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtwork;
    +	}
    +
    +	
    +	public function setReaktorFile($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFileId(NULL);
    +		} else {
    +			$this->setFileId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorFile = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorFile($con = null)
    +	{
    +		if ($this->aReaktorFile === null && ($this->file_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorFilePeer.php';
    +
    +			$this->aReaktorFile = ReaktorFilePeer::retrieveByPK($this->file_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorFile;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseReaktorArtworkFile:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseReaktorArtworkFile::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseReaktorArtworkFilePeer.php b/lib/model/om/BaseReaktorArtworkFilePeer.php
    new file mode 100644
    index 0000000..4809ec9
    --- /dev/null
    +++ b/lib/model/om/BaseReaktorArtworkFilePeer.php
    @@ -0,0 +1,844 @@
    + array ('ArtworkId', 'FileId', 'FileOrder', ),
    +		BasePeer::TYPE_COLNAME => array (ReaktorArtworkFilePeer::ARTWORK_ID, ReaktorArtworkFilePeer::FILE_ID, ReaktorArtworkFilePeer::FILE_ORDER, ),
    +		BasePeer::TYPE_FIELDNAME => array ('artwork_id', 'file_id', 'file_order', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('ArtworkId' => 0, 'FileId' => 1, 'FileOrder' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (ReaktorArtworkFilePeer::ARTWORK_ID => 0, ReaktorArtworkFilePeer::FILE_ID => 1, ReaktorArtworkFilePeer::FILE_ORDER => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('artwork_id' => 0, 'file_id' => 1, 'file_order' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ReaktorArtworkFileMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ReaktorArtworkFileMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ReaktorArtworkFilePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ReaktorArtworkFilePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ReaktorArtworkFilePeer::ARTWORK_ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkFilePeer::FILE_ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkFilePeer::FILE_ORDER);
    +
    +	}
    +
    +	const COUNT = 'COUNT(reaktor_artwork_file.ARTWORK_ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT reaktor_artwork_file.ARTWORK_ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ReaktorArtworkFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ReaktorArtworkFilePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ReaktorArtworkFilePeer::populateObjects(ReaktorArtworkFilePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFilePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkFilePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ReaktorArtworkFilePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ReaktorArtworkFilePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = ReaktorArtworkFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = ReaktorArtworkFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkFilePeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkFilePeer::NUM_COLUMNS - ReaktorArtworkFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtworkFile($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkFiles();
    +				$obj2->addReaktorArtworkFile($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkFilePeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkFilePeer::NUM_COLUMNS - ReaktorArtworkFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorFilePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtworkFile($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkFiles();
    +				$obj2->addReaktorArtworkFile($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = ReaktorArtworkFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkFilePeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkFilePeer::NUM_COLUMNS - ReaktorArtworkFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtworkFile($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkFiles();
    +				$obj2->addReaktorArtworkFile($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorFile(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtworkFile($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworkFiles();
    +				$obj3->addReaktorArtworkFile($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = ReaktorArtworkFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = ReaktorArtworkFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkFilePeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkFilePeer::NUM_COLUMNS - ReaktorArtworkFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkFilePeer::FILE_ID, ReaktorFilePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtworkFile($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkFiles();
    +				$obj2->addReaktorArtworkFile($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkFilePeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkFilePeer::NUM_COLUMNS - ReaktorArtworkFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkFilePeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtworkFile($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkFiles();
    +				$obj2->addReaktorArtworkFile($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ReaktorArtworkFilePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFilePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReaktorArtworkFilePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFilePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkFilePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFilePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReaktorArtworkFilePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ReaktorArtworkFilePeer::ARTWORK_ID);
    +			$selectCriteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $criteria->remove(ReaktorArtworkFilePeer::ARTWORK_ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(ReaktorArtworkFilePeer::FILE_ID);
    +			$selectCriteria->add(ReaktorArtworkFilePeer::FILE_ID, $criteria->remove(ReaktorArtworkFilePeer::FILE_ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkFilePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkFilePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ReaktorArtworkFilePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkFilePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ReaktorArtworkFile) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $vals[0], Criteria::IN);
    +			$criteria->add(ReaktorArtworkFilePeer::FILE_ID, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ReaktorArtworkFile $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ReaktorArtworkFilePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ReaktorArtworkFilePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ReaktorArtworkFilePeer::DATABASE_NAME, ReaktorArtworkFilePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ReaktorArtworkFilePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $artwork_id, $file_id, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(ReaktorArtworkFilePeer::ARTWORK_ID, $artwork_id);
    +		$criteria->add(ReaktorArtworkFilePeer::FILE_ID, $file_id);
    +		$v = ReaktorArtworkFilePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseReaktorArtworkFilePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ReaktorArtworkFileMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ReaktorArtworkFileMapBuilder');
    +}
    diff --git a/lib/model/om/BaseReaktorArtworkHistory.php b/lib/model/om/BaseReaktorArtworkHistory.php
    new file mode 100644
    index 0000000..e6150d2
    --- /dev/null
    +++ b/lib/model/om/BaseReaktorArtworkHistory.php
    @@ -0,0 +1,847 @@
    +id;
    +	}
    +
    +	
    +	public function getArtworkId()
    +	{
    +
    +		return $this->artwork_id;
    +	}
    +
    +	
    +	public function getFileId()
    +	{
    +
    +		return $this->file_id;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getModifiedFlag($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->modified_flag === null || $this->modified_flag === '') {
    +			return null;
    +		} elseif (!is_int($this->modified_flag)) {
    +						$ts = strtotime($this->modified_flag);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [modified_flag] as date/time value: " . var_export($this->modified_flag, true));
    +			}
    +		} else {
    +			$ts = $this->modified_flag;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getUserId()
    +	{
    +
    +		return $this->user_id;
    +	}
    +
    +	
    +	public function getStatus()
    +	{
    +
    +		return $this->status;
    +	}
    +
    +	
    +	public function getComment()
    +	{
    +
    +		return $this->comment;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkHistoryPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setArtworkId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork_id !== $v) {
    +			$this->artwork_id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkHistoryPeer::ARTWORK_ID;
    +		}
    +
    +		if ($this->aReaktorArtworkRelatedByArtworkId !== null && $this->aReaktorArtworkRelatedByArtworkId->getId() !== $v) {
    +			$this->aReaktorArtworkRelatedByArtworkId = null;
    +		}
    +
    +	} 
    +	
    +	public function setFileId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->file_id !== $v) {
    +			$this->file_id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkHistoryPeer::FILE_ID;
    +		}
    +
    +		if ($this->aReaktorArtworkRelatedByFileId !== null && $this->aReaktorArtworkRelatedByFileId->getId() !== $v) {
    +			$this->aReaktorArtworkRelatedByFileId = null;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = ReaktorArtworkHistoryPeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setModifiedFlag($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [modified_flag] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->modified_flag !== $ts) {
    +			$this->modified_flag = $ts;
    +			$this->modifiedColumns[] = ReaktorArtworkHistoryPeer::MODIFIED_FLAG;
    +		}
    +
    +	} 
    +	
    +	public function setUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->user_id !== $v) {
    +			$this->user_id = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkHistoryPeer::USER_ID;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setStatus($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->status !== $v) {
    +			$this->status = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkHistoryPeer::STATUS;
    +		}
    +
    +		if ($this->aArtworkStatus !== null && $this->aArtworkStatus->getId() !== $v) {
    +			$this->aArtworkStatus = null;
    +		}
    +
    +	} 
    +	
    +	public function setComment($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->comment !== $v) {
    +			$this->comment = $v;
    +			$this->modifiedColumns[] = ReaktorArtworkHistoryPeer::COMMENT;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->artwork_id = $rs->getInt($startcol + 1);
    +
    +			$this->file_id = $rs->getInt($startcol + 2);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 3, null);
    +
    +			$this->modified_flag = $rs->getTimestamp($startcol + 4, null);
    +
    +			$this->user_id = $rs->getInt($startcol + 5);
    +
    +			$this->status = $rs->getInt($startcol + 6);
    +
    +			$this->comment = $rs->getString($startcol + 7);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 8; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ReaktorArtworkHistory object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistory:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkHistoryPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ReaktorArtworkHistoryPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistory:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistory:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(ReaktorArtworkHistoryPeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkHistoryPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistory:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aReaktorArtworkRelatedByArtworkId !== null) {
    +				if ($this->aReaktorArtworkRelatedByArtworkId->isModified()) {
    +					$affectedRows += $this->aReaktorArtworkRelatedByArtworkId->save($con);
    +				}
    +				$this->setReaktorArtworkRelatedByArtworkId($this->aReaktorArtworkRelatedByArtworkId);
    +			}
    +
    +			if ($this->aReaktorArtworkRelatedByFileId !== null) {
    +				if ($this->aReaktorArtworkRelatedByFileId->isModified()) {
    +					$affectedRows += $this->aReaktorArtworkRelatedByFileId->save($con);
    +				}
    +				$this->setReaktorArtworkRelatedByFileId($this->aReaktorArtworkRelatedByFileId);
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +			if ($this->aArtworkStatus !== null) {
    +				if ($this->aArtworkStatus->isModified() || $this->aArtworkStatus->getCurrentArtworkStatusI18n()->isModified()) {
    +					$affectedRows += $this->aArtworkStatus->save($con);
    +				}
    +				$this->setArtworkStatus($this->aArtworkStatus);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ReaktorArtworkHistoryPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ReaktorArtworkHistoryPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aReaktorArtworkRelatedByArtworkId !== null) {
    +				if (!$this->aReaktorArtworkRelatedByArtworkId->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtworkRelatedByArtworkId->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorArtworkRelatedByFileId !== null) {
    +				if (!$this->aReaktorArtworkRelatedByFileId->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtworkRelatedByFileId->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aArtworkStatus !== null) {
    +				if (!$this->aArtworkStatus->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aArtworkStatus->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ReaktorArtworkHistoryPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReaktorArtworkHistoryPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getArtworkId();
    +				break;
    +			case 2:
    +				return $this->getFileId();
    +				break;
    +			case 3:
    +				return $this->getCreatedAt();
    +				break;
    +			case 4:
    +				return $this->getModifiedFlag();
    +				break;
    +			case 5:
    +				return $this->getUserId();
    +				break;
    +			case 6:
    +				return $this->getStatus();
    +				break;
    +			case 7:
    +				return $this->getComment();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReaktorArtworkHistoryPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getArtworkId(),
    +			$keys[2] => $this->getFileId(),
    +			$keys[3] => $this->getCreatedAt(),
    +			$keys[4] => $this->getModifiedFlag(),
    +			$keys[5] => $this->getUserId(),
    +			$keys[6] => $this->getStatus(),
    +			$keys[7] => $this->getComment(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReaktorArtworkHistoryPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setArtworkId($value);
    +				break;
    +			case 2:
    +				$this->setFileId($value);
    +				break;
    +			case 3:
    +				$this->setCreatedAt($value);
    +				break;
    +			case 4:
    +				$this->setModifiedFlag($value);
    +				break;
    +			case 5:
    +				$this->setUserId($value);
    +				break;
    +			case 6:
    +				$this->setStatus($value);
    +				break;
    +			case 7:
    +				$this->setComment($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReaktorArtworkHistoryPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setArtworkId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setFileId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setCreatedAt($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setModifiedFlag($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setUserId($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setStatus($arr[$keys[6]]);
    +		if (array_key_exists($keys[7], $arr)) $this->setComment($arr[$keys[7]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ReaktorArtworkHistoryPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ReaktorArtworkHistoryPeer::ID)) $criteria->add(ReaktorArtworkHistoryPeer::ID, $this->id);
    +		if ($this->isColumnModified(ReaktorArtworkHistoryPeer::ARTWORK_ID)) $criteria->add(ReaktorArtworkHistoryPeer::ARTWORK_ID, $this->artwork_id);
    +		if ($this->isColumnModified(ReaktorArtworkHistoryPeer::FILE_ID)) $criteria->add(ReaktorArtworkHistoryPeer::FILE_ID, $this->file_id);
    +		if ($this->isColumnModified(ReaktorArtworkHistoryPeer::CREATED_AT)) $criteria->add(ReaktorArtworkHistoryPeer::CREATED_AT, $this->created_at);
    +		if ($this->isColumnModified(ReaktorArtworkHistoryPeer::MODIFIED_FLAG)) $criteria->add(ReaktorArtworkHistoryPeer::MODIFIED_FLAG, $this->modified_flag);
    +		if ($this->isColumnModified(ReaktorArtworkHistoryPeer::USER_ID)) $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->user_id);
    +		if ($this->isColumnModified(ReaktorArtworkHistoryPeer::STATUS)) $criteria->add(ReaktorArtworkHistoryPeer::STATUS, $this->status);
    +		if ($this->isColumnModified(ReaktorArtworkHistoryPeer::COMMENT)) $criteria->add(ReaktorArtworkHistoryPeer::COMMENT, $this->comment);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ReaktorArtworkHistoryPeer::DATABASE_NAME);
    +
    +		$criteria->add(ReaktorArtworkHistoryPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setArtworkId($this->artwork_id);
    +
    +		$copyObj->setFileId($this->file_id);
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +		$copyObj->setModifiedFlag($this->modified_flag);
    +
    +		$copyObj->setUserId($this->user_id);
    +
    +		$copyObj->setStatus($this->status);
    +
    +		$copyObj->setComment($this->comment);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ReaktorArtworkHistoryPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setReaktorArtworkRelatedByArtworkId($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArtworkId(NULL);
    +		} else {
    +			$this->setArtworkId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtworkRelatedByArtworkId = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkRelatedByArtworkId($con = null)
    +	{
    +		if ($this->aReaktorArtworkRelatedByArtworkId === null && ($this->artwork_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtworkRelatedByArtworkId = ReaktorArtworkPeer::retrieveByPK($this->artwork_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtworkRelatedByArtworkId;
    +	}
    +
    +	
    +	public function setReaktorArtworkRelatedByFileId($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFileId(NULL);
    +		} else {
    +			$this->setFileId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtworkRelatedByFileId = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkRelatedByFileId($con = null)
    +	{
    +		if ($this->aReaktorArtworkRelatedByFileId === null && ($this->file_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtworkRelatedByFileId = ReaktorArtworkPeer::retrieveByPK($this->file_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtworkRelatedByFileId;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUserId(NULL);
    +		} else {
    +			$this->setUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +	
    +	public function setArtworkStatus($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setStatus(NULL);
    +		} else {
    +			$this->setStatus($v->getId());
    +		}
    +
    +
    +		$this->aArtworkStatus = $v;
    +	}
    +
    +
    +	
    +	public function getArtworkStatus($con = null)
    +	{
    +		if ($this->aArtworkStatus === null && ($this->status !== null)) {
    +						include_once 'lib/model/om/BaseArtworkStatusPeer.php';
    +
    +			$this->aArtworkStatus = ArtworkStatusPeer::retrieveByPK($this->status, $con);
    +
    +			
    +		}
    +		return $this->aArtworkStatus;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseReaktorArtworkHistory:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseReaktorArtworkHistory::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseReaktorArtworkHistoryPeer.php b/lib/model/om/BaseReaktorArtworkHistoryPeer.php
    new file mode 100644
    index 0000000..a5d0b12
    --- /dev/null
    +++ b/lib/model/om/BaseReaktorArtworkHistoryPeer.php
    @@ -0,0 +1,1431 @@
    + array ('Id', 'ArtworkId', 'FileId', 'CreatedAt', 'ModifiedFlag', 'UserId', 'Status', 'Comment', ),
    +		BasePeer::TYPE_COLNAME => array (ReaktorArtworkHistoryPeer::ID, ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkHistoryPeer::CREATED_AT, ReaktorArtworkHistoryPeer::MODIFIED_FLAG, ReaktorArtworkHistoryPeer::USER_ID, ReaktorArtworkHistoryPeer::STATUS, ReaktorArtworkHistoryPeer::COMMENT, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'artwork_id', 'file_id', 'created_at', 'modified_flag', 'user_id', 'status', 'comment', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'ArtworkId' => 1, 'FileId' => 2, 'CreatedAt' => 3, 'ModifiedFlag' => 4, 'UserId' => 5, 'Status' => 6, 'Comment' => 7, ),
    +		BasePeer::TYPE_COLNAME => array (ReaktorArtworkHistoryPeer::ID => 0, ReaktorArtworkHistoryPeer::ARTWORK_ID => 1, ReaktorArtworkHistoryPeer::FILE_ID => 2, ReaktorArtworkHistoryPeer::CREATED_AT => 3, ReaktorArtworkHistoryPeer::MODIFIED_FLAG => 4, ReaktorArtworkHistoryPeer::USER_ID => 5, ReaktorArtworkHistoryPeer::STATUS => 6, ReaktorArtworkHistoryPeer::COMMENT => 7, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'artwork_id' => 1, 'file_id' => 2, 'created_at' => 3, 'modified_flag' => 4, 'user_id' => 5, 'status' => 6, 'comment' => 7, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ReaktorArtworkHistoryMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ReaktorArtworkHistoryMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ReaktorArtworkHistoryPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ReaktorArtworkHistoryPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::ARTWORK_ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::FILE_ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::CREATED_AT);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::MODIFIED_FLAG);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::USER_ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::STATUS);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COMMENT);
    +
    +	}
    +
    +	const COUNT = 'COUNT(reaktor_artwork_history.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT reaktor_artwork_history.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ReaktorArtworkHistoryPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ReaktorArtworkHistoryPeer::populateObjects(ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistoryPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkHistoryPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ReaktorArtworkHistoryPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ReaktorArtworkHistoryPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinReaktorArtworkRelatedByArtworkId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorArtworkRelatedByFileId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinArtworkStatus(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtworkRelatedByArtworkId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedByArtworkId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtworkHistoryRelatedByArtworkId($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorysRelatedByArtworkId();
    +				$obj2->addReaktorArtworkHistoryRelatedByArtworkId($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtworkRelatedByFileId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedByFileId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtworkHistoryRelatedByFileId($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorysRelatedByFileId();
    +				$obj2->addReaktorArtworkHistoryRelatedByFileId($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtworkHistory($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorys();
    +				$obj2->addReaktorArtworkHistory($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArtworkStatus(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArtworkStatusPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtworkHistory($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorys();
    +				$obj2->addReaktorArtworkHistory($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol6 = $startcol5 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedByArtworkId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtworkHistoryRelatedByArtworkId($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorysRelatedByArtworkId();
    +				$obj2->addReaktorArtworkHistoryRelatedByArtworkId($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtworkRelatedByFileId(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtworkHistoryRelatedByFileId($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworkHistorysRelatedByFileId();
    +				$obj3->addReaktorArtworkHistoryRelatedByFileId($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4 = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addReaktorArtworkHistory($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initReaktorArtworkHistorys();
    +				$obj4->addReaktorArtworkHistory($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj5 = new $cls();
    +			$obj5->hydrate($rs, $startcol5);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj5 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj5->getPrimaryKey() === $obj5->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj5->addReaktorArtworkHistory($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj5->initReaktorArtworkHistorys();
    +				$obj5->addReaktorArtworkHistory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtworkRelatedByArtworkId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtworkRelatedByFileId(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArtworkStatus(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkHistoryPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = ReaktorArtworkHistoryPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtworkRelatedByArtworkId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtworkHistory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorys();
    +				$obj2->addReaktorArtworkHistory($obj1);
    +			}
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtworkHistory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworkHistorys();
    +				$obj3->addReaktorArtworkHistory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtworkRelatedByFileId(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtworkHistory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorys();
    +				$obj2->addReaktorArtworkHistory($obj1);
    +			}
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtworkHistory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworkHistorys();
    +				$obj3->addReaktorArtworkHistory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedByArtworkId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtworkHistoryRelatedByArtworkId($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorysRelatedByArtworkId();
    +				$obj2->addReaktorArtworkHistoryRelatedByArtworkId($obj1);
    +			}
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtworkRelatedByFileId(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtworkHistoryRelatedByFileId($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworkHistorysRelatedByFileId();
    +				$obj3->addReaktorArtworkHistoryRelatedByFileId($obj1);
    +			}
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addReaktorArtworkHistory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initReaktorArtworkHistorys();
    +				$obj4->addReaktorArtworkHistory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArtworkStatus(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkHistoryPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkHistoryPeer::NUM_COLUMNS - ReaktorArtworkHistoryPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::FILE_ID, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkHistoryPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkHistoryPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedByArtworkId(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtworkHistoryRelatedByArtworkId($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworkHistorysRelatedByArtworkId();
    +				$obj2->addReaktorArtworkHistoryRelatedByArtworkId($obj1);
    +			}
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtworkRelatedByFileId(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtworkHistoryRelatedByFileId($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworkHistorysRelatedByFileId();
    +				$obj3->addReaktorArtworkHistoryRelatedByFileId($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addReaktorArtworkHistory($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initReaktorArtworkHistorys();
    +				$obj4->addReaktorArtworkHistory($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ReaktorArtworkHistoryPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistoryPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReaktorArtworkHistoryPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ReaktorArtworkHistoryPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistoryPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkHistoryPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistoryPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReaktorArtworkHistoryPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ReaktorArtworkHistoryPeer::ID);
    +			$selectCriteria->add(ReaktorArtworkHistoryPeer::ID, $criteria->remove(ReaktorArtworkHistoryPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkHistoryPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkHistoryPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ReaktorArtworkHistoryPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkHistoryPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ReaktorArtworkHistory) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ReaktorArtworkHistoryPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ReaktorArtworkHistory $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ReaktorArtworkHistoryPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ReaktorArtworkHistoryPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ReaktorArtworkHistoryPeer::DATABASE_NAME, ReaktorArtworkHistoryPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ReaktorArtworkHistoryPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ReaktorArtworkHistoryPeer::DATABASE_NAME);
    +
    +		$criteria->add(ReaktorArtworkHistoryPeer::ID, $pk);
    +
    +
    +		$v = ReaktorArtworkHistoryPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ReaktorArtworkHistoryPeer::ID, $pks, Criteria::IN);
    +			$objs = ReaktorArtworkHistoryPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseReaktorArtworkHistoryPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ReaktorArtworkHistoryMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ReaktorArtworkHistoryMapBuilder');
    +}
    diff --git a/lib/model/om/BaseReaktorArtworkPeer.php b/lib/model/om/BaseReaktorArtworkPeer.php
    new file mode 100644
    index 0000000..6f46960
    --- /dev/null
    +++ b/lib/model/om/BaseReaktorArtworkPeer.php
    @@ -0,0 +1,1544 @@
    + array ('Id', 'UserId', 'ArtworkIdentifier', 'CreatedAt', 'SubmittedAt', 'ActionedAt', 'ModifiedFlag', 'Title', 'ActionedBy', 'Status', 'Description', 'ModifiedNote', 'ArtworkOrder', 'AverageRating', 'TeamId', 'UnderDiscussion', 'MultiUser', 'FirstFileId', 'Deleted', ),
    +		BasePeer::TYPE_COLNAME => array (ReaktorArtworkPeer::ID, ReaktorArtworkPeer::USER_ID, ReaktorArtworkPeer::ARTWORK_IDENTIFIER, ReaktorArtworkPeer::CREATED_AT, ReaktorArtworkPeer::SUBMITTED_AT, ReaktorArtworkPeer::ACTIONED_AT, ReaktorArtworkPeer::MODIFIED_FLAG, ReaktorArtworkPeer::TITLE, ReaktorArtworkPeer::ACTIONED_BY, ReaktorArtworkPeer::STATUS, ReaktorArtworkPeer::DESCRIPTION, ReaktorArtworkPeer::MODIFIED_NOTE, ReaktorArtworkPeer::ARTWORK_ORDER, ReaktorArtworkPeer::AVERAGE_RATING, ReaktorArtworkPeer::TEAM_ID, ReaktorArtworkPeer::UNDER_DISCUSSION, ReaktorArtworkPeer::MULTI_USER, ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorArtworkPeer::DELETED, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'user_id', 'artwork_identifier', 'created_at', 'submitted_at', 'actioned_at', 'modified_flag', 'title', 'actioned_by', 'status', 'description', 'modified_note', 'artwork_order', 'average_rating', 'team_id', 'under_discussion', 'multi_user', 'first_file_id', 'deleted', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'UserId' => 1, 'ArtworkIdentifier' => 2, 'CreatedAt' => 3, 'SubmittedAt' => 4, 'ActionedAt' => 5, 'ModifiedFlag' => 6, 'Title' => 7, 'ActionedBy' => 8, 'Status' => 9, 'Description' => 10, 'ModifiedNote' => 11, 'ArtworkOrder' => 12, 'AverageRating' => 13, 'TeamId' => 14, 'UnderDiscussion' => 15, 'MultiUser' => 16, 'FirstFileId' => 17, 'Deleted' => 18, ),
    +		BasePeer::TYPE_COLNAME => array (ReaktorArtworkPeer::ID => 0, ReaktorArtworkPeer::USER_ID => 1, ReaktorArtworkPeer::ARTWORK_IDENTIFIER => 2, ReaktorArtworkPeer::CREATED_AT => 3, ReaktorArtworkPeer::SUBMITTED_AT => 4, ReaktorArtworkPeer::ACTIONED_AT => 5, ReaktorArtworkPeer::MODIFIED_FLAG => 6, ReaktorArtworkPeer::TITLE => 7, ReaktorArtworkPeer::ACTIONED_BY => 8, ReaktorArtworkPeer::STATUS => 9, ReaktorArtworkPeer::DESCRIPTION => 10, ReaktorArtworkPeer::MODIFIED_NOTE => 11, ReaktorArtworkPeer::ARTWORK_ORDER => 12, ReaktorArtworkPeer::AVERAGE_RATING => 13, ReaktorArtworkPeer::TEAM_ID => 14, ReaktorArtworkPeer::UNDER_DISCUSSION => 15, ReaktorArtworkPeer::MULTI_USER => 16, ReaktorArtworkPeer::FIRST_FILE_ID => 17, ReaktorArtworkPeer::DELETED => 18, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'user_id' => 1, 'artwork_identifier' => 2, 'created_at' => 3, 'submitted_at' => 4, 'actioned_at' => 5, 'modified_flag' => 6, 'title' => 7, 'actioned_by' => 8, 'status' => 9, 'description' => 10, 'modified_note' => 11, 'artwork_order' => 12, 'average_rating' => 13, 'team_id' => 14, 'under_discussion' => 15, 'multi_user' => 16, 'first_file_id' => 17, 'deleted' => 18, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ReaktorArtworkMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ReaktorArtworkMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ReaktorArtworkPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ReaktorArtworkPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::USER_ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::ARTWORK_IDENTIFIER);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::CREATED_AT);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::SUBMITTED_AT);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::ACTIONED_AT);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::MODIFIED_FLAG);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::TITLE);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::ACTIONED_BY);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::STATUS);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::DESCRIPTION);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::MODIFIED_NOTE);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::ARTWORK_ORDER);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::AVERAGE_RATING);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::TEAM_ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::UNDER_DISCUSSION);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::MULTI_USER);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::FIRST_FILE_ID);
    +
    +		$criteria->addSelectColumn(ReaktorArtworkPeer::DELETED);
    +
    +	}
    +
    +	const COUNT = 'COUNT(reaktor_artwork.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT reaktor_artwork.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ReaktorArtworkPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ReaktorArtworkPeer::populateObjects(ReaktorArtworkPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ReaktorArtworkPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ReaktorArtworkPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinArtworkStatus(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardGroup(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinArtworkStatus(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ArtworkStatusPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardGroup(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardGroupPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardGroupPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardGroup(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorFilePeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorFile(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		sfGuardGroupPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardGroupPeer::NUM_COLUMNS;
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol6 = $startcol5 + ReaktorFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworks();
    +				$obj3->addReaktorArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardGroupPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4 = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardGroup(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addReaktorArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initReaktorArtworks();
    +				$obj4->addReaktorArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj5 = new $cls();
    +			$obj5->hydrate($rs, $startcol5);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj5 = $temp_obj1->getReaktorFile(); 				if ($temp_obj5->getPrimaryKey() === $obj5->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj5->addReaktorArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj5->initReaktorArtworks();
    +				$obj5->addReaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptArtworkStatus(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardGroup(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorFile(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$criteria->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +		$rs = ReaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		sfGuardGroupPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardGroupPeer::NUM_COLUMNS;
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + ReaktorFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1);
    +			}
    +
    +			$omClass = sfGuardGroupPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardGroup(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworks();
    +				$obj3->addReaktorArtwork($obj1);
    +			}
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getReaktorFile(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initReaktorArtworks();
    +				$obj4->addReaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptArtworkStatus(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		sfGuardGroupPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardGroupPeer::NUM_COLUMNS;
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + ReaktorFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1);
    +			}
    +
    +			$omClass = sfGuardGroupPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardGroup(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworks();
    +				$obj3->addReaktorArtwork($obj1);
    +			}
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getReaktorFile(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initReaktorArtworks();
    +				$obj4->addReaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardGroup(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + ReaktorFilePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::FIRST_FILE_ID, ReaktorFilePeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1);
    +			}
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworks();
    +				$obj3->addReaktorArtwork($obj1);
    +			}
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getReaktorFile(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initReaktorArtworks();
    +				$obj4->addReaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorFile(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorArtworkPeer::NUM_COLUMNS - ReaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		ArtworkStatusPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ArtworkStatusPeer::NUM_COLUMNS;
    +
    +		sfGuardGroupPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardGroupPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::STATUS, ArtworkStatusPeer::ID);
    +
    +		$c->addJoin(ReaktorArtworkPeer::TEAM_ID, sfGuardGroupPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorArtworks();
    +				$obj2->addReaktorArtwork($obj1);
    +			}
    +
    +			$omClass = ArtworkStatusPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getArtworkStatus(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initReaktorArtworks();
    +				$obj3->addReaktorArtwork($obj1);
    +			}
    +
    +			$omClass = sfGuardGroupPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardGroup(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addReaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initReaktorArtworks();
    +				$obj4->addReaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ReaktorArtworkPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReaktorArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ReaktorArtworkPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReaktorArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ReaktorArtworkPeer::ID);
    +			$selectCriteria->add(ReaktorArtworkPeer::ID, $criteria->remove(ReaktorArtworkPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReaktorArtworkPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorArtworkPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ReaktorArtworkPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ReaktorArtwork) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ReaktorArtworkPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ReaktorArtwork $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ReaktorArtworkPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ReaktorArtworkPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ReaktorArtworkPeer::DATABASE_NAME, ReaktorArtworkPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ReaktorArtworkPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ReaktorArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(ReaktorArtworkPeer::ID, $pk);
    +
    +
    +		$v = ReaktorArtworkPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ReaktorArtworkPeer::ID, $pks, Criteria::IN);
    +			$objs = ReaktorArtworkPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseReaktorArtworkPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ReaktorArtworkMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ReaktorArtworkMapBuilder');
    +}
    diff --git a/lib/model/om/BaseReaktorFile.php b/lib/model/om/BaseReaktorFile.php
    new file mode 100644
    index 0000000..b6e1128
    --- /dev/null
    +++ b/lib/model/om/BaseReaktorFile.php
    @@ -0,0 +1,1584 @@
    +id;
    +	}
    +
    +	
    +	public function getFilename()
    +	{
    +
    +		return $this->filename;
    +	}
    +
    +	
    +	public function getUserId()
    +	{
    +
    +		return $this->user_id;
    +	}
    +
    +	
    +	public function getRealpath()
    +	{
    +
    +		return $this->realpath;
    +	}
    +
    +	
    +	public function getThumbpath()
    +	{
    +
    +		return $this->thumbpath;
    +	}
    +
    +	
    +	public function getOriginalpath()
    +	{
    +
    +		return $this->originalpath;
    +	}
    +
    +	
    +	public function getOriginalMimetypeId()
    +	{
    +
    +		return $this->original_mimetype_id;
    +	}
    +
    +	
    +	public function getConvertedMimetypeId()
    +	{
    +
    +		return $this->converted_mimetype_id;
    +	}
    +
    +	
    +	public function getThumbnailMimetypeId()
    +	{
    +
    +		return $this->thumbnail_mimetype_id;
    +	}
    +
    +	
    +	public function getUploadedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->uploaded_at === null || $this->uploaded_at === '') {
    +			return null;
    +		} elseif (!is_int($this->uploaded_at)) {
    +						$ts = strtotime($this->uploaded_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [uploaded_at] as date/time value: " . var_export($this->uploaded_at, true));
    +			}
    +		} else {
    +			$ts = $this->uploaded_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getModifiedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->modified_at === null || $this->modified_at === '') {
    +			return null;
    +		} elseif (!is_int($this->modified_at)) {
    +						$ts = strtotime($this->modified_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [modified_at] as date/time value: " . var_export($this->modified_at, true));
    +			}
    +		} else {
    +			$ts = $this->modified_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getReportedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->reported_at === null || $this->reported_at === '') {
    +			return null;
    +		} elseif (!is_int($this->reported_at)) {
    +						$ts = strtotime($this->reported_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [reported_at] as date/time value: " . var_export($this->reported_at, true));
    +			}
    +		} else {
    +			$ts = $this->reported_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getReported()
    +	{
    +
    +		return $this->reported;
    +	}
    +
    +	
    +	public function getTotalReportedEver()
    +	{
    +
    +		return $this->total_reported_ever;
    +	}
    +
    +	
    +	public function getMarkedUnsuitable()
    +	{
    +
    +		return $this->marked_unsuitable;
    +	}
    +
    +	
    +	public function getUnderDiscussion()
    +	{
    +
    +		return $this->under_discussion;
    +	}
    +
    +	
    +	public function getIdentifier()
    +	{
    +
    +		return $this->identifier;
    +	}
    +
    +	
    +	public function getHidden()
    +	{
    +
    +		return $this->hidden;
    +	}
    +
    +	
    +	public function getDeleted()
    +	{
    +
    +		return $this->deleted;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setFilename($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->filename !== $v) {
    +			$this->filename = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::FILENAME;
    +		}
    +
    +	} 
    +	
    +	public function setUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->user_id !== $v) {
    +			$this->user_id = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::USER_ID;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setRealpath($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->realpath !== $v) {
    +			$this->realpath = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::REALPATH;
    +		}
    +
    +	} 
    +	
    +	public function setThumbpath($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->thumbpath !== $v) {
    +			$this->thumbpath = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::THUMBPATH;
    +		}
    +
    +	} 
    +	
    +	public function setOriginalpath($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->originalpath !== $v) {
    +			$this->originalpath = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::ORIGINALPATH;
    +		}
    +
    +	} 
    +	
    +	public function setOriginalMimetypeId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->original_mimetype_id !== $v) {
    +			$this->original_mimetype_id = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::ORIGINAL_MIMETYPE_ID;
    +		}
    +
    +	} 
    +	
    +	public function setConvertedMimetypeId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->converted_mimetype_id !== $v) {
    +			$this->converted_mimetype_id = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::CONVERTED_MIMETYPE_ID;
    +		}
    +
    +	} 
    +	
    +	public function setThumbnailMimetypeId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->thumbnail_mimetype_id !== $v) {
    +			$this->thumbnail_mimetype_id = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::THUMBNAIL_MIMETYPE_ID;
    +		}
    +
    +	} 
    +	
    +	public function setUploadedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [uploaded_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->uploaded_at !== $ts) {
    +			$this->uploaded_at = $ts;
    +			$this->modifiedColumns[] = ReaktorFilePeer::UPLOADED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setModifiedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [modified_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->modified_at !== $ts) {
    +			$this->modified_at = $ts;
    +			$this->modifiedColumns[] = ReaktorFilePeer::MODIFIED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setReportedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [reported_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->reported_at !== $ts) {
    +			$this->reported_at = $ts;
    +			$this->modifiedColumns[] = ReaktorFilePeer::REPORTED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setReported($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->reported !== $v || $v === 0) {
    +			$this->reported = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::REPORTED;
    +		}
    +
    +	} 
    +	
    +	public function setTotalReportedEver($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->total_reported_ever !== $v || $v === 0) {
    +			$this->total_reported_ever = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::TOTAL_REPORTED_EVER;
    +		}
    +
    +	} 
    +	
    +	public function setMarkedUnsuitable($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->marked_unsuitable !== $v || $v === 0) {
    +			$this->marked_unsuitable = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::MARKED_UNSUITABLE;
    +		}
    +
    +	} 
    +	
    +	public function setUnderDiscussion($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->under_discussion !== $v || $v === 0) {
    +			$this->under_discussion = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::UNDER_DISCUSSION;
    +		}
    +
    +	} 
    +	
    +	public function setIdentifier($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->identifier !== $v) {
    +			$this->identifier = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::IDENTIFIER;
    +		}
    +
    +	} 
    +	
    +	public function setHidden($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->hidden !== $v || $v === 0) {
    +			$this->hidden = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::HIDDEN;
    +		}
    +
    +	} 
    +	
    +	public function setDeleted($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->deleted !== $v || $v === 0) {
    +			$this->deleted = $v;
    +			$this->modifiedColumns[] = ReaktorFilePeer::DELETED;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->filename = $rs->getString($startcol + 1);
    +
    +			$this->user_id = $rs->getInt($startcol + 2);
    +
    +			$this->realpath = $rs->getString($startcol + 3);
    +
    +			$this->thumbpath = $rs->getString($startcol + 4);
    +
    +			$this->originalpath = $rs->getString($startcol + 5);
    +
    +			$this->original_mimetype_id = $rs->getInt($startcol + 6);
    +
    +			$this->converted_mimetype_id = $rs->getInt($startcol + 7);
    +
    +			$this->thumbnail_mimetype_id = $rs->getInt($startcol + 8);
    +
    +			$this->uploaded_at = $rs->getTimestamp($startcol + 9, null);
    +
    +			$this->modified_at = $rs->getTimestamp($startcol + 10, null);
    +
    +			$this->reported_at = $rs->getTimestamp($startcol + 11, null);
    +
    +			$this->reported = $rs->getInt($startcol + 12);
    +
    +			$this->total_reported_ever = $rs->getInt($startcol + 13);
    +
    +			$this->marked_unsuitable = $rs->getInt($startcol + 14);
    +
    +			$this->under_discussion = $rs->getInt($startcol + 15);
    +
    +			$this->identifier = $rs->getString($startcol + 16);
    +
    +			$this->hidden = $rs->getInt($startcol + 17);
    +
    +			$this->deleted = $rs->getInt($startcol + 18);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 19; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ReaktorFile object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorFile:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorFilePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ReaktorFilePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReaktorFile:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorFile:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorFilePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseReaktorFile:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ReaktorFilePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ReaktorFilePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collReaktorArtworks !== null) {
    +				foreach($this->collReaktorArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collReaktorArtworkFiles !== null) {
    +				foreach($this->collReaktorArtworkFiles as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collFileMetadatas !== null) {
    +				foreach($this->collFileMetadatas as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ReaktorFilePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collReaktorArtworks !== null) {
    +					foreach($this->collReaktorArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collReaktorArtworkFiles !== null) {
    +					foreach($this->collReaktorArtworkFiles as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collFileMetadatas !== null) {
    +					foreach($this->collFileMetadatas as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReaktorFilePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getFilename();
    +				break;
    +			case 2:
    +				return $this->getUserId();
    +				break;
    +			case 3:
    +				return $this->getRealpath();
    +				break;
    +			case 4:
    +				return $this->getThumbpath();
    +				break;
    +			case 5:
    +				return $this->getOriginalpath();
    +				break;
    +			case 6:
    +				return $this->getOriginalMimetypeId();
    +				break;
    +			case 7:
    +				return $this->getConvertedMimetypeId();
    +				break;
    +			case 8:
    +				return $this->getThumbnailMimetypeId();
    +				break;
    +			case 9:
    +				return $this->getUploadedAt();
    +				break;
    +			case 10:
    +				return $this->getModifiedAt();
    +				break;
    +			case 11:
    +				return $this->getReportedAt();
    +				break;
    +			case 12:
    +				return $this->getReported();
    +				break;
    +			case 13:
    +				return $this->getTotalReportedEver();
    +				break;
    +			case 14:
    +				return $this->getMarkedUnsuitable();
    +				break;
    +			case 15:
    +				return $this->getUnderDiscussion();
    +				break;
    +			case 16:
    +				return $this->getIdentifier();
    +				break;
    +			case 17:
    +				return $this->getHidden();
    +				break;
    +			case 18:
    +				return $this->getDeleted();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReaktorFilePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getFilename(),
    +			$keys[2] => $this->getUserId(),
    +			$keys[3] => $this->getRealpath(),
    +			$keys[4] => $this->getThumbpath(),
    +			$keys[5] => $this->getOriginalpath(),
    +			$keys[6] => $this->getOriginalMimetypeId(),
    +			$keys[7] => $this->getConvertedMimetypeId(),
    +			$keys[8] => $this->getThumbnailMimetypeId(),
    +			$keys[9] => $this->getUploadedAt(),
    +			$keys[10] => $this->getModifiedAt(),
    +			$keys[11] => $this->getReportedAt(),
    +			$keys[12] => $this->getReported(),
    +			$keys[13] => $this->getTotalReportedEver(),
    +			$keys[14] => $this->getMarkedUnsuitable(),
    +			$keys[15] => $this->getUnderDiscussion(),
    +			$keys[16] => $this->getIdentifier(),
    +			$keys[17] => $this->getHidden(),
    +			$keys[18] => $this->getDeleted(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReaktorFilePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setFilename($value);
    +				break;
    +			case 2:
    +				$this->setUserId($value);
    +				break;
    +			case 3:
    +				$this->setRealpath($value);
    +				break;
    +			case 4:
    +				$this->setThumbpath($value);
    +				break;
    +			case 5:
    +				$this->setOriginalpath($value);
    +				break;
    +			case 6:
    +				$this->setOriginalMimetypeId($value);
    +				break;
    +			case 7:
    +				$this->setConvertedMimetypeId($value);
    +				break;
    +			case 8:
    +				$this->setThumbnailMimetypeId($value);
    +				break;
    +			case 9:
    +				$this->setUploadedAt($value);
    +				break;
    +			case 10:
    +				$this->setModifiedAt($value);
    +				break;
    +			case 11:
    +				$this->setReportedAt($value);
    +				break;
    +			case 12:
    +				$this->setReported($value);
    +				break;
    +			case 13:
    +				$this->setTotalReportedEver($value);
    +				break;
    +			case 14:
    +				$this->setMarkedUnsuitable($value);
    +				break;
    +			case 15:
    +				$this->setUnderDiscussion($value);
    +				break;
    +			case 16:
    +				$this->setIdentifier($value);
    +				break;
    +			case 17:
    +				$this->setHidden($value);
    +				break;
    +			case 18:
    +				$this->setDeleted($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReaktorFilePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setFilename($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setUserId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setRealpath($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setThumbpath($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setOriginalpath($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setOriginalMimetypeId($arr[$keys[6]]);
    +		if (array_key_exists($keys[7], $arr)) $this->setConvertedMimetypeId($arr[$keys[7]]);
    +		if (array_key_exists($keys[8], $arr)) $this->setThumbnailMimetypeId($arr[$keys[8]]);
    +		if (array_key_exists($keys[9], $arr)) $this->setUploadedAt($arr[$keys[9]]);
    +		if (array_key_exists($keys[10], $arr)) $this->setModifiedAt($arr[$keys[10]]);
    +		if (array_key_exists($keys[11], $arr)) $this->setReportedAt($arr[$keys[11]]);
    +		if (array_key_exists($keys[12], $arr)) $this->setReported($arr[$keys[12]]);
    +		if (array_key_exists($keys[13], $arr)) $this->setTotalReportedEver($arr[$keys[13]]);
    +		if (array_key_exists($keys[14], $arr)) $this->setMarkedUnsuitable($arr[$keys[14]]);
    +		if (array_key_exists($keys[15], $arr)) $this->setUnderDiscussion($arr[$keys[15]]);
    +		if (array_key_exists($keys[16], $arr)) $this->setIdentifier($arr[$keys[16]]);
    +		if (array_key_exists($keys[17], $arr)) $this->setHidden($arr[$keys[17]]);
    +		if (array_key_exists($keys[18], $arr)) $this->setDeleted($arr[$keys[18]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ReaktorFilePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ReaktorFilePeer::ID)) $criteria->add(ReaktorFilePeer::ID, $this->id);
    +		if ($this->isColumnModified(ReaktorFilePeer::FILENAME)) $criteria->add(ReaktorFilePeer::FILENAME, $this->filename);
    +		if ($this->isColumnModified(ReaktorFilePeer::USER_ID)) $criteria->add(ReaktorFilePeer::USER_ID, $this->user_id);
    +		if ($this->isColumnModified(ReaktorFilePeer::REALPATH)) $criteria->add(ReaktorFilePeer::REALPATH, $this->realpath);
    +		if ($this->isColumnModified(ReaktorFilePeer::THUMBPATH)) $criteria->add(ReaktorFilePeer::THUMBPATH, $this->thumbpath);
    +		if ($this->isColumnModified(ReaktorFilePeer::ORIGINALPATH)) $criteria->add(ReaktorFilePeer::ORIGINALPATH, $this->originalpath);
    +		if ($this->isColumnModified(ReaktorFilePeer::ORIGINAL_MIMETYPE_ID)) $criteria->add(ReaktorFilePeer::ORIGINAL_MIMETYPE_ID, $this->original_mimetype_id);
    +		if ($this->isColumnModified(ReaktorFilePeer::CONVERTED_MIMETYPE_ID)) $criteria->add(ReaktorFilePeer::CONVERTED_MIMETYPE_ID, $this->converted_mimetype_id);
    +		if ($this->isColumnModified(ReaktorFilePeer::THUMBNAIL_MIMETYPE_ID)) $criteria->add(ReaktorFilePeer::THUMBNAIL_MIMETYPE_ID, $this->thumbnail_mimetype_id);
    +		if ($this->isColumnModified(ReaktorFilePeer::UPLOADED_AT)) $criteria->add(ReaktorFilePeer::UPLOADED_AT, $this->uploaded_at);
    +		if ($this->isColumnModified(ReaktorFilePeer::MODIFIED_AT)) $criteria->add(ReaktorFilePeer::MODIFIED_AT, $this->modified_at);
    +		if ($this->isColumnModified(ReaktorFilePeer::REPORTED_AT)) $criteria->add(ReaktorFilePeer::REPORTED_AT, $this->reported_at);
    +		if ($this->isColumnModified(ReaktorFilePeer::REPORTED)) $criteria->add(ReaktorFilePeer::REPORTED, $this->reported);
    +		if ($this->isColumnModified(ReaktorFilePeer::TOTAL_REPORTED_EVER)) $criteria->add(ReaktorFilePeer::TOTAL_REPORTED_EVER, $this->total_reported_ever);
    +		if ($this->isColumnModified(ReaktorFilePeer::MARKED_UNSUITABLE)) $criteria->add(ReaktorFilePeer::MARKED_UNSUITABLE, $this->marked_unsuitable);
    +		if ($this->isColumnModified(ReaktorFilePeer::UNDER_DISCUSSION)) $criteria->add(ReaktorFilePeer::UNDER_DISCUSSION, $this->under_discussion);
    +		if ($this->isColumnModified(ReaktorFilePeer::IDENTIFIER)) $criteria->add(ReaktorFilePeer::IDENTIFIER, $this->identifier);
    +		if ($this->isColumnModified(ReaktorFilePeer::HIDDEN)) $criteria->add(ReaktorFilePeer::HIDDEN, $this->hidden);
    +		if ($this->isColumnModified(ReaktorFilePeer::DELETED)) $criteria->add(ReaktorFilePeer::DELETED, $this->deleted);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ReaktorFilePeer::DATABASE_NAME);
    +
    +		$criteria->add(ReaktorFilePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setFilename($this->filename);
    +
    +		$copyObj->setUserId($this->user_id);
    +
    +		$copyObj->setRealpath($this->realpath);
    +
    +		$copyObj->setThumbpath($this->thumbpath);
    +
    +		$copyObj->setOriginalpath($this->originalpath);
    +
    +		$copyObj->setOriginalMimetypeId($this->original_mimetype_id);
    +
    +		$copyObj->setConvertedMimetypeId($this->converted_mimetype_id);
    +
    +		$copyObj->setThumbnailMimetypeId($this->thumbnail_mimetype_id);
    +
    +		$copyObj->setUploadedAt($this->uploaded_at);
    +
    +		$copyObj->setModifiedAt($this->modified_at);
    +
    +		$copyObj->setReportedAt($this->reported_at);
    +
    +		$copyObj->setReported($this->reported);
    +
    +		$copyObj->setTotalReportedEver($this->total_reported_ever);
    +
    +		$copyObj->setMarkedUnsuitable($this->marked_unsuitable);
    +
    +		$copyObj->setUnderDiscussion($this->under_discussion);
    +
    +		$copyObj->setIdentifier($this->identifier);
    +
    +		$copyObj->setHidden($this->hidden);
    +
    +		$copyObj->setDeleted($this->deleted);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getReaktorArtworks() as $relObj) {
    +				$copyObj->addReaktorArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getReaktorArtworkFiles() as $relObj) {
    +				$copyObj->addReaktorArtworkFile($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getFileMetadatas() as $relObj) {
    +				$copyObj->addFileMetadata($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ReaktorFilePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUserId(NULL);
    +		} else {
    +			$this->setUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +	
    +	public function initReaktorArtworks()
    +	{
    +		if ($this->collReaktorArtworks === null) {
    +			$this->collReaktorArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getReaktorArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collReaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +				ReaktorArtworkPeer::addSelectColumns($criteria);
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +				ReaktorArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) {
    +					$this->collReaktorArtworks = ReaktorArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastReaktorArtworkCriteria = $criteria;
    +		return $this->collReaktorArtworks;
    +	}
    +
    +	
    +	public function countReaktorArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +		return ReaktorArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addReaktorArtwork(ReaktorArtwork $l)
    +	{
    +		$this->collReaktorArtworks[] = $l;
    +		$l->setReaktorFile($this);
    +	}
    +
    +
    +	
    +	public function getReaktorArtworksJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) {
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkCriteria = $criteria;
    +
    +		return $this->collReaktorArtworks;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworksJoinArtworkStatus($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinArtworkStatus($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) {
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinArtworkStatus($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkCriteria = $criteria;
    +
    +		return $this->collReaktorArtworks;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworksJoinsfGuardGroup($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardGroup($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkPeer::FIRST_FILE_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) {
    +				$this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardGroup($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkCriteria = $criteria;
    +
    +		return $this->collReaktorArtworks;
    +	}
    +
    +	
    +	public function initReaktorArtworkFiles()
    +	{
    +		if ($this->collReaktorArtworkFiles === null) {
    +			$this->collReaktorArtworkFiles = array();
    +		}
    +	}
    +
    +	
    +	public function getReaktorArtworkFiles($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkFiles === null) {
    +			if ($this->isNew()) {
    +			   $this->collReaktorArtworkFiles = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkFilePeer::FILE_ID, $this->getId());
    +
    +				ReaktorArtworkFilePeer::addSelectColumns($criteria);
    +				$this->collReaktorArtworkFiles = ReaktorArtworkFilePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ReaktorArtworkFilePeer::FILE_ID, $this->getId());
    +
    +				ReaktorArtworkFilePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastReaktorArtworkFileCriteria) || !$this->lastReaktorArtworkFileCriteria->equals($criteria)) {
    +					$this->collReaktorArtworkFiles = ReaktorArtworkFilePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastReaktorArtworkFileCriteria = $criteria;
    +		return $this->collReaktorArtworkFiles;
    +	}
    +
    +	
    +	public function countReaktorArtworkFiles($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ReaktorArtworkFilePeer::FILE_ID, $this->getId());
    +
    +		return ReaktorArtworkFilePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addReaktorArtworkFile(ReaktorArtworkFile $l)
    +	{
    +		$this->collReaktorArtworkFiles[] = $l;
    +		$l->setReaktorFile($this);
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkFilesJoinReaktorArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseReaktorArtworkFilePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collReaktorArtworkFiles === null) {
    +			if ($this->isNew()) {
    +				$this->collReaktorArtworkFiles = array();
    +			} else {
    +
    +				$criteria->add(ReaktorArtworkFilePeer::FILE_ID, $this->getId());
    +
    +				$this->collReaktorArtworkFiles = ReaktorArtworkFilePeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ReaktorArtworkFilePeer::FILE_ID, $this->getId());
    +
    +			if (!isset($this->lastReaktorArtworkFileCriteria) || !$this->lastReaktorArtworkFileCriteria->equals($criteria)) {
    +				$this->collReaktorArtworkFiles = ReaktorArtworkFilePeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		}
    +		$this->lastReaktorArtworkFileCriteria = $criteria;
    +
    +		return $this->collReaktorArtworkFiles;
    +	}
    +
    +	
    +	public function initFileMetadatas()
    +	{
    +		if ($this->collFileMetadatas === null) {
    +			$this->collFileMetadatas = array();
    +		}
    +	}
    +
    +	
    +	public function getFileMetadatas($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFileMetadataPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collFileMetadatas === null) {
    +			if ($this->isNew()) {
    +			   $this->collFileMetadatas = array();
    +			} else {
    +
    +				$criteria->add(FileMetadataPeer::FILE, $this->getId());
    +
    +				FileMetadataPeer::addSelectColumns($criteria);
    +				$this->collFileMetadatas = FileMetadataPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(FileMetadataPeer::FILE, $this->getId());
    +
    +				FileMetadataPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastFileMetadataCriteria) || !$this->lastFileMetadataCriteria->equals($criteria)) {
    +					$this->collFileMetadatas = FileMetadataPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastFileMetadataCriteria = $criteria;
    +		return $this->collFileMetadatas;
    +	}
    +
    +	
    +	public function countFileMetadatas($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseFileMetadataPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(FileMetadataPeer::FILE, $this->getId());
    +
    +		return FileMetadataPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addFileMetadata(FileMetadata $l)
    +	{
    +		$this->collFileMetadatas[] = $l;
    +		$l->setReaktorFile($this);
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseReaktorFile:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseReaktorFile::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseReaktorFilePeer.php b/lib/model/om/BaseReaktorFilePeer.php
    new file mode 100644
    index 0000000..15d1c2e
    --- /dev/null
    +++ b/lib/model/om/BaseReaktorFilePeer.php
    @@ -0,0 +1,677 @@
    + array ('Id', 'Filename', 'UserId', 'Realpath', 'Thumbpath', 'Originalpath', 'OriginalMimetypeId', 'ConvertedMimetypeId', 'ThumbnailMimetypeId', 'UploadedAt', 'ModifiedAt', 'ReportedAt', 'Reported', 'TotalReportedEver', 'MarkedUnsuitable', 'UnderDiscussion', 'Identifier', 'Hidden', 'Deleted', ),
    +		BasePeer::TYPE_COLNAME => array (ReaktorFilePeer::ID, ReaktorFilePeer::FILENAME, ReaktorFilePeer::USER_ID, ReaktorFilePeer::REALPATH, ReaktorFilePeer::THUMBPATH, ReaktorFilePeer::ORIGINALPATH, ReaktorFilePeer::ORIGINAL_MIMETYPE_ID, ReaktorFilePeer::CONVERTED_MIMETYPE_ID, ReaktorFilePeer::THUMBNAIL_MIMETYPE_ID, ReaktorFilePeer::UPLOADED_AT, ReaktorFilePeer::MODIFIED_AT, ReaktorFilePeer::REPORTED_AT, ReaktorFilePeer::REPORTED, ReaktorFilePeer::TOTAL_REPORTED_EVER, ReaktorFilePeer::MARKED_UNSUITABLE, ReaktorFilePeer::UNDER_DISCUSSION, ReaktorFilePeer::IDENTIFIER, ReaktorFilePeer::HIDDEN, ReaktorFilePeer::DELETED, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'filename', 'user_id', 'realpath', 'thumbpath', 'originalpath', 'original_mimetype_id', 'converted_mimetype_id', 'thumbnail_mimetype_id', 'uploaded_at', 'modified_at', 'reported_at', 'reported', 'total_reported_ever', 'marked_unsuitable', 'under_discussion', 'identifier', 'hidden', 'deleted', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Filename' => 1, 'UserId' => 2, 'Realpath' => 3, 'Thumbpath' => 4, 'Originalpath' => 5, 'OriginalMimetypeId' => 6, 'ConvertedMimetypeId' => 7, 'ThumbnailMimetypeId' => 8, 'UploadedAt' => 9, 'ModifiedAt' => 10, 'ReportedAt' => 11, 'Reported' => 12, 'TotalReportedEver' => 13, 'MarkedUnsuitable' => 14, 'UnderDiscussion' => 15, 'Identifier' => 16, 'Hidden' => 17, 'Deleted' => 18, ),
    +		BasePeer::TYPE_COLNAME => array (ReaktorFilePeer::ID => 0, ReaktorFilePeer::FILENAME => 1, ReaktorFilePeer::USER_ID => 2, ReaktorFilePeer::REALPATH => 3, ReaktorFilePeer::THUMBPATH => 4, ReaktorFilePeer::ORIGINALPATH => 5, ReaktorFilePeer::ORIGINAL_MIMETYPE_ID => 6, ReaktorFilePeer::CONVERTED_MIMETYPE_ID => 7, ReaktorFilePeer::THUMBNAIL_MIMETYPE_ID => 8, ReaktorFilePeer::UPLOADED_AT => 9, ReaktorFilePeer::MODIFIED_AT => 10, ReaktorFilePeer::REPORTED_AT => 11, ReaktorFilePeer::REPORTED => 12, ReaktorFilePeer::TOTAL_REPORTED_EVER => 13, ReaktorFilePeer::MARKED_UNSUITABLE => 14, ReaktorFilePeer::UNDER_DISCUSSION => 15, ReaktorFilePeer::IDENTIFIER => 16, ReaktorFilePeer::HIDDEN => 17, ReaktorFilePeer::DELETED => 18, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'filename' => 1, 'user_id' => 2, 'realpath' => 3, 'thumbpath' => 4, 'originalpath' => 5, 'original_mimetype_id' => 6, 'converted_mimetype_id' => 7, 'thumbnail_mimetype_id' => 8, 'uploaded_at' => 9, 'modified_at' => 10, 'reported_at' => 11, 'reported' => 12, 'total_reported_ever' => 13, 'marked_unsuitable' => 14, 'under_discussion' => 15, 'identifier' => 16, 'hidden' => 17, 'deleted' => 18, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ReaktorFileMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ReaktorFileMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ReaktorFilePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ReaktorFilePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::ID);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::FILENAME);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::USER_ID);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::REALPATH);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::THUMBPATH);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::ORIGINALPATH);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::ORIGINAL_MIMETYPE_ID);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::CONVERTED_MIMETYPE_ID);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::THUMBNAIL_MIMETYPE_ID);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::UPLOADED_AT);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::MODIFIED_AT);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::REPORTED_AT);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::REPORTED);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::TOTAL_REPORTED_EVER);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::MARKED_UNSUITABLE);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::UNDER_DISCUSSION);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::IDENTIFIER);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::HIDDEN);
    +
    +		$criteria->addSelectColumn(ReaktorFilePeer::DELETED);
    +
    +	}
    +
    +	const COUNT = 'COUNT(reaktor_file.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT reaktor_file.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ReaktorFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ReaktorFilePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ReaktorFilePeer::populateObjects(ReaktorFilePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorFilePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorFilePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ReaktorFilePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ReaktorFilePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorFilePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = ReaktorFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol = (ReaktorFilePeer::NUM_COLUMNS - ReaktorFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ReaktorFilePeer::USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addReaktorFile($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initReaktorFiles();
    +				$obj2->addReaktorFile($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReaktorFilePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReaktorFilePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ReaktorFilePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = ReaktorFilePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ReaktorFilePeer::addSelectColumns($c);
    +		$startcol2 = (ReaktorFilePeer::NUM_COLUMNS - ReaktorFilePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ReaktorFilePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ReaktorFilePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addReaktorFile($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initReaktorFiles();
    +				$obj2->addReaktorFile($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ReaktorFilePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorFilePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReaktorFilePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ReaktorFilePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseReaktorFilePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorFilePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReaktorFilePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReaktorFilePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ReaktorFilePeer::ID);
    +			$selectCriteria->add(ReaktorFilePeer::ID, $criteria->remove(ReaktorFilePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReaktorFilePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReaktorFilePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += ReaktorFilePeer::doOnDeleteCascade(new Criteria(), $con);
    +			$affectedRows += BasePeer::doDeleteAll(ReaktorFilePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReaktorFilePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ReaktorFile) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ReaktorFilePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			$affectedRows += ReaktorFilePeer::doOnDeleteCascade($criteria, $con);
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected static function doOnDeleteCascade(Criteria $criteria, Connection $con)
    +	{
    +				$affectedRows = 0;
    +
    +				$objects = ReaktorFilePeer::doSelect($criteria, $con);
    +		foreach($objects as $obj) {
    +
    +
    +			include_once 'lib/model/FileMetadata.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(FileMetadataPeer::FILE, $obj->getId());
    +			$affectedRows += FileMetadataPeer::doDelete($c, $con);
    +		}
    +		return $affectedRows;
    +	}
    +
    +	
    +	public static function doValidate(ReaktorFile $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ReaktorFilePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ReaktorFilePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ReaktorFilePeer::DATABASE_NAME, ReaktorFilePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ReaktorFilePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ReaktorFilePeer::DATABASE_NAME);
    +
    +		$criteria->add(ReaktorFilePeer::ID, $pk);
    +
    +
    +		$v = ReaktorFilePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ReaktorFilePeer::ID, $pks, Criteria::IN);
    +			$objs = ReaktorFilePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseReaktorFilePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ReaktorFileMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ReaktorFileMapBuilder');
    +}
    diff --git a/lib/model/om/BaseRecommendedArtwork.php b/lib/model/om/BaseRecommendedArtwork.php
    new file mode 100644
    index 0000000..9a0aff0
    --- /dev/null
    +++ b/lib/model/om/BaseRecommendedArtwork.php
    @@ -0,0 +1,751 @@
    +id;
    +	}
    +
    +	
    +	public function getArtwork()
    +	{
    +
    +		return $this->artwork;
    +	}
    +
    +	
    +	public function getSubreaktor()
    +	{
    +
    +		return $this->subreaktor;
    +	}
    +
    +	
    +	public function getLocalsubreaktor()
    +	{
    +
    +		return $this->localsubreaktor;
    +	}
    +
    +	
    +	public function getUpdatedBy()
    +	{
    +
    +		return $this->updated_by;
    +	}
    +
    +	
    +	public function getUpdatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->updated_at === null || $this->updated_at === '') {
    +			return null;
    +		} elseif (!is_int($this->updated_at)) {
    +						$ts = strtotime($this->updated_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [updated_at] as date/time value: " . var_export($this->updated_at, true));
    +			}
    +		} else {
    +			$ts = $this->updated_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = RecommendedArtworkPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setArtwork($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork !== $v) {
    +			$this->artwork = $v;
    +			$this->modifiedColumns[] = RecommendedArtworkPeer::ARTWORK;
    +		}
    +
    +		if ($this->aReaktorArtwork !== null && $this->aReaktorArtwork->getId() !== $v) {
    +			$this->aReaktorArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor !== $v) {
    +			$this->subreaktor = $v;
    +			$this->modifiedColumns[] = RecommendedArtworkPeer::SUBREAKTOR;
    +		}
    +
    +		if ($this->aSubreaktorRelatedBySubreaktor !== null && $this->aSubreaktorRelatedBySubreaktor->getId() !== $v) {
    +			$this->aSubreaktorRelatedBySubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function setLocalsubreaktor($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->localsubreaktor !== $v) {
    +			$this->localsubreaktor = $v;
    +			$this->modifiedColumns[] = RecommendedArtworkPeer::LOCALSUBREAKTOR;
    +		}
    +
    +		if ($this->aSubreaktorRelatedByLocalsubreaktor !== null && $this->aSubreaktorRelatedByLocalsubreaktor->getId() !== $v) {
    +			$this->aSubreaktorRelatedByLocalsubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function setUpdatedBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->updated_by !== $v) {
    +			$this->updated_by = $v;
    +			$this->modifiedColumns[] = RecommendedArtworkPeer::UPDATED_BY;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setUpdatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [updated_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->updated_at !== $ts) {
    +			$this->updated_at = $ts;
    +			$this->modifiedColumns[] = RecommendedArtworkPeer::UPDATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->artwork = $rs->getInt($startcol + 1);
    +
    +			$this->subreaktor = $rs->getInt($startcol + 2);
    +
    +			$this->localsubreaktor = $rs->getInt($startcol + 3);
    +
    +			$this->updated_by = $rs->getInt($startcol + 4);
    +
    +			$this->updated_at = $rs->getTimestamp($startcol + 5, null);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 6; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating RecommendedArtwork object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRecommendedArtwork:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(RecommendedArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			RecommendedArtworkPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseRecommendedArtwork:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRecommendedArtwork:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isModified() && !$this->isColumnModified(RecommendedArtworkPeer::UPDATED_AT))
    +    {
    +      $this->setUpdatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(RecommendedArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseRecommendedArtwork:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aReaktorArtwork !== null) {
    +				if ($this->aReaktorArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtwork->save($con);
    +				}
    +				$this->setReaktorArtwork($this->aReaktorArtwork);
    +			}
    +
    +			if ($this->aSubreaktorRelatedBySubreaktor !== null) {
    +				if ($this->aSubreaktorRelatedBySubreaktor->isModified() || $this->aSubreaktorRelatedBySubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktorRelatedBySubreaktor->save($con);
    +				}
    +				$this->setSubreaktorRelatedBySubreaktor($this->aSubreaktorRelatedBySubreaktor);
    +			}
    +
    +			if ($this->aSubreaktorRelatedByLocalsubreaktor !== null) {
    +				if ($this->aSubreaktorRelatedByLocalsubreaktor->isModified() || $this->aSubreaktorRelatedByLocalsubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktorRelatedByLocalsubreaktor->save($con);
    +				}
    +				$this->setSubreaktorRelatedByLocalsubreaktor($this->aSubreaktorRelatedByLocalsubreaktor);
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = RecommendedArtworkPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += RecommendedArtworkPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aReaktorArtwork !== null) {
    +				if (!$this->aReaktorArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtwork->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aSubreaktorRelatedBySubreaktor !== null) {
    +				if (!$this->aSubreaktorRelatedBySubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktorRelatedBySubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aSubreaktorRelatedByLocalsubreaktor !== null) {
    +				if (!$this->aSubreaktorRelatedByLocalsubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktorRelatedByLocalsubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = RecommendedArtworkPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = RecommendedArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getArtwork();
    +				break;
    +			case 2:
    +				return $this->getSubreaktor();
    +				break;
    +			case 3:
    +				return $this->getLocalsubreaktor();
    +				break;
    +			case 4:
    +				return $this->getUpdatedBy();
    +				break;
    +			case 5:
    +				return $this->getUpdatedAt();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = RecommendedArtworkPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getArtwork(),
    +			$keys[2] => $this->getSubreaktor(),
    +			$keys[3] => $this->getLocalsubreaktor(),
    +			$keys[4] => $this->getUpdatedBy(),
    +			$keys[5] => $this->getUpdatedAt(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = RecommendedArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setArtwork($value);
    +				break;
    +			case 2:
    +				$this->setSubreaktor($value);
    +				break;
    +			case 3:
    +				$this->setLocalsubreaktor($value);
    +				break;
    +			case 4:
    +				$this->setUpdatedBy($value);
    +				break;
    +			case 5:
    +				$this->setUpdatedAt($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = RecommendedArtworkPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setArtwork($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setSubreaktor($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setLocalsubreaktor($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setUpdatedBy($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setUpdatedAt($arr[$keys[5]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(RecommendedArtworkPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(RecommendedArtworkPeer::ID)) $criteria->add(RecommendedArtworkPeer::ID, $this->id);
    +		if ($this->isColumnModified(RecommendedArtworkPeer::ARTWORK)) $criteria->add(RecommendedArtworkPeer::ARTWORK, $this->artwork);
    +		if ($this->isColumnModified(RecommendedArtworkPeer::SUBREAKTOR)) $criteria->add(RecommendedArtworkPeer::SUBREAKTOR, $this->subreaktor);
    +		if ($this->isColumnModified(RecommendedArtworkPeer::LOCALSUBREAKTOR)) $criteria->add(RecommendedArtworkPeer::LOCALSUBREAKTOR, $this->localsubreaktor);
    +		if ($this->isColumnModified(RecommendedArtworkPeer::UPDATED_BY)) $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->updated_by);
    +		if ($this->isColumnModified(RecommendedArtworkPeer::UPDATED_AT)) $criteria->add(RecommendedArtworkPeer::UPDATED_AT, $this->updated_at);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(RecommendedArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(RecommendedArtworkPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setArtwork($this->artwork);
    +
    +		$copyObj->setSubreaktor($this->subreaktor);
    +
    +		$copyObj->setLocalsubreaktor($this->localsubreaktor);
    +
    +		$copyObj->setUpdatedBy($this->updated_by);
    +
    +		$copyObj->setUpdatedAt($this->updated_at);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new RecommendedArtworkPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setReaktorArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArtwork(NULL);
    +		} else {
    +			$this->setArtwork($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtwork === null && ($this->artwork !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtwork = ReaktorArtworkPeer::retrieveByPK($this->artwork, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtwork;
    +	}
    +
    +	
    +	public function setSubreaktorRelatedBySubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSubreaktor(NULL);
    +		} else {
    +			$this->setSubreaktor($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktorRelatedBySubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktorRelatedBySubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktorRelatedBySubreaktor === null && ($this->subreaktor !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktorRelatedBySubreaktor = SubreaktorPeer::retrieveByPK($this->subreaktor, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktorRelatedBySubreaktor;
    +	}
    +
    +	
    +	public function setSubreaktorRelatedByLocalsubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setLocalsubreaktor(NULL);
    +		} else {
    +			$this->setLocalsubreaktor($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktorRelatedByLocalsubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktorRelatedByLocalsubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktorRelatedByLocalsubreaktor === null && ($this->localsubreaktor !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktorRelatedByLocalsubreaktor = SubreaktorPeer::retrieveByPK($this->localsubreaktor, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktorRelatedByLocalsubreaktor;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUpdatedBy(NULL);
    +		} else {
    +			$this->setUpdatedBy($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->updated_by !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->updated_by, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseRecommendedArtwork:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseRecommendedArtwork::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseRecommendedArtworkPeer.php b/lib/model/om/BaseRecommendedArtworkPeer.php
    new file mode 100644
    index 0000000..5ed50ca
    --- /dev/null
    +++ b/lib/model/om/BaseRecommendedArtworkPeer.php
    @@ -0,0 +1,1421 @@
    + array ('Id', 'Artwork', 'Subreaktor', 'Localsubreaktor', 'UpdatedBy', 'UpdatedAt', ),
    +		BasePeer::TYPE_COLNAME => array (RecommendedArtworkPeer::ID, RecommendedArtworkPeer::ARTWORK, RecommendedArtworkPeer::SUBREAKTOR, RecommendedArtworkPeer::LOCALSUBREAKTOR, RecommendedArtworkPeer::UPDATED_BY, RecommendedArtworkPeer::UPDATED_AT, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'artwork', 'subreaktor', 'localsubreaktor', 'updated_by', 'updated_at', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Artwork' => 1, 'Subreaktor' => 2, 'Localsubreaktor' => 3, 'UpdatedBy' => 4, 'UpdatedAt' => 5, ),
    +		BasePeer::TYPE_COLNAME => array (RecommendedArtworkPeer::ID => 0, RecommendedArtworkPeer::ARTWORK => 1, RecommendedArtworkPeer::SUBREAKTOR => 2, RecommendedArtworkPeer::LOCALSUBREAKTOR => 3, RecommendedArtworkPeer::UPDATED_BY => 4, RecommendedArtworkPeer::UPDATED_AT => 5, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'artwork' => 1, 'subreaktor' => 2, 'localsubreaktor' => 3, 'updated_by' => 4, 'updated_at' => 5, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/RecommendedArtworkMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.RecommendedArtworkMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = RecommendedArtworkPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(RecommendedArtworkPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(RecommendedArtworkPeer::ID);
    +
    +		$criteria->addSelectColumn(RecommendedArtworkPeer::ARTWORK);
    +
    +		$criteria->addSelectColumn(RecommendedArtworkPeer::SUBREAKTOR);
    +
    +		$criteria->addSelectColumn(RecommendedArtworkPeer::LOCALSUBREAKTOR);
    +
    +		$criteria->addSelectColumn(RecommendedArtworkPeer::UPDATED_BY);
    +
    +		$criteria->addSelectColumn(RecommendedArtworkPeer::UPDATED_AT);
    +
    +	}
    +
    +	const COUNT = 'COUNT(recommended_artwork.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT recommended_artwork.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = RecommendedArtworkPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return RecommendedArtworkPeer::populateObjects(RecommendedArtworkPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRecommendedArtworkPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRecommendedArtworkPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			RecommendedArtworkPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = RecommendedArtworkPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinSubreaktorRelatedBySubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::SUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinSubreaktorRelatedByLocalsubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::LOCALSUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addRecommendedArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworks();
    +				$obj2->addRecommendedArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktorRelatedBySubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(RecommendedArtworkPeer::SUBREAKTOR, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktorRelatedBySubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addRecommendedArtworkRelatedBySubreaktor($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworksRelatedBySubreaktor();
    +				$obj2->addRecommendedArtworkRelatedBySubreaktor($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktorRelatedByLocalsubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(RecommendedArtworkPeer::LOCALSUBREAKTOR, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktorRelatedByLocalsubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addRecommendedArtworkRelatedByLocalsubreaktor($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworksRelatedByLocalsubreaktor();
    +				$obj2->addRecommendedArtworkRelatedByLocalsubreaktor($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addRecommendedArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworks();
    +				$obj2->addRecommendedArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::SUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::LOCALSUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol6 = $startcol5 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::SUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::LOCALSUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRecommendedArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworks();
    +				$obj2->addRecommendedArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getSubreaktorRelatedBySubreaktor(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addRecommendedArtworkRelatedBySubreaktor($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initRecommendedArtworksRelatedBySubreaktor();
    +				$obj3->addRecommendedArtworkRelatedBySubreaktor($obj1);
    +			}
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4 = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getSubreaktorRelatedByLocalsubreaktor(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addRecommendedArtworkRelatedByLocalsubreaktor($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initRecommendedArtworksRelatedByLocalsubreaktor();
    +				$obj4->addRecommendedArtworkRelatedByLocalsubreaktor($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj5 = new $cls();
    +			$obj5->hydrate($rs, $startcol5);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj5 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj5->getPrimaryKey() === $obj5->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj5->addRecommendedArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj5->initRecommendedArtworks();
    +				$obj5->addRecommendedArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::SUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::LOCALSUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptSubreaktorRelatedBySubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptSubreaktorRelatedByLocalsubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RecommendedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::SUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$criteria->addJoin(RecommendedArtworkPeer::LOCALSUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$rs = RecommendedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RecommendedArtworkPeer::SUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::LOCALSUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktorRelatedBySubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRecommendedArtworkRelatedBySubreaktor($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworksRelatedBySubreaktor();
    +				$obj2->addRecommendedArtworkRelatedBySubreaktor($obj1);
    +			}
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getSubreaktorRelatedByLocalsubreaktor(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addRecommendedArtworkRelatedByLocalsubreaktor($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initRecommendedArtworksRelatedByLocalsubreaktor();
    +				$obj3->addRecommendedArtworkRelatedByLocalsubreaktor($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addRecommendedArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initRecommendedArtworks();
    +				$obj4->addRecommendedArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptSubreaktorRelatedBySubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRecommendedArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworks();
    +				$obj2->addRecommendedArtwork($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addRecommendedArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initRecommendedArtworks();
    +				$obj3->addRecommendedArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptSubreaktorRelatedByLocalsubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::UPDATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRecommendedArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworks();
    +				$obj2->addRecommendedArtwork($obj1);
    +			}
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addRecommendedArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initRecommendedArtworks();
    +				$obj3->addRecommendedArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RecommendedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RecommendedArtworkPeer::NUM_COLUMNS - RecommendedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RecommendedArtworkPeer::ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::SUBREAKTOR, SubreaktorPeer::ID);
    +
    +		$c->addJoin(RecommendedArtworkPeer::LOCALSUBREAKTOR, SubreaktorPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RecommendedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRecommendedArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRecommendedArtworks();
    +				$obj2->addRecommendedArtwork($obj1);
    +			}
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getSubreaktorRelatedBySubreaktor(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addRecommendedArtworkRelatedBySubreaktor($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initRecommendedArtworksRelatedBySubreaktor();
    +				$obj3->addRecommendedArtworkRelatedBySubreaktor($obj1);
    +			}
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4  = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getSubreaktorRelatedByLocalsubreaktor(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addRecommendedArtworkRelatedByLocalsubreaktor($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initRecommendedArtworksRelatedByLocalsubreaktor();
    +				$obj4->addRecommendedArtworkRelatedByLocalsubreaktor($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return RecommendedArtworkPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRecommendedArtworkPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseRecommendedArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(RecommendedArtworkPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseRecommendedArtworkPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRecommendedArtworkPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRecommendedArtworkPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseRecommendedArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(RecommendedArtworkPeer::ID);
    +			$selectCriteria->add(RecommendedArtworkPeer::ID, $criteria->remove(RecommendedArtworkPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseRecommendedArtworkPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRecommendedArtworkPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(RecommendedArtworkPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(RecommendedArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof RecommendedArtwork) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(RecommendedArtworkPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(RecommendedArtwork $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(RecommendedArtworkPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(RecommendedArtworkPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(RecommendedArtworkPeer::DATABASE_NAME, RecommendedArtworkPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = RecommendedArtworkPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(RecommendedArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(RecommendedArtworkPeer::ID, $pk);
    +
    +
    +		$v = RecommendedArtworkPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(RecommendedArtworkPeer::ID, $pks, Criteria::IN);
    +			$objs = RecommendedArtworkPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseRecommendedArtworkPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/RecommendedArtworkMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.RecommendedArtworkMapBuilder');
    +}
    diff --git a/lib/model/om/BaseRejectionType.php b/lib/model/om/BaseRejectionType.php
    new file mode 100644
    index 0000000..0081953
    --- /dev/null
    +++ b/lib/model/om/BaseRejectionType.php
    @@ -0,0 +1,535 @@
    +id;
    +	}
    +
    +	
    +	public function getBasename()
    +	{
    +
    +		return $this->basename;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = RejectionTypePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setBasename($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->basename !== $v) {
    +			$this->basename = $v;
    +			$this->modifiedColumns[] = RejectionTypePeer::BASENAME;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->basename = $rs->getString($startcol + 1);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 2; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating RejectionType object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionType:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(RejectionTypePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			RejectionTypePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseRejectionType:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionType:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(RejectionTypePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseRejectionType:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = RejectionTypePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += RejectionTypePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collRejectionTypeI18ns !== null) {
    +				foreach($this->collRejectionTypeI18ns as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = RejectionTypePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collRejectionTypeI18ns !== null) {
    +					foreach($this->collRejectionTypeI18ns as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = RejectionTypePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getBasename();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = RejectionTypePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getBasename(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = RejectionTypePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setBasename($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = RejectionTypePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setBasename($arr[$keys[1]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(RejectionTypePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(RejectionTypePeer::ID)) $criteria->add(RejectionTypePeer::ID, $this->id);
    +		if ($this->isColumnModified(RejectionTypePeer::BASENAME)) $criteria->add(RejectionTypePeer::BASENAME, $this->basename);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(RejectionTypePeer::DATABASE_NAME);
    +
    +		$criteria->add(RejectionTypePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setBasename($this->basename);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getRejectionTypeI18ns() as $relObj) {
    +				$copyObj->addRejectionTypeI18n($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new RejectionTypePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function initRejectionTypeI18ns()
    +	{
    +		if ($this->collRejectionTypeI18ns === null) {
    +			$this->collRejectionTypeI18ns = array();
    +		}
    +	}
    +
    +	
    +	public function getRejectionTypeI18ns($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRejectionTypeI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRejectionTypeI18ns === null) {
    +			if ($this->isNew()) {
    +			   $this->collRejectionTypeI18ns = array();
    +			} else {
    +
    +				$criteria->add(RejectionTypeI18nPeer::ID, $this->getId());
    +
    +				RejectionTypeI18nPeer::addSelectColumns($criteria);
    +				$this->collRejectionTypeI18ns = RejectionTypeI18nPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(RejectionTypeI18nPeer::ID, $this->getId());
    +
    +				RejectionTypeI18nPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastRejectionTypeI18nCriteria) || !$this->lastRejectionTypeI18nCriteria->equals($criteria)) {
    +					$this->collRejectionTypeI18ns = RejectionTypeI18nPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastRejectionTypeI18nCriteria = $criteria;
    +		return $this->collRejectionTypeI18ns;
    +	}
    +
    +	
    +	public function countRejectionTypeI18ns($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRejectionTypeI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(RejectionTypeI18nPeer::ID, $this->getId());
    +
    +		return RejectionTypeI18nPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addRejectionTypeI18n(RejectionTypeI18n $l)
    +	{
    +		$this->collRejectionTypeI18ns[] = $l;
    +		$l->setRejectionType($this);
    +	}
    +
    +  public function getCulture()
    +  {
    +    return $this->culture;
    +  }
    +
    +  public function setCulture($culture)
    +  {
    +    $this->culture = $culture;
    +  }
    +
    +  public function getName()
    +  {
    +    $obj = $this->getCurrentRejectionTypeI18n();
    +
    +    return ($obj ? $obj->getName() : null);
    +  }
    +
    +  public function setName($value)
    +  {
    +    $this->getCurrentRejectionTypeI18n()->setName($value);
    +  }
    +
    +  public function getDescription()
    +  {
    +    $obj = $this->getCurrentRejectionTypeI18n();
    +
    +    return ($obj ? $obj->getDescription() : null);
    +  }
    +
    +  public function setDescription($value)
    +  {
    +    $this->getCurrentRejectionTypeI18n()->setDescription($value);
    +  }
    +
    +  protected $current_i18n = array();
    +
    +  public function getCurrentRejectionTypeI18n()
    +  {
    +    if (!isset($this->current_i18n[$this->culture]))
    +    {
    +      $obj = RejectionTypeI18nPeer::retrieveByPK($this->getId(), $this->culture);
    +      if ($obj)
    +      {
    +        $this->setRejectionTypeI18nForCulture($obj, $this->culture);
    +      }
    +      else
    +      {
    +        $this->setRejectionTypeI18nForCulture(new RejectionTypeI18n(), $this->culture);
    +        $this->current_i18n[$this->culture]->setCulture($this->culture);
    +      }
    +    }
    +
    +    return $this->current_i18n[$this->culture];
    +  }
    +
    +  public function setRejectionTypeI18nForCulture($object, $culture)
    +  {
    +    $this->current_i18n[$culture] = $object;
    +    $this->addRejectionTypeI18n($object);
    +  }
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseRejectionType:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseRejectionType::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseRejectionTypeI18n.php b/lib/model/om/BaseRejectionTypeI18n.php
    new file mode 100644
    index 0000000..58c6ae3
    --- /dev/null
    +++ b/lib/model/om/BaseRejectionTypeI18n.php
    @@ -0,0 +1,512 @@
    +id;
    +	}
    +
    +	
    +	public function getName()
    +	{
    +
    +		return $this->name;
    +	}
    +
    +	
    +	public function getDescription()
    +	{
    +
    +		return $this->description;
    +	}
    +
    +	
    +	public function getCulture()
    +	{
    +
    +		return $this->culture;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = RejectionTypeI18nPeer::ID;
    +		}
    +
    +		if ($this->aRejectionType !== null && $this->aRejectionType->getId() !== $v) {
    +			$this->aRejectionType = null;
    +		}
    +
    +	} 
    +	
    +	public function setName($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->name !== $v) {
    +			$this->name = $v;
    +			$this->modifiedColumns[] = RejectionTypeI18nPeer::NAME;
    +		}
    +
    +	} 
    +	
    +	public function setDescription($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->description !== $v) {
    +			$this->description = $v;
    +			$this->modifiedColumns[] = RejectionTypeI18nPeer::DESCRIPTION;
    +		}
    +
    +	} 
    +	
    +	public function setCulture($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->culture !== $v) {
    +			$this->culture = $v;
    +			$this->modifiedColumns[] = RejectionTypeI18nPeer::CULTURE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->name = $rs->getString($startcol + 1);
    +
    +			$this->description = $rs->getString($startcol + 2);
    +
    +			$this->culture = $rs->getString($startcol + 3);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 4; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating RejectionTypeI18n object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18n:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(RejectionTypeI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			RejectionTypeI18nPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18n:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18n:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(RejectionTypeI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18n:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aRejectionType !== null) {
    +				if ($this->aRejectionType->isModified() || $this->aRejectionType->getCurrentRejectionTypeI18n()->isModified()) {
    +					$affectedRows += $this->aRejectionType->save($con);
    +				}
    +				$this->setRejectionType($this->aRejectionType);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = RejectionTypeI18nPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += RejectionTypeI18nPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aRejectionType !== null) {
    +				if (!$this->aRejectionType->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aRejectionType->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = RejectionTypeI18nPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = RejectionTypeI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getName();
    +				break;
    +			case 2:
    +				return $this->getDescription();
    +				break;
    +			case 3:
    +				return $this->getCulture();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = RejectionTypeI18nPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getName(),
    +			$keys[2] => $this->getDescription(),
    +			$keys[3] => $this->getCulture(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = RejectionTypeI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setName($value);
    +				break;
    +			case 2:
    +				$this->setDescription($value);
    +				break;
    +			case 3:
    +				$this->setCulture($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = RejectionTypeI18nPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setName($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setDescription($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setCulture($arr[$keys[3]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(RejectionTypeI18nPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(RejectionTypeI18nPeer::ID)) $criteria->add(RejectionTypeI18nPeer::ID, $this->id);
    +		if ($this->isColumnModified(RejectionTypeI18nPeer::NAME)) $criteria->add(RejectionTypeI18nPeer::NAME, $this->name);
    +		if ($this->isColumnModified(RejectionTypeI18nPeer::DESCRIPTION)) $criteria->add(RejectionTypeI18nPeer::DESCRIPTION, $this->description);
    +		if ($this->isColumnModified(RejectionTypeI18nPeer::CULTURE)) $criteria->add(RejectionTypeI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(RejectionTypeI18nPeer::DATABASE_NAME);
    +
    +		$criteria->add(RejectionTypeI18nPeer::ID, $this->id);
    +		$criteria->add(RejectionTypeI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getId();
    +
    +		$pks[1] = $this->getCulture();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setId($keys[0]);
    +
    +		$this->setCulture($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setName($this->name);
    +
    +		$copyObj->setDescription($this->description);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +		$copyObj->setCulture(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new RejectionTypeI18nPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setRejectionType($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setId(NULL);
    +		} else {
    +			$this->setId($v->getId());
    +		}
    +
    +
    +		$this->aRejectionType = $v;
    +	}
    +
    +
    +	
    +	public function getRejectionType($con = null)
    +	{
    +		if ($this->aRejectionType === null && ($this->id !== null)) {
    +						include_once 'lib/model/om/BaseRejectionTypePeer.php';
    +
    +			$this->aRejectionType = RejectionTypePeer::retrieveByPK($this->id, $con);
    +
    +			
    +		}
    +		return $this->aRejectionType;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseRejectionTypeI18n:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseRejectionTypeI18n::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseRejectionTypeI18nPeer.php b/lib/model/om/BaseRejectionTypeI18nPeer.php
    new file mode 100644
    index 0000000..708db81
    --- /dev/null
    +++ b/lib/model/om/BaseRejectionTypeI18nPeer.php
    @@ -0,0 +1,574 @@
    + array ('Id', 'Name', 'Description', 'Culture', ),
    +		BasePeer::TYPE_COLNAME => array (RejectionTypeI18nPeer::ID, RejectionTypeI18nPeer::NAME, RejectionTypeI18nPeer::DESCRIPTION, RejectionTypeI18nPeer::CULTURE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'description', 'culture', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Name' => 1, 'Description' => 2, 'Culture' => 3, ),
    +		BasePeer::TYPE_COLNAME => array (RejectionTypeI18nPeer::ID => 0, RejectionTypeI18nPeer::NAME => 1, RejectionTypeI18nPeer::DESCRIPTION => 2, RejectionTypeI18nPeer::CULTURE => 3, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'description' => 2, 'culture' => 3, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/RejectionTypeI18nMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.RejectionTypeI18nMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = RejectionTypeI18nPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(RejectionTypeI18nPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(RejectionTypeI18nPeer::ID);
    +
    +		$criteria->addSelectColumn(RejectionTypeI18nPeer::NAME);
    +
    +		$criteria->addSelectColumn(RejectionTypeI18nPeer::DESCRIPTION);
    +
    +		$criteria->addSelectColumn(RejectionTypeI18nPeer::CULTURE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(rejection_type_i18n.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT rejection_type_i18n.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RejectionTypeI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RejectionTypeI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = RejectionTypeI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = RejectionTypeI18nPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return RejectionTypeI18nPeer::populateObjects(RejectionTypeI18nPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18nPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRejectionTypeI18nPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			RejectionTypeI18nPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = RejectionTypeI18nPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinRejectionType(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RejectionTypeI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RejectionTypeI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RejectionTypeI18nPeer::ID, RejectionTypePeer::ID);
    +
    +		$rs = RejectionTypeI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinRejectionType(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RejectionTypeI18nPeer::addSelectColumns($c);
    +		$startcol = (RejectionTypeI18nPeer::NUM_COLUMNS - RejectionTypeI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		RejectionTypePeer::addSelectColumns($c);
    +
    +		$c->addJoin(RejectionTypeI18nPeer::ID, RejectionTypePeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RejectionTypeI18nPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = RejectionTypePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getRejectionType(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addRejectionTypeI18n($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initRejectionTypeI18ns();
    +				$obj2->addRejectionTypeI18n($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RejectionTypeI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RejectionTypeI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RejectionTypeI18nPeer::ID, RejectionTypePeer::ID);
    +
    +		$rs = RejectionTypeI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RejectionTypeI18nPeer::addSelectColumns($c);
    +		$startcol2 = (RejectionTypeI18nPeer::NUM_COLUMNS - RejectionTypeI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		RejectionTypePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + RejectionTypePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RejectionTypeI18nPeer::ID, RejectionTypePeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RejectionTypeI18nPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = RejectionTypePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getRejectionType(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRejectionTypeI18n($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRejectionTypeI18ns();
    +				$obj2->addRejectionTypeI18n($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return RejectionTypeI18nPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18nPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseRejectionTypeI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18nPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRejectionTypeI18nPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18nPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseRejectionTypeI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(RejectionTypeI18nPeer::ID);
    +			$selectCriteria->add(RejectionTypeI18nPeer::ID, $criteria->remove(RejectionTypeI18nPeer::ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(RejectionTypeI18nPeer::CULTURE);
    +			$selectCriteria->add(RejectionTypeI18nPeer::CULTURE, $criteria->remove(RejectionTypeI18nPeer::CULTURE), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypeI18nPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRejectionTypeI18nPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(RejectionTypeI18nPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(RejectionTypeI18nPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof RejectionTypeI18n) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(RejectionTypeI18nPeer::ID, $vals[0], Criteria::IN);
    +			$criteria->add(RejectionTypeI18nPeer::CULTURE, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(RejectionTypeI18n $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(RejectionTypeI18nPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(RejectionTypeI18nPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(RejectionTypeI18nPeer::DATABASE_NAME, RejectionTypeI18nPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = RejectionTypeI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $id, $culture, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(RejectionTypeI18nPeer::ID, $id);
    +		$criteria->add(RejectionTypeI18nPeer::CULTURE, $culture);
    +		$v = RejectionTypeI18nPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseRejectionTypeI18nPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/RejectionTypeI18nMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.RejectionTypeI18nMapBuilder');
    +}
    diff --git a/lib/model/om/BaseRejectionTypePeer.php b/lib/model/om/BaseRejectionTypePeer.php
    new file mode 100644
    index 0000000..a0b8034
    --- /dev/null
    +++ b/lib/model/om/BaseRejectionTypePeer.php
    @@ -0,0 +1,479 @@
    + array ('Id', 'Basename', ),
    +		BasePeer::TYPE_COLNAME => array (RejectionTypePeer::ID, RejectionTypePeer::BASENAME, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'basename', ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Basename' => 1, ),
    +		BasePeer::TYPE_COLNAME => array (RejectionTypePeer::ID => 0, RejectionTypePeer::BASENAME => 1, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'basename' => 1, ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/RejectionTypeMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.RejectionTypeMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = RejectionTypePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(RejectionTypePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(RejectionTypePeer::ID);
    +
    +		$criteria->addSelectColumn(RejectionTypePeer::BASENAME);
    +
    +	}
    +
    +	const COUNT = 'COUNT(rejection_type.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT rejection_type.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RejectionTypePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RejectionTypePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = RejectionTypePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = RejectionTypePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return RejectionTypePeer::populateObjects(RejectionTypePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRejectionTypePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			RejectionTypePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = RejectionTypePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +  
    +  public static function doSelectWithI18n(Criteria $c, $culture = null, $con = null)
    +  {
    +    if ($culture === null)
    +    {
    +      $culture = sfContext::getInstance()->getUser()->getCulture();
    +    }
    +
    +        if ($c->getDbName() == Propel::getDefaultDB())
    +    {
    +      $c->setDbName(self::DATABASE_NAME);
    +    }
    +
    +    RejectionTypePeer::addSelectColumns($c);
    +    $startcol = (RejectionTypePeer::NUM_COLUMNS - RejectionTypePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +    RejectionTypeI18nPeer::addSelectColumns($c);
    +
    +    $c->addJoin(RejectionTypePeer::ID, RejectionTypeI18nPeer::ID);
    +    $c->add(RejectionTypeI18nPeer::CULTURE, $culture);
    +
    +    $rs = BasePeer::doSelect($c, $con);
    +    $results = array();
    +
    +    while($rs->next()) {
    +
    +      $omClass = RejectionTypePeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj1 = new $cls();
    +      $obj1->hydrate($rs);
    +      $obj1->setCulture($culture);
    +
    +      $omClass = RejectionTypeI18nPeer::getOMClass($rs, $startcol);
    +
    +      $cls = Propel::import($omClass);
    +      $obj2 = new $cls();
    +      $obj2->hydrate($rs, $startcol);
    +
    +      $obj1->setRejectionTypeI18nForCulture($obj2, $culture);
    +      $obj2->setRejectionType($obj1);
    +
    +      $results[] = $obj1;
    +    }
    +    return $results;
    +  }
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return RejectionTypePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseRejectionTypePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(RejectionTypePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseRejectionTypePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRejectionTypePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseRejectionTypePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(RejectionTypePeer::ID);
    +			$selectCriteria->add(RejectionTypePeer::ID, $criteria->remove(RejectionTypePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseRejectionTypePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRejectionTypePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += RejectionTypePeer::doOnDeleteCascade(new Criteria(), $con);
    +			$affectedRows += BasePeer::doDeleteAll(RejectionTypePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(RejectionTypePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof RejectionType) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(RejectionTypePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			$affectedRows += RejectionTypePeer::doOnDeleteCascade($criteria, $con);
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected static function doOnDeleteCascade(Criteria $criteria, Connection $con)
    +	{
    +				$affectedRows = 0;
    +
    +				$objects = RejectionTypePeer::doSelect($criteria, $con);
    +		foreach($objects as $obj) {
    +
    +
    +			include_once 'lib/model/RejectionTypeI18n.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(RejectionTypeI18nPeer::ID, $obj->getId());
    +			$affectedRows += RejectionTypeI18nPeer::doDelete($c, $con);
    +		}
    +		return $affectedRows;
    +	}
    +
    +	
    +	public static function doValidate(RejectionType $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(RejectionTypePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(RejectionTypePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(RejectionTypePeer::DATABASE_NAME, RejectionTypePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = RejectionTypePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(RejectionTypePeer::DATABASE_NAME);
    +
    +		$criteria->add(RejectionTypePeer::ID, $pk);
    +
    +
    +		$v = RejectionTypePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(RejectionTypePeer::ID, $pks, Criteria::IN);
    +			$objs = RejectionTypePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseRejectionTypePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/RejectionTypeMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.RejectionTypeMapBuilder');
    +}
    diff --git a/lib/model/om/BaseRelatedArtwork.php b/lib/model/om/BaseRelatedArtwork.php
    new file mode 100644
    index 0000000..700b84f
    --- /dev/null
    +++ b/lib/model/om/BaseRelatedArtwork.php
    @@ -0,0 +1,702 @@
    +id;
    +	}
    +
    +	
    +	public function getFirstArtwork()
    +	{
    +
    +		return $this->first_artwork;
    +	}
    +
    +	
    +	public function getSecondArtwork()
    +	{
    +
    +		return $this->second_artwork;
    +	}
    +
    +	
    +	public function getCreatedAt($format = 'Y-m-d H:i:s')
    +	{
    +
    +		if ($this->created_at === null || $this->created_at === '') {
    +			return null;
    +		} elseif (!is_int($this->created_at)) {
    +						$ts = strtotime($this->created_at);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true));
    +			}
    +		} else {
    +			$ts = $this->created_at;
    +		}
    +		if ($format === null) {
    +			return $ts;
    +		} elseif (strpos($format, '%') !== false) {
    +			return strftime($format, $ts);
    +		} else {
    +			return date($format, $ts);
    +		}
    +	}
    +
    +	
    +	public function getCreatedBy()
    +	{
    +
    +		return $this->created_by;
    +	}
    +
    +	
    +	public function getOrderBy()
    +	{
    +
    +		return $this->order_by;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = RelatedArtworkPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setFirstArtwork($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->first_artwork !== $v) {
    +			$this->first_artwork = $v;
    +			$this->modifiedColumns[] = RelatedArtworkPeer::FIRST_ARTWORK;
    +		}
    +
    +		if ($this->aReaktorArtworkRelatedByFirstArtwork !== null && $this->aReaktorArtworkRelatedByFirstArtwork->getId() !== $v) {
    +			$this->aReaktorArtworkRelatedByFirstArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function setSecondArtwork($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->second_artwork !== $v) {
    +			$this->second_artwork = $v;
    +			$this->modifiedColumns[] = RelatedArtworkPeer::SECOND_ARTWORK;
    +		}
    +
    +		if ($this->aReaktorArtworkRelatedBySecondArtwork !== null && $this->aReaktorArtworkRelatedBySecondArtwork->getId() !== $v) {
    +			$this->aReaktorArtworkRelatedBySecondArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedAt($v)
    +	{
    +
    +		if ($v !== null && !is_int($v)) {
    +			$ts = strtotime($v);
    +			if ($ts === -1 || $ts === false) { 				throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true));
    +			}
    +		} else {
    +			$ts = $v;
    +		}
    +		if ($this->created_at !== $ts) {
    +			$this->created_at = $ts;
    +			$this->modifiedColumns[] = RelatedArtworkPeer::CREATED_AT;
    +		}
    +
    +	} 
    +	
    +	public function setCreatedBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->created_by !== $v) {
    +			$this->created_by = $v;
    +			$this->modifiedColumns[] = RelatedArtworkPeer::CREATED_BY;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setOrderBy($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->order_by !== $v || $v === 0) {
    +			$this->order_by = $v;
    +			$this->modifiedColumns[] = RelatedArtworkPeer::ORDER_BY;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->first_artwork = $rs->getInt($startcol + 1);
    +
    +			$this->second_artwork = $rs->getInt($startcol + 2);
    +
    +			$this->created_at = $rs->getTimestamp($startcol + 3, null);
    +
    +			$this->created_by = $rs->getInt($startcol + 4);
    +
    +			$this->order_by = $rs->getInt($startcol + 5);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 6; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating RelatedArtwork object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRelatedArtwork:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(RelatedArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			RelatedArtworkPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseRelatedArtwork:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRelatedArtwork:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +    if ($this->isNew() && !$this->isColumnModified(RelatedArtworkPeer::CREATED_AT))
    +    {
    +      $this->setCreatedAt(time());
    +    }
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(RelatedArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseRelatedArtwork:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aReaktorArtworkRelatedByFirstArtwork !== null) {
    +				if ($this->aReaktorArtworkRelatedByFirstArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtworkRelatedByFirstArtwork->save($con);
    +				}
    +				$this->setReaktorArtworkRelatedByFirstArtwork($this->aReaktorArtworkRelatedByFirstArtwork);
    +			}
    +
    +			if ($this->aReaktorArtworkRelatedBySecondArtwork !== null) {
    +				if ($this->aReaktorArtworkRelatedBySecondArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtworkRelatedBySecondArtwork->save($con);
    +				}
    +				$this->setReaktorArtworkRelatedBySecondArtwork($this->aReaktorArtworkRelatedBySecondArtwork);
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = RelatedArtworkPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += RelatedArtworkPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aReaktorArtworkRelatedByFirstArtwork !== null) {
    +				if (!$this->aReaktorArtworkRelatedByFirstArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtworkRelatedByFirstArtwork->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorArtworkRelatedBySecondArtwork !== null) {
    +				if (!$this->aReaktorArtworkRelatedBySecondArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtworkRelatedBySecondArtwork->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = RelatedArtworkPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = RelatedArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getFirstArtwork();
    +				break;
    +			case 2:
    +				return $this->getSecondArtwork();
    +				break;
    +			case 3:
    +				return $this->getCreatedAt();
    +				break;
    +			case 4:
    +				return $this->getCreatedBy();
    +				break;
    +			case 5:
    +				return $this->getOrderBy();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = RelatedArtworkPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getFirstArtwork(),
    +			$keys[2] => $this->getSecondArtwork(),
    +			$keys[3] => $this->getCreatedAt(),
    +			$keys[4] => $this->getCreatedBy(),
    +			$keys[5] => $this->getOrderBy(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = RelatedArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setFirstArtwork($value);
    +				break;
    +			case 2:
    +				$this->setSecondArtwork($value);
    +				break;
    +			case 3:
    +				$this->setCreatedAt($value);
    +				break;
    +			case 4:
    +				$this->setCreatedBy($value);
    +				break;
    +			case 5:
    +				$this->setOrderBy($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = RelatedArtworkPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setFirstArtwork($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setSecondArtwork($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setCreatedAt($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setCreatedBy($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setOrderBy($arr[$keys[5]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(RelatedArtworkPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(RelatedArtworkPeer::ID)) $criteria->add(RelatedArtworkPeer::ID, $this->id);
    +		if ($this->isColumnModified(RelatedArtworkPeer::FIRST_ARTWORK)) $criteria->add(RelatedArtworkPeer::FIRST_ARTWORK, $this->first_artwork);
    +		if ($this->isColumnModified(RelatedArtworkPeer::SECOND_ARTWORK)) $criteria->add(RelatedArtworkPeer::SECOND_ARTWORK, $this->second_artwork);
    +		if ($this->isColumnModified(RelatedArtworkPeer::CREATED_AT)) $criteria->add(RelatedArtworkPeer::CREATED_AT, $this->created_at);
    +		if ($this->isColumnModified(RelatedArtworkPeer::CREATED_BY)) $criteria->add(RelatedArtworkPeer::CREATED_BY, $this->created_by);
    +		if ($this->isColumnModified(RelatedArtworkPeer::ORDER_BY)) $criteria->add(RelatedArtworkPeer::ORDER_BY, $this->order_by);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(RelatedArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(RelatedArtworkPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setFirstArtwork($this->first_artwork);
    +
    +		$copyObj->setSecondArtwork($this->second_artwork);
    +
    +		$copyObj->setCreatedAt($this->created_at);
    +
    +		$copyObj->setCreatedBy($this->created_by);
    +
    +		$copyObj->setOrderBy($this->order_by);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new RelatedArtworkPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setReaktorArtworkRelatedByFirstArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setFirstArtwork(NULL);
    +		} else {
    +			$this->setFirstArtwork($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtworkRelatedByFirstArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkRelatedByFirstArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtworkRelatedByFirstArtwork === null && ($this->first_artwork !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtworkRelatedByFirstArtwork = ReaktorArtworkPeer::retrieveByPK($this->first_artwork, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtworkRelatedByFirstArtwork;
    +	}
    +
    +	
    +	public function setReaktorArtworkRelatedBySecondArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSecondArtwork(NULL);
    +		} else {
    +			$this->setSecondArtwork($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtworkRelatedBySecondArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtworkRelatedBySecondArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtworkRelatedBySecondArtwork === null && ($this->second_artwork !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtworkRelatedBySecondArtwork = ReaktorArtworkPeer::retrieveByPK($this->second_artwork, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtworkRelatedBySecondArtwork;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setCreatedBy(NULL);
    +		} else {
    +			$this->setCreatedBy($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->created_by !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->created_by, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseRelatedArtwork:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseRelatedArtwork::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseRelatedArtworkPeer.php b/lib/model/om/BaseRelatedArtworkPeer.php
    new file mode 100644
    index 0000000..5273891
    --- /dev/null
    +++ b/lib/model/om/BaseRelatedArtworkPeer.php
    @@ -0,0 +1,1086 @@
    + array ('Id', 'FirstArtwork', 'SecondArtwork', 'CreatedAt', 'CreatedBy', 'OrderBy', ),
    +		BasePeer::TYPE_COLNAME => array (RelatedArtworkPeer::ID, RelatedArtworkPeer::FIRST_ARTWORK, RelatedArtworkPeer::SECOND_ARTWORK, RelatedArtworkPeer::CREATED_AT, RelatedArtworkPeer::CREATED_BY, RelatedArtworkPeer::ORDER_BY, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'first_artwork', 'second_artwork', 'created_at', 'created_by', 'order_by', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'FirstArtwork' => 1, 'SecondArtwork' => 2, 'CreatedAt' => 3, 'CreatedBy' => 4, 'OrderBy' => 5, ),
    +		BasePeer::TYPE_COLNAME => array (RelatedArtworkPeer::ID => 0, RelatedArtworkPeer::FIRST_ARTWORK => 1, RelatedArtworkPeer::SECOND_ARTWORK => 2, RelatedArtworkPeer::CREATED_AT => 3, RelatedArtworkPeer::CREATED_BY => 4, RelatedArtworkPeer::ORDER_BY => 5, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'first_artwork' => 1, 'second_artwork' => 2, 'created_at' => 3, 'created_by' => 4, 'order_by' => 5, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/RelatedArtworkMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.RelatedArtworkMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = RelatedArtworkPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(RelatedArtworkPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(RelatedArtworkPeer::ID);
    +
    +		$criteria->addSelectColumn(RelatedArtworkPeer::FIRST_ARTWORK);
    +
    +		$criteria->addSelectColumn(RelatedArtworkPeer::SECOND_ARTWORK);
    +
    +		$criteria->addSelectColumn(RelatedArtworkPeer::CREATED_AT);
    +
    +		$criteria->addSelectColumn(RelatedArtworkPeer::CREATED_BY);
    +
    +		$criteria->addSelectColumn(RelatedArtworkPeer::ORDER_BY);
    +
    +	}
    +
    +	const COUNT = 'COUNT(related_artwork.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT related_artwork.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = RelatedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = RelatedArtworkPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return RelatedArtworkPeer::populateObjects(RelatedArtworkPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRelatedArtworkPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRelatedArtworkPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			RelatedArtworkPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = RelatedArtworkPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinReaktorArtworkRelatedByFirstArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RelatedArtworkPeer::FIRST_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$rs = RelatedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorArtworkRelatedBySecondArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RelatedArtworkPeer::SECOND_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$rs = RelatedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RelatedArtworkPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RelatedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtworkRelatedByFirstArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RelatedArtworkPeer::addSelectColumns($c);
    +		$startcol = (RelatedArtworkPeer::NUM_COLUMNS - RelatedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(RelatedArtworkPeer::FIRST_ARTWORK, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RelatedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedByFirstArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addRelatedArtworkRelatedByFirstArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initRelatedArtworksRelatedByFirstArtwork();
    +				$obj2->addRelatedArtworkRelatedByFirstArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtworkRelatedBySecondArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RelatedArtworkPeer::addSelectColumns($c);
    +		$startcol = (RelatedArtworkPeer::NUM_COLUMNS - RelatedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(RelatedArtworkPeer::SECOND_ARTWORK, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RelatedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedBySecondArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addRelatedArtworkRelatedBySecondArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initRelatedArtworksRelatedBySecondArtwork();
    +				$obj2->addRelatedArtworkRelatedBySecondArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RelatedArtworkPeer::addSelectColumns($c);
    +		$startcol = (RelatedArtworkPeer::NUM_COLUMNS - RelatedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(RelatedArtworkPeer::CREATED_BY, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RelatedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addRelatedArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initRelatedArtworks();
    +				$obj2->addRelatedArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RelatedArtworkPeer::FIRST_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(RelatedArtworkPeer::SECOND_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(RelatedArtworkPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RelatedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RelatedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RelatedArtworkPeer::NUM_COLUMNS - RelatedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol5 = $startcol4 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RelatedArtworkPeer::FIRST_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(RelatedArtworkPeer::SECOND_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(RelatedArtworkPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RelatedArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedByFirstArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRelatedArtworkRelatedByFirstArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRelatedArtworksRelatedByFirstArtwork();
    +				$obj2->addRelatedArtworkRelatedByFirstArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtworkRelatedBySecondArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addRelatedArtworkRelatedBySecondArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initRelatedArtworksRelatedBySecondArtwork();
    +				$obj3->addRelatedArtworkRelatedBySecondArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj4 = new $cls();
    +			$obj4->hydrate($rs, $startcol4);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj4 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj4->getPrimaryKey() === $obj4->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj4->addRelatedArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj4->initRelatedArtworks();
    +				$obj4->addRelatedArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtworkRelatedByFirstArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RelatedArtworkPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RelatedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtworkRelatedBySecondArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RelatedArtworkPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +		$rs = RelatedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(RelatedArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(RelatedArtworkPeer::FIRST_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$criteria->addJoin(RelatedArtworkPeer::SECOND_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$rs = RelatedArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtworkRelatedByFirstArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RelatedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RelatedArtworkPeer::NUM_COLUMNS - RelatedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RelatedArtworkPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RelatedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRelatedArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRelatedArtworks();
    +				$obj2->addRelatedArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtworkRelatedBySecondArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RelatedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RelatedArtworkPeer::NUM_COLUMNS - RelatedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RelatedArtworkPeer::CREATED_BY, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RelatedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRelatedArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRelatedArtworks();
    +				$obj2->addRelatedArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		RelatedArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (RelatedArtworkPeer::NUM_COLUMNS - RelatedArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(RelatedArtworkPeer::FIRST_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +		$c->addJoin(RelatedArtworkPeer::SECOND_ARTWORK, ReaktorArtworkPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = RelatedArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtworkRelatedByFirstArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addRelatedArtworkRelatedByFirstArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initRelatedArtworksRelatedByFirstArtwork();
    +				$obj2->addRelatedArtworkRelatedByFirstArtwork($obj1);
    +			}
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3  = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtworkRelatedBySecondArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addRelatedArtworkRelatedBySecondArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initRelatedArtworksRelatedBySecondArtwork();
    +				$obj3->addRelatedArtworkRelatedBySecondArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return RelatedArtworkPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRelatedArtworkPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseRelatedArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(RelatedArtworkPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseRelatedArtworkPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRelatedArtworkPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseRelatedArtworkPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseRelatedArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(RelatedArtworkPeer::ID);
    +			$selectCriteria->add(RelatedArtworkPeer::ID, $criteria->remove(RelatedArtworkPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseRelatedArtworkPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseRelatedArtworkPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(RelatedArtworkPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(RelatedArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof RelatedArtwork) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(RelatedArtworkPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(RelatedArtwork $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(RelatedArtworkPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(RelatedArtworkPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(RelatedArtworkPeer::DATABASE_NAME, RelatedArtworkPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = RelatedArtworkPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(RelatedArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(RelatedArtworkPeer::ID, $pk);
    +
    +
    +		$v = RelatedArtworkPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(RelatedArtworkPeer::ID, $pks, Criteria::IN);
    +			$objs = RelatedArtworkPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseRelatedArtworkPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/RelatedArtworkMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.RelatedArtworkMapBuilder');
    +}
    diff --git a/lib/model/om/BaseReportBookmark.php b/lib/model/om/BaseReportBookmark.php
    new file mode 100644
    index 0000000..f69ac9a
    --- /dev/null
    +++ b/lib/model/om/BaseReportBookmark.php
    @@ -0,0 +1,530 @@
    +id;
    +	}
    +
    +	
    +	public function getTitle()
    +	{
    +
    +		return $this->title;
    +	}
    +
    +	
    +	public function getDescription()
    +	{
    +
    +		return $this->description;
    +	}
    +
    +	
    +	public function getArgs()
    +	{
    +
    +		return $this->args;
    +	}
    +
    +	
    +	public function getType()
    +	{
    +
    +		return $this->type;
    +	}
    +
    +	
    +	public function getListOrder()
    +	{
    +
    +		return $this->list_order;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ReportBookmarkPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setTitle($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->title !== $v) {
    +			$this->title = $v;
    +			$this->modifiedColumns[] = ReportBookmarkPeer::TITLE;
    +		}
    +
    +	} 
    +	
    +	public function setDescription($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->description !== $v) {
    +			$this->description = $v;
    +			$this->modifiedColumns[] = ReportBookmarkPeer::DESCRIPTION;
    +		}
    +
    +	} 
    +	
    +	public function setArgs($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->args !== $v) {
    +			$this->args = $v;
    +			$this->modifiedColumns[] = ReportBookmarkPeer::ARGS;
    +		}
    +
    +	} 
    +	
    +	public function setType($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->type !== $v || $v === 'artwork') {
    +			$this->type = $v;
    +			$this->modifiedColumns[] = ReportBookmarkPeer::TYPE;
    +		}
    +
    +	} 
    +	
    +	public function setListOrder($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->list_order !== $v || $v === 0) {
    +			$this->list_order = $v;
    +			$this->modifiedColumns[] = ReportBookmarkPeer::LIST_ORDER;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->title = $rs->getString($startcol + 1);
    +
    +			$this->description = $rs->getString($startcol + 2);
    +
    +			$this->args = $rs->getString($startcol + 3);
    +
    +			$this->type = $rs->getString($startcol + 4);
    +
    +			$this->list_order = $rs->getInt($startcol + 5);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 6; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ReportBookmark object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReportBookmark:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReportBookmarkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ReportBookmarkPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReportBookmark:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReportBookmark:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReportBookmarkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseReportBookmark:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ReportBookmarkPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ReportBookmarkPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = ReportBookmarkPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReportBookmarkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getTitle();
    +				break;
    +			case 2:
    +				return $this->getDescription();
    +				break;
    +			case 3:
    +				return $this->getArgs();
    +				break;
    +			case 4:
    +				return $this->getType();
    +				break;
    +			case 5:
    +				return $this->getListOrder();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReportBookmarkPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getTitle(),
    +			$keys[2] => $this->getDescription(),
    +			$keys[3] => $this->getArgs(),
    +			$keys[4] => $this->getType(),
    +			$keys[5] => $this->getListOrder(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ReportBookmarkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setTitle($value);
    +				break;
    +			case 2:
    +				$this->setDescription($value);
    +				break;
    +			case 3:
    +				$this->setArgs($value);
    +				break;
    +			case 4:
    +				$this->setType($value);
    +				break;
    +			case 5:
    +				$this->setListOrder($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ReportBookmarkPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setTitle($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setDescription($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setArgs($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setType($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setListOrder($arr[$keys[5]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ReportBookmarkPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ReportBookmarkPeer::ID)) $criteria->add(ReportBookmarkPeer::ID, $this->id);
    +		if ($this->isColumnModified(ReportBookmarkPeer::TITLE)) $criteria->add(ReportBookmarkPeer::TITLE, $this->title);
    +		if ($this->isColumnModified(ReportBookmarkPeer::DESCRIPTION)) $criteria->add(ReportBookmarkPeer::DESCRIPTION, $this->description);
    +		if ($this->isColumnModified(ReportBookmarkPeer::ARGS)) $criteria->add(ReportBookmarkPeer::ARGS, $this->args);
    +		if ($this->isColumnModified(ReportBookmarkPeer::TYPE)) $criteria->add(ReportBookmarkPeer::TYPE, $this->type);
    +		if ($this->isColumnModified(ReportBookmarkPeer::LIST_ORDER)) $criteria->add(ReportBookmarkPeer::LIST_ORDER, $this->list_order);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ReportBookmarkPeer::DATABASE_NAME);
    +
    +		$criteria->add(ReportBookmarkPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setTitle($this->title);
    +
    +		$copyObj->setDescription($this->description);
    +
    +		$copyObj->setArgs($this->args);
    +
    +		$copyObj->setType($this->type);
    +
    +		$copyObj->setListOrder($this->list_order);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ReportBookmarkPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseReportBookmark:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseReportBookmark::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseReportBookmarkPeer.php b/lib/model/om/BaseReportBookmarkPeer.php
    new file mode 100644
    index 0000000..2d9fc16
    --- /dev/null
    +++ b/lib/model/om/BaseReportBookmarkPeer.php
    @@ -0,0 +1,431 @@
    + array ('Id', 'Title', 'Description', 'Args', 'Type', 'ListOrder', ),
    +		BasePeer::TYPE_COLNAME => array (ReportBookmarkPeer::ID, ReportBookmarkPeer::TITLE, ReportBookmarkPeer::DESCRIPTION, ReportBookmarkPeer::ARGS, ReportBookmarkPeer::TYPE, ReportBookmarkPeer::LIST_ORDER, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'title', 'description', 'args', 'type', 'list_order', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Title' => 1, 'Description' => 2, 'Args' => 3, 'Type' => 4, 'ListOrder' => 5, ),
    +		BasePeer::TYPE_COLNAME => array (ReportBookmarkPeer::ID => 0, ReportBookmarkPeer::TITLE => 1, ReportBookmarkPeer::DESCRIPTION => 2, ReportBookmarkPeer::ARGS => 3, ReportBookmarkPeer::TYPE => 4, ReportBookmarkPeer::LIST_ORDER => 5, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'title' => 1, 'description' => 2, 'args' => 3, 'type' => 4, 'list_order' => 5, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ReportBookmarkMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ReportBookmarkMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ReportBookmarkPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ReportBookmarkPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ReportBookmarkPeer::ID);
    +
    +		$criteria->addSelectColumn(ReportBookmarkPeer::TITLE);
    +
    +		$criteria->addSelectColumn(ReportBookmarkPeer::DESCRIPTION);
    +
    +		$criteria->addSelectColumn(ReportBookmarkPeer::ARGS);
    +
    +		$criteria->addSelectColumn(ReportBookmarkPeer::TYPE);
    +
    +		$criteria->addSelectColumn(ReportBookmarkPeer::LIST_ORDER);
    +
    +	}
    +
    +	const COUNT = 'COUNT(report_bookmark.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT report_bookmark.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ReportBookmarkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ReportBookmarkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ReportBookmarkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ReportBookmarkPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ReportBookmarkPeer::populateObjects(ReportBookmarkPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReportBookmarkPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReportBookmarkPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ReportBookmarkPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ReportBookmarkPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ReportBookmarkPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReportBookmarkPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReportBookmarkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ReportBookmarkPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseReportBookmarkPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReportBookmarkPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseReportBookmarkPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseReportBookmarkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ReportBookmarkPeer::ID);
    +			$selectCriteria->add(ReportBookmarkPeer::ID, $criteria->remove(ReportBookmarkPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseReportBookmarkPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseReportBookmarkPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ReportBookmarkPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ReportBookmarkPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ReportBookmark) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ReportBookmarkPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ReportBookmark $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ReportBookmarkPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ReportBookmarkPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ReportBookmarkPeer::DATABASE_NAME, ReportBookmarkPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ReportBookmarkPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ReportBookmarkPeer::DATABASE_NAME);
    +
    +		$criteria->add(ReportBookmarkPeer::ID, $pk);
    +
    +
    +		$v = ReportBookmarkPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ReportBookmarkPeer::ID, $pks, Criteria::IN);
    +			$objs = ReportBookmarkPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseReportBookmarkPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ReportBookmarkMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ReportBookmarkMapBuilder');
    +}
    diff --git a/lib/model/om/BaseResidence.php b/lib/model/om/BaseResidence.php
    new file mode 100644
    index 0000000..42cca4e
    --- /dev/null
    +++ b/lib/model/om/BaseResidence.php
    @@ -0,0 +1,735 @@
    +id;
    +	}
    +
    +	
    +	public function getName()
    +	{
    +
    +		return $this->name;
    +	}
    +
    +	
    +	public function getLevel()
    +	{
    +
    +		return $this->level;
    +	}
    +
    +	
    +	public function getParent()
    +	{
    +
    +		return $this->parent;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ResidencePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setName($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->name !== $v) {
    +			$this->name = $v;
    +			$this->modifiedColumns[] = ResidencePeer::NAME;
    +		}
    +
    +	} 
    +	
    +	public function setLevel($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->level !== $v) {
    +			$this->level = $v;
    +			$this->modifiedColumns[] = ResidencePeer::LEVEL;
    +		}
    +
    +		if ($this->aResidenceLevel !== null && $this->aResidenceLevel->getId() !== $v) {
    +			$this->aResidenceLevel = null;
    +		}
    +
    +	} 
    +	
    +	public function setParent($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->parent !== $v) {
    +			$this->parent = $v;
    +			$this->modifiedColumns[] = ResidencePeer::PARENT;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->name = $rs->getString($startcol + 1);
    +
    +			$this->level = $rs->getInt($startcol + 2);
    +
    +			$this->parent = $rs->getInt($startcol + 3);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 4; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating Residence object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidence:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidencePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ResidencePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseResidence:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidence:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidencePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseResidence:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aResidenceLevel !== null) {
    +				if ($this->aResidenceLevel->isModified() || $this->aResidenceLevel->getCurrentResidenceLevelI18n()->isModified()) {
    +					$affectedRows += $this->aResidenceLevel->save($con);
    +				}
    +				$this->setResidenceLevel($this->aResidenceLevel);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ResidencePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ResidencePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collsfGuardUsers !== null) {
    +				foreach($this->collsfGuardUsers as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collLokalreaktorResidences !== null) {
    +				foreach($this->collLokalreaktorResidences as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aResidenceLevel !== null) {
    +				if (!$this->aResidenceLevel->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aResidenceLevel->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ResidencePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collsfGuardUsers !== null) {
    +					foreach($this->collsfGuardUsers as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collLokalreaktorResidences !== null) {
    +					foreach($this->collLokalreaktorResidences as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ResidencePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getName();
    +				break;
    +			case 2:
    +				return $this->getLevel();
    +				break;
    +			case 3:
    +				return $this->getParent();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ResidencePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getName(),
    +			$keys[2] => $this->getLevel(),
    +			$keys[3] => $this->getParent(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ResidencePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setName($value);
    +				break;
    +			case 2:
    +				$this->setLevel($value);
    +				break;
    +			case 3:
    +				$this->setParent($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ResidencePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setName($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setLevel($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setParent($arr[$keys[3]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ResidencePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ResidencePeer::ID)) $criteria->add(ResidencePeer::ID, $this->id);
    +		if ($this->isColumnModified(ResidencePeer::NAME)) $criteria->add(ResidencePeer::NAME, $this->name);
    +		if ($this->isColumnModified(ResidencePeer::LEVEL)) $criteria->add(ResidencePeer::LEVEL, $this->level);
    +		if ($this->isColumnModified(ResidencePeer::PARENT)) $criteria->add(ResidencePeer::PARENT, $this->parent);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ResidencePeer::DATABASE_NAME);
    +
    +		$criteria->add(ResidencePeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setName($this->name);
    +
    +		$copyObj->setLevel($this->level);
    +
    +		$copyObj->setParent($this->parent);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getsfGuardUsers() as $relObj) {
    +				$copyObj->addsfGuardUser($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getLokalreaktorResidences() as $relObj) {
    +				$copyObj->addLokalreaktorResidence($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ResidencePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setResidenceLevel($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setLevel(NULL);
    +		} else {
    +			$this->setLevel($v->getId());
    +		}
    +
    +
    +		$this->aResidenceLevel = $v;
    +	}
    +
    +
    +	
    +	public function getResidenceLevel($con = null)
    +	{
    +		if ($this->aResidenceLevel === null && ($this->level !== null)) {
    +						include_once 'lib/model/om/BaseResidenceLevelPeer.php';
    +
    +			$this->aResidenceLevel = ResidenceLevelPeer::retrieveByPK($this->level, $con);
    +
    +			
    +		}
    +		return $this->aResidenceLevel;
    +	}
    +
    +	
    +	public function initsfGuardUsers()
    +	{
    +		if ($this->collsfGuardUsers === null) {
    +			$this->collsfGuardUsers = array();
    +		}
    +	}
    +
    +	
    +	public function getsfGuardUsers($criteria = null, $con = null)
    +	{
    +				include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collsfGuardUsers === null) {
    +			if ($this->isNew()) {
    +			   $this->collsfGuardUsers = array();
    +			} else {
    +
    +				$criteria->add(sfGuardUserPeer::RESIDENCE_ID, $this->getId());
    +
    +				sfGuardUserPeer::addSelectColumns($criteria);
    +				$this->collsfGuardUsers = sfGuardUserPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(sfGuardUserPeer::RESIDENCE_ID, $this->getId());
    +
    +				sfGuardUserPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastsfGuardUserCriteria) || !$this->lastsfGuardUserCriteria->equals($criteria)) {
    +					$this->collsfGuardUsers = sfGuardUserPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastsfGuardUserCriteria = $criteria;
    +		return $this->collsfGuardUsers;
    +	}
    +
    +	
    +	public function countsfGuardUsers($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(sfGuardUserPeer::RESIDENCE_ID, $this->getId());
    +
    +		return sfGuardUserPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addsfGuardUser(sfGuardUser $l)
    +	{
    +		$this->collsfGuardUsers[] = $l;
    +		$l->setResidence($this);
    +	}
    +
    +	
    +	public function initLokalreaktorResidences()
    +	{
    +		if ($this->collLokalreaktorResidences === null) {
    +			$this->collLokalreaktorResidences = array();
    +		}
    +	}
    +
    +	
    +	public function getLokalreaktorResidences($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorResidencePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collLokalreaktorResidences === null) {
    +			if ($this->isNew()) {
    +			   $this->collLokalreaktorResidences = array();
    +			} else {
    +
    +				$criteria->add(LokalreaktorResidencePeer::RESIDENCE_ID, $this->getId());
    +
    +				LokalreaktorResidencePeer::addSelectColumns($criteria);
    +				$this->collLokalreaktorResidences = LokalreaktorResidencePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(LokalreaktorResidencePeer::RESIDENCE_ID, $this->getId());
    +
    +				LokalreaktorResidencePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastLokalreaktorResidenceCriteria) || !$this->lastLokalreaktorResidenceCriteria->equals($criteria)) {
    +					$this->collLokalreaktorResidences = LokalreaktorResidencePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastLokalreaktorResidenceCriteria = $criteria;
    +		return $this->collLokalreaktorResidences;
    +	}
    +
    +	
    +	public function countLokalreaktorResidences($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorResidencePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(LokalreaktorResidencePeer::RESIDENCE_ID, $this->getId());
    +
    +		return LokalreaktorResidencePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addLokalreaktorResidence(LokalreaktorResidence $l)
    +	{
    +		$this->collLokalreaktorResidences[] = $l;
    +		$l->setResidence($this);
    +	}
    +
    +
    +	
    +	public function getLokalreaktorResidencesJoinSubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorResidencePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collLokalreaktorResidences === null) {
    +			if ($this->isNew()) {
    +				$this->collLokalreaktorResidences = array();
    +			} else {
    +
    +				$criteria->add(LokalreaktorResidencePeer::RESIDENCE_ID, $this->getId());
    +
    +				$this->collLokalreaktorResidences = LokalreaktorResidencePeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(LokalreaktorResidencePeer::RESIDENCE_ID, $this->getId());
    +
    +			if (!isset($this->lastLokalreaktorResidenceCriteria) || !$this->lastLokalreaktorResidenceCriteria->equals($criteria)) {
    +				$this->collLokalreaktorResidences = LokalreaktorResidencePeer::doSelectJoinSubreaktor($criteria, $con);
    +			}
    +		}
    +		$this->lastLokalreaktorResidenceCriteria = $criteria;
    +
    +		return $this->collLokalreaktorResidences;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseResidence:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseResidence::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseResidenceLevel.php b/lib/model/om/BaseResidenceLevel.php
    new file mode 100644
    index 0000000..9b36c6a
    --- /dev/null
    +++ b/lib/model/om/BaseResidenceLevel.php
    @@ -0,0 +1,659 @@
    +id;
    +	}
    +
    +	
    +	public function getLevelname()
    +	{
    +
    +		return $this->levelname;
    +	}
    +
    +	
    +	public function getListorder()
    +	{
    +
    +		return $this->listorder;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ResidenceLevelPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setLevelname($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->levelname !== $v) {
    +			$this->levelname = $v;
    +			$this->modifiedColumns[] = ResidenceLevelPeer::LEVELNAME;
    +		}
    +
    +	} 
    +	
    +	public function setListorder($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->listorder !== $v) {
    +			$this->listorder = $v;
    +			$this->modifiedColumns[] = ResidenceLevelPeer::LISTORDER;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->levelname = $rs->getString($startcol + 1);
    +
    +			$this->listorder = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ResidenceLevel object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevel:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidenceLevelPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ResidenceLevelPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevel:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevel:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidenceLevelPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseResidenceLevel:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ResidenceLevelPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ResidenceLevelPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collResidenceLevelI18ns !== null) {
    +				foreach($this->collResidenceLevelI18ns as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collResidences !== null) {
    +				foreach($this->collResidences as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = ResidenceLevelPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collResidenceLevelI18ns !== null) {
    +					foreach($this->collResidenceLevelI18ns as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collResidences !== null) {
    +					foreach($this->collResidences as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ResidenceLevelPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getLevelname();
    +				break;
    +			case 2:
    +				return $this->getListorder();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ResidenceLevelPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getLevelname(),
    +			$keys[2] => $this->getListorder(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ResidenceLevelPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setLevelname($value);
    +				break;
    +			case 2:
    +				$this->setListorder($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ResidenceLevelPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setLevelname($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setListorder($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ResidenceLevelPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ResidenceLevelPeer::ID)) $criteria->add(ResidenceLevelPeer::ID, $this->id);
    +		if ($this->isColumnModified(ResidenceLevelPeer::LEVELNAME)) $criteria->add(ResidenceLevelPeer::LEVELNAME, $this->levelname);
    +		if ($this->isColumnModified(ResidenceLevelPeer::LISTORDER)) $criteria->add(ResidenceLevelPeer::LISTORDER, $this->listorder);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ResidenceLevelPeer::DATABASE_NAME);
    +
    +		$criteria->add(ResidenceLevelPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setLevelname($this->levelname);
    +
    +		$copyObj->setListorder($this->listorder);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getResidenceLevelI18ns() as $relObj) {
    +				$copyObj->addResidenceLevelI18n($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getResidences() as $relObj) {
    +				$copyObj->addResidence($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ResidenceLevelPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function initResidenceLevelI18ns()
    +	{
    +		if ($this->collResidenceLevelI18ns === null) {
    +			$this->collResidenceLevelI18ns = array();
    +		}
    +	}
    +
    +	
    +	public function getResidenceLevelI18ns($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseResidenceLevelI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collResidenceLevelI18ns === null) {
    +			if ($this->isNew()) {
    +			   $this->collResidenceLevelI18ns = array();
    +			} else {
    +
    +				$criteria->add(ResidenceLevelI18nPeer::ID, $this->getId());
    +
    +				ResidenceLevelI18nPeer::addSelectColumns($criteria);
    +				$this->collResidenceLevelI18ns = ResidenceLevelI18nPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ResidenceLevelI18nPeer::ID, $this->getId());
    +
    +				ResidenceLevelI18nPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastResidenceLevelI18nCriteria) || !$this->lastResidenceLevelI18nCriteria->equals($criteria)) {
    +					$this->collResidenceLevelI18ns = ResidenceLevelI18nPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastResidenceLevelI18nCriteria = $criteria;
    +		return $this->collResidenceLevelI18ns;
    +	}
    +
    +	
    +	public function countResidenceLevelI18ns($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseResidenceLevelI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ResidenceLevelI18nPeer::ID, $this->getId());
    +
    +		return ResidenceLevelI18nPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addResidenceLevelI18n(ResidenceLevelI18n $l)
    +	{
    +		$this->collResidenceLevelI18ns[] = $l;
    +		$l->setResidenceLevel($this);
    +	}
    +
    +	
    +	public function initResidences()
    +	{
    +		if ($this->collResidences === null) {
    +			$this->collResidences = array();
    +		}
    +	}
    +
    +	
    +	public function getResidences($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseResidencePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collResidences === null) {
    +			if ($this->isNew()) {
    +			   $this->collResidences = array();
    +			} else {
    +
    +				$criteria->add(ResidencePeer::LEVEL, $this->getId());
    +
    +				ResidencePeer::addSelectColumns($criteria);
    +				$this->collResidences = ResidencePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ResidencePeer::LEVEL, $this->getId());
    +
    +				ResidencePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastResidenceCriteria) || !$this->lastResidenceCriteria->equals($criteria)) {
    +					$this->collResidences = ResidencePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastResidenceCriteria = $criteria;
    +		return $this->collResidences;
    +	}
    +
    +	
    +	public function countResidences($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseResidencePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ResidencePeer::LEVEL, $this->getId());
    +
    +		return ResidencePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addResidence(Residence $l)
    +	{
    +		$this->collResidences[] = $l;
    +		$l->setResidenceLevel($this);
    +	}
    +
    +  public function getCulture()
    +  {
    +    return $this->culture;
    +  }
    +
    +  public function setCulture($culture)
    +  {
    +    $this->culture = $culture;
    +  }
    +
    +  public function getName()
    +  {
    +    $obj = $this->getCurrentResidenceLevelI18n();
    +
    +    return ($obj ? $obj->getName() : null);
    +  }
    +
    +  public function setName($value)
    +  {
    +    $this->getCurrentResidenceLevelI18n()->setName($value);
    +  }
    +
    +  protected $current_i18n = array();
    +
    +  public function getCurrentResidenceLevelI18n()
    +  {
    +    if (!isset($this->current_i18n[$this->culture]))
    +    {
    +      $obj = ResidenceLevelI18nPeer::retrieveByPK($this->getId(), $this->culture);
    +      if ($obj)
    +      {
    +        $this->setResidenceLevelI18nForCulture($obj, $this->culture);
    +      }
    +      else
    +      {
    +        $this->setResidenceLevelI18nForCulture(new ResidenceLevelI18n(), $this->culture);
    +        $this->current_i18n[$this->culture]->setCulture($this->culture);
    +      }
    +    }
    +
    +    return $this->current_i18n[$this->culture];
    +  }
    +
    +  public function setResidenceLevelI18nForCulture($object, $culture)
    +  {
    +    $this->current_i18n[$culture] = $object;
    +    $this->addResidenceLevelI18n($object);
    +  }
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseResidenceLevel:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseResidenceLevel::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseResidenceLevelI18n.php b/lib/model/om/BaseResidenceLevelI18n.php
    new file mode 100644
    index 0000000..3265e17
    --- /dev/null
    +++ b/lib/model/om/BaseResidenceLevelI18n.php
    @@ -0,0 +1,472 @@
    +name;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function getCulture()
    +	{
    +
    +		return $this->culture;
    +	}
    +
    +	
    +	public function setName($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->name !== $v) {
    +			$this->name = $v;
    +			$this->modifiedColumns[] = ResidenceLevelI18nPeer::NAME;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = ResidenceLevelI18nPeer::ID;
    +		}
    +
    +		if ($this->aResidenceLevel !== null && $this->aResidenceLevel->getId() !== $v) {
    +			$this->aResidenceLevel = null;
    +		}
    +
    +	} 
    +	
    +	public function setCulture($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->culture !== $v) {
    +			$this->culture = $v;
    +			$this->modifiedColumns[] = ResidenceLevelI18nPeer::CULTURE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->name = $rs->getString($startcol + 0);
    +
    +			$this->id = $rs->getInt($startcol + 1);
    +
    +			$this->culture = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating ResidenceLevelI18n object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18n:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidenceLevelI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			ResidenceLevelI18nPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18n:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18n:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidenceLevelI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18n:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aResidenceLevel !== null) {
    +				if ($this->aResidenceLevel->isModified() || $this->aResidenceLevel->getCurrentResidenceLevelI18n()->isModified()) {
    +					$affectedRows += $this->aResidenceLevel->save($con);
    +				}
    +				$this->setResidenceLevel($this->aResidenceLevel);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = ResidenceLevelI18nPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += ResidenceLevelI18nPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aResidenceLevel !== null) {
    +				if (!$this->aResidenceLevel->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aResidenceLevel->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = ResidenceLevelI18nPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ResidenceLevelI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getName();
    +				break;
    +			case 1:
    +				return $this->getId();
    +				break;
    +			case 2:
    +				return $this->getCulture();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ResidenceLevelI18nPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getName(),
    +			$keys[1] => $this->getId(),
    +			$keys[2] => $this->getCulture(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = ResidenceLevelI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setName($value);
    +				break;
    +			case 1:
    +				$this->setId($value);
    +				break;
    +			case 2:
    +				$this->setCulture($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = ResidenceLevelI18nPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setName($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setCulture($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(ResidenceLevelI18nPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(ResidenceLevelI18nPeer::NAME)) $criteria->add(ResidenceLevelI18nPeer::NAME, $this->name);
    +		if ($this->isColumnModified(ResidenceLevelI18nPeer::ID)) $criteria->add(ResidenceLevelI18nPeer::ID, $this->id);
    +		if ($this->isColumnModified(ResidenceLevelI18nPeer::CULTURE)) $criteria->add(ResidenceLevelI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(ResidenceLevelI18nPeer::DATABASE_NAME);
    +
    +		$criteria->add(ResidenceLevelI18nPeer::ID, $this->id);
    +		$criteria->add(ResidenceLevelI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getId();
    +
    +		$pks[1] = $this->getCulture();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setId($keys[0]);
    +
    +		$this->setCulture($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setName($this->name);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +		$copyObj->setCulture(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new ResidenceLevelI18nPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setResidenceLevel($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setId(NULL);
    +		} else {
    +			$this->setId($v->getId());
    +		}
    +
    +
    +		$this->aResidenceLevel = $v;
    +	}
    +
    +
    +	
    +	public function getResidenceLevel($con = null)
    +	{
    +		if ($this->aResidenceLevel === null && ($this->id !== null)) {
    +						include_once 'lib/model/om/BaseResidenceLevelPeer.php';
    +
    +			$this->aResidenceLevel = ResidenceLevelPeer::retrieveByPK($this->id, $con);
    +
    +			
    +		}
    +		return $this->aResidenceLevel;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseResidenceLevelI18n:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseResidenceLevelI18n::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseResidenceLevelI18nPeer.php b/lib/model/om/BaseResidenceLevelI18nPeer.php
    new file mode 100644
    index 0000000..84e8391
    --- /dev/null
    +++ b/lib/model/om/BaseResidenceLevelI18nPeer.php
    @@ -0,0 +1,569 @@
    + array ('Name', 'Id', 'Culture', ),
    +		BasePeer::TYPE_COLNAME => array (ResidenceLevelI18nPeer::NAME, ResidenceLevelI18nPeer::ID, ResidenceLevelI18nPeer::CULTURE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('name', 'id', 'culture', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Name' => 0, 'Id' => 1, 'Culture' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (ResidenceLevelI18nPeer::NAME => 0, ResidenceLevelI18nPeer::ID => 1, ResidenceLevelI18nPeer::CULTURE => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('name' => 0, 'id' => 1, 'culture' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ResidenceLevelI18nMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ResidenceLevelI18nMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ResidenceLevelI18nPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ResidenceLevelI18nPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ResidenceLevelI18nPeer::NAME);
    +
    +		$criteria->addSelectColumn(ResidenceLevelI18nPeer::ID);
    +
    +		$criteria->addSelectColumn(ResidenceLevelI18nPeer::CULTURE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(residence_level_i18n.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT residence_level_i18n.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ResidenceLevelI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ResidenceLevelI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ResidenceLevelI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ResidenceLevelI18nPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ResidenceLevelI18nPeer::populateObjects(ResidenceLevelI18nPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18nPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidenceLevelI18nPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ResidenceLevelI18nPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ResidenceLevelI18nPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinResidenceLevel(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ResidenceLevelI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ResidenceLevelI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ResidenceLevelI18nPeer::ID, ResidenceLevelPeer::ID);
    +
    +		$rs = ResidenceLevelI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinResidenceLevel(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ResidenceLevelI18nPeer::addSelectColumns($c);
    +		$startcol = (ResidenceLevelI18nPeer::NUM_COLUMNS - ResidenceLevelI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ResidenceLevelPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ResidenceLevelI18nPeer::ID, ResidenceLevelPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ResidenceLevelI18nPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ResidenceLevelPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getResidenceLevel(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addResidenceLevelI18n($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initResidenceLevelI18ns();
    +				$obj2->addResidenceLevelI18n($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ResidenceLevelI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ResidenceLevelI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ResidenceLevelI18nPeer::ID, ResidenceLevelPeer::ID);
    +
    +		$rs = ResidenceLevelI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ResidenceLevelI18nPeer::addSelectColumns($c);
    +		$startcol2 = (ResidenceLevelI18nPeer::NUM_COLUMNS - ResidenceLevelI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ResidenceLevelPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ResidenceLevelPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ResidenceLevelI18nPeer::ID, ResidenceLevelPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ResidenceLevelI18nPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ResidenceLevelPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getResidenceLevel(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addResidenceLevelI18n($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initResidenceLevelI18ns();
    +				$obj2->addResidenceLevelI18n($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ResidenceLevelI18nPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18nPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseResidenceLevelI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18nPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidenceLevelI18nPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18nPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseResidenceLevelI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ResidenceLevelI18nPeer::ID);
    +			$selectCriteria->add(ResidenceLevelI18nPeer::ID, $criteria->remove(ResidenceLevelI18nPeer::ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(ResidenceLevelI18nPeer::CULTURE);
    +			$selectCriteria->add(ResidenceLevelI18nPeer::CULTURE, $criteria->remove(ResidenceLevelI18nPeer::CULTURE), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelI18nPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidenceLevelI18nPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ResidenceLevelI18nPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidenceLevelI18nPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ResidenceLevelI18n) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(ResidenceLevelI18nPeer::ID, $vals[0], Criteria::IN);
    +			$criteria->add(ResidenceLevelI18nPeer::CULTURE, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(ResidenceLevelI18n $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ResidenceLevelI18nPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ResidenceLevelI18nPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ResidenceLevelI18nPeer::DATABASE_NAME, ResidenceLevelI18nPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ResidenceLevelI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $id, $culture, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(ResidenceLevelI18nPeer::ID, $id);
    +		$criteria->add(ResidenceLevelI18nPeer::CULTURE, $culture);
    +		$v = ResidenceLevelI18nPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseResidenceLevelI18nPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ResidenceLevelI18nMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ResidenceLevelI18nMapBuilder');
    +}
    diff --git a/lib/model/om/BaseResidenceLevelPeer.php b/lib/model/om/BaseResidenceLevelPeer.php
    new file mode 100644
    index 0000000..45a1e8f
    --- /dev/null
    +++ b/lib/model/om/BaseResidenceLevelPeer.php
    @@ -0,0 +1,484 @@
    + array ('Id', 'Levelname', 'Listorder', ),
    +		BasePeer::TYPE_COLNAME => array (ResidenceLevelPeer::ID, ResidenceLevelPeer::LEVELNAME, ResidenceLevelPeer::LISTORDER, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'levelname', 'listorder', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Levelname' => 1, 'Listorder' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (ResidenceLevelPeer::ID => 0, ResidenceLevelPeer::LEVELNAME => 1, ResidenceLevelPeer::LISTORDER => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'levelname' => 1, 'listorder' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ResidenceLevelMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ResidenceLevelMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ResidenceLevelPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ResidenceLevelPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ResidenceLevelPeer::ID);
    +
    +		$criteria->addSelectColumn(ResidenceLevelPeer::LEVELNAME);
    +
    +		$criteria->addSelectColumn(ResidenceLevelPeer::LISTORDER);
    +
    +	}
    +
    +	const COUNT = 'COUNT(residence_level.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT residence_level.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ResidenceLevelPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ResidenceLevelPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ResidenceLevelPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ResidenceLevelPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ResidenceLevelPeer::populateObjects(ResidenceLevelPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidenceLevelPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ResidenceLevelPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ResidenceLevelPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +  
    +  public static function doSelectWithI18n(Criteria $c, $culture = null, $con = null)
    +  {
    +    if ($culture === null)
    +    {
    +      $culture = sfContext::getInstance()->getUser()->getCulture();
    +    }
    +
    +        if ($c->getDbName() == Propel::getDefaultDB())
    +    {
    +      $c->setDbName(self::DATABASE_NAME);
    +    }
    +
    +    ResidenceLevelPeer::addSelectColumns($c);
    +    $startcol = (ResidenceLevelPeer::NUM_COLUMNS - ResidenceLevelPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +    ResidenceLevelI18nPeer::addSelectColumns($c);
    +
    +    $c->addJoin(ResidenceLevelPeer::ID, ResidenceLevelI18nPeer::ID);
    +    $c->add(ResidenceLevelI18nPeer::CULTURE, $culture);
    +
    +    $rs = BasePeer::doSelect($c, $con);
    +    $results = array();
    +
    +    while($rs->next()) {
    +
    +      $omClass = ResidenceLevelPeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj1 = new $cls();
    +      $obj1->hydrate($rs);
    +      $obj1->setCulture($culture);
    +
    +      $omClass = ResidenceLevelI18nPeer::getOMClass($rs, $startcol);
    +
    +      $cls = Propel::import($omClass);
    +      $obj2 = new $cls();
    +      $obj2->hydrate($rs, $startcol);
    +
    +      $obj1->setResidenceLevelI18nForCulture($obj2, $culture);
    +      $obj2->setResidenceLevel($obj1);
    +
    +      $results[] = $obj1;
    +    }
    +    return $results;
    +  }
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ResidenceLevelPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseResidenceLevelPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ResidenceLevelPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseResidenceLevelPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidenceLevelPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseResidenceLevelPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ResidenceLevelPeer::ID);
    +			$selectCriteria->add(ResidenceLevelPeer::ID, $criteria->remove(ResidenceLevelPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseResidenceLevelPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidenceLevelPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += ResidenceLevelPeer::doOnDeleteCascade(new Criteria(), $con);
    +			$affectedRows += BasePeer::doDeleteAll(ResidenceLevelPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidenceLevelPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof ResidenceLevel) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ResidenceLevelPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			$affectedRows += ResidenceLevelPeer::doOnDeleteCascade($criteria, $con);
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected static function doOnDeleteCascade(Criteria $criteria, Connection $con)
    +	{
    +				$affectedRows = 0;
    +
    +				$objects = ResidenceLevelPeer::doSelect($criteria, $con);
    +		foreach($objects as $obj) {
    +
    +
    +			include_once 'lib/model/ResidenceLevelI18n.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(ResidenceLevelI18nPeer::ID, $obj->getId());
    +			$affectedRows += ResidenceLevelI18nPeer::doDelete($c, $con);
    +		}
    +		return $affectedRows;
    +	}
    +
    +	
    +	public static function doValidate(ResidenceLevel $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ResidenceLevelPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ResidenceLevelPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ResidenceLevelPeer::DATABASE_NAME, ResidenceLevelPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ResidenceLevelPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ResidenceLevelPeer::DATABASE_NAME);
    +
    +		$criteria->add(ResidenceLevelPeer::ID, $pk);
    +
    +
    +		$v = ResidenceLevelPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ResidenceLevelPeer::ID, $pks, Criteria::IN);
    +			$objs = ResidenceLevelPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseResidenceLevelPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ResidenceLevelMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ResidenceLevelMapBuilder');
    +}
    diff --git a/lib/model/om/BaseResidencePeer.php b/lib/model/om/BaseResidencePeer.php
    new file mode 100644
    index 0000000..beabf4a
    --- /dev/null
    +++ b/lib/model/om/BaseResidencePeer.php
    @@ -0,0 +1,582 @@
    + array ('Id', 'Name', 'Level', 'Parent', ),
    +		BasePeer::TYPE_COLNAME => array (ResidencePeer::ID, ResidencePeer::NAME, ResidencePeer::LEVEL, ResidencePeer::PARENT, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'level', 'parent', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Name' => 1, 'Level' => 2, 'Parent' => 3, ),
    +		BasePeer::TYPE_COLNAME => array (ResidencePeer::ID => 0, ResidencePeer::NAME => 1, ResidencePeer::LEVEL => 2, ResidencePeer::PARENT => 3, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'level' => 2, 'parent' => 3, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/ResidenceMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.ResidenceMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = ResidencePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(ResidencePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(ResidencePeer::ID);
    +
    +		$criteria->addSelectColumn(ResidencePeer::NAME);
    +
    +		$criteria->addSelectColumn(ResidencePeer::LEVEL);
    +
    +		$criteria->addSelectColumn(ResidencePeer::PARENT);
    +
    +	}
    +
    +	const COUNT = 'COUNT(residence.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT residence.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = ResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = ResidencePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return ResidencePeer::populateObjects(ResidencePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidencePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidencePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			ResidencePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = ResidencePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinResidenceLevel(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ResidencePeer::LEVEL, ResidenceLevelPeer::ID);
    +
    +		$rs = ResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinResidenceLevel(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ResidencePeer::addSelectColumns($c);
    +		$startcol = (ResidencePeer::NUM_COLUMNS - ResidencePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ResidenceLevelPeer::addSelectColumns($c);
    +
    +		$c->addJoin(ResidencePeer::LEVEL, ResidenceLevelPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ResidencePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ResidenceLevelPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getResidenceLevel(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addResidence($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initResidences();
    +				$obj2->addResidence($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(ResidencePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(ResidencePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(ResidencePeer::LEVEL, ResidenceLevelPeer::ID);
    +
    +		$rs = ResidencePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		ResidencePeer::addSelectColumns($c);
    +		$startcol2 = (ResidencePeer::NUM_COLUMNS - ResidencePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ResidenceLevelPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ResidenceLevelPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(ResidencePeer::LEVEL, ResidenceLevelPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = ResidencePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = ResidenceLevelPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getResidenceLevel(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addResidence($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initResidences();
    +				$obj2->addResidence($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return ResidencePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidencePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseResidencePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(ResidencePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseResidencePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidencePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseResidencePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseResidencePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(ResidencePeer::ID);
    +			$selectCriteria->add(ResidencePeer::ID, $criteria->remove(ResidencePeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseResidencePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseResidencePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(ResidencePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(ResidencePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof Residence) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(ResidencePeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(Residence $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(ResidencePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(ResidencePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(ResidencePeer::DATABASE_NAME, ResidencePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = ResidencePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(ResidencePeer::DATABASE_NAME);
    +
    +		$criteria->add(ResidencePeer::ID, $pk);
    +
    +
    +		$v = ResidencePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(ResidencePeer::ID, $pks, Criteria::IN);
    +			$objs = ResidencePeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseResidencePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/ResidenceMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.ResidenceMapBuilder');
    +}
    diff --git a/lib/model/om/BaseSubreaktor.php b/lib/model/om/BaseSubreaktor.php
    new file mode 100644
    index 0000000..578bf9f
    --- /dev/null
    +++ b/lib/model/om/BaseSubreaktor.php
    @@ -0,0 +1,1845 @@
    +id;
    +	}
    +
    +	
    +	public function getReference()
    +	{
    +
    +		return $this->reference;
    +	}
    +
    +	
    +	public function getLokalreaktor()
    +	{
    +
    +		return $this->lokalreaktor;
    +	}
    +
    +	
    +	public function getLive()
    +	{
    +
    +		return $this->live;
    +	}
    +
    +	
    +	public function getSubreaktorOrder()
    +	{
    +
    +		return $this->subreaktor_order;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = SubreaktorPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setReference($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->reference !== $v) {
    +			$this->reference = $v;
    +			$this->modifiedColumns[] = SubreaktorPeer::REFERENCE;
    +		}
    +
    +	} 
    +	
    +	public function setLokalreaktor($v)
    +	{
    +
    +		if ($this->lokalreaktor !== $v || $v === false) {
    +			$this->lokalreaktor = $v;
    +			$this->modifiedColumns[] = SubreaktorPeer::LOKALREAKTOR;
    +		}
    +
    +	} 
    +	
    +	public function setLive($v)
    +	{
    +
    +		if ($this->live !== $v || $v === false) {
    +			$this->live = $v;
    +			$this->modifiedColumns[] = SubreaktorPeer::LIVE;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktorOrder($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor_order !== $v || $v === 0) {
    +			$this->subreaktor_order = $v;
    +			$this->modifiedColumns[] = SubreaktorPeer::SUBREAKTOR_ORDER;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->reference = $rs->getString($startcol + 1);
    +
    +			$this->lokalreaktor = $rs->getBoolean($startcol + 2);
    +
    +			$this->live = $rs->getBoolean($startcol + 3);
    +
    +			$this->subreaktor_order = $rs->getInt($startcol + 4);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 5; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating Subreaktor object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktor:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			SubreaktorPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktor:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktor:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseSubreaktor:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = SubreaktorPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += SubreaktorPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			if ($this->collSubreaktorArtworks !== null) {
    +				foreach($this->collSubreaktorArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collRecommendedArtworksRelatedBySubreaktor !== null) {
    +				foreach($this->collRecommendedArtworksRelatedBySubreaktor as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collRecommendedArtworksRelatedByLocalsubreaktor !== null) {
    +				foreach($this->collRecommendedArtworksRelatedByLocalsubreaktor as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collUserInterests !== null) {
    +				foreach($this->collUserInterests as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collLokalreaktorArtworks !== null) {
    +				foreach($this->collLokalreaktorArtworks as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collLokalreaktorResidences !== null) {
    +				foreach($this->collLokalreaktorResidences as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collSubreaktorI18ns !== null) {
    +				foreach($this->collSubreaktorI18ns as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collCategorySubreaktors !== null) {
    +				foreach($this->collCategorySubreaktors as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collArticleSubreaktors !== null) {
    +				foreach($this->collArticleSubreaktors as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			if ($this->collSubreaktorIdentifiers !== null) {
    +				foreach($this->collSubreaktorIdentifiers as $referrerFK) {
    +					if (!$referrerFK->isDeleted()) {
    +						$affectedRows += $referrerFK->save($con);
    +					}
    +				}
    +			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +			if (($retval = SubreaktorPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +				if ($this->collSubreaktorArtworks !== null) {
    +					foreach($this->collSubreaktorArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collRecommendedArtworksRelatedBySubreaktor !== null) {
    +					foreach($this->collRecommendedArtworksRelatedBySubreaktor as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collRecommendedArtworksRelatedByLocalsubreaktor !== null) {
    +					foreach($this->collRecommendedArtworksRelatedByLocalsubreaktor as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collUserInterests !== null) {
    +					foreach($this->collUserInterests as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collLokalreaktorArtworks !== null) {
    +					foreach($this->collLokalreaktorArtworks as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collLokalreaktorResidences !== null) {
    +					foreach($this->collLokalreaktorResidences as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collSubreaktorI18ns !== null) {
    +					foreach($this->collSubreaktorI18ns as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collCategorySubreaktors !== null) {
    +					foreach($this->collCategorySubreaktors as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collArticleSubreaktors !== null) {
    +					foreach($this->collArticleSubreaktors as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +				if ($this->collSubreaktorIdentifiers !== null) {
    +					foreach($this->collSubreaktorIdentifiers as $referrerFK) {
    +						if (!$referrerFK->validate($columns)) {
    +							$failureMap = array_merge($failureMap, $referrerFK->getValidationFailures());
    +						}
    +					}
    +				}
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = SubreaktorPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getReference();
    +				break;
    +			case 2:
    +				return $this->getLokalreaktor();
    +				break;
    +			case 3:
    +				return $this->getLive();
    +				break;
    +			case 4:
    +				return $this->getSubreaktorOrder();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = SubreaktorPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getReference(),
    +			$keys[2] => $this->getLokalreaktor(),
    +			$keys[3] => $this->getLive(),
    +			$keys[4] => $this->getSubreaktorOrder(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = SubreaktorPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setReference($value);
    +				break;
    +			case 2:
    +				$this->setLokalreaktor($value);
    +				break;
    +			case 3:
    +				$this->setLive($value);
    +				break;
    +			case 4:
    +				$this->setSubreaktorOrder($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = SubreaktorPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setReference($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setLokalreaktor($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setLive($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setSubreaktorOrder($arr[$keys[4]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(SubreaktorPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(SubreaktorPeer::ID)) $criteria->add(SubreaktorPeer::ID, $this->id);
    +		if ($this->isColumnModified(SubreaktorPeer::REFERENCE)) $criteria->add(SubreaktorPeer::REFERENCE, $this->reference);
    +		if ($this->isColumnModified(SubreaktorPeer::LOKALREAKTOR)) $criteria->add(SubreaktorPeer::LOKALREAKTOR, $this->lokalreaktor);
    +		if ($this->isColumnModified(SubreaktorPeer::LIVE)) $criteria->add(SubreaktorPeer::LIVE, $this->live);
    +		if ($this->isColumnModified(SubreaktorPeer::SUBREAKTOR_ORDER)) $criteria->add(SubreaktorPeer::SUBREAKTOR_ORDER, $this->subreaktor_order);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(SubreaktorPeer::DATABASE_NAME);
    +
    +		$criteria->add(SubreaktorPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setReference($this->reference);
    +
    +		$copyObj->setLokalreaktor($this->lokalreaktor);
    +
    +		$copyObj->setLive($this->live);
    +
    +		$copyObj->setSubreaktorOrder($this->subreaktor_order);
    +
    +
    +		if ($deepCopy) {
    +									$copyObj->setNew(false);
    +
    +			foreach($this->getSubreaktorArtworks() as $relObj) {
    +				$copyObj->addSubreaktorArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getRecommendedArtworksRelatedBySubreaktor() as $relObj) {
    +				$copyObj->addRecommendedArtworkRelatedBySubreaktor($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getRecommendedArtworksRelatedByLocalsubreaktor() as $relObj) {
    +				$copyObj->addRecommendedArtworkRelatedByLocalsubreaktor($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getUserInterests() as $relObj) {
    +				$copyObj->addUserInterest($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getLokalreaktorArtworks() as $relObj) {
    +				$copyObj->addLokalreaktorArtwork($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getLokalreaktorResidences() as $relObj) {
    +				$copyObj->addLokalreaktorResidence($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getSubreaktorI18ns() as $relObj) {
    +				$copyObj->addSubreaktorI18n($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getCategorySubreaktors() as $relObj) {
    +				$copyObj->addCategorySubreaktor($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getArticleSubreaktors() as $relObj) {
    +				$copyObj->addArticleSubreaktor($relObj->copy($deepCopy));
    +			}
    +
    +			foreach($this->getSubreaktorIdentifiers() as $relObj) {
    +				$copyObj->addSubreaktorIdentifier($relObj->copy($deepCopy));
    +			}
    +
    +		} 
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new SubreaktorPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function initSubreaktorArtworks()
    +	{
    +		if ($this->collSubreaktorArtworks === null) {
    +			$this->collSubreaktorArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getSubreaktorArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collSubreaktorArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collSubreaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				SubreaktorArtworkPeer::addSelectColumns($criteria);
    +				$this->collSubreaktorArtworks = SubreaktorArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				SubreaktorArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastSubreaktorArtworkCriteria) || !$this->lastSubreaktorArtworkCriteria->equals($criteria)) {
    +					$this->collSubreaktorArtworks = SubreaktorArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastSubreaktorArtworkCriteria = $criteria;
    +		return $this->collSubreaktorArtworks;
    +	}
    +
    +	
    +	public function countSubreaktorArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +		return SubreaktorArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addSubreaktorArtwork(SubreaktorArtwork $l)
    +	{
    +		$this->collSubreaktorArtworks[] = $l;
    +		$l->setSubreaktor($this);
    +	}
    +
    +
    +	
    +	public function getSubreaktorArtworksJoinReaktorArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collSubreaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collSubreaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				$this->collSubreaktorArtworks = SubreaktorArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +			if (!isset($this->lastSubreaktorArtworkCriteria) || !$this->lastSubreaktorArtworkCriteria->equals($criteria)) {
    +				$this->collSubreaktorArtworks = SubreaktorArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		}
    +		$this->lastSubreaktorArtworkCriteria = $criteria;
    +
    +		return $this->collSubreaktorArtworks;
    +	}
    +
    +	
    +	public function initRecommendedArtworksRelatedBySubreaktor()
    +	{
    +		if ($this->collRecommendedArtworksRelatedBySubreaktor === null) {
    +			$this->collRecommendedArtworksRelatedBySubreaktor = array();
    +		}
    +	}
    +
    +	
    +	public function getRecommendedArtworksRelatedBySubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworksRelatedBySubreaktor === null) {
    +			if ($this->isNew()) {
    +			   $this->collRecommendedArtworksRelatedBySubreaktor = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::SUBREAKTOR, $this->getId());
    +
    +				RecommendedArtworkPeer::addSelectColumns($criteria);
    +				$this->collRecommendedArtworksRelatedBySubreaktor = RecommendedArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(RecommendedArtworkPeer::SUBREAKTOR, $this->getId());
    +
    +				RecommendedArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastRecommendedArtworkRelatedBySubreaktorCriteria) || !$this->lastRecommendedArtworkRelatedBySubreaktorCriteria->equals($criteria)) {
    +					$this->collRecommendedArtworksRelatedBySubreaktor = RecommendedArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastRecommendedArtworkRelatedBySubreaktorCriteria = $criteria;
    +		return $this->collRecommendedArtworksRelatedBySubreaktor;
    +	}
    +
    +	
    +	public function countRecommendedArtworksRelatedBySubreaktor($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(RecommendedArtworkPeer::SUBREAKTOR, $this->getId());
    +
    +		return RecommendedArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addRecommendedArtworkRelatedBySubreaktor(RecommendedArtwork $l)
    +	{
    +		$this->collRecommendedArtworksRelatedBySubreaktor[] = $l;
    +		$l->setSubreaktorRelatedBySubreaktor($this);
    +	}
    +
    +
    +	
    +	public function getRecommendedArtworksRelatedBySubreaktorJoinReaktorArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworksRelatedBySubreaktor === null) {
    +			if ($this->isNew()) {
    +				$this->collRecommendedArtworksRelatedBySubreaktor = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::SUBREAKTOR, $this->getId());
    +
    +				$this->collRecommendedArtworksRelatedBySubreaktor = RecommendedArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RecommendedArtworkPeer::SUBREAKTOR, $this->getId());
    +
    +			if (!isset($this->lastRecommendedArtworkRelatedBySubreaktorCriteria) || !$this->lastRecommendedArtworkRelatedBySubreaktorCriteria->equals($criteria)) {
    +				$this->collRecommendedArtworksRelatedBySubreaktor = RecommendedArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		}
    +		$this->lastRecommendedArtworkRelatedBySubreaktorCriteria = $criteria;
    +
    +		return $this->collRecommendedArtworksRelatedBySubreaktor;
    +	}
    +
    +
    +	
    +	public function getRecommendedArtworksRelatedBySubreaktorJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworksRelatedBySubreaktor === null) {
    +			if ($this->isNew()) {
    +				$this->collRecommendedArtworksRelatedBySubreaktor = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::SUBREAKTOR, $this->getId());
    +
    +				$this->collRecommendedArtworksRelatedBySubreaktor = RecommendedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RecommendedArtworkPeer::SUBREAKTOR, $this->getId());
    +
    +			if (!isset($this->lastRecommendedArtworkRelatedBySubreaktorCriteria) || !$this->lastRecommendedArtworkRelatedBySubreaktorCriteria->equals($criteria)) {
    +				$this->collRecommendedArtworksRelatedBySubreaktor = RecommendedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastRecommendedArtworkRelatedBySubreaktorCriteria = $criteria;
    +
    +		return $this->collRecommendedArtworksRelatedBySubreaktor;
    +	}
    +
    +	
    +	public function initRecommendedArtworksRelatedByLocalsubreaktor()
    +	{
    +		if ($this->collRecommendedArtworksRelatedByLocalsubreaktor === null) {
    +			$this->collRecommendedArtworksRelatedByLocalsubreaktor = array();
    +		}
    +	}
    +
    +	
    +	public function getRecommendedArtworksRelatedByLocalsubreaktor($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworksRelatedByLocalsubreaktor === null) {
    +			if ($this->isNew()) {
    +			   $this->collRecommendedArtworksRelatedByLocalsubreaktor = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::LOCALSUBREAKTOR, $this->getId());
    +
    +				RecommendedArtworkPeer::addSelectColumns($criteria);
    +				$this->collRecommendedArtworksRelatedByLocalsubreaktor = RecommendedArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(RecommendedArtworkPeer::LOCALSUBREAKTOR, $this->getId());
    +
    +				RecommendedArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria) || !$this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria->equals($criteria)) {
    +					$this->collRecommendedArtworksRelatedByLocalsubreaktor = RecommendedArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria = $criteria;
    +		return $this->collRecommendedArtworksRelatedByLocalsubreaktor;
    +	}
    +
    +	
    +	public function countRecommendedArtworksRelatedByLocalsubreaktor($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(RecommendedArtworkPeer::LOCALSUBREAKTOR, $this->getId());
    +
    +		return RecommendedArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addRecommendedArtworkRelatedByLocalsubreaktor(RecommendedArtwork $l)
    +	{
    +		$this->collRecommendedArtworksRelatedByLocalsubreaktor[] = $l;
    +		$l->setSubreaktorRelatedByLocalsubreaktor($this);
    +	}
    +
    +
    +	
    +	public function getRecommendedArtworksRelatedByLocalsubreaktorJoinReaktorArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworksRelatedByLocalsubreaktor === null) {
    +			if ($this->isNew()) {
    +				$this->collRecommendedArtworksRelatedByLocalsubreaktor = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::LOCALSUBREAKTOR, $this->getId());
    +
    +				$this->collRecommendedArtworksRelatedByLocalsubreaktor = RecommendedArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RecommendedArtworkPeer::LOCALSUBREAKTOR, $this->getId());
    +
    +			if (!isset($this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria) || !$this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria->equals($criteria)) {
    +				$this->collRecommendedArtworksRelatedByLocalsubreaktor = RecommendedArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		}
    +		$this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria = $criteria;
    +
    +		return $this->collRecommendedArtworksRelatedByLocalsubreaktor;
    +	}
    +
    +
    +	
    +	public function getRecommendedArtworksRelatedByLocalsubreaktorJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseRecommendedArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collRecommendedArtworksRelatedByLocalsubreaktor === null) {
    +			if ($this->isNew()) {
    +				$this->collRecommendedArtworksRelatedByLocalsubreaktor = array();
    +			} else {
    +
    +				$criteria->add(RecommendedArtworkPeer::LOCALSUBREAKTOR, $this->getId());
    +
    +				$this->collRecommendedArtworksRelatedByLocalsubreaktor = RecommendedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(RecommendedArtworkPeer::LOCALSUBREAKTOR, $this->getId());
    +
    +			if (!isset($this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria) || !$this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria->equals($criteria)) {
    +				$this->collRecommendedArtworksRelatedByLocalsubreaktor = RecommendedArtworkPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastRecommendedArtworkRelatedByLocalsubreaktorCriteria = $criteria;
    +
    +		return $this->collRecommendedArtworksRelatedByLocalsubreaktor;
    +	}
    +
    +	
    +	public function initUserInterests()
    +	{
    +		if ($this->collUserInterests === null) {
    +			$this->collUserInterests = array();
    +		}
    +	}
    +
    +	
    +	public function getUserInterests($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseUserInterestPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collUserInterests === null) {
    +			if ($this->isNew()) {
    +			   $this->collUserInterests = array();
    +			} else {
    +
    +				$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				UserInterestPeer::addSelectColumns($criteria);
    +				$this->collUserInterests = UserInterestPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				UserInterestPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastUserInterestCriteria) || !$this->lastUserInterestCriteria->equals($criteria)) {
    +					$this->collUserInterests = UserInterestPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastUserInterestCriteria = $criteria;
    +		return $this->collUserInterests;
    +	}
    +
    +	
    +	public function countUserInterests($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseUserInterestPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $this->getId());
    +
    +		return UserInterestPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addUserInterest(UserInterest $l)
    +	{
    +		$this->collUserInterests[] = $l;
    +		$l->setSubreaktor($this);
    +	}
    +
    +
    +	
    +	public function getUserInterestsJoinsfGuardUser($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseUserInterestPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collUserInterests === null) {
    +			if ($this->isNew()) {
    +				$this->collUserInterests = array();
    +			} else {
    +
    +				$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				$this->collUserInterests = UserInterestPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $this->getId());
    +
    +			if (!isset($this->lastUserInterestCriteria) || !$this->lastUserInterestCriteria->equals($criteria)) {
    +				$this->collUserInterests = UserInterestPeer::doSelectJoinsfGuardUser($criteria, $con);
    +			}
    +		}
    +		$this->lastUserInterestCriteria = $criteria;
    +
    +		return $this->collUserInterests;
    +	}
    +
    +	
    +	public function initLokalreaktorArtworks()
    +	{
    +		if ($this->collLokalreaktorArtworks === null) {
    +			$this->collLokalreaktorArtworks = array();
    +		}
    +	}
    +
    +	
    +	public function getLokalreaktorArtworks($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collLokalreaktorArtworks === null) {
    +			if ($this->isNew()) {
    +			   $this->collLokalreaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				LokalreaktorArtworkPeer::addSelectColumns($criteria);
    +				$this->collLokalreaktorArtworks = LokalreaktorArtworkPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				LokalreaktorArtworkPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastLokalreaktorArtworkCriteria) || !$this->lastLokalreaktorArtworkCriteria->equals($criteria)) {
    +					$this->collLokalreaktorArtworks = LokalreaktorArtworkPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastLokalreaktorArtworkCriteria = $criteria;
    +		return $this->collLokalreaktorArtworks;
    +	}
    +
    +	
    +	public function countLokalreaktorArtworks($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +		return LokalreaktorArtworkPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addLokalreaktorArtwork(LokalreaktorArtwork $l)
    +	{
    +		$this->collLokalreaktorArtworks[] = $l;
    +		$l->setSubreaktor($this);
    +	}
    +
    +
    +	
    +	public function getLokalreaktorArtworksJoinReaktorArtwork($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorArtworkPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collLokalreaktorArtworks === null) {
    +			if ($this->isNew()) {
    +				$this->collLokalreaktorArtworks = array();
    +			} else {
    +
    +				$criteria->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				$this->collLokalreaktorArtworks = LokalreaktorArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $this->getId());
    +
    +			if (!isset($this->lastLokalreaktorArtworkCriteria) || !$this->lastLokalreaktorArtworkCriteria->equals($criteria)) {
    +				$this->collLokalreaktorArtworks = LokalreaktorArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con);
    +			}
    +		}
    +		$this->lastLokalreaktorArtworkCriteria = $criteria;
    +
    +		return $this->collLokalreaktorArtworks;
    +	}
    +
    +	
    +	public function initLokalreaktorResidences()
    +	{
    +		if ($this->collLokalreaktorResidences === null) {
    +			$this->collLokalreaktorResidences = array();
    +		}
    +	}
    +
    +	
    +	public function getLokalreaktorResidences($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorResidencePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collLokalreaktorResidences === null) {
    +			if ($this->isNew()) {
    +			   $this->collLokalreaktorResidences = array();
    +			} else {
    +
    +				$criteria->add(LokalreaktorResidencePeer::SUBREAKTOR_ID, $this->getId());
    +
    +				LokalreaktorResidencePeer::addSelectColumns($criteria);
    +				$this->collLokalreaktorResidences = LokalreaktorResidencePeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(LokalreaktorResidencePeer::SUBREAKTOR_ID, $this->getId());
    +
    +				LokalreaktorResidencePeer::addSelectColumns($criteria);
    +				if (!isset($this->lastLokalreaktorResidenceCriteria) || !$this->lastLokalreaktorResidenceCriteria->equals($criteria)) {
    +					$this->collLokalreaktorResidences = LokalreaktorResidencePeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastLokalreaktorResidenceCriteria = $criteria;
    +		return $this->collLokalreaktorResidences;
    +	}
    +
    +	
    +	public function countLokalreaktorResidences($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorResidencePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(LokalreaktorResidencePeer::SUBREAKTOR_ID, $this->getId());
    +
    +		return LokalreaktorResidencePeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addLokalreaktorResidence(LokalreaktorResidence $l)
    +	{
    +		$this->collLokalreaktorResidences[] = $l;
    +		$l->setSubreaktor($this);
    +	}
    +
    +
    +	
    +	public function getLokalreaktorResidencesJoinResidence($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseLokalreaktorResidencePeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collLokalreaktorResidences === null) {
    +			if ($this->isNew()) {
    +				$this->collLokalreaktorResidences = array();
    +			} else {
    +
    +				$criteria->add(LokalreaktorResidencePeer::SUBREAKTOR_ID, $this->getId());
    +
    +				$this->collLokalreaktorResidences = LokalreaktorResidencePeer::doSelectJoinResidence($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(LokalreaktorResidencePeer::SUBREAKTOR_ID, $this->getId());
    +
    +			if (!isset($this->lastLokalreaktorResidenceCriteria) || !$this->lastLokalreaktorResidenceCriteria->equals($criteria)) {
    +				$this->collLokalreaktorResidences = LokalreaktorResidencePeer::doSelectJoinResidence($criteria, $con);
    +			}
    +		}
    +		$this->lastLokalreaktorResidenceCriteria = $criteria;
    +
    +		return $this->collLokalreaktorResidences;
    +	}
    +
    +	
    +	public function initSubreaktorI18ns()
    +	{
    +		if ($this->collSubreaktorI18ns === null) {
    +			$this->collSubreaktorI18ns = array();
    +		}
    +	}
    +
    +	
    +	public function getSubreaktorI18ns($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collSubreaktorI18ns === null) {
    +			if ($this->isNew()) {
    +			   $this->collSubreaktorI18ns = array();
    +			} else {
    +
    +				$criteria->add(SubreaktorI18nPeer::ID, $this->getId());
    +
    +				SubreaktorI18nPeer::addSelectColumns($criteria);
    +				$this->collSubreaktorI18ns = SubreaktorI18nPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(SubreaktorI18nPeer::ID, $this->getId());
    +
    +				SubreaktorI18nPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastSubreaktorI18nCriteria) || !$this->lastSubreaktorI18nCriteria->equals($criteria)) {
    +					$this->collSubreaktorI18ns = SubreaktorI18nPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastSubreaktorI18nCriteria = $criteria;
    +		return $this->collSubreaktorI18ns;
    +	}
    +
    +	
    +	public function countSubreaktorI18ns($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorI18nPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(SubreaktorI18nPeer::ID, $this->getId());
    +
    +		return SubreaktorI18nPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addSubreaktorI18n(SubreaktorI18n $l)
    +	{
    +		$this->collSubreaktorI18ns[] = $l;
    +		$l->setSubreaktor($this);
    +	}
    +
    +	
    +	public function initCategorySubreaktors()
    +	{
    +		if ($this->collCategorySubreaktors === null) {
    +			$this->collCategorySubreaktors = array();
    +		}
    +	}
    +
    +	
    +	public function getCategorySubreaktors($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategorySubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategorySubreaktors === null) {
    +			if ($this->isNew()) {
    +			   $this->collCategorySubreaktors = array();
    +			} else {
    +
    +				$criteria->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				CategorySubreaktorPeer::addSelectColumns($criteria);
    +				$this->collCategorySubreaktors = CategorySubreaktorPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				CategorySubreaktorPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastCategorySubreaktorCriteria) || !$this->lastCategorySubreaktorCriteria->equals($criteria)) {
    +					$this->collCategorySubreaktors = CategorySubreaktorPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastCategorySubreaktorCriteria = $criteria;
    +		return $this->collCategorySubreaktors;
    +	}
    +
    +	
    +	public function countCategorySubreaktors($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategorySubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +		return CategorySubreaktorPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addCategorySubreaktor(CategorySubreaktor $l)
    +	{
    +		$this->collCategorySubreaktors[] = $l;
    +		$l->setSubreaktor($this);
    +	}
    +
    +
    +	
    +	public function getCategorySubreaktorsJoinCategory($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseCategorySubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collCategorySubreaktors === null) {
    +			if ($this->isNew()) {
    +				$this->collCategorySubreaktors = array();
    +			} else {
    +
    +				$criteria->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				$this->collCategorySubreaktors = CategorySubreaktorPeer::doSelectJoinCategory($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(CategorySubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +			if (!isset($this->lastCategorySubreaktorCriteria) || !$this->lastCategorySubreaktorCriteria->equals($criteria)) {
    +				$this->collCategorySubreaktors = CategorySubreaktorPeer::doSelectJoinCategory($criteria, $con);
    +			}
    +		}
    +		$this->lastCategorySubreaktorCriteria = $criteria;
    +
    +		return $this->collCategorySubreaktors;
    +	}
    +
    +	
    +	public function initArticleSubreaktors()
    +	{
    +		if ($this->collArticleSubreaktors === null) {
    +			$this->collArticleSubreaktors = array();
    +		}
    +	}
    +
    +	
    +	public function getArticleSubreaktors($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleSubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleSubreaktors === null) {
    +			if ($this->isNew()) {
    +			   $this->collArticleSubreaktors = array();
    +			} else {
    +
    +				$criteria->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				ArticleSubreaktorPeer::addSelectColumns($criteria);
    +				$this->collArticleSubreaktors = ArticleSubreaktorPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				ArticleSubreaktorPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastArticleSubreaktorCriteria) || !$this->lastArticleSubreaktorCriteria->equals($criteria)) {
    +					$this->collArticleSubreaktors = ArticleSubreaktorPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastArticleSubreaktorCriteria = $criteria;
    +		return $this->collArticleSubreaktors;
    +	}
    +
    +	
    +	public function countArticleSubreaktors($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleSubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +		return ArticleSubreaktorPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addArticleSubreaktor(ArticleSubreaktor $l)
    +	{
    +		$this->collArticleSubreaktors[] = $l;
    +		$l->setSubreaktor($this);
    +	}
    +
    +
    +	
    +	public function getArticleSubreaktorsJoinArticle($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseArticleSubreaktorPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collArticleSubreaktors === null) {
    +			if ($this->isNew()) {
    +				$this->collArticleSubreaktors = array();
    +			} else {
    +
    +				$criteria->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				$this->collArticleSubreaktors = ArticleSubreaktorPeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		} else {
    +									
    +			$criteria->add(ArticleSubreaktorPeer::SUBREAKTOR_ID, $this->getId());
    +
    +			if (!isset($this->lastArticleSubreaktorCriteria) || !$this->lastArticleSubreaktorCriteria->equals($criteria)) {
    +				$this->collArticleSubreaktors = ArticleSubreaktorPeer::doSelectJoinArticle($criteria, $con);
    +			}
    +		}
    +		$this->lastArticleSubreaktorCriteria = $criteria;
    +
    +		return $this->collArticleSubreaktors;
    +	}
    +
    +	
    +	public function initSubreaktorIdentifiers()
    +	{
    +		if ($this->collSubreaktorIdentifiers === null) {
    +			$this->collSubreaktorIdentifiers = array();
    +		}
    +	}
    +
    +	
    +	public function getSubreaktorIdentifiers($criteria = null, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorIdentifierPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		if ($this->collSubreaktorIdentifiers === null) {
    +			if ($this->isNew()) {
    +			   $this->collSubreaktorIdentifiers = array();
    +			} else {
    +
    +				$criteria->add(SubreaktorIdentifierPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				SubreaktorIdentifierPeer::addSelectColumns($criteria);
    +				$this->collSubreaktorIdentifiers = SubreaktorIdentifierPeer::doSelect($criteria, $con);
    +			}
    +		} else {
    +						if (!$this->isNew()) {
    +												
    +
    +				$criteria->add(SubreaktorIdentifierPeer::SUBREAKTOR_ID, $this->getId());
    +
    +				SubreaktorIdentifierPeer::addSelectColumns($criteria);
    +				if (!isset($this->lastSubreaktorIdentifierCriteria) || !$this->lastSubreaktorIdentifierCriteria->equals($criteria)) {
    +					$this->collSubreaktorIdentifiers = SubreaktorIdentifierPeer::doSelect($criteria, $con);
    +				}
    +			}
    +		}
    +		$this->lastSubreaktorIdentifierCriteria = $criteria;
    +		return $this->collSubreaktorIdentifiers;
    +	}
    +
    +	
    +	public function countSubreaktorIdentifiers($criteria = null, $distinct = false, $con = null)
    +	{
    +				include_once 'lib/model/om/BaseSubreaktorIdentifierPeer.php';
    +		if ($criteria === null) {
    +			$criteria = new Criteria();
    +		}
    +		elseif ($criteria instanceof Criteria)
    +		{
    +			$criteria = clone $criteria;
    +		}
    +
    +		$criteria->add(SubreaktorIdentifierPeer::SUBREAKTOR_ID, $this->getId());
    +
    +		return SubreaktorIdentifierPeer::doCount($criteria, $distinct, $con);
    +	}
    +
    +	
    +	public function addSubreaktorIdentifier(SubreaktorIdentifier $l)
    +	{
    +		$this->collSubreaktorIdentifiers[] = $l;
    +		$l->setSubreaktor($this);
    +	}
    +
    +  public function getCulture()
    +  {
    +    return $this->culture;
    +  }
    +
    +  public function setCulture($culture)
    +  {
    +    $this->culture = $culture;
    +  }
    +
    +  public function getName()
    +  {
    +    $obj = $this->getCurrentSubreaktorI18n();
    +
    +    return ($obj ? $obj->getName() : null);
    +  }
    +
    +  public function setName($value)
    +  {
    +    $this->getCurrentSubreaktorI18n()->setName($value);
    +  }
    +
    +  protected $current_i18n = array();
    +
    +  public function getCurrentSubreaktorI18n()
    +  {
    +    if (!isset($this->current_i18n[$this->culture]))
    +    {
    +      $obj = SubreaktorI18nPeer::retrieveByPK($this->getId(), $this->culture);
    +      if ($obj)
    +      {
    +        $this->setSubreaktorI18nForCulture($obj, $this->culture);
    +      }
    +      else
    +      {
    +        $this->setSubreaktorI18nForCulture(new SubreaktorI18n(), $this->culture);
    +        $this->current_i18n[$this->culture]->setCulture($this->culture);
    +      }
    +    }
    +
    +    return $this->current_i18n[$this->culture];
    +  }
    +
    +  public function setSubreaktorI18nForCulture($object, $culture)
    +  {
    +    $this->current_i18n[$culture] = $object;
    +    $this->addSubreaktorI18n($object);
    +  }
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseSubreaktor:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseSubreaktor::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseSubreaktorArtwork.php b/lib/model/om/BaseSubreaktorArtwork.php
    new file mode 100644
    index 0000000..7c14ad4
    --- /dev/null
    +++ b/lib/model/om/BaseSubreaktorArtwork.php
    @@ -0,0 +1,512 @@
    +id;
    +	}
    +
    +	
    +	public function getSubreaktorId()
    +	{
    +
    +		return $this->subreaktor_id;
    +	}
    +
    +	
    +	public function getArtworkId()
    +	{
    +
    +		return $this->artwork_id;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = SubreaktorArtworkPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktorId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor_id !== $v) {
    +			$this->subreaktor_id = $v;
    +			$this->modifiedColumns[] = SubreaktorArtworkPeer::SUBREAKTOR_ID;
    +		}
    +
    +		if ($this->aSubreaktor !== null && $this->aSubreaktor->getId() !== $v) {
    +			$this->aSubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function setArtworkId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->artwork_id !== $v) {
    +			$this->artwork_id = $v;
    +			$this->modifiedColumns[] = SubreaktorArtworkPeer::ARTWORK_ID;
    +		}
    +
    +		if ($this->aReaktorArtwork !== null && $this->aReaktorArtwork->getId() !== $v) {
    +			$this->aReaktorArtwork = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->subreaktor_id = $rs->getInt($startcol + 1);
    +
    +			$this->artwork_id = $rs->getInt($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating SubreaktorArtwork object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtwork:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			SubreaktorArtworkPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtwork:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtwork:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtwork:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if ($this->aSubreaktor->isModified() || $this->aSubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktor->save($con);
    +				}
    +				$this->setSubreaktor($this->aSubreaktor);
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if ($this->aReaktorArtwork->isModified()) {
    +					$affectedRows += $this->aReaktorArtwork->save($con);
    +				}
    +				$this->setReaktorArtwork($this->aReaktorArtwork);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = SubreaktorArtworkPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += SubreaktorArtworkPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if (!$this->aSubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aReaktorArtwork !== null) {
    +				if (!$this->aReaktorArtwork->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aReaktorArtwork->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = SubreaktorArtworkPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = SubreaktorArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getSubreaktorId();
    +				break;
    +			case 2:
    +				return $this->getArtworkId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = SubreaktorArtworkPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getSubreaktorId(),
    +			$keys[2] => $this->getArtworkId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = SubreaktorArtworkPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setSubreaktorId($value);
    +				break;
    +			case 2:
    +				$this->setArtworkId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = SubreaktorArtworkPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setSubreaktorId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setArtworkId($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(SubreaktorArtworkPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(SubreaktorArtworkPeer::ID)) $criteria->add(SubreaktorArtworkPeer::ID, $this->id);
    +		if ($this->isColumnModified(SubreaktorArtworkPeer::SUBREAKTOR_ID)) $criteria->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $this->subreaktor_id);
    +		if ($this->isColumnModified(SubreaktorArtworkPeer::ARTWORK_ID)) $criteria->add(SubreaktorArtworkPeer::ARTWORK_ID, $this->artwork_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(SubreaktorArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(SubreaktorArtworkPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setSubreaktorId($this->subreaktor_id);
    +
    +		$copyObj->setArtworkId($this->artwork_id);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new SubreaktorArtworkPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSubreaktorId(NULL);
    +		} else {
    +			$this->setSubreaktorId($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktor === null && ($this->subreaktor_id !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktor = SubreaktorPeer::retrieveByPK($this->subreaktor_id, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktor;
    +	}
    +
    +	
    +	public function setReaktorArtwork($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setArtworkId(NULL);
    +		} else {
    +			$this->setArtworkId($v->getId());
    +		}
    +
    +
    +		$this->aReaktorArtwork = $v;
    +	}
    +
    +
    +	
    +	public function getReaktorArtwork($con = null)
    +	{
    +		if ($this->aReaktorArtwork === null && ($this->artwork_id !== null)) {
    +						include_once 'lib/model/om/BaseReaktorArtworkPeer.php';
    +
    +			$this->aReaktorArtwork = ReaktorArtworkPeer::retrieveByPK($this->artwork_id, $con);
    +
    +			
    +		}
    +		return $this->aReaktorArtwork;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseSubreaktorArtwork:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseSubreaktorArtwork::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseSubreaktorArtworkPeer.php b/lib/model/om/BaseSubreaktorArtworkPeer.php
    new file mode 100644
    index 0000000..df34e9b
    --- /dev/null
    +++ b/lib/model/om/BaseSubreaktorArtworkPeer.php
    @@ -0,0 +1,852 @@
    + array ('Id', 'SubreaktorId', 'ArtworkId', ),
    +		BasePeer::TYPE_COLNAME => array (SubreaktorArtworkPeer::ID, SubreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorArtworkPeer::ARTWORK_ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'subreaktor_id', 'artwork_id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'SubreaktorId' => 1, 'ArtworkId' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (SubreaktorArtworkPeer::ID => 0, SubreaktorArtworkPeer::SUBREAKTOR_ID => 1, SubreaktorArtworkPeer::ARTWORK_ID => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'subreaktor_id' => 1, 'artwork_id' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/SubreaktorArtworkMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.SubreaktorArtworkMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = SubreaktorArtworkPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(SubreaktorArtworkPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(SubreaktorArtworkPeer::ID);
    +
    +		$criteria->addSelectColumn(SubreaktorArtworkPeer::SUBREAKTOR_ID);
    +
    +		$criteria->addSelectColumn(SubreaktorArtworkPeer::ARTWORK_ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(subreaktor_artwork.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT subreaktor_artwork.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = SubreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = SubreaktorArtworkPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return SubreaktorArtworkPeer::populateObjects(SubreaktorArtworkPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtworkPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorArtworkPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			SubreaktorArtworkPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = SubreaktorArtworkPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = SubreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = SubreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol = (SubreaktorArtworkPeer::NUM_COLUMNS - SubreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(SubreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addSubreaktorArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initSubreaktorArtworks();
    +				$obj2->addSubreaktorArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol = (SubreaktorArtworkPeer::NUM_COLUMNS - SubreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +
    +		$c->addJoin(SubreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addSubreaktorArtwork($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initSubreaktorArtworks();
    +				$obj2->addSubreaktorArtwork($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$criteria->addJoin(SubreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = SubreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (SubreaktorArtworkPeer::NUM_COLUMNS - SubreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(SubreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$c->addJoin(SubreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addSubreaktorArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initSubreaktorArtworks();
    +				$obj2->addSubreaktorArtwork($obj1);
    +			}
    +
    +
    +					
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addSubreaktorArtwork($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initSubreaktorArtworks();
    +				$obj3->addSubreaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +		$rs = SubreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptReaktorArtwork(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorArtworkPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = SubreaktorArtworkPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (SubreaktorArtworkPeer::NUM_COLUMNS - SubreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		ReaktorArtworkPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(SubreaktorArtworkPeer::ARTWORK_ID, ReaktorArtworkPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = ReaktorArtworkPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getReaktorArtwork(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addSubreaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initSubreaktorArtworks();
    +				$obj2->addSubreaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptReaktorArtwork(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorArtworkPeer::addSelectColumns($c);
    +		$startcol2 = (SubreaktorArtworkPeer::NUM_COLUMNS - SubreaktorArtworkPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(SubreaktorArtworkPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorArtworkPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addSubreaktorArtwork($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initSubreaktorArtworks();
    +				$obj2->addSubreaktorArtwork($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return SubreaktorArtworkPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtworkPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseSubreaktorArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(SubreaktorArtworkPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtworkPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorArtworkPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtworkPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseSubreaktorArtworkPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(SubreaktorArtworkPeer::ID);
    +			$selectCriteria->add(SubreaktorArtworkPeer::ID, $criteria->remove(SubreaktorArtworkPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorArtworkPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorArtworkPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(SubreaktorArtworkPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorArtworkPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof SubreaktorArtwork) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(SubreaktorArtworkPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(SubreaktorArtwork $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(SubreaktorArtworkPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(SubreaktorArtworkPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(SubreaktorArtworkPeer::DATABASE_NAME, SubreaktorArtworkPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = SubreaktorArtworkPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(SubreaktorArtworkPeer::DATABASE_NAME);
    +
    +		$criteria->add(SubreaktorArtworkPeer::ID, $pk);
    +
    +
    +		$v = SubreaktorArtworkPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(SubreaktorArtworkPeer::ID, $pks, Criteria::IN);
    +			$objs = SubreaktorArtworkPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseSubreaktorArtworkPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/SubreaktorArtworkMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.SubreaktorArtworkMapBuilder');
    +}
    diff --git a/lib/model/om/BaseSubreaktorI18n.php b/lib/model/om/BaseSubreaktorI18n.php
    new file mode 100644
    index 0000000..d19d694
    --- /dev/null
    +++ b/lib/model/om/BaseSubreaktorI18n.php
    @@ -0,0 +1,472 @@
    +name;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function getCulture()
    +	{
    +
    +		return $this->culture;
    +	}
    +
    +	
    +	public function setName($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->name !== $v) {
    +			$this->name = $v;
    +			$this->modifiedColumns[] = SubreaktorI18nPeer::NAME;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = SubreaktorI18nPeer::ID;
    +		}
    +
    +		if ($this->aSubreaktor !== null && $this->aSubreaktor->getId() !== $v) {
    +			$this->aSubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function setCulture($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->culture !== $v) {
    +			$this->culture = $v;
    +			$this->modifiedColumns[] = SubreaktorI18nPeer::CULTURE;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->name = $rs->getString($startcol + 0);
    +
    +			$this->id = $rs->getInt($startcol + 1);
    +
    +			$this->culture = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating SubreaktorI18n object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18n:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			SubreaktorI18nPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18n:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18n:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorI18nPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18n:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if ($this->aSubreaktor->isModified() || $this->aSubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktor->save($con);
    +				}
    +				$this->setSubreaktor($this->aSubreaktor);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = SubreaktorI18nPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += SubreaktorI18nPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if (!$this->aSubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = SubreaktorI18nPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = SubreaktorI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getName();
    +				break;
    +			case 1:
    +				return $this->getId();
    +				break;
    +			case 2:
    +				return $this->getCulture();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = SubreaktorI18nPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getName(),
    +			$keys[1] => $this->getId(),
    +			$keys[2] => $this->getCulture(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = SubreaktorI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setName($value);
    +				break;
    +			case 1:
    +				$this->setId($value);
    +				break;
    +			case 2:
    +				$this->setCulture($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = SubreaktorI18nPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setName($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setCulture($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(SubreaktorI18nPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(SubreaktorI18nPeer::NAME)) $criteria->add(SubreaktorI18nPeer::NAME, $this->name);
    +		if ($this->isColumnModified(SubreaktorI18nPeer::ID)) $criteria->add(SubreaktorI18nPeer::ID, $this->id);
    +		if ($this->isColumnModified(SubreaktorI18nPeer::CULTURE)) $criteria->add(SubreaktorI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(SubreaktorI18nPeer::DATABASE_NAME);
    +
    +		$criteria->add(SubreaktorI18nPeer::ID, $this->id);
    +		$criteria->add(SubreaktorI18nPeer::CULTURE, $this->culture);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getId();
    +
    +		$pks[1] = $this->getCulture();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setId($keys[0]);
    +
    +		$this->setCulture($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setName($this->name);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +		$copyObj->setCulture(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new SubreaktorI18nPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setId(NULL);
    +		} else {
    +			$this->setId($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktor === null && ($this->id !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktor = SubreaktorPeer::retrieveByPK($this->id, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktor;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseSubreaktorI18n:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseSubreaktorI18n::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseSubreaktorI18nPeer.php b/lib/model/om/BaseSubreaktorI18nPeer.php
    new file mode 100644
    index 0000000..f36916e
    --- /dev/null
    +++ b/lib/model/om/BaseSubreaktorI18nPeer.php
    @@ -0,0 +1,569 @@
    + array ('Name', 'Id', 'Culture', ),
    +		BasePeer::TYPE_COLNAME => array (SubreaktorI18nPeer::NAME, SubreaktorI18nPeer::ID, SubreaktorI18nPeer::CULTURE, ),
    +		BasePeer::TYPE_FIELDNAME => array ('name', 'id', 'culture', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Name' => 0, 'Id' => 1, 'Culture' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (SubreaktorI18nPeer::NAME => 0, SubreaktorI18nPeer::ID => 1, SubreaktorI18nPeer::CULTURE => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('name' => 0, 'id' => 1, 'culture' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/SubreaktorI18nMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.SubreaktorI18nMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = SubreaktorI18nPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(SubreaktorI18nPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(SubreaktorI18nPeer::NAME);
    +
    +		$criteria->addSelectColumn(SubreaktorI18nPeer::ID);
    +
    +		$criteria->addSelectColumn(SubreaktorI18nPeer::CULTURE);
    +
    +	}
    +
    +	const COUNT = 'COUNT(subreaktor_i18n.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT subreaktor_i18n.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = SubreaktorI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = SubreaktorI18nPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return SubreaktorI18nPeer::populateObjects(SubreaktorI18nPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18nPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorI18nPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			SubreaktorI18nPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = SubreaktorI18nPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorI18nPeer::ID, SubreaktorPeer::ID);
    +
    +		$rs = SubreaktorI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorI18nPeer::addSelectColumns($c);
    +		$startcol = (SubreaktorI18nPeer::NUM_COLUMNS - SubreaktorI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(SubreaktorI18nPeer::ID, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorI18nPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addSubreaktorI18n($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initSubreaktorI18ns();
    +				$obj2->addSubreaktorI18n($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorI18nPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorI18nPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorI18nPeer::ID, SubreaktorPeer::ID);
    +
    +		$rs = SubreaktorI18nPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorI18nPeer::addSelectColumns($c);
    +		$startcol2 = (SubreaktorI18nPeer::NUM_COLUMNS - SubreaktorI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(SubreaktorI18nPeer::ID, SubreaktorPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorI18nPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addSubreaktorI18n($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initSubreaktorI18ns();
    +				$obj2->addSubreaktorI18n($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return SubreaktorI18nPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18nPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseSubreaktorI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18nPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorI18nPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18nPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseSubreaktorI18nPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(SubreaktorI18nPeer::ID);
    +			$selectCriteria->add(SubreaktorI18nPeer::ID, $criteria->remove(SubreaktorI18nPeer::ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(SubreaktorI18nPeer::CULTURE);
    +			$selectCriteria->add(SubreaktorI18nPeer::CULTURE, $criteria->remove(SubreaktorI18nPeer::CULTURE), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorI18nPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorI18nPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(SubreaktorI18nPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorI18nPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof SubreaktorI18n) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(SubreaktorI18nPeer::ID, $vals[0], Criteria::IN);
    +			$criteria->add(SubreaktorI18nPeer::CULTURE, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(SubreaktorI18n $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(SubreaktorI18nPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(SubreaktorI18nPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(SubreaktorI18nPeer::DATABASE_NAME, SubreaktorI18nPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = SubreaktorI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $id, $culture, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(SubreaktorI18nPeer::ID, $id);
    +		$criteria->add(SubreaktorI18nPeer::CULTURE, $culture);
    +		$v = SubreaktorI18nPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseSubreaktorI18nPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/SubreaktorI18nMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.SubreaktorI18nMapBuilder');
    +}
    diff --git a/lib/model/om/BaseSubreaktorIdentifier.php b/lib/model/om/BaseSubreaktorIdentifier.php
    new file mode 100644
    index 0000000..be0a337
    --- /dev/null
    +++ b/lib/model/om/BaseSubreaktorIdentifier.php
    @@ -0,0 +1,463 @@
    +id;
    +	}
    +
    +	
    +	public function getSubreaktorId()
    +	{
    +
    +		return $this->subreaktor_id;
    +	}
    +
    +	
    +	public function getIdentifier()
    +	{
    +
    +		return $this->identifier;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = SubreaktorIdentifierPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktorId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor_id !== $v) {
    +			$this->subreaktor_id = $v;
    +			$this->modifiedColumns[] = SubreaktorIdentifierPeer::SUBREAKTOR_ID;
    +		}
    +
    +		if ($this->aSubreaktor !== null && $this->aSubreaktor->getId() !== $v) {
    +			$this->aSubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function setIdentifier($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->identifier !== $v) {
    +			$this->identifier = $v;
    +			$this->modifiedColumns[] = SubreaktorIdentifierPeer::IDENTIFIER;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->subreaktor_id = $rs->getInt($startcol + 1);
    +
    +			$this->identifier = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating SubreaktorIdentifier object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifier:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorIdentifierPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			SubreaktorIdentifierPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifier:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifier:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorIdentifierPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifier:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if ($this->aSubreaktor->isModified() || $this->aSubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktor->save($con);
    +				}
    +				$this->setSubreaktor($this->aSubreaktor);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = SubreaktorIdentifierPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += SubreaktorIdentifierPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aSubreaktor !== null) {
    +				if (!$this->aSubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = SubreaktorIdentifierPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = SubreaktorIdentifierPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getSubreaktorId();
    +				break;
    +			case 2:
    +				return $this->getIdentifier();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = SubreaktorIdentifierPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getSubreaktorId(),
    +			$keys[2] => $this->getIdentifier(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = SubreaktorIdentifierPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setSubreaktorId($value);
    +				break;
    +			case 2:
    +				$this->setIdentifier($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = SubreaktorIdentifierPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setSubreaktorId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setIdentifier($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(SubreaktorIdentifierPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(SubreaktorIdentifierPeer::ID)) $criteria->add(SubreaktorIdentifierPeer::ID, $this->id);
    +		if ($this->isColumnModified(SubreaktorIdentifierPeer::SUBREAKTOR_ID)) $criteria->add(SubreaktorIdentifierPeer::SUBREAKTOR_ID, $this->subreaktor_id);
    +		if ($this->isColumnModified(SubreaktorIdentifierPeer::IDENTIFIER)) $criteria->add(SubreaktorIdentifierPeer::IDENTIFIER, $this->identifier);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(SubreaktorIdentifierPeer::DATABASE_NAME);
    +
    +		$criteria->add(SubreaktorIdentifierPeer::ID, $this->id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setSubreaktorId($this->subreaktor_id);
    +
    +		$copyObj->setIdentifier($this->identifier);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new SubreaktorIdentifierPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSubreaktorId(NULL);
    +		} else {
    +			$this->setSubreaktorId($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktor === null && ($this->subreaktor_id !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktor = SubreaktorPeer::retrieveByPK($this->subreaktor_id, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktor;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseSubreaktorIdentifier:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseSubreaktorIdentifier::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseSubreaktorIdentifierPeer.php b/lib/model/om/BaseSubreaktorIdentifierPeer.php
    new file mode 100644
    index 0000000..3e7d671
    --- /dev/null
    +++ b/lib/model/om/BaseSubreaktorIdentifierPeer.php
    @@ -0,0 +1,577 @@
    + array ('Id', 'SubreaktorId', 'Identifier', ),
    +		BasePeer::TYPE_COLNAME => array (SubreaktorIdentifierPeer::ID, SubreaktorIdentifierPeer::SUBREAKTOR_ID, SubreaktorIdentifierPeer::IDENTIFIER, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'subreaktor_id', 'identifier', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'SubreaktorId' => 1, 'Identifier' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (SubreaktorIdentifierPeer::ID => 0, SubreaktorIdentifierPeer::SUBREAKTOR_ID => 1, SubreaktorIdentifierPeer::IDENTIFIER => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'subreaktor_id' => 1, 'identifier' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/SubreaktorIdentifierMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.SubreaktorIdentifierMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = SubreaktorIdentifierPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(SubreaktorIdentifierPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(SubreaktorIdentifierPeer::ID);
    +
    +		$criteria->addSelectColumn(SubreaktorIdentifierPeer::SUBREAKTOR_ID);
    +
    +		$criteria->addSelectColumn(SubreaktorIdentifierPeer::IDENTIFIER);
    +
    +	}
    +
    +	const COUNT = 'COUNT(subreaktor_identifier.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT subreaktor_identifier.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorIdentifierPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorIdentifierPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = SubreaktorIdentifierPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = SubreaktorIdentifierPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return SubreaktorIdentifierPeer::populateObjects(SubreaktorIdentifierPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifierPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorIdentifierPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			SubreaktorIdentifierPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = SubreaktorIdentifierPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorIdentifierPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorIdentifierPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorIdentifierPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = SubreaktorIdentifierPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorIdentifierPeer::addSelectColumns($c);
    +		$startcol = (SubreaktorIdentifierPeer::NUM_COLUMNS - SubreaktorIdentifierPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(SubreaktorIdentifierPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorIdentifierPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addSubreaktorIdentifier($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initSubreaktorIdentifiers();
    +				$obj2->addSubreaktorIdentifier($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorIdentifierPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorIdentifierPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(SubreaktorIdentifierPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = SubreaktorIdentifierPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		SubreaktorIdentifierPeer::addSelectColumns($c);
    +		$startcol2 = (SubreaktorIdentifierPeer::NUM_COLUMNS - SubreaktorIdentifierPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(SubreaktorIdentifierPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = SubreaktorIdentifierPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addSubreaktorIdentifier($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initSubreaktorIdentifiers();
    +				$obj2->addSubreaktorIdentifier($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return SubreaktorIdentifierPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifierPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseSubreaktorIdentifierPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(SubreaktorIdentifierPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifierPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorIdentifierPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifierPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseSubreaktorIdentifierPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(SubreaktorIdentifierPeer::ID);
    +			$selectCriteria->add(SubreaktorIdentifierPeer::ID, $criteria->remove(SubreaktorIdentifierPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorIdentifierPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorIdentifierPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(SubreaktorIdentifierPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorIdentifierPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof SubreaktorIdentifier) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(SubreaktorIdentifierPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(SubreaktorIdentifier $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(SubreaktorIdentifierPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(SubreaktorIdentifierPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(SubreaktorIdentifierPeer::DATABASE_NAME, SubreaktorIdentifierPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = SubreaktorIdentifierPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(SubreaktorIdentifierPeer::DATABASE_NAME);
    +
    +		$criteria->add(SubreaktorIdentifierPeer::ID, $pk);
    +
    +
    +		$v = SubreaktorIdentifierPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(SubreaktorIdentifierPeer::ID, $pks, Criteria::IN);
    +			$objs = SubreaktorIdentifierPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseSubreaktorIdentifierPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/SubreaktorIdentifierMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.SubreaktorIdentifierMapBuilder');
    +}
    diff --git a/lib/model/om/BaseSubreaktorPeer.php b/lib/model/om/BaseSubreaktorPeer.php
    new file mode 100644
    index 0000000..ca14869
    --- /dev/null
    +++ b/lib/model/om/BaseSubreaktorPeer.php
    @@ -0,0 +1,501 @@
    + array ('Id', 'Reference', 'Lokalreaktor', 'Live', 'SubreaktorOrder', ),
    +		BasePeer::TYPE_COLNAME => array (SubreaktorPeer::ID, SubreaktorPeer::REFERENCE, SubreaktorPeer::LOKALREAKTOR, SubreaktorPeer::LIVE, SubreaktorPeer::SUBREAKTOR_ORDER, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'reference', 'lokalreaktor', 'live', 'subreaktor_order', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Reference' => 1, 'Lokalreaktor' => 2, 'Live' => 3, 'SubreaktorOrder' => 4, ),
    +		BasePeer::TYPE_COLNAME => array (SubreaktorPeer::ID => 0, SubreaktorPeer::REFERENCE => 1, SubreaktorPeer::LOKALREAKTOR => 2, SubreaktorPeer::LIVE => 3, SubreaktorPeer::SUBREAKTOR_ORDER => 4, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'reference' => 1, 'lokalreaktor' => 2, 'live' => 3, 'subreaktor_order' => 4, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/SubreaktorMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.SubreaktorMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = SubreaktorPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(SubreaktorPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(SubreaktorPeer::ID);
    +
    +		$criteria->addSelectColumn(SubreaktorPeer::REFERENCE);
    +
    +		$criteria->addSelectColumn(SubreaktorPeer::LOKALREAKTOR);
    +
    +		$criteria->addSelectColumn(SubreaktorPeer::LIVE);
    +
    +		$criteria->addSelectColumn(SubreaktorPeer::SUBREAKTOR_ORDER);
    +
    +	}
    +
    +	const COUNT = 'COUNT(subreaktor.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT subreaktor.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(SubreaktorPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(SubreaktorPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = SubreaktorPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = SubreaktorPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return SubreaktorPeer::populateObjects(SubreaktorPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			SubreaktorPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = SubreaktorPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +  
    +  public static function doSelectWithI18n(Criteria $c, $culture = null, $con = null)
    +  {
    +    if ($culture === null)
    +    {
    +      $culture = sfContext::getInstance()->getUser()->getCulture();
    +    }
    +
    +        if ($c->getDbName() == Propel::getDefaultDB())
    +    {
    +      $c->setDbName(self::DATABASE_NAME);
    +    }
    +
    +    SubreaktorPeer::addSelectColumns($c);
    +    $startcol = (SubreaktorPeer::NUM_COLUMNS - SubreaktorPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +    SubreaktorI18nPeer::addSelectColumns($c);
    +
    +    $c->addJoin(SubreaktorPeer::ID, SubreaktorI18nPeer::ID);
    +    $c->add(SubreaktorI18nPeer::CULTURE, $culture);
    +
    +    $rs = BasePeer::doSelect($c, $con);
    +    $results = array();
    +
    +    while($rs->next()) {
    +
    +      $omClass = SubreaktorPeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj1 = new $cls();
    +      $obj1->hydrate($rs);
    +      $obj1->setCulture($culture);
    +
    +      $omClass = SubreaktorI18nPeer::getOMClass($rs, $startcol);
    +
    +      $cls = Propel::import($omClass);
    +      $obj2 = new $cls();
    +      $obj2->hydrate($rs, $startcol);
    +
    +      $obj1->setSubreaktorI18nForCulture($obj2, $culture);
    +      $obj2->setSubreaktor($obj1);
    +
    +      $results[] = $obj1;
    +    }
    +    return $results;
    +  }
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return SubreaktorPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseSubreaktorPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(SubreaktorPeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseSubreaktorPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseSubreaktorPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(SubreaktorPeer::ID);
    +			$selectCriteria->add(SubreaktorPeer::ID, $criteria->remove(SubreaktorPeer::ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseSubreaktorPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseSubreaktorPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += SubreaktorPeer::doOnDeleteCascade(new Criteria(), $con);
    +			$affectedRows += BasePeer::doDeleteAll(SubreaktorPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(SubreaktorPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof Subreaktor) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(SubreaktorPeer::ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			$affectedRows += SubreaktorPeer::doOnDeleteCascade($criteria, $con);
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected static function doOnDeleteCascade(Criteria $criteria, Connection $con)
    +	{
    +				$affectedRows = 0;
    +
    +				$objects = SubreaktorPeer::doSelect($criteria, $con);
    +		foreach($objects as $obj) {
    +
    +
    +			include_once 'lib/model/UserInterest.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(UserInterestPeer::SUBREAKTOR_ID, $obj->getId());
    +			$affectedRows += UserInterestPeer::doDelete($c, $con);
    +
    +			include_once 'lib/model/SubreaktorI18n.php';
    +
    +						$c = new Criteria();
    +			
    +			$c->add(SubreaktorI18nPeer::ID, $obj->getId());
    +			$affectedRows += SubreaktorI18nPeer::doDelete($c, $con);
    +		}
    +		return $affectedRows;
    +	}
    +
    +	
    +	public static function doValidate(Subreaktor $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(SubreaktorPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(SubreaktorPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(SubreaktorPeer::DATABASE_NAME, SubreaktorPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = SubreaktorPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(SubreaktorPeer::DATABASE_NAME);
    +
    +		$criteria->add(SubreaktorPeer::ID, $pk);
    +
    +
    +		$v = SubreaktorPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(SubreaktorPeer::ID, $pks, Criteria::IN);
    +			$objs = SubreaktorPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseSubreaktorPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/SubreaktorMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.SubreaktorMapBuilder');
    +}
    diff --git a/lib/model/om/BaseTransUnit.php b/lib/model/om/BaseTransUnit.php
    new file mode 100644
    index 0000000..5ff4d78
    --- /dev/null
    +++ b/lib/model/om/BaseTransUnit.php
    @@ -0,0 +1,817 @@
    +msg_id;
    +	}
    +
    +	
    +	public function getCatId()
    +	{
    +
    +		return $this->cat_id;
    +	}
    +
    +	
    +	public function getId()
    +	{
    +
    +		return $this->id;
    +	}
    +
    +	
    +	public function getSource()
    +	{
    +
    +		return $this->source;
    +	}
    +
    +	
    +	public function getTarget()
    +	{
    +
    +		return $this->target;
    +	}
    +
    +	
    +	public function getModule()
    +	{
    +
    +		return $this->module;
    +	}
    +
    +	
    +	public function getFilename()
    +	{
    +
    +		return $this->filename;
    +	}
    +
    +	
    +	public function getComments()
    +	{
    +
    +		return $this->comments;
    +	}
    +
    +	
    +	public function getDateAdded()
    +	{
    +
    +		return $this->date_added;
    +	}
    +
    +	
    +	public function getDateModified()
    +	{
    +
    +		return $this->date_modified;
    +	}
    +
    +	
    +	public function getAuthor()
    +	{
    +
    +		return $this->author;
    +	}
    +
    +	
    +	public function getTranslated()
    +	{
    +
    +		return $this->translated;
    +	}
    +
    +	
    +	public function setMsgId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->msg_id !== $v) {
    +			$this->msg_id = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::MSG_ID;
    +		}
    +
    +	} 
    +	
    +	public function setCatId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->cat_id !== $v || $v === 1) {
    +			$this->cat_id = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::CAT_ID;
    +		}
    +
    +		if ($this->aCatalogue !== null && $this->aCatalogue->getCatId() !== $v) {
    +			$this->aCatalogue = null;
    +		}
    +
    +	} 
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->id !== $v || $v === '') {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setSource($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->source !== $v) {
    +			$this->source = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::SOURCE;
    +		}
    +
    +	} 
    +	
    +	public function setTarget($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->target !== $v) {
    +			$this->target = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::TARGET;
    +		}
    +
    +	} 
    +	
    +	public function setModule($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->module !== $v || $v === '') {
    +			$this->module = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::MODULE;
    +		}
    +
    +	} 
    +	
    +	public function setFilename($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->filename !== $v || $v === '') {
    +			$this->filename = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::FILENAME;
    +		}
    +
    +	} 
    +	
    +	public function setComments($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->comments !== $v) {
    +			$this->comments = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::COMMENTS;
    +		}
    +
    +	} 
    +	
    +	public function setDateAdded($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->date_added !== $v || $v === 0) {
    +			$this->date_added = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::DATE_ADDED;
    +		}
    +
    +	} 
    +	
    +	public function setDateModified($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->date_modified !== $v || $v === 0) {
    +			$this->date_modified = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::DATE_MODIFIED;
    +		}
    +
    +	} 
    +	
    +	public function setAuthor($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->author !== $v || $v === '') {
    +			$this->author = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::AUTHOR;
    +		}
    +
    +	} 
    +	
    +	public function setTranslated($v)
    +	{
    +
    +		if ($this->translated !== $v || $v === false) {
    +			$this->translated = $v;
    +			$this->modifiedColumns[] = TransUnitPeer::TRANSLATED;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->msg_id = $rs->getInt($startcol + 0);
    +
    +			$this->cat_id = $rs->getInt($startcol + 1);
    +
    +			$this->id = $rs->getString($startcol + 2);
    +
    +			$this->source = $rs->getString($startcol + 3);
    +
    +			$this->target = $rs->getString($startcol + 4);
    +
    +			$this->module = $rs->getString($startcol + 5);
    +
    +			$this->filename = $rs->getString($startcol + 6);
    +
    +			$this->comments = $rs->getString($startcol + 7);
    +
    +			$this->date_added = $rs->getInt($startcol + 8);
    +
    +			$this->date_modified = $rs->getInt($startcol + 9);
    +
    +			$this->author = $rs->getString($startcol + 10);
    +
    +			$this->translated = $rs->getBoolean($startcol + 11);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 12; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating TransUnit object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseTransUnit:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(TransUnitPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			TransUnitPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseTransUnit:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseTransUnit:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(TransUnitPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseTransUnit:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->aCatalogue !== null) {
    +				if ($this->aCatalogue->isModified()) {
    +					$affectedRows += $this->aCatalogue->save($con);
    +				}
    +				$this->setCatalogue($this->aCatalogue);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = TransUnitPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setMsgId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += TransUnitPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->aCatalogue !== null) {
    +				if (!$this->aCatalogue->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aCatalogue->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = TransUnitPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = TransUnitPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getMsgId();
    +				break;
    +			case 1:
    +				return $this->getCatId();
    +				break;
    +			case 2:
    +				return $this->getId();
    +				break;
    +			case 3:
    +				return $this->getSource();
    +				break;
    +			case 4:
    +				return $this->getTarget();
    +				break;
    +			case 5:
    +				return $this->getModule();
    +				break;
    +			case 6:
    +				return $this->getFilename();
    +				break;
    +			case 7:
    +				return $this->getComments();
    +				break;
    +			case 8:
    +				return $this->getDateAdded();
    +				break;
    +			case 9:
    +				return $this->getDateModified();
    +				break;
    +			case 10:
    +				return $this->getAuthor();
    +				break;
    +			case 11:
    +				return $this->getTranslated();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = TransUnitPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getMsgId(),
    +			$keys[1] => $this->getCatId(),
    +			$keys[2] => $this->getId(),
    +			$keys[3] => $this->getSource(),
    +			$keys[4] => $this->getTarget(),
    +			$keys[5] => $this->getModule(),
    +			$keys[6] => $this->getFilename(),
    +			$keys[7] => $this->getComments(),
    +			$keys[8] => $this->getDateAdded(),
    +			$keys[9] => $this->getDateModified(),
    +			$keys[10] => $this->getAuthor(),
    +			$keys[11] => $this->getTranslated(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = TransUnitPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setMsgId($value);
    +				break;
    +			case 1:
    +				$this->setCatId($value);
    +				break;
    +			case 2:
    +				$this->setId($value);
    +				break;
    +			case 3:
    +				$this->setSource($value);
    +				break;
    +			case 4:
    +				$this->setTarget($value);
    +				break;
    +			case 5:
    +				$this->setModule($value);
    +				break;
    +			case 6:
    +				$this->setFilename($value);
    +				break;
    +			case 7:
    +				$this->setComments($value);
    +				break;
    +			case 8:
    +				$this->setDateAdded($value);
    +				break;
    +			case 9:
    +				$this->setDateModified($value);
    +				break;
    +			case 10:
    +				$this->setAuthor($value);
    +				break;
    +			case 11:
    +				$this->setTranslated($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = TransUnitPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setMsgId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setCatId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setId($arr[$keys[2]]);
    +		if (array_key_exists($keys[3], $arr)) $this->setSource($arr[$keys[3]]);
    +		if (array_key_exists($keys[4], $arr)) $this->setTarget($arr[$keys[4]]);
    +		if (array_key_exists($keys[5], $arr)) $this->setModule($arr[$keys[5]]);
    +		if (array_key_exists($keys[6], $arr)) $this->setFilename($arr[$keys[6]]);
    +		if (array_key_exists($keys[7], $arr)) $this->setComments($arr[$keys[7]]);
    +		if (array_key_exists($keys[8], $arr)) $this->setDateAdded($arr[$keys[8]]);
    +		if (array_key_exists($keys[9], $arr)) $this->setDateModified($arr[$keys[9]]);
    +		if (array_key_exists($keys[10], $arr)) $this->setAuthor($arr[$keys[10]]);
    +		if (array_key_exists($keys[11], $arr)) $this->setTranslated($arr[$keys[11]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(TransUnitPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(TransUnitPeer::MSG_ID)) $criteria->add(TransUnitPeer::MSG_ID, $this->msg_id);
    +		if ($this->isColumnModified(TransUnitPeer::CAT_ID)) $criteria->add(TransUnitPeer::CAT_ID, $this->cat_id);
    +		if ($this->isColumnModified(TransUnitPeer::ID)) $criteria->add(TransUnitPeer::ID, $this->id);
    +		if ($this->isColumnModified(TransUnitPeer::SOURCE)) $criteria->add(TransUnitPeer::SOURCE, $this->source);
    +		if ($this->isColumnModified(TransUnitPeer::TARGET)) $criteria->add(TransUnitPeer::TARGET, $this->target);
    +		if ($this->isColumnModified(TransUnitPeer::MODULE)) $criteria->add(TransUnitPeer::MODULE, $this->module);
    +		if ($this->isColumnModified(TransUnitPeer::FILENAME)) $criteria->add(TransUnitPeer::FILENAME, $this->filename);
    +		if ($this->isColumnModified(TransUnitPeer::COMMENTS)) $criteria->add(TransUnitPeer::COMMENTS, $this->comments);
    +		if ($this->isColumnModified(TransUnitPeer::DATE_ADDED)) $criteria->add(TransUnitPeer::DATE_ADDED, $this->date_added);
    +		if ($this->isColumnModified(TransUnitPeer::DATE_MODIFIED)) $criteria->add(TransUnitPeer::DATE_MODIFIED, $this->date_modified);
    +		if ($this->isColumnModified(TransUnitPeer::AUTHOR)) $criteria->add(TransUnitPeer::AUTHOR, $this->author);
    +		if ($this->isColumnModified(TransUnitPeer::TRANSLATED)) $criteria->add(TransUnitPeer::TRANSLATED, $this->translated);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(TransUnitPeer::DATABASE_NAME);
    +
    +		$criteria->add(TransUnitPeer::MSG_ID, $this->msg_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		return $this->getMsgId();
    +	}
    +
    +	
    +	public function setPrimaryKey($key)
    +	{
    +		$this->setMsgId($key);
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setCatId($this->cat_id);
    +
    +		$copyObj->setId($this->id);
    +
    +		$copyObj->setSource($this->source);
    +
    +		$copyObj->setTarget($this->target);
    +
    +		$copyObj->setModule($this->module);
    +
    +		$copyObj->setFilename($this->filename);
    +
    +		$copyObj->setComments($this->comments);
    +
    +		$copyObj->setDateAdded($this->date_added);
    +
    +		$copyObj->setDateModified($this->date_modified);
    +
    +		$copyObj->setAuthor($this->author);
    +
    +		$copyObj->setTranslated($this->translated);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setMsgId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new TransUnitPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setCatalogue($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setCatId('1');
    +		} else {
    +			$this->setCatId($v->getCatId());
    +		}
    +
    +
    +		$this->aCatalogue = $v;
    +	}
    +
    +
    +	
    +	public function getCatalogue($con = null)
    +	{
    +		if ($this->aCatalogue === null && ($this->cat_id !== null)) {
    +						include_once 'lib/model/om/BaseCataloguePeer.php';
    +
    +			$this->aCatalogue = CataloguePeer::retrieveByPK($this->cat_id, $con);
    +
    +			
    +		}
    +		return $this->aCatalogue;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseTransUnit:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseTransUnit::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseTransUnitPeer.php b/lib/model/om/BaseTransUnitPeer.php
    new file mode 100644
    index 0000000..59108ce
    --- /dev/null
    +++ b/lib/model/om/BaseTransUnitPeer.php
    @@ -0,0 +1,622 @@
    + array ('MsgId', 'CatId', 'Id', 'Source', 'Target', 'Module', 'Filename', 'Comments', 'DateAdded', 'DateModified', 'Author', 'Translated', ),
    +		BasePeer::TYPE_COLNAME => array (TransUnitPeer::MSG_ID, TransUnitPeer::CAT_ID, TransUnitPeer::ID, TransUnitPeer::SOURCE, TransUnitPeer::TARGET, TransUnitPeer::MODULE, TransUnitPeer::FILENAME, TransUnitPeer::COMMENTS, TransUnitPeer::DATE_ADDED, TransUnitPeer::DATE_MODIFIED, TransUnitPeer::AUTHOR, TransUnitPeer::TRANSLATED, ),
    +		BasePeer::TYPE_FIELDNAME => array ('msg_id', 'cat_id', 'id', 'source', 'target', 'module', 'filename', 'comments', 'date_added', 'date_modified', 'author', 'translated', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('MsgId' => 0, 'CatId' => 1, 'Id' => 2, 'Source' => 3, 'Target' => 4, 'Module' => 5, 'Filename' => 6, 'Comments' => 7, 'DateAdded' => 8, 'DateModified' => 9, 'Author' => 10, 'Translated' => 11, ),
    +		BasePeer::TYPE_COLNAME => array (TransUnitPeer::MSG_ID => 0, TransUnitPeer::CAT_ID => 1, TransUnitPeer::ID => 2, TransUnitPeer::SOURCE => 3, TransUnitPeer::TARGET => 4, TransUnitPeer::MODULE => 5, TransUnitPeer::FILENAME => 6, TransUnitPeer::COMMENTS => 7, TransUnitPeer::DATE_ADDED => 8, TransUnitPeer::DATE_MODIFIED => 9, TransUnitPeer::AUTHOR => 10, TransUnitPeer::TRANSLATED => 11, ),
    +		BasePeer::TYPE_FIELDNAME => array ('msg_id' => 0, 'cat_id' => 1, 'id' => 2, 'source' => 3, 'target' => 4, 'module' => 5, 'filename' => 6, 'comments' => 7, 'date_added' => 8, 'date_modified' => 9, 'author' => 10, 'translated' => 11, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/TransUnitMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.TransUnitMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = TransUnitPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(TransUnitPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(TransUnitPeer::MSG_ID);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::CAT_ID);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::ID);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::SOURCE);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::TARGET);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::MODULE);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::FILENAME);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::COMMENTS);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::DATE_ADDED);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::DATE_MODIFIED);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::AUTHOR);
    +
    +		$criteria->addSelectColumn(TransUnitPeer::TRANSLATED);
    +
    +	}
    +
    +	const COUNT = 'COUNT(trans_unit.MSG_ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT trans_unit.MSG_ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(TransUnitPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(TransUnitPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = TransUnitPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = TransUnitPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return TransUnitPeer::populateObjects(TransUnitPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseTransUnitPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseTransUnitPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			TransUnitPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = TransUnitPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinCatalogue(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(TransUnitPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(TransUnitPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(TransUnitPeer::CAT_ID, CataloguePeer::CAT_ID);
    +
    +		$rs = TransUnitPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinCatalogue(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		TransUnitPeer::addSelectColumns($c);
    +		$startcol = (TransUnitPeer::NUM_COLUMNS - TransUnitPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		CataloguePeer::addSelectColumns($c);
    +
    +		$c->addJoin(TransUnitPeer::CAT_ID, CataloguePeer::CAT_ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = TransUnitPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = CataloguePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getCatalogue(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addTransUnit($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initTransUnits();
    +				$obj2->addTransUnit($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(TransUnitPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(TransUnitPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(TransUnitPeer::CAT_ID, CataloguePeer::CAT_ID);
    +
    +		$rs = TransUnitPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		TransUnitPeer::addSelectColumns($c);
    +		$startcol2 = (TransUnitPeer::NUM_COLUMNS - TransUnitPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		CataloguePeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + CataloguePeer::NUM_COLUMNS;
    +
    +		$c->addJoin(TransUnitPeer::CAT_ID, CataloguePeer::CAT_ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = TransUnitPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = CataloguePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getCatalogue(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addTransUnit($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initTransUnits();
    +				$obj2->addTransUnit($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return TransUnitPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseTransUnitPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseTransUnitPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(TransUnitPeer::MSG_ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseTransUnitPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseTransUnitPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseTransUnitPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseTransUnitPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(TransUnitPeer::MSG_ID);
    +			$selectCriteria->add(TransUnitPeer::MSG_ID, $criteria->remove(TransUnitPeer::MSG_ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseTransUnitPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseTransUnitPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(TransUnitPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(TransUnitPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof TransUnit) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +			$criteria->add(TransUnitPeer::MSG_ID, (array) $values, Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(TransUnit $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(TransUnitPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(TransUnitPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(TransUnitPeer::DATABASE_NAME, TransUnitPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = TransUnitPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK($pk, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$criteria = new Criteria(TransUnitPeer::DATABASE_NAME);
    +
    +		$criteria->add(TransUnitPeer::MSG_ID, $pk);
    +
    +
    +		$v = TransUnitPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) > 0 ? $v[0] : null;
    +	}
    +
    +	
    +	public static function retrieveByPKs($pks, $con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$objs = null;
    +		if (empty($pks)) {
    +			$objs = array();
    +		} else {
    +			$criteria = new Criteria();
    +			$criteria->add(TransUnitPeer::MSG_ID, $pks, Criteria::IN);
    +			$objs = TransUnitPeer::doSelect($criteria, $con);
    +		}
    +		return $objs;
    +	}
    +
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseTransUnitPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/TransUnitMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.TransUnitMapBuilder');
    +}
    diff --git a/lib/model/om/BaseUserInterest.php b/lib/model/om/BaseUserInterest.php
    new file mode 100644
    index 0000000..a92275a
    --- /dev/null
    +++ b/lib/model/om/BaseUserInterest.php
    @@ -0,0 +1,481 @@
    +user_id;
    +	}
    +
    +	
    +	public function getSubreaktorId()
    +	{
    +
    +		return $this->subreaktor_id;
    +	}
    +
    +	
    +	public function setUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->user_id !== $v) {
    +			$this->user_id = $v;
    +			$this->modifiedColumns[] = UserInterestPeer::USER_ID;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setSubreaktorId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->subreaktor_id !== $v) {
    +			$this->subreaktor_id = $v;
    +			$this->modifiedColumns[] = UserInterestPeer::SUBREAKTOR_ID;
    +		}
    +
    +		if ($this->aSubreaktor !== null && $this->aSubreaktor->getId() !== $v) {
    +			$this->aSubreaktor = null;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->user_id = $rs->getInt($startcol + 0);
    +
    +			$this->subreaktor_id = $rs->getInt($startcol + 1);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 2; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating UserInterest object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserInterest:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(UserInterestPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			UserInterestPeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseUserInterest:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserInterest:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(UserInterestPeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseUserInterest:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +			if ($this->aSubreaktor !== null) {
    +				if ($this->aSubreaktor->isModified() || $this->aSubreaktor->getCurrentSubreaktorI18n()->isModified()) {
    +					$affectedRows += $this->aSubreaktor->save($con);
    +				}
    +				$this->setSubreaktor($this->aSubreaktor);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = UserInterestPeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += UserInterestPeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +			if ($this->aSubreaktor !== null) {
    +				if (!$this->aSubreaktor->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->aSubreaktor->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = UserInterestPeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = UserInterestPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getUserId();
    +				break;
    +			case 1:
    +				return $this->getSubreaktorId();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = UserInterestPeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getUserId(),
    +			$keys[1] => $this->getSubreaktorId(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = UserInterestPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setUserId($value);
    +				break;
    +			case 1:
    +				$this->setSubreaktorId($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = UserInterestPeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setUserId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setSubreaktorId($arr[$keys[1]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(UserInterestPeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(UserInterestPeer::USER_ID)) $criteria->add(UserInterestPeer::USER_ID, $this->user_id);
    +		if ($this->isColumnModified(UserInterestPeer::SUBREAKTOR_ID)) $criteria->add(UserInterestPeer::SUBREAKTOR_ID, $this->subreaktor_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(UserInterestPeer::DATABASE_NAME);
    +
    +		$criteria->add(UserInterestPeer::USER_ID, $this->user_id);
    +		$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $this->subreaktor_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getUserId();
    +
    +		$pks[1] = $this->getSubreaktorId();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setUserId($keys[0]);
    +
    +		$this->setSubreaktorId($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setUserId(NULL); 
    +		$copyObj->setSubreaktorId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new UserInterestPeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUserId(NULL);
    +		} else {
    +			$this->setUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +	
    +	public function setSubreaktor($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setSubreaktorId(NULL);
    +		} else {
    +			$this->setSubreaktorId($v->getId());
    +		}
    +
    +
    +		$this->aSubreaktor = $v;
    +	}
    +
    +
    +	
    +	public function getSubreaktor($con = null)
    +	{
    +		if ($this->aSubreaktor === null && ($this->subreaktor_id !== null)) {
    +						include_once 'lib/model/om/BaseSubreaktorPeer.php';
    +
    +			$this->aSubreaktor = SubreaktorPeer::retrieveByPK($this->subreaktor_id, $con);
    +
    +			
    +		}
    +		return $this->aSubreaktor;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseUserInterest:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseUserInterest::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseUserInterestPeer.php b/lib/model/om/BaseUserInterestPeer.php
    new file mode 100644
    index 0000000..1b031b4
    --- /dev/null
    +++ b/lib/model/om/BaseUserInterestPeer.php
    @@ -0,0 +1,839 @@
    + array ('UserId', 'SubreaktorId', ),
    +		BasePeer::TYPE_COLNAME => array (UserInterestPeer::USER_ID, UserInterestPeer::SUBREAKTOR_ID, ),
    +		BasePeer::TYPE_FIELDNAME => array ('user_id', 'subreaktor_id', ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('UserId' => 0, 'SubreaktorId' => 1, ),
    +		BasePeer::TYPE_COLNAME => array (UserInterestPeer::USER_ID => 0, UserInterestPeer::SUBREAKTOR_ID => 1, ),
    +		BasePeer::TYPE_FIELDNAME => array ('user_id' => 0, 'subreaktor_id' => 1, ),
    +		BasePeer::TYPE_NUM => array (0, 1, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/UserInterestMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.UserInterestMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = UserInterestPeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(UserInterestPeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(UserInterestPeer::USER_ID);
    +
    +		$criteria->addSelectColumn(UserInterestPeer::SUBREAKTOR_ID);
    +
    +	}
    +
    +	const COUNT = 'COUNT(user_interest.USER_ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT user_interest.USER_ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = UserInterestPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = UserInterestPeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return UserInterestPeer::populateObjects(UserInterestPeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserInterestPeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseUserInterestPeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			UserInterestPeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = UserInterestPeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(UserInterestPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = UserInterestPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(UserInterestPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = UserInterestPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		UserInterestPeer::addSelectColumns($c);
    +		$startcol = (UserInterestPeer::NUM_COLUMNS - UserInterestPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(UserInterestPeer::USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = UserInterestPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addUserInterest($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initUserInterests();
    +				$obj2->addUserInterest($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		UserInterestPeer::addSelectColumns($c);
    +		$startcol = (UserInterestPeer::NUM_COLUMNS - UserInterestPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		SubreaktorPeer::addSelectColumns($c);
    +
    +		$c->addJoin(UserInterestPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = UserInterestPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addUserInterest($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initUserInterests();
    +				$obj2->addUserInterest($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(UserInterestPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$criteria->addJoin(UserInterestPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = UserInterestPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		UserInterestPeer::addSelectColumns($c);
    +		$startcol2 = (UserInterestPeer::NUM_COLUMNS - UserInterestPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol4 = $startcol3 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(UserInterestPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$c->addJoin(UserInterestPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = UserInterestPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addUserInterest($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initUserInterests();
    +				$obj2->addUserInterest($obj1);
    +			}
    +
    +
    +					
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj3 = new $cls();
    +			$obj3->hydrate($rs, $startcol3);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj3 = $temp_obj1->getSubreaktor(); 				if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj3->addUserInterest($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj3->initUserInterests();
    +				$obj3->addUserInterest($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(UserInterestPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +		$rs = UserInterestPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doCountJoinAllExceptSubreaktor(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserInterestPeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(UserInterestPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = UserInterestPeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		UserInterestPeer::addSelectColumns($c);
    +		$startcol2 = (UserInterestPeer::NUM_COLUMNS - UserInterestPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		SubreaktorPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + SubreaktorPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(UserInterestPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = UserInterestPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = SubreaktorPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getSubreaktor(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addUserInterest($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initUserInterests();
    +				$obj2->addUserInterest($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAllExceptSubreaktor(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +								if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		UserInterestPeer::addSelectColumns($c);
    +		$startcol2 = (UserInterestPeer::NUM_COLUMNS - UserInterestPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(UserInterestPeer::USER_ID, sfGuardUserPeer::ID);
    +
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = UserInterestPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2  = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addUserInterest($obj1);
    +					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initUserInterests();
    +				$obj2->addUserInterest($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return UserInterestPeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserInterestPeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseUserInterestPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseUserInterestPeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseUserInterestPeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserInterestPeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseUserInterestPeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(UserInterestPeer::USER_ID);
    +			$selectCriteria->add(UserInterestPeer::USER_ID, $criteria->remove(UserInterestPeer::USER_ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(UserInterestPeer::SUBREAKTOR_ID);
    +			$selectCriteria->add(UserInterestPeer::SUBREAKTOR_ID, $criteria->remove(UserInterestPeer::SUBREAKTOR_ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseUserInterestPeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseUserInterestPeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(UserInterestPeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(UserInterestPeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof UserInterest) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(UserInterestPeer::USER_ID, $vals[0], Criteria::IN);
    +			$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(UserInterest $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(UserInterestPeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(UserInterestPeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(UserInterestPeer::DATABASE_NAME, UserInterestPeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = UserInterestPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $user_id, $subreaktor_id, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(UserInterestPeer::USER_ID, $user_id);
    +		$criteria->add(UserInterestPeer::SUBREAKTOR_ID, $subreaktor_id);
    +		$v = UserInterestPeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseUserInterestPeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/UserInterestMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.UserInterestMapBuilder');
    +}
    diff --git a/lib/model/om/BaseUserResource.php b/lib/model/om/BaseUserResource.php
    new file mode 100644
    index 0000000..0262174
    --- /dev/null
    +++ b/lib/model/om/BaseUserResource.php
    @@ -0,0 +1,473 @@
    +id;
    +	}
    +
    +	
    +	public function getUserId()
    +	{
    +
    +		return $this->user_id;
    +	}
    +
    +	
    +	public function getUrl()
    +	{
    +
    +		return $this->url;
    +	}
    +
    +	
    +	public function setId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->id !== $v) {
    +			$this->id = $v;
    +			$this->modifiedColumns[] = UserResourcePeer::ID;
    +		}
    +
    +	} 
    +	
    +	public function setUserId($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_int($v) && is_numeric($v)) {
    +			$v = (int) $v;
    +		}
    +
    +		if ($this->user_id !== $v) {
    +			$this->user_id = $v;
    +			$this->modifiedColumns[] = UserResourcePeer::USER_ID;
    +		}
    +
    +		if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) {
    +			$this->asfGuardUser = null;
    +		}
    +
    +	} 
    +	
    +	public function setUrl($v)
    +	{
    +
    +		
    +		
    +		if ($v !== null && !is_string($v)) {
    +			$v = (string) $v; 
    +		}
    +
    +		if ($this->url !== $v) {
    +			$this->url = $v;
    +			$this->modifiedColumns[] = UserResourcePeer::URL;
    +		}
    +
    +	} 
    +	
    +	public function hydrate(ResultSet $rs, $startcol = 1)
    +	{
    +		try {
    +
    +			$this->id = $rs->getInt($startcol + 0);
    +
    +			$this->user_id = $rs->getInt($startcol + 1);
    +
    +			$this->url = $rs->getString($startcol + 2);
    +
    +			$this->resetModified();
    +
    +			$this->setNew(false);
    +
    +						return $startcol + 3; 
    +		} catch (Exception $e) {
    +			throw new PropelException("Error populating UserResource object", $e);
    +		}
    +	}
    +
    +	
    +	public function delete($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserResource:delete:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, $this, $con);
    +      if ($ret)
    +      {
    +        return;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("This object has already been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(UserResourcePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			UserResourcePeer::doDelete($this, $con);
    +			$this->setDeleted(true);
    +			$con->commit();
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	
    +
    +    foreach (sfMixer::getCallables('BaseUserResource:delete:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con);
    +    }
    +
    +  }
    +	
    +	public function save($con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserResource:save:pre') as $callable)
    +    {
    +      $affectedRows = call_user_func($callable, $this, $con);
    +      if (is_int($affectedRows))
    +      {
    +        return $affectedRows;
    +      }
    +    }
    +
    +
    +		if ($this->isDeleted()) {
    +			throw new PropelException("You cannot save an object that has been deleted.");
    +		}
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(UserResourcePeer::DATABASE_NAME);
    +		}
    +
    +		try {
    +			$con->begin();
    +			$affectedRows = $this->doSave($con);
    +			$con->commit();
    +    foreach (sfMixer::getCallables('BaseUserResource:save:post') as $callable)
    +    {
    +      call_user_func($callable, $this, $con, $affectedRows);
    +    }
    +
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	protected function doSave($con)
    +	{
    +		$affectedRows = 0; 		if (!$this->alreadyInSave) {
    +			$this->alreadyInSave = true;
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if ($this->asfGuardUser->isModified()) {
    +					$affectedRows += $this->asfGuardUser->save($con);
    +				}
    +				$this->setsfGuardUser($this->asfGuardUser);
    +			}
    +
    +
    +						if ($this->isModified()) {
    +				if ($this->isNew()) {
    +					$pk = UserResourcePeer::doInsert($this, $con);
    +					$affectedRows += 1; 										 										 
    +					$this->setId($pk);  
    +					$this->setNew(false);
    +				} else {
    +					$affectedRows += UserResourcePeer::doUpdate($this, $con);
    +				}
    +				$this->resetModified(); 			}
    +
    +			$this->alreadyInSave = false;
    +		}
    +		return $affectedRows;
    +	} 
    +	
    +	protected $validationFailures = array();
    +
    +	
    +	public function getValidationFailures()
    +	{
    +		return $this->validationFailures;
    +	}
    +
    +	
    +	public function validate($columns = null)
    +	{
    +		$res = $this->doValidate($columns);
    +		if ($res === true) {
    +			$this->validationFailures = array();
    +			return true;
    +		} else {
    +			$this->validationFailures = $res;
    +			return false;
    +		}
    +	}
    +
    +	
    +	protected function doValidate($columns = null)
    +	{
    +		if (!$this->alreadyInValidation) {
    +			$this->alreadyInValidation = true;
    +			$retval = null;
    +
    +			$failureMap = array();
    +
    +
    +												
    +			if ($this->asfGuardUser !== null) {
    +				if (!$this->asfGuardUser->validate($columns)) {
    +					$failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures());
    +				}
    +			}
    +
    +
    +			if (($retval = UserResourcePeer::doValidate($this, $columns)) !== true) {
    +				$failureMap = array_merge($failureMap, $retval);
    +			}
    +
    +
    +
    +			$this->alreadyInValidation = false;
    +		}
    +
    +		return (!empty($failureMap) ? $failureMap : true);
    +	}
    +
    +	
    +	public function getByName($name, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = UserResourcePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->getByPosition($pos);
    +	}
    +
    +	
    +	public function getByPosition($pos)
    +	{
    +		switch($pos) {
    +			case 0:
    +				return $this->getId();
    +				break;
    +			case 1:
    +				return $this->getUserId();
    +				break;
    +			case 2:
    +				return $this->getUrl();
    +				break;
    +			default:
    +				return null;
    +				break;
    +		} 	}
    +
    +	
    +	public function toArray($keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = UserResourcePeer::getFieldNames($keyType);
    +		$result = array(
    +			$keys[0] => $this->getId(),
    +			$keys[1] => $this->getUserId(),
    +			$keys[2] => $this->getUrl(),
    +		);
    +		return $result;
    +	}
    +
    +	
    +	public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME)
    +	{
    +		$pos = UserResourcePeer::translateFieldName($name, $type, BasePeer::TYPE_NUM);
    +		return $this->setByPosition($pos, $value);
    +	}
    +
    +	
    +	public function setByPosition($pos, $value)
    +	{
    +		switch($pos) {
    +			case 0:
    +				$this->setId($value);
    +				break;
    +			case 1:
    +				$this->setUserId($value);
    +				break;
    +			case 2:
    +				$this->setUrl($value);
    +				break;
    +		} 	}
    +
    +	
    +	public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    +	{
    +		$keys = UserResourcePeer::getFieldNames($keyType);
    +
    +		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    +		if (array_key_exists($keys[1], $arr)) $this->setUserId($arr[$keys[1]]);
    +		if (array_key_exists($keys[2], $arr)) $this->setUrl($arr[$keys[2]]);
    +	}
    +
    +	
    +	public function buildCriteria()
    +	{
    +		$criteria = new Criteria(UserResourcePeer::DATABASE_NAME);
    +
    +		if ($this->isColumnModified(UserResourcePeer::ID)) $criteria->add(UserResourcePeer::ID, $this->id);
    +		if ($this->isColumnModified(UserResourcePeer::USER_ID)) $criteria->add(UserResourcePeer::USER_ID, $this->user_id);
    +		if ($this->isColumnModified(UserResourcePeer::URL)) $criteria->add(UserResourcePeer::URL, $this->url);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function buildPkeyCriteria()
    +	{
    +		$criteria = new Criteria(UserResourcePeer::DATABASE_NAME);
    +
    +		$criteria->add(UserResourcePeer::ID, $this->id);
    +		$criteria->add(UserResourcePeer::USER_ID, $this->user_id);
    +
    +		return $criteria;
    +	}
    +
    +	
    +	public function getPrimaryKey()
    +	{
    +		$pks = array();
    +
    +		$pks[0] = $this->getId();
    +
    +		$pks[1] = $this->getUserId();
    +
    +		return $pks;
    +	}
    +
    +	
    +	public function setPrimaryKey($keys)
    +	{
    +
    +		$this->setId($keys[0]);
    +
    +		$this->setUserId($keys[1]);
    +
    +	}
    +
    +	
    +	public function copyInto($copyObj, $deepCopy = false)
    +	{
    +
    +		$copyObj->setUrl($this->url);
    +
    +
    +		$copyObj->setNew(true);
    +
    +		$copyObj->setId(NULL); 
    +		$copyObj->setUserId(NULL); 
    +	}
    +
    +	
    +	public function copy($deepCopy = false)
    +	{
    +				$clazz = get_class($this);
    +		$copyObj = new $clazz();
    +		$this->copyInto($copyObj, $deepCopy);
    +		return $copyObj;
    +	}
    +
    +	
    +	public function getPeer()
    +	{
    +		if (self::$peer === null) {
    +			self::$peer = new UserResourcePeer();
    +		}
    +		return self::$peer;
    +	}
    +
    +	
    +	public function setsfGuardUser($v)
    +	{
    +
    +
    +		if ($v === null) {
    +			$this->setUserId(NULL);
    +		} else {
    +			$this->setUserId($v->getId());
    +		}
    +
    +
    +		$this->asfGuardUser = $v;
    +	}
    +
    +
    +	
    +	public function getsfGuardUser($con = null)
    +	{
    +		if ($this->asfGuardUser === null && ($this->user_id !== null)) {
    +						include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php';
    +
    +			$this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con);
    +
    +			
    +		}
    +		return $this->asfGuardUser;
    +	}
    +
    +
    +  public function __call($method, $arguments)
    +  {
    +    if (!$callable = sfMixer::getCallable('BaseUserResource:'.$method))
    +    {
    +      throw new sfException(sprintf('Call to undefined method BaseUserResource::%s', $method));
    +    }
    +
    +    array_unshift($arguments, $this);
    +
    +    return call_user_func_array($callable, $arguments);
    +  }
    +
    +
    +} 
    \ No newline at end of file
    diff --git a/lib/model/om/BaseUserResourcePeer.php b/lib/model/om/BaseUserResourcePeer.php
    new file mode 100644
    index 0000000..648c257
    --- /dev/null
    +++ b/lib/model/om/BaseUserResourcePeer.php
    @@ -0,0 +1,570 @@
    + array ('Id', 'UserId', 'Url', ),
    +		BasePeer::TYPE_COLNAME => array (UserResourcePeer::ID, UserResourcePeer::USER_ID, UserResourcePeer::URL, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id', 'user_id', 'url', ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	private static $fieldKeys = array (
    +		BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'UserId' => 1, 'Url' => 2, ),
    +		BasePeer::TYPE_COLNAME => array (UserResourcePeer::ID => 0, UserResourcePeer::USER_ID => 1, UserResourcePeer::URL => 2, ),
    +		BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'user_id' => 1, 'url' => 2, ),
    +		BasePeer::TYPE_NUM => array (0, 1, 2, )
    +	);
    +
    +	
    +	public static function getMapBuilder()
    +	{
    +		include_once 'lib/model/map/UserResourceMapBuilder.php';
    +		return BasePeer::getMapBuilder('lib.model.map.UserResourceMapBuilder');
    +	}
    +	
    +	public static function getPhpNameMap()
    +	{
    +		if (self::$phpNameMap === null) {
    +			$map = UserResourcePeer::getTableMap();
    +			$columns = $map->getColumns();
    +			$nameMap = array();
    +			foreach ($columns as $column) {
    +				$nameMap[$column->getPhpName()] = $column->getColumnName();
    +			}
    +			self::$phpNameMap = $nameMap;
    +		}
    +		return self::$phpNameMap;
    +	}
    +	
    +	static public function translateFieldName($name, $fromType, $toType)
    +	{
    +		$toNames = self::getFieldNames($toType);
    +		$key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null;
    +		if ($key === null) {
    +			throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true));
    +		}
    +		return $toNames[$key];
    +	}
    +
    +	
    +
    +	static public function getFieldNames($type = BasePeer::TYPE_PHPNAME)
    +	{
    +		if (!array_key_exists($type, self::$fieldNames)) {
    +			throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.');
    +		}
    +		return self::$fieldNames[$type];
    +	}
    +
    +	
    +	public static function alias($alias, $column)
    +	{
    +		return str_replace(UserResourcePeer::TABLE_NAME.'.', $alias.'.', $column);
    +	}
    +
    +	
    +	public static function addSelectColumns(Criteria $criteria)
    +	{
    +
    +		$criteria->addSelectColumn(UserResourcePeer::ID);
    +
    +		$criteria->addSelectColumn(UserResourcePeer::USER_ID);
    +
    +		$criteria->addSelectColumn(UserResourcePeer::URL);
    +
    +	}
    +
    +	const COUNT = 'COUNT(user_resource.ID)';
    +	const COUNT_DISTINCT = 'COUNT(DISTINCT user_resource.ID)';
    +
    +	
    +	public static function doCount(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserResourcePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserResourcePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$rs = UserResourcePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +	
    +	public static function doSelectOne(Criteria $criteria, $con = null)
    +	{
    +		$critcopy = clone $criteria;
    +		$critcopy->setLimit(1);
    +		$objects = UserResourcePeer::doSelect($critcopy, $con);
    +		if ($objects) {
    +			return $objects[0];
    +		}
    +		return null;
    +	}
    +	
    +	public static function doSelect(Criteria $criteria, $con = null)
    +	{
    +		return UserResourcePeer::populateObjects(UserResourcePeer::doSelectRS($criteria, $con));
    +	}
    +	
    +	public static function doSelectRS(Criteria $criteria, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserResourcePeer:addDoSelectRS:addDoSelectRS') as $callable)
    +    {
    +      call_user_func($callable, 'BaseUserResourcePeer', $criteria, $con);
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if (!$criteria->getSelectColumns()) {
    +			$criteria = clone $criteria;
    +			UserResourcePeer::addSelectColumns($criteria);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +						return BasePeer::doSelect($criteria, $con);
    +	}
    +	
    +	public static function populateObjects(ResultSet $rs)
    +	{
    +		$results = array();
    +	
    +				$cls = UserResourcePeer::getOMClass();
    +		$cls = Propel::import($cls);
    +				while($rs->next()) {
    +		
    +			$obj = new $cls();
    +			$obj->hydrate($rs);
    +			$results[] = $obj;
    +			
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +				$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserResourcePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserResourcePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(UserResourcePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = UserResourcePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinsfGuardUser(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		UserResourcePeer::addSelectColumns($c);
    +		$startcol = (UserResourcePeer::NUM_COLUMNS - UserResourcePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +		sfGuardUserPeer::addSelectColumns($c);
    +
    +		$c->addJoin(UserResourcePeer::USER_ID, sfGuardUserPeer::ID);
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = UserResourcePeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol);
    +
    +			$newObject = true;
    +			foreach($results as $temp_obj1) {
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +										$temp_obj2->addUserResource($obj1); 					break;
    +				}
    +			}
    +			if ($newObject) {
    +				$obj2->initUserResources();
    +				$obj2->addUserResource($obj1); 			}
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +
    +	
    +	public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null)
    +	{
    +		$criteria = clone $criteria;
    +
    +				$criteria->clearSelectColumns()->clearOrderByColumns();
    +		if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) {
    +			$criteria->addSelectColumn(UserResourcePeer::COUNT_DISTINCT);
    +		} else {
    +			$criteria->addSelectColumn(UserResourcePeer::COUNT);
    +		}
    +
    +				foreach($criteria->getGroupByColumns() as $column)
    +		{
    +			$criteria->addSelectColumn($column);
    +		}
    +
    +		$criteria->addJoin(UserResourcePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = UserResourcePeer::doSelectRS($criteria, $con);
    +		if ($rs->next()) {
    +			return $rs->getInt(1);
    +		} else {
    +						return 0;
    +		}
    +	}
    +
    +
    +	
    +	public static function doSelectJoinAll(Criteria $c, $con = null)
    +	{
    +		$c = clone $c;
    +
    +				if ($c->getDbName() == Propel::getDefaultDB()) {
    +			$c->setDbName(self::DATABASE_NAME);
    +		}
    +
    +		UserResourcePeer::addSelectColumns($c);
    +		$startcol2 = (UserResourcePeer::NUM_COLUMNS - UserResourcePeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +		sfGuardUserPeer::addSelectColumns($c);
    +		$startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS;
    +
    +		$c->addJoin(UserResourcePeer::USER_ID, sfGuardUserPeer::ID);
    +
    +		$rs = BasePeer::doSelect($c, $con);
    +		$results = array();
    +
    +		while($rs->next()) {
    +
    +			$omClass = UserResourcePeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj1 = new $cls();
    +			$obj1->hydrate($rs);
    +
    +
    +					
    +			$omClass = sfGuardUserPeer::getOMClass();
    +
    +
    +			$cls = Propel::import($omClass);
    +			$obj2 = new $cls();
    +			$obj2->hydrate($rs, $startcol2);
    +
    +			$newObject = true;
    +			for ($j=0, $resCount=count($results); $j < $resCount; $j++) {
    +				$temp_obj1 = $results[$j];
    +				$temp_obj2 = $temp_obj1->getsfGuardUser(); 				if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) {
    +					$newObject = false;
    +					$temp_obj2->addUserResource($obj1); 					break;
    +				}
    +			}
    +
    +			if ($newObject) {
    +				$obj2->initUserResources();
    +				$obj2->addUserResource($obj1);
    +			}
    +
    +			$results[] = $obj1;
    +		}
    +		return $results;
    +	}
    +
    +	
    +	public static function getTableMap()
    +	{
    +		return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME);
    +	}
    +
    +	
    +	public static function getOMClass()
    +	{
    +		return UserResourcePeer::CLASS_DEFAULT;
    +	}
    +
    +	
    +	public static function doInsert($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserResourcePeer:doInsert:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseUserResourcePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} else {
    +			$criteria = $values->buildCriteria(); 		}
    +
    +		$criteria->remove(UserResourcePeer::ID); 
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		try {
    +									$con->begin();
    +			$pk = BasePeer::doInsert($criteria, $con);
    +			$con->commit();
    +		} catch(PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +
    +		
    +    foreach (sfMixer::getCallables('BaseUserResourcePeer:doInsert:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseUserResourcePeer', $values, $con, $pk);
    +    }
    +
    +    return $pk;
    +	}
    +
    +	
    +	public static function doUpdate($values, $con = null)
    +	{
    +
    +    foreach (sfMixer::getCallables('BaseUserResourcePeer:doUpdate:pre') as $callable)
    +    {
    +      $ret = call_user_func($callable, 'BaseUserResourcePeer', $values, $con);
    +      if (false !== $ret)
    +      {
    +        return $ret;
    +      }
    +    }
    +
    +
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +
    +		$selectCriteria = new Criteria(self::DATABASE_NAME);
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 
    +			$comparison = $criteria->getComparison(UserResourcePeer::ID);
    +			$selectCriteria->add(UserResourcePeer::ID, $criteria->remove(UserResourcePeer::ID), $comparison);
    +
    +			$comparison = $criteria->getComparison(UserResourcePeer::USER_ID);
    +			$selectCriteria->add(UserResourcePeer::USER_ID, $criteria->remove(UserResourcePeer::USER_ID), $comparison);
    +
    +		} else { 			$criteria = $values->buildCriteria(); 			$selectCriteria = $values->buildPkeyCriteria(); 		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$ret = BasePeer::doUpdate($selectCriteria, $criteria, $con);
    +	
    +
    +    foreach (sfMixer::getCallables('BaseUserResourcePeer:doUpdate:post') as $callable)
    +    {
    +      call_user_func($callable, 'BaseUserResourcePeer', $values, $con, $ret);
    +    }
    +
    +    return $ret;
    +  }
    +
    +	
    +	public static function doDeleteAll($con = null)
    +	{
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$affectedRows = 0; 		try {
    +									$con->begin();
    +			$affectedRows += BasePeer::doDeleteAll(UserResourcePeer::TABLE_NAME, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	 public static function doDelete($values, $con = null)
    +	 {
    +		if ($con === null) {
    +			$con = Propel::getConnection(UserResourcePeer::DATABASE_NAME);
    +		}
    +
    +		if ($values instanceof Criteria) {
    +			$criteria = clone $values; 		} elseif ($values instanceof UserResource) {
    +
    +			$criteria = $values->buildPkeyCriteria();
    +		} else {
    +						$criteria = new Criteria(self::DATABASE_NAME);
    +												if(count($values) == count($values, COUNT_RECURSIVE))
    +			{
    +								$values = array($values);
    +			}
    +			$vals = array();
    +			foreach($values as $value)
    +			{
    +
    +				$vals[0][] = $value[0];
    +				$vals[1][] = $value[1];
    +			}
    +
    +			$criteria->add(UserResourcePeer::ID, $vals[0], Criteria::IN);
    +			$criteria->add(UserResourcePeer::USER_ID, $vals[1], Criteria::IN);
    +		}
    +
    +				$criteria->setDbName(self::DATABASE_NAME);
    +
    +		$affectedRows = 0; 
    +		try {
    +									$con->begin();
    +			
    +			$affectedRows += BasePeer::doDelete($criteria, $con);
    +			$con->commit();
    +			return $affectedRows;
    +		} catch (PropelException $e) {
    +			$con->rollback();
    +			throw $e;
    +		}
    +	}
    +
    +	
    +	public static function doValidate(UserResource $obj, $cols = null)
    +	{
    +		$columns = array();
    +
    +		if ($cols) {
    +			$dbMap = Propel::getDatabaseMap(UserResourcePeer::DATABASE_NAME);
    +			$tableMap = $dbMap->getTable(UserResourcePeer::TABLE_NAME);
    +
    +			if (! is_array($cols)) {
    +				$cols = array($cols);
    +			}
    +
    +			foreach($cols as $colName) {
    +				if ($tableMap->containsColumn($colName)) {
    +					$get = 'get' . $tableMap->getColumn($colName)->getPhpName();
    +					$columns[$colName] = $obj->$get();
    +				}
    +			}
    +		} else {
    +
    +		}
    +
    +		$res =  BasePeer::doValidate(UserResourcePeer::DATABASE_NAME, UserResourcePeer::TABLE_NAME, $columns);
    +    if ($res !== true) {
    +        $request = sfContext::getInstance()->getRequest();
    +        foreach ($res as $failed) {
    +            $col = UserResourcePeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME);
    +            $request->setError($col, $failed->getMessage());
    +        }
    +    }
    +
    +    return $res;
    +	}
    +
    +	
    +	public static function retrieveByPK( $id, $user_id, $con = null) {
    +		if ($con === null) {
    +			$con = Propel::getConnection(self::DATABASE_NAME);
    +		}
    +		$criteria = new Criteria();
    +		$criteria->add(UserResourcePeer::ID, $id);
    +		$criteria->add(UserResourcePeer::USER_ID, $user_id);
    +		$v = UserResourcePeer::doSelect($criteria, $con);
    +
    +		return !empty($v) ? $v[0] : null;
    +	}
    +} 
    +if (Propel::isInit()) {
    +			try {
    +		BaseUserResourcePeer::getMapBuilder();
    +	} catch (Exception $e) {
    +		Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR);
    +	}
    +} else {
    +			require_once 'lib/model/map/UserResourceMapBuilder.php';
    +	Propel::registerMapBuilder('lib.model.map.UserResourceMapBuilder');
    +}
    diff --git a/lib/model/sfComment.php b/lib/model/sfComment.php
    new file mode 100644
    index 0000000..06aa700
    --- /dev/null
    +++ b/lib/model/sfComment.php
    @@ -0,0 +1,237 @@
    +
    + * @copyright 2008 Linpro AS
    + * @license   http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
    + *
    + */
    +
    +class sfComment extends BasesfComment
    +{
    +  protected 
    +    $user = null,
    +    $artwork = null;
    +  
    +  public function setArtwork($artwork)
    +  {
    +    $this->artwork = $artwork;
    +  }
    +
    +  public function setUser($user)
    +  {
    +    $this->user = $user;
    +  }
    +
    +  public function getArtwork()
    +  {
    +  if (!$this->artwork)
    +  {
    +    $this->artwork = ReaktorArtworkPeer::retrieveByPk($this->getCommentableId());
    +  }
    +    return $this->artwork;
    +  }
    +
    +  public function getUser()
    +  {
    +  if (!$this->user)
    +  {
    +    $this->user = sfGuardUserPeer::retrieveByPK($this->getAuthorId());
    +  }
    +  return $this->user;
    +  }
    +
    +  /**
    +   * Get latest commented artworks that belongs to a user
    +   *
    +   * @param integer $user_id
    +   * @return array comment objects
    +   */
    +  public static function getLatestCommented($user_id)
    +  {
    +    $c = new Criteria();
    +    $c->add(sfCommentPeer::COMMENTABLE_MODEL, 'ReaktorArtwork');
    +    $c->add(sfCommentPeer::NAMESPACE, 'frontend');
    +    $c->add(sfCommentPeer::UNSUITABLE, 2, Criteria::NOT_EQUAL);
    +    $c->add(sfCommentPeer::AUTHOR_ID, $user_id, Criteria::NOT_EQUAL);
    +    $c->add(ReaktorArtworkPeer::STATUS, 3, Criteria::EQUAL);
    +    $c->add(ReaktorArtworkPeer::USER_ID, $user_id);
    +    $c->addGroupByColumn(ReaktorArtworkPeer::TITLE);
    +    $c->setLimit(5);
    +    return sfCommentPeer::doSelectJoinUserAndArtwork($c);
    +  
    +  }
    +  
    +  /**
    +   * Get latest comments a user has written
    +   *
    +   * @param integer $user_id
    +   * @param integer $count
    +   * @return array comment object
    +   */
    +  public static function getLatestWrittenComments($user_id, $count = 5)
    +  {
    +    $c = new Criteria();
    +    $c->add(sfCommentPeer::COMMENTABLE_MODEL, 'ReaktorArtwork');
    +    $c->add(sfCommentPeer::NAMESPACE, 'frontend');    
    +    $c->add(sfCommentPeer::AUTHOR_ID, $user_id);
    +    $c->setLimit($count);
    +    $c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT);
    +    return sfCommentPeer::doSelectJoinUserAndArtwork($c);
    +  }
    +  
    +  /**
    +   * Get latests comments from artworks that belong to a subreaktor or lokalreaktor.
    +   * 
    +   * Comments are included if it belongs to an artwork with the given lokalreaktor as a category,
    +   * or if the user who owns the artworks has a residence that belong to the lokalReaktor.
    +   * 
    +   * This means a user do not have to belong to the lokalreaktor to have it's comments included, 
    +   * similarily all comments made by a user who does belong to the lokalreaktor isn't included. 
    +   *
    +   * @param string $subreaktor
    +   * @param int $count
    +   * @return array sfComment 
    +   */
    +  public static function getReaktorsLatestComments($subreaktor = null, $count = 5, $lokalreaktor = null)
    +  { 
    +    $c = new Criteria();
    +    
    +    $c->add(sfCommentPeer::COMMENTABLE_MODEL, 'ReaktorArtwork');
    +    $c->add(sfCommentPeer::NAMESPACE, 'frontend');     
    +    $c->add(sfCommentPeer::UNSUITABLE, 2, Criteria::NOT_EQUAL);
    +    $c->add(ReaktorArtworkPeer::STATUS, 3);
    +    
    +    $c->addJoin(sfCommentPeer::COMMENTABLE_ID, ReaktorArtworkPeer::ID, Criteria::LEFT_JOIN);
    +    $c->addJoin(ReaktorArtworkPeer::USER_ID, sfGuardUserPeer::ID, Criteria::LEFT_JOIN);
    +    
    +    if ($subreaktor instanceof Subreaktor)
    +    {
    +      $c->addJoin(ReaktorArtworkPeer::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN);
    +      $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, $subreaktor->getId());
    +    }
    +    elseif (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor)
    +    {
    +      $c->addJoin(ReaktorArtworkPeer::ID, SubreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN);
    +      $c->add(SubreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedSubreaktor()->getId());
    +    }
    +    
    +    if ($lokalreaktor instanceof Subreaktor)
    +    {      
    +      $c->addJoin(ReaktorArtworkPeer::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN);
    +      $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN);
    +      $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, $lokalreaktor->getId());
    +      $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, $lokalreaktor->getResidences(), Criteria::IN);
    +      $ctn->addOr($ctn2);
    +      $c->add($ctn);
    +      
    +    }
    +    elseif (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor)
    +    {
    +      $c->addJoin(ReaktorArtworkPeer::ID, LokalreaktorArtworkPeer::ARTWORK_ID, Criteria::LEFT_JOIN);
    +      $c->addJoin(LokalreaktorArtworkPeer::SUBREAKTOR_ID, LokalreaktorResidencePeer::SUBREAKTOR_ID, Criteria::LEFT_JOIN);
    +      $ctn = $c->getNewCriterion(LokalreaktorArtworkPeer::SUBREAKTOR_ID, Subreaktor::getProvidedLokalreaktor()->getId());
    +      $ctn2 = $c->getNewCriterion(sfGuardUserPeer::RESIDENCE_ID, Subreaktor::getProvidedLokalreaktor()->getResidences(), Criteria::IN);
    +      $ctn->addOr($ctn2);
    +      $c->add($ctn); 
    +
    +    }
    +
    +    $c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT);    
    +    $c->setLimit($count); 
    +    $c->setDistinct();
    +    return sfCommentPeer::doSelect($c);
    +  }
    +  
    +  /**
    +   * Get latest comments a user has received
    +   *
    +   * @param integer $user_id
    +   * @param integer $count
    +   * @return array comment object
    +   */
    +  public static function getLatestReceivedComments($user_id, $count = 5)
    +  {
    +    $c = new Criteria();
    +    $c->add(sfCommentPeer::COMMENTABLE_MODEL, 'ReaktorArtwork');
    +    $c->add(sfCommentPeer::NAMESPACE, 'frontend');    
    +    $c->add(sfCommentPeer::AUTHOR_ID, $user_id, Criteria::NOT_EQUAL);
    +    $c->add(ReaktorArtworkPeer::USER_ID, $user_id);
    +    $c->setLimit($count);
    +    $c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT);
    +    return sfCommentPeer::doSelectJoinUserAndArtwork($c);
    +  }
    +
    +   /**
    +   * Required by the Feed plugin to generate routes automatically
    +   *
    +   * @return string The culture in question, "no" if none specified
    +   */
    +  public function getFeedsfCulture()
    +  {
    +    return sfContext::getInstance()->getRequest()->getParameter('sf_culture', 'no');
    +  }
    +  
    +  /**
    +   * Get the provided subreaktor for Feed generator
    +   *
    +   * @return subreaktor|null
    +   */
    +  public function getFeedSubreaktor()
    +  {
    +    if (subreaktor::isValid())
    +    {
    +      return Subreaktor::getProvided();
    +    }
    +  }
    +  
    +  /**
    +   * Return the parent artwork title rather than the comment title
    +   * This is so the link back to the artwork is correct
    +   *
    +   * @return string the artwork title
    +   */
    +  public function getFeedTitle()
    +  {
    +    return $this->getArtwork()->getTitle();
    +  }
    +  
    +  /**
    +   * Return the parent artwork Id rather than the comment Id
    +   * This is so the link back to the artwork is correct
    +   *
    +   * @return integer the artwork ID
    +   */
    +  public function getFeedId()
    +  {
    +    return $this->getArtwork()->getId();
    +  }
    +  
    +  /**
    +   * Return the feed title and text for use in the RSS body
    +   *
    +   * @return string the title and text of the comment
    +   */
    +  public function getFeedDescription()
    +  {
    +    return $this->getTitle().' - '.$this->getText();
    +  }
    +  
    +  /**
    +   * Generate valid absolute url for Atom IDs
    +   * NOTE: The URL generated is for the artwork, including the comment fragment 
    +   * 
    +   * @return string the artwork absolute URL
    +   */
    +  public function getFeedUniqueId()
    +  {
    +    return sfContext::getInstance()->getController()->genUrl($this->getArtwork()->getLink(), true) . "#message_" . $this->getId();
    +  }
    +
    +  
    +}
    +
    +
    diff --git a/lib/model/sfCommentPeer.php b/lib/model/sfCommentPeer.php
    new file mode 100644
    index 0000000..393ff81
    --- /dev/null
    +++ b/lib/model/sfCommentPeer.php
    @@ -0,0 +1,323 @@
    +add(sfCommentPeer::COMMENTABLE_MODEL, $comment_model);
    +
    +    $date_array = explode('-', $date);
    +    
    +    if(count($date_array) == 3)
    +    {
    +      $from = $date.' 00:00:00';
    +      $to   = $date.' 23:59:59';     
    +    }
    +    else
    +    {
    +      $from = $date.'-01 00:00:00';
    +      $to   = $date.'-'.date('t', strtotime($date)).' 23:59:59';
    +    }
    +    $crit1 = $c->getNewCriterion( sfCommentPeer::CREATED_AT, $from, Criteria::GREATER_EQUAL);
    +    $crit2 = $c->getNewCriterion( sfCommentPeer::CREATED_AT, $to, Criteria::LESS_EQUAL);
    +    $crit1->addAnd( $crit2 );
    +    $c->add( $crit1 );
    +
    +    if($unsuitable)
    +    {
    +      $c->add(sfCommentPeer::UNSUITABLE, $unsuitable);
    +    }
    +    
    +    $c->add(sfCommentPeer::NAMESPACE, $namespace);
    +    $c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT);
    +    $c->addDescendingOrderByColumn(sfCommentPeer::ID);
    +    
    +    $pager->setCriteria($c);
    +    $pager->setPage($page);
    +    $pager->setPeerMethod('doSelectJoinUserAndArtwork');
    +    $pager->init();
    +    
    +    return $pager;
    +    
    +  }
    +  
    +  public static function getCommentsByUnsuitableStatus($comment_model, $namespace, $page, $status = 1)
    +  {
    +    $pager = new sfPropelPager('sfComment', sfConfig::get("app_admin_commentlistmax", 3));
    +    $c     = new Criteria();   
    +
    +    $c->add(sfCommentPeer::COMMENTABLE_MODEL, $comment_model);
    +
    +    $c->add(sfCommentPeer::UNSUITABLE, $status);
    +    
    +    $c->add(sfCommentPeer::NAMESPACE, $namespace);
    +    $c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT);
    +    $c->addDescendingOrderByColumn(sfCommentPeer::ID);
    +    
    +    $pager->setCriteria($c);
    +    $pager->setPage($page);
    +    $pager->setPeerMethod('doSelectJoinUserAndArtwork');
    +    $pager->init();
    +    
    +    return $pager;
    +  }
    +  
    +  public static function getUnsuitableComments($comment_model, $namespace, $page)
    +  {
    +    return self::getCommentsByUnsuitableStatus($comment_model, $namespace, $page, 2);
    +  }
    +
    +  public static function getReportedComments($comment_model, $namespace, $page)
    +  {
    +    return self::getCommentsByUnsuitableStatus($comment_model, $namespace, $page, 1);
    +  }
    +  
    +  public static function getNumberofCommentsByUnsuitableStatus($status = 1)
    +  {
    +  	$c = new Criteria();
    +  	$c->add(sfCommentPeer::UNSUITABLE, $status);
    +    $c->addJoin(sfCommentPeer::AUTHOR_ID, sfGuardUserPeer::ID);
    +  	return sfCommentPeer::doCount($c);
    +  }
    +  
    +/**
    +   * Get comments that a user has made
    +   *
    +   * @param sfGuardUser|integer $user the user object or id
    +   * @param string         $comment_model the model used by the comment engine
    +   * @param string         $namespace     the namespace used by the comment engine
    +   */
    +  public static function getCommentsByUser($user, $comment_model, $namespace, $page)
    +  {
    +    if ($user instanceof sfGuardUser)
    +    {
    +      $userId = $user->getId();
    +    }
    +    else
    +    {
    +      $userId = intval($user);
    +    }
    +    
    +    $pager = new sfPropelPager('sfComment', sfConfig::get("app_admin_commentlistmax", 3));
    +    $c = new Criteria();
    +     
    +    $c->add(sfCommentPeer::COMMENTABLE_MODEL, $comment_model);
    +    $c->add(sfCommentPeer::NAMESPACE, $namespace);
    +    $c->add(sfCommentPeer::AUTHOR_ID, $userId);
    +    $c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT);
    +    
    +    $pager->setCriteria($c);
    +    $pager->setPage($page);
    +    $pager->setPeerMethod('doSelectJoinUserAndArtwork');
    +    $pager->init();
    +    
    +    return $pager;
    +    
    +  }
    +  
    +  /**
    +   * Count comments per date between $from and $to, and return in array.
    +   *
    +   * @param string $comment_model
    +   * @param string $namespace
    +   * @param string $type
    +   * @param string $from
    +   * @param string $to
    +   * 
    +   * @return array $comments Comment counts per date between $from and $to
    +   */
    +  public static function getCommentCountInTimePeriod($comment_model, $namespace, $type, $from, $to)
    +  {
    +   
    +    $c = new Criteria();
    +    $c->addSelectColumn('date('.sfCommentPeer::CREATED_AT.')');
    +
    +    $c->addSelectColumn(sfCommentPeer::COUNT);
    +    $c->add(sfCommentPeer::COMMENTABLE_MODEL, $comment_model);
    +    $c->add(sfCommentPeer::NAMESPACE, $namespace);
    +    
    +    $crit1 = $c->getNewCriterion( sfCommentPeer::CREATED_AT,$from.' 00:00:00', Criteria::GREATER_EQUAL);
    +    $crit2 = $c->getNewCriterion( sfCommentPeer::CREATED_AT, $to.' 23:59:59', Criteria::LESS_EQUAL);
    +    $crit1->addAnd( $crit2 );
    +    $c->add( $crit1 );
    +    
    +    $c->addGroupByColumn('date(sf_comment.CREATED_AT)');
    +    
    +    $rs = self::doSelectRS($c);
    +     
    +    $comments= array();
    +    while ($rs->next()) {
    +    	$comments[$rs->getString(1)] = $rs->getString(2);
    +    }
    +    
    +    return $comments;  
    +  }
    +  
    +  /**
    +   * Returns the list of the comments attached to the object. The options array
    +   * can contain several options :
    +   * - order : order of the comments
    +   * 
    +   * @param      BaseObject  $object
    +   * @param      Array       $options
    +   * @param      Criteria    $criteria
    +   * 
    +   * @return     Array
    +   */
    +  public static function getComments(BaseObject $object, $options = array(), Criteria $criteria = null)
    +  {
    +    $c = sfCommentPeer::getCommentsCriteria($object, $options, $criteria);
    +    $comment_objects = sfCommentPeer::doSelectJoinSfGuardUser($c);
    +    
    +    $comments = array();
    +    
    +    foreach ($comment_objects as $comment_object)
    +    {
    +      $comment = $comment_object->toArray();
    +      $comment_user = $comment_object->getSfGuardUser();
    +      $comment['AuthorName'] = $comment_user->getUsername();
    +      $comment['AuthorVisible'] = $comment_user->getShowContent();
    +      $comments[] = $comment;
    +    }
    +    return $comments;
    +  }
    +
    +  /**
    +   * Query to hydrate and join the User object and artwork object to the
    +   * comment results so you don't have to use extra queries when looking up
    +   * related data
    +   *
    +   * @return array full of sfComment objects
    +   */
    +  public static function doSelectJoinUserAndArtwork(Criteria $c, $con = null)
    +  {
    +    $c = clone $c;
    +
    +    // Set the correct dbName if it has not been overridden
    +    if ($c->getDbName() == Propel::getDefaultDB()) {
    +        $c->setDbName(self::DATABASE_NAME);
    +    }
    +
    +    // Add select columns for sfComment
    +    sfCommentPeer::addSelectColumns($c);
    +    $startcol2 = (sfCommentPeer::NUM_COLUMNS - sfCommentPeer::NUM_LAZY_LOAD_COLUMNS) + 1;
    +
    +    // Add select columns for Artwork
    +    ReaktorArtworkPeer::addSelectColumns($c);
    +    $startcol3 = $startcol2 + ReaktorArtworkPeer::NUM_COLUMNS ;
    +
    +    // Add select columns for sfGuardUser
    +    sfGuardUserPeer::addSelectColumns($c);
    +
    +    // [NOTE 1]
    +    $c->addJoin(sfCommentPeer::COMMENTABLE_ID, ReaktorArtworkPeer::ID);
    +    $c->addJoin(sfCommentPeer::AUTHOR_ID, sfGuardUserPeer::ID);
    +
    +    $rs = BasePeer::doSelect($c, $con);
    +    $results = array();
    +
    +    while($rs->next())
    +    {
    +      // Hydrate the sfComment object
    +      $omClass = sfCommentPeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj1 = new $cls();
    +      $obj1->hydrate($rs);
    +
    +      // Hydrate the Artwork object
    +      $omClass = ReaktorArtworkPeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj2 = new $cls();
    +      $obj2->hydrate($rs, $startcol2);
    +
    +      // Hydrate the sfGuardUser object
    +      $omClass = sfGuardUserPeer::getOMClass();
    +
    +      $cls = Propel::import($omClass);
    +      $obj3 = new $cls();
    +      $obj3->hydrate($rs, $startcol3);
    +
    +      // [NOTE 2]
    +      $obj1->setArtwork($obj2);
    +      $obj1->setUser($obj3); 
    +      $results[] = $obj1;
    +    }
    +		
    +    return $results;
    +  }
    +  
    +  /**
    +   * Returns a criteria for comments selection. The options array
    +   * can contain several options :
    +   * - order : order of the comments
    +   * 
    +   * @param      BaseObject  $object
    +   * @param      Array       $options
    +   * @param      Criteria    $criteria
    +   * 
    +   * @return     Array
    +   */
    +  protected static function getCommentsCriteria(BaseObject $object, $options = array(), Criteria $criteria = null)
    +  {
    +    if ($criteria != null)
    +    {
    +      $c = clone $criteria;
    +    }
    +    else
    +    {
    +      $c = new Criteria();
    +    }
    +
    +    $c->add(sfCommentPeer::COMMENTABLE_ID, $object->getPrimaryKey());
    +    $c->add(sfCommentPeer::COMMENTABLE_MODEL, get_class($object));
    +
    +    if (isset($options['namespace']))
    +    {
    +      $c->add(sfCommentPeer::NAMESPACE, $options['namespace']);
    +    }
    +    else
    +    {
    +      $c->add(sfCommentPeer::NAMESPACE, '');
    +    }
    +
    +    if (isset($options['order']) && ($options['order'] == 'desc'))
    +    {
    +      $c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT);
    +      $c->addDescendingOrderByColumn(sfCommentPeer::ID);
    +    }
    +    else
    +    {
    +      $c->addAscendingOrderByColumn(sfCommentPeer::CREATED_AT);
    +      $c->addAscendingOrderByColumn(sfCommentPeer::ID);
    +    }
    +
    +    return $c;
    +  }
    +  
    +}
    diff --git a/lib/model/sfGuardGroup.php b/lib/model/sfGuardGroup.php
    new file mode 100644
    index 0000000..047b539
    --- /dev/null
    +++ b/lib/model/sfGuardGroup.php
    @@ -0,0 +1,43 @@
    +
    + * @version    SVN: $Id: sfGuardGroup.php 5760 2007-10-30 07:51:16Z francois $
    + */
    +class sfGuardGroup extends PluginsfGuardGroup
    +{
    +	
    +	public function __toString()
    +	{
    +		return $this->getDescription();
    +	}
    +	
    +	public function getMembers($numUnapproved = 0)
    +	{
    +		
    +		$groups = $this->getsfGuardUserGroups();
    +		$group = array_shift($groups);
    +		if (!$group)
    +			return array();
    +			$c = new Criteria();
    +		$c->add(sfGuardUserGroupPeer::GROUP_ID,$group->getGroupId());
    +		$c->add(sfGuardUserPeer::EDITORIAL_NOTIFICATION,$numUnapproved,Criteria::GREATER_THAN);
    +		$c->addOr(sfGuardUserPeer::EDITORIAL_NOTIFICATION,2);
    +		$users = sfGuardUserGroupPeer::doSelectJoinsfGuardUser($c);
    +		
    +		return $users;
    +	}	
    +	
    +	/**
    +	 * Return whether a group is enabled or not
    +	 *
    +	 * @return boolean
    +	 */
    +	public function isEnabled()
    +	{
    +	  return (bool) $this->getIsEnabled();
    +	}
    +}
    diff --git a/lib/model/sfGuardGroupPeer.php b/lib/model/sfGuardGroupPeer.php
    new file mode 100644
    index 0000000..1746b63
    --- /dev/null
    +++ b/lib/model/sfGuardGroupPeer.php
    @@ -0,0 +1,98 @@
    +
    + *
    + * For the full copyright and license information, please view the LICENSE
    + * file that was distributed with this source code.
    + */
    +
    +/**
    + *
    + * @package    symfony
    + * @subpackage plugin
    + * @author     Fabien Potencier 
    + * @version    SVN: $Id: sfGuardGroupPeer.php 5760 2007-10-30 07:51:16Z francois $
    + */
    +class sfGuardGroupPeer extends PluginsfGuardGroupPeer
    +{  
    +  /**
    +   * Return editorial team groups based on a list or return all
    +   *
    +   * @param array $teams An array of teams (group names)
    +   */
    +  public static function getActiveEditorialTeams($teams = array())
    +  {
    +    return self::getEditorialTeams(true, $teams);
    +  }
    +  
    +  /**
    +   * Return a group object by name
    +   * 
    +   * @param string $name The group name
    +   * 
    +   * @return sfGuardGroup
    +   */
    +  public static function getGroupByName($name)
    +  {
    +    $c = new Criteria();
    +    $c->add(self::NAME, $name);
    +    
    +    return self::doSelectOne($c);
    +  }
    +  
    +  /**
    +   * Returns an array of sfGuardGroup which are editorial teams
    +   *
    +   * @param boolean $enabled   Whether to only return enabled teams, true by default
    +   * @param array   $teamNames An array of team names to filter on
    +   * 
    +   * @return array|sfGuardGroup
    +   */
    +  public static function getEditorialTeams($enabled = true, $teams = array())
    +  {
    +    $crit = new Criteria();
    +    if ($enabled)
    +    {
    +      $crit->add(sfGuardGroupPeer::IS_ENABLED, true);
    +    }
    +    $crit->add(sfGuardGroupPeer::IS_EDITORIAL_TEAM, true);
    +    
    +    if (!empty($teams))
    +    {
    +      $crit->add(self::NAME, $teams, Criteria::IN);
    +    }
    +    
    +    return SfGuardGroupPeer::doSelect($crit);
    +  }
    +
    +  /**
    +   * Returns an array of sfGuardGroup s which are normal user groups
    +   *
    +   * @return array|sfGuardGroup
    +   */
    +  public static function getUserGroups()
    +  {
    +    $crit = new Criteria();
    +    $crit->add(sfGuardGroupPeer::IS_EDITORIAL_TEAM, false);
    +    return SfGuardGroupPeer::doSelect($crit);
    +  }  
    +  
    +  public static function getEditorialTeamsAsIndexedArray()
    +  {
    +  	$teams = self::getEditorialTeams();
    +  	$arr = array();
    +  	foreach ($teams as $team)
    +  	{
    +  		$arr[$team->getId()] = $team->getDescription();
    +  	}
    +  	return $arr;
    +  }
    +  
    +  public static function getOMClass()
    +  {
    +    return 'lib.model.sfGuardGroup';
    +  }
    +  
    +
    +}
    diff --git a/lib/model/sfGuardPermission.php b/lib/model/sfGuardPermission.php
    new file mode 100644
    index 0000000..a8a462b
    --- /dev/null
    +++ b/lib/model/sfGuardPermission.php
    @@ -0,0 +1,30 @@
    +
    + *
    + * For the full copyright and license information, please view the LICENSE
    + * file that was distributed with this source code.
    + */
    +
    +/**
    + *
    + * @package    symfony
    + * @subpackage plugin
    + * @author     Fabien Potencier 
    + * @version    SVN: $Id: sfGuardPermission.php 5760 2007-10-30 07:51:16Z francois $
    + */
    +class sfGuardPermission extends PluginsfGuardPermission
    +{
    +	function __toString()
    +	{
    +		return $this->getDescription();
    +	}
    +	
    +	public function hydrate (ResultSet $rs, $startcol = 1)
    +	{
    +		parent::hydrate($rs, $startcol);
    +		$this->setculture(sfContext::getInstance()->getUser()->getCulture());
    +	}
    +}
    diff --git a/lib/model/sfGuardPermissionPeer.php b/lib/model/sfGuardPermissionPeer.php
    new file mode 100644
    index 0000000..06b304a
    --- /dev/null
    +++ b/lib/model/sfGuardPermissionPeer.php
    @@ -0,0 +1,26 @@
    +
    + *
    + * For the full copyright and license information, please view the LICENSE
    + * file that was distributed with this source code.
    + */
    +
    +/**
    + *
    + * @package    symfony
    + * @subpackage plugin
    + * @author     Fabien Potencier 
    + * @version    SVN: $Id: sfGuardPermissionPeer.php 5760 2007-10-30 07:51:16Z francois $
    + */
    +class sfGuardPermissionPeer extends PluginsfGuardPermissionPeer
    +{
    +
    +  public static function getOMClass()
    +  {
    +    //return 'lib.model.sfGuardPlugin.sfGuardUser';
    +    return 'lib.model.sfGuardPermission';
    +  }
    +}
    diff --git a/lib/model/sfGuardUser.php b/lib/model/sfGuardUser.php
    new file mode 100644
    index 0000000..3c22bf2
    --- /dev/null
    +++ b/lib/model/sfGuardUser.php
    @@ -0,0 +1,503 @@
    +
    + * @copyright 2008 Linpro
    + * @license   http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
    + * 
    + */
    +
    +/**
    + * The sfGuardUser class, extended with some basic functions
    + * 
    + * PHP version 5
    + *
    + * @author    juneih 
    + * @copyright 2008 Linpro
    + * @license   http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
    + * 
    + */
    +class sfGuardUser extends PluginsfGuardUser
    +{
    +  
    +	protected $_editorialteams = null;
    +	
    +  /**
    +   * To string is used in dropdowns and when trying to print objects.
    +   *
    +   * @return unknown
    +   */
    +  public function __toString()
    +  {
    +    return $this->getUsername();
    +  }
    +
    +  /**
    +   * Same as the __toString() method. Needed for the Feed plugin
    +   *
    +   * @see __toString()
    +   * @return string
    +   */
    +  public function getUser()
    +  {
    +    return (string)$this;
    +  }
    +  
    +  /**
    +	 * Set date of birth, and handle both input as array and string.
    +	 *
    +	 * @param array $v Date of birth
    +	 * 
    +	 * @return void
    +	 */
    +  public function setDob($v)
    +  {
    +    if ( is_array($v) && array_key_exists('year', $v) && array_key_exists('month', $v) && array_key_exists('day', $v))
    +    {
    +      if ( !empty($v['year']) && !empty($v['month']) && !empty($v['day']) )
    +      {
    +        parent::setDob($v['year'].'-'.$v['month'].'-'.$v['day']);
    +      }
    +      else
    +      {
    +        parent::setDob(null);
    +      }
    +    }
    +    else
    +    {
    +      parent::setDob($v);
    +    }
    +  }
    +  
    +  /**
    +   * Handles updating reaktor userdata
    +   *
    +   * @param object $action webrequest object
    +   * 
    +   * @return null
    +   */
    +  public function updateUser($action)
    +  {   
    +    if ($action->getRequestParameter('password_profile'))
    +    {
    +      parent::setPassword($action->getRequestParameter('password_profile'));
    +    }
    +    parent::setUsername($action->getRequestParameter('username_profile'));
    +    //parent::setId($action->getRequestParameter('id') ? $action->getRequestParameter('id') : null);
    +    if ($action->getRequestParameter('email') != parent::getEmail())
    +    {
    +      if (!$action->getUser()->hasCredential('editprofile'))
    +      {
    +        parent::setNewEmail($action->getRequestParameter('email'));
    +        parent::setNewEmailKey(stringMagick::generateSalt());
    +    
    +        global $mail_data;
    +        $mail_data = array('user' => $this,
    +                             'salt' => $this->getSalt(),
    +                             'newEmailKey' => $this->getNewEmailKey());
    +       
    +        // Send e-mail to new address
    +        $raw_email = $action->sendEmail('mail', 'sendNewEmailActivation');
    +        $action->logMessage($raw_email, 'debug');
    +        
    +        // Send e-mail to old address  
    +        $raw_email = $action->sendEmail('mail', 'sendNewEmailActivationNotification');
    +        $action->logMessage($raw_email, 'debug');
    +      }
    +      else
    +      {
    +        parent::setEmail($action->getRequestParameter('email'));
    +      }
    +    }
    +    parent::setName($action->getRequestParameter('name'));
    +    
    +    $this->setDob($action->getRequestParameter('dob'));
    +    if($action->getRequestParameter('sex')=='2'||$action->getRequestParameter('sex')=='1')
    +    {    
    +      parent::setSex($action->getRequestParameter('sex'));
    +    }
    +    parent::setDescription($action->getRequestParameter('description'));
    +    parent::setResidenceId($action->getRequestParameter('residence_id'));
    +    
    +    //set Interests
    +    UserInterestPeer::deleteByUser($action->getRequestParameter('id'));    
    +    $subs = SubreaktorPeer::doSelect(new Criteria());
    +    foreach ($subs as $sub)
    +    {      
    +      if ($action->getRequestParameter($sub->getName()))
    +      {
    +        $user_interest = new UserInterest();
    +        $user_interest->setUserId($action->getRequestParameter('id'));
    +        $user_interest->setSubreaktorId($action->getRequestParameter($sub->getName()));
    +        $user_interest->save();
    +      }
    +    }
    +
    +    parent::setMsn($action->getRequestParameter('msn'));
    +    if($action->getRequestParameter('icq'))
    +    {
    +      parent::setIcq($action->getRequestParameter('icq'));
    +    }
    +    else
    +    {
    +      parent::setIcq(null);
    +    }
    +    parent::setHomepage($action->getRequestParameter('homepage'));
    +    parent::setEmailPrivate(($action->getRequestParameter('email_private') == '') ? 0 : 1);
    +    parent::setNamePrivate(($action->getRequestParameter('name_private') == '') ? 0 : 1);
    +    parent::setShowLoginStatus(($action->getRequestParameter('show_login_status') == '') ? 0 : 1);
    +    parent::setPhone($action->getRequestParameter('phone'));
    +    parent::setOptIn(($action->getRequestParameter('opt_in') == '') ? 0 : 1 );
    +    parent::setCulture($action->getRequestParameter('catalogue'));
    +    $avatar_filename = $action->getRequest()->getFilename('avatar');
    +    
    +    if ($avatar_filename)
    +    {
    +      //create filename 
    +      if (!parent::getAvatar())
    +      {
    +        $explode_avatar_filename = explode(".", $avatar_filename);
    +        $file_extention          = end($explode_avatar_filename);
    +        $string_magick           = new stringMagick();
    +        $random                  = $string_magick->randomString();
    +        $new_avatar_filename     = time().$random.'.'.$file_extention; 
    +      }
    +      else
    +      {
    +        $new_avatar_filename = parent::getAvatar();
    +      }                
    +      $avatar_filepath = sfConfig::get('sf_upload_dir').'/profile_images/'.$new_avatar_filename;
    +
    +      //resize avatar
    +      $resizedImage = new imageResize($action->getRequest()->getFileValue('avatar', 'tmp_name'),
    +        $avatar_filepath, sfConfig::get('app_profile_max_image_width', '75'),
    +        sfConfig::get('app_profile_max_image_height', '100'));
    +        
    +      //save file in web/upload/profile_images/timestamprandom.extention and filname in database
    +      $resizedImage->imageWrite();                  
    +      parent::setAvatar($new_avatar_filename);
    +    }        
    +    parent::save();
    +  }
    +  
    +  /**
    +   * Overrides the parent save function
    +   *
    +   * @param unknown_type $con Connection object
    +   * 
    +   * @return void
    +   */
    +  public function save($con = null)
    +  {
    +    // pre save hook
    +    $send_email = false;
    +    
    +    // If the user is created when a user is logged in, that means we
    +    // are talking about an admin user, since users who are authenticated
    +    // will be redirected to the profile page if they try to register
    +    if (sfContext::getInstance()->getUser()->isAuthenticated())
    +    {
    +      // is this a new user?
    +      if (!$this->getId() && !$this->getIsVerified())
    +      {
    +        $send_email = true;
    +      }
    +    }
    +    // call the parent save() method
    +    parent::save($con);
    +
    +    if ($send_email)
    +    {
    +      // Create and send e-mail
    +      global $mail_data;
    +      $mail_data = array('user' => $this);
    +      $raw_email = sfContext::getInstance()->getController()->sendEmail('mail', 'sendActivationEmail');
    +    }
    +  }
    +  
    +  /**
    +   * Handles registering reaktor userdata
    +   *
    +   * @param object $action Web request object
    +   * 
    +   * @return void
    +   */
    +  public function registerUser($action)
    +  {
    +    //$db_user = new sfGuardUser();
    +    parent::setUsername(trim($action->getRequestParameter('username_profile')));
    +    parent::setPassword($action->getRequestParameter('password_profile'));
    +    parent::setIsActive(1); 
    +    parent::setShowContent(1);   
    +    parent::setEmail($action->getRequestParameter('email'));
    +    parent::setResidenceId($action->getRequestParameter('residence_id'));
    +    $this->setDob($action->getRequestParameter('dob'));
    +    parent::setSex($action->getRequestParameter('sex'));
    +
    +    parent::save();
    +    $user_group = new sfGuardUserGroup();
    +    $user_group->setsfGuardGroup(sfGuardGroupPeer::retrieveByPK(2));
    +    $user_group->setsfGuardUser($this);
    +    $user_group->save();
    +    //return $db_user;
    +  }
    +   
    +  /**
    +   * Handles activating reaktor user 
    +   *
    +   * @param object $action web_request object
    +   * 
    +   * @return void
    +   */ 
    +  public function activateUser($action)
    +  {    
    +    parent::setIsVerified(1);
    +    parent::save();
    +  }
    +  
    +  /**
    +   * Set the email to the new email and blank out the 'new email' field.
    +   *
    +   * @param object $action web request object
    +   * 
    +   * @return void
    +   */
    +  public function changeEmail($action)
    +  {
    +    parent::setEmail(parent::getNewEmail());
    +    parent::setNewEmail('');
    +    parent::save();
    +  }
    +  
    +  /**
    +   * Return the number of artworks this user has submitted
    +   *
    +   * @param string $type The type to filter by
    +   * 
    +   * @return integer number of artworks
    +   */
    +  public function getArtworkCount($type = null)
    +  {
    +    return ReaktorArtworkPeer::countUserArtworks($this, $type);
    +  }
    +  
    +  /**
    +   * returns a list of a users editorial teams
    +   *
    +   * @return array
    +   */
    +  public function getEditorialTeams()
    +  {
    +  	if ($this->_editorialteams === null)
    +  	{
    +  		$this->_editorialteams = array();
    +  		foreach ($this->getGroups() as $aGroup)
    +  		{
    +  			if ($aGroup->getIsEditorialTeam())
    +  			{
    +  				$this->_editorialteams[$aGroup->getName()] = $aGroup;
    +  			}
    +  		}
    +  	}
    +  	return $this->_editorialteams;
    +  }
    +  
    +  /**
    +   * Return true if the user is part of the specified editorial team
    +   *
    +   * @param string $teamname
    +   * 
    +   * @return boolean
    +   */
    +  public function hasEditorialTeam($teamname)
    +  {
    +  	if ($this->hasGroup($teamname))
    +  	{
    +  		if ($this->groups[$teamname]->isEditorialTeam())
    +  		{
    +  			return true;
    +  		}
    +  		else
    +  		{
    +  			return false;
    +  		}
    +  	}
    +  	else
    +  	{
    +  		return false;
    +  	}
    +  }
    +  
    +  /**
    +   * Returns the users avatar or a default image
    +   * 
    +   * @param string $default optional filename, default is default.gif
    +   * @return string filename
    +   */
    +  public function getAvatarOrDefault($default = "default.gif")
    +  {
    +    return parent::getAvatar() ? parent::getAvatar() : $default;
    +  }
    +
    +  /**
    +   * Required by the Feed plugin to generate routes automatically
    +   *
    +   * @return string The culture in question, "no" if none specified
    +   */
    +  public function getFeedsfCulture()
    +  {
    +    return sfContext::getInstance()->getRequest()->getParameter("sf_culture", "no");
    +  }
    +
    +  /**
    +   * Get the provided subreaktor for Feed generator
    +   *
    +   * @return subreaktor|null
    +   */
    +  public function getFeedSubreaktor()
    +  {
    +    if (subreaktor::isValid())
    +    {
    +      return Subreaktor::getProvided();
    +    }
    +  }
    +  
    +  /**
    +   * Get the absolute URL to the users portfolio
    +   * Required to generate valid Atom1.0 feeds
    +   * 
    +   * @return string absolute URL to his portfolio
    +   */
    +  public function getFeedUniqueId()
    +  {
    +    return sfContext::getInstance()->getController()->genUrl("@portfolio?user={$this->getId()}", true);
    +  }
    +
    +
    +  public function getPermissions()
    +  {
    +    if (!$this->permissions)
    +    {
    +      $this->permissions = array();
    +
    +      $c = new Criteria();
    +      $c->add(sfGuardUserPermissionPeer::USER_ID, $this->getId());
    +      $c->add(sfGuardUserPermissionPeer::EXCLUDE, 0);
    +      $ups = sfGuardUserPermissionPeer::doSelectJoinsfGuardPermission($c);
    +
    +      foreach ($ups as $up)
    +      {
    +        $permission = $up->getsfGuardPermission();
    +        $this->permissions[$permission->getName()] = $permission;
    +      }
    +    }
    +
    +    return $this->permissions;
    +  }
    +
    +  // merge of permission in a group + permissions, and exclude the explicitly 
    +  // revoked permissions
    +  public function getAllPermissions()
    +  {
    +    if (!$this->allPermissions)
    +    {
    +      $this->allPermissions = $this->getPermissions();
    +
    +      foreach ($this->getGroups() as $group)
    +      {
    +        foreach ($group->getsfGuardGroupPermissions() as $gp)
    +        {
    +          $permission = $gp->getsfGuardPermission();
    +
    +          $this->allPermissions[$permission->getName()] = $permission;
    +        }
    +      }
    +
    +      /* Remove excluded permissinos */
    +      $c = new Criteria();
    +      $c->add(sfGuardUserPermissionPeer::USER_ID, $this->getId());
    +      $c->add(sfGuardUserPermissionPeer::EXCLUDE, 1);
    +      $ups = sfGuardUserPermissionPeer::doSelectJoinsfGuardPermission($c);
    +
    +      foreach ($ups as $up)
    +      {
    +        $permission = $up->getsfGuardPermission()->getName();
    +        unset($this->allPermissions[$permission]);
    +      }
    + 
    +    }
    +
    +    return $this->allPermissions;
    +  }
    +
    +
    +  public function getNameOrUsername()
    +  {
    +    return ($this->getName()!='' ? $this->getName() : $this->getUsername() );
    +  }
    +
    +
    +
    +  public function checkPasswordByGuard($password)
    +  {
    +    $algorithm = $this->getAlgorithm();
    +    if (false !== $pos = strpos($algorithm, '::'))
    +    {
    +      $algorithm = array(substr($algorithm, 0, $pos), substr($algorithm, $pos + 2));
    +    }
    +    if (!is_callable($algorithm))
    +    {
    +      throw new sfException(sprintf('The algorithm callable "%s" is not callable.', $algorithm));
    +    }
    +	$prototype_login = $this->getPassword() == call_user_func_array($algorithm, array($password.$this->getSalt()));
    +	if ($algorithm === 'md5' && $prototype_login)
    +	{
    +		return $prototype_login;
    +	}
    +	else
    +	{
    +    	return $this->getPassword() == call_user_func_array($algorithm, array($this->getSalt().$password));
    +	}
    +  }
    +
    +  public function getLink()
    +  {
    +    return '@portfolio?user=' . $this->getUsername();
    +  }
    +  
    +  /**
    +   * For the sake of form validation, it's better if we have an empty string as default in the field
    +   * in the cases where icq number is 0 or null
    +   *
    +   * @return integer
    +   */
    +  public function getIcq()
    +  {
    +    return parent::getIcq() ? parent::getIcq() : "";
    +  }
    +  
    +  /**
    +   * Return the correct age for this user
    +   *
    +   * @return integer
    +   */
    +  public function getAge()
    +  {
    +    $dob = strtotime($this->getDob());
    +    
    +    $year_diff  = date("Y") - date("Y", $dob);
    +    $month_diff = date("m") - date("m", $dob);
    +    $day_diff   = date("d") - date("d", $dob);
    +    
    +    if ($month_diff < 0 || ($month_diff == 0 && $day_diff < 0)) 
    +    {
    +      $year_diff--;
    +    }
    +    return $year_diff;
    +  }
    +}
    +
    diff --git a/lib/model/sfGuardUserGroup.php b/lib/model/sfGuardUserGroup.php
    new file mode 100644
    index 0000000..cfd0217
    --- /dev/null
    +++ b/lib/model/sfGuardUserGroup.php
    @@ -0,0 +1,20 @@
    +
    + *
    + * For the full copyright and license information, please view the LICENSE
    + * file that was distributed with this source code.
    + */
    +
    +/**
    + *
    + * @package    symfony
    + * @subpackage plugin
    + * @author     Fabien Potencier 
    + * @version    SVN: $Id: sfGuardUserGroup.php 5760 2007-10-30 07:51:16Z francois $
    + */
    +class sfGuardUserGroup extends PluginsfGuardUserGroup
    +{
    +}
    diff --git a/lib/model/sfGuardUserGroupPeer.php b/lib/model/sfGuardUserGroupPeer.php
    new file mode 100644
    index 0000000..3b31d0b
    --- /dev/null
    +++ b/lib/model/sfGuardUserGroupPeer.php
    @@ -0,0 +1,77 @@
    +
    + *
    + * For the full copyright and license information, please view the LICENSE
    + * file that was distributed with this source code.
    + */
    +
    +/**
    + *
    + * @package    symfony
    + * @subpackage plugin
    + * @author     Fabien Potencier 
    + * @version    SVN: $Id: sfGuardUserGroupPeer.php 5760 2007-10-30 07:51:16Z francois $
    + */
    +class sfGuardUserGroupPeer extends PluginsfGuardUserGroupPeer
    +{
    +
    +	public static function getOMClass()
    +  {
    +    //return 'lib.model.sfGuardPlugin.sfGuardUser';
    +    return 'lib.model.sfGuardUserGroup';
    +  }
    +  
    +  /*public static function getEditorialTeams()
    +  {
    +  	$c = new Criteria();
    +  	$c->add(sfGuardGroupPeer::IS_EDITORIAL_TEAM, 1);
    +  	$c->addAscendingOrderByColumn(sfGuardUserGroupPeer::USER_ID);
    +  	return self::doSelectJoinAll($c);
    +  }*/
    +  
    +  public static function getMembersofEditorialTeam($team_id, $active = null)
    +  {
    +  	$c = new Criteria();
    +    $c->setDistinct();
    +  	$c->add(sfGuardUserGroupPeer::GROUP_ID, $team_id);
    +  	
    +  	if ($active === true)
    +  	{
    +  		$c->add(sfGuardUserPeer::IS_ACTIVE, 1);
    +  	} else if ($active === false)
    +  	{
    +  		$c->add(sfGuardUserPeer::IS_ACTIVE, 0);
    +  	}
    +  	
    +  	$res = self::doSelectJoinsfGuardUser($c);
    +  	
    +  	$users = array();
    +  	foreach ($res as $row)
    +  	{
    +  		if (sfGuardUserPeer::isUserStaffMember($row->getSfGuardUser()->getId()))
    +  		{
    +  			$users[$row->getSfGuardUser()->getId()] = $row->getSfGuardUser();
    +  		}
    +  	}
    +  	return $users;
    +  }
    +  
    +  public static function getMembersofEditorialTeams()
    +  {
    +    $c = new Criteria();
    +    $c->setDistinct();
    +    $c->add(sfGuardGroupPeer::IS_EDITORIAL_TEAM, 1);
    +    $res = self::doSelectJoinAll($c);
    +    
    +    $users = array();
    +    foreach ($res as $row)
    +    {
    +      $users[$row->getSfGuardUser()->getId()] = $row->getSfGuardUser()->getUsername();
    +    }
    +    return $users;
    +  }
    +  
    +}
    diff --git a/lib/model/sfGuardUserPeer.php b/lib/model/sfGuardUserPeer.php
    new file mode 100644
    index 0000000..08b8f50
    --- /dev/null
    +++ b/lib/model/sfGuardUserPeer.php
    @@ -0,0 +1,724 @@
    +add(self::SALT, $salt);
    +    
    +    return self::doSelectOne($c);     
    +  }
    +  
    +  /**
    +   * Get all emails from all users who ticket the opt in e-mail box
    +   *
    +   * @return array $emails String array of e-mails
    +   */
    +  public static function retrieveOptInEmails()
    +  {
    +    $c = new Criteria();
    +    $c->addSelectColumn(sfGuardUserPeer::EMAIL);
    +    $c->add(sfGuardUserPeer::OPT_IN, 1, Criteria::EQUAL);
    +    
    +    $rs = sfGuardUserPeer::doSelectRS($c);
    +    $emails = array();
    +    while($rs->next())
    +    {
    +      $emails[] = $rs->getString(1);
    +    }    
    +    return $emails;
    +  }
    +  
    +  public static function retrieveByEmail($email)
    +  {
    +    $c = new Criteria();
    +    $c->add(self::EMAIL, $email);
    +    
    +    return self::doSelectOne($c);
    +  }
    +  
    +  /**
    +   * Returns a user with that username
    +   *
    +   * @param string $username
    +   * 
    +   * @return sfGuardUser
    +   */
    +  public static function getByUsername($username)
    +  {
    +    $c = new Criteria();
    +    $c->add(self::USERNAME, $username);
    +    
    +    return self::doSelectOne($c);
    +  }
    +
    +  /**
    +   * Returns an array of users whose username starts with the provided phrase
    +   *
    +   * @param string $starting_with
    +   * 
    +   * @return array
    +   */
    +  public static function getByUsernameStartingWith($starting_with)
    +  {
    +    $c = new Criteria();
    +    $c->add(self::USERNAME, $username . '%', Criteria::LIKE);
    +    $c->add(self::IS_ACTIVE, true);
    +    $c->add(self::IS_VERIFIED, true);
    +    
    +    return self::doSelectOne($c);
    +  }
    +  
    +  public static function getUsersByMatchingInterests($user_id, $count = null)
    +  {
    +    $c = new Criteria();
    +    $c->add(UserInterestPeer::USER_ID, $user_id);
    +    $user_interests = UserInterestPeer::doSelect($c);
    +    
    +    $interests = array();
    +    
    +    foreach($user_interests as $user_interest)
    +    {
    +      $interests[] = $user_interest->getSubreaktorId();
    +    }
    +    
    +    $uc = new Criteria();
    +    $uc->add(UserInterestPeer::SUBREAKTOR_ID, $interests, Criteria::IN);
    +    $uc->addJoin(parent::ID, UserInterestPeer::USER_ID, Criteria::LEFT_JOIN);
    +    $uc->add(parent::ID, $user_id, Criteria::NOT_EQUAL);
    +    $uc->setDistinct();
    +    $uc->add(parent::IS_ACTIVE, 1);    
    +    $uc->addDescendingOrderByColumn('rand(now())');
    +    $uc->addDescendingOrderByColumn(parent::CREATED_AT);
    +    if($count)
    +    {
    +      $uc->setLimit($count);
    +    }
    +    
    +    return parent::doSelect($uc);
    +  }
    +
    +  public static function getAllActiveUsers()
    +  {
    +    $c = new Criteria();
    +    
    +    $c->add(parent::IS_ACTIVE, 1);
    +    
    +    return parent::doSelect($c);
    +  }
    +
    +
    +  /**
    +   * Retrieve all users with usernames starting with $chars
    +   * 
    +   * @param string $chars 
    +   * @return array
    +   */
    +  public static function getUsernamesStartingWith($chars, $limit = 0)
    +  {
    +    $c = new Criteria();
    +    
    +    $c->add(parent::IS_ACTIVE, 1);
    +    $c->add(parent::IS_VERIFIED, 1);
    +    $c->add(parent::USERNAME, "$chars%", Criteria::LIKE);
    +    if ($limit > 0)
    +    {
    +      $c->setLimit($limit);
    +    }
    +    
    +    return parent::doSelect($c);
    +  }
    +
    +  /**
    +   * Retrive all active&verified users
    +   * 
    +   * @param mixed $limit 
    +   * @param mixed $showcontent 
    +   * @param mixed $subreaktor 
    +   * @param mixed $lokalreaktor 
    +   * @return array
    +   */
    +  public static function getLastUsers($limit, $showcontent, $subreaktor, $lokalreaktor, $active = false)
    +  {
    +    $c = new Criteria();
    +    $c->addDescendingOrderByColumn(sfGuardUserPeer::ID);
    +    $c->add(parent::IS_ACTIVE, 1);
    +    $c->add(parent::IS_VERIFIED, 1);
    +
    +    if ($showcontent)
    +    {
    +      $c->add(sfGuardUserPeer::SHOW_CONTENT, true);
    +    }
    +    
    +    if ($active) 
    +    {
    +      $c->add(sfGuardUserPeer::LAST_ACTIVE, null, Criteria::NOT_EQUAL);
    +    }
    +
    +    $c->setLimit($limit);
    +    if ($subreaktor || $lokalreaktor || Subreaktor::isValid())
    +    {
    +      $c->addJoin(parent::ID, UserInterestPeer::USER_ID, Criteria::LEFT_JOIN);
    +      $c->addJoin(UserInterestPeer::SUBREAKTOR_ID, SubreaktorPeer::ID);
    +      
    +      if ($subreaktor)
    +      {
    +        $reference = $subreaktor instanceof Subreaktor ? $subreaktor->getReference() : $subreaktor;
    +        $c->add(SubreaktorPeer::REFERENCE, $reference, Criteria::EQUAL);
    +      }
    +      elseif (Subreaktor::getProvidedSubreaktor() instanceof Subreaktor)
    +      {
    +      	$c->add(SubreaktorPeer::REFERENCE, Subreaktor::getProvidedSubreaktor()->getReference(), Criteria::EQUAL);
    +      }
    +    
    +      if ($lokalreaktor)
    +      {
    +        $reference = $lokalreaktor instanceof Subreaktor ? $lokalreaktor->getReference() : $lokalreaktor;
    +        $c->add(SubreaktorPeer::REFERENCE, $reference, Criteria::EQUAL);
    +      }
    +      elseif (Subreaktor::getProvidedLokalreaktor() instanceof Subreaktor)
    +      {
    +        $c->add(SubreaktorPeer::REFERENCE, Subreaktor::getProvidedLokalreaktor()->getReference(), Criteria::EQUAL);
    +      }
    +      
    +    }
    +    
    +    return parent::doSelect($c);
    +  }
    +  
    +  /**
    +   * Execute report query
    +   * 
    +   * @param array $args An array of all the possible arguments
    +   * 
    +   * @return array
    +   */
    +  public static function reportQuery($args)
    +  {
    +  	
    +  	$c = new Criteria();
    +    
    +    if (isset($args["interest"]))
    +    {
    +      $c->addJoin(parent::ID, UserInterestPeer::USER_ID, Criteria::LEFT_JOIN);
    +      $c->add(UserInterestPeer::SUBREAKTOR_ID, $args["interest"]);
    +    }
    +
    +    if (isset($args["residence"]))
    +    {
    +      $c->add(sfGuardUserPeer::RESIDENCE_ID, $args["residence"]);
    +    }
    +    
    +    if (isset($args["sex"]))
    +    {
    +      $c->add(sfGuardUserPeer::SEX, $args["sex"]);
    +    }
    +    
    +
    +    if (isset($args["activated"]))
    +    {
    +      $c->add(sfGuardUserPeer::IS_ACTIVE, $args["activated"]);
    +    }
    +
    +
    +    if (isset($args["verified"]))
    +    {
    +      $c->add(sfGuardUserPeer::IS_VERIFIED, $args["verified"]);
    +    }
    +
    +
    +    if (isset($args["showContent"]))
    +    {
    +      $c->add(sfGuardUserPeer::SHOW_CONTENT, $args["showContent"]);
    +    }
    +
    +
    +
    +
    +    
    +    $user_ids1 = array();
    +    $user_ids2 = array();
    +    $user_ids3 = array();
    +    
    +    if (isset($args["publishedArtwork"]) || isset($args["notPublishedArtwork"]))
    +    {
    +      $d = new Criteria();
    +      $d->addJoin(parent::ID, ReaktorArtworkPeer::USER_ID, Criteria::LEFT_JOIN);
    +      $d->addGroupByColumn(ReaktorArtworkPeer::USER_ID);
    +      
    +      $users = sfGuardUserPeer::doSelect($d);
    +      
    +      foreach ($users as $user)
    +      {
    +        $user_ids1[] = $user->getId();
    +      }
    +      if (isset($args["publishedArtwork"]) || isset($args["notPublishedArtwork"]))
    +      {
    +        $c->add(self::ID, $user_ids1, Criteria::IN);
    +      }
    +      if (isset($args["notPublishedArtwork"]))
    +      {
    +        $c->add(self::ID, $user_ids1, Criteria::NOT_IN);
    +      }
    +    }
    +    
    +    if (isset($args["commentedArtwork"]) || isset($args["notCommentedArtwork"]))
    +    {
    +       $d = new Criteria();
    +       $d->addJoin(parent::ID, sfCommentPeer::AUTHOR_ID, Criteria::LEFT_JOIN);
    +       $d->addGroupByColumn(sfCommentPeer::AUTHOR_ID);
    +       
    +       $users = sfGuardUserPeer::doSelect($d);
    +       
    +       foreach ($users as $user)
    +       {
    +         
    +          $user_ids2[] = $user->getId();
    +       }
    +       
    +       if (isset($args["commentAndOr"]) /*&& isset($args["publishedArtwork"])*/)
    +      {
    +        if(isset($args["commentedArtwork"]))
    +        {
    +          $c->addAnd(self::ID, $user_ids2, Criteria::IN);
    +        }
    +        if(isset($args["notCommentedArtwork"]))
    +        {
    +          $c->addAnd(self::ID, $user_ids2, Criteria::NOT_IN);
    +        }
    +      }
    +      else
    +      {
    +      	if (isset($args["commentedArtwork"]))
    +        {
    +          $c->addOr(self::ID, $user_ids2, Criteria::IN);
    +        }
    +        if (!isset($args["commentedArtwork"]))
    +        {
    +          $c->addOr(self::ID, $user_ids2, Criteria::NOT_IN);
    +        }
    +      }
    +    }
    +    
    +    if (isset($args["voted"]) || isset($args["notVoted"]))
    +    {
    +       $d = new Criteria();
    +       $d->addJoin(parent::ID, sfRatingPeer::USER_ID, Criteria::LEFT_JOIN);
    +       $d->addGroupByColumn(sfRatingPeer::USER_ID);
    +
    +       $users = sfGuardUserPeer::doSelect($d);
    +       $user_ids = array();
    +       foreach ($users as $user)
    +       {
    +         $user_ids3[] = $user->getId();
    +       }
    +       if (isset($args["voteAndOr"]) && (isset($args["publishedArtwork"]) 
    +           || isset($args["commentedArtwork"]) || isset($args["notPublishedArtwork"]) || isset($args["notCommentedArtwork"])))
    +       {
    +          if (isset($args["voted"]))
    +          {
    +            $c->addAnd(self::ID, $user_ids3, Criteria::IN);
    +          }
    +          if (isset($args["notVoted"]))
    +          {
    +            $c->addAnd(self::ID, $user_ids3, Criteria::NOT_IN);
    +          }
    +       }
    +       else
    +       {
    +          if (isset($args["voted"]))
    +          {
    +            $c->addOr(self::ID, $user_ids3, Criteria::IN);
    +          }
    +          if (isset($args["notVoted"]))
    +          {
    +            $c->addOr(self::ID, $user_ids3, Criteria::NOT_IN);
    +          }
    +       }
    +      
    +    }
    +    
    +    $c->setDistinct();
    +    $c_copy = clone($c);
    +
    +    if (isset($args["startDate"]))
    +    {
    +       $critA = $c->getNewCriterion(sfGuardUserPeer::CREATED_AT, $args["startDate"], Criteria::GREATER_EQUAL);
    +       $c->addAnd($critA);
    +    }
    +    
    +    
    +    if (isset($args["endDate"]))
    +    {
    +       $critB = $c->getNewCriterion(sfGuardUserPeer::CREATED_AT, $args["endDate"], Criteria::LESS_EQUAL);
    +       $c->addAnd($critB);
    +    }
    +    $res['query'] =  self::doSelectJoinAll($c);
    +    if (isset($args["startDate"]) && isset($args["endDate"]))
    +    {
    +      $steps    = 10;
    +      $timeDiff = strtotime($args["endDate"]) - strtotime($args["startDate"]);
    +      $step     = $timeDiff / $steps;
    +      for ($i = 0 ; $i <= $steps ; $i++)
    +      {
    +        $c = clone($c_copy);
    +        $c->add($c->getNewCriterion(sfGuardUserPeer::CREATED_AT, date("Y-m-d", strtotime($args["startDate"]) + $step * $i), Criteria::GREATER_THAN));
    +        $c->addAnd($c->getNewCriterion(sfGuardUserPeer::CREATED_AT, date("Y-m-d", strtotime($args["startDate"]) + $step * ($i+1)), Criteria::LESS_THAN));
    +       
    +        $tmp = self::doSelectJoinAll($c);
    +        unset($c);
    +        $res['graphData'][]                = count($tmp);
    +        $res['dateData'][] = array(
    +            "start"                        => strtotime($args["startDate"]) + $step * ($i-1),
    +            "end"                          => strtotime($args["startDate"]) + $step * $i,
    +        );
    +      }
    +    }
    +    return $res;
    +  }
    +  
    +  /**
    +   * Get the most active users in different ways. like uploads
    +   *  Used for reports
    +   *
    +   * @param int $limit
    +   * @param date string $start
    +   * @param sate string $end
    +   * @param int $subreaktor
    +   * @param int $sex
    +   * @return array
    +   */
    +  public static function getMostActiveUsers($limit = 20, $start = null, $end = null, $subreaktor = null, $sex = null)
    +  {
    +    $extraWhereClause = "";
    +    $extraTables      = "";
    +    $endWhereClause   = "";
    +    $timeDiff         = strtotime($end) - strtotime($start);
    +    $steps            = 10;
    +    $step             = $timeDiff / $steps;
    +    
    +    if ($start)
    +    {
    +      $extraWhereClause .= "AND submitted_at >= '$start' ";
    +    }
    +    if ($end)
    +    {
    +      $endWhereClause .= "AND submitted_at <= '$end' ";
    +    }
    +    if ($subreaktor)
    +    {
    +      $extraWhereClause .= "AND subreaktor_artwork.artwork_id = reaktor_artwork.id ".
    +                           "AND subreaktor_artwork.subreaktor_id = subreaktor.id ".
    +                           "AND subreaktor.id = $subreaktor";
    +      $extraTables = ",subreaktor_artwork,subreaktor ";
    +    }
    +    if ($sex)
    +    {
    +      $extraWhereClause .= "AND sf_guard_user.sex = $sex ";
    +    }
    +    $query = "SELECT user_id,username,COUNT(*) as cnt FROM reaktor_artwork,sf_guard_user $extraTables ".
    +             "WHERE reaktor_artwork.user_id = sf_guard_user.id $extraWhereClause $endWhereClause GROUP BY user_id ORDER BY cnt DESC LIMIT $limit";
    +    
    +    $graphQueries = array();
    +    $allRes = array();
    +    if ($start && $end)
    +    {  
    +      for ($i = 0 ; $i <= $steps ; $i++)
    +      {
    +        $endWhereClause = "AND submitted_at < '".date("Y-m-d",strtotime($start) + $step * $i)."' " . 
    +                          "AND submitted_at > '".date("Y-m-d",strtotime($start) + $step * ($i-1))."' ";;
    +        //print $endWhereClause.'
    '; + $graphQueries[] = "SELECT user_id,username,COUNT(*) as cnt FROM reaktor_artwork,sf_guard_user $extraTables ". + "WHERE reaktor_artwork.user_id = sf_guard_user.id $extraWhereClause $endWhereClause GROUP BY user_id ORDER BY cnt DESC"; + + $allRes['dateData'][]['start'] = strtotime($start)+ $step * ($i-1); + $allRes['dateData'][count($allRes['dateData'])-1]['end'] = strtotime($start)+ $step * $i; + } + } + + return self::reportCreoleQuery($query, $graphQueries,$allRes); + + } + + /** + * Get the users with most comments'used for reports + * + * @param int $limit + * @param date string $start + * @param date string $end + * @param int $subreaktor + * @param int $sex + * @return array + */ + public static function getMostCommentingUsers($limit = 20, $start = null, $end = null, $subreaktor = null, $sex = null) + { + $extraWhereClause = ""; + $extraTables = ""; + $timeDiff = strtotime($end) - strtotime($start); + $steps = 10; + $step = $timeDiff/$steps; + $endWhereClause = ""; + if ($start) + { + $extraWhereClause .= "AND sf_comment.created_at >= '$start' "; + } + if ($end) + { + $endWhereClause .= "AND sf_comment.created_at <= '$end' "; + } + if ($subreaktor) + { + $extraWhereClause .= "AND sf_comment.commentable_id = reaktor_artwork.id ". + "AND subreaktor_artwork.artwork_id = reaktor_artwork.id ". + "AND subreaktor_artwork.subreaktor_id = subreaktor.id ". + "AND subreaktor.id = $subreaktor"; + $extraTables = ",reaktor_artwork,subreaktor_artwork,subreaktor "; + } + if ($sex) + { + $extraWhereClause .= "AND sf_guard_user.sex = $sex "; + } + $query = "SELECT author_id,username,COUNT(*) as cnt FROM sf_comment,sf_guard_user $extraTables". + "WHERE sf_comment.author_id = sf_guard_user.id $extraWhereClause $endWhereClause GROUP BY author_id ORDER BY cnt DESC LIMIT $limit"; + + $graphQueries = array(); + $allRes = array(); + if ($start && $end) + { + for ($i = 0 ; $i <= $steps ; $i++) + { + $endWhereClause = "AND sf_comment.created_at < '".date("Y-m-d",strtotime($start) + $step * $i)."' " . + "AND sf_comment.created_at > '".date("Y-m-d",strtotime($start) + $step * ($i-1))."' "; + $graphQueries[] = "SELECT author_id,username,COUNT(*) as cnt FROM sf_comment,sf_guard_user $extraTables". + "WHERE sf_comment.author_id = sf_guard_user.id $extraWhereClause $endWhereClause GROUP BY author_id ORDER BY cnt DESC"; + + $allRes['dateData'][]['start'] = strtotime($start)+ $step * ($i-1); + $allRes['dateData'][count($allRes['dateData'])-1]['end'] = strtotime($start)+ $step * $i; + } + } + + return self::reportCreoleQuery($query,$graphQueries,$allRes); + } + + /** + * Generic function for executing the custom queries needed for the reports + * + * @param string $query the mysql query string + * @return array + */ + public static function reportCreoleQuery($query,$graphQueries,$allRes = array()) + { + $c = Propel::getConnection(); + $statement = $c->prepareStatement($query); + $resultset = $statement->executeQuery(); + $result = array(); + + while ($resultset->next()) + { + + $tmp['username'] = $resultset->getString('username'); + $tmp['occurence'] = $resultset->getInt('cnt'); + $result[] = $tmp; + } + $allRes['query'] = $result; + if (count($graphQueries)) + { + foreach($graphQueries as $query) + { + //print $query."
    "; + + $statement = $c->prepareStatement($query); + $resultset = $statement->executeQuery(); + $counter = 0; + while ($resultset->next()) + { + $counter++; + } + $allRes['graphData'][] = $counter; + + } + } + return $allRes; + + } + + /** + * Return the number of users currently logged in + * + * @return integer + */ + public static function getOnlineCount() + { + $count_this_sess=0; + + if (!function_exists("apc_store")) { + return self::getOnlineUsers(true); + } + if (! ($online = sfProcessCache::get("onlineCount")) ) { + $online = array(); + } + $user = sfContext::getInstance()->getUser(); + if ($user->isAuthenticated()) { + $user_id = $user->getId(); + } else { + $user_id = 0; + } + +// Avoid robots counting [they dont accept cookies] +if(isset($_COOKIE["reaktor"])){ + $online[session_id()] = array("time" => $_SERVER["REQUEST_TIME"], "user" => $user_id); + } else { +// Count user when site is refreshed for the first time and we can't get cookie + $count_this_sess=1; + } + + // Remove idling sessions from the cache + $past = $_SERVER["REQUEST_TIME"] - sfConfig::get('logged_in_time', 1800); + foreach($online as $id => $info) { + if ($info["time"] < $past) { + unset($online[$id]); + } + } + + sfProcessCache::set("onlineCount", $online); + return count($online)+$count_this_sess; + } + + /** + * Return the users that are currently logged in + * + * @param boolean $count Whether to return just a count + * + * @return array + */ + public static function getOnlineUsers($count = false) + { + if (!$onlineUserArray = sfProcessCache::get("onlineCount")) + { + return; + } + $ids = array(); + foreach ($onlineUserArray as $onlineUser) + { + $ids[] = $onlineUser["user"]; + } + $c = new Criteria(); + $c->add(self::ID, $ids, Criteria::IN); + + if ($count) + { + return self::doCount($c); + } + else + { + return self::doSelect($c); + } + } + + /** + * Returns whether or not $user_id is logged in + * + * @param int $user_id + * @return bool + */ + public static function isUserOnline($user_id) + { + if (!function_exists("apc_store") || !($online = sfProcessCache::get("onlineCount"))) { + $c = new Criteria(); + $c->add(sfGuardUserPeer::ID,$user_id); + $c->add(sfGuardUserPeer::SHOW_LOGIN_STATUS, 1); + $c->add(sfGuardUserPeer::LAST_LOGIN,microtime(true)-sfConfig::get('logged_in_time', 1800),Criteria::GREATER_THAN); + $res = sfGuardUserPeer::doSelect($c); + return (bool)count($res); + } + + foreach($online as $id => $info) + { + if ($info["user"] == $user_id) + { + return true; + } + } + return false; + } + + /** + * Returns whether or not $user_id is a member of the group "Staff" + * + * @param int $user_id + * @return bool + */ + public static function isUserStaffMember($user_id) + { + $c = new Criteria(); + $c->addJoin(sfGuardUserPeer::ID, sfGuardUserGroupPeer::USER_ID); + $c->add(sfGuardUserPeer::ID, $user_id); + $c->add(sfGuardUserGroupPeer::GROUP_ID, 3); // the group staff has id = 3 + $res = sfGuardUserPeer::doSelect($c); + if (count($res) > 0) + { + return true; + } + else + { + return false; + } + } + + + public static function getMostActiveSince($time,$actions,$limit=20) + { + $c = new Criteria(); + $qry = "SELECT count(*) as cnt, username FROM history,sf_guard_user WHERE history.USER_ID=sf_guard_user.ID AND history.CREATED_AT>'".date('Y-m-d', $time)."' AND history.ACTION_ID IN ("; + foreach ($actions as $key => $action) + { + if ($key != 0) + $qry .= ","; + $qry .= $action; + } + $qry .= ") GROUP BY history.USER_ID order by cnt DESC LIMIT $limit"; + return self::reportCreoleQuery($qry,array()); + } +} diff --git a/log/reaktor_dev.log b/log/reaktor_dev.log new file mode 100644 index 0000000..d98a7d2 --- /dev/null +++ b/log/reaktor_dev.log @@ -0,0 +1 @@ +Feb 01 14:47:17 symfony [err] {sfParseException} Configuration file "/usr/share/php/data/symfony/config/php.yml" specifies key "zend.ze1_compatibility_mode" which is not a php.ini directive. diff --git a/plugins/.channels/.alias/pear.txt b/plugins/.channels/.alias/pear.txt new file mode 100644 index 0000000..f4730b9 --- /dev/null +++ b/plugins/.channels/.alias/pear.txt @@ -0,0 +1 @@ +pear.php.net \ No newline at end of file diff --git a/plugins/.channels/.alias/pecl.txt b/plugins/.channels/.alias/pecl.txt new file mode 100644 index 0000000..2de48f1 --- /dev/null +++ b/plugins/.channels/.alias/pecl.txt @@ -0,0 +1 @@ +pecl.php.net \ No newline at end of file diff --git a/plugins/.channels/.alias/symfony.txt b/plugins/.channels/.alias/symfony.txt new file mode 100644 index 0000000..2589a3a --- /dev/null +++ b/plugins/.channels/.alias/symfony.txt @@ -0,0 +1 @@ +pear.symfony-project.com \ No newline at end of file diff --git a/plugins/.channels/__uri.reg b/plugins/.channels/__uri.reg new file mode 100644 index 0000000..d7fa8c9 --- /dev/null +++ b/plugins/.channels/__uri.reg @@ -0,0 +1 @@ +a:4:{s:4:"name";s:5:"__uri";s:7:"servers";a:1:{s:7:"primary";a:1:{s:6:"xmlrpc";a:1:{s:8:"function";a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:4:"****";}}}}s:7:"summary";s:34:"Pseudo-channel for static packages";s:13:"_lastmodified";s:31:"Wed, 30 Jan 2008 09:41:39 +0100";} \ No newline at end of file diff --git a/plugins/.channels/pear.php.net.reg b/plugins/.channels/pear.php.net.reg new file mode 100644 index 0000000..e6f80c5 --- /dev/null +++ b/plugins/.channels/pear.php.net.reg @@ -0,0 +1 @@ +a:5:{s:4:"name";s:12:"pear.php.net";s:14:"suggestedalias";s:4:"pear";s:7:"summary";s:40:"PHP Extension and Application Repository";s:7:"servers";a:1:{s:7:"primary";a:2:{s:6:"xmlrpc";a:1:{s:8:"function";a:10:{i:0;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:9:"logintest";}i:1;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:26:"package.listLatestReleases";}i:2;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:15:"package.listAll";}i:3;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:12:"package.info";}i:4;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:22:"package.getDownloadURL";}i:5;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.1";}s:8:"_content";s:22:"package.getDownloadURL";}i:6;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:25:"package.getDepDownloadURL";}i:7;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.1";}s:8:"_content";s:25:"package.getDepDownloadURL";}i:8;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:14:"package.search";}i:9;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:15:"channel.listAll";}}}s:4:"rest";a:1:{s:7:"baseurl";a:2:{i:0;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.0";}s:8:"_content";s:25:"http://pear.php.net/rest/";}i:1;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.1";}s:8:"_content";s:25:"http://pear.php.net/rest/";}}}}}s:13:"_lastmodified";s:31:"Wed, 30 Jan 2008 09:41:39 +0100";} \ No newline at end of file diff --git a/plugins/.channels/pear.symfony-project.com.reg b/plugins/.channels/pear.symfony-project.com.reg new file mode 100644 index 0000000..511a0b0 --- /dev/null +++ b/plugins/.channels/pear.symfony-project.com.reg @@ -0,0 +1 @@ +a:6:{s:7:"attribs";a:4:{s:7:"version";s:3:"1.0";s:5:"xmlns";s:31:"http://pear.php.net/channel-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:75:"http://pear.php.net/dtd/channel-1.0 http://pear.php.net/dtd/channel-1.0.xsd";}s:4:"name";s:24:"pear.symfony-project.com";s:7:"summary";s:28:"symfony project PEAR channel";s:14:"suggestedalias";s:7:"symfony";s:7:"servers";a:1:{s:7:"primary";a:1:{s:4:"rest";a:1:{s:7:"baseurl";a:2:{i:0;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.0";}s:8:"_content";s:56:"http://pear.symfony-project.com/Chiara_PEAR_Server_REST/";}i:1;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.1";}s:8:"_content";s:56:"http://pear.symfony-project.com/Chiara_PEAR_Server_REST/";}}}}}s:13:"_lastmodified";a:2:{s:4:"ETag";s:19:"113845-297-dc93f000";s:13:"Last-Modified";s:31:"Tue, 29 Jul 2008 08:03:35 +0000";}} \ No newline at end of file diff --git a/plugins/.channels/pecl.php.net.reg b/plugins/.channels/pecl.php.net.reg new file mode 100644 index 0000000..98bdfbc --- /dev/null +++ b/plugins/.channels/pecl.php.net.reg @@ -0,0 +1 @@ +a:6:{s:4:"name";s:12:"pecl.php.net";s:14:"suggestedalias";s:4:"pecl";s:7:"summary";s:31:"PHP Extension Community Library";s:7:"servers";a:1:{s:7:"primary";a:2:{s:6:"xmlrpc";a:1:{s:8:"function";a:10:{i:0;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:9:"logintest";}i:1;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:26:"package.listLatestReleases";}i:2;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:15:"package.listAll";}i:3;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:12:"package.info";}i:4;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:22:"package.getDownloadURL";}i:5;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.1";}s:8:"_content";s:22:"package.getDownloadURL";}i:6;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:25:"package.getDepDownloadURL";}i:7;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.1";}s:8:"_content";s:25:"package.getDepDownloadURL";}i:8;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:14:"package.search";}i:9;a:2:{s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}s:8:"_content";s:15:"channel.listAll";}}}s:4:"rest";a:1:{s:7:"baseurl";a:2:{i:0;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.0";}s:8:"_content";s:25:"http://pecl.php.net/rest/";}i:1;a:2:{s:7:"attribs";a:1:{s:4:"type";s:7:"REST1.1";}s:8:"_content";s:25:"http://pecl.php.net/rest/";}}}}}s:15:"validatepackage";a:2:{s:8:"_content";s:19:"PEAR_Validator_PECL";s:7:"attribs";a:1:{s:7:"version";s:3:"1.0";}}s:13:"_lastmodified";s:31:"Wed, 30 Jan 2008 09:41:39 +0100";} \ No newline at end of file diff --git a/plugins/.depdb b/plugins/.depdb new file mode 100644 index 0000000..81b853e --- /dev/null +++ b/plugins/.depdb @@ -0,0 +1 @@ +a:3:{s:8:"_version";s:3:"1.0";s:12:"dependencies";a:1:{s:24:"pear.symfony-project.com";a:11:{s:13:"sfguardplugin";a:1:{i:0;a:3:{s:3:"dep";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:35:"sfpropelactastaggablebehaviorplugin";a:1:{i:0;a:3:{s:3:"dep";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:17:"sfthumbnailplugin";a:1:{i:0;a:3:{s:3:"dep";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:20:"sfmedialibraryplugin";a:1:{i:0;a:3:{s:3:"dep";a:4:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:34:"sfpropelactasratablebehaviorplugin";a:1:{i:0;a:3:{s:3:"dep";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:31:"sfpropelalternativeschemaplugin";a:1:{i:0;a:3:{s:3:"dep";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:19:"sfi18nextractplugin";a:1:{i:0;a:3:{s:3:"dep";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:13:"sffeed2plugin";a:1:{i:0;a:3:{s:3:"dep";a:4:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"0.8.1";s:3:"max";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:15:"dwjpgraphplugin";a:1:{i:0;a:3:{s:3:"dep";a:4:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.2.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:18:"sfwebbrowserplugin";a:1:{i:0;a:3:{s:3:"dep";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"0.8.1";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}s:17:"sfrecaptchaplugin";a:1:{i:0;a:3:{s:3:"dep";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}s:4:"type";s:8:"required";s:5:"group";b:0;}}}}s:8:"packages";a:1:{s:24:"pear.symfony-project.com";a:1:{s:7:"symfony";a:11:{i:0;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:13:"sfguardplugin";}i:1;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:35:"sfpropelactastaggablebehaviorplugin";}i:2;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:17:"sfthumbnailplugin";}i:3;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:20:"sfmedialibraryplugin";}i:4;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:34:"sfpropelactasratablebehaviorplugin";}i:5;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:31:"sfpropelalternativeschemaplugin";}i:6;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:19:"sfi18nextractplugin";}i:7;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:13:"sffeed2plugin";}i:8;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:15:"dwjpgraphplugin";}i:9;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:18:"sfwebbrowserplugin";}i:10;a:2:{s:7:"channel";s:24:"pear.symfony-project.com";s:7:"package";s:17:"sfrecaptchaplugin";}}}}} \ No newline at end of file diff --git a/plugins/.depdblock b/plugins/.depdblock new file mode 100644 index 0000000..e69de29 diff --git a/plugins/.filemap b/plugins/.filemap new file mode 100644 index 0000000..aa1f10f --- /dev/null +++ b/plugins/.filemap @@ -0,0 +1 @@ +a:1:{s:4:"data";a:258:{s:34:"sflightboxplugin/config/config.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:46:"sflightboxplugin/lib/helper/LightboxHelper.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:67:"sflightboxplugin/modules/sfLightboxPlugin/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:68:"sflightboxplugin/modules/sfLightboxPlugin/templates/modalSuccess.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:67:"sflightboxplugin/modules/sfLightboxPlugin/templates/testSuccess.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:61:"sflightboxplugin/modules/sfLightboxPlugin/templates/_test.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:37:"sflightboxplugin/web/css/lightbox.css";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:37:"sflightboxplugin/web/css/modalbox.css";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:45:"sflightboxplugin/web/images/en/closelabel.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:44:"sflightboxplugin/web/images/en/nextlabel.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:44:"sflightboxplugin/web/images/en/prevlabel.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:45:"sflightboxplugin/web/images/fr/closelabel.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:44:"sflightboxplugin/web/images/fr/nextlabel.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:44:"sflightboxplugin/web/images/fr/prevlabel.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:37:"sflightboxplugin/web/images/blank.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:37:"sflightboxplugin/web/images/close.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:39:"sflightboxplugin/web/images/loading.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:36:"sflightboxplugin/web/images/next.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:36:"sflightboxplugin/web/images/prev.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:35:"sflightboxplugin/web/js/lightbox.js";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:35:"sflightboxplugin/web/js/modalbox.js";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:24:"sflightboxplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:23:"sflightboxplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:16:"sflightboxplugin";}s:68:"sfpropelalternativeschemaplugin/lib/sfPropelDatabaseSchema.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:66:"sfpropelalternativeschemaplugin/lib/SfAlternativeObjectBuilder.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:64:"sfpropelalternativeschemaplugin/lib/SfAlternativePeerBuilder.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:65:"sfpropelalternativeschemaplugin/test/unit/fixtures/new_schema.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:61:"sfpropelalternativeschemaplugin/test/unit/fixtures/schema.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:61:"sfpropelalternativeschemaplugin/test/unit/fixtures/schema.xml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:72:"sfpropelalternativeschemaplugin/test/unit/sfPropelDatabaseSchemaTest.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:38:"sfpropelalternativeschemaplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:39:"sfpropelalternativeschemaplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:31:"sfpropelalternativeschemaplugin";}s:24:"sfrecaptchaplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:25:"sfrecaptchaplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:38:"sfrecaptchaplugin/lib/recaptchalib.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:52:"sfrecaptchaplugin/lib/sfReCaptchaValidator.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:48:"sfrecaptchaplugin/lib/helper/recaptchaHelper.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:61:"sfrecaptchaplugin/modules/recaptcha/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:62:"sfrecaptchaplugin/modules/recaptcha/templates/indexSuccess.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:65:"sfrecaptchaplugin/modules/recaptcha/templates/mailhideSuccess.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:54:"sfrecaptchaplugin/modules/recaptcha/validate/index.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfrecaptchaplugin";}s:45:"sfwebbrowserplugin/lib/sfWebBrowser.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:18:"sfwebbrowserplugin";}s:47:"sfwebbrowserplugin/lib/sfFopenAdapter.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:18:"sfwebbrowserplugin";}s:46:"sfwebbrowserplugin/lib/sfCurlAdapter.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:18:"sfwebbrowserplugin";}s:49:"sfwebbrowserplugin/lib/sfSocketsAdapter.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:18:"sfwebbrowserplugin";}s:25:"sfwebbrowserplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:18:"sfwebbrowserplugin";}s:26:"sfwebbrowserplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:18:"sfwebbrowserplugin";}s:53:"sfpropelactastaggablebehaviorplugin/config/config.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:53:"sfpropelactastaggablebehaviorplugin/config/schema.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:61:"sfpropelactastaggablebehaviorplugin/lib/helper/TagsHelper.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:53:"sfpropelactastaggablebehaviorplugin/lib/model/Tag.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:57:"sfpropelactastaggablebehaviorplugin/lib/model/Tagging.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:61:"sfpropelactastaggablebehaviorplugin/lib/model/TaggingPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:57:"sfpropelactastaggablebehaviorplugin/lib/model/TagPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:79:"sfpropelactastaggablebehaviorplugin/lib/sfPropelActAsTaggableBehavior.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:78:"sfpropelactastaggablebehaviorplugin/lib/sfPropelActAsTaggableToolkit.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:83:"sfpropelactastaggablebehaviorplugin/test/unit/sfPropelActAsTaggableBehaviorTest.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:42:"sfpropelactastaggablebehaviorplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:43:"sfpropelactastaggablebehaviorplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:35:"sfpropelactastaggablebehaviorplugin";}s:34:"sffeed2plugin/lib/sfFeed.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:38:"sffeed2plugin/lib/sfFeedItem.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:43:"sffeed2plugin/lib/sfFeedEnclosure.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:39:"sffeed2plugin/lib/sfAtom1Feed.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:37:"sffeed2plugin/lib/sfRssFeed.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:40:"sffeed2plugin/lib/sfRss201Feed.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:40:"sffeed2plugin/lib/sfRss091Feed.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:39:"sffeed2plugin/lib/sfRss10Feed.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:38:"sffeed2plugin/lib/sfFeedPeer.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:20:"sffeed2plugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:21:"sffeed2plugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sffeed2plugin";}s:31:"sfguardplugin/config/config.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:31:"sfguardplugin/config/schema.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:40:"sfguardplugin/data/fixtures/fixtures.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:50:"sfguardplugin/data/tasks/sfGuardSuperAdminTask.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:53:"sfguardplugin/lib/model/plugin/PluginsfGuardGroup.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:57:"sfguardplugin/lib/model/plugin/PluginsfGuardGroupPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:63:"sfguardplugin/lib/model/plugin/PluginsfGuardGroupPermission.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:67:"sfguardplugin/lib/model/plugin/PluginsfGuardGroupPermissionPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:58:"sfguardplugin/lib/model/plugin/PluginsfGuardPermission.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:62:"sfguardplugin/lib/model/plugin/PluginsfGuardPermissionPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:52:"sfguardplugin/lib/model/plugin/PluginsfGuardUser.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:56:"sfguardplugin/lib/model/plugin/PluginsfGuardUserPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:57:"sfguardplugin/lib/model/plugin/PluginsfGuardUserGroup.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:61:"sfguardplugin/lib/model/plugin/PluginsfGuardUserGroupPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:62:"sfguardplugin/lib/model/plugin/PluginsfGuardUserPermission.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:66:"sfguardplugin/lib/model/plugin/PluginsfGuardUserPermissionPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:59:"sfguardplugin/lib/model/plugin/PluginsfGuardRememberKey.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:63:"sfguardplugin/lib/model/plugin/PluginsfGuardRememberKeyPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:40:"sfguardplugin/lib/model/sfGuardGroup.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:44:"sfguardplugin/lib/model/sfGuardGroupPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:50:"sfguardplugin/lib/model/sfGuardGroupPermission.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:54:"sfguardplugin/lib/model/sfGuardGroupPermissionPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:45:"sfguardplugin/lib/model/sfGuardPermission.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:49:"sfguardplugin/lib/model/sfGuardPermissionPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:39:"sfguardplugin/lib/model/sfGuardUser.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:43:"sfguardplugin/lib/model/sfGuardUserPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:44:"sfguardplugin/lib/model/sfGuardUserGroup.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:48:"sfguardplugin/lib/model/sfGuardUserGroupPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:49:"sfguardplugin/lib/model/sfGuardUserPermission.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:53:"sfguardplugin/lib/model/sfGuardUserPermissionPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:46:"sfguardplugin/lib/model/sfGuardRememberKey.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:50:"sfguardplugin/lib/model/sfGuardRememberKeyPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:52:"sfguardplugin/lib/user/sfGuardSecurityUser.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:58:"sfguardplugin/lib/validator/sfGuardUserValidator.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:54:"sfguardplugin/lib/sfGuardBasicSecurityFilter.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:59:"sfguardplugin/modules/sfGuardAuth/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:53:"sfguardplugin/modules/sfGuardAuth/config/security.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:70:"sfguardplugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:61:"sfguardplugin/modules/sfGuardAuth/templates/secureSuccess.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:61:"sfguardplugin/modules/sfGuardAuth/templates/signinSuccess.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:53:"sfguardplugin/modules/sfGuardAuth/validate/signin.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:60:"sfguardplugin/modules/sfGuardGroup/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:55:"sfguardplugin/modules/sfGuardGroup/config/generator.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:52:"sfguardplugin/modules/sfGuardGroup/validate/edit.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:65:"sfguardplugin/modules/sfGuardPermission/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:60:"sfguardplugin/modules/sfGuardPermission/config/generator.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:57:"sfguardplugin/modules/sfGuardPermission/validate/edit.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:59:"sfguardplugin/modules/sfGuardUser/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:54:"sfguardplugin/modules/sfGuardUser/config/generator.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:70:"sfguardplugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:57:"sfguardplugin/modules/sfGuardUser/templates/_password.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:61:"sfguardplugin/modules/sfGuardUser/templates/_password_bis.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:51:"sfguardplugin/modules/sfGuardUser/validate/edit.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:20:"sfguardplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:21:"sfguardplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:13:"sfguardplugin";}s:43:"dwjpgraphplugin/lib/jpgraph/lang/de.inc.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:43:"dwjpgraphplugin/lib/jpgraph/lang/en.inc.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/lang/prod.inc.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:37:"dwjpgraphplugin/lib/jpgraph/flags.dat";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:50:"dwjpgraphplugin/lib/jpgraph/flags_thumb100x100.dat";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/flags_thumb60x60.dat";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/flags_thumb35x35.dat";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/imgdata_balls.inc";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:46:"dwjpgraphplugin/lib/jpgraph/imgdata_bevels.inc";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/imgdata_diamonds.inc";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/imgdata_pushpins.inc";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/imgdata_stars.inc";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:46:"dwjpgraphplugin/lib/jpgraph/jpg-config.inc.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:39:"dwjpgraphplugin/lib/jpgraph/jpgraph.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/jpgraph_antispam.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:55:"dwjpgraphplugin/lib/jpgraph/jpgraph_antispam-digits.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:43:"dwjpgraphplugin/lib/jpgraph/jpgraph_bar.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:46:"dwjpgraphplugin/lib/jpgraph/jpgraph_canvas.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:49:"dwjpgraphplugin/lib/jpgraph/jpgraph_canvtools.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:44:"dwjpgraphplugin/lib/jpgraph/jpgraph_date.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/jpgraph_error.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:54:"dwjpgraphplugin/lib/jpgraph/jpgraph_errhandler.inc.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/jpgraph_flags.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/jpgraph_gantt.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/jpgraph_gradient.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/jpgraph_iconplot.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/jpgraph_imgtrans.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:44:"dwjpgraphplugin/lib/jpgraph/jpgraph_line.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:43:"dwjpgraphplugin/lib/jpgraph/jpgraph_log.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:46:"dwjpgraphplugin/lib/jpgraph/jpgraph_mgraph.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:43:"dwjpgraphplugin/lib/jpgraph/jpgraph_pie.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/jpgraph_pie3d.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:48:"dwjpgraphplugin/lib/jpgraph/jpgraph_plotband.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:52:"dwjpgraphplugin/lib/jpgraph/jpgraph_plotmark.inc.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/jpgraph_polar.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/jpgraph_radar.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:47:"dwjpgraphplugin/lib/jpgraph/jpgraph_regstat.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:47:"dwjpgraphplugin/lib/jpgraph/jpgraph_scatter.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"dwjpgraphplugin/lib/jpgraph/jpgraph_stock.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:35:"dwjpgraphplugin/lib/jpgraph/QPL.txt";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:39:"dwjpgraphplugin/lib/sfJpGraph.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:65:"dwjpgraphplugin/modules/dwJpgraphPlugin/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:38:"dwjpgraphplugin/test/sfJpGraphTest.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:22:"dwjpgraphplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:23:"dwjpgraphplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:15:"dwjpgraphplugin";}s:45:"sfi18nextractplugin/data/tasks/sfPakeI18N.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:58:"sfi18nextractplugin/lib/sfI18nApplicationExtract.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:47:"sfi18nextractplugin/lib/sfI18nExtract.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:58:"sfi18nextractplugin/lib/sfI18nExtractorInterface.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:53:"sfi18nextractplugin/lib/sfI18nModuleExtract.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:52:"sfi18nextractplugin/lib/sfI18nPhpExtractor.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:53:"sfi18nextractplugin/lib/sfI18nYamlExtractor.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:62:"sfi18nextractplugin/lib/sfI18nYamlGeneratorExtractor.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:61:"sfi18nextractplugin/lib/sfI18nYamlValidateExtractor.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:26:"sfi18nextractplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:27:"sfi18nextractplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:19:"sfi18nextractplugin";}s:52:"sfpropelactasratablebehaviorplugin/config/config.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:61:"sfpropelactasratablebehaviorplugin/config/config_handlers.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:52:"sfpropelactasratablebehaviorplugin/config/schema.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:71:"sfpropelactasratablebehaviorplugin/lib/model/map/sfRatingMapBuilder.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:64:"sfpropelactasratablebehaviorplugin/lib/model/om/BasesfRating.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:68:"sfpropelactasratablebehaviorplugin/lib/model/om/BasesfRatingPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:57:"sfpropelactasratablebehaviorplugin/lib/model/sfRating.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:61:"sfpropelactasratablebehaviorplugin/lib/model/sfRatingPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:77:"sfpropelactasratablebehaviorplugin/lib/sfPropelActAsRatableBehavior.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:81:"sfpropelactasratablebehaviorplugin/test/unit/sfPropelActAsRatableBehaviorTest.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:42:"sfpropelactasratablebehaviorplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:41:"sfpropelactasratablebehaviorplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:34:"sfpropelactasratablebehaviorplugin";}s:39:"sfsimplecmsplugin/config/app.yml.sample";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:35:"sfsimplecmsplugin/config/config.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:35:"sfsimplecmsplugin/config/schema.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:45:"sfsimplecmsplugin/data/fixtures/test_data.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:50:"sfsimplecmsplugin/lib/helper/sfSimpleCMSHelper.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:61:"sfsimplecmsplugin/lib/model/map/sfSimpleCMSSlotMapBuilder.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:61:"sfsimplecmsplugin/lib/model/map/sfSimpleCMSPageMapBuilder.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:54:"sfsimplecmsplugin/lib/model/om/BasesfSimpleCMSPage.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:58:"sfsimplecmsplugin/lib/model/om/BasesfSimpleCMSPagePeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:54:"sfsimplecmsplugin/lib/model/om/BasesfSimpleCMSSlot.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:58:"sfsimplecmsplugin/lib/model/om/BasesfSimpleCMSSlotPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:47:"sfsimplecmsplugin/lib/model/sfSimpleCMSPage.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:51:"sfsimplecmsplugin/lib/model/sfSimpleCMSPagePeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:47:"sfsimplecmsplugin/lib/model/sfSimpleCMSSlot.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:51:"sfsimplecmsplugin/lib/model/sfSimpleCMSSlotPeer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:61:"sfsimplecmsplugin/lib/slotType/sfSimpleCMSSlotImage.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:63:"sfsimplecmsplugin/lib/slotType/sfSimpleCMSSlotModular.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:59:"sfsimplecmsplugin/lib/slotType/sfSimpleCMSSlotPhp.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:64:"sfsimplecmsplugin/lib/slotType/sfSimpleCMSSlotRichText.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:60:"sfsimplecmsplugin/lib/slotType/sfSimpleCMSSlotText.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:63:"sfsimplecmsplugin/lib/slotType/sfSimpleCMSSlotTypeInterface.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:48:"sfsimplecmsplugin/lib/sfSimpleCMSTools.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:63:"sfsimplecmsplugin/modules/sfSimpleCMS/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:66:"sfsimplecmsplugin/modules/sfSimpleCMS/actions/components.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:74:"sfsimplecmsplugin/modules/sfSimpleCMS/lib/BasesfSimpleCMSActions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:77:"sfsimplecmsplugin/modules/sfSimpleCMS/lib/BasesfSimpleCMSComponents.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:64:"sfsimplecmsplugin/modules/sfSimpleCMS/templates/homeTemplate.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:58:"sfsimplecmsplugin/modules/sfSimpleCMS/templates/layout.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:70:"sfsimplecmsplugin/modules/sfSimpleCMS/templates/simplePageTemplate.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:63:"sfsimplecmsplugin/modules/sfSimpleCMS/templates/_breadcrumb.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:64:"sfsimplecmsplugin/modules/sfSimpleCMS/templates/_editorTools.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:58:"sfsimplecmsplugin/modules/sfSimpleCMS/templates/_embed.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:64:"sfsimplecmsplugin/modules/sfSimpleCMS/templates/_latestPages.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:67:"sfsimplecmsplugin/modules/sfSimpleCMS/templates/_mainNavigation.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:57:"sfsimplecmsplugin/modules/sfSimpleCMS/validate/create.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:57:"sfsimplecmsplugin/modules/sfSimpleCMS/validate/update.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:68:"sfsimplecmsplugin/modules/sfSimpleCMSAdmin/actions/actions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:63:"sfsimplecmsplugin/modules/sfSimpleCMSAdmin/config/generator.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:84:"sfsimplecmsplugin/modules/sfSimpleCMSAdmin/lib/BasesfSimpleCMSAdminActions.class.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:70:"sfsimplecmsplugin/modules/sfSimpleCMSAdmin/templates/_is_published.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:69:"sfsimplecmsplugin/modules/sfSimpleCMSAdmin/templates/_list_footer.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:71:"sfsimplecmsplugin/modules/sfSimpleCMSAdmin/templates/_localizations.php";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:63:"sfsimplecmsplugin/modules/sfSimpleCMSAdmin/validate/addPage.yml";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:44:"sfsimplecmsplugin/web/css/CMSEditorTools.css";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:42:"sfsimplecmsplugin/web/css/CMSTemplates.css";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:54:"sfsimplecmsplugin/web/images/application_form_edit.png";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:52:"sfsimplecmsplugin/web/images/bullet_toggle_minus.png";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:51:"sfsimplecmsplugin/web/images/bullet_toggle_plus.png";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:47:"sfsimplecmsplugin/web/images/cms_toolbox_bg.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:48:"sfsimplecmsplugin/web/images/cms_toolbox_bg1.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:54:"sfsimplecmsplugin/web/images/cms_toolbox_header_bg.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:48:"sfsimplecmsplugin/web/images/page_white_edit.png";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:51:"sfsimplecmsplugin/web/images/page_white_magnify.png";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:48:"sfsimplecmsplugin/web/images/page_white_text.png";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:42:"sfsimplecmsplugin/web/images/tab_right.png";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:47:"sfsimplecmsplugin/web/images/symfony_button.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:40:"sfsimplecmsplugin/web/images/head_bg.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:39:"sfsimplecmsplugin/web/images/nav_bg.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:44:"sfsimplecmsplugin/web/images/nav-item_bg.gif";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:47:"sfsimplecmsplugin/web/images/coffee_machine.png";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:43:"sfsimplecmsplugin/web/js/cookies_handler.js";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:39:"sfsimplecmsplugin/web/js/editorTools.js";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:41:"sfsimplecmsplugin/web/js/tiny_mce_AJAX.js";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:25:"sfsimplecmsplugin/LICENSE";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}s:24:"sfsimplecmsplugin/README";a:2:{i:0;s:24:"pear.symfony-project.com";i:1;s:17:"sfsimplecmsplugin";}}} \ No newline at end of file diff --git a/plugins/.lock b/plugins/.lock new file mode 100644 index 0000000..e69de29 diff --git a/plugins/.pearrc b/plugins/.pearrc new file mode 100644 index 0000000..ecdd7bc --- /dev/null +++ b/plugins/.pearrc @@ -0,0 +1,2 @@ +#PEAR_Config 0.9 +a:8:{s:10:"__channels";a:4:{s:5:"__uri";a:0:{}s:24:"pear.symfony-project.com";a:0:{}s:12:"pecl.php.net";a:0:{}s:11:"doc.php.net";a:0:{}}s:7:"php_dir";s:30:"/crypto/linpro/reaktor/plugins";s:8:"data_dir";s:30:"/crypto/linpro/reaktor/plugins";s:8:"test_dir";s:30:"/crypto/linpro/reaktor/plugins";s:7:"doc_dir";s:30:"/crypto/linpro/reaktor/plugins";s:7:"bin_dir";s:30:"/crypto/linpro/reaktor/plugins";s:9:"cache_dir";s:30:"/crypto/linpro/reaktor/cache//";s:12:"download_dir";s:30:"/crypto/linpro/reaktor/cache//";} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/dwjpgraphplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/dwjpgraphplugin.reg new file mode 100644 index 0000000..8262c96 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/dwjpgraphplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.7.1";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:15:"dwJpgraphPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:15:"dwJpgraphPlugin";s:11:"description";s:65:"dwJpgraphPlugin is for dynamically generating graphs via Jpgraph.";s:4:"lead";a:4:{s:4:"name";s:14:"Dustin Whittle";s:4:"user";s:8:"dwhittle";s:5:"email";s:34:"dustin.whittle@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2008-03-14";s:4:"time";s:8:"11:11:09";s:7:"version";a:2:{s:7:"release";s:5:"1.0.1";s:3:"api";s:5:"1.0.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:46:"http://www.symfony-project.com/content/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:45:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"422dfa08ec2462c2c1e372f2db4127d2";s:4:"name";s:27:"lib/jpgraph/lang/de.inc.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"640a0d4973699a1eb2c5f9d262572268";s:4:"name";s:27:"lib/jpgraph/lang/en.inc.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7e66c9313089392e26514bbbdea23fa2";s:4:"name";s:29:"lib/jpgraph/lang/prod.inc.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"058b2e8c37039f1281e1d33cdc98cc72";s:4:"name";s:21:"lib/jpgraph/flags.dat";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"efef598db76af8e4b9bc28167e68a22a";s:4:"name";s:34:"lib/jpgraph/flags_thumb100x100.dat";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d6da78161788f31a88214288eac51305";s:4:"name";s:32:"lib/jpgraph/flags_thumb60x60.dat";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1453ea849382b65101679db6ed5de68d";s:4:"name";s:32:"lib/jpgraph/flags_thumb35x35.dat";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"42d020d4b425bc395572b5af3a11185f";s:4:"name";s:29:"lib/jpgraph/imgdata_balls.inc";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7a68759dbd3ef4979713571a9af90894";s:4:"name";s:30:"lib/jpgraph/imgdata_bevels.inc";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7623e758447d3b1b1e1d9a9c82d271cd";s:4:"name";s:32:"lib/jpgraph/imgdata_diamonds.inc";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0ecc41313a07e5593fd288e58ce6a008";s:4:"name";s:32:"lib/jpgraph/imgdata_pushpins.inc";s:4:"role";s:4:"data";}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ca808c475e5085a9e388bee191579fbe";s:4:"name";s:29:"lib/jpgraph/imgdata_stars.inc";s:4:"role";s:4:"data";}}i:12;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d72192c104ba3630ec4ec27771de75a5";s:4:"name";s:30:"lib/jpgraph/jpg-config.inc.php";s:4:"role";s:4:"data";}}i:13;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"cc55d5961c5c6f67b463a7543979909c";s:4:"name";s:23:"lib/jpgraph/jpgraph.php";s:4:"role";s:4:"data";}}i:14;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1f73bdae39983a837d1e07b9f6a0e64e";s:4:"name";s:32:"lib/jpgraph/jpgraph_antispam.php";s:4:"role";s:4:"data";}}i:15;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"72b4cd483dce5333ec6811c0f77d18d0";s:4:"name";s:39:"lib/jpgraph/jpgraph_antispam-digits.php";s:4:"role";s:4:"data";}}i:16;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b3ae39dcc3f6038657075d9848f1b63a";s:4:"name";s:27:"lib/jpgraph/jpgraph_bar.php";s:4:"role";s:4:"data";}}i:17;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"dbc58f52de147f6843283b34207fb5cb";s:4:"name";s:30:"lib/jpgraph/jpgraph_canvas.php";s:4:"role";s:4:"data";}}i:18;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8ae288c7f1860874815444c0fe701692";s:4:"name";s:33:"lib/jpgraph/jpgraph_canvtools.php";s:4:"role";s:4:"data";}}i:19;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"09d141a116c1a5bbabff0cdd98bc6078";s:4:"name";s:28:"lib/jpgraph/jpgraph_date.php";s:4:"role";s:4:"data";}}i:20;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e760326116173403b3f46359434afcd4";s:4:"name";s:29:"lib/jpgraph/jpgraph_error.php";s:4:"role";s:4:"data";}}i:21;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3da2db1a213028bd420e762b53c27b45";s:4:"name";s:38:"lib/jpgraph/jpgraph_errhandler.inc.php";s:4:"role";s:4:"data";}}i:22;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7d1f4a5d71de4a85a43c05e8ca963667";s:4:"name";s:29:"lib/jpgraph/jpgraph_flags.php";s:4:"role";s:4:"data";}}i:23;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"92f471b733093b0801d86e5fb1ec8c6e";s:4:"name";s:29:"lib/jpgraph/jpgraph_gantt.php";s:4:"role";s:4:"data";}}i:24;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"18dd18c6ce674612bb50bdbaa0960290";s:4:"name";s:32:"lib/jpgraph/jpgraph_gradient.php";s:4:"role";s:4:"data";}}i:25;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8a397569a05d63aed709cb494ab575cf";s:4:"name";s:32:"lib/jpgraph/jpgraph_iconplot.php";s:4:"role";s:4:"data";}}i:26;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"05b52d82829a8b02e1f1bb91adb4b8b7";s:4:"name";s:32:"lib/jpgraph/jpgraph_imgtrans.php";s:4:"role";s:4:"data";}}i:27;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"df06f860466ac04faa7686cde1517132";s:4:"name";s:28:"lib/jpgraph/jpgraph_line.php";s:4:"role";s:4:"data";}}i:28;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"60ebcf86439df2ee5807990d8c882156";s:4:"name";s:27:"lib/jpgraph/jpgraph_log.php";s:4:"role";s:4:"data";}}i:29;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b2f6eb4604f95222b16fcffe3bfaac97";s:4:"name";s:30:"lib/jpgraph/jpgraph_mgraph.php";s:4:"role";s:4:"data";}}i:30;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"14d19040c81de8d94fb5adcc36ee63c0";s:4:"name";s:27:"lib/jpgraph/jpgraph_pie.php";s:4:"role";s:4:"data";}}i:31;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f2db6bf4fa0bb9be0e13e629c2f16ff3";s:4:"name";s:29:"lib/jpgraph/jpgraph_pie3d.php";s:4:"role";s:4:"data";}}i:32;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e38dacfb211c032089a3c54b31105a58";s:4:"name";s:32:"lib/jpgraph/jpgraph_plotband.php";s:4:"role";s:4:"data";}}i:33;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fb3d81874ed5f89db47edde3d6753283";s:4:"name";s:36:"lib/jpgraph/jpgraph_plotmark.inc.php";s:4:"role";s:4:"data";}}i:34;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"991aa03b8758148b695cd4101b63080c";s:4:"name";s:29:"lib/jpgraph/jpgraph_polar.php";s:4:"role";s:4:"data";}}i:35;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7a86c2a34dd740deb1a1314c68c8ce01";s:4:"name";s:29:"lib/jpgraph/jpgraph_radar.php";s:4:"role";s:4:"data";}}i:36;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"205bdffdf46e55da7c9448e1c26d3646";s:4:"name";s:31:"lib/jpgraph/jpgraph_regstat.php";s:4:"role";s:4:"data";}}i:37;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c9c1b90ec47db1713857ba55ff4beb48";s:4:"name";s:31:"lib/jpgraph/jpgraph_scatter.php";s:4:"role";s:4:"data";}}i:38;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2b8e822ecce1f14d6f7393ea1ecb63e5";s:4:"name";s:29:"lib/jpgraph/jpgraph_stock.php";s:4:"role";s:4:"data";}}i:39;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c667ff321fab55b4d59783146fb43d8c";s:4:"name";s:19:"lib/jpgraph/QPL.txt";s:4:"role";s:4:"data";}}i:40;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0d40ab478c5b11b6c23836eab5eda368";s:4:"name";s:23:"lib/sfJpGraph.class.php";s:4:"role";s:4:"data";}}i:41;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"bf7134b9ce3489ca066cbeb28b1f1cbe";s:4:"name";s:49:"modules/dwJpgraphPlugin/actions/actions.class.php";s:4:"role";s:4:"data";}}i:42;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"741b8725ad47aa3e728214b119ea7ab9";s:4:"name";s:22:"test/sfJpGraphTest.php";s:4:"role";s:4:"data";}}i:43;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4e781e0e34e47a08b3a25701f11529fd";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:44;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d1a5a4c24611c325ba0a47ab03b10510";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.0.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:4:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.2.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:45:{s:27:"lib/jpgraph/lang/de.inc.php";a:4:{s:6:"md5sum";s:32:"422dfa08ec2462c2c1e372f2db4127d2";s:4:"name";s:27:"lib/jpgraph/lang/de.inc.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/lang/de.inc.php";}s:27:"lib/jpgraph/lang/en.inc.php";a:4:{s:6:"md5sum";s:32:"640a0d4973699a1eb2c5f9d262572268";s:4:"name";s:27:"lib/jpgraph/lang/en.inc.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/lang/en.inc.php";}s:29:"lib/jpgraph/lang/prod.inc.php";a:4:{s:6:"md5sum";s:32:"7e66c9313089392e26514bbbdea23fa2";s:4:"name";s:29:"lib/jpgraph/lang/prod.inc.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/lang/prod.inc.php";}s:21:"lib/jpgraph/flags.dat";a:4:{s:6:"md5sum";s:32:"058b2e8c37039f1281e1d33cdc98cc72";s:4:"name";s:21:"lib/jpgraph/flags.dat";s:4:"role";s:4:"data";s:12:"installed_as";s:82:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/flags.dat";}s:34:"lib/jpgraph/flags_thumb100x100.dat";a:4:{s:6:"md5sum";s:32:"efef598db76af8e4b9bc28167e68a22a";s:4:"name";s:34:"lib/jpgraph/flags_thumb100x100.dat";s:4:"role";s:4:"data";s:12:"installed_as";s:95:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb100x100.dat";}s:32:"lib/jpgraph/flags_thumb60x60.dat";a:4:{s:6:"md5sum";s:32:"d6da78161788f31a88214288eac51305";s:4:"name";s:32:"lib/jpgraph/flags_thumb60x60.dat";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb60x60.dat";}s:32:"lib/jpgraph/flags_thumb35x35.dat";a:4:{s:6:"md5sum";s:32:"1453ea849382b65101679db6ed5de68d";s:4:"name";s:32:"lib/jpgraph/flags_thumb35x35.dat";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb35x35.dat";}s:29:"lib/jpgraph/imgdata_balls.inc";a:4:{s:6:"md5sum";s:32:"42d020d4b425bc395572b5af3a11185f";s:4:"name";s:29:"lib/jpgraph/imgdata_balls.inc";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_balls.inc";}s:30:"lib/jpgraph/imgdata_bevels.inc";a:4:{s:6:"md5sum";s:32:"7a68759dbd3ef4979713571a9af90894";s:4:"name";s:30:"lib/jpgraph/imgdata_bevels.inc";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_bevels.inc";}s:32:"lib/jpgraph/imgdata_diamonds.inc";a:4:{s:6:"md5sum";s:32:"7623e758447d3b1b1e1d9a9c82d271cd";s:4:"name";s:32:"lib/jpgraph/imgdata_diamonds.inc";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_diamonds.inc";}s:32:"lib/jpgraph/imgdata_pushpins.inc";a:4:{s:6:"md5sum";s:32:"0ecc41313a07e5593fd288e58ce6a008";s:4:"name";s:32:"lib/jpgraph/imgdata_pushpins.inc";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_pushpins.inc";}s:29:"lib/jpgraph/imgdata_stars.inc";a:4:{s:6:"md5sum";s:32:"ca808c475e5085a9e388bee191579fbe";s:4:"name";s:29:"lib/jpgraph/imgdata_stars.inc";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_stars.inc";}s:30:"lib/jpgraph/jpg-config.inc.php";a:4:{s:6:"md5sum";s:32:"d72192c104ba3630ec4ec27771de75a5";s:4:"name";s:30:"lib/jpgraph/jpg-config.inc.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpg-config.inc.php";}s:23:"lib/jpgraph/jpgraph.php";a:4:{s:6:"md5sum";s:32:"cc55d5961c5c6f67b463a7543979909c";s:4:"name";s:23:"lib/jpgraph/jpgraph.php";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php";}s:32:"lib/jpgraph/jpgraph_antispam.php";a:4:{s:6:"md5sum";s:32:"1f73bdae39983a837d1e07b9f6a0e64e";s:4:"name";s:32:"lib/jpgraph/jpgraph_antispam.php";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam.php";}s:39:"lib/jpgraph/jpgraph_antispam-digits.php";a:4:{s:6:"md5sum";s:32:"72b4cd483dce5333ec6811c0f77d18d0";s:4:"name";s:39:"lib/jpgraph/jpgraph_antispam-digits.php";s:4:"role";s:4:"data";s:12:"installed_as";s:100:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam-digits.php";}s:27:"lib/jpgraph/jpgraph_bar.php";a:4:{s:6:"md5sum";s:32:"b3ae39dcc3f6038657075d9848f1b63a";s:4:"name";s:27:"lib/jpgraph/jpgraph_bar.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_bar.php";}s:30:"lib/jpgraph/jpgraph_canvas.php";a:4:{s:6:"md5sum";s:32:"dbc58f52de147f6843283b34207fb5cb";s:4:"name";s:30:"lib/jpgraph/jpgraph_canvas.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvas.php";}s:33:"lib/jpgraph/jpgraph_canvtools.php";a:4:{s:6:"md5sum";s:32:"8ae288c7f1860874815444c0fe701692";s:4:"name";s:33:"lib/jpgraph/jpgraph_canvtools.php";s:4:"role";s:4:"data";s:12:"installed_as";s:94:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvtools.php";}s:28:"lib/jpgraph/jpgraph_date.php";a:4:{s:6:"md5sum";s:32:"09d141a116c1a5bbabff0cdd98bc6078";s:4:"name";s:28:"lib/jpgraph/jpgraph_date.php";s:4:"role";s:4:"data";s:12:"installed_as";s:89:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_date.php";}s:29:"lib/jpgraph/jpgraph_error.php";a:4:{s:6:"md5sum";s:32:"e760326116173403b3f46359434afcd4";s:4:"name";s:29:"lib/jpgraph/jpgraph_error.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_error.php";}s:38:"lib/jpgraph/jpgraph_errhandler.inc.php";a:4:{s:6:"md5sum";s:32:"3da2db1a213028bd420e762b53c27b45";s:4:"name";s:38:"lib/jpgraph/jpgraph_errhandler.inc.php";s:4:"role";s:4:"data";s:12:"installed_as";s:99:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_errhandler.inc.php";}s:29:"lib/jpgraph/jpgraph_flags.php";a:4:{s:6:"md5sum";s:32:"7d1f4a5d71de4a85a43c05e8ca963667";s:4:"name";s:29:"lib/jpgraph/jpgraph_flags.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_flags.php";}s:29:"lib/jpgraph/jpgraph_gantt.php";a:4:{s:6:"md5sum";s:32:"92f471b733093b0801d86e5fb1ec8c6e";s:4:"name";s:29:"lib/jpgraph/jpgraph_gantt.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php";}s:32:"lib/jpgraph/jpgraph_gradient.php";a:4:{s:6:"md5sum";s:32:"18dd18c6ce674612bb50bdbaa0960290";s:4:"name";s:32:"lib/jpgraph/jpgraph_gradient.php";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gradient.php";}s:32:"lib/jpgraph/jpgraph_iconplot.php";a:4:{s:6:"md5sum";s:32:"8a397569a05d63aed709cb494ab575cf";s:4:"name";s:32:"lib/jpgraph/jpgraph_iconplot.php";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_iconplot.php";}s:32:"lib/jpgraph/jpgraph_imgtrans.php";a:4:{s:6:"md5sum";s:32:"05b52d82829a8b02e1f1bb91adb4b8b7";s:4:"name";s:32:"lib/jpgraph/jpgraph_imgtrans.php";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_imgtrans.php";}s:28:"lib/jpgraph/jpgraph_line.php";a:4:{s:6:"md5sum";s:32:"df06f860466ac04faa7686cde1517132";s:4:"name";s:28:"lib/jpgraph/jpgraph_line.php";s:4:"role";s:4:"data";s:12:"installed_as";s:89:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_line.php";}s:27:"lib/jpgraph/jpgraph_log.php";a:4:{s:6:"md5sum";s:32:"60ebcf86439df2ee5807990d8c882156";s:4:"name";s:27:"lib/jpgraph/jpgraph_log.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_log.php";}s:30:"lib/jpgraph/jpgraph_mgraph.php";a:4:{s:6:"md5sum";s:32:"b2f6eb4604f95222b16fcffe3bfaac97";s:4:"name";s:30:"lib/jpgraph/jpgraph_mgraph.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_mgraph.php";}s:27:"lib/jpgraph/jpgraph_pie.php";a:4:{s:6:"md5sum";s:32:"14d19040c81de8d94fb5adcc36ee63c0";s:4:"name";s:27:"lib/jpgraph/jpgraph_pie.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie.php";}s:29:"lib/jpgraph/jpgraph_pie3d.php";a:4:{s:6:"md5sum";s:32:"f2db6bf4fa0bb9be0e13e629c2f16ff3";s:4:"name";s:29:"lib/jpgraph/jpgraph_pie3d.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie3d.php";}s:32:"lib/jpgraph/jpgraph_plotband.php";a:4:{s:6:"md5sum";s:32:"e38dacfb211c032089a3c54b31105a58";s:4:"name";s:32:"lib/jpgraph/jpgraph_plotband.php";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php";}s:36:"lib/jpgraph/jpgraph_plotmark.inc.php";a:4:{s:6:"md5sum";s:32:"fb3d81874ed5f89db47edde3d6753283";s:4:"name";s:36:"lib/jpgraph/jpgraph_plotmark.inc.php";s:4:"role";s:4:"data";s:12:"installed_as";s:97:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotmark.inc.php";}s:29:"lib/jpgraph/jpgraph_polar.php";a:4:{s:6:"md5sum";s:32:"991aa03b8758148b695cd4101b63080c";s:4:"name";s:29:"lib/jpgraph/jpgraph_polar.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php";}s:29:"lib/jpgraph/jpgraph_radar.php";a:4:{s:6:"md5sum";s:32:"7a86c2a34dd740deb1a1314c68c8ce01";s:4:"name";s:29:"lib/jpgraph/jpgraph_radar.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php";}s:31:"lib/jpgraph/jpgraph_regstat.php";a:4:{s:6:"md5sum";s:32:"205bdffdf46e55da7c9448e1c26d3646";s:4:"name";s:31:"lib/jpgraph/jpgraph_regstat.php";s:4:"role";s:4:"data";s:12:"installed_as";s:92:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_regstat.php";}s:31:"lib/jpgraph/jpgraph_scatter.php";a:4:{s:6:"md5sum";s:32:"c9c1b90ec47db1713857ba55ff4beb48";s:4:"name";s:31:"lib/jpgraph/jpgraph_scatter.php";s:4:"role";s:4:"data";s:12:"installed_as";s:92:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_scatter.php";}s:29:"lib/jpgraph/jpgraph_stock.php";a:4:{s:6:"md5sum";s:32:"2b8e822ecce1f14d6f7393ea1ecb63e5";s:4:"name";s:29:"lib/jpgraph/jpgraph_stock.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_stock.php";}s:19:"lib/jpgraph/QPL.txt";a:4:{s:6:"md5sum";s:32:"c667ff321fab55b4d59783146fb43d8c";s:4:"name";s:19:"lib/jpgraph/QPL.txt";s:4:"role";s:4:"data";s:12:"installed_as";s:80:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/QPL.txt";}s:23:"lib/sfJpGraph.class.php";a:4:{s:6:"md5sum";s:32:"0d40ab478c5b11b6c23836eab5eda368";s:4:"name";s:23:"lib/sfJpGraph.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/sfJpGraph.class.php";}s:49:"modules/dwJpgraphPlugin/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"bf7134b9ce3489ca066cbeb28b1f1cbe";s:4:"name";s:49:"modules/dwJpgraphPlugin/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:110:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/modules/dwJpgraphPlugin/actions/actions.class.php";}s:22:"test/sfJpGraphTest.php";a:4:{s:6:"md5sum";s:32:"741b8725ad47aa3e728214b119ea7ab9";s:4:"name";s:22:"test/sfJpGraphTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/test/sfJpGraphTest.php";}s:6:"README";a:4:{s:6:"md5sum";s:32:"4e781e0e34e47a08b3a25701f11529fd";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:67:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"d1a5a4c24611c325ba0a47ab03b10510";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:68:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:8:{s:77:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph/lang";b:1;s:72:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib/jpgraph";b:1;s:64:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/lib";b:1;s:92:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/modules/dwJpgraphPlugin/actions";b:1;s:84:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/modules/dwJpgraphPlugin";b:1;s:68:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/modules";b:1;s:65:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin/test";b:1;s:60:"/crypto/home/russ/sfprojects/reaktor/plugins/dwJpgraphPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.0.1";s:12:"release_date";s:10:"2008-03-14";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.0.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.2.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:14:"Dustin Whittle";s:5:"email";s:34:"dustin.whittle@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:8:"dwhittle";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1214476886;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sffeed2plugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sffeed2plugin.reg new file mode 100644 index 0000000..b2d8e89 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sffeed2plugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.5.1";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:13:"sfFeed2Plugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:42:"Feed manager for reading and writing feeds";s:11:"description";s:244:"The sfFeed2Plugin offers an object interface for feeds and feed items, feed input methods using a web feed or an array of objects as source, and feed output methods for displaying items on a page and serving feeds through a symfony application.";s:4:"lead";a:4:{s:4:"name";s:19:"François Zaninotto";s:4:"user";s:10:"fzaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-04-15";s:4:"time";s:8:"21:27:56";s:7:"version";a:2:{s:7:"release";s:5:"0.9.4";s:3:"api";s:5:"0.9.4";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:11:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f292ac47af0366949c677925c315a540";s:4:"name";s:20:"lib/sfFeed.class.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5f4c0c79f5ae72698c563097d6862e61";s:4:"name";s:24:"lib/sfFeedItem.class.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a6032452940f66caa289eaa908b2f691";s:4:"name";s:29:"lib/sfFeedEnclosure.class.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7ec6995fdf4c4ee133ad6e53c8d9adf8";s:4:"name";s:25:"lib/sfAtom1Feed.class.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"262b8218dbca3d361f382976933c0a64";s:4:"name";s:23:"lib/sfRssFeed.class.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d88bfc353aae15567644541ad402f9b6";s:4:"name";s:26:"lib/sfRss201Feed.class.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f9617693cf2880d1dc690a8fd1cd10e0";s:4:"name";s:26:"lib/sfRss091Feed.class.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a6ee0ba1d3e96517a67a174303ff96ff";s:4:"name";s:25:"lib/sfRss10Feed.class.php";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fd474d6e18469b42a4d3174fdccf52db";s:4:"name";s:24:"lib/sfFeedPeer.class.php";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f8044acbf13bc8e6e9cc3ef2d7448d16";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"feca6d513f7eadaf6002fe0b62c629c3";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.1.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:4:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"0.8.1";s:3:"max";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:11:{s:20:"lib/sfFeed.class.php";a:4:{s:6:"md5sum";s:32:"f292ac47af0366949c677925c315a540";s:4:"name";s:20:"lib/sfFeed.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfFeed.class.php";}s:24:"lib/sfFeedItem.class.php";a:4:{s:6:"md5sum";s:32:"5f4c0c79f5ae72698c563097d6862e61";s:4:"name";s:24:"lib/sfFeedItem.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfFeedItem.class.php";}s:29:"lib/sfFeedEnclosure.class.php";a:4:{s:6:"md5sum";s:32:"a6032452940f66caa289eaa908b2f691";s:4:"name";s:29:"lib/sfFeedEnclosure.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfFeedEnclosure.class.php";}s:25:"lib/sfAtom1Feed.class.php";a:4:{s:6:"md5sum";s:32:"7ec6995fdf4c4ee133ad6e53c8d9adf8";s:4:"name";s:25:"lib/sfAtom1Feed.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfAtom1Feed.class.php";}s:23:"lib/sfRssFeed.class.php";a:4:{s:6:"md5sum";s:32:"262b8218dbca3d361f382976933c0a64";s:4:"name";s:23:"lib/sfRssFeed.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:82:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfRssFeed.class.php";}s:26:"lib/sfRss201Feed.class.php";a:4:{s:6:"md5sum";s:32:"d88bfc353aae15567644541ad402f9b6";s:4:"name";s:26:"lib/sfRss201Feed.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:85:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfRss201Feed.class.php";}s:26:"lib/sfRss091Feed.class.php";a:4:{s:6:"md5sum";s:32:"f9617693cf2880d1dc690a8fd1cd10e0";s:4:"name";s:26:"lib/sfRss091Feed.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:85:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfRss091Feed.class.php";}s:25:"lib/sfRss10Feed.class.php";a:4:{s:6:"md5sum";s:32:"a6ee0ba1d3e96517a67a174303ff96ff";s:4:"name";s:25:"lib/sfRss10Feed.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfRss10Feed.class.php";}s:24:"lib/sfFeedPeer.class.php";a:4:{s:6:"md5sum";s:32:"fd474d6e18469b42a4d3174fdccf52db";s:4:"name";s:24:"lib/sfFeedPeer.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib/sfFeedPeer.class.php";}s:6:"README";a:4:{s:6:"md5sum";s:32:"f8044acbf13bc8e6e9cc3ef2d7448d16";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:65:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"feca6d513f7eadaf6002fe0b62c629c3";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:66:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:2:{s:62:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin/lib";b:1;s:58:"/crypto/home/russ/sfprojects/reaktor/plugins/sfFeed2Plugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"0.9.4";s:12:"release_date";s:10:"2007-04-15";s:13:"release_state";s:4:"beta";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.1.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"0.8.1";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:19:"François Zaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:10:"fzaninotto";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1212592758;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfguardplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfguardplugin.reg new file mode 100644 index 0000000..9d761c9 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfguardplugin.reg @@ -0,0 +1 @@ +a:23:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.6.2";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:13:"sfGuardPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:27:"Identity management plugin.";s:11:"description";s:27:"Identity management plugin.";s:4:"lead";a:3:{i:0;a:4:{s:4:"name";s:16:"Fabien POTENCIER";s:4:"user";s:6:"fabpot";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";}i:1;a:4:{s:4:"name";s:11:"Jason IBELE";s:4:"user";s:6:"draven";s:5:"email";s:0:"";s:6:"active";s:3:"yes";}i:2;a:4:{s:4:"name";s:9:"Dave DASH";s:4:"user";s:8:"davedash";s:5:"email";s:23:"dd-symfony@davedash.com";s:6:"active";s:3:"yes";}}s:9:"developer";a:4:{s:4:"name";s:18:"Francois Zaninotto";s:4:"user";s:10:"fzaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-11-14";s:4:"time";s:8:"12:19:09";s:7:"version";a:2:{s:7:"release";s:6:"1.1.13";s:3:"api";s:5:"1.1.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:55:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ab282c8b4720c527a8417b16055d21d1";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d0757bcfa1d181e1ca3a19f020fd3449";s:4:"name";s:17:"config/schema.yml";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0105fe20c2763f75e32e8e961f31128c";s:4:"name";s:26:"data/fixtures/fixtures.yml";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f7619f7c853063841490e319cb970c77";s:4:"name";s:36:"data/tasks/sfGuardSuperAdminTask.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"eb8c2971c4e78853ed160582cbd1fdad";s:4:"name";s:39:"lib/model/plugin/PluginsfGuardGroup.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"463dbb33baa17e8206d7cf2c67cad586";s:4:"name";s:43:"lib/model/plugin/PluginsfGuardGroupPeer.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"96b2c9a808d98a62ec319a98ec18f7a3";s:4:"name";s:49:"lib/model/plugin/PluginsfGuardGroupPermission.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a27015ffe3c4ee6941768ab81b905ccc";s:4:"name";s:53:"lib/model/plugin/PluginsfGuardGroupPermissionPeer.php";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0a7d8f0a8a44fda33137ff0ceebca28d";s:4:"name";s:44:"lib/model/plugin/PluginsfGuardPermission.php";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9777aac874f8ab3e6b8f211e8ebfadb0";s:4:"name";s:48:"lib/model/plugin/PluginsfGuardPermissionPeer.php";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f033a65c9a4e96b6cb83df254a34dea1";s:4:"name";s:38:"lib/model/plugin/PluginsfGuardUser.php";s:4:"role";s:4:"data";}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f175fd14bca0cf111472416c46d27187";s:4:"name";s:42:"lib/model/plugin/PluginsfGuardUserPeer.php";s:4:"role";s:4:"data";}}i:12;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f391da116c782d0b6228938080233fa7";s:4:"name";s:43:"lib/model/plugin/PluginsfGuardUserGroup.php";s:4:"role";s:4:"data";}}i:13;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"06a5f1f1e244fc4314ba8f2a04ecdf05";s:4:"name";s:47:"lib/model/plugin/PluginsfGuardUserGroupPeer.php";s:4:"role";s:4:"data";}}i:14;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"bbce776d40aa48cf43c42a7fa3af5cd8";s:4:"name";s:48:"lib/model/plugin/PluginsfGuardUserPermission.php";s:4:"role";s:4:"data";}}i:15;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1921bb69ab4ca42df3fd0010e4044bd3";s:4:"name";s:52:"lib/model/plugin/PluginsfGuardUserPermissionPeer.php";s:4:"role";s:4:"data";}}i:16;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d6a73c6835391c6288041557c2f7af13";s:4:"name";s:45:"lib/model/plugin/PluginsfGuardRememberKey.php";s:4:"role";s:4:"data";}}i:17;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4dd4228ec71a9c44c762f975602e8d72";s:4:"name";s:49:"lib/model/plugin/PluginsfGuardRememberKeyPeer.php";s:4:"role";s:4:"data";}}i:18;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9245d43219014e6441f127fa5d47c8a5";s:4:"name";s:26:"lib/model/sfGuardGroup.php";s:4:"role";s:4:"data";}}i:19;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8a5c30e0fb4fded9573f246942a992e3";s:4:"name";s:30:"lib/model/sfGuardGroupPeer.php";s:4:"role";s:4:"data";}}i:20;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7f681003ad4578e9b4186043a15949e6";s:4:"name";s:36:"lib/model/sfGuardGroupPermission.php";s:4:"role";s:4:"data";}}i:21;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3c57b7d02efdf09b0a483e1b8e550c36";s:4:"name";s:40:"lib/model/sfGuardGroupPermissionPeer.php";s:4:"role";s:4:"data";}}i:22;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"70c384d3059e3c3322cf4b19dda8ea0b";s:4:"name";s:31:"lib/model/sfGuardPermission.php";s:4:"role";s:4:"data";}}i:23;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7e3c874ec581e31804e17d22e046bde5";s:4:"name";s:35:"lib/model/sfGuardPermissionPeer.php";s:4:"role";s:4:"data";}}i:24;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1c419a9f35bb8c25225c2d90b5b4c540";s:4:"name";s:25:"lib/model/sfGuardUser.php";s:4:"role";s:4:"data";}}i:25;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1db6b7b87d3fc60188fba71e68160004";s:4:"name";s:29:"lib/model/sfGuardUserPeer.php";s:4:"role";s:4:"data";}}i:26;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f85105e667baac09b06ccb4352efb5fb";s:4:"name";s:30:"lib/model/sfGuardUserGroup.php";s:4:"role";s:4:"data";}}i:27;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"eb48db623592137cc84654c4ab259bf2";s:4:"name";s:34:"lib/model/sfGuardUserGroupPeer.php";s:4:"role";s:4:"data";}}i:28;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3e3e45f6694d8c97f7a32fa2340afaaa";s:4:"name";s:35:"lib/model/sfGuardUserPermission.php";s:4:"role";s:4:"data";}}i:29;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"eccc9e2abdeeac011ad730e858031447";s:4:"name";s:39:"lib/model/sfGuardUserPermissionPeer.php";s:4:"role";s:4:"data";}}i:30;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3ecbe2a03ccf2c359b37272744698d8a";s:4:"name";s:32:"lib/model/sfGuardRememberKey.php";s:4:"role";s:4:"data";}}i:31;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9a755193ff8dde84129fb5609c3e4741";s:4:"name";s:36:"lib/model/sfGuardRememberKeyPeer.php";s:4:"role";s:4:"data";}}i:32;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e48959a0aaeb57af4f1f7d330fa2f0b9";s:4:"name";s:38:"lib/user/sfGuardSecurityUser.class.php";s:4:"role";s:4:"data";}}i:33;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"84b07a43dace53a9071c4c8363c78a0b";s:4:"name";s:44:"lib/validator/sfGuardUserValidator.class.php";s:4:"role";s:4:"data";}}i:34;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9ba11d48da1f695e6b6e98602475296f";s:4:"name";s:40:"lib/sfGuardBasicSecurityFilter.class.php";s:4:"role";s:4:"data";}}i:35;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9ff03d75726c449c903b97e45a8c6fc5";s:4:"name";s:45:"modules/sfGuardAuth/actions/actions.class.php";s:4:"role";s:4:"data";}}i:36;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"511d361ba246118e1e7a02fa91a27d3b";s:4:"name";s:39:"modules/sfGuardAuth/config/security.yml";s:4:"role";s:4:"data";}}i:37;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"bc01750406118f1a7cce64f6846e5224";s:4:"name";s:56:"modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php";s:4:"role";s:4:"data";}}i:38;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"274eec84f3e99ea1aa078418dffae554";s:4:"name";s:47:"modules/sfGuardAuth/templates/secureSuccess.php";s:4:"role";s:4:"data";}}i:39;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9d1da4fca5ef77d77e011f373f6f13f7";s:4:"name";s:47:"modules/sfGuardAuth/templates/signinSuccess.php";s:4:"role";s:4:"data";}}i:40;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"583668a0732d28846ad353cfcfebc0b5";s:4:"name";s:39:"modules/sfGuardAuth/validate/signin.yml";s:4:"role";s:4:"data";}}i:41;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2bf9475ca596dc6089698e3131af98b8";s:4:"name";s:46:"modules/sfGuardGroup/actions/actions.class.php";s:4:"role";s:4:"data";}}i:42;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d010d0866c5f98497fe440a5bbcd115a";s:4:"name";s:41:"modules/sfGuardGroup/config/generator.yml";s:4:"role";s:4:"data";}}i:43;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9bddc16cc60a11aa4572478b62c303e3";s:4:"name";s:38:"modules/sfGuardGroup/validate/edit.yml";s:4:"role";s:4:"data";}}i:44;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"79d2d16acf565e3532f5aab0334210ef";s:4:"name";s:51:"modules/sfGuardPermission/actions/actions.class.php";s:4:"role";s:4:"data";}}i:45;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fecb15383c341560c25ca96c44ad6e68";s:4:"name";s:46:"modules/sfGuardPermission/config/generator.yml";s:4:"role";s:4:"data";}}i:46;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"725219ec00157d35b97b760fe8ab0c60";s:4:"name";s:43:"modules/sfGuardPermission/validate/edit.yml";s:4:"role";s:4:"data";}}i:47;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a41087e2c360c94c75f34a6a163e044e";s:4:"name";s:45:"modules/sfGuardUser/actions/actions.class.php";s:4:"role";s:4:"data";}}i:48;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"901f22dca5ecdd2fc28ba8cb1c385dc1";s:4:"name";s:40:"modules/sfGuardUser/config/generator.yml";s:4:"role";s:4:"data";}}i:49;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"029bf12a3be5ac560f1d9c0511350b19";s:4:"name";s:56:"modules/sfGuardUser/lib/BasesfGuardUserActions.class.php";s:4:"role";s:4:"data";}}i:50;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f6e893173f92c83a6af48f227259e114";s:4:"name";s:43:"modules/sfGuardUser/templates/_password.php";s:4:"role";s:4:"data";}}i:51;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"43d049c62485645065697f2ae098777c";s:4:"name";s:47:"modules/sfGuardUser/templates/_password_bis.php";s:4:"role";s:4:"data";}}i:52;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"aa213f724f25d2a367b184bc9fdd36d1";s:4:"name";s:37:"modules/sfGuardUser/validate/edit.yml";s:4:"role";s:4:"data";}}i:53;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3f891a0cb755d820b08e2639f002c6ae";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:54;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c0ab88a4687e9ff8e0fb6c95ca49ed74";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.0.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:55:{s:17:"config/config.php";a:4:{s:6:"md5sum";s:32:"ab282c8b4720c527a8417b16055d21d1";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";s:12:"installed_as";s:52:"/opt/reaktor/plugins/sfGuardPlugin/config/config.php";}s:17:"config/schema.yml";a:4:{s:6:"md5sum";s:32:"d0757bcfa1d181e1ca3a19f020fd3449";s:4:"name";s:17:"config/schema.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:52:"/opt/reaktor/plugins/sfGuardPlugin/config/schema.yml";}s:26:"data/fixtures/fixtures.yml";a:4:{s:6:"md5sum";s:32:"0105fe20c2763f75e32e8e961f31128c";s:4:"name";s:26:"data/fixtures/fixtures.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:61:"/opt/reaktor/plugins/sfGuardPlugin/data/fixtures/fixtures.yml";}s:36:"data/tasks/sfGuardSuperAdminTask.php";a:4:{s:6:"md5sum";s:32:"f7619f7c853063841490e319cb970c77";s:4:"name";s:36:"data/tasks/sfGuardSuperAdminTask.php";s:4:"role";s:4:"data";s:12:"installed_as";s:71:"/opt/reaktor/plugins/sfGuardPlugin/data/tasks/sfGuardSuperAdminTask.php";}s:39:"lib/model/plugin/PluginsfGuardGroup.php";a:4:{s:6:"md5sum";s:32:"eb8c2971c4e78853ed160582cbd1fdad";s:4:"name";s:39:"lib/model/plugin/PluginsfGuardGroup.php";s:4:"role";s:4:"data";s:12:"installed_as";s:74:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroup.php";}s:43:"lib/model/plugin/PluginsfGuardGroupPeer.php";a:4:{s:6:"md5sum";s:32:"463dbb33baa17e8206d7cf2c67cad586";s:4:"name";s:43:"lib/model/plugin/PluginsfGuardGroupPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:78:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPeer.php";}s:49:"lib/model/plugin/PluginsfGuardGroupPermission.php";a:4:{s:6:"md5sum";s:32:"96b2c9a808d98a62ec319a98ec18f7a3";s:4:"name";s:49:"lib/model/plugin/PluginsfGuardGroupPermission.php";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermission.php";}s:53:"lib/model/plugin/PluginsfGuardGroupPermissionPeer.php";a:4:{s:6:"md5sum";s:32:"a27015ffe3c4ee6941768ab81b905ccc";s:4:"name";s:53:"lib/model/plugin/PluginsfGuardGroupPermissionPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermissionPeer.php";}s:44:"lib/model/plugin/PluginsfGuardPermission.php";a:4:{s:6:"md5sum";s:32:"0a7d8f0a8a44fda33137ff0ceebca28d";s:4:"name";s:44:"lib/model/plugin/PluginsfGuardPermission.php";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermission.php";}s:48:"lib/model/plugin/PluginsfGuardPermissionPeer.php";a:4:{s:6:"md5sum";s:32:"9777aac874f8ab3e6b8f211e8ebfadb0";s:4:"name";s:48:"lib/model/plugin/PluginsfGuardPermissionPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermissionPeer.php";}s:38:"lib/model/plugin/PluginsfGuardUser.php";a:4:{s:6:"md5sum";s:32:"f033a65c9a4e96b6cb83df254a34dea1";s:4:"name";s:38:"lib/model/plugin/PluginsfGuardUser.php";s:4:"role";s:4:"data";s:12:"installed_as";s:73:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUser.php";}s:42:"lib/model/plugin/PluginsfGuardUserPeer.php";a:4:{s:6:"md5sum";s:32:"f175fd14bca0cf111472416c46d27187";s:4:"name";s:42:"lib/model/plugin/PluginsfGuardUserPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:77:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPeer.php";}s:43:"lib/model/plugin/PluginsfGuardUserGroup.php";a:4:{s:6:"md5sum";s:32:"f391da116c782d0b6228938080233fa7";s:4:"name";s:43:"lib/model/plugin/PluginsfGuardUserGroup.php";s:4:"role";s:4:"data";s:12:"installed_as";s:78:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroup.php";}s:47:"lib/model/plugin/PluginsfGuardUserGroupPeer.php";a:4:{s:6:"md5sum";s:32:"06a5f1f1e244fc4314ba8f2a04ecdf05";s:4:"name";s:47:"lib/model/plugin/PluginsfGuardUserGroupPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:82:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroupPeer.php";}s:48:"lib/model/plugin/PluginsfGuardUserPermission.php";a:4:{s:6:"md5sum";s:32:"bbce776d40aa48cf43c42a7fa3af5cd8";s:4:"name";s:48:"lib/model/plugin/PluginsfGuardUserPermission.php";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermission.php";}s:52:"lib/model/plugin/PluginsfGuardUserPermissionPeer.php";a:4:{s:6:"md5sum";s:32:"1921bb69ab4ca42df3fd0010e4044bd3";s:4:"name";s:52:"lib/model/plugin/PluginsfGuardUserPermissionPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:87:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermissionPeer.php";}s:45:"lib/model/plugin/PluginsfGuardRememberKey.php";a:4:{s:6:"md5sum";s:32:"d6a73c6835391c6288041557c2f7af13";s:4:"name";s:45:"lib/model/plugin/PluginsfGuardRememberKey.php";s:4:"role";s:4:"data";s:12:"installed_as";s:80:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKey.php";}s:49:"lib/model/plugin/PluginsfGuardRememberKeyPeer.php";a:4:{s:6:"md5sum";s:32:"4dd4228ec71a9c44c762f975602e8d72";s:4:"name";s:49:"lib/model/plugin/PluginsfGuardRememberKeyPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKeyPeer.php";}s:26:"lib/model/sfGuardGroup.php";a:4:{s:6:"md5sum";s:32:"9245d43219014e6441f127fa5d47c8a5";s:4:"name";s:26:"lib/model/sfGuardGroup.php";s:4:"role";s:4:"data";s:12:"installed_as";s:61:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardGroup.php";}s:30:"lib/model/sfGuardGroupPeer.php";a:4:{s:6:"md5sum";s:32:"8a5c30e0fb4fded9573f246942a992e3";s:4:"name";s:30:"lib/model/sfGuardGroupPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:65:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardGroupPeer.php";}s:36:"lib/model/sfGuardGroupPermission.php";a:4:{s:6:"md5sum";s:32:"7f681003ad4578e9b4186043a15949e6";s:4:"name";s:36:"lib/model/sfGuardGroupPermission.php";s:4:"role";s:4:"data";s:12:"installed_as";s:71:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermission.php";}s:40:"lib/model/sfGuardGroupPermissionPeer.php";a:4:{s:6:"md5sum";s:32:"3c57b7d02efdf09b0a483e1b8e550c36";s:4:"name";s:40:"lib/model/sfGuardGroupPermissionPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:75:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermissionPeer.php";}s:31:"lib/model/sfGuardPermission.php";a:4:{s:6:"md5sum";s:32:"70c384d3059e3c3322cf4b19dda8ea0b";s:4:"name";s:31:"lib/model/sfGuardPermission.php";s:4:"role";s:4:"data";s:12:"installed_as";s:66:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardPermission.php";}s:35:"lib/model/sfGuardPermissionPeer.php";a:4:{s:6:"md5sum";s:32:"7e3c874ec581e31804e17d22e046bde5";s:4:"name";s:35:"lib/model/sfGuardPermissionPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:70:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardPermissionPeer.php";}s:25:"lib/model/sfGuardUser.php";a:4:{s:6:"md5sum";s:32:"1c419a9f35bb8c25225c2d90b5b4c540";s:4:"name";s:25:"lib/model/sfGuardUser.php";s:4:"role";s:4:"data";s:12:"installed_as";s:60:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardUser.php";}s:29:"lib/model/sfGuardUserPeer.php";a:4:{s:6:"md5sum";s:32:"1db6b7b87d3fc60188fba71e68160004";s:4:"name";s:29:"lib/model/sfGuardUserPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:64:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardUserPeer.php";}s:30:"lib/model/sfGuardUserGroup.php";a:4:{s:6:"md5sum";s:32:"f85105e667baac09b06ccb4352efb5fb";s:4:"name";s:30:"lib/model/sfGuardUserGroup.php";s:4:"role";s:4:"data";s:12:"installed_as";s:65:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardUserGroup.php";}s:34:"lib/model/sfGuardUserGroupPeer.php";a:4:{s:6:"md5sum";s:32:"eb48db623592137cc84654c4ab259bf2";s:4:"name";s:34:"lib/model/sfGuardUserGroupPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:69:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardUserGroupPeer.php";}s:35:"lib/model/sfGuardUserPermission.php";a:4:{s:6:"md5sum";s:32:"3e3e45f6694d8c97f7a32fa2340afaaa";s:4:"name";s:35:"lib/model/sfGuardUserPermission.php";s:4:"role";s:4:"data";s:12:"installed_as";s:70:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardUserPermission.php";}s:39:"lib/model/sfGuardUserPermissionPeer.php";a:4:{s:6:"md5sum";s:32:"eccc9e2abdeeac011ad730e858031447";s:4:"name";s:39:"lib/model/sfGuardUserPermissionPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:74:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardUserPermissionPeer.php";}s:32:"lib/model/sfGuardRememberKey.php";a:4:{s:6:"md5sum";s:32:"3ecbe2a03ccf2c359b37272744698d8a";s:4:"name";s:32:"lib/model/sfGuardRememberKey.php";s:4:"role";s:4:"data";s:12:"installed_as";s:67:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardRememberKey.php";}s:36:"lib/model/sfGuardRememberKeyPeer.php";a:4:{s:6:"md5sum";s:32:"9a755193ff8dde84129fb5609c3e4741";s:4:"name";s:36:"lib/model/sfGuardRememberKeyPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:71:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/sfGuardRememberKeyPeer.php";}s:38:"lib/user/sfGuardSecurityUser.class.php";a:4:{s:6:"md5sum";s:32:"e48959a0aaeb57af4f1f7d330fa2f0b9";s:4:"name";s:38:"lib/user/sfGuardSecurityUser.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:73:"/opt/reaktor/plugins/sfGuardPlugin/lib/user/sfGuardSecurityUser.class.php";}s:44:"lib/validator/sfGuardUserValidator.class.php";a:4:{s:6:"md5sum";s:32:"84b07a43dace53a9071c4c8363c78a0b";s:4:"name";s:44:"lib/validator/sfGuardUserValidator.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"/opt/reaktor/plugins/sfGuardPlugin/lib/validator/sfGuardUserValidator.class.php";}s:40:"lib/sfGuardBasicSecurityFilter.class.php";a:4:{s:6:"md5sum";s:32:"9ba11d48da1f695e6b6e98602475296f";s:4:"name";s:40:"lib/sfGuardBasicSecurityFilter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:75:"/opt/reaktor/plugins/sfGuardPlugin/lib/sfGuardBasicSecurityFilter.class.php";}s:45:"modules/sfGuardAuth/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"9ff03d75726c449c903b97e45a8c6fc5";s:4:"name";s:45:"modules/sfGuardAuth/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:80:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/actions/actions.class.php";}s:39:"modules/sfGuardAuth/config/security.yml";a:4:{s:6:"md5sum";s:32:"511d361ba246118e1e7a02fa91a27d3b";s:4:"name";s:39:"modules/sfGuardAuth/config/security.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:74:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/config/security.yml";}s:56:"modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php";a:4:{s:6:"md5sum";s:32:"bc01750406118f1a7cce64f6846e5224";s:4:"name";s:56:"modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php";}s:47:"modules/sfGuardAuth/templates/secureSuccess.php";a:4:{s:6:"md5sum";s:32:"274eec84f3e99ea1aa078418dffae554";s:4:"name";s:47:"modules/sfGuardAuth/templates/secureSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:82:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/templates/secureSuccess.php";}s:47:"modules/sfGuardAuth/templates/signinSuccess.php";a:4:{s:6:"md5sum";s:32:"9d1da4fca5ef77d77e011f373f6f13f7";s:4:"name";s:47:"modules/sfGuardAuth/templates/signinSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:82:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/templates/signinSuccess.php";}s:39:"modules/sfGuardAuth/validate/signin.yml";a:4:{s:6:"md5sum";s:32:"583668a0732d28846ad353cfcfebc0b5";s:4:"name";s:39:"modules/sfGuardAuth/validate/signin.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:74:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/validate/signin.yml";}s:46:"modules/sfGuardGroup/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"2bf9475ca596dc6089698e3131af98b8";s:4:"name";s:46:"modules/sfGuardGroup/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:81:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardGroup/actions/actions.class.php";}s:41:"modules/sfGuardGroup/config/generator.yml";a:4:{s:6:"md5sum";s:32:"d010d0866c5f98497fe440a5bbcd115a";s:4:"name";s:41:"modules/sfGuardGroup/config/generator.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:76:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardGroup/config/generator.yml";}s:38:"modules/sfGuardGroup/validate/edit.yml";a:4:{s:6:"md5sum";s:32:"9bddc16cc60a11aa4572478b62c303e3";s:4:"name";s:38:"modules/sfGuardGroup/validate/edit.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:73:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardGroup/validate/edit.yml";}s:51:"modules/sfGuardPermission/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"79d2d16acf565e3532f5aab0334210ef";s:4:"name";s:51:"modules/sfGuardPermission/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:86:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardPermission/actions/actions.class.php";}s:46:"modules/sfGuardPermission/config/generator.yml";a:4:{s:6:"md5sum";s:32:"fecb15383c341560c25ca96c44ad6e68";s:4:"name";s:46:"modules/sfGuardPermission/config/generator.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:81:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardPermission/config/generator.yml";}s:43:"modules/sfGuardPermission/validate/edit.yml";a:4:{s:6:"md5sum";s:32:"725219ec00157d35b97b760fe8ab0c60";s:4:"name";s:43:"modules/sfGuardPermission/validate/edit.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:78:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardPermission/validate/edit.yml";}s:45:"modules/sfGuardUser/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"a41087e2c360c94c75f34a6a163e044e";s:4:"name";s:45:"modules/sfGuardUser/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:80:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/actions/actions.class.php";}s:40:"modules/sfGuardUser/config/generator.yml";a:4:{s:6:"md5sum";s:32:"901f22dca5ecdd2fc28ba8cb1c385dc1";s:4:"name";s:40:"modules/sfGuardUser/config/generator.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:75:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/config/generator.yml";}s:56:"modules/sfGuardUser/lib/BasesfGuardUserActions.class.php";a:4:{s:6:"md5sum";s:32:"029bf12a3be5ac560f1d9c0511350b19";s:4:"name";s:56:"modules/sfGuardUser/lib/BasesfGuardUserActions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php";}s:43:"modules/sfGuardUser/templates/_password.php";a:4:{s:6:"md5sum";s:32:"f6e893173f92c83a6af48f227259e114";s:4:"name";s:43:"modules/sfGuardUser/templates/_password.php";s:4:"role";s:4:"data";s:12:"installed_as";s:78:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/templates/_password.php";}s:47:"modules/sfGuardUser/templates/_password_bis.php";a:4:{s:6:"md5sum";s:32:"43d049c62485645065697f2ae098777c";s:4:"name";s:47:"modules/sfGuardUser/templates/_password_bis.php";s:4:"role";s:4:"data";s:12:"installed_as";s:82:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/templates/_password_bis.php";}s:37:"modules/sfGuardUser/validate/edit.yml";a:4:{s:6:"md5sum";s:32:"aa213f724f25d2a367b184bc9fdd36d1";s:4:"name";s:37:"modules/sfGuardUser/validate/edit.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:72:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/validate/edit.yml";}s:6:"README";a:4:{s:6:"md5sum";s:32:"3f891a0cb755d820b08e2639f002c6ae";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:41:"/opt/reaktor/plugins/sfGuardPlugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"c0ab88a4687e9ff8e0fb6c95ca49ed74";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:42:"/opt/reaktor/plugins/sfGuardPlugin/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:31:{s:41:"/opt/reaktor/plugins/sfGuardPlugin/config";b:1;s:34:"/opt/reaktor/plugins/sfGuardPlugin";b:1;s:48:"/opt/reaktor/plugins/sfGuardPlugin/data/fixtures";b:1;s:39:"/opt/reaktor/plugins/sfGuardPlugin/data";b:1;s:45:"/opt/reaktor/plugins/sfGuardPlugin/data/tasks";b:1;s:51:"/opt/reaktor/plugins/sfGuardPlugin/lib/model/plugin";b:1;s:44:"/opt/reaktor/plugins/sfGuardPlugin/lib/model";b:1;s:38:"/opt/reaktor/plugins/sfGuardPlugin/lib";b:1;s:43:"/opt/reaktor/plugins/sfGuardPlugin/lib/user";b:1;s:48:"/opt/reaktor/plugins/sfGuardPlugin/lib/validator";b:1;s:62:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/actions";b:1;s:54:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth";b:1;s:42:"/opt/reaktor/plugins/sfGuardPlugin/modules";b:1;s:61:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/config";b:1;s:58:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/lib";b:1;s:64:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/templates";b:1;s:63:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardAuth/validate";b:1;s:63:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardGroup/actions";b:1;s:55:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardGroup";b:1;s:62:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardGroup/config";b:1;s:64:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardGroup/validate";b:1;s:68:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardPermission/actions";b:1;s:60:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardPermission";b:1;s:67:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardPermission/config";b:1;s:69:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardPermission/validate";b:1;s:62:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/actions";b:1;s:54:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser";b:1;s:61:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/config";b:1;s:58:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/lib";b:1;s:64:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/templates";b:1;s:63:"/opt/reaktor/plugins/sfGuardPlugin/modules/sfGuardUser/validate";b:1;}s:3:"old";a:7:{s:7:"version";s:6:"1.1.13";s:12:"release_date";s:10:"2007-11-14";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.0.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:4:{i:0;a:5:{s:4:"name";s:16:"Fabien POTENCIER";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:6:"fabpot";s:4:"role";s:4:"lead";}i:1;a:5:{s:4:"name";s:11:"Jason IBELE";s:5:"email";s:0:"";s:6:"active";s:3:"yes";s:6:"handle";s:6:"draven";s:4:"role";s:4:"lead";}i:2;a:5:{s:4:"name";s:9:"Dave DASH";s:5:"email";s:23:"dd-symfony@davedash.com";s:6:"active";s:3:"yes";s:6:"handle";s:8:"davedash";s:4:"role";s:4:"lead";}i:3;a:5:{s:4:"name";s:18:"Francois Zaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:10:"fzaninotto";s:4:"role";s:9:"developer";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1201682501;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfi18nextractplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfi18nextractplugin.reg new file mode 100644 index 0000000..de6e814 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfi18nextractplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.6.2";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:19:"sfI18nExtractPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:29:"i18n string extractor plugin.";s:11:"description";s:81:"i18n string extractor plugin. This is a backport of a symfony 1.1 native feature.";s:4:"lead";a:4:{s:4:"name";s:16:"Fabien POTENCIER";s:4:"user";s:6:"fabpot";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2008-01-14";s:4:"time";s:8:"15:22:22";s:7:"version";a:2:{s:7:"release";s:5:"1.0.5";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:11:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0280dae77d05597bba3a1296554c8c90";s:4:"name";s:25:"data/tasks/sfPakeI18N.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9234ba6d60a2b05e77cc8248ff464ead";s:4:"name";s:38:"lib/sfI18nApplicationExtract.class.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"25d15638eabffe4db4cdd51a24f69af5";s:4:"name";s:27:"lib/sfI18nExtract.class.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"075abb83022c92275bbc5c493d4faff8";s:4:"name";s:38:"lib/sfI18nExtractorInterface.class.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e9a03eea9836198a92f1f1cc68f23e14";s:4:"name";s:33:"lib/sfI18nModuleExtract.class.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8fa38494d93adfb95cd08903f6f76da0";s:4:"name";s:32:"lib/sfI18nPhpExtractor.class.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"45ff17051348ec15f8d960d1caff73a7";s:4:"name";s:33:"lib/sfI18nYamlExtractor.class.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f27bff7153f8b88817ea0214347e60ea";s:4:"name";s:42:"lib/sfI18nYamlGeneratorExtractor.class.php";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fb74e8e260f330473fa9f7d0f84e6c6b";s:4:"name";s:41:"lib/sfI18nYamlValidateExtractor.class.php";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2268d071e2e0de6412c3d85df8c1754d";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c0ab88a4687e9ff8e0fb6c95ca49ed74";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.0.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:11:{s:25:"data/tasks/sfPakeI18N.php";a:4:{s:6:"md5sum";s:32:"0280dae77d05597bba3a1296554c8c90";s:4:"name";s:25:"data/tasks/sfPakeI18N.php";s:4:"role";s:4:"data";s:12:"installed_as";s:89:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/data/tasks/sfPakeI18N.php";}s:38:"lib/sfI18nApplicationExtract.class.php";a:4:{s:6:"md5sum";s:32:"9234ba6d60a2b05e77cc8248ff464ead";s:4:"name";s:38:"lib/sfI18nApplicationExtract.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:102:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib/sfI18nApplicationExtract.class.php";}s:27:"lib/sfI18nExtract.class.php";a:4:{s:6:"md5sum";s:32:"25d15638eabffe4db4cdd51a24f69af5";s:4:"name";s:27:"lib/sfI18nExtract.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib/sfI18nExtract.class.php";}s:38:"lib/sfI18nExtractorInterface.class.php";a:4:{s:6:"md5sum";s:32:"075abb83022c92275bbc5c493d4faff8";s:4:"name";s:38:"lib/sfI18nExtractorInterface.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:102:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib/sfI18nExtractorInterface.class.php";}s:33:"lib/sfI18nModuleExtract.class.php";a:4:{s:6:"md5sum";s:32:"e9a03eea9836198a92f1f1cc68f23e14";s:4:"name";s:33:"lib/sfI18nModuleExtract.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:97:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib/sfI18nModuleExtract.class.php";}s:32:"lib/sfI18nPhpExtractor.class.php";a:4:{s:6:"md5sum";s:32:"8fa38494d93adfb95cd08903f6f76da0";s:4:"name";s:32:"lib/sfI18nPhpExtractor.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:96:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib/sfI18nPhpExtractor.class.php";}s:33:"lib/sfI18nYamlExtractor.class.php";a:4:{s:6:"md5sum";s:32:"45ff17051348ec15f8d960d1caff73a7";s:4:"name";s:33:"lib/sfI18nYamlExtractor.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:97:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib/sfI18nYamlExtractor.class.php";}s:42:"lib/sfI18nYamlGeneratorExtractor.class.php";a:4:{s:6:"md5sum";s:32:"f27bff7153f8b88817ea0214347e60ea";s:4:"name";s:42:"lib/sfI18nYamlGeneratorExtractor.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:106:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib/sfI18nYamlGeneratorExtractor.class.php";}s:41:"lib/sfI18nYamlValidateExtractor.class.php";a:4:{s:6:"md5sum";s:32:"fb74e8e260f330473fa9f7d0f84e6c6b";s:4:"name";s:41:"lib/sfI18nYamlValidateExtractor.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib/sfI18nYamlValidateExtractor.class.php";}s:6:"README";a:4:{s:6:"md5sum";s:32:"2268d071e2e0de6412c3d85df8c1754d";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:70:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"c0ab88a4687e9ff8e0fb6c95ca49ed74";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:71:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:4:{s:74:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/data/tasks";b:1;s:68:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/data";b:1;s:67:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin/lib";b:1;s:63:"/home/olepw/workspace/deich_reaktor/plugins/sfI18nExtractPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.0.5";s:12:"release_date";s:10:"2008-01-14";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.0.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:16:"Fabien POTENCIER";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:6:"fabpot";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1210241021;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sflightboxplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sflightboxplugin.reg new file mode 100644 index 0000000..644e708 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sflightboxplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.5.1";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:16:"sfLightboxPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:28:"Lightbox2 plugin for Symfony";s:11:"description";s:111:"sfLightboxPlugin is a symfony plugin that provides an easy to use wrapper for the Lightbox2 javascript library.";s:4:"lead";a:4:{s:4:"name";s:12:"Vernet Loïc";s:4:"user";s:4:"COil";s:5:"email";s:24:"qrf_coil[at]yahoo[dot]fr";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-04-27";s:4:"time";s:8:"10:39:23";s:7:"version";a:2:{s:7:"release";s:5:"1.0.5";s:3:"api";s:5:"1.0.5";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:23:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"de8b74d1b45f03c31e9947548380c9c5";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"55aff3a9dcec08f756c2b6c7d93db833";s:4:"name";s:29:"lib/helper/LightboxHelper.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4522f37959a5fb14b2841342e9644498";s:4:"name";s:50:"modules/sfLightboxPlugin/actions/actions.class.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8949a290beed540e7159853b89bd6e89";s:4:"name";s:51:"modules/sfLightboxPlugin/templates/modalSuccess.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8949a290beed540e7159853b89bd6e89";s:4:"name";s:50:"modules/sfLightboxPlugin/templates/testSuccess.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"59c580502fe1c554be795d26fc41a371";s:4:"name";s:44:"modules/sfLightboxPlugin/templates/_test.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"74f9199c0070b9adcbfbfa7458310978";s:4:"name";s:20:"web/css/lightbox.css";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d5b833dcfa984a5b769f6f700e17ef5a";s:4:"name";s:20:"web/css/modalbox.css";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0e5462b0b4f00432eac4b33d5fa31c5a";s:4:"name";s:28:"web/images/en/closelabel.gif";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"485d89b62f7af7f0ce9427bb9a636e7e";s:4:"name";s:27:"web/images/en/nextlabel.gif";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d935f4acf56e0b83218bbdb5835e4e23";s:4:"name";s:27:"web/images/en/prevlabel.gif";s:4:"role";s:4:"data";}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"df15677979100975ea320b635fe6fd42";s:4:"name";s:28:"web/images/fr/closelabel.gif";s:4:"role";s:4:"data";}}i:12;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"706a5bf8248f60a56986f0cd34301ca5";s:4:"name";s:27:"web/images/fr/nextlabel.gif";s:4:"role";s:4:"data";}}i:13;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6cd26f7578b3d9f220d1cfa5cb4c66a6";s:4:"name";s:27:"web/images/fr/prevlabel.gif";s:4:"role";s:4:"data";}}i:14;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fc94fb0c3ed8a8f909dbc7630a0987ff";s:4:"name";s:20:"web/images/blank.gif";s:4:"role";s:4:"data";}}i:15;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"540f65d2b2f94032d6c3037622843a50";s:4:"name";s:20:"web/images/close.gif";s:4:"role";s:4:"data";}}i:16;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7e99e1159a3686f6aa4f90043c554483";s:4:"name";s:22:"web/images/loading.gif";s:4:"role";s:4:"data";}}i:17;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"804543daa860e91aabe9ba634e64ed2b";s:4:"name";s:19:"web/images/next.gif";s:4:"role";s:4:"data";}}i:18;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ef26ef0081ed01613cf6fa8b68019ca4";s:4:"name";s:19:"web/images/prev.gif";s:4:"role";s:4:"data";}}i:19;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6793a9454f12622c7b781abe097c95ed";s:4:"name";s:18:"web/js/lightbox.js";s:4:"role";s:4:"data";}}i:20;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d138da05c92c33451485dad29078fb9f";s:4:"name";s:18:"web/js/modalbox.js";s:4:"role";s:4:"data";}}i:21;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fbf6fa3933f7a7d1d7e0486ca8324ee2";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}i:22;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f1befd545a9d58e433f82d24b33814c9";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.1.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"0.8.1";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:23:{s:17:"config/config.php";a:4:{s:6:"md5sum";s:32:"de8b74d1b45f03c31e9947548380c9c5";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";s:12:"installed_as";s:78:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/config/config.php";}s:29:"lib/helper/LightboxHelper.php";a:4:{s:6:"md5sum";s:32:"55aff3a9dcec08f756c2b6c7d93db833";s:4:"name";s:29:"lib/helper/LightboxHelper.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/lib/helper/LightboxHelper.php";}s:50:"modules/sfLightboxPlugin/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"4522f37959a5fb14b2841342e9644498";s:4:"name";s:50:"modules/sfLightboxPlugin/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:111:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/modules/sfLightboxPlugin/actions/actions.class.php";}s:51:"modules/sfLightboxPlugin/templates/modalSuccess.php";a:4:{s:6:"md5sum";s:32:"8949a290beed540e7159853b89bd6e89";s:4:"name";s:51:"modules/sfLightboxPlugin/templates/modalSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:112:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/modules/sfLightboxPlugin/templates/modalSuccess.php";}s:50:"modules/sfLightboxPlugin/templates/testSuccess.php";a:4:{s:6:"md5sum";s:32:"8949a290beed540e7159853b89bd6e89";s:4:"name";s:50:"modules/sfLightboxPlugin/templates/testSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:111:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/modules/sfLightboxPlugin/templates/testSuccess.php";}s:44:"modules/sfLightboxPlugin/templates/_test.php";a:4:{s:6:"md5sum";s:32:"59c580502fe1c554be795d26fc41a371";s:4:"name";s:44:"modules/sfLightboxPlugin/templates/_test.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/modules/sfLightboxPlugin/templates/_test.php";}s:20:"web/css/lightbox.css";a:4:{s:6:"md5sum";s:32:"74f9199c0070b9adcbfbfa7458310978";s:4:"name";s:20:"web/css/lightbox.css";s:4:"role";s:4:"data";s:12:"installed_as";s:81:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/css/lightbox.css";}s:20:"web/css/modalbox.css";a:4:{s:6:"md5sum";s:32:"d5b833dcfa984a5b769f6f700e17ef5a";s:4:"name";s:20:"web/css/modalbox.css";s:4:"role";s:4:"data";s:12:"installed_as";s:81:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/css/modalbox.css";}s:28:"web/images/en/closelabel.gif";a:4:{s:6:"md5sum";s:32:"0e5462b0b4f00432eac4b33d5fa31c5a";s:4:"name";s:28:"web/images/en/closelabel.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:89:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/en/closelabel.gif";}s:27:"web/images/en/nextlabel.gif";a:4:{s:6:"md5sum";s:32:"485d89b62f7af7f0ce9427bb9a636e7e";s:4:"name";s:27:"web/images/en/nextlabel.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/en/nextlabel.gif";}s:27:"web/images/en/prevlabel.gif";a:4:{s:6:"md5sum";s:32:"d935f4acf56e0b83218bbdb5835e4e23";s:4:"name";s:27:"web/images/en/prevlabel.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/en/prevlabel.gif";}s:28:"web/images/fr/closelabel.gif";a:4:{s:6:"md5sum";s:32:"df15677979100975ea320b635fe6fd42";s:4:"name";s:28:"web/images/fr/closelabel.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:89:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/fr/closelabel.gif";}s:27:"web/images/fr/nextlabel.gif";a:4:{s:6:"md5sum";s:32:"706a5bf8248f60a56986f0cd34301ca5";s:4:"name";s:27:"web/images/fr/nextlabel.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/fr/nextlabel.gif";}s:27:"web/images/fr/prevlabel.gif";a:4:{s:6:"md5sum";s:32:"6cd26f7578b3d9f220d1cfa5cb4c66a6";s:4:"name";s:27:"web/images/fr/prevlabel.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/fr/prevlabel.gif";}s:20:"web/images/blank.gif";a:4:{s:6:"md5sum";s:32:"fc94fb0c3ed8a8f909dbc7630a0987ff";s:4:"name";s:20:"web/images/blank.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:81:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/blank.gif";}s:20:"web/images/close.gif";a:4:{s:6:"md5sum";s:32:"540f65d2b2f94032d6c3037622843a50";s:4:"name";s:20:"web/images/close.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:81:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/close.gif";}s:22:"web/images/loading.gif";a:4:{s:6:"md5sum";s:32:"7e99e1159a3686f6aa4f90043c554483";s:4:"name";s:22:"web/images/loading.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/loading.gif";}s:19:"web/images/next.gif";a:4:{s:6:"md5sum";s:32:"804543daa860e91aabe9ba634e64ed2b";s:4:"name";s:19:"web/images/next.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:80:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/next.gif";}s:19:"web/images/prev.gif";a:4:{s:6:"md5sum";s:32:"ef26ef0081ed01613cf6fa8b68019ca4";s:4:"name";s:19:"web/images/prev.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:80:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/prev.gif";}s:18:"web/js/lightbox.js";a:4:{s:6:"md5sum";s:32:"6793a9454f12622c7b781abe097c95ed";s:4:"name";s:18:"web/js/lightbox.js";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/js/lightbox.js";}s:18:"web/js/modalbox.js";a:4:{s:6:"md5sum";s:32:"d138da05c92c33451485dad29078fb9f";s:4:"name";s:18:"web/js/modalbox.js";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/js/modalbox.js";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"fbf6fa3933f7a7d1d7e0486ca8324ee2";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:68:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/LICENSE";}s:6:"README";a:4:{s:6:"md5sum";s:32:"f1befd545a9d58e433f82d24b33814c9";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:67:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/README";}}s:12:"_lastversion";N;s:7:"dirtree";a:14:{s:67:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/config";b:1;s:71:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/lib/helper";b:1;s:64:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/lib";b:1;s:93:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/modules/sfLightboxPlugin/actions";b:1;s:85:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/modules/sfLightboxPlugin";b:1;s:68:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/modules";b:1;s:95:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/modules/sfLightboxPlugin/templates";b:1;s:68:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/css";b:1;s:64:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web";b:1;s:74:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/en";b:1;s:71:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images";b:1;s:74:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/images/fr";b:1;s:67:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin/web/js";b:1;s:60:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfLightboxPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.0.5";s:12:"release_date";s:10:"2007-04-27";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.1.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"0.8.1";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:12:"Vernet Loïc";s:5:"email";s:24:"qrf_coil[at]yahoo[dot]fr";s:6:"active";s:3:"yes";s:6:"handle";s:4:"COil";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1203600715;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfmedialibraryplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfmedialibraryplugin.reg new file mode 100644 index 0000000..4a09e93 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfmedialibraryplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.6.1";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:20:"sfMediaLibraryPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:23:"Asset management plugin";s:11:"description";s:282:"The sfMediaLibraryPlugin provides an easy-to-use interface to manage web assets (images, PDF documents, Flash objects, and so on). It also provides an extension to tinyMCE so that the media inclusion feature of rich text editors uses the assets uploaded through the plugin's module.";s:4:"lead";a:4:{s:4:"name";s:19:"François Zaninotto";s:4:"user";s:10:"fzaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-11-16";s:4:"time";s:8:"19:29:22";s:7:"version";a:2:{s:7:"release";s:5:"0.9.1";s:3:"api";s:5:"0.9.1";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:37:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"59105a8758135f5cf23dcb3b8088f22d";s:4:"name";s:35:"lib/helper/sfMediaLibraryHelper.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6086ced60c90be057a5221e3ff9b53d6";s:4:"name";s:48:"modules/sfMediaLibrary/actions/actions.class.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"317bbba1b9f9475115a944d2fee41eb4";s:4:"name";s:38:"modules/sfMediaLibrary/config/view.yml";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2d0878c9b79f15e08c915643fe1210b1";s:4:"name";s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.es.xml";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3eb60bc0b52877110b8621b7f7986602";s:4:"name";s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.fr.xml";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ba747d11f311cb3fc944407e294e44a0";s:4:"name";s:52:"modules/sfMediaLibrary/i18n/sfMediaLibrary.pt_BR.xml";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3ac1cdfbb04780421d5343c39e4efde2";s:4:"name";s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.it.xml";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"bbefc18ba0cbefa5fea667edf621a1dd";s:4:"name";s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.de.xml";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"90aef8f6aa840f3da312fd1a928997b5";s:4:"name";s:52:"modules/sfMediaLibrary/i18n/sfMediaLibrary.nl_NL.xml";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f1055224e171b1c755e15645b2e1e12c";s:4:"name";s:62:"modules/sfMediaLibrary/lib/BasesfMediaLibraryActions.class.php";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"96ad209ebd57f36d11d26e79a157904b";s:4:"name";s:50:"modules/sfMediaLibrary/templates/choiceSuccess.php";s:4:"role";s:4:"data";}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4a2cfd605aa8413632022152a5720355";s:4:"name";s:49:"modules/sfMediaLibrary/templates/indexSuccess.php";s:4:"role";s:4:"data";}}i:12;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7f591f318379c545e7ee9841664020dd";s:4:"name";s:50:"modules/sfMediaLibrary/templates/renameSuccess.php";s:4:"role";s:4:"data";}}i:13;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c7e7e738780d62ed0dec989b853c14fd";s:4:"name";s:43:"modules/sfMediaLibrary/templates/_block.php";s:4:"role";s:4:"data";}}i:14;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a8ac3c60b1f6a4ad64ac5c66abe2092c";s:4:"name";s:42:"modules/sfMediaLibrary/templates/_dirs.php";s:4:"role";s:4:"data";}}i:15;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2c89c825348edfe32e842ff147c44b51";s:4:"name";s:43:"modules/sfMediaLibrary/templates/_files.php";s:4:"role";s:4:"data";}}i:16;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0cc7c8bda1c9d0df90c48abcb83e9e9f";s:4:"name";s:17:"web/css/media.css";s:4:"role";s:4:"data";}}i:17;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"06bbb8e4be4588635a6bd742669e096e";s:4:"name";s:22:"web/images/archive.png";s:4:"role";s:4:"data";}}i:18;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"36e70f3d7035b1d10e970c1dc399499a";s:4:"name";s:18:"web/images/bin.png";s:4:"role";s:4:"data";}}i:19;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"99888590ef147031f18bec42533906a6";s:4:"name";s:21:"web/images/delete.png";s:4:"role";s:4:"data";}}i:20;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b152895afab84e6f3dfa7a58f26a491f";s:4:"name";s:18:"web/images/doc.png";s:4:"role";s:4:"data";}}i:21;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"fbcb11a571906d79fbb2affa64643fdc";s:4:"name";s:19:"web/images/edit.png";s:4:"role";s:4:"data";}}i:22;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7a5d8fdb91d6497b9962343c5649868e";s:4:"name";s:22:"web/images/filenew.png";s:4:"role";s:4:"data";}}i:23;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3d1bfcf55d8f10f8ea00d314778350a6";s:4:"name";s:21:"web/images/folder.png";s:4:"role";s:4:"data";}}i:24;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3e7c0d3d361de86228d86c2404db8cfc";s:4:"name";s:25:"web/images/folder_new.png";s:4:"role";s:4:"data";}}i:25;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b94c179975e6bbd9a320dea6ecc7b7ae";s:4:"name";s:26:"web/images/folder_open.png";s:4:"role";s:4:"data";}}i:26;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"dbaec06786fe05e85a306aaabe68003c";s:4:"name";s:19:"web/images/html.png";s:4:"role";s:4:"data";}}i:27;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e9d1e005bd85c801fbd463b7487895c5";s:4:"name";s:20:"web/images/image.png";s:4:"role";s:4:"data";}}i:28;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9f68f5a5f501145348af0bb490b9f135";s:4:"name";s:18:"web/images/pdf.png";s:4:"role";s:4:"data";}}i:29;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d465433911233f1746778931be8d8fe7";s:4:"name";s:18:"web/images/ppt.png";s:4:"role";s:4:"data";}}i:30;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5a305ec12ae3d94bc179a254b55c56da";s:4:"name";s:18:"web/images/txt.png";s:4:"role";s:4:"data";}}i:31;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4916f08cf952402163d8ece7a90c28a3";s:4:"name";s:22:"web/images/unknown.png";s:4:"role";s:4:"data";}}i:32;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"196aa29c950f3eaf8a6f1506eec0a132";s:4:"name";s:17:"web/images/up.png";s:4:"role";s:4:"data";}}i:33;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"27724a9553c32e71ed5509387ba2f823";s:4:"name";s:18:"web/images/xls.png";s:4:"role";s:4:"data";}}i:34;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f3b7d1e03522fde026b2e3a5214d39b5";s:4:"name";s:14:"web/js/main.js";s:4:"role";s:4:"data";}}i:35;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"00f64fb43ce5d2c983fd2a1e839ab7d3";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}i:36;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f09e4670f9be2e1cb3ca852218d6a083";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.1.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:4:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:37:{s:35:"lib/helper/sfMediaLibraryHelper.php";a:4:{s:6:"md5sum";s:32:"59105a8758135f5cf23dcb3b8088f22d";s:4:"name";s:35:"lib/helper/sfMediaLibraryHelper.php";s:4:"role";s:4:"data";s:12:"installed_as";s:101:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/lib/helper/sfMediaLibraryHelper.php";}s:48:"modules/sfMediaLibrary/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"6086ced60c90be057a5221e3ff9b53d6";s:4:"name";s:48:"modules/sfMediaLibrary/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:114:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/actions/actions.class.php";}s:38:"modules/sfMediaLibrary/config/view.yml";a:4:{s:6:"md5sum";s:32:"317bbba1b9f9475115a944d2fee41eb4";s:4:"name";s:38:"modules/sfMediaLibrary/config/view.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:104:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/config/view.yml";}s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.es.xml";a:4:{s:6:"md5sum";s:32:"2d0878c9b79f15e08c915643fe1210b1";s:4:"name";s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.es.xml";s:4:"role";s:4:"data";s:12:"installed_as";s:115:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/i18n/sfMediaLibrary.es.xml";}s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.fr.xml";a:4:{s:6:"md5sum";s:32:"3eb60bc0b52877110b8621b7f7986602";s:4:"name";s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.fr.xml";s:4:"role";s:4:"data";s:12:"installed_as";s:115:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/i18n/sfMediaLibrary.fr.xml";}s:52:"modules/sfMediaLibrary/i18n/sfMediaLibrary.pt_BR.xml";a:4:{s:6:"md5sum";s:32:"ba747d11f311cb3fc944407e294e44a0";s:4:"name";s:52:"modules/sfMediaLibrary/i18n/sfMediaLibrary.pt_BR.xml";s:4:"role";s:4:"data";s:12:"installed_as";s:118:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/i18n/sfMediaLibrary.pt_BR.xml";}s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.it.xml";a:4:{s:6:"md5sum";s:32:"3ac1cdfbb04780421d5343c39e4efde2";s:4:"name";s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.it.xml";s:4:"role";s:4:"data";s:12:"installed_as";s:115:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/i18n/sfMediaLibrary.it.xml";}s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.de.xml";a:4:{s:6:"md5sum";s:32:"bbefc18ba0cbefa5fea667edf621a1dd";s:4:"name";s:49:"modules/sfMediaLibrary/i18n/sfMediaLibrary.de.xml";s:4:"role";s:4:"data";s:12:"installed_as";s:115:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/i18n/sfMediaLibrary.de.xml";}s:52:"modules/sfMediaLibrary/i18n/sfMediaLibrary.nl_NL.xml";a:4:{s:6:"md5sum";s:32:"90aef8f6aa840f3da312fd1a928997b5";s:4:"name";s:52:"modules/sfMediaLibrary/i18n/sfMediaLibrary.nl_NL.xml";s:4:"role";s:4:"data";s:12:"installed_as";s:118:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/i18n/sfMediaLibrary.nl_NL.xml";}s:62:"modules/sfMediaLibrary/lib/BasesfMediaLibraryActions.class.php";a:4:{s:6:"md5sum";s:32:"f1055224e171b1c755e15645b2e1e12c";s:4:"name";s:62:"modules/sfMediaLibrary/lib/BasesfMediaLibraryActions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:128:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/lib/BasesfMediaLibraryActions.class.php";}s:50:"modules/sfMediaLibrary/templates/choiceSuccess.php";a:4:{s:6:"md5sum";s:32:"96ad209ebd57f36d11d26e79a157904b";s:4:"name";s:50:"modules/sfMediaLibrary/templates/choiceSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:116:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/templates/choiceSuccess.php";}s:49:"modules/sfMediaLibrary/templates/indexSuccess.php";a:4:{s:6:"md5sum";s:32:"4a2cfd605aa8413632022152a5720355";s:4:"name";s:49:"modules/sfMediaLibrary/templates/indexSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:115:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/templates/indexSuccess.php";}s:50:"modules/sfMediaLibrary/templates/renameSuccess.php";a:4:{s:6:"md5sum";s:32:"7f591f318379c545e7ee9841664020dd";s:4:"name";s:50:"modules/sfMediaLibrary/templates/renameSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:116:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/templates/renameSuccess.php";}s:43:"modules/sfMediaLibrary/templates/_block.php";a:4:{s:6:"md5sum";s:32:"c7e7e738780d62ed0dec989b853c14fd";s:4:"name";s:43:"modules/sfMediaLibrary/templates/_block.php";s:4:"role";s:4:"data";s:12:"installed_as";s:109:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/templates/_block.php";}s:42:"modules/sfMediaLibrary/templates/_dirs.php";a:4:{s:6:"md5sum";s:32:"a8ac3c60b1f6a4ad64ac5c66abe2092c";s:4:"name";s:42:"modules/sfMediaLibrary/templates/_dirs.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/templates/_dirs.php";}s:43:"modules/sfMediaLibrary/templates/_files.php";a:4:{s:6:"md5sum";s:32:"2c89c825348edfe32e842ff147c44b51";s:4:"name";s:43:"modules/sfMediaLibrary/templates/_files.php";s:4:"role";s:4:"data";s:12:"installed_as";s:109:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/templates/_files.php";}s:17:"web/css/media.css";a:4:{s:6:"md5sum";s:32:"0cc7c8bda1c9d0df90c48abcb83e9e9f";s:4:"name";s:17:"web/css/media.css";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/css/media.css";}s:22:"web/images/archive.png";a:4:{s:6:"md5sum";s:32:"06bbb8e4be4588635a6bd742669e096e";s:4:"name";s:22:"web/images/archive.png";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/archive.png";}s:18:"web/images/bin.png";a:4:{s:6:"md5sum";s:32:"36e70f3d7035b1d10e970c1dc399499a";s:4:"name";s:18:"web/images/bin.png";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/bin.png";}s:21:"web/images/delete.png";a:4:{s:6:"md5sum";s:32:"99888590ef147031f18bec42533906a6";s:4:"name";s:21:"web/images/delete.png";s:4:"role";s:4:"data";s:12:"installed_as";s:87:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/delete.png";}s:18:"web/images/doc.png";a:4:{s:6:"md5sum";s:32:"b152895afab84e6f3dfa7a58f26a491f";s:4:"name";s:18:"web/images/doc.png";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/doc.png";}s:19:"web/images/edit.png";a:4:{s:6:"md5sum";s:32:"fbcb11a571906d79fbb2affa64643fdc";s:4:"name";s:19:"web/images/edit.png";s:4:"role";s:4:"data";s:12:"installed_as";s:85:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/edit.png";}s:22:"web/images/filenew.png";a:4:{s:6:"md5sum";s:32:"7a5d8fdb91d6497b9962343c5649868e";s:4:"name";s:22:"web/images/filenew.png";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/filenew.png";}s:21:"web/images/folder.png";a:4:{s:6:"md5sum";s:32:"3d1bfcf55d8f10f8ea00d314778350a6";s:4:"name";s:21:"web/images/folder.png";s:4:"role";s:4:"data";s:12:"installed_as";s:87:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/folder.png";}s:25:"web/images/folder_new.png";a:4:{s:6:"md5sum";s:32:"3e7c0d3d361de86228d86c2404db8cfc";s:4:"name";s:25:"web/images/folder_new.png";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/folder_new.png";}s:26:"web/images/folder_open.png";a:4:{s:6:"md5sum";s:32:"b94c179975e6bbd9a320dea6ecc7b7ae";s:4:"name";s:26:"web/images/folder_open.png";s:4:"role";s:4:"data";s:12:"installed_as";s:92:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/folder_open.png";}s:19:"web/images/html.png";a:4:{s:6:"md5sum";s:32:"dbaec06786fe05e85a306aaabe68003c";s:4:"name";s:19:"web/images/html.png";s:4:"role";s:4:"data";s:12:"installed_as";s:85:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/html.png";}s:20:"web/images/image.png";a:4:{s:6:"md5sum";s:32:"e9d1e005bd85c801fbd463b7487895c5";s:4:"name";s:20:"web/images/image.png";s:4:"role";s:4:"data";s:12:"installed_as";s:86:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/image.png";}s:18:"web/images/pdf.png";a:4:{s:6:"md5sum";s:32:"9f68f5a5f501145348af0bb490b9f135";s:4:"name";s:18:"web/images/pdf.png";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/pdf.png";}s:18:"web/images/ppt.png";a:4:{s:6:"md5sum";s:32:"d465433911233f1746778931be8d8fe7";s:4:"name";s:18:"web/images/ppt.png";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/ppt.png";}s:18:"web/images/txt.png";a:4:{s:6:"md5sum";s:32:"5a305ec12ae3d94bc179a254b55c56da";s:4:"name";s:18:"web/images/txt.png";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/txt.png";}s:22:"web/images/unknown.png";a:4:{s:6:"md5sum";s:32:"4916f08cf952402163d8ece7a90c28a3";s:4:"name";s:22:"web/images/unknown.png";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/unknown.png";}s:17:"web/images/up.png";a:4:{s:6:"md5sum";s:32:"196aa29c950f3eaf8a6f1506eec0a132";s:4:"name";s:17:"web/images/up.png";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/up.png";}s:18:"web/images/xls.png";a:4:{s:6:"md5sum";s:32:"27724a9553c32e71ed5509387ba2f823";s:4:"name";s:18:"web/images/xls.png";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images/xls.png";}s:14:"web/js/main.js";a:4:{s:6:"md5sum";s:32:"f3b7d1e03522fde026b2e3a5214d39b5";s:4:"name";s:14:"web/js/main.js";s:4:"role";s:4:"data";s:12:"installed_as";s:80:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/js/main.js";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"00f64fb43ce5d2c983fd2a1e839ab7d3";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:73:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/LICENSE";}s:6:"README";a:4:{s:6:"md5sum";s:32:"f09e4670f9be2e1cb3ca852218d6a083";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:72:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/README";}}s:12:"_lastversion";N;s:7:"dirtree";a:14:{s:76:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/lib/helper";b:1;s:69:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/lib";b:1;s:96:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/actions";b:1;s:88:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary";b:1;s:73:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules";b:1;s:95:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/config";b:1;s:93:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/i18n";b:1;s:92:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/lib";b:1;s:98:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/modules/sfMediaLibrary/templates";b:1;s:73:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/css";b:1;s:69:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web";b:1;s:76:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/images";b:1;s:72:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin/web/js";b:1;s:65:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfMediaLibraryPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"0.9.1";s:12:"release_date";s:10:"2007-11-16";s:13:"release_state";s:4:"beta";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.1.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:19:"François Zaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:10:"fzaninotto";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1202140249;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfpropelactasratablebehaviorplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfpropelactasratablebehaviorplugin.reg new file mode 100644 index 0000000..5bd2df2 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfpropelactasratablebehaviorplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:6:"1.4.11";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:34:"sfPropelActAsRatableBehaviorPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:23:"Propel ratable behavior";s:11:"description";s:87:"This Symfony plugin allow rating capacity to a Propel object through a Propel behavior.";s:4:"lead";a:4:{s:4:"name";s:17:"Nicolas Perriault";s:4:"user";s:7:"nicolas";s:5:"email";s:20:"nperriault@gmail.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-09-05";s:4:"time";s:8:"16:51:18";s:7:"version";a:2:{s:7:"release";s:5:"0.5.0";s:3:"api";s:5:"0.5.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:12:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"50b2430e592fb02c3d93e1e782ee0b40";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"073d5a07220835c3a435a76a462f2307";s:4:"name";s:26:"config/config_handlers.yml";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e3ffec20808742557c28c19b73bc73f8";s:4:"name";s:17:"config/schema.yml";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"90f72a08ec28f28bf9d372dcd1d68d8a";s:4:"name";s:36:"lib/model/map/sfRatingMapBuilder.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e48272f786a3311f638860e7ceb55871";s:4:"name";s:29:"lib/model/om/BasesfRating.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c57d00733724268e3f2ba1f02e858030";s:4:"name";s:33:"lib/model/om/BasesfRatingPeer.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e045737699eafcb37367dafe2920a913";s:4:"name";s:22:"lib/model/sfRating.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"13c434c4ab18332ecf68e6477f1f5509";s:4:"name";s:26:"lib/model/sfRatingPeer.php";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"75e68768f1b7e4fecb2ced44ed66552e";s:4:"name";s:42:"lib/sfPropelActAsRatableBehavior.class.php";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b182cfb2c0de38164c575a698cf96383";s:4:"name";s:46:"test/unit/sfPropelActAsRatableBehaviorTest.php";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a2d16633aab60e6528d9138a7cec9d2d";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9684d658dcf82a467d67a36264fa97c2";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.1.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:12:{s:17:"config/config.php";a:4:{s:6:"md5sum";s:32:"50b2430e592fb02c3d93e1e782ee0b40";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";s:12:"installed_as";s:96:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/config/config.php";}s:26:"config/config_handlers.yml";a:4:{s:6:"md5sum";s:32:"073d5a07220835c3a435a76a462f2307";s:4:"name";s:26:"config/config_handlers.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/config/config_handlers.yml";}s:17:"config/schema.yml";a:4:{s:6:"md5sum";s:32:"e3ffec20808742557c28c19b73bc73f8";s:4:"name";s:17:"config/schema.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:96:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/config/schema.yml";}s:36:"lib/model/map/sfRatingMapBuilder.php";a:4:{s:6:"md5sum";s:32:"90f72a08ec28f28bf9d372dcd1d68d8a";s:4:"name";s:36:"lib/model/map/sfRatingMapBuilder.php";s:4:"role";s:4:"data";s:12:"installed_as";s:115:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/map/sfRatingMapBuilder.php";}s:29:"lib/model/om/BasesfRating.php";a:4:{s:6:"md5sum";s:32:"e48272f786a3311f638860e7ceb55871";s:4:"name";s:29:"lib/model/om/BasesfRating.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRating.php";}s:33:"lib/model/om/BasesfRatingPeer.php";a:4:{s:6:"md5sum";s:32:"c57d00733724268e3f2ba1f02e858030";s:4:"name";s:33:"lib/model/om/BasesfRatingPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:112:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRatingPeer.php";}s:22:"lib/model/sfRating.php";a:4:{s:6:"md5sum";s:32:"e045737699eafcb37367dafe2920a913";s:4:"name";s:22:"lib/model/sfRating.php";s:4:"role";s:4:"data";s:12:"installed_as";s:101:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/sfRating.php";}s:26:"lib/model/sfRatingPeer.php";a:4:{s:6:"md5sum";s:32:"13c434c4ab18332ecf68e6477f1f5509";s:4:"name";s:26:"lib/model/sfRatingPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/sfRatingPeer.php";}s:42:"lib/sfPropelActAsRatableBehavior.class.php";a:4:{s:6:"md5sum";s:32:"75e68768f1b7e4fecb2ced44ed66552e";s:4:"name";s:42:"lib/sfPropelActAsRatableBehavior.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:121:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableBehavior.class.php";}s:46:"test/unit/sfPropelActAsRatableBehaviorTest.php";a:4:{s:6:"md5sum";s:32:"b182cfb2c0de38164c575a698cf96383";s:4:"name";s:46:"test/unit/sfPropelActAsRatableBehaviorTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:125:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/test/unit/sfPropelActAsRatableBehaviorTest.php";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"a2d16633aab60e6528d9138a7cec9d2d";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:86:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/LICENSE";}s:6:"README";a:4:{s:6:"md5sum";s:32:"9684d658dcf82a467d67a36264fa97c2";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:85:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/README";}}s:12:"_lastversion";N;s:7:"dirtree";a:8:{s:85:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/config";b:1;s:92:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/map";b:1;s:88:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model";b:1;s:82:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib";b:1;s:91:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om";b:1;s:88:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/test/unit";b:1;s:83:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin/test";b:1;s:78:"/home/olepw/workspace/deich_reaktor/plugins/sfPropelActAsRatableBehaviorPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"0.5.0";s:12:"release_date";s:10:"2007-09-05";s:13:"release_state";s:4:"beta";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.1.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:17:"Nicolas Perriault";s:5:"email";s:20:"nperriault@gmail.com";s:6:"active";s:3:"yes";s:6:"handle";s:7:"nicolas";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1205753930;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfpropelactastaggablebehaviorplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfpropelactastaggablebehaviorplugin.reg new file mode 100644 index 0000000..f5f525e --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfpropelactastaggablebehaviorplugin.reg @@ -0,0 +1,9 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.4.9";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:35:"sfPropelActAsTaggableBehaviorPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:24:"Propel taggable behavior";s:11:"description";s:126:"This behavior permits to attach tags to Propel objects. It includes tag-clouds generation and helpers to display these clouds.";s:4:"lead";a:4:{s:4:"name";s:12:"Xavier Lacot";s:4:"user";s:6:"xavier";s:5:"email";s:16:"xavier@lacot.org";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-12-11";s:4:"time";s:8:"10:57:29";s:7:"version";a:2:{s:7:"release";s:5:"0.4.0";s:3:"api";s:5:"0.4.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:82:"* added machine tags support (also called "triple tags") (thanks to Michael Nolan)";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:12:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"be086e5bb0f860ebe638605e517a81c3";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"217f1a0d881b8030899b90be06b6d566";s:4:"name";s:17:"config/schema.yml";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1d2a70f67daf386e9dc99eee8a1a4ee0";s:4:"name";s:25:"lib/helper/TagsHelper.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"79bc793fc277c89c40f70d473993ebe6";s:4:"name";s:17:"lib/model/Tag.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d69ba5a606d39ec6f9d524b13a016f78";s:4:"name";s:21:"lib/model/Tagging.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"21fc5a0fcf74ca5506845e1944488c80";s:4:"name";s:25:"lib/model/TaggingPeer.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3fe7c350bf8511b244a669bba19f065c";s:4:"name";s:21:"lib/model/TagPeer.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d949e9c16f7173681b6e4cf66ed5ba88";s:4:"name";s:43:"lib/sfPropelActAsTaggableBehavior.class.php";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b7465bc92ecfec7438feba359d89a8a2";s:4:"name";s:42:"lib/sfPropelActAsTaggableToolkit.class.php";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"90bc20b2dabe7b20c8d26edbe70295f5";s:4:"name";s:47:"test/unit/sfPropelActAsTaggableBehaviorTest.php";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ffa0182fd708913b6afb91cdabf82cda";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c82aac9ad4c11c37161927f67a00e637";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.0.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";a:1:{s:7:"release";a:4:{i:0;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.4.0";s:3:"api";s:5:"0.4.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2007-12-11";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:82:"* added machine tags support (also called "triple tags") (thanks to Michael Nolan)";}i:1;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.3.0";s:3:"api";s:5:"0.3.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2007-07-02";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:60:"* fixed bug in tags removal (thanks to Alexander Alexandrov)";}i:2;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.2.0";s:3:"api";s:5:"0.2.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2007-06-27";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:88:"* indexes on tags model +* bugfixes +* thanks to Nicolas Perriault for his useful comments";}i:3;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"0.1.0";s:3:"api";s:5:"0.1.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:4:"date";s:10:"2007-05-21";s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:174:"Initial public release + * add/remove tag(s) on an object + * multi-tags object search + * multi-models selection + * tag cloud generation + * related tags handling + * unit-tested";}}}s:8:"filelist";a:12:{s:17:"config/config.php";a:4:{s:6:"md5sum";s:32:"be086e5bb0f860ebe638605e517a81c3";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";s:12:"installed_as";s:97:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/config/config.php";}s:17:"config/schema.yml";a:4:{s:6:"md5sum";s:32:"217f1a0d881b8030899b90be06b6d566";s:4:"name";s:17:"config/schema.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:97:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/config/schema.yml";}s:25:"lib/helper/TagsHelper.php";a:4:{s:6:"md5sum";s:32:"1d2a70f67daf386e9dc99eee8a1a4ee0";s:4:"name";s:25:"lib/helper/TagsHelper.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/helper/TagsHelper.php";}s:17:"lib/model/Tag.php";a:4:{s:6:"md5sum";s:32:"79bc793fc277c89c40f70d473993ebe6";s:4:"name";s:17:"lib/model/Tag.php";s:4:"role";s:4:"data";s:12:"installed_as";s:97:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tag.php";}s:21:"lib/model/Tagging.php";a:4:{s:6:"md5sum";s:32:"d69ba5a606d39ec6f9d524b13a016f78";s:4:"name";s:21:"lib/model/Tagging.php";s:4:"role";s:4:"data";s:12:"installed_as";s:101:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tagging.php";}s:25:"lib/model/TaggingPeer.php";a:4:{s:6:"md5sum";s:32:"21fc5a0fcf74ca5506845e1944488c80";s:4:"name";s:25:"lib/model/TaggingPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TaggingPeer.php";}s:21:"lib/model/TagPeer.php";a:4:{s:6:"md5sum";s:32:"3fe7c350bf8511b244a669bba19f065c";s:4:"name";s:21:"lib/model/TagPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:101:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TagPeer.php";}s:43:"lib/sfPropelActAsTaggableBehavior.class.php";a:4:{s:6:"md5sum";s:32:"d949e9c16f7173681b6e4cf66ed5ba88";s:4:"name";s:43:"lib/sfPropelActAsTaggableBehavior.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:123:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableBehavior.class.php";}s:42:"lib/sfPropelActAsTaggableToolkit.class.php";a:4:{s:6:"md5sum";s:32:"b7465bc92ecfec7438feba359d89a8a2";s:4:"name";s:42:"lib/sfPropelActAsTaggableToolkit.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:122:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableToolkit.class.php";}s:47:"test/unit/sfPropelActAsTaggableBehaviorTest.php";a:4:{s:6:"md5sum";s:32:"90bc20b2dabe7b20c8d26edbe70295f5";s:4:"name";s:47:"test/unit/sfPropelActAsTaggableBehaviorTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:127:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/test/unit/sfPropelActAsTaggableBehaviorTest.php";}s:6:"README";a:4:{s:6:"md5sum";s:32:"ffa0182fd708913b6afb91cdabf82cda";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:86:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"c82aac9ad4c11c37161927f67a00e637";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:87:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:7:{s:86:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/config";b:1;s:90:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/helper";b:1;s:83:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib";b:1;s:89:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model";b:1;s:89:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/test/unit";b:1;s:84:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin/test";b:1;s:79:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfPropelActAsTaggableBehaviorPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"0.4.0";s:12:"release_date";s:10:"2007-12-11";s:13:"release_state";s:4:"beta";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:82:"* added machine tags support (also called "triple tags") (thanks to Michael Nolan)";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.0.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:12:"Xavier Lacot";s:5:"email";s:16:"xavier@lacot.org";s:6:"active";s:3:"yes";s:6:"handle";s:6:"xavier";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1201779864;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfpropelalternativeschemaplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfpropelalternativeschemaplugin.reg new file mode 100644 index 0000000..3f3eca6 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfpropelalternativeschemaplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.5.4";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:148:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:31:"sfPropelAlternativeSchemaPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:57:"Alternative propel schema syntax for customizable schemas";s:11:"description";s:361:"This plugin extends the symfony model generator, based on Propel, to allow a schema to override another one. It also provides a new YAML syntax for defining database schemas, more explicit and more readable. This new syntax is completely backward compatible with symfony's current `schema.yml` syntax, so installing this plugin will not break your applications.";s:4:"lead";a:4:{s:4:"name";s:18:"Francois Zaninotto";s:4:"user";s:10:"fzaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-10-18";s:4:"time";s:8:"09:59:10";s:7:"version";a:2:{s:7:"release";s:5:"1.0.0";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:9:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"778f07aefe891d83883ae4a4b60b6a9e";s:4:"name";s:36:"lib/sfPropelDatabaseSchema.class.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c835b41128bf7db6bf9370220a891fc5";s:4:"name";s:34:"lib/SfAlternativeObjectBuilder.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c82e4e7d70c77cebdc19bf4dbd24f48e";s:4:"name";s:32:"lib/SfAlternativePeerBuilder.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"832c9ceb016a1e9aa442f53e883a5bb7";s:4:"name";s:33:"test/unit/fixtures/new_schema.yml";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8fc1e43dabdb7ca3a868549b9768c887";s:4:"name";s:29:"test/unit/fixtures/schema.yml";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7273d7e119309fdd16d22da2eb647ad1";s:4:"name";s:29:"test/unit/fixtures/schema.xml";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"687a0e32547177d2302958c77d410147";s:4:"name";s:40:"test/unit/sfPropelDatabaseSchemaTest.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"595ab8ec0ec3aaae766a4bca0bc02cb8";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"83b34726672b35ee4dd82f5d7fea127d";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.0.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:9:{s:36:"lib/sfPropelDatabaseSchema.class.php";a:4:{s:6:"md5sum";s:32:"778f07aefe891d83883ae4a4b60b6a9e";s:4:"name";s:36:"lib/sfPropelDatabaseSchema.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\lib\sfPropelDatabaseSchema.class.php";}s:34:"lib/SfAlternativeObjectBuilder.php";a:4:{s:6:"md5sum";s:32:"c835b41128bf7db6bf9370220a891fc5";s:4:"name";s:34:"lib/SfAlternativeObjectBuilder.php";s:4:"role";s:4:"data";s:12:"installed_as";s:106:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\lib\SfAlternativeObjectBuilder.php";}s:32:"lib/SfAlternativePeerBuilder.php";a:4:{s:6:"md5sum";s:32:"c82e4e7d70c77cebdc19bf4dbd24f48e";s:4:"name";s:32:"lib/SfAlternativePeerBuilder.php";s:4:"role";s:4:"data";s:12:"installed_as";s:104:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\lib\SfAlternativePeerBuilder.php";}s:33:"test/unit/fixtures/new_schema.yml";a:4:{s:6:"md5sum";s:32:"832c9ceb016a1e9aa442f53e883a5bb7";s:4:"name";s:33:"test/unit/fixtures/new_schema.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\test\unit\fixtures\new_schema.yml";}s:29:"test/unit/fixtures/schema.yml";a:4:{s:6:"md5sum";s:32:"8fc1e43dabdb7ca3a868549b9768c887";s:4:"name";s:29:"test/unit/fixtures/schema.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:101:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\test\unit\fixtures\schema.yml";}s:29:"test/unit/fixtures/schema.xml";a:4:{s:6:"md5sum";s:32:"7273d7e119309fdd16d22da2eb647ad1";s:4:"name";s:29:"test/unit/fixtures/schema.xml";s:4:"role";s:4:"data";s:12:"installed_as";s:101:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\test\unit\fixtures\schema.xml";}s:40:"test/unit/sfPropelDatabaseSchemaTest.php";a:4:{s:6:"md5sum";s:32:"687a0e32547177d2302958c77d410147";s:4:"name";s:40:"test/unit/sfPropelDatabaseSchemaTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:112:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\test\unit\sfPropelDatabaseSchemaTest.php";}s:6:"README";a:4:{s:6:"md5sum";s:32:"595ab8ec0ec3aaae766a4bca0bc02cb8";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:78:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"83b34726672b35ee4dd82f5d7fea127d";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:5:{s:75:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\lib";b:1;s:71:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin";b:1;s:90:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\test\unit\fixtures";b:1;s:81:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\test\unit";b:1;s:76:"C:\Users\Russ\workspace\reaktor\plugins\sfPropelAlternativeSchemaPlugin\test";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.0.0";s:12:"release_date";s:10:"2007-10-18";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.0.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:18:"Francois Zaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:10:"fzaninotto";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1205928643;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfrecaptchaplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfrecaptchaplugin.reg new file mode 100644 index 0000000..d2dd0ff --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfrecaptchaplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.7.1";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:17:"sfReCaptchaPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:43:"Integrates the reCAPTCHA service in symfony";s:11:"description";s:39:"Integrates reCAPTCHA service in symfony";s:4:"lead";a:4:{s:4:"name";s:13:"Arthur Koziel";s:4:"user";s:12:"arthurkoziel";s:5:"email";s:23:"arthur@arthurkoziel.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2008-05-04";s:4:"time";s:8:"19:25:33";s:7:"version";a:2:{s:7:"release";s:5:"1.0.4";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:9:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"66c8581370ad4665a20f1e1afd8eea06";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"134760c2721f9e0749d24a71c3c09af4";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d5c9e8dd05f35f978887c63a1e9a00dd";s:4:"name";s:20:"lib/recaptchalib.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9a5ee441f94332df33dd4a350e83d135";s:4:"name";s:34:"lib/sfReCaptchaValidator.class.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0f6b973f43adb8fc7e23fb70e7bd4738";s:4:"name";s:30:"lib/helper/recaptchaHelper.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"56236a7f6b578f1b92718f53bba73fc6";s:4:"name";s:43:"modules/recaptcha/actions/actions.class.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b42be3bd1b8f552d73dcb27f1992bb78";s:4:"name";s:44:"modules/recaptcha/templates/indexSuccess.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5c6360688de8ecde58a419c249d105fc";s:4:"name";s:47:"modules/recaptcha/templates/mailhideSuccess.php";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"03177fb2165b108bd89db25a23388963";s:4:"name";s:36:"modules/recaptcha/validate/index.yml";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.0.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:9:{s:6:"README";a:4:{s:6:"md5sum";s:32:"66c8581370ad4665a20f1e1afd8eea06";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:55:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"134760c2721f9e0749d24a71c3c09af4";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:56:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/LICENSE";}s:20:"lib/recaptchalib.php";a:4:{s:6:"md5sum";s:32:"d5c9e8dd05f35f978887c63a1e9a00dd";s:4:"name";s:20:"lib/recaptchalib.php";s:4:"role";s:4:"data";s:12:"installed_as";s:69:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/lib/recaptchalib.php";}s:34:"lib/sfReCaptchaValidator.class.php";a:4:{s:6:"md5sum";s:32:"9a5ee441f94332df33dd4a350e83d135";s:4:"name";s:34:"lib/sfReCaptchaValidator.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/lib/sfReCaptchaValidator.class.php";}s:30:"lib/helper/recaptchaHelper.php";a:4:{s:6:"md5sum";s:32:"0f6b973f43adb8fc7e23fb70e7bd4738";s:4:"name";s:30:"lib/helper/recaptchaHelper.php";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/lib/helper/recaptchaHelper.php";}s:43:"modules/recaptcha/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"56236a7f6b578f1b92718f53bba73fc6";s:4:"name";s:43:"modules/recaptcha/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:92:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules/recaptcha/actions/actions.class.php";}s:44:"modules/recaptcha/templates/indexSuccess.php";a:4:{s:6:"md5sum";s:32:"b42be3bd1b8f552d73dcb27f1992bb78";s:4:"name";s:44:"modules/recaptcha/templates/indexSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules/recaptcha/templates/indexSuccess.php";}s:47:"modules/recaptcha/templates/mailhideSuccess.php";a:4:{s:6:"md5sum";s:32:"5c6360688de8ecde58a419c249d105fc";s:4:"name";s:47:"modules/recaptcha/templates/mailhideSuccess.php";s:4:"role";s:4:"data";s:12:"installed_as";s:96:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules/recaptcha/templates/mailhideSuccess.php";}s:36:"modules/recaptcha/validate/index.yml";a:4:{s:6:"md5sum";s:32:"03177fb2165b108bd89db25a23388963";s:4:"name";s:36:"modules/recaptcha/validate/index.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:85:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules/recaptcha/validate/index.yml";}}s:12:"_lastversion";N;s:7:"dirtree";a:8:{s:48:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin";b:1;s:52:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/lib";b:1;s:59:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/lib/helper";b:1;s:74:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules/recaptcha/actions";b:1;s:66:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules/recaptcha";b:1;s:56:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules";b:1;s:76:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules/recaptcha/templates";b:1;s:75:"/crypto/linpro/reaktor/plugins/sfReCaptchaPlugin/modules/recaptcha/validate";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.0.4";s:12:"release_date";s:10:"2008-05-04";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.0.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:13:"Arthur Koziel";s:5:"email";s:23:"arthur@arthurkoziel.com";s:6:"active";s:3:"yes";s:6:"handle";s:12:"arthurkoziel";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1217318616;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfsimplecmsplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfsimplecmsplugin.reg new file mode 100644 index 0000000..058a57d --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfsimplecmsplugin.reg @@ -0,0 +1,13 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.6.2";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:17:"sfSimpleCMSPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:50:"Simple Content Management System (CMS) for symfony";s:11:"description";s:634:"This plugin allows you to add a simple Content Management System (CMS) to your symfony application with the following features: + - Uses Javascript and Ajax to provide a neat user experience + - Edit zones in pages + - Edit page URL (you can use / in page path) + - Edit content in the real context ('edit in place') + - Preview result + - Create and manage a tree structure for pages + - i18n ready (the interface is translated) + - l10n ready (a page can have different versions) + - support multiple templates + - Basic publication workflow + - Breadcrumb navigation + - User management is controlled through [wiki:sfGuardPlugin]";s:4:"lead";a:4:{s:4:"name";s:18:"Francois Zaninotto";s:4:"user";s:10:"fzaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2008-02-28";s:4:"time";s:8:"08:51:10";s:7:"version";a:2:{s:7:"release";s:5:"0.7.3";s:3:"api";s:5:"0.7.3";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:65:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"37314471619a1f968134d398baba5664";s:4:"name";s:21:"config/app.yml.sample";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"077e5c4dec283e565088ccb346d6618a";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"54ce432bd3667df08d60374016594bc8";s:4:"name";s:17:"config/schema.yml";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b15b2486e640170449348187f33a277f";s:4:"name";s:27:"data/fixtures/test_data.yml";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"333628e56e198d9ab4c78168e9953a65";s:4:"name";s:32:"lib/helper/sfSimpleCMSHelper.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a66b1871a802e058e8ea4b4fa06847f9";s:4:"name";s:43:"lib/model/map/sfSimpleCMSSlotMapBuilder.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f1b2a1aff75cf89301cac7d0444d81b5";s:4:"name";s:43:"lib/model/map/sfSimpleCMSPageMapBuilder.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9e3c6523e2d13b6471882a9c7c4f146b";s:4:"name";s:36:"lib/model/om/BasesfSimpleCMSPage.php";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"000cf920faadaa3ebdb55f7adc6e814c";s:4:"name";s:40:"lib/model/om/BasesfSimpleCMSPagePeer.php";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"479223faeee5cca8f26c7745601a2de9";s:4:"name";s:36:"lib/model/om/BasesfSimpleCMSSlot.php";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"91fe7e2b65bf3d8cbbbc858ee6894c32";s:4:"name";s:40:"lib/model/om/BasesfSimpleCMSSlotPeer.php";s:4:"role";s:4:"data";}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3da52ae6e22a0b4b12af5729a6844b42";s:4:"name";s:29:"lib/model/sfSimpleCMSPage.php";s:4:"role";s:4:"data";}}i:12;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6c2bff184e39af22eac7972c5ba49435";s:4:"name";s:33:"lib/model/sfSimpleCMSPagePeer.php";s:4:"role";s:4:"data";}}i:13;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a683f72754c0bee547d9e9789879b132";s:4:"name";s:29:"lib/model/sfSimpleCMSSlot.php";s:4:"role";s:4:"data";}}i:14;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5b3a1ef19a62aa125cfaa21b5526e9b1";s:4:"name";s:33:"lib/model/sfSimpleCMSSlotPeer.php";s:4:"role";s:4:"data";}}i:15;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"42cb80cfa8b021963b58db648d05888c";s:4:"name";s:43:"lib/slotType/sfSimpleCMSSlotImage.class.php";s:4:"role";s:4:"data";}}i:16;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4c008a52ccaa602ee8111d440a295218";s:4:"name";s:45:"lib/slotType/sfSimpleCMSSlotModular.class.php";s:4:"role";s:4:"data";}}i:17;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"76c3946085df1ba7eedd193becb12852";s:4:"name";s:41:"lib/slotType/sfSimpleCMSSlotPhp.class.php";s:4:"role";s:4:"data";}}i:18;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"554d3d03fd891ff2af75ff02286c54f6";s:4:"name";s:46:"lib/slotType/sfSimpleCMSSlotRichText.class.php";s:4:"role";s:4:"data";}}i:19;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"17f0e3da7dcd396f53a3d32f202e2ca1";s:4:"name";s:42:"lib/slotType/sfSimpleCMSSlotText.class.php";s:4:"role";s:4:"data";}}i:20;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ff0ff18c98623dd28fad878f9898da92";s:4:"name";s:45:"lib/slotType/sfSimpleCMSSlotTypeInterface.php";s:4:"role";s:4:"data";}}i:21;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6bb09d01dba9db978181897d5c38f571";s:4:"name";s:30:"lib/sfSimpleCMSTools.class.php";s:4:"role";s:4:"data";}}i:22;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"5a15524cfaac71be04c0c1feed267d23";s:4:"name";s:45:"modules/sfSimpleCMS/actions/actions.class.php";s:4:"role";s:4:"data";}}i:23;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"28b3d736a78cdec9d73561b19be731bd";s:4:"name";s:48:"modules/sfSimpleCMS/actions/components.class.php";s:4:"role";s:4:"data";}}i:24;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0ea8116beb9d58cc65e59f7d70256222";s:4:"name";s:56:"modules/sfSimpleCMS/lib/BasesfSimpleCMSActions.class.php";s:4:"role";s:4:"data";}}i:25;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"68bd7f46fee30d17083d3793487e68af";s:4:"name";s:59:"modules/sfSimpleCMS/lib/BasesfSimpleCMSComponents.class.php";s:4:"role";s:4:"data";}}i:26;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0e06b5418d6d931bc6024fc23332e649";s:4:"name";s:46:"modules/sfSimpleCMS/templates/homeTemplate.php";s:4:"role";s:4:"data";}}i:27;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a5ff349b864034288b502ed6c14718d2";s:4:"name";s:40:"modules/sfSimpleCMS/templates/layout.php";s:4:"role";s:4:"data";}}i:28;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"74554c20edf70126161f2ddc9b7cdc33";s:4:"name";s:52:"modules/sfSimpleCMS/templates/simplePageTemplate.php";s:4:"role";s:4:"data";}}i:29;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"92b1ef55b6fcccfa1b8bae7326a8a3cb";s:4:"name";s:45:"modules/sfSimpleCMS/templates/_breadcrumb.php";s:4:"role";s:4:"data";}}i:30;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a5d85ffab5336ece265a9b8e5939fb80";s:4:"name";s:46:"modules/sfSimpleCMS/templates/_editorTools.php";s:4:"role";s:4:"data";}}i:31;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e8d9b380cae9bb0e4c50f89872dd0e19";s:4:"name";s:40:"modules/sfSimpleCMS/templates/_embed.php";s:4:"role";s:4:"data";}}i:32;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"96b4dad63c42feef7debd5ec033c5c62";s:4:"name";s:46:"modules/sfSimpleCMS/templates/_latestPages.php";s:4:"role";s:4:"data";}}i:33;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a1d41f3914b69d5bf6d869f8057a1d15";s:4:"name";s:49:"modules/sfSimpleCMS/templates/_mainNavigation.php";s:4:"role";s:4:"data";}}i:34;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"431f4a3b0c0972fccd517705bd9799a3";s:4:"name";s:39:"modules/sfSimpleCMS/validate/create.yml";s:4:"role";s:4:"data";}}i:35;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ee9e3a24bb2aa155879881f2b28d9952";s:4:"name";s:39:"modules/sfSimpleCMS/validate/update.yml";s:4:"role";s:4:"data";}}i:36;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1d4a99e5c3c5ef0a170d45a3d8cfcea1";s:4:"name";s:50:"modules/sfSimpleCMSAdmin/actions/actions.class.php";s:4:"role";s:4:"data";}}i:37;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4c80e4acb119490274291ebed5e9ceac";s:4:"name";s:45:"modules/sfSimpleCMSAdmin/config/generator.yml";s:4:"role";s:4:"data";}}i:38;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"94a313f624b2948366972bb046abecde";s:4:"name";s:66:"modules/sfSimpleCMSAdmin/lib/BasesfSimpleCMSAdminActions.class.php";s:4:"role";s:4:"data";}}i:39;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"484ea8f78b81c8a0a4626a41c7d57402";s:4:"name";s:52:"modules/sfSimpleCMSAdmin/templates/_is_published.php";s:4:"role";s:4:"data";}}i:40;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"14148afa18e0eaf0efbef6f9d6d454bf";s:4:"name";s:51:"modules/sfSimpleCMSAdmin/templates/_list_footer.php";s:4:"role";s:4:"data";}}i:41;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e635647677306812438e039252cb4c69";s:4:"name";s:53:"modules/sfSimpleCMSAdmin/templates/_localizations.php";s:4:"role";s:4:"data";}}i:42;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ba6165fb7c5b1da054d348321c8fd568";s:4:"name";s:45:"modules/sfSimpleCMSAdmin/validate/addPage.yml";s:4:"role";s:4:"data";}}i:43;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"14487fff8033f89b3301338017e351a0";s:4:"name";s:26:"web/css/CMSEditorTools.css";s:4:"role";s:4:"data";}}i:44;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e6abcebfff62f601ed8398e13c96ab1f";s:4:"name";s:24:"web/css/CMSTemplates.css";s:4:"role";s:4:"data";}}i:45;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2161618f547a2c1239d32810bfa85f0b";s:4:"name";s:36:"web/images/application_form_edit.png";s:4:"role";s:4:"data";}}i:46;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f483e9d22444dd5c246372e3aa97e1bc";s:4:"name";s:34:"web/images/bullet_toggle_minus.png";s:4:"role";s:4:"data";}}i:47;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"82672a640296b7c9aa5d9bc73be05e36";s:4:"name";s:33:"web/images/bullet_toggle_plus.png";s:4:"role";s:4:"data";}}i:48;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2bc754cc7b7e0a43910765e9f84c701f";s:4:"name";s:29:"web/images/cms_toolbox_bg.gif";s:4:"role";s:4:"data";}}i:49;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1199d1d15d5276efccbe9c7ac6b89fa6";s:4:"name";s:30:"web/images/cms_toolbox_bg1.gif";s:4:"role";s:4:"data";}}i:50;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"046a717fd44e63a44045f4761a12ee0c";s:4:"name";s:36:"web/images/cms_toolbox_header_bg.gif";s:4:"role";s:4:"data";}}i:51;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"97176626eef35c7beb4f05a850325042";s:4:"name";s:30:"web/images/page_white_edit.png";s:4:"role";s:4:"data";}}i:52;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ceac7fe99a67b541c9b65eb6fd2dfdb7";s:4:"name";s:33:"web/images/page_white_magnify.png";s:4:"role";s:4:"data";}}i:53;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0da66bdb013f9a9d12ce7219e642bc25";s:4:"name";s:30:"web/images/page_white_text.png";s:4:"role";s:4:"data";}}i:54;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"58aa38a653b4024727f123ccf79fd570";s:4:"name";s:24:"web/images/tab_right.png";s:4:"role";s:4:"data";}}i:55;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a623c1ba71612765a0b700845ae81208";s:4:"name";s:29:"web/images/symfony_button.gif";s:4:"role";s:4:"data";}}i:56;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"dd1368e1ec45e02df603fc8f1eb09fac";s:4:"name";s:22:"web/images/head_bg.gif";s:4:"role";s:4:"data";}}i:57;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"56b8c6daf858d5d02ab826bb39a90d49";s:4:"name";s:21:"web/images/nav_bg.gif";s:4:"role";s:4:"data";}}i:58;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"7d788e412b63e2bbf1b5202fa8f5560c";s:4:"name";s:26:"web/images/nav-item_bg.gif";s:4:"role";s:4:"data";}}i:59;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"479fcb41f08a74f0446040099294c1ce";s:4:"name";s:29:"web/images/coffee_machine.png";s:4:"role";s:4:"data";}}i:60;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2bbd576de75178c086507625b662091e";s:4:"name";s:25:"web/js/cookies_handler.js";s:4:"role";s:4:"data";}}i:61;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"3b7cf0f6307e43f81cb90cfed06aa7fa";s:4:"name";s:21:"web/js/editorTools.js";s:4:"role";s:4:"data";}}i:62;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c41fdd0e2b39f290c2de0b4c94692867";s:4:"name";s:23:"web/js/tiny_mce_AJAX.js";s:4:"role";s:4:"data";}}i:63;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"870052400d8268831de3244e6d15f444";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}i:64;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"d067180cd27190e553f61b60e2e72956";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.1.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:65:{s:21:"config/app.yml.sample";a:4:{s:6:"md5sum";s:32:"37314471619a1f968134d398baba5664";s:4:"name";s:21:"config/app.yml.sample";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/config/app.yml.sample";}s:17:"config/config.php";a:4:{s:6:"md5sum";s:32:"077e5c4dec283e565088ccb346d6618a";s:4:"name";s:17:"config/config.php";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/config/config.php";}s:17:"config/schema.yml";a:4:{s:6:"md5sum";s:32:"54ce432bd3667df08d60374016594bc8";s:4:"name";s:17:"config/schema.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:79:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/config/schema.yml";}s:27:"data/fixtures/test_data.yml";a:4:{s:6:"md5sum";s:32:"b15b2486e640170449348187f33a277f";s:4:"name";s:27:"data/fixtures/test_data.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:89:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/data/fixtures/test_data.yml";}s:32:"lib/helper/sfSimpleCMSHelper.php";a:4:{s:6:"md5sum";s:32:"333628e56e198d9ab4c78168e9953a65";s:4:"name";s:32:"lib/helper/sfSimpleCMSHelper.php";s:4:"role";s:4:"data";s:12:"installed_as";s:94:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/helper/sfSimpleCMSHelper.php";}s:43:"lib/model/map/sfSimpleCMSSlotMapBuilder.php";a:4:{s:6:"md5sum";s:32:"a66b1871a802e058e8ea4b4fa06847f9";s:4:"name";s:43:"lib/model/map/sfSimpleCMSSlotMapBuilder.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/map/sfSimpleCMSSlotMapBuilder.php";}s:43:"lib/model/map/sfSimpleCMSPageMapBuilder.php";a:4:{s:6:"md5sum";s:32:"f1b2a1aff75cf89301cac7d0444d81b5";s:4:"name";s:43:"lib/model/map/sfSimpleCMSPageMapBuilder.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/map/sfSimpleCMSPageMapBuilder.php";}s:36:"lib/model/om/BasesfSimpleCMSPage.php";a:4:{s:6:"md5sum";s:32:"9e3c6523e2d13b6471882a9c7c4f146b";s:4:"name";s:36:"lib/model/om/BasesfSimpleCMSPage.php";s:4:"role";s:4:"data";s:12:"installed_as";s:98:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/om/BasesfSimpleCMSPage.php";}s:40:"lib/model/om/BasesfSimpleCMSPagePeer.php";a:4:{s:6:"md5sum";s:32:"000cf920faadaa3ebdb55f7adc6e814c";s:4:"name";s:40:"lib/model/om/BasesfSimpleCMSPagePeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:102:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/om/BasesfSimpleCMSPagePeer.php";}s:36:"lib/model/om/BasesfSimpleCMSSlot.php";a:4:{s:6:"md5sum";s:32:"479223faeee5cca8f26c7745601a2de9";s:4:"name";s:36:"lib/model/om/BasesfSimpleCMSSlot.php";s:4:"role";s:4:"data";s:12:"installed_as";s:98:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/om/BasesfSimpleCMSSlot.php";}s:40:"lib/model/om/BasesfSimpleCMSSlotPeer.php";a:4:{s:6:"md5sum";s:32:"91fe7e2b65bf3d8cbbbc858ee6894c32";s:4:"name";s:40:"lib/model/om/BasesfSimpleCMSSlotPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:102:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/om/BasesfSimpleCMSSlotPeer.php";}s:29:"lib/model/sfSimpleCMSPage.php";a:4:{s:6:"md5sum";s:32:"3da52ae6e22a0b4b12af5729a6844b42";s:4:"name";s:29:"lib/model/sfSimpleCMSPage.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/sfSimpleCMSPage.php";}s:33:"lib/model/sfSimpleCMSPagePeer.php";a:4:{s:6:"md5sum";s:32:"6c2bff184e39af22eac7972c5ba49435";s:4:"name";s:33:"lib/model/sfSimpleCMSPagePeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:95:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/sfSimpleCMSPagePeer.php";}s:29:"lib/model/sfSimpleCMSSlot.php";a:4:{s:6:"md5sum";s:32:"a683f72754c0bee547d9e9789879b132";s:4:"name";s:29:"lib/model/sfSimpleCMSSlot.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/sfSimpleCMSSlot.php";}s:33:"lib/model/sfSimpleCMSSlotPeer.php";a:4:{s:6:"md5sum";s:32:"5b3a1ef19a62aa125cfaa21b5526e9b1";s:4:"name";s:33:"lib/model/sfSimpleCMSSlotPeer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:95:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/sfSimpleCMSSlotPeer.php";}s:43:"lib/slotType/sfSimpleCMSSlotImage.class.php";a:4:{s:6:"md5sum";s:32:"42cb80cfa8b021963b58db648d05888c";s:4:"name";s:43:"lib/slotType/sfSimpleCMSSlotImage.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/slotType/sfSimpleCMSSlotImage.class.php";}s:45:"lib/slotType/sfSimpleCMSSlotModular.class.php";a:4:{s:6:"md5sum";s:32:"4c008a52ccaa602ee8111d440a295218";s:4:"name";s:45:"lib/slotType/sfSimpleCMSSlotModular.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/slotType/sfSimpleCMSSlotModular.class.php";}s:41:"lib/slotType/sfSimpleCMSSlotPhp.class.php";a:4:{s:6:"md5sum";s:32:"76c3946085df1ba7eedd193becb12852";s:4:"name";s:41:"lib/slotType/sfSimpleCMSSlotPhp.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:103:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/slotType/sfSimpleCMSSlotPhp.class.php";}s:46:"lib/slotType/sfSimpleCMSSlotRichText.class.php";a:4:{s:6:"md5sum";s:32:"554d3d03fd891ff2af75ff02286c54f6";s:4:"name";s:46:"lib/slotType/sfSimpleCMSSlotRichText.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/slotType/sfSimpleCMSSlotRichText.class.php";}s:42:"lib/slotType/sfSimpleCMSSlotText.class.php";a:4:{s:6:"md5sum";s:32:"17f0e3da7dcd396f53a3d32f202e2ca1";s:4:"name";s:42:"lib/slotType/sfSimpleCMSSlotText.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:104:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/slotType/sfSimpleCMSSlotText.class.php";}s:45:"lib/slotType/sfSimpleCMSSlotTypeInterface.php";a:4:{s:6:"md5sum";s:32:"ff0ff18c98623dd28fad878f9898da92";s:4:"name";s:45:"lib/slotType/sfSimpleCMSSlotTypeInterface.php";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/slotType/sfSimpleCMSSlotTypeInterface.php";}s:30:"lib/sfSimpleCMSTools.class.php";a:4:{s:6:"md5sum";s:32:"6bb09d01dba9db978181897d5c38f571";s:4:"name";s:30:"lib/sfSimpleCMSTools.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:92:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/sfSimpleCMSTools.class.php";}s:45:"modules/sfSimpleCMS/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"5a15524cfaac71be04c0c1feed267d23";s:4:"name";s:45:"modules/sfSimpleCMS/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/actions/actions.class.php";}s:48:"modules/sfSimpleCMS/actions/components.class.php";a:4:{s:6:"md5sum";s:32:"28b3d736a78cdec9d73561b19be731bd";s:4:"name";s:48:"modules/sfSimpleCMS/actions/components.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:110:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/actions/components.class.php";}s:56:"modules/sfSimpleCMS/lib/BasesfSimpleCMSActions.class.php";a:4:{s:6:"md5sum";s:32:"0ea8116beb9d58cc65e59f7d70256222";s:4:"name";s:56:"modules/sfSimpleCMS/lib/BasesfSimpleCMSActions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:118:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/lib/BasesfSimpleCMSActions.class.php";}s:59:"modules/sfSimpleCMS/lib/BasesfSimpleCMSComponents.class.php";a:4:{s:6:"md5sum";s:32:"68bd7f46fee30d17083d3793487e68af";s:4:"name";s:59:"modules/sfSimpleCMS/lib/BasesfSimpleCMSComponents.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:121:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/lib/BasesfSimpleCMSComponents.class.php";}s:46:"modules/sfSimpleCMS/templates/homeTemplate.php";a:4:{s:6:"md5sum";s:32:"0e06b5418d6d931bc6024fc23332e649";s:4:"name";s:46:"modules/sfSimpleCMS/templates/homeTemplate.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates/homeTemplate.php";}s:40:"modules/sfSimpleCMS/templates/layout.php";a:4:{s:6:"md5sum";s:32:"a5ff349b864034288b502ed6c14718d2";s:4:"name";s:40:"modules/sfSimpleCMS/templates/layout.php";s:4:"role";s:4:"data";s:12:"installed_as";s:102:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates/layout.php";}s:52:"modules/sfSimpleCMS/templates/simplePageTemplate.php";a:4:{s:6:"md5sum";s:32:"74554c20edf70126161f2ddc9b7cdc33";s:4:"name";s:52:"modules/sfSimpleCMS/templates/simplePageTemplate.php";s:4:"role";s:4:"data";s:12:"installed_as";s:114:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates/simplePageTemplate.php";}s:45:"modules/sfSimpleCMS/templates/_breadcrumb.php";a:4:{s:6:"md5sum";s:32:"92b1ef55b6fcccfa1b8bae7326a8a3cb";s:4:"name";s:45:"modules/sfSimpleCMS/templates/_breadcrumb.php";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates/_breadcrumb.php";}s:46:"modules/sfSimpleCMS/templates/_editorTools.php";a:4:{s:6:"md5sum";s:32:"a5d85ffab5336ece265a9b8e5939fb80";s:4:"name";s:46:"modules/sfSimpleCMS/templates/_editorTools.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates/_editorTools.php";}s:40:"modules/sfSimpleCMS/templates/_embed.php";a:4:{s:6:"md5sum";s:32:"e8d9b380cae9bb0e4c50f89872dd0e19";s:4:"name";s:40:"modules/sfSimpleCMS/templates/_embed.php";s:4:"role";s:4:"data";s:12:"installed_as";s:102:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates/_embed.php";}s:46:"modules/sfSimpleCMS/templates/_latestPages.php";a:4:{s:6:"md5sum";s:32:"96b4dad63c42feef7debd5ec033c5c62";s:4:"name";s:46:"modules/sfSimpleCMS/templates/_latestPages.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates/_latestPages.php";}s:49:"modules/sfSimpleCMS/templates/_mainNavigation.php";a:4:{s:6:"md5sum";s:32:"a1d41f3914b69d5bf6d869f8057a1d15";s:4:"name";s:49:"modules/sfSimpleCMS/templates/_mainNavigation.php";s:4:"role";s:4:"data";s:12:"installed_as";s:111:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates/_mainNavigation.php";}s:39:"modules/sfSimpleCMS/validate/create.yml";a:4:{s:6:"md5sum";s:32:"431f4a3b0c0972fccd517705bd9799a3";s:4:"name";s:39:"modules/sfSimpleCMS/validate/create.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:101:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/validate/create.yml";}s:39:"modules/sfSimpleCMS/validate/update.yml";a:4:{s:6:"md5sum";s:32:"ee9e3a24bb2aa155879881f2b28d9952";s:4:"name";s:39:"modules/sfSimpleCMS/validate/update.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:101:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/validate/update.yml";}s:50:"modules/sfSimpleCMSAdmin/actions/actions.class.php";a:4:{s:6:"md5sum";s:32:"1d4a99e5c3c5ef0a170d45a3d8cfcea1";s:4:"name";s:50:"modules/sfSimpleCMSAdmin/actions/actions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:112:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/actions/actions.class.php";}s:45:"modules/sfSimpleCMSAdmin/config/generator.yml";a:4:{s:6:"md5sum";s:32:"4c80e4acb119490274291ebed5e9ceac";s:4:"name";s:45:"modules/sfSimpleCMSAdmin/config/generator.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/config/generator.yml";}s:66:"modules/sfSimpleCMSAdmin/lib/BasesfSimpleCMSAdminActions.class.php";a:4:{s:6:"md5sum";s:32:"94a313f624b2948366972bb046abecde";s:4:"name";s:66:"modules/sfSimpleCMSAdmin/lib/BasesfSimpleCMSAdminActions.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:128:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/lib/BasesfSimpleCMSAdminActions.class.php";}s:52:"modules/sfSimpleCMSAdmin/templates/_is_published.php";a:4:{s:6:"md5sum";s:32:"484ea8f78b81c8a0a4626a41c7d57402";s:4:"name";s:52:"modules/sfSimpleCMSAdmin/templates/_is_published.php";s:4:"role";s:4:"data";s:12:"installed_as";s:114:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/templates/_is_published.php";}s:51:"modules/sfSimpleCMSAdmin/templates/_list_footer.php";a:4:{s:6:"md5sum";s:32:"14148afa18e0eaf0efbef6f9d6d454bf";s:4:"name";s:51:"modules/sfSimpleCMSAdmin/templates/_list_footer.php";s:4:"role";s:4:"data";s:12:"installed_as";s:113:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/templates/_list_footer.php";}s:53:"modules/sfSimpleCMSAdmin/templates/_localizations.php";a:4:{s:6:"md5sum";s:32:"e635647677306812438e039252cb4c69";s:4:"name";s:53:"modules/sfSimpleCMSAdmin/templates/_localizations.php";s:4:"role";s:4:"data";s:12:"installed_as";s:115:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/templates/_localizations.php";}s:45:"modules/sfSimpleCMSAdmin/validate/addPage.yml";a:4:{s:6:"md5sum";s:32:"ba6165fb7c5b1da054d348321c8fd568";s:4:"name";s:45:"modules/sfSimpleCMSAdmin/validate/addPage.yml";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/validate/addPage.yml";}s:26:"web/css/CMSEditorTools.css";a:4:{s:6:"md5sum";s:32:"14487fff8033f89b3301338017e351a0";s:4:"name";s:26:"web/css/CMSEditorTools.css";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/css/CMSEditorTools.css";}s:24:"web/css/CMSTemplates.css";a:4:{s:6:"md5sum";s:32:"e6abcebfff62f601ed8398e13c96ab1f";s:4:"name";s:24:"web/css/CMSTemplates.css";s:4:"role";s:4:"data";s:12:"installed_as";s:86:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/css/CMSTemplates.css";}s:36:"web/images/application_form_edit.png";a:4:{s:6:"md5sum";s:32:"2161618f547a2c1239d32810bfa85f0b";s:4:"name";s:36:"web/images/application_form_edit.png";s:4:"role";s:4:"data";s:12:"installed_as";s:98:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/application_form_edit.png";}s:34:"web/images/bullet_toggle_minus.png";a:4:{s:6:"md5sum";s:32:"f483e9d22444dd5c246372e3aa97e1bc";s:4:"name";s:34:"web/images/bullet_toggle_minus.png";s:4:"role";s:4:"data";s:12:"installed_as";s:96:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/bullet_toggle_minus.png";}s:33:"web/images/bullet_toggle_plus.png";a:4:{s:6:"md5sum";s:32:"82672a640296b7c9aa5d9bc73be05e36";s:4:"name";s:33:"web/images/bullet_toggle_plus.png";s:4:"role";s:4:"data";s:12:"installed_as";s:95:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/bullet_toggle_plus.png";}s:29:"web/images/cms_toolbox_bg.gif";a:4:{s:6:"md5sum";s:32:"2bc754cc7b7e0a43910765e9f84c701f";s:4:"name";s:29:"web/images/cms_toolbox_bg.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/cms_toolbox_bg.gif";}s:30:"web/images/cms_toolbox_bg1.gif";a:4:{s:6:"md5sum";s:32:"1199d1d15d5276efccbe9c7ac6b89fa6";s:4:"name";s:30:"web/images/cms_toolbox_bg1.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:92:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/cms_toolbox_bg1.gif";}s:36:"web/images/cms_toolbox_header_bg.gif";a:4:{s:6:"md5sum";s:32:"046a717fd44e63a44045f4761a12ee0c";s:4:"name";s:36:"web/images/cms_toolbox_header_bg.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:98:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/cms_toolbox_header_bg.gif";}s:30:"web/images/page_white_edit.png";a:4:{s:6:"md5sum";s:32:"97176626eef35c7beb4f05a850325042";s:4:"name";s:30:"web/images/page_white_edit.png";s:4:"role";s:4:"data";s:12:"installed_as";s:92:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/page_white_edit.png";}s:33:"web/images/page_white_magnify.png";a:4:{s:6:"md5sum";s:32:"ceac7fe99a67b541c9b65eb6fd2dfdb7";s:4:"name";s:33:"web/images/page_white_magnify.png";s:4:"role";s:4:"data";s:12:"installed_as";s:95:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/page_white_magnify.png";}s:30:"web/images/page_white_text.png";a:4:{s:6:"md5sum";s:32:"0da66bdb013f9a9d12ce7219e642bc25";s:4:"name";s:30:"web/images/page_white_text.png";s:4:"role";s:4:"data";s:12:"installed_as";s:92:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/page_white_text.png";}s:24:"web/images/tab_right.png";a:4:{s:6:"md5sum";s:32:"58aa38a653b4024727f123ccf79fd570";s:4:"name";s:24:"web/images/tab_right.png";s:4:"role";s:4:"data";s:12:"installed_as";s:86:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/tab_right.png";}s:29:"web/images/symfony_button.gif";a:4:{s:6:"md5sum";s:32:"a623c1ba71612765a0b700845ae81208";s:4:"name";s:29:"web/images/symfony_button.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/symfony_button.gif";}s:22:"web/images/head_bg.gif";a:4:{s:6:"md5sum";s:32:"dd1368e1ec45e02df603fc8f1eb09fac";s:4:"name";s:22:"web/images/head_bg.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:84:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/head_bg.gif";}s:21:"web/images/nav_bg.gif";a:4:{s:6:"md5sum";s:32:"56b8c6daf858d5d02ab826bb39a90d49";s:4:"name";s:21:"web/images/nav_bg.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/nav_bg.gif";}s:26:"web/images/nav-item_bg.gif";a:4:{s:6:"md5sum";s:32:"7d788e412b63e2bbf1b5202fa8f5560c";s:4:"name";s:26:"web/images/nav-item_bg.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/nav-item_bg.gif";}s:29:"web/images/coffee_machine.png";a:4:{s:6:"md5sum";s:32:"479fcb41f08a74f0446040099294c1ce";s:4:"name";s:29:"web/images/coffee_machine.png";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images/coffee_machine.png";}s:25:"web/js/cookies_handler.js";a:4:{s:6:"md5sum";s:32:"2bbd576de75178c086507625b662091e";s:4:"name";s:25:"web/js/cookies_handler.js";s:4:"role";s:4:"data";s:12:"installed_as";s:87:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/js/cookies_handler.js";}s:21:"web/js/editorTools.js";a:4:{s:6:"md5sum";s:32:"3b7cf0f6307e43f81cb90cfed06aa7fa";s:4:"name";s:21:"web/js/editorTools.js";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/js/editorTools.js";}s:23:"web/js/tiny_mce_AJAX.js";a:4:{s:6:"md5sum";s:32:"c41fdd0e2b39f290c2de0b4c94692867";s:4:"name";s:23:"web/js/tiny_mce_AJAX.js";s:4:"role";s:4:"data";s:12:"installed_as";s:85:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/js/tiny_mce_AJAX.js";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"870052400d8268831de3244e6d15f444";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:69:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/LICENSE";}s:6:"README";a:4:{s:6:"md5sum";s:32:"d067180cd27190e553f61b60e2e72956";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:68:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/README";}}s:12:"_lastversion";N;s:7:"dirtree";a:26:{s:68:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/config";b:1;s:75:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/data/fixtures";b:1;s:66:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/data";b:1;s:72:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/helper";b:1;s:65:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib";b:1;s:75:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/map";b:1;s:71:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model";b:1;s:74:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/model/om";b:1;s:74:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/lib/slotType";b:1;s:89:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/actions";b:1;s:81:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS";b:1;s:69:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules";b:1;s:85:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/lib";b:1;s:91:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/templates";b:1;s:90:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMS/validate";b:1;s:94:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/actions";b:1;s:86:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin";b:1;s:93:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/config";b:1;s:90:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/lib";b:1;s:96:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/templates";b:1;s:95:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/modules/sfSimpleCMSAdmin/validate";b:1;s:69:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/css";b:1;s:65:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web";b:1;s:72:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/images";b:1;s:68:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin/web/js";b:1;s:61:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfSimpleCMSPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"0.7.3";s:12:"release_date";s:10:"2008-02-28";s:13:"release_state";s:4:"beta";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.1.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:18:"Francois Zaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:10:"fzaninotto";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1214898703;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfthumbnailplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfthumbnailplugin.reg new file mode 100644 index 0000000..e5d9f30 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfthumbnailplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:5:"1.6.1";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:17:"sfThumbnailPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:37:"symfony thumbnail generation support.";s:11:"description";s:37:"symfony thumbnail generation support.";s:4:"lead";a:4:{s:4:"name";s:16:"Fabien POTENCIER";s:4:"user";s:6:"fabpot";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-10-13";s:4:"time";s:8:"16:38:44";s:7:"version";a:2:{s:7:"release";s:5:"1.5.0";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:5:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ade44239bce430f61f7c0c8cd1ce89b0";s:4:"name";s:25:"lib/sfThumbnail.class.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ea7aec8b4be6212af8434f65efa85a69";s:4:"name";s:25:"lib/sfGDAdapter.class.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"add9e55ed76cc8d607b11bf2a4704aea";s:4:"name";s:34:"lib/sfImageMagickAdapter.class.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c5de5dccc5785beae22f92424d51cad6";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"c0ab88a4687e9ff8e0fb6c95ca49ed74";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.0.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"1.0.0";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:5:{s:25:"lib/sfThumbnail.class.php";a:4:{s:6:"md5sum";s:32:"ade44239bce430f61f7c0c8cd1ce89b0";s:4:"name";s:25:"lib/sfThumbnail.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfThumbnailPlugin/lib/sfThumbnail.class.php";}s:25:"lib/sfGDAdapter.class.php";a:4:{s:6:"md5sum";s:32:"ea7aec8b4be6212af8434f65efa85a69";s:4:"name";s:25:"lib/sfGDAdapter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfThumbnailPlugin/lib/sfGDAdapter.class.php";}s:34:"lib/sfImageMagickAdapter.class.php";a:4:{s:6:"md5sum";s:32:"add9e55ed76cc8d607b11bf2a4704aea";s:4:"name";s:34:"lib/sfImageMagickAdapter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:97:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfThumbnailPlugin/lib/sfImageMagickAdapter.class.php";}s:6:"README";a:4:{s:6:"md5sum";s:32:"c5de5dccc5785beae22f92424d51cad6";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:69:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfThumbnailPlugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"c0ab88a4687e9ff8e0fb6c95ca49ed74";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:70:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfThumbnailPlugin/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:2:{s:66:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfThumbnailPlugin/lib";b:1;s:62:"/crypto/home/Russ Flynn/sfprojects/reaktor/plugins/sfThumbnailPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.5.0";s:12:"release_date";s:10:"2007-10-13";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.0.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.0.0";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:16:"Fabien POTENCIER";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:6:"fabpot";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1202140197;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/sfwebbrowserplugin.reg b/plugins/.registry/.channel.pear.symfony-project.com/sfwebbrowserplugin.reg new file mode 100644 index 0000000..c2fc2ac --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/sfwebbrowserplugin.reg @@ -0,0 +1 @@ +a:22:{s:7:"attribs";a:6:{s:15:"packagerversion";s:6:"1.4.11";s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:18:"sfWebBrowserPlugin";s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:22:"Standalone HTTP client";s:11:"description";s:129:"The sfWebBrowserPlugin proposes an HTTP client capable of making web requests. The interface is similar to that of sfTestBrowser.";s:4:"lead";a:4:{s:4:"name";s:19:"François Zaninotto";s:4:"user";s:10:"fzaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2007-03-27";s:4:"time";s:8:"08:00:24";s:7:"version";a:2:{s:7:"release";s:5:"1.0.1";s:3:"api";s:5:"1.0.1";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:6:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"a9d52e4906863ed3a405b68597d2aba0";s:4:"name";s:26:"lib/sfWebBrowser.class.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"2a3ac092173e6d304cfc560555398e77";s:4:"name";s:28:"lib/sfFopenAdapter.class.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"cfdca311866b0293c03ffcd569e19e29";s:4:"name";s:27:"lib/sfCurlAdapter.class.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"77965c7cadbd5e2ef2f008934dd7e216";s:4:"name";s:30:"lib/sfSocketsAdapter.class.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6b53ff0d3d5eba2cb6b02c72ede003f0";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"feca6d513f7eadaf6002fe0b62c629c3";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:3:{s:3:"php";a:1:{s:3:"min";s:5:"5.1.0";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}s:7:"package";a:5:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:3:"min";s:5:"0.8.1";s:3:"max";s:5:"1.1.0";s:7:"exclude";s:5:"1.1.0";}}}s:10:"phprelease";s:0:"";s:9:"changelog";s:0:"";s:8:"filelist";a:6:{s:26:"lib/sfWebBrowser.class.php";a:4:{s:6:"md5sum";s:32:"a9d52e4906863ed3a405b68597d2aba0";s:4:"name";s:26:"lib/sfWebBrowser.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:89:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php";}s:28:"lib/sfFopenAdapter.class.php";a:4:{s:6:"md5sum";s:32:"2a3ac092173e6d304cfc560555398e77";s:4:"name";s:28:"lib/sfFopenAdapter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:91:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfWebBrowserPlugin/lib/sfFopenAdapter.class.php";}s:27:"lib/sfCurlAdapter.class.php";a:4:{s:6:"md5sum";s:32:"cfdca311866b0293c03ffcd569e19e29";s:4:"name";s:27:"lib/sfCurlAdapter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:90:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php";}s:30:"lib/sfSocketsAdapter.class.php";a:4:{s:6:"md5sum";s:32:"77965c7cadbd5e2ef2f008934dd7e216";s:4:"name";s:30:"lib/sfSocketsAdapter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:93:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfWebBrowserPlugin/lib/sfSocketsAdapter.class.php";}s:6:"README";a:4:{s:6:"md5sum";s:32:"6b53ff0d3d5eba2cb6b02c72ede003f0";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:69:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfWebBrowserPlugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"feca6d513f7eadaf6002fe0b62c629c3";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:70:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfWebBrowserPlugin/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:2:{s:66:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfWebBrowserPlugin/lib";b:1;s:62:"/home/dae/.reaktorworkspace/Reaktor/plugins/sfWebBrowserPlugin";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.0.1";s:12:"release_date";s:10:"2007-03-27";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:4:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.1.0";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}i:2;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"le";s:7:"version";s:5:"1.1.0";s:8:"optional";s:2:"no";}i:3;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"name";s:7:"symfony";s:3:"rel";s:2:"ge";s:7:"version";s:5:"0.8.1";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:19:"François Zaninotto";s:5:"email";s:38:"francois.zaninotto@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:10:"fzaninotto";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1216284297;} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/symfony.reg b/plugins/.registry/.channel.pear.symfony-project.com/symfony.reg new file mode 100644 index 0000000..2cd29c9 --- /dev/null +++ b/plugins/.registry/.channel.pear.symfony-project.com/symfony.reg @@ -0,0 +1,3 @@ +a:9:{s:4:"name";s:7:"symfony";s:7:"channel";s:24:"pear.symfony-project.com";s:4:"date";s:10:"2008-07-29";s:4:"time";s:8:"08:03:35";s:7:"version";a:2:{s:7:"release";s:7:"1.0.18 +";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1217318615;s:3:"old";a:2:{s:7:"version";s:7:"1.0.18 +";s:13:"release_state";s:6:"stable";}} \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/LICENSE b/plugins/dwJpgraphPlugin/LICENSE new file mode 100644 index 0000000..523e923 --- /dev/null +++ b/plugins/dwJpgraphPlugin/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +The JPGRAPH library is licensed under THE Q PUBLIC LICENSE version 1.0, please see lib/jpgraph/QPL.txt for more information. \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/README b/plugins/dwJpgraphPlugin/README new file mode 100644 index 0000000..1d774a5 --- /dev/null +++ b/plugins/dwJpgraphPlugin/README @@ -0,0 +1,23 @@ += dwJpgraphPlugin = + +The `dwJpgraphPlugin` provides abstraction for the PHP Jpgraph library. + +== Installation == + + * Install the plugin + + {{{ + symfony plugin-install http://plugins.symfony-project.org/dwJpgraphPlugin + }}} + + * Clear you cache + + {{{ + symfony cc + }}} + + * You're done. + +== Using the plugin == + +See the example module/action: dwJpgraphPlugin/test. \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/QPL.txt b/plugins/dwJpgraphPlugin/lib/jpgraph/QPL.txt new file mode 100644 index 0000000..66986cb --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/QPL.txt @@ -0,0 +1,119 @@ +THE Q PUBLIC LICENSE version 1.0 + +Copyright (C) 1999 Trolltech AS, Norway. + Everyone is permitted to copy and + distribute this license document. + +The intent of this license is to establish freedom to share and change +the software regulated by this license under the open source model. + +This license applies to any software containing a notice placed by the +copyright holder saying that it may be distributed under the terms of +the Q Public License version 1.0. Such software is herein referred to +as the Software. This license covers modification and distribution of +the Software, use of third-party application programs based on the +Software, and development of free software which uses the Software. + + +Granted Rights + +1. You are granted the non-exclusive rights set forth in this license + provided you agree to and comply with any and all conditions in + this license. Whole or partial distribution of the Software, or + software items that link with the Software, in any form signifies + acceptance of this license. + + +2. You may copy and distribute the Software in unmodified form + provided that the entire package, including - but not restricted to + - copyright, trademark notices and disclaimers, as released by the + initial developer of the Software, is distributed. + + +3. You may make modifications to the Software and distribute your + modifications, in a form that is separate from the Software, such + as patches. The following restrictions apply to modifications: + + a. Modifications must not alter or remove any copyright notices in the + Software. + + b. When modifications to the Software are released under this license, + a non-exclusive royalty-free right is granted to the initial developer + of the Software to distribute your modification in future versions of + the Software provided such versions remain available under these terms + in addition to any other license(s) of the initial developer. + + +4. You may distribute machine-executable forms of the Software or + machine-executable forms of modified versions of the Software, + provided that you meet these restrictions: + + a. You must include this license document in the distribution. + + b. You must ensure that all recipients of the machine-executable forms + are also able to receive the complete machine-readable source code to + the distributed Software, including all modifications, without any + charge beyond the costs of data transfer, and place prominent notices + in the distribution explaining this. + + c. You must ensure that all modifications included in the + machine-executable forms are available under the terms of this + license. + + +5. You may use the original or modified versions of the Software to + compile, link and run application programs legally developed by you + or by others. + + +6. You may develop application programs, reusable components and other + software items that link with the original or modified versions of + the Software. These items, when distributed, are subject to the + following requirements: + + + + a. You must ensure that all recipients of machine-executable forms of + these items are also able to receive and use the complete + machine-readable source code to the items without any charge beyond + the costs of data transfer. + + + b. You must explicitly license all recipients of your items to use and + re-distribute original and modified versions of the items in both + machine-executable and source code forms. The recipients must be able + to do so without any charges whatsoever, and they must be able to + re-distribute to anyone they choose. + + + c. If the items are not available to the general public, and the + initial developer of the Software requests a copy of the items, then + you must supply one. + + +Limitations of Liability + +In no event shall the initial developers or copyright holders be +liable for any damages whatsoever, including - but not restricted to - +lost revenue or profits or other direct, indirect, special, incidental +or consequential damages, even if they have been advised of the +possibility of such damages, except to the extent invariable law, if +any, provides otherwise. + + +No Warranty + +The Software and this license document are provided AS IS with NO +WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + + +Choice of Law + +This license is governed by the Laws of Norway. Disputes shall be +settled by Oslo City Court. + + + + + diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/flags.dat b/plugins/dwJpgraphPlugin/lib/jpgraph/flags.dat new file mode 100644 index 0000000..1cd2e72 Binary files /dev/null and b/plugins/dwJpgraphPlugin/lib/jpgraph/flags.dat differ diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb100x100.dat b/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb100x100.dat new file mode 100644 index 0000000..545e7ad Binary files /dev/null and b/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb100x100.dat differ diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb35x35.dat b/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb35x35.dat new file mode 100644 index 0000000..7335011 Binary files /dev/null and b/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb35x35.dat differ diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb60x60.dat b/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb60x60.dat new file mode 100644 index 0000000..6107d08 Binary files /dev/null and b/plugins/dwJpgraphPlugin/lib/jpgraph/flags_thumb60x60.dat differ diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_balls.inc b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_balls.inc new file mode 100644 index 0000000..cb1bb0a --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_balls.inc @@ -0,0 +1,1061 @@ + 'imgdata_large', + MARK_IMG_MBALL => 'imgdata_small', + MARK_IMG_SBALL => 'imgdata_xsmall', + MARK_IMG_BALL => 'imgdata_xsmall'); + protected $colors,$index,$maxidx; + private $colors_1 = array('blue','lightblue','brown','darkgreen', + 'green','purple','red','gray','yellow','silver','gray'); + private $index_1 = array('blue'=>9,'lightblue'=>1,'brown'=>6,'darkgreen'=>7, + 'green'=>8,'purple'=>4,'red'=>0,'gray'=>5,'silver'=>3,'yellow'=>2); + private $maxidx_1 = 9 ; + + private $colors_2 = array('blue','bluegreen','brown','cyan', + 'darkgray','greengray','gray','green', + 'greenblue','lightblue','lightred', + 'purple','red','white','yellow'); + + + private $index_2 = array('blue'=>9,'bluegreen'=>13,'brown'=>8,'cyan'=>12, + 'darkgray'=>5,'greengray'=>6,'gray'=>2,'green'=>10, + 'greenblue'=>3,'lightblue'=>1,'lightred'=>14, + 'purple'=>7,'red'=>0,'white'=>11,'yellow'=>4); + + private $maxidx_2 = 14 ; + + + private $colors_3 = array('bluegreen','cyan','darkgray','greengray', + 'gray','graypurple','green','greenblue','lightblue', + 'lightred','navy','orange','purple','red','yellow'); + + private $index_3 = array('bluegreen'=>1,'cyan'=>11,'darkgray'=>14,'greengray'=>10, + 'gray'=>3,'graypurple'=>4,'green'=>9,'greenblue'=>7, + 'lightblue'=>13,'lightred'=>0,'navy'=>2,'orange'=>12, + 'purple'=>8,'red'=>5,'yellow'=>6); + private $maxidx_3 = 14 ; + + protected $imgdata_large, $imgdata_small, $imgdata_xsmall ; + + + function GetImg($aMark,$aIdx) { + switch( $aMark ) { + case MARK_IMG_SBALL: + case MARK_IMG_BALL: + $this->colors = $this->colors_3; + $this->index = $this->index_3 ; + $this->maxidx = $this->maxidx_3 ; + break; + case MARK_IMG_MBALL: + $this->colors = $this->colors_2; + $this->index = $this->index_2 ; + $this->maxidx = $this->maxidx_2 ; + break; + default: + $this->colors = $this->colors_1; + $this->index = $this->index_1 ; + $this->maxidx = $this->maxidx_1 ; + break; + } + return parent::GetImg($aMark,$aIdx); + } + + function ImgData_Balls() { + +//========================================================== +// File: bl_red.png +//========================================================== + $this->imgdata_large[0][0]= 1072 ; + $this->imgdata_large[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAByF'. + 'BMVEX/////////xsb/vb3/lIz/hIT/e3v/c3P/c2v/a2v/Y2P/'. + 'UlL/Skr/SkL/Qjn/MTH/MSn/KSn/ISH/IRj/GBj/GBD/EBD/EA'. + 'j/CAj/CAD/AAD3QkL3MTH3KSn3KSH3GBj3EBD3CAj3AAD1zMzv'. + 'QkLvISHvIRjvGBjvEBDvEAjvAADnUlLnSkrnMTnnKSnnIRjnGB'. + 'DnEBDnCAjnAADec3PeSkreISHeGBjeGBDeEAjWhITWa2vWUlLW'. + 'SkrWISnWGBjWEBDWEAjWCAjWAADOnp7Oa2vOGCHOGBjOGBDOEB'. + 'DOCAjOAADJrq7Gt7fGGBjGEBDGCAjGAADEpKS/v7+9QkK9GBC9'. + 'EBC9CAi9AAC1e3u1a2u1Skq1KSm1EBC1CAi1AACtEBCtCBCtCA'. + 'itAACngYGlCAilAACghIScOTmcCAicAACYgYGUGAiUCAiUAAiU'. + 'AACMKSmMEACMAACEa2uEGAiEAAB7GBh7CAB7AABzOTlzGBBzCA'. + 'BzAABrSkprOTlrGBhrAABjOTljAABaQkJaOTlaCABaAABSKSlS'. + 'GBhSAABKKSlKGBhKAABCGBhCCABCAAA5CAA5AAAxCAAxAAApCA'. + 'ApAAAhAAAYAACc9eRyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFD'. + 'UHLytKAAAB4UlEQVR4nGNgIAK4mGjrmNq6BmFIWMmISUpKSmk5'. + 'B8ZEokj4qoiLiQCBgqald3xaBpKMj6y4sLCQkJCIvIaFV0RaUR'. + 'lCSk5cWEiAn19ASN7QwisuraihHiajKyEixM/NwckjoKrvEACU'. + 'qumpg7pAUlREiJdNmZmLT9/cMzwps7Smc3I2WEpGUkxYkJuFiY'. + 'lTxszePzY1v7Shc2oX2D+K4iLCgjzsrOw8embuYUmZeTVtPVOn'. + 'gqSslYAOF+Ln4ZHWtXMPTcjMrWno7J82rRgoZWOsqaCgrqaqqm'. + 'fn5peQmlsK1DR52vRaoFSIs5GRoYG5ub27n19CYm5pdVPnxKnT'. + 'pjWDpLydnZwcHTz8QxMSEnJLgDL9U6dNnQ6Sio4PDAgICA+PTU'. + 'zNzSkph8hADIxKS46Pj0tKTc3MLSksqWrtmQySAjuDIT8rKy0r'. + 'Kz+vtLSmur6jb9JUIJgGdjxDQUVRUVFpaUVNQ1NrZ9+kKVOmTZ'. + 'k6vR0sldJUAwQNTU2dnX0TgOJTQLrSIYFY2dPW1NbW2TNxwtQp'. + 'U6ZMmjJt2rRGWNB3TO7vnzh5MsgSoB6gy7sREdY7bRrQEDAGOb'. + 'wXOQW0TJsOEpwClmxBTTbZ7UDVIPkp7dkYaYqhuLa5trYYUxwL'. + 'AADzm6uekAAcXAAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bl_bluegreen.png +//========================================================== + $this->imgdata_large[1][0]= 1368 ; + $this->imgdata_large[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMMFi8hE9b2uAAABOVJREFUeNq9lk2sJFUVx3+3qv'. + 'tW95t57zFvhiFxmCFRUJRoNCQiJARMhiFx/Igxii5goTG6ZDAu'. + '/EhcSCIrTAgLEiKsJ8ywABNZEMJXEDYCukAmjgjzBkK/j35V1d'. + '333FtV97io97pfzwxfG86qcu/N+Z3zP+fcW/Apmfk4hx57+R/6'. + 'Rqmc9ykhsWjlsUngAA1fXIQ7b73pI/186IGHnn9dH/8frC8v4I'. + 'PiG53uaerR4GmKkv31mB8cyfjd946ZTwR66qVX9OTWIi8UKUv9'. + 'BOrZXpYZvFeiBvzI0fgSUSFKwbVG+Pl1V3HH0VvNR4KeeukV/f'. + 'PmMmdHhst76aXD64AbeVQ9bjNHaiGOC2o3wLrAb2/4LL/84ffn'. + 'fCdzkOdayKpLppBemrBsU5Y1Zdmm9LJdGU6E/t4M24Q26jRDRL'. + 'j3mdc49cSTekFsMzs5XuTsyLDUNSDQ25NwKOly9YIl22MYhJr/'. + 'uoDtBBoT0CxBRGYOAhibIaOCe//2MpfM6KHnX9cXipSlbkKWmS'. + 'nk9iv38J0jixw7vJfrTMYBOvhSoQHJBS09ANELloAGDxW8tfoW'. + 'J+5/UC8CPS0LU7r3SpYarr7M8rmFjMPLXT6/33L4si7Z2GCrQC'. + '+0ctlOaNs9DReV8vSLr85ndPLpZ/WNvHW+01kAVFBOGvJx0wYg'. + 'Sp47RIQ4Emwa8FGJXlDxSCFo5YlVgAo2hwPue/hRndboTV3EW2'. + 'Wp3k6wBp8q56QiWzecW6vwQfnPRkAWhFgILnq08jQ+R2nlUzzN'. + 'uES9Q7Vd+9fba7NmWJW61db2247qACmcjxXr45psYphsFGSLBu'. + 'kIajxqtjNwHkvAjQt0sg3crhPA2+fPz0CuyNFOghsGsr19mnFg'. + 'DGwrRm8UoAtNmQPQtRXDgdC4HImCFEKcCE0oieUWUYq2LtbiGp'. + 'mBQmppfIkjw45DK0QNNkvQ0jMBtPL0UnDRM1rN+cxKwzvOo2NP'. + 'tykR9a1kfpZNDLMG6QDYJqCTBvUe1+uxs+YKyPoGrTwY2HhvC4'. + 'CDWQd5d4xNApNQEEMgjgLdUCLBQ5cprL/trwNwKG2IUmDqDFd5'. + 'sr5BWrlxuSdLDFEFlqAzXGc4zFjupqh6uqYihpxJcEgp026l2w'. + '7wFUv7Z6AvrfRo/n0OYzPwIKE3HUKAJg2otMBiElnsF7wngis9'. + '3ZDjNnLi7huCWUZfueZKTu/M0V3HvmkOFDVxVKDG04ScejSgW5'. + 'V0q5JYFEghuDLHlTmToqDeGOCKIVtrW9hsdmXufEcNLPSXuPHa'. + 'a+bvuh9df5AH/v5PDFmbWQC3Mx+TVvfGVTRB2CodNgT2JBX003'. + 'aANZAYS/BxCv32TV/l2C03G7jgmfjGiT/qmeEmibEYm7XzAO2k'. + 'A+pbgHhBgydqu54YO5eRiLCy7yDvPP6Xqf+5Z+Lu277OYuOpiw'. + 'H15oBmlNOMcmK5RbP+PrEscGU+DSAxdg4CICIkxnLP8aNz63Og'. + 'H3/rdvOb795GVhuaYo0oBc3GGrEsUPVTwO6a7LYd+X51x3Hu/t'. + 'lP5tS65FN+6okn9U+n/sqb596dTvhOF+02myXTmkQNrOw7yD3H'. + 'j14E+UDQjp24/0E9/eKrbA4HH3aMK1b2ccvXvswjv//1J/s5ud'. + 'Due/hRPfP+OmfOrk7vrn7a48ihA3zh8CH+8Iuffiw/n4r9H1ZZ'. + '0zz7G56hAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bl_yellow.png +//========================================================== + $this->imgdata_large[2][0]= 1101 ; + $this->imgdata_large[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. + 'BMVEX//////////+///+f//9b//8b//73//7X//63//6X//5T/'. + '/4z//4T//3P//2v//1r//0r//0L//zH//yn//yH//xj//xD//w'. + 'j//wD/90L/9zn/9zH/9xj/9xD/9wj/9wD39yn37zn37zH37yH3'. + '7xD37wj37wDv70Lv50rv50Lv5znv5yHv5xjv5wjv5wDn51Ln5x'. + 'Dn3jHn3iHn3hjn3hDn3gje3oze3nPe3lLe1oze1nPe1lLe1ine'. + '1iHe1hje1hDe1gje1gDW1qXW1mvWzqXWzkLWzhjWzhDWzgjWzg'. + 'DOzrXOzq3OzpzOzgDOxkrOxinOxhjOxhDOxgjOxgDGxqXGxnvG'. + 'xmvGvRjGvRDGvQjGvQDFxbnAvr6/v7+9vaW9vZS9vQi9vQC9tR'. + 'C9tQi9tQC7u7W1tZS1tXu1tTG1tQi1rRC1rQi1rQCtrYytrSGt'. + 'rQitrQCtpYStpSGtpQitpQClpYSlpXulpQClnBClnAilnACcnG'. + 'ucnAicnACclAiclACUlFqUlCmUlAiUlACUjFKUjAiUjACMjFKM'. + 'jEqMjACMhACEhACEewB7ezF7exB7ewB7cwBzcylzcwBzaxBzaw'. + 'BraxhrawhrawBrYxBrYwBjYwBjWgBaWgBaUgCXBwRMAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwkRFBKiJZ4hAAAB7ElEQVR4nI3S+1vS'. + 'UBgHcB67WJmIMWAVdDHEDLBC6Go0slj3Ft0m9RRBWQEmFZFDEM'. + 'Qgt0EMFBY7p/+198hj1kM/9N1+++x73rOd6XT/kStnTx4fPzd9'. + 'uwfOjFhomj7smAhwj/6Cm2O0xUwy6g7cCL99uCW3jtBmE7lsdr'. + 'fvejgpzP7uEDFRRoqy2k8xQPnypo2BUMP6waF9Vpf3ciiSzErL'. + 'XTkPc0zDe3bsHDAcc00yoVgqL3UWN2iENpspff+2vn6D0+NnZ9'. + '6lC5K6RuSqBTZn1O/a3rd7v/MSez+WyIpVFX8GuuCA9SjD4N6B'. + 'oRNTfo5PCAVR0fBXoIuOQzab1XjwwNHx00GOj8/nKtV1DdeArk'. + '24R+0ul9PjmbrHPYl+EipyU0OoQSjg8/m83kl/MMhx0fjCkqio'. + 'SMOE7t4JMAzDsizH81AqSdW2hroLPg4/CEF4PhKNx98vlevrbY'. + 'QQXgV6kXwVfjkTiSXmhYVcSa7DIE1DOENe7GM6lUym0l+EXKks'. + 'K20VAeH2M0JvVgrZfL5Qqkiy0lRVaMBd7H7EZUmsiJJcrTdVja'. + 'wGpdbTLj3/3qwrUOjAfGgg4LnNA5tdQx14Hm00QFBm65hfNzAm'. + '+yIFhFtzuj+z2MI/MQn6Uez5pz4Ua41G7VumB/6RX4zMr1TKBr'. + 'SXAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bl_silver.png +//========================================================== + $this->imgdata_large[3][0]= 1481 ; + $this->imgdata_large[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAADAF'. + 'BMVEUAAADOzs7Gxsa9vb21tbXOxsbOzsbGzsb3///O1ta1vb2c'. + 'paVSWlpKWlpSY2ve5+97hIze7/9aY2vO5/9zhJRaa3tSY3PGzt'. + 'aMlJxrc3tja3NKUlpCSlK1vcZze4RSWmPW5/+Upb3G3v9zhJxS'. + 'Y3t7jKVaa4TO3veltc6ElK1re5Rjc4ycpbV7hJRaY3M5QlLn7/'. + '/Gzt6lrb2EjJzO3v9ja3vG1ve9zu+1xueltdacrc6UpcaMnL1C'. + 'SlqElLV7jK1zhKVre5zW3u/O1ue1vc6ttcaMlKVze4xrc4RSWm'. + 'tKUmPG1v+9zve1xu+tveeltd6crdbe5/+9xt6cpb17hJxaY3s5'. + 'QlrW3vfO1u/Gzue1vdattc6lrcaUnLWMlK2EjKVze5Rrc4xja4'. + 'RSWnNKUmtCSmO9xuecpcZ7hKVaY4TW3v/O1vfGzu+1vd6ttdal'. + 'rc69xu+UnL2MlLWEjK1ze5xrc5R7hK1ja4zO1v+1veettd6lrd'. + 'aMlL3Gzv/39//W1t7Gxs61tb29vcatrbWlpa2cnKWUlJyEhIx7'. + 'e4TW1ufGxta1tcZSUlqcnK3W1u+UlKW9vda1tc57e4ytrcalpb'. + '1ra3vOzu9jY3OUlK29vd6MjKWEhJxaWmtSUmNzc4xKSlpjY3tK'. + 'SmNCQlqUjJzOxs7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'. + 'AAAAAAAAAAAAAAAAAAAAAAAAD///9fnkWVAAAAAnRSTlP/AOW3'. + 'MEoAAAABYktHRP+lB/LFAAAACXBIWXMAAABFAAAARQBP+QatAA'. + 'AB/klEQVR42mNgxAsYqCdd3+lcb4hLmj8wMMvEu8DCMqYbU9op'. + 'UEFB2MTb26eyysomFl06XEEhUCHLpAKo2z/fujikEUVaXUFBMB'. + 'BouLePuV+VVWGRciIXknSEsImCQd3//xwmPr65llaFcSFJHkjS'. + '3iYmWUDZ//8NfCr989NjNUMSUyTg0jneSiaCINn/gmlVQM12qg'. + 'lJnp5waTMTE5NAkCyHWZW/lXWNfUlikmdYK0zax7siS4EDKJtd'. + 'mQeU1XRwLBdLkRGASucWmGVnZ4dnhZvn5lmm29iVOWpnJqcuko'. + 'JKR1Wm5eTkRKYF5eblp9sU2ZeUJiV7zbfVg0pH56UFBQXNjIqK'. + 'jgkujItX1koKTVmYajsdKu2qETVhwgSXiUDZ2Bn9xqUeoZ5e0t'. + 'LzYYZ3B092ndjtOnmKTmycW1s7SHa+l5dtB8zlccE6RlN0dGbM'. + 'mDVbd5KupNBcL6+F82XgHouLj5vRP2PWLGNdd4+ppnxe8tJec6'. + 'XnNsKkm0uVQ5RDRHQTPTym68nPlZbvkfYCexsa5rpJ2qXa5Umm'. + 'ocmec3m8vHjmSs+fgxyhC5JDQ8WSPT2lvbzm8vDIe0nbtiBLN8'. + '8BigNdu1B6Lsje+fPbUFMLi5TMfGmvHi/puUAv23q2YCTFNqH5'. + 'MvPnSwPh3HasCbm3XUpv+nS5VtrkEkwAANSTpGHdye9PAAAASn'. + 'RFWHRzaWduYXR1cmUANGJkODkyYmE4MWZhNTk4MTIyNDJjNjUx'. + 'NzZhY2UxMDAzOGFhZjdhZWIyNzliNTM2ZGFmZDlkM2RiNDU3Zm'. + 'NlNT9CliMAAAAASUVORK5CYII=' ; + +//========================================================== +// File: bl_purple.png +//========================================================== + $this->imgdata_large[4][0]= 1149 ; + $this->imgdata_large[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACAV'. + 'BMVEX/////////7///5///1v//xv//rf//pf//lP//jP//hP//'. + 'c///a///Wv//Wvf/Uv//Sv//Qv//Qvf/Off/Mf//Kf//If//If'. + 'f/GP//GPf/EP//EPf/CP//CPf/CO//AP//APf3Oe/3Kff3Ke/3'. + 'Ie/3GO/3EO/3AO/vSu/vSufvOefvMefvIefvGOfvEOfvCOfvAO'. + 'fnUufnSufnMd7nId7nGN7nGNbnEN7nCN7nAN7ejN7ejNbec97e'. + 'c9beUtbeQtbeIdbeGNbeENbeCNbeANbWpdbWa9bWQs7WGM7WEM'. + '7WCM7WAM7Otc7Orc7OnM7OSsbOIb3OGMbOEMbOCMbOAM7OAMbG'. + 'pcbGnMbGe8bGa8bGKbXGEL3GCL3GAL3FucXBu73AvsC/v7+9pb'. + '29Ka29GLW9ELW9CLW9AL29ALW5rrm1lLW1e7W1MbW1GKW1EK21'. + 'CLW1CK21AK2tjK2thKWtMaWtIaWtGJytCK2tCKWtAK2tAKWlhK'. + 'Wle6WlEJylCJylAKWlAJyca5ycGJScEJScCJScAJycAJSUWpSU'. + 'UoyUKZSUEIyUCIyUAJSUAIyMUoyMSoyMIYSMEISMCISMAIyMAI'. + 'SECHuEAISEAHt7MXt7EHt7CHt7AHt7AHNzKXNzEGtzAHNzAGtr'. + 'GGtrEGNrCGtrAGtrAGNjCFpjAGNjAFpaAFpaAFIpZn4bAAAAAX'. + 'RSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsS'. + 'AdLdfvwAAAAHdElNRQfTAwkRFB0ymoOwAAAB9UlEQVR4nGNgIA'. + 'K42hhqGtm5+WFIWClKycvLK6gbuARGoEj4aMjLSElISUir6Tt7'. + 'x+aEIWR8leQlwEBSTc/CK7awLguuR0lGQkJMVFRUTFJVzwko1d'. + 'oFk9OQl5IQE+Dh5hVR0TV3CkkvbJgyASJjDZIR5GBl5eRX0TH1'. + 'DEqrbJ2ypBEspSgvJSXKw8bMxMavbOLoGZNf1TZlybw4oIyfLN'. + 'BxotxsLEzsQiaOHkFpBQ2905esrAZK2SpIAaUEuDm5+LTNPAKj'. + 'C+pbps1evrIDKGWnLictKSkuLKyoZQyUya9o7Z2+YMXKGUApew'. + 'M9PTVdXR0TEwf3wOjUirruafOXL18xFyjl72Kpb25qaurg4REU'. + 'EFVe2zJ5zpLlK1aCpbydnZ2dnDwDA6NTopLLeiZNXbB8BcTAyP'. + 'TQ0JDg4KCY1NS83JKmiVOBepYvX9UPlAovzEiPSU/LLyior2vq'. + 'mjZr3vLlIF01IC+XVhUWFlZW1Lc290ycOGfxohVATSsXx4Oksn'. + 'vaWlsb2tq6J0+bM2/RohVA81asbIcEYueU3t7JU6ZNnwNyGkhm'. + '+cp5CRCppJnzZ8+ZM3/JUogECBbBIixr8Yqly8FCy8F6ltUgoj'. + 'lz7sqVK2ByK+cVMSCDxoUrwWDVysXt8WhJKqG4Y8bcuTP6qrGk'. + 'QwwAABiMu7T4HMi4AAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bl_gray.png +//========================================================== + $this->imgdata_large[5][0]= 905 ; + $this->imgdata_large[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAABO1'. + 'BMVEX////////3///39/fv7+/e5+fW3t7Wzs7WxsbG1tbGzsbG'. + 'xsbDxMS/v7++wMC+v7+9zsa9xsa9vb29tbW9ra29pa24uLi1xs'. + 'a1vb21tbWxtrattbWmpqalra2cra2cpaWcnJycjIyUpaWUnJyU'. + 'lJSUjIyMnJyMnJSMlJSMlIyMjJSMjIyElJSElIyEjIyEhIR7jI'. + 'x7hIR7hHt7e3t7e3N7e2tzhIRze3tze3Nzc3Nre3trc3Nrc2tr'. + 'a2tjc3Njc2tja3Nja2tjY2NjWlpaa2taY2taY2NaY1paWlpaUl'. + 'JSY2NSY1pSWlpSWlJSUlJSUkpKWlpKWlJKUlpKUlJKUkpKSkpK'. + 'SkJCUlJCUkJCSkpCSkJCQkI5Sko5QkI5Qjk5OUI5OTkxQkIxOT'. + 'kxMTkxMTEpMTEhMTEhKSkYISEpy7AFAAAAAXRSTlMAQObYZgAA'. + 'AAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdE'. + 'lNRQfTAwkRFQfW40uLAAABx0lEQVR4nI3SbXfSMBQA4NV3nce5'. + 'TecAHUywRMHSgFuBCFsQUqwBS1OsWQh0GTj//y8wZUzdwQ/efM'. + 'tzcm/uuXdj4z9ic/PR9k4qk1qDnf0X2/uZzKt8GaRvSubg4LVp'. + 'mkWzCGAT/i3Zsm2XNQHLsm2n2937LaaNnGoJFAEo27B50qN0ay'. + 'Wg26lXsw8fP8nmzcJb2CbsnF5JmmCE8ncN404KvLfsYwd7/MdV'. + 'Pdgl/VbKMIzbuwVgVZw2JlSKJTVJ3609vWUY957lgAUd1KNcqr'. + 'yWnOcOPn8q7d5/8PywAqsOOiVDrn42NFk+HQ7dVuXNYeFdBTpN'. + 'nY5JdZl8xI5Y+HXYaTVqEDp1hAnRohZM03EUjMdhn5wghOoNnD'. + 'wSK7KiiDPqEtz+iD4ctdyAifNYzUnScBSxwPd6GLfRURW7Ay5i'. + 'pS5bmrY8348C5vvUI+TLiIVSJrVA0heK/GDkJxYMRoyfCSmk4s'. + 'uWc3yic/oBo4yF374LGQs5Xw0GyQljI8bYmEsxVUoKxa6HMpAT'. + 'vgyhU2mR8uU1pXmsa8ezqb6U4mwWF/5MeY8uLtQ0nmmQ8UWYvb'. + 'EcJaYWar7QhztrO5Wr4Q4hDbAG/4hfTAF2iCiWrCEAAAAASUVO'. + 'RK5CYII=' ; + +//========================================================== +// File: bl_brown.png +//========================================================== + $this->imgdata_large[6][0]= 1053 ; + $this->imgdata_large[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAABoV'. + 'BMVEX////Gzs7GvbXGrZTGpXu9nHO1nHO1nIy9taXGxs7GtaXO'. + 'nHPGlFrGjEq9hEq1hEqte0Klczmcazmce1KtnIzGxsbGvb3OlF'. + 'LOlFq9hFKte0qcc0KUYzGEWimMc1K9ta3OnGvOnGPWnGO9jFq9'. + 'jFKlc0KUazmMYzl7UilzUjGtpZzGxr3GnGPWpWvepXO1hFJ7Wj'. + 'FrSiFjUjG1ra3GnHPvxpT/5733zpythFKUa0KEYzlzUilaOSF7'. + 'Wjm9jErvvYz/99b///f/78bnrYS1hFqle0p7UjFrSiljQiFCMR'. + 'iMhHO9lGvGjFLWnGv/3q3////erXuthEqlc0paQiFKMRhSQin/'. + '1qX/997//++cc0pjSilaQilKORhCKRiclIy9pYzGlGPntYT33q'. + '3vvZSEWjlSOSE5KRB7c2O1lHutczmthFqte1JrWkqtjGtCKRBa'. + 'SjmljGuca0KMYzGMaznOztaclISUYzmEWjFKOSF7a1qEYzFaSi'. + 'GUjISEa0pKOSm9vb2llIxaQhg5IQiEc2tzY0paORilnJy1raVS'. + 'OSljUkJjWkKTpvQWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkREiei'. + 'zP2EAAAB9UlEQVR4nGWS/VfSUBjHL5QluhhBxtwyWcCus5Blpm'. + 'wDC4ONaWXCyBi7RMZmpQ2Bypm9W/byV3cHHo/W88s95/s5z/d5'. + 'uwCcCh/4L3zAf+bs0NC588On9QAYGSUuBINk6GI4cmnsBLk8Go'. + '1SFEGMkzRzZeLq5JE8FvDHouw1lqXiCZJOcnCKnx4AcP0GBqmZ'. + 'mRgRT9MMB4Wbs7cGSXNRik3dnp9fiMUzNCNKgpzN9bsaWaQo9s'. + '7dfH7pXiFTZCBU1JK27LmtBO8TDx7mV1eXHqXXyiIUFLWiVzHx'. + 'BxcJIvV4/cn6wkqmWOOwmVE3UQOAp6HxRKL5bGPj+VwhUhalFq'. + '8alm5vAt+LlySZTsebzcKrraIIW4JqZC3N3ga+1+EQTZKZta1M'. + 'pCZCSeDViqVrThsEdsLJZLJYLpZrHVGScrKBvTQNtQHY6XIM02'. + 'E6Ik7odRW1Dzy3N28n3kGuB3tQagm7UMBFXI/sATAs7L5vdbEs'. + '8Lycm923NB0j5wMe6KOsKIIyxcuqauxbrmlqyEWfPmPy5assY1'. + 'U1SvWKZWom9nK/HfQ3+v2HYZSMStayTNN0PYKqg11P1nWsWq7u'. + '4gJeY8g9PLrddNXRdW8Iryv86I3ja/9s26gvukhDdvUQnIjlKr'. + 'IdZCNH+3Xw779qbG63f//ZOzb6C4+ofdbzERrSAAAAAElFTkSu'. + 'QmCC' ; + +//========================================================== +// File: bl_darkgreen.png +//========================================================== + $this->imgdata_large[7][0]= 1113 ; + $this->imgdata_large[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAAB2l'. + 'BMVEX////////3///v///n/+/e99bW/+/W99bO786/v7++vr69'. + '/96999a7wb24vbu1/9a1zqW1u7itxrWosq6l772l1qWlxrWlxq'. + '2lva2cxpSU562U3q2UxqWUvaWUpZyM77WM57WMvYyMtZyMrZyM'. + 'pZSMnJSEvZyEtYyErZSElIx7zpR7xpx7xpR7vZR7jIRz1pRzxp'. + 'RzjIRrzpRrzoxrxoxrtYRrrYxrrXtrpYRrhHNjzoxjxoxjxoRj'. + 'vYRjtYRjrXtjpXtjlGNje2tazoxazoRaxoxaxoRavYRatYRatX'. + 'tarXtapXNanHNajFpae2tSzoRSxoRSvXtStXtSrXtSrXNSpXNS'. + 'nHNSnGtSlGtSlGNSjGtSjGNKvXtKtXNKrXNKpWtKnGtKlGNKjG'. + 'NKhGNKhFJKc1pKa1JCrWtCpWtCnGtClGNCjGNCjFpChFpCe1JC'. + 'a1JCY1I5pWs5nGM5lGM5jFo5hFo5e1o5c0o5WkoxjFoxhFoxhF'. + 'Ixe1Ixc1Ixc0oxa0ophFIpe0opc0opa0opa0IpY0IpWkIpWjkp'. + 'UkIpUjkhc0oha0IhY0IhWjkhWjEhUjkhUjEhSjEhSikhQjEhQi'. + 'kYWjkYSjEYSikYQjEYQikQSikQQikQQiEQOSExf8saAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwkRFCaDkWqUAAAB+ElEQVR4nI3S+1vS'. + 'UBgHcGZlPV0ks/vFrmQWFimJjiwiYUJWjFBWFhClyZCy5hLrwA'. + 'x2EIwJC1w7zf2vnU0re+iHvs9++7x7zznvORbLf+TA6ct9fYMX'. + 'jrfAUYefpp+/iM1ykxf/lmuhUZ/PTwXC8dml5Wcd23o5H5Mk6b'. + '5NUU8icXbhS67rNzn9JDnguOEYGQtEEtwC+Crs3RJ76P5A/znr'. + 'vsNX7wQnEiwHCtK7TTkW8rvdZ9uJtvZTLkxpHhSrP66bNEj7/P'. + '3WNoLYeeSWQQCIpe9lQw7RNEU5rDsIYtcJ14Nocg7kRUlBNkxn'. + 'YmGKcp7cv3vPwR7XOJPmc0VYU3Sv0e9NOBAYG7Hbz/cMjTMveZ'. + 'CHkqxuTBv0PhYJB4N3XR6PJ5rMAPMnpGUxDX1IxSeMTEaZp1OZ'. + 'nGAIQiYtsalUIhFlmGTy3sO3AizJCKn6DKYryxzHsWyaneMzr6'. + 'cWxRVZVlFTe4SpE3zm+U/4+whyiwJcWVMQNr3XONirVWAklxcE'. + 'EdbqchPhjhVzGpeqhUKhWBQhLElr9fo3pDaQPrw5xOl1CGG1JE'. + 'k1uYEBIVkrb02+o6RItfq6rBhbw/tuINT96766KhuqYpY3UFPF'. + 'BbY/19yZ1XF1U0UNBa9T7rZsz80K0jWk6bpWGW55UzbvTHZ+3t'. + 'vbAv/IT+K1uCmhIrKJAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bl_green.png +//========================================================== + $this->imgdata_large[8][0]= 1484 ; + $this->imgdata_large[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMMFjM4kcoDJQAABVlJREFUeNq9ll2MJFUVx3/11V'. + 'Vd/TE9vU0v4zLDwJIF16jBqLAPhsRXEiDqg0QTJiQSjcSNvCzw'. + 'sBEDDxizhvAAxBgf1oR9QF9NiE9ESFZkQyZB5WtddmdnZ3qqqr'. + 'uqbt367Cofqu3ZZpWVaDzJfbkf53//55z/PVdZXV3l/2H6f7Lp'. + '5VdOV/4Nb+GmHpUeA7AdBNxc3kafNb73jRPK9Xwon8ToxVefqU'. + 'b91wibH5EkCQBCizFihTSviHUHR0hWws9xe3wvJ7/7nPKpgX5y'. + '9oFqt3eOgWniRBoAbUBGGqZUibSYaeoT2B5bnkdaSA6793Cv/S'. + 'QPPbihXBfo5VdOV+8dfgnvwAU62YH5fCZ12sDujFkwyegCqTrB'. + 'iUOKTOJKj8jr88jS8zy6cXwBTP048nuHX0I0nDlIp7RpTG7kM0'. + 'sdyAYsTVukUuWGhlWHMq0ITL92lnUp9R1Obz/GmTNnqn9bDD8/'. + '+0D1oX0O0zQZZDYCsK2j3Gl9jQqDfHiei8GfiKVLlsZkJaBAN1'. + '0i6PgwUbB0GxG5/PrtE/xLRr959Znqw9452oVNI+jiJhnr1pe4'. + 'k29zB1/nFr5Kj7tpt1YYhJ0FJ7nUYbcJQBgahN2MzeCP/OipR6'. + 'prgN6Qr6ELFQFUWoRpNVjlKwxZB8DCpE+PtfEKqV1cUzxpVudu'. + 'GTBHA5Y1g99e+dUio9O/P1Vpq+/WE5GGjDSMoAtAQjrf3C52IP'. + 'QxpY4WK2hpReka9Gfrhqgz0bACRoCWjDh56kQ1z9FeuUUQxVhK'. + 'B92sD1VahM+bAJgcoJhGjP/6Ln8rAgDiRCVRKiIzxMkkodBJ85'. + 'im1IlEHbE4k1xyNveL4YP8HarmGJIOpqyjeQmfNHmTvnqZTWBt'. + 'vIJXpPwlukJSuSTKGK3pEwtJmiX00ZlInTyNscImO6XBITvH1c'. + '8vVt2OucdKvIyeKRTNCivsEMgcpg6taYs30nfq0Gqg6hOSSFJ4'. + 'BSnJPht0IqEjWmOGocEI6F0J94F0qaL6BntTF0MtUfweKQKAPU'. + 'Wwp4OcVnQAmVb0p9DLOzjEhEKnGRmoRc7EzRGlwA6NujAKG4yP'. + '6Sjwc4aVznZ7DK0xXdkDoJf0kGmFBniFBOBGcZSCCSKd0IwN0k'. + 'IS+QZWCGVZex4BnUxya3+Zt9iugQbcRFpIAtuHvAZulPUdLhUJ'. + 'RqegI3WcqaSXddlT3idsWMSRRGkEtNwmyTifAwyBo7LP+11J0e'. + '7tM7pZOYblHkBLcqZ5LcYtw6Wbd4CM3SpE9foYZsIHoqDKCrbz'. + 'mLSQtPwmuhXgtBLs0GBdbXOhFGB7WBKO2F8GXt9/VO97Ya3atF'. + '7nUHnwGjGGQqcPxFEdFqURkEidiZszAERoYIsGju1hq21kWee3'. + 'bw15+8WpsvAy3K1+i3JkkhZyPpxxjjPOsfOYiZ+TFhLPzQnHOU'. + 'tpzGB2dgA4tscIkKIx19Cxg/fPL7vQJu47eXt1VvsDK8pwPueZ'. + 'PuZoQMOqhRoJHSs0kKLBWjvjYinmeQGw1TaX1RFdfZ3LMzYLjA'. + 'C++dkn6AaH2Nobk6cxEzdnuG0TdC8zvdJkN0hqkFkO/jwL0fxa'. + 'so8sBcuFzQ+/+MRC+BeAHnpwQzn++ee5KT9Eshuy46dcKAXm32'. + '0uzPQhS4GttkH2GQID2Wc0Y4LtAbDxhZ/x5A+e/uTG9+jGceXH'. + '9/ySnnIXnUzOxXe1038mW3ZynNmam4yYWkO+f9cv+Oljz16/lV'. + '9tDz/9nerc1hm8ZEScSRK7VvtYl1i1dklsOKyvc+zg/bzw1O8+'. + '/efkajt56kR1ydlEJBc5H46xzbrJ3dY9wrB7hGcff+6/+279L+'. + '0fHxyiE8XMLl4AAAAASUVORK5CYII=' ; + +//========================================================== +// File: bl_blue.png +//========================================================== + $this->imgdata_large[9][0]= 1169 ; + $this->imgdata_large[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAMAAACelLz8AAACEF'. + 'BMVEX/////////7//35//v1v/exv/Wvf/Wrf/Wpf/Orf+/v7+9'. + 'tc69jP+9hP+5ucW1tc6tlP+rq7Wlpdalpcalpb2cnM6cnMacc/'. + '+cWv+UlLWUjN6UjK2Uc/+Ma/+MUv+EhKWEa/+EQvd7e8Z7e7V7'. + 'e6V7c957Wv9za9Zza8ZzSv9ra5xrSv9rOf9rMe9jUudjQv9jOe'. + '9aWpRaUt5aUpRaSu9aSudSUoxSSs5SSoxSMf9KQtZKOfdKMedK'. + 'Kf9KKe9CKf9CKb1CKa1CIfdCIedCId45MXs5Kfc5If85Iec5Id'. + 'Y5GP8xMbUxMXsxKc4xKZQxIf8xGP8xGO8xGN4xGNYxGL0xGK0p'. + 'KXMpIYwpGP8pGO8pGOcpGNYpGM4pEP8pEPcpEOcpEN4pENYpEM'. + 'YpEL0hGKUhEP8hEPchEO8hEOchEN4hENYhEM4hEMYhELUhCP8h'. + 'CO8hCN4YGJwYGGsYEL0YEK0YEHMYCN4YCM4YCMYYCL0YCKUYAP'. + '8QEJQQEIwQEHsQEGsQCM4QCLUQCK0QCKUQCJwQCJQQCIwQCHMQ'. + 'CGsQAP8QAPcQAO8QAOcQAN4QANYQAM4QAMYQAL0QALUQAKUQAJ'. + 'QQAIQICGsICGMIAO8IANYIAL0IALUIAK0IAKUIAJwIAJQIAIwI'. + 'AIQIAHsIAHMIAGsIAGMAAN4AAMYAAK0AAJQAAIwAAIQAAHMAAG'. + 'sAAGMAAFrR1dDlAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkRFRPMOZ'. + '/2AAAB+klEQVR4nGNgIAIIqeqZmBqpi2JISNml5lVXV3d198Yo'. + 'oUjwm1SnxsbGRsSm5ZfNXO4tjCTjVh0ABhFx6QV9E1Y0S8JkuN'. + '3yAgLc7W3t/QPi4jPKJ8ye1yoIlTKpjvVy15eVUbN0i4zKLJ8w'. + 'ae6qcKgLqmMj3PUFWFl5NJ0CExLLJzbNW7BWCyxlXR0ba6/Axs'. + 'zELmfnkRBT0QiSKgXJCOflxUbYy3KyMHEoOrtEZ1c2TZ6/cMl6'. + 'eaCUamdsbIC7tjgPr4SBS3BMMVDTwkXr1hsDpYy6UmMj/O0tdX'. + 'QNbDxjknJLWqYsXLx0vStQynxGflpkZGCgs7Onp29SbtNkoMy6'. + 'pevCgFJWy3oyMuKjgoKCPWNCvEuqWhcsWrJ06XqQlPnMvrKyrM'. + 'TomJjkZAfHlNa2qdOWrlu63gcopbG8v7+hvLwip7g4JdSxsLZu'. + '8dKlS9ettwBKic2eNXHChIkTG5tKqgpr2uo6loLAehWQx0LnzJ'. + '49p6mpeXLLlNq6RUvqly6dvnR9Bx9ISnnlvLmT582bMr9t4aL2'. + '+vrp60GaDCGB6Ld6wfwFCxYCJZYsXQ+SmL6+FBryInVrFi1atH'. + 'jJkqVQsH6pNCzCJNvXrQW6CmQJREYFEc2CYevXrwMLAyXXl0oz'. + 'IAOt0vVQUGSIkabkDV3DwlzNVDAksAAAfUbNQRCwr88AAAAASU'. + 'VORK5CYII=' ; + +//========================================================== +// File: bs_red.png +//========================================================== + $this->imgdata_small[0][0]= 437 ; + $this->imgdata_small[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. + 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. + 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. + 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. + 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. + 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGDNEMgOYAAAAm0'. + 'lEQVR4nI3Q3RKCIBAFYGZMy9RKzX7MVUAUlQTe/+kS0K49d3wD'. + '7JlFaG+CvIR3FvzPXgpLatxevVVS+Jzv0BDGk/UJwOkQ1ph2g/'. + 'Ct5ACX4wNT1o/zzUoJUFUGBiGfVnDTYGJgmrWy8iKEtp0Bpd2d'. + 'jLGu56MB7f4JOOfDJAwoNwslk/jOUi+Jts6RVNrC1hkhPy50Ef'. + 'u79/ADQMQSGQ8bBywAAAAASUVORK5CYII=' ; + + +//========================================================== +// File: bs_lightblue.png +//========================================================== + $this->imgdata_small[1][0]= 657 ; + $this->imgdata_small[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABVl'. + 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. + 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. + '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. + 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. + 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. + 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. + 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. + 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. + 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. + 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGTok'. + '9Yp9AAAAtElEQVR4nGNgIBaw8wkpKghzwvksPAKiUsraprYiLF'. + 'ARXkE2JiZ1PXMHXzGIAIekOFBE08TGLTCOCyzCLyvDxsZqZOnk'. + 'E56kAhaRV9NQUjW2tPcMjs9wBYsY6Oobmlk7egRGpxZmgkW0zC'. + '2s7Jy9giKT8gohaiQcnVzc/UNjkrMLCyHmcHr7BYREJKTlFxbm'. + 'QOxiEIuKTUzJKgQCaZibpdOzQfwCOZibGRi4dcJyw3S4iQ4HAL'. + 'qvIlIAMH7YAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bs_gray.png +//========================================================== + $this->imgdata_small[2][0]= 550 ; + $this->imgdata_small[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAMAAADH72RtAAABI1'. + 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. + 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. + 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. + 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. + 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. + 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. + '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. + 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. + 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIA'. + 'AAsSAdLdfvwAAAAHdElNRQfTAwkUGiIctEHoAAAAfElEQVR4nI'. + '2N2xKDIAwF+bZ2kAa8cNFosBD//yvKWGh9dN+yk9kjxH28R7ze'. + 'wzBOYSX6CaNB927Z9qZ66KTSNmBM7UU9Hx2c5qjmJaWCaV5j4t'. + 'o1ANr40sn5a+x4biElrqHgrXMeac/c1nEpFHG0LSFoo/jO/BeF'. + 'lJnFbT58ayUf0BpA8wAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bs_greenblue.png +//========================================================== + $this->imgdata_small[3][0]= 503 ; + $this->imgdata_small[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAxl'. + 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. + '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. + '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. + 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. + 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. + 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. + 'dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfT'. + 'AwkUGTIqLgJPAAAAqklEQVR4nI2QVxOCMBCEM6Mi2OiCvSslJB'. + 'CUoqjn//9TYgCfubf9Zu9uZxFqO+rscO7b6l/LljMZX29J2pNr'. + 'YjmX4ZaIEs2NeiWO19NNacl8rHAyD4LR6jjw6PMRdTjZE0JOiU'. + 'dDv2ALTlzRvSdCCfAHGCc7yRPSrAQRQOWxKc3C/IUjBlDdUcM8'. + '97vFGwBY9QsZGBc/A4DWZNbeXIPWZEZI0c2lqSute/gCO9MXGY'. + '4/IOkAAAAASUVORK5CYII=' ; + +//========================================================== +// File: bs_yellow.png +//========================================================== + $this->imgdata_small[4][0]= 507 ; + $this->imgdata_small[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAzF'. + 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. + 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. + 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. + 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. + 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. + '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. + 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAH'. + 'dElNRQfTAwkUGSDZl3MHAAAAqElEQVR4nI3QWRNDMBAA4My09E'. + 'IF1SME0VT1okXvM/3//6kEfbZv+81eswA0DfHxRpOV+M+zkDGG'. + 'rL63zCoJ2ef2RLZDIqNqYexyvFrY9ePkxGWdpvfzC7tEGtIRly'. + 'nqzboFKMlizAXbNnZyiFUKAy4bZ+B6W0lRaQDLmg4h/k7eFwDL'. + 'OWIky8qhXUBQ7gKGmsxpC+ah1TdriwByqG8GQNDNr6kLjf/wAx'. + 'KgEq+FpPbfAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bs_darkgray.png +//========================================================== + $this->imgdata_small[5][0]= 611 ; + $this->imgdata_small[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAABJl'. + 'BMVEX////////o8v/f6O7W4OnR3PXL1OTL0evEyLvCzePAwMC/'. + 'v7a8wsq7t7C1xum1vtS1q6GzopmyxeKsrsOqvNWoq7anvN+nsb'. + 'qhrcGgqbGfpq6cp7+bqMuVmJKRm7yPlKKMnL6FkKWFipOEkLSE'. + 'j6qEhoqAiaB+jqd8haF7hZR4iJt4g5l3hZl2gIt2cod1hJVzeY'. + 'VzboJvhp9sfJJsb41peY1pd5xpdoVod4xndI5lcHxka4BjcYVg'. + 'Z3BfboFbb4lbZnZbYntaZ4laZYVZV3JYYWpXX3JWWm5VX4RVW2'. + 'NUYX9SXHxPWn5OVFxNWWtNVXVMVWFKV3xHUGZGU3dGTldFSlxE'. + 'Sk9ESXBCRlNBS3k/SGs/RU4+R1k9R2U6RFU2PUg0PEQxNU0ECL'. + 'QWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAA'. + 'CxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGQmbJetrAAAAtklEQV'. + 'R4nGNgwAK4JZTNNOWlYDxhMT4ZDTOzQE1uMF9CiJWVU0LbxDlS'. + 'G8QVF+FnZ2KRNHAIiPUHaZGSlmZj5lH19A1KjLUA8lXU5MWllF'. + 'yjo30TYr2BfG19G11b37CEeN84H38gX1HbwTUkOjo+zjfG3hLI'. + 'l1exCvCNCwnxjfMz0gTyRdXNHXx9fUNCQu2MwU6SN3ZwD42LCH'. + 'W30IK4T8vUJSAkNMhDiwPqYiktXWN9JZj7UQAAjWEfhlG+kScA'. + 'AAAASUVORK5CYII=' ; + + +//========================================================== +// File: bs_darkgreen.png +//========================================================== + $this->imgdata_small[6][0]= 666 ; + $this->imgdata_small[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABX1'. + 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. + 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. + 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. + 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. + '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. + 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. + 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. + 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. + 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. + 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAwkUGRjxlcuZAAAAtElEQVR4nGNgIBZw8osqqIpzw/msfI'. + 'IiUmr6lo6SbFARASEOJiYtQ2uXADmIAJeEGFBE18LBMySBBywi'. + 'LC/LwcFiZuvmH5WiAxZR0tRW1DC3dfYJS8zyAouYGBibWtm7+o'. + 'TEpZfkgEX0rG3snNx9Q2NSCksgaqRd3Ty8gyLiU/NKSiDmcPsF'. + 'BodHJ2UUlZTkQ+xikIlNSE7LLgECZagL2VQyc0H8YnV2uD94jS'. + 'ILIo14iQ4HALarJBNwbJVNAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bs_purple.png +//========================================================== + $this->imgdata_small[7][0]= 447 ; + $this->imgdata_small[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAnF'. + 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. + 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. + 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. + 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. + 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGS'. + 'o5QpoZAAAAnElEQVR4nI3Q2xJDMBAG4MyQokWrZz3oSkJISJH3'. + 'f7dK0Gv/Xb7J7vyzCK0NjtPsHuH/2wlhTE7LnTNLCO/TFQjjIp'. + 'hHAA6bY06LSqppMAY47x+04HXTba2kAFlmQKr+YuVDCGUG2k6/'. + 'rNwYK8rKwKCnPxHnVS0aA3rag4UQslUGhrlk0Kpv1+sx3tLZ6w'. + 'dtYemMkOsnz8R3V9/hB87DEu2Wos5+AAAAAElFTkSuQmCC' ; + + +//========================================================== +// File: bs_brown.png +//========================================================== + $this->imgdata_small[8][0]= 677 ; + $this->imgdata_small[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABaF'. + 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. + 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. + 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. + 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. + '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. + 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. + 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. + 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. + 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. + 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. + 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLd'. + 'fvwAAAAHdElNRQfTAwkUGho0tvl2AAAAtklEQVR4nGNgIBaoSg'. + 'mLKGpowfkGMty8AqJKpi4mRlAROR5ONg4JFUv3YHOIgDo/HwsT'. + 'q6yps29EsjZYREFIkJ2ZS9/OMzA20wEsIi8uKSZtaOPmH5WSFw'. + 'YW0VRW07Vw8vCLSMguLwCL6FlaObp6B0TGZxSXQ9TouHv6+IXG'. + 'JGYWlpdDzNEKCgmPjkvLKS0vL4LYxWAen5SelV8OBNZQFxrZ5h'. + 'aC+GX2MDczMBh7pZakehkTHQ4AA0Am/jsB5gkAAAAASUVORK5C'. + 'YII=' ; + +//========================================================== +// File: bs_blue.png +//========================================================== + $this->imgdata_small[9][0]= 436 ; + $this->imgdata_small[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAk1'. + 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. + 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. + 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. + 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. + 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGhNNakHSAAAAmk'. + 'lEQVR4nI3P2xKCIBAGYGfM6SBWo1nauIqogaDA+z9dK9Lhrv47'. + 'vtl/2A2CfxNlJRRp9IETYGraJeEb7ocLNKznia8A7Db7umWDUG'. + 'sxAzhurxRHxok4KQGqCuEhlL45oU1D2w5BztY4KRhj/bCAsetM'. + '2uObjwvY8/oX50JItYDxSyZSTrO2mNhvGMbaWAevnbFIcpuTr7'. + 't+5AkyfBIKSJHdSQAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bs_green.png +//========================================================== + $this->imgdata_small[10][0]= 452 ; + $this->imgdata_small[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAn1'. + 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. + '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. + 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. + '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. + 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. + 'AIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAw'. + 'kUGgW5vvSDAAAAnklEQVR4nI3QSxKCMAwA0M4gqCgoiiJ+kEAL'. + 'LQUq0PufzX7ENdnlJZNkgtDS2CYZvK6bf+7EoKLA9cH5SQzv6A'. + 'YloTywsAbYr44FrlgrXCMJwHl3xxVtuuFkJAPIcw2tGB9GcFli'. + 'oqEf5GTkSUhVMw2TtD0XSlnDOw3SznE5520vNEi7CwW9+Ayjyq'. + 'U/3+yPuq5gvhkhL0xlGnqL//AFf14UIh4mkEkAAAAASUVORK5C'. + 'YII=' ; + + +//========================================================== +// File: bs_white.png +//========================================================== + $this->imgdata_small[11][0]= 480 ; + $this->imgdata_small[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAAQCAYAAADwMZRfAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFTsY/ewvBQAAAW1JREFUeJytkz2u4jAUhT/jic'. + 'gfBUKiZhE0bIKeVbCWrIKenp6eDiGlCEEEBArIxvzGU4xeZjLk'. + 'jWb05lRXuvbx+exr4bouX1Xjyw7Atz81F4uFBYjjGIDhcCjq1o'. + 'k6nN1uZwFerxfP55Msy1itVmRZBsB4PK6YveHkeW5d18XzPIIg'. + 'wPd9Wq0WnU6HMAxJkoQoiuynOIfDwUopkVIihKAoCgAcx6Hdbm'. + 'OMIU1T5vN55eBKEikljUYDIX6kFUKU9e8aDAZlmjcca+1b7TgO'. + '1+uVy+VS9nzfr8e53++VzdZaiqIgz3OMMWitOZ/PaK0JgqDeRC'. + 'mF53lIKYGfr3O73TDGoJQiTVO01nS73XqT4/FIs9kkCAIej0eZ'. + 'brPZEMcxSZKgtQZgMpmIWpN+vy+m06n1PK9yTx8Gy+WS/X5Pr9'. + 'er9GuHLYoiG4YhSilOpxPr9Zrtdlti/JriU5MPjUYjq7UuEWaz'. + '2d+P/b/qv/zi75oetJcv7QQXAAAAAElFTkSuQmCC' ; + + +//========================================================== +// File: bs_cyan.png +//========================================================== + $this->imgdata_small[12][0]= 633 ; + $this->imgdata_small[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAABPl'. + 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. + '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. + 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. + '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. + 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. + '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. + '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. + 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. + 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwkUGQDi+VPPAAAAtElEQVR4nGNgIBawikipyIiy'. + 'wfksfJpGRkamNtr8LFARPiMFHmFDcztXfwGoFi0jLiZuZRtnry'. + 'BddrCIiJEGL6eklYO7X3iCOFhE2thESdHawdUnJDZFDiyiamZh'. + 'aevk5h0UlZSpBhaRtbN3dPHwDY5MSM+EqBFzc/f0DgiLTkjLzI'. + 'SYw6bjHxgaEZeckZmpD7GLQSAqJj4xNRMIBGFuFtRLA/ENhGBu'. + 'ZmDgkJBXl5fgIDocAAKcINaFePT4AAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bs_bluegreen.png +//========================================================== + $this->imgdata_small[13][0]= 493 ; + $this->imgdata_small[13][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAvV'. + 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. + 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. + '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. + 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. + '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. + 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. + 'AJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGxNUcXCT'. + 'AAAAqUlEQVR4nI2Q1xKCMBREM2NHLCCogAGCjd6SqLT8/2cZKT'. + '6zb3tm987OBWCsXoejp8rC35fi4+l6gXFZlD0Rz6fZ1tdDmKR9'. + 'RdOmkzmP7DDpilfX3SzvRgQ/Vr1uiZplfsCBiVf03RJd140wgj'. + 'kmNqMtuYXcxyYmNWJdRoYwzpM9qRvGujuCmSR7q7ARY00/MiWk'. + 'sCnjkobNEm1+HknDZgAqR0GKU43+wxdu2hYzbsHU6AAAAABJRU'. + '5ErkJggg==' ; + +//========================================================== +// File: bs_lightred.png +//========================================================== + $this->imgdata_small[14][0]= 532 ; + $this->imgdata_small[14][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAA3l'. + 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. + 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. + 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. + 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. + 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. + 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. + 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAwkUGjoP2Nm+AAAAr0'. + 'lEQVR4nGNgIBaYiOk62imYwPnMkiIyso76yhJSzFARMxkRNk49'. + 'a3t5OW6oFk1LVkYOfWUHKxUXiEYzLS12DnN3VXkjIRtFsIiSk5'. + '6evqGqhYGKugAfWMRa1FpD2UHeQEXQRlgALCJur+rgbCUNFOAS'. + 'hqjRkZe3MpBTcwEKCEPMMTGSs3Xz8OQHCnBBHckt6OJpIyAMBD'. + 'wwN/MYc4H4LK4wNzMwmGrzcvFqmxIdDgDiHRT6VVQkrAAAAABJ'. + 'RU5ErkJggg==' ; + +//========================================================== +// File: bxs_lightred.png +//========================================================== + $this->imgdata_xsmall[0][0]= 432 ; + $this->imgdata_xsmall[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAA3l'. + 'BMVEX///////+/v7/Gvb0hGBj/5///3v//zu//1u//xucpGCG9'. + 'nK21lKVSQkp7Wms5KTExISlaOUpjQlIhEBj/tdbOhKXnrcbGjK'. + 'Wla4TetcbGnK2EWmv/rc73pcZ7UmOcY3vOpbW1jJzenLW9e5Rz'. + 'Slq1c4xrQlJSOULGhJz/pcb3nL2chIzOnK33rcbelK3WjKWMWm'. + 'vGe5SEUmM5ISnOtb3GrbXerb3vpb2ca3v/rcaUY3POhJxCKTF7'. + 'SlrWnK21e4ytc4TvnLXnlK2la3taOUK1lJxrSlLGhJRjQkpSMT'. + 'lw+q2nAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKBOgGhWjAAAAS0'. + 'lEQVR4nGNgQAEmunYmEJaMCKe1vBxYzJKVQ9lKBSSupKdnaKGi'. + 'zgdkiqs6WKnYcIGYJnK2HvzCwmCNgi42wsLCECNMeXlNUY0HAL'. + 'DaB7Du8MiEAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bxs_bluegreen.png +//========================================================== + $this->imgdata_xsmall[1][0]= 397 ; + $this->imgdata_xsmall[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAvV'. + 'BMVEX///////+/v79j//855/8x3v851v9Spb1C1v8AOUqEtcZK'. + 'lK1StdYxzv8hxv8AY4QASmNSlK1KpcZKtd4YQlIYnM4YrecIvf'. + '8AtfcAre8AjL0AhLUAc5wAa5QAWnsAQloAKTkAGCFKhJxKrdYY'. + 'jL0Ypd4Atf8ArfcApecAnN4AlM4AjMYAe60Ac6UAY4wAUnNSnL'. + '0AlNYAWoQASmsAOVIAITGEtc4YWnsAUnsAMUqtvcaErcYAKUIA'. + 'GCkAECHUyVh/AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAA'. + 'AJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUKDVyF5Be'. + 'AAAASUlEQVR4nGNgQAFmYqJcEJaEOJ+UrD5YTJKFTZrfGCQuaq'. + 'glLWvMaQ5kqujo6hnbKIKYXPr68gp2dmCNJiZAlh3ECGsREWtU'. + '4wF1kwdpAHfnSwAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bxs_navy.png +//========================================================== + $this->imgdata_xsmall[2][0]= 353 ; + $this->imgdata_xsmall[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. + 'BMVEX///////+/v7+trcbGxv+EhM6EhNaEhP97e/9zc/9ra/9S'. + 'UsZKSrVSUs5jY/9SUtZKSsZSUudKSt5KSudKSv8YGIQpKf8YGK'. + 'UYGN4YGO8YGPcQEP8ICP8AAP8AAPcAAO8AAOcAAN4AANYAAM4A'. + 'AMYAAL0AALUAAK0AAKUAAJwAAJQAAIwAAIQAAHsAAHMAAGsAAG'. + 'ONFkFbAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJxXO4axZAAAAR0'. + 'lEQVR4nGNgQAGskhKsEJaslIi8ijpYTJaDU1FVAyQuKSujoKKh'. + 'LQ5kSigpqWro6oOYrOoaWroGBmCNWiCWAdQwUVFWVOMBOp4GCJ'. + 's5S60AAAAASUVORK5CYII=' ; + +//========================================================== +// File: bxs_gray.png +//========================================================== + $this->imgdata_xsmall[3][0]= 492 ; + $this->imgdata_xsmall[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABI1'. + 'BMVEX///8AAAD8EAD8IAD8NAD8RAD8VAAYGBi/v7+goKCCgoJk'. + 'ZGRGRkb8yAD83AD87AD8/AD4+ADo+ADY+ADI+AC0+ACk+ACU+A'. + 'CE+AB0/ABk/ABU/ABE/AAw/AAg/AAQ/AAA/AAA+AAA6BAA2CAA'. + 'yDQAtEQApFQAlGQAhHQAdIgAZJgAVKgARLgAMMgAINwAEOwAAP'. + 'wAAPgIAPAQAOgYAOAkANgsANA0AMg8AMBEALhMALBUAKhcAKBo'. + 'AJhwAJB4AIiAAID////4+Pjy8vLs7Ozm5ubg4ODa2trT09PNzc'. + '3Hx8fBwcG7u7u1tbWurq6oqKiioqKcnJyWlpaQkJCJiYmDg4N9'. + 'fX13d3dxcXFra2tkZGReXl5YWFhSUlJMTExGRkZAQEA1BLn4AA'. + 'AAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEA'. + 'AAsRAX9kX5EAAAAHdElNRQfTAwkUKC74clmyAAAAQklEQVR4nG'. + 'NgQAVBYVCGt5dXYEQ0mOnp5h4QFgVmeri6+4dHxYMVeHoFRUTH'. + 'gTUFBIZBWAwMkZEx8bFQM2Lj0UwHANc/DV6yq/BiAAAAAElFTk'. + 'SuQmCC' ; + +//========================================================== +// File: bxs_graypurple.png +//========================================================== + $this->imgdata_xsmall[4][0]= 542 ; + $this->imgdata_xsmall[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABSl'. + 'BMVEX////////11P/MqdvKrNfAwMC+u7+9u7+4rr24lsi3rby3'. + 'lMe1rLq1o720q7i0oL20ksSzoryyqbaykMGxlb2wkL+vnbiujb'. + '2sjLuri7qpl7GoirWoibenmK2mla6mjLKmhrSllauki7CjhrCj'. + 'hLGihLChg6+ggq2fkqadkKOcfqqai6Gag6WYe6WXeqSWeaOTd6'. + 'CTd5+Rdp6RdZ6RdZ2Qg5eOc5qMcpiLcZeJb5WIbpOHbZKGbJGE'. + 'a4+CaY2AZ4t/Z4p/Zop/Zol+Zol7ZIZ6Y4V5YoR1ZH11X391Xn'. + '9zXX1yXXtxXHtvWnluWXhsV3VqVnNpVXJoVHFnU3BmUm9jUGth'. + 'VGdgTmheTGZcS2RcSmRaSWJYR19XRl5SQllRQlhQQVdPQFZOP1'. + 'VLPlFJO09IPE5IOk5FOEtEN0lDOEpDOElDNklCNkc/M0XhbrfD'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. + 'EAAAsRAX9kX5EAAAAHdElNRQfTAwkUKCgREfyHAAAATUlEQVR4'. + 'nGNgQAEcIko8EBY3M5Ougy+IxSXMwmTsFsAHZMqrSRvZB0W7A5'. + 'k6FlYugXEZICaPr394Um4uSAFDRFRCbm4uxAihsDAhVOMBHT0L'. + 'hkeRpo8AAAAASUVORK5CYII=' ; + +//========================================================== +// File: bxs_red.png +//========================================================== + $this->imgdata_xsmall[5][0]= 357 ; + $this->imgdata_xsmall[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAk1'. + 'BMVEX////////GxsbGra3/xsbOhITWhIT/hIT/e3v/c3P/a2vG'. + 'UlK1SkrOUlL/Y2PWUlLGSkrnUlLeSkrnSkr/SkqEGBj/KSmlGB'. + 'jeGBjvGBj3GBj/EBD/CAj/AAD3AADvAADnAADeAADWAADOAADG'. + 'AAC9AAC1AACtAAClAACcAACUAACMAACEAAB7AABzAABrAABjAA'. + 'BuukXBAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZ'. + 'cwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIyjy5SVMAAAAS0'. + 'lEQVR4nGNgQAFsUpJsEJastIi8ijpYTJaDU0FVgxXIlJKVUVDR'. + '0BYHMiUUlVQ1dPVBTDZ1dS1dAwOQAgYtbSDLAGIEq6goK6rxAD'. + 'yXBg73lwGUAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: bxs_yellow.png +//========================================================== + $this->imgdata_xsmall[6][0]= 414 ; + $this->imgdata_xsmall[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAzF'. + 'BMVEX///////+/v79zYwCMewDOxoTWzoTezkr/5wj/5wDnzgDe'. + 'xgC1pQCtnACllACcjACUhABjWgDGvVK1rUrOxlLGvUqEexilnB'. + 'jv3hj35xj/7wj/7wD35wDv3gDn1gDezgDWxgDOvQDGtQC9rQCE'. + 'ewB7cwBzawBrYwDWzlLn3lLe1krn3kre1hi9tQC1rQCtpQClnA'. + 'CclACUjACMhAD/9wC/v7///8bOzoT//4T//3v//3P//2v//2Pn'. + '50r//0r//yn39xj//xD//wBjYwDO8noaAAAAAXRSTlMAQObYZg'. + 'AAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAH'. + 'dElNRQfTAwkUIzoBXFQEAAAAS0lEQVR4nGNgQAFsDhJsEJaTo5'. + '2skj5YzMnSSk7ZwBzIlOSUklPiMxYHMnW4FXT5VNVBTDZeXiNV'. + 'QUGQAgYBYyBLEGIEq5gYK6rxAH4kBmHBaMQQAAAAAElFTkSuQm'. + 'CC' ; + +//========================================================== +// File: bxs_greenblue.png +//========================================================== + $this->imgdata_xsmall[7][0]= 410 ; + $this->imgdata_xsmall[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAxl'. + 'BMVEX///////+/v79znJQhSkJ7raU5hHtjraVKnJRCjIRClIyU'. + '9++E595avbVaxr2/v7+ctbWcvb17nJxrjIx7paUxQkK9//+Mvb'. + '17ra2Evb17tbVCY2MQGBiU5+ec9/eM5+d71tZanJxjra1rvb1j'. + 'tbVSnJxara1rzs5jxsZKlJRChIQpUlIhQkJatbVSpaU5c3MxY2'. + 'MYMTEQISFavb1Sra1KnJxCjIw5e3sxa2spWlpClJQhSkoYOTkp'. + 'Y2MhUlIQKSkIGBgQMTH+e30mAAAAAXRSTlMAQObYZgAAAAFiS0'. + 'dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfT'. + 'AwkUJy5/6kV9AAAATUlEQVR4nGNgQAGCyuyCEJaGugKHviVYzF'. + 'hO3sxCWwDIVNLTM9PXtpEGMhW12Cy0DR1ATEFLSxZ7BweQAgYd'. + 'HUMHBweIEQKiogKoxgMAo/4H5AfSehsAAAAASUVORK5CYII=' ; + +//========================================================== +// File: bxs_purple.png +//========================================================== + $this->imgdata_xsmall[8][0]= 364 ; + $this->imgdata_xsmall[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAnF'. + 'BMVEX///////+/v7/Gvca9rb3Grcb/xv+1hLWte629hL21e7XG'. + 'hMbWhNbOe87We9b/hP//e/97OXv/c///a///Y/+cOZz/Sv/WOd'. + 'bnOefvOe//Kf9jCGNrCGv/EP//CP/nCOf/AP/3APfvAO/nAOfe'. + 'AN7WANbOAM7GAMa9AL21ALWtAK2lAKWcAJyUAJSMAIyEAIR7AH'. + 'tzAHNrAGtjAGPP1sZnAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUIj'. + 'mBTjT/AAAASUlEQVR4nGNgQAGskhKsEJaCrJiSuhZYTEFASFlD'. + 'GyQuqSCnrK6tJwpkiquoamgbGIGYrFpaugbGxmCNunpAljHECB'. + 'ZBQRZU4wFSMAZsXeM71AAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bxs_green.png +//========================================================== + $this->imgdata_xsmall[9][0]= 370 ; + $this->imgdata_xsmall[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAAn1'. + 'BMVEX///////+/v7+/v7/G/8aUxpSMvYyUzpSMzoyM1oxarVqE'. + '/4R7/3tavVpKnEpaxlpz/3Nr/2tKtUpj/2Na51pKzkpK1kpK50'. + 'pK/0oYcxgp/ykYlBgY3hgY7xgY9xgQ/xAI/wgA/wAA9wAA7wAA'. + '5wAA3gAA1gAAzgAAxgAAvQAAtQAArQAApQAAnAAAlAAAjAAAhA'. + 'AAewAAcwAAawAAYwA0tyxUAAAAAXRSTlMAQObYZgAAAAFiS0dE'. + 'AIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAw'. + 'kUKBrZxq0HAAAATElEQVR4nGNgQAGccrIcEJaivISyhjaIxa7I'. + 'I6CiqcMKZMopKqho6OhLA5kyqmqaOobGICartraeoYkJSAGDnj'. + '6QZQIxgk1Skg3VeABlVgbItqEBUwAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bxs_darkgreen.png +//========================================================== + $this->imgdata_xsmall[10][0]= 563 ; + $this->imgdata_xsmall[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABX1'. + 'BMVEX////////l/+nAwMC86r+8wb28wby8wLy78sCzw7SywrSx'. + 'wLKwvrGuvK+syK+ryq2rx62n36ym3aumxKmk2qij0Keh16ahva'. + 'Og1aSguKKe06KeuaCetZ+d0KGdtZ+bz6Cay56ZyZ2Zwp2Zr5qZ'. + 'rpqYwJuXyZuXrJmVw5mUxZiTxJeTw5eTq5WRwJWPtJKOvZKKuI'. + '6Kt42Kn4yJt42ItIuGsomFsYmEsIiEr4eDr4eBrIR/qoN+qIJ8'. + 'poB7pH56o356on14nnt2nXl0mndzmnZzmXZymHVwlXNvlHJukn'. + 'FtiHBqjm1qjW1oi2toiWpniWplh2hlhmdkhWdig2VggGNgf2Je'. + 'fmFdfGBde19bbl1aeFxXdFpWclhVclhVcVdUcFZTb1VSbVRQal'. + 'JPaVFKY0xKYkxJYUtIYEpHX0lEWkZCWERCV0NCVkM/U0A+U0A+'. + 'UUA+UEA9Uj89UT48Tj45TDvewfrHAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. + 'RQfTAwkUKCFozUQjAAAATUlEQVR4nGNgQAGcoqrcEJYQB5OhSw'. + 'CIxSXGwWThGcIDZCppK5o7hyV6AZl6NnbuoSmFICZ3YHB0RkkJ'. + 'SAFDbEJaSUkJxAjeyEheVOMBQj4MOEkWew4AAAAASUVORK5CYI'. + 'I=' ; + +//========================================================== +// File: bxs_cyan.png +//========================================================== + $this->imgdata_xsmall[11][0]= 530 ; + $this->imgdata_xsmall[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABPl'. + 'BMVEX////////F///AwMCvxsaC1NSC0dGCz8+CzMyA//94//91'. + '//9q//9j//9X4uJX09NXz89Xx8dXxMRL//9L5uZL3d1L2NhLxs'. + 'ZLt7cv//8e9fUe8fEe7u4e398epqYehoYX//8L+PgK//8F9fUE'. + '/v4E5+cEb28EZ2cC//8C/v4C/f0CzMwCrq4Cjo4CdXUCaWkCZW'. + 'UB/PwA//8A/f0A+/sA8/MA7e0A7OwA6+sA5eUA5OQA4uIA4eEA'. + '3NwA2toA2NgA1dUA09MA0tIA0NAAysoAxsYAxcUAxMQAv78Avr'. + '4AvLwAtrYAtbUAs7MAsLAAra0Aq6sAqKgApaUApKQAoqIAoKAA'. + 'n58AmpoAlZUAk5MAkpIAkJAAj48AjIwAiYkAh4cAf38AfX0Ae3'. + 'sAenoAcnIAcHAAa2sAaWkAaGgAYmIUPEuTAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAA'. + 'AHdElNRQfTAwkUKQFKuFWqAAAATUlEQVR4nGNgQAGsUjJsEJaR'. + 'grC5qz9YzIiL28YriB3IlDZRsnYNiZUDMmXtHT2CE9JBTDb/wI'. + 'jkzEyQAoaomMTMzEyIERzy8hyoxgMAN2MLVPW0f4gAAAAASUVO'. + 'RK5CYII=' ; + +//========================================================== +// File: bxs_orange.png +//========================================================== + $this->imgdata_xsmall[12][0]= 572 ; + $this->imgdata_xsmall[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABaF'. + 'BMVEX//////////8X/3oD/3nj/1HX/0Gr/xGP/rkv/gBf+iS/2'. + 'bAL1agDxaQDuZwDrZwLpZQDmZQLlZADjcx7gZATeYQDdZgraXw'. + 'DZXwHYXgDXiEvXZAvUjlfUXwXTjVfTbR7ShUvRbR7RWwDMWQDL'. + 'WADKooLKWADJoYLJgkvHWATGoILFn4LFgEvFVgDEZx7EVQDDt6'. + '/DVQDCt6/CnoLChlfCVADAwMC+hFe+UgC8UgC6UQC4gVe4UAC3'. + 'gVe3UAC1gFe1eUu1TwC1TgCzTgCwTQKuTACrSgCqSgCpSgCpSQ'. + 'CodEulSACkRwCiRgCdRACcRACaQwCYQgCWQgKVQQCVQACUQACS'. + 'UR6RPwCOPgCNPQCLPACKPACJOwCEOQCBOAB+NwB9NgB8NgB7NQ'. + 'B6NwJ4NAB3RR52MwB0MgBuLwBtLwBsLwBqLgBpLQBkLQJiKgBh'. + 'KgBgKwRcKABbKQJbJwBaKQRaJwBYKAJVJQDZvdIYAAAAAXRSTl'. + 'MAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9k'. + 'X5EAAAAHdElNRQfTAwkUJBSSy88MAAAATUlEQVR4nGNgQAGqwo'. + 'paEBYPJ4eKezCIpc7HwmrqG6ENZMpLihm6RaWEAZl6Vo7ekRnF'. + 'IKZWSHhcTnk5SAFDfFJWeXk5xAjj1FRjVOMBeFwNcWYSLjsAAA'. + 'AASUVORK5CYII=' ; + +//========================================================== +// File: bxs_lightblue.png +//========================================================== + $this->imgdata_xsmall[13][0]= 554 ; + $this->imgdata_xsmall[13][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAABVl'. + 'BMVEX////////d///AwMC7wcS08P+y+P+xxdCwxM+uws2twMur'. + 'vsinzNynytylzuKhyN6e5v6d5P+d1fOcwNWcu8ub4f+at8iZ3v'. + '+ZvdGY2/yW2f+VscGU1vuT1fqTr72Sx+SSxeKR0fWRz/GPz/OP'. + 'rr+OyeqMy+6Myu2LyeyKxueJudSGw+SGorGDvt+Cvd6CvN2Aud'. + 'p+uNd+t9Z9tdV8tdR8tNN6sc94r813rct2q8h0qcZ0qMVzp8Rx'. + 'o8Bwor5tn7ptnrptnrlsnbhqmbRpmbNpi51ol7Flkqtkkqtkka'. + 'pjj6hijaRhjaZgi6NfiqJfiaFdh55bhJtag5pZgphYgJZYf5VX'. + 'cn9Ve5FSeI1RdopRdYlQdYlPc4dPcoZPcoVNcINLboBLbH9GZn'. + 'hGZXdFZHZEY3RDYnJCXW4/W2s/WWg+Wmo7VmU7VGM7U2E6VGM6'. + 'VGI5UV82T1wGxheQAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHU'. + 'gAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElNRQfTAwkUJziL'. + 'PvAsAAAATUlEQVR4nGNgQAHsQgqcEJYgG5Oegy+IxSHOxmTiFs'. + 'gFZMprKBnbB8e7AplaFlbOQUl5ICanX0BEWmEhSAFDVGxKYWEh'. + 'xAjusDBuVOMBJO8LrFHRAykAAAAASUVORK5CYII=' ; + +//========================================================== +// File: bxs_darkgray.png +//========================================================== + $this->imgdata_xsmall[14][0]= 574 ; + $this->imgdata_xsmall[14][1]= + 'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABm'. + 'JLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsRAAALEQF/ZF+RAAAB'. + 'iElEQVR42k3QPU8TYRwA8P//ebkXrgdIColXRAOEkJqbaExMut'. + 'DBhE1GNjYHPg+DG6ODiU6QOLjVxITBcFKBYCstlAC2Bz17fe76'. + 'vLD6+wg/1FpTRFR5lpaub/u1eGBGaAT4HneD4OlXx7avtDYUjT'. + 'HQabd2Ti8e3vVSKzxrtHS32wIpFVldno22Nqvvg2Bhl0gp/aNm'. + 'vJ3qqXAtLIva+ks1H0wqlSXi4+d6+OFTfRsAfHJx2d1od24rZP'. + 'xP2HzopINr1mkesX7ccojqif0v9crxWXODZTno3+dNGA7uWLsd'. + 'mUYU4fHJCViMG9umLBmM4L6fagZGg9QKfjZ+Qfy3C3G/B3mugF'. + 'IHHNcDf64E3KJALApk2p8CSolUUqLjFkyxOGMsTtFyJ+Wz57NQ'. + '8DghS4sLB0svioeZZo7nPhFoUKZDIVFbglkTTnl5/rC8snjAkJ'. + 'Bk/XV5LxHC/v7tR8jzTFPbg8LENK9WX0Vv31T2AEmCSmlKCCoh'. + 'ROnP1U1tPFYjJBRcbtzSf+GPsFTAQBq1n4AAAABKdEVYdHNpZ2'. + '5hdHVyZQBiYzYyMDIyNjgwYThjODMyMmUxNjk0NWUzZjljOGFh'. + 'N2VmZWFhMjA4OTE2ZjkwOTdhZWE1MzYyMjk0MWRkM2I5EqaPDA'. + 'AAAABJRU5ErkJggg==' ; + } +} + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_bevels.inc b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_bevels.inc new file mode 100644 index 0000000..97de442 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_bevels.inc @@ -0,0 +1,104 @@ + 'imgdata'); + + protected $colors = array('green','purple','orange','red','yellow'); + protected $index = array('green'=>1,'purple'=>4,'orange'=>2,'red'=>0,'yellow'=>3); + protected $maxidx = 4 ; + + protected $imgdata ; + + function ImgData_Bevels() { +//========================================================== +// File: bullets_balls_red_013.png +//========================================================== + $this->imgdata[0][0]= 337 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/f3+LFwcmNxMuxm62DmqKth1VpZmIWg6fv'. + 'HCa7K0BwMEytCjFnIyUlEBg9vhQvAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNhk+pYJVAAAAl0lEQVR4nE2Q2xLDIAgFHUWBKJf//9'. + 'oekmbafVDZARRbK/pYTKP9WNcNv64zzUdd9BjmrgnsVXRNSzO3'. + 'CJ5ahdhy0XKQkxld1kxb45j7dp0x2lBNOyVgQpMaoadX7Hs7zr'. + 'P1yKj47DKBnKaBKiSAkNss7O6PkMx6kIgYXISQJpcZCqdY6KR+'. + 'J1PkS5Xob/h7MNz8x6D3fz5DKQjpkZOBYAAAAABJRU5ErkJggg'. + '==' ; + +//========================================================== +// File: bullets_balls_green_013.png +//========================================================== + $this->imgdata[1][0]= 344 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/e3+K3vriUub/Dm18j4xc3ob10k0ItqQlU'. + 'e5JBmwpxY1ENaKBgUh0iHgwsSre9AAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNTfJXtxZAAAAnklEQVR4nE2QWY4EMQhDUVhSIRC4/2'. + 'kbaqLp9p+f2AxAayAzDfiK9znPORuvH0x8Ss9z6I9sHp6tcxE9'. + 'nLmWmebmt5F5p2AR0+C9AWpLBjXRaZsCAT3SqklVp0YkAWaGtd'. + 'c5Z41/STYpPzW7BjyiRrwkVmQto/Cw9tNEMvsgcekyCyFPboIu'. + 'IsuXiKffYB4NK4r/h6d4g9HPPwCR7i8+GscIiiaonUAAAAAASU'. + 'VORK5CYII=' ; + +//========================================================== +// File: bullets_balls_oy_035.png +//========================================================== + $this->imgdata[2][0]= 341 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/f3+K5tbqNwcjnkjXjbxR2i5anfEoNkbis'. + 'PBxpU0sZbZejKgdqIRIlERIwYtkYAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNgK0wEu5AAAAm0lEQVR4nE3QVxIEIQgEUErAgTHA/U'. + '+7zbipf9RXgoGo0liMmX6RdSPLPtZM9F4LuuSIaZtZWffiU6Iz'. + 'Y8SOMF0NogBj30ioGRGLZgiPvce1TbIRz6oBQEbOFGK0rIoxrn'. + '5hDomMA1cfGRCaRVhjS3gkzheM+4HtnlkXcvdZhWG4qZawewe6'. + '9Jnz/TKLB/ML6HUepn//QczazuwFO/0Ivpolhi4AAAAASUVORK'. + '5CYII=' ; + +//========================================================== +// File: bullets_balls_oy_036.png +//========================================================== + $this->imgdata[3][0]= 340 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////////27t/e3+LO3hfYzz65ubiNwci6uQ12ipadgVGa'. + 'fwsNkbhnVkcaZ5dwSA8lFg7CEepmAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAAHdElN'. + 'RQfTAxcCBySi1nevAAAAjElEQVR4nFXPWw7EIAgFUNMoCMhj/6'. + 'staKczc/2RkwjS2glQ+w3YytgXCXCZpRo8gJdGxZadJws13CUP'. + '4SZI4MYiUxypeiGGw1XShVBTNN9kLXP2GRrZPFvKgd7z/sqGGV'. + '7C7r7r3l09alYN3iA8Yn+ImdVrNoEeSRqJPAaHfhZzLYwXstdZ'. + 'rP3n2bvdAI4INwtihiwAAAAASUVORK5CYII=' ; + +//========================================================== +// File: bullets_balls_pp_019.png +//========================================================== + $this->imgdata[4][0]= 334 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAMAAAAMs7fIAAAAM1'. + 'BMVEX////+/v7i4eO/w8eHxcvKroNVormtfkjrMN2BeXQrepPc'. + 'Esy4IL+OFaR7F25LHF8mFRh5XXtUAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAxcBNgkjEpIxAAAAlElEQVR4nE2QAQ7FIAhDDTAVndL7n3'. + 'ZV/7JfEwMvFIWUlkTMVNInbVv5ZeJqG7Smh2QTBwJBpsdizAZP'. + '5NyW0awhK8kYodnZxS6ECvPRp2sI+y7PBv1mN02KH7h77QCJ8D'. + '4VvY5NUgEmCwj6ZMzHtJRgRSXwC1gfcqJJH0GBnSnK1kUQ72DY'. + 'CPBv+MCS/e0jib77eQAJxwiEWm7hFwAAAABJRU5ErkJggg==' ; + + } +} + + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_diamonds.inc b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_diamonds.inc new file mode 100644 index 0000000..8bc52b8 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_diamonds.inc @@ -0,0 +1,177 @@ +'imgdata'); + protected $colors = array('lightblue','darkblue','gray', + 'blue','pink','purple','red','yellow'); + protected $index = array('lightblue' =>7,'darkblue'=>2,'gray'=>6, + 'blue'=>4,'pink'=>1,'purple'=>5,'red'=>0,'yellow'=>3); + + protected $maxidx = 7 ; + protected $imgdata ; + + function ImgData_Diamonds() { +//========================================================== +// File: diam_red.png +//========================================================== + $this->imgdata[0][0]= 668 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. + 'BMVEX///////+cAAD/AADOAABjAABrAADWGBjOCAj/CAj/GBj/'. + 'EBCcCAiMOTl7KSl7ISFzGBilGBjOEBBrCAjv5+eMQkK1QkKtMT'. + 'GtKSnWKSn/KSlzEBCcEBDexsb/tbXOe3ucWlqcUlKUSkr/e3vn'. + 'a2u9UlL/a2uEMTHeUlLeSkqtOTn/UlL/SkrWOTn/QkL/OTmlIS'. + 'H/MTH/ISH39/f/9/f35+fezs7/5+fvzs7WtbXOra3nvb3/zs7G'. + 'nJzvtbXGlJTepaW9jIy1hITWlJS1e3uta2ulY2P/lJTnhITne3'. + 'vGY2O9Wlr/c3PeY2O1Skr/Y2P/WlreQkLWISGlEBCglEUaAAAA'. + 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. + 'sSAdLdfvwAAAAHdElNRQfTAwsWEw5WI4qnAAABGUlEQVR4nHXQ'. + '1XLDMBAFUKUCM1NiO8zcpIxpp8z0//9SWY7b2LHv6EU6s1qtAN'. + 'iMBAojLPkigpJvogKC4pxDuQipjanlICXof1RQDkYEF21mKIfg'. + '/GGKtjAmOKt9oSyuCU7OhyiDCQnjowGfRnooCJIkiWJvv8NxnG'. + 'nyNAwFcekvZpPP3mu7Vrp8fOq8DYbTyjdnAvBj7Jbd7nP95urs'. + '+MC2D6unF+Cu0VJULQBAlsOQuueN3Hrp2nGUvqppemBZ0aU7Se'. + 'SXvYZFMKaLJn7MH3btJmZEMEmGSOreqy0SI/4ffo3uiUOYEACy'. + 'OFopmNWlP5uZd9uPWmUoxvK9ilO9NtBo6mS7KkZD0fOJYqgGBU'. + 'S/T7OKCAA9tfsFOicXcbxt29cAAAAASUVORK5CYII=' ; + +//========================================================== +// File: diam_pink.png +//========================================================== + $this->imgdata[1][0]= 262 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgID/M5n/Zpn/zMz/mZn1xELhAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEi3tX8qUAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + +//========================================================== +// File: diam_blue.png +//========================================================== + $this->imgdata[2][0]= 662 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA+V'. + 'BMVEX///+AgIAAAJwAAP8AAM4AAGMAAGsQEP8YGHMQEHMYGP8Q'. + 'EKUICJwICM5KSpQxMYQpKXsYGNYQEM4ICGsICP97e85aWpw5OY'. + 'xSUv85ObVCQt4xMa0pKa0hIaUpKf+9vd6EhLVra+dzc/9SUr1r'. + 'a/9aWt5SUt5CQrVaWv9KSv8hIXs5Of8xMf8pKdYhIdYYGKUhIf'. + '/Ozs739//v7/fn5+/v7//n5/fW1ufOzufOzu/W1v+trc69veel'. + 'pc6trd6UlMa9vf+MjL21tfe1tf+UlNZzc61ra6Wlpf+EhOeMjP'. + '9ra8ZSUpyEhP9CQoxKSrVCQv85Od4xMdYQENZnJhlWAAAAAXRS'. + 'TlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAd'. + 'LdfvwAAAAHdElNRQfTAwsWEx3Snct5AAABFklEQVR4nHXR5XbD'. + 'IBgGYM6AuHsaqbvOfeuknev9X8xISbplSd5/8JyXwwcA/I0AKm'. + 'PFchVBdvKNKggKQx2VIoRwMZihMiQE49YUlWBCcPL0hYq4ITh+'. + 'qKECUoLDZWqoQNA766F/mJHlHXblPJJNiyURhM5eU9cNw5BlmS'. + 'IrLOLxhzfotF7vwO2j3ez2ap/TmW4AIM7DoN9+tu+vLk6Pdg9O'. + '6ufXjfXLm6pxPACSJIpRFAa+/26DhuK6qjbiON40k0N3skjOvm'. + 'NijBmchF5mi+1jhQqDmWyIzPp1hUlrv8On5l+6mMm1tigFNyrt'. + '5R97g+FKKyGKkTNKesXPJTZXOFIrUoKiypcTQVHjK4g8H2dWEQ'. + 'B8bvUDLSQXSr41rmEAAAAASUVORK5CYII=' ; + +//========================================================== +// File: diam_yellow.png +//========================================================== + $this->imgdata[3][0]= 262 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgIBmMwCZZgD/zADMmQD/QLMZAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEwcv/zIDAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + +//========================================================== +// File: diam_lightblue.png +//========================================================== + $this->imgdata[4][0]= 671 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/1'. + 'BMVEX///+AgIAAnP8A//8Azv8AY/8Aa/8I//8Y1v8Izv8Y//8Q'. + '//8InP8Qzv8Ypf85jP8he/8Yc/8Ia/8pe/8p//8p1v9Ctf8xrf'. + '8prf8QnP8Qc/9CjP+1//97//9r//9S//9K//9C//85//8x//8h'. + '//9r5/9K3v9S3v851v97zv9Svf85rf8hpf/G3v9SnP9anP9KlP'. + '8xhP/n7//v7+f3///n///O//+U//9z//9j//9a//975/9C3v8h'. + '1v+E5/+17/9j3v/O7//n9/+95/+l3v9jxv+U1v8Qpf9avf9Ktf'. + '+Uxv+11v97tf9rrf+cxv+Mvf9jpf+tzv+Etf/O3v/39/8Akkxr'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. + 'IAAAsSAdLdfvwAAAAHdElNRQfTAwsWEiHk6Ya/AAABGUlEQVR4'. + 'nHXQ13KDMBAF0J2o0E01GHDvJa7p3em95/+/JQJMYjDc0Yt0Zr'. + 'VaAaxHgtxwbSGPkGQpOIeQ2ORxJiJmNWYZyAhZR0WcgQGhViU0'. + 'nEGoedDHGxgRapRPcRpXhOr7XZzCmLjaXk9IIjvkOEmSRLG62+'. + 'F5XlEElhA5sW21GvXj6mGlDBfnJ51lr9svnvEKwH1hu2QPbwd3'. + 'N9eXVzuL7/Hn29frdKaamgcgy67L3HFG9gDefV+dm5qme4YRXL'. + 'oVR374mRqUELZYosf84XAxISFRQuMh4rrH8YxGSP6HX6H97NNQ'. + 'KEAaR08qCeuSnx2a8zIPWqUowtKHSRK91rAw0elmVYQFVc8mhq'. + '7p5RD7Ps3IIwA9sfsFxFUX6eZ4Zh4AAAAASUVORK5CYII=' ; + +//========================================================== +// File: diam_purple.png +//========================================================== + $this->imgdata[5][0]= 657 ; + $this->imgdata[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAMAAAC6CgRnAAAA/F'. + 'BMVEX///////8xAP/OAP+cAP9jAP9rAP+cCP85CP/OEP9SKf/O'. + 'CP9CEP9zGP9rCP+lGP/WOf/WIf9KIf9jOf+MQv+EMf97If9zEP'. + '+1Sv+lIf/ne//eUv/na//n5//Oxv/Wzv+chP9zUv97Wv9rQv9a'. + 'Mf9KGP/v5/+te/97Kf+9Y/+tOf+tKf+lEP/vtf/WMf/WKf/v7+'. + 'f39/+tnP+9rf9rSv9jQv9CGP+ljP+EY//Gtf+tlP+Ma/9zSv/e'. + 'zv+UUv+9lP+cWv+lY/+cUv+MOf+EKf+UQv/Opf/OhP/Ga/+1Qv'. + '/Oe/+9Uv/ntf/eWv/eSv/WGP/3zv/vlP/WEP//9/+pL4oHAAAA'. + 'AXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAA'. + 'sSAdLdfvwAAAAHdElNRQfTAwsWEjX+M1LCAAABDklEQVR4nHXQ'. + '1bLDIBAGYFqIEW+ksbr7cXd3ff93OUCamdOE/Mxw882yywLwPz'. + '+gNKotlRFUVnNUQlCxTMRFCKEdE+MgpJaEiIOU4DKaoSIygtb3'. + 'FBUQrm3xjPK4JvXjK0A5hFniYSBtIilQVYUm+X0KTVNiYah+2q'. + 'ulFb8nUbSovD2+TCavwXQWmnMA6ro+di+uR5cPzfPhVqPV3N1p'. + 'n3b3+rimAWAYhP3xnXd7P6oc9vadPsa1wYEs00dFQRAFehlX21'. + '25Sg9NOgwF5jeNTjVL9om0TjDc1lmeCKZ17nFPzhPtSRt6J06R'. + 'WKUoeG3MoXRa/wjLHGLodwZcotPqjsYngnWslRBZH91hWTbpD2'. + 'EdF1ECWW1SAAAAAElFTkSuQmCC' ; + +//========================================================== +// File: diam_gray.png +//========================================================== + $this->imgdata[6][0]= 262 ; + $this->imgdata[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX//////wAzMzNmZmbMzMyZmZlq4Qo5AAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWExZFTxLxAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + +//========================================================== +// File: diam_blgr.png +//========================================================== + $this->imgdata[7][0]= 262 ; + $this->imgdata[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABsAAAAbBAMAAAB/+ulmAAAAEl'. + 'BMVEX///+AgIBmzP9m///M//+Z//8hMmBVAAAAAXRSTlMAQObY'. + 'ZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAA'. + 'AHdElNRQfTAwsWEwCxm6egAAAAbUlEQVR4nFXJwQ3AMAhDUdRm'. + 'kKojuCswABf2X6UEEiC+WF+PyDfoGEuvwXogq3Rk1Y6W0tBSG8'. + '6Uwpla6CmJnpoYKRsjjb/Y63vo9kIkLcZCCsbGYGwMRqIzEp1R'. + 'OBmFk9HQGA2N0ZEIz5HX+h/jailYpfz4dAAAAABJRU5ErkJggg'. + '==' ; + } +} + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_pushpins.inc b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_pushpins.inc new file mode 100644 index 0000000..a382eef --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_pushpins.inc @@ -0,0 +1,517 @@ + 'imgdata_small', + MARK_IMG_SPUSHPIN => 'imgdata_small', + MARK_IMG_LPUSHPIN => 'imgdata_large'); + + protected $colors = array('blue','green','orange','pink','red'); + protected $index = array('red' => 0, 'orange' => 1, 'pink' => 2, 'blue' => 3, 'green' => 4 ) ; + protected $maxidx = 4 ; + protected $imgdata_large, $imgdata_small ; + + function ImgData_PushPins() { + + // The anchor should be where the needle "hits" the paper + // (bottom left corner) + $this->anchor_x = 0; + $this->anchor_y = 1; + +//========================================================== +// File: ppl_red.png +//========================================================== + $this->imgdata_large[0][0]= 2490 ; + $this->imgdata_large[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMKBh4Ryh89CgAACUdJREFUeJy9mNtTFFcexz+/7p'. + '4Lw1wZJKDGCAwmDAqUySamcCq1ed6k9mn3UfMP7F+1T3nYqn2J'. + 'lZdoDEjpbq0KG8EBFBFBEJye6Zmenkv32Ydu5GYiUMmeqq6uqT'. + '6Xz3zP73aOcIKmAQkIFyD3N/jrBPwlKjLQEglVlJKyUjR3u7cc'. + 'WLoP3/4dvv03LNrQ8I6x1rFbDML9kOmHvh7IRHU9JKmUSG8vpF'. + 'IoXX/TV0AiEM5A5jT0noFMFMJHXUt/d5f9TUAbhtQ3cPFruDog'. + '8klHMnmO0dGYe/myOJGINEwTz3F2higFXgy8PpAkOC+h8hoaCt'. + '4ppHFcQAWSgOQlyI/p+lUjmRxWAwNJd3xca/f34yoFi4tgmjtD'. + 'NIFkJ4xcgBCgVqEBFJ9DqcZea/gNAAVEg7AOGYnHe9XoaJd3+X'. + 'LISSSwnz6lsbKCZ9sHh4UVdBkwdA6cPwNnIfJPmC3Ctgft3wwQ'. + 'QPkvTZJJnbExzfvsM2nMzVG7e5fG48d4lnXwTwEYCjJxuHQBog'. + 'BHUfKkgAIIhiGk06hTp/Dm5qS1uYlXLvtWd4gPgIiCrAEcVckT'. + 'Ab5p7TaYJrK1hQaEenrwSiVfQdc91P0kSp7Ii89D5ksY/kAkLy'. + 'IZXFdXkQjS1YUSEbdcRu168V6+HTUNIKJDRwdE+sBIQmP9Ld59'. + 'bEBA3of4F/D+uXb7rGaaCSmXI3pPj64PDaHCYfEqFVSjgWo2D2'. + '73XlJNQTgCyQykIuBWoNKEeh1aLXBPBCggGdBOgxZVSjoajVhH'. + 'o5HWlIpq4bCQSgm9vXhK4ZZKh5SUYygp4J1EQVUD9xlU18BJQD'. + 'bUbJ5T5XJStyxN9fSI099P3baxV1dRloW2h2ivx/yakg2ot6F1'. + 'EkCa4G1D+zVEq5ArKTWM42Q6HUczQV7U66w9e0ZpdRXlOIQ5vF'. + 'VHUXILKify4jiEzkOqC3peQMoBQymFlMt4Dx6wUSxSsm2UZXEK'. + 'P30QvOUt8/2Sd78CdWwFDTA+gsw3cOlPcPUD+CQB52oQ21RKXM'. + 'eRhGXhOg7VoKrx8KuS4ygZhVg3ZI8FGIfwR9BVgAtfwxdXdP3L'. + '86nUR91dXelNXTeWWy10paQHX602YAP1ADASAL7LJvFtMpOCc0'. + 'cG3FHuGlz6Gr4YEpnoTCbzsdHRbOzy5RCRiLRMk5rjyOtAimwA'. + 'U4U3SurBN/0wnAASBCVDIKpB4kiAB5Ub0/UvO9LpPAMDGfn005'. + 'AxPCzxep3Q6iqPLUseBoufCZRsAE6g5g5kKIDfKUj3wnpAG8QB'. + '/Z1OIqANQuI65AtwNScyYXR2XlAXL2YZHzcklRKWl5GVFXFtGx'. + 'MoAiV/EQaAGH6BUQNWgQpwFngv+Ca8KUAQEBcwgTJHyMV7679R'. + 'XS8YqdSI6u/PMD5ukMtJY3GR2uQkr5aXeWVZOEALmA8WsIAxfL'. + 'd0goVLAdCOd+/YpgqeVtBv4yiA++q/RKKXixe7GB8PSyoljcVF'. + 'yg8fyubyMpulEk2lyAIfAAvAC+B+oOQFoAt/+0rAejB/EzjNri'. + 'vvqNnCd64jxcE39V8spnP+vMbAgDSePKE2NcXm06dslMuUlcID'. + 'TuFvqwXMBU8N39bGgRR+ki0Dz4L5DSAe9NGD7zq+6kcN1L6H2b'. + 'ao5WWaQHllRTafPmWrVMJUimoAQrBYJFjQwre7B6A8YAi8LCgD'. + '5DVo6/hbb/iHK1KggvFeD3hHziQKEMuiNTNDbXGRTdtmw7Iwla'. + 'KGH0oqwbscLOoG46rAY6AOzRhY74PT6QuUKEN4PegXxd/yEDTT'. + 'YMWOk+oEaLkuFdNk0zTZwjfkavDUArXWgGXgFb4dEShXhfYqlI'. + 'ow3w9rg3B6ED60IOOA5oEYQBrcpG+mj9bg0VG8GMJhVDZLyzAo'. + 'VSq8rFYxXXefcjVgG9+uisDrXUCApoKSBcUHMBmHhfcgNwhtD3'. + 'q9IG6Lr15b4OUTmPwBJt8JqGuapp05o0mhoHnptLQfPsR+8IBK'. + 'uYyNH3yr+B77LHheA3tK1Ta+IrMeTL2C6Xl48TOsNWDDgAz7s5'. + '/r+krP/eddCsbj8fDQ4GBm9MqVvvRXX2VULBayRGRzaYn1SoWa'. + 'UjgB4PIB5QK4ZgBXBKaAHxQsrED1H7CRgCUPwgHZDqACmhWwXv'. + '2aDRqGYeRyufS169cvThQKV88PDuYbW1vJ5VRK+5euqxWlPMdX'. + 'SRqgreHbZGN3ijfKBXBTAeh2Fdwi2MofshP/dvKwCmKhp4m83Y'. + 'vj8Xg4l8tlCoXC0MTExMTFkZE/1m37wvLGRvKRacoD1209E7Fc'. + 'pZwYREOQqEJ4z3HskHLsz4AoXykPIBSN0t3dTTQafROoHdumXC'. + '4fjoMiog0ODiauX7+eLxQKV3O53ETdti88nJnJ3rl505ifmWm3'. + 'arWSodR8GNbycDoNHy5C5jFold1k8d+DyvELNwg93d18/vnn9P'. + 'X1oes6nufx/Plz7t+/fxhQKSWJRCI5NjaWHxkZKdj1+sjSwkJm'. + '+uZN/dZ337VqCwullGUVdZjsgIUC5LqhrUPvCugWuApeApPAzY'. + 'PKHWyaphGNRunt7WVwcBARwfM8Ojo6sCzrMKBhGLphGFEF2Wq1'. + '2jc7M5OZ/vHH0MPbt93awkJJmeZsC6ZaMK3DCwvWdNioQUb5B6'. + 'AdBR+9SzkAz/NwHIeXL18iIui6TjgcJplMMjY2th8wHo+Hh4aG'. + 'MsPDw6fddru7+Phxx51bt/RbN260qwsLpZhlFZsw9QJ+2Pbrga'. + 'oJG2FY2oKwuTtVEz9uV34NbqdtbW0xPT1NNBoF4MyZM1y5coWu'. + 'rq5dQBHRcrlc4tq1a/l8Pj9RMs38ndu3Ez//9JNXLRZNyuXZJk'. + 'xVYKoExQpsK/+IaAuYb7no8zjC/R+A4zisrq7u+53NZjl16tQ+'. + 'QIlEIslsNpuPRCJXZ2dnh2/duNFRW1oy07a96MKd575yxRqU1B'. + '5vPMpF5HHa1tYW9+7do7Ozc/eQpZTSQ6FQt1Lq8pMnT/5w7969'. + 'nuLcXE1rNufO9fRMhlKpOyvt9qPtVmvb25fFfvvWbrepVCqHwo'. + 'xaX19vff/996ZhGC8qlkW9Wt1Onz073fXxxz+6MB+9e9dUjuO+'. + '7ebq9wLdB9hoNCrr6+s/4wf3FCJW3fPmTZhXsNWCprjuW66Dfr'. + '928KAfBhJAEgiJSLuzs7OSTqctoFkqlZRt26j/I+L/AGjPTN4d'. + 'Nqn4AAAAAElFTkSuQmCC' ; + +//========================================================== +// File: ppl_orange.png +//========================================================== + $this->imgdata_large[1][0]= 2753 ; + $this->imgdata_large[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQ0VCkHCzQAACk5JREFUeJytmGtzG0d2hp8zNw'. + 'AEcRdJ6EJK9FL0CqZUm9jWbkwq3vhDstl8dmLvz8rP2H8Q75ZT'. + 'pkRfpLgqsS6WIFEKGYkiSBCDO+banQ8DUpRWEkklXQUUqlCDfv'. + 'rp857pgfAOQ4AMOJdg4R/hX96Hf06bvDc5iT07i8yeg8ksiIAI'. + '4TBi/ds9/vivD/njapNHvRBfHXMu410AM+BUoVSF05NQsi1sO4'. + '8402AXwLQTuP31OAZO2aG0MEn14iSlnI1z3LnMk8IZYJyBwjIs'. + '/TWsVIWPJkvMFS4zMfMhUp5BsoCpAAEBLYKaMFGn00jBxnvu02'. + '35+JHmSJEnBpQEcPo38MmCxd/nS9Ry71Ga/g1W9a8gn0GsHkgA'. + '6DGjxkqb5CoO+YxF3A3p+jGjQUzoK+L/V0ADzFMwtSR8eLbAr8'. + 'uXOTf9NzhTc0geSLUQcYHgYEH786RMg0zWJHV2Aitv4x/HpHVS'. + 'QA2YBqTTGIUq5qkPMWaWkVwPnPtAA/BevmZcjxaaUtHh8pJJGu'. + 'DpCB9FvT7A7YT7S3p5vFMNzmWo/O0MSx/Ms3TqI8r59zFTfUQe'. + 'I7SBODE3tnfoIxYnNHligwik0zAzDdVpyKbA8sff5YAeMEwgkV'. + 'cufQeTJzZoCsaFLKXPTnNpoUTNsSgJmNoGsuNQjIDwYD2HlnZy'. + 'k++yxTKXZfKTU8zOpjhneeQYkorSmGERtIlICBKRbLX+y98YN3'. + 'ADcNIm+bJD4U3pPnmbEaRgYVRTGBkDSSsmxKfY7ZLuDJA4hdjl'. + 'JEgyBB2SJOvQ9RzTpNKoEwNq0CNFvOXR3/HxMgYVPObaz8kPmh'. + 'hkEWMatAfRONGGvLizyOE9P8KkpwhPDAgQKJQbELUD0oOIhbbH'. + 'JeVTmowxjAgZutB5AoOngA+2DdYrcTyOyYZP9+QpBvI29vwEhb'. + 'It042BVQgDy9KTMfkwQG1A9ACCLlgBBGUwxxoc52WDh2ATyEPp'. + '1hoaPvrEBh0Dq5an9OUsl/9hylk5b5c+mowLc4E2Jtw4Eoljyf'. + 'ogA/AGEAagNRjGyUxOmEycyVA5EWDBxrmUp3ytLIv/NJP69Goh'. + '+9mFydIvS5PZYkvH1oY/RFtKymlwBFQAgQd+kAA6qSQ8pvn2mp'. + 'SkJkuVFHPHBnQMrEt5Sl+e4/Lvp51PF1PF5Xy6WMvOWZXMom8z'. + 'OZTQ8+j5sbQiMEwopsCIwRtBGIJSCdzbTGo9NimkDcgdC7Bg49'. + 'TG5n4/nfr0Si77WdYp1YzyZEkWPdteaEnB7pPqBTxuIf/VgciE'. + 'SgasCPwh+GNIkaNNag1RiPge5pEhMQVjfoLcF+eoXSvbKxedwn'. + 'LKzC3KWbOi5/sW5a44/SHFUSgVA7SCzRG0AvA9mPOgFIETgu4n'. + 'Ww0wNQWFAqRSL6D2ZQYBdDrQ7R7jXiwgRcvIL02makuTmWtpM/'. + '+BlLMl5vuWzLVEuwH6oYnR1KS8kJINGXMM2YdfRlALoQoQQKeb'. + 'bDVwoMdxQMaLCwLo96HZTF5HbrEhmOftianfZisfzueKv7ZmrX'. + 'MsjhxKXZGBjzyeEHmSE3oWiggtyVGmE8DTIXTC5NxgAxOAGUM8'. + 'fun9mnSSLQ/CxNzOTgJ3LIMgoGwkKBiiMyaVviHVkdCO4FEKNv'. + 'LQzWBYHfITPa4UBVM0LR/WB7ARJsdDDTjA6deYFIFUOimJ3d0E'. + 'sNdLavYYgBpthqKcjiiJRO8K6CK0CsJTjfQAGaJtD9vQFAxNNQ'. + '1FB0yBAfA8gdMAIagLoCVAen0M00zMOTYShNDtoHs9CAIUoI4E'. + '1IBihCdNhsMhsj6NuV7BCC2IBpBqQaaFOENCCeiEsO1BO4RQgy'. + 'I5Hm4k4oIU9MrgZSAdBeTabZz+ODxKQRRBFBJo6IUc51anYRQo'. + 'dto+24FNxYCiaWKkQsj00KkO4gxRRkAngJ868M0u3OkkM+hxQA'. + 'cQ7YD7GO5XYSsPZybh/TCkFIYY+kWniTW4Q7jXgHvHMhiRpmuW'. + 'ca08GZkkZ/nY6TZMNhCnf2CuPoDVJvxpB+q9BHA8Ag1uH+oP4c'. + 'YEPCzDwmzSLquShHW/E0YRbG/BjZtw40hAy7aNzJlzRn75E6N0'. + 'qiwTzafI7kOU3gWrhzZC2iHcbsPqLlxvJnCt4KC1RYAL3I5hzY'. + 'Xv/huePYCtITQMKEnyB4KQvMURuJvw889HGSwUCs7CwkLpo6tX'. + 'Ty/+7nel6VLGDn/8N9m+eZuo1UP8iNhLau6b3RfmOsHBGTUYw9'. + 'WBNeDrGB4+h/4qNLKwTnLbHj9CJw/6GoIh9Jpvq0HHcayFhYXi'. + 'l3/4w9LK8vLKexfma3G/mb/3n1njTivS7tNQaaU1grQDjJ868D'. + 'Axx6vmxnBrY9C9IcSbSXbavNjb/S3eN6/0m1JcKBScixcvllZW'. + 'Vi6uLC8v12q1v/M8b/HxVjP//YYr32yE4dYWvShO0ogi14xwxq'. + 'F4rbnxZ3cMjtpvEEeMvwA0TdOYn5/PffHFF7Vr166tvPeLXyx7'. + 'nrd4+/btyg/frFo//Xgncnd67qCn78earQqcmYD3fSi1wPCTSV'. + '3gzqvm9uFOMl5nUAqFQn5paal26dKla57vf7D+6FHph9VV88af'. + 'vgq79bo70e3VT2l9A3hYg4UiRALVHTCHSZvYBm4A//6quf8zoG'. + '3bpuM4acMwKr1+//SDe/dK31+/bv90/Xrcq9fduNW6rbVeC+E7'. + 'gWdD2DKg4UEpBmPcm10RuScida31ntb62HAigoigDw6Gh0axWH'. + 'QWFhZKi4uLZ+I4PrVer2e+u37dXPvqq6hbr7tOp1NXWq89h6/b'. + '8FBB34WGBesdcPrj38lkMkGlUuml0+mu53nR3t4eo9HoSLhMJk'. + 'OlUiGdTuN5Hq7rvgA0TdO4cOFC7vPPP6/VarXldqdTu7m2lrv7'. + '7beq++BBO263b/tKrfWSXlbvwJ6CuAtDgTYiaBFMw6BSqfDxxx'. + '+rarWqGo0GN2/eZGtrC6XenAkRoVKpcPXqVWZmZmg0Gty6desF'. + 'oIhIOp3Ol8vlmmVZK3fv3Lm09uc/Zwbr653ccPgoNIzvnmn99Z'. + '7W9QG46lAaM5mM2l95GIYUi0VOnz7N7OwsWmsymQzyuse5Q8Mw'. + 'DNLpNDMzM5w/f/7A6AGgUkoajYa9urpayOXzUz/fvZutr68Pim'. + 'F4/2y1+n2o9Q/ru7uPesPhXnyo4A+vfHp6mmazybNnz9jZ2UFr'. + 'TbPZJAhe+8/aS0Mphed5NBoNABqNBqPR6MWBVWstvu/nnj9/Pv'. + 'vo0aPq5uZmPBgM/qcwPf39xV/9ajU1M3Nvq9PZaw8GoT50PjdN'. + 'k6mpKa5cucL58+eJ45j19XWePHnCzs4OnudhmiaWZRGGIVH05r'. + 'yEYYjrumxubrKxsfFyDQJ6NBp1Pc+7C4jWumBaVm+kVL2l1H2l'. + '1G6otS+H6V6z8u3tbVzXpdFooJRicXGRqakptre3uXXr1ltrcT'. + 'Qa8ezZszemWAE9rfUdYBOwtVLRbrPZ+48ff+wDvuu6Sr3MB4Dr'. + 'uty6desgfa1WC3iRyrNnz4pSSmezWUzTfGtYtNYcdvC/9sMlgP'. + 'n5N4cAAAAASUVORK5CYII=' ; + +//========================================================== +// File: ppl_pink.png +//========================================================== + $this->imgdata_large[2][0]= 2779 ; + $this->imgdata_large[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQolY9lkpgAACmhJREFUeJy9mOtzFNl5h5+3b9'. + 'Mz0kzPBWmEVtIiWYhIiC0HCDhB8lb8ISk7nzdZ5+/zJ/8BTmpT'. + '660CZLwG1pVFgBkgGIHECEaa+/T9nHzQCCQuRpCNz6mp6g893U'. + '8/c37ve3qEjxiC4OA4n/Lp/EUu/tsMM/+aEWduVBx7WhdkShcY'. + 'xUH2zo0Dwod/5N6vf8V//PoGdx8M8EOFPtK9jI8BdHCcMuVSmf'. + 'LxHLmSZdm2U8xIbmKETDGDZZnIy4dBbCynyGhphurEDBOlHFnn'. + 'qPcyPxTOwDCOccw7w5nlBRZWylI+ny/mZ6rL1dzUZ5/IWGZU3D'. + 'ZIOMQDDaJcHDVGWUbJBi9odVr0QoVSPzigIEaZ8vgSS/8wZU3/'. + 'k1fylipz5dLM2WlrZqHKaGCKbEbontq3KAKWQyZfZKTgYqc9Bp'. + '2I2PcJ4ogk/UEBQcwipbFZmT13vDBx8fhnE1Ofnp9yJopFyT3X'. + 'yANfks0QHSQMDaL37pOxMLIu2UyVkjVKLjyKSeuD8dAYCFkso1'. + 'gYMaeWJ40T56cl8yAi/O4FSa2P6kYczIDsgVpAqcDImZPMuAB1'. + 'dkLQtcc8a/bwox8IUHAxZVxGZMouSLVYwKuMkD5IxN+JSdsRJB'. + 'pexuTVgYYM6EoGmxkmg3/hEhNUMr/hd7dqbOzExMn/GRDAxWZc'. + 'j3I8HiXfMjF2FQowKw7pjoN6E/Llw/GBJj8qxVOMlX4ipxc/lY'. + 'kl2zBLkmrTcEzMkoNoRLVidLi/9g+Z3I+1xRHX5EcAihxnbPRv'. + 'OTU9kZSmpKPy9FTGrLimPZ1H+UiyGaF67w6n7E1DwMngFDxGvc'. + 'w70v0xZUby5IxjlIyMssUJrJwVWkXBdbXvSvwEibcSdKCAFI16'. + '4/sc0SRo9cGAGq1DwvQFzV6DVuBiV4zYnlEts6A2TSPcSiXoxo'. + 'QqJCEEFMbQ2b69o5qMiOOPqIMQkagu/aSL7waE8101WFShLjk9'. + 'yxgEvjRUiyYd+gwAjY2J9VpXfZ/JEXLhDp3OR6U4T97+hEnPwx'. + 'tv4HsRjy2tTQSFzQgDUnwSLBQRI+x1ZgcH87Vcv4SF19Kt0ezS'. + '1h9s0Ma25pgr/YJfnLnEysok0+ezjM6EBLldGqKIJYuDRhOQEJ'. + 'Oih8X9Q0xmcXNjlCofBJgn78wxVz7L2YWf8tPPz1hnfjbjzfxN'. + 'qVwutq2etZXUQSXikcXGIgUiUkJSDIQMJgYGJsaB3c7b1qQ4GZ'. + 'xSkdGZIwMeNLfK6uezMnvJK3pLxeVixfvMsyVjSNSO6IV9adPG'. + 'AArkEEz8oUkFmBjYGO80qfd6pCWIayD59wIKcsjcKqufn7JO/S'. + 'xfyi+5c24pey5rZ09mJRNkiDdT/tzbkBr3SYkpMYpgEaIJSYhI'. + 'kSOY1GhilAQk5ntDIojxCZ/kf87Pl85xbuWEnLiUy+cW3NNuJX'. + 'MmY5meKf6mT7wZS+THdOjxlG06tIlIOMZxchSxcFFEGAwAGGME'. + 'jwyZYSnWL3cXWiIUbUI6hO/vxXuFOV84ycmlBWthNeflTjuzTi'. + 'lzJmM5s46Ej0J63/ZoPmoy6PYxtYVNhmfs0mbAND1mmKVMBY1L'. + 'mxA1LN7WgXQbCApNhKJHRIM+DQbv7yQGhjnJ5NgFuXBuxpu5mD'. + 'udm3LPuY7pmZLUE6L1SIJaIPFuDAqyw9lnwDYv6NFHkWJh4ZDB'. + 'wCBFD3uMxsTAwcBAiElpE/KcPg36dIiOvpsRxDCyhmlP2YY9ZU'. + 'v8NMb/1id+FGO0DTztkSXLOONUqeITsMkW2zwnJEIDFhYGx+A1'. + 'kwK4mASkvKDPc3p0iYhRRwYUhZLUTyV6Eu0t4s1Y4kcx6W6KaM'. + 'EZThcXH59RRhGEgIAddnBwNEBKqqpUtWBIF22YDIhJsbEkJqFN'. + 'qLtERHs7GnUkwISEQAf0uj30bY39PzbiC6qrDu2cExJ69Nhhhz'. + '59UlIUipCQOnVi4sjG7ubJBy6um0C+he/0iDHQKIQERYyKFLqr'. + 'SI/W6kJCnvOcrWSLSquC1/Jw9Ks3R0FQKHr0uMc9bnCDGjX69A'. + 'H0XlcJkibN5jOe/alCZStHbjJL9lSMLkXExvCXRiDV6GZEeGeX'. + '3TvvBVQoEjfBL/v0rT75Th7VU5C8gktI6NLlMY+5yU3WWGODDf'. + 'r098tHpNFNH7/2lKdXXdz7efLzVaqJIBOCmK8AJUlI6g0aV+9y'. + '9+p7AR3bMQpTBWPy7yeN6fy0jNwewfpvC9Xe+3kFoUuXe9zj5n'. + 'BusEGHjh6GIAGawC2FWuvSvbbF1maFylZAsC1ISZADBiVNSJrP'. + 'eX73MY//skHP85z5+fnSxQsXj//4n39cmnPn7LbZlsajBmEnBL'. + '1nuEGDG9x4aa5Ldz+h0RCuBqwBv1Wo+7vs9r7n++0MmYeAM+zB'. + '+61EK1QUEnbbtN+9Bh3Hsebn54u//PdfLq9eWl2ZnZ1dSnaSwu'. + 'Pin40b9g3doKE0WoNIl65xj3v75njd3BBubQi6ExKmDWkMRKSl'. + 'tSbVKQcMao1Go5Ugb0+x53nOyZMnSysrKydXLq1cWlxa/McgCB'. + 'Yev3hU+GPrD3I5/q94k3pXYQY58q6B5Bs0HB//neaGx00gyWaz'. + 'VCoV7bquCoKAnZ0dfN/f03egLGj0m3XQNE1jdnY2/+WXXy6trq'. + '6uzP3oR5eCIFi4detW5feXL1vr679Let37zVB3/mQytjXJwmSB'. + 'wikHp9ShY0RESqObwPrr5oBERKhUKly4cIFqtUq9XufmzZtsbW'. + '2hXvuDwTTNtxZq8TyvsLy8vLS4uLgahOHphw8elL69fNlc++qr'. + 'uFOrNXPddm1cczVL5f5P+Lv5MuOJgTGxwYbZpZsCdeAq8M1Bcw'. + 'CGYeC6LtVqlRMnTjAyMkKn0yGXyx0N0LZt03Ec1zCMSrfXO37v'. + 'zp3S769csb+/ciXt1mrNdHf3ltZ6Lca8ZpJsduhtCdb2gEFJoQ'. + 'xADYHuHDS3f32lFEEQUK/XGRkZoVAocP78eZaXl9FaI/Jq25Uk'. + 'yWHAYrHozM/PlxYWFibTND32sFbLXrtyxVz76qukXas1M61WTW'. + 'm99gx+20TdN9jqtfjP7QzOwwYNp037Zd0DukDnIByA1pqdnR2+'. + '++472u02Z8+eZWJiAsMwDsEBRNGBzYJpmsaJEyfyX3zxxdLS0t'. + 'KlVqu1dP3q1cLta9ekU6u1dat1J9b6Sk9kraV1rYXegW7apDYw'. + 'kFY6fPc4MNTw88bwfZ/NzU2UUnieRxAEiAiGcXiXfcigiIjruo'. + 'VyubxkWdbK7fX1xWvffFMInjzBM82uMT5+p++6V1UUrSe7u03t'. + '+8lezlKt3gHyl0aSJDQaDa5fv876+vo+w6FzDq1BpZRsb2/bly'. + '9f9vL5/Njdu3fzG0+eMJHNxsfn532vXN5NPG/7abPZal6/Hvfe'. + 'kroPHfsm98f7AHW9Xo+//vrrlmVZm71+37QNw3JnZ9PK4uJGpV'. + 'pt4Dh+vLGhsrmcfv1iHzu01m89HjIdCon2fb8TBMHtvYeRUn50'. + '1Oj4vqp3Ok1f5LYSadfr9dQfDN642P/XeF2DA+SBAuA4jkOhUK'. + 'BQKESO43S11p3BYBDt7u4y+CtB/i/q7jp1GMiw2AAAAABJRU5E'. + 'rkJggg==' ; + +//========================================================== +// File: ppl_blue.png +//========================================================== + $this->imgdata_large[3][0]= 2284 ; + $this->imgdata_large[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFRAiTZAL3gAACHlJREFUeJy9mGtv29YZgJ9zKF'. + 'F3y/Q9jh05tuQkarKgbYasde0UBdZgwNou/Vqga/sD9mP2B4a1'. + 'BbZ9atFPxb5sqOtmXbI19bqsluPYiR3HN90vFEWRZx/IJI5zqa'. + 'x0OwBBSgR5Hj7v+55zSEFXTUgIJyA9C6/9RsjMjAyFIxxJCDc7'. + 'iBqKgyZACGg3G2x9+xXf/fG33P3mC9qNKsp1O+1JdkEnQTdgIO'. + 'ttCSMUi8gj072MnugllAyB9G8rBGi6RsToJTF6iuRoFi1kHKZf'. + '7fB8Iggj0/Dy23D2dakNTR3JDsXPvzstxmZGRMER1EwHhQAEgE'. + 'CLhIkPD6InY9S3djGLJVBtQP1Qb4HDAyoJYQOOZkPx49nhTH9i'. + '7MUBGT7egxkJgd70wZS/CUkoZtA/fRoE1DZ2ACiv52ibReCp4e'. + '7CIEHomxDiuVdGTqUnf/ZeOjR8fpiVXZul5ZrY3bWwbdcLr/dA'. + 'AAIpAwQjUWIjQ+g9HZvswiCgBVF9/SI6OSLGzo0i+oLi6+Utbq'. + '+bKEftgwOE/0Ohocf66M+cBjo22U2RQLIHMhmYnvaOpR9S8bSU'. + 'UqCURGpRkuMZMm9cIvPGJZLj0yBjT2LprkiSkykx9cuXIhOnUs'. + 'm+QNC2XdG02ggBTcvFabsPWwTPpBAChSCgh4kYBpoeplWp47Qs'. + '7EYDt21xINzd5GCAxLExRl89Z+nHjpbKMmjbmkgfDzI0JEW53K'. + 'Jaa6NcAOEX8v52uJzsBlAS6u0hcnTIccPRqhWPCUcLD+s1EaUp'. + 'HCEhEMCyHNpt9SjgIU12A6iw6xb123vYhaaKjB9tlgMD5X+uBp'. + 'zdkpg6azA8EaNQtKlVba+Xez4eCntnJrsDdFsW5nYFpxlFN846'. + 'DXe8utkM4mhi+EgQmjYbS2WqexZKk6BpjwJ2YlK5VjeA3pNDiH'. + 'YjRWPzPE7tmBo8EWwGhkXx+z3uXL7D3rU97LIF8RBEAl6lK/Uo'. + '6JNM1rZ2aTcr3eUgIQOGTgbdwXMGyRejenLYTvQGbAdRuetSud'. + 'OivVuFZgtCEgICghICnZoMhmlVTPR49LCAEkQUhk/B7KXe0MWf'. + 'nxj8xVR/cDheK14WZmtVMJSBnlGoN6FmQq0FLfdwJgORKPHRo/'. + 'Snzx4G0F/FjJ4KiOdmjPCrrx8bffnMybMv9MQGNG3rzlVqtR1B'. + 'sh/CYXCD4Aag1oCW7ZnUOjSp6WFi/QNEB8Y7BfTNjZyCmUvJ0I'. + 'XXT47MTp98Ybon9VZCk8cVazfqlNargsY34G7ByAlIjkHd9CCr'. + 'LbBdiHViUgiECuDKYCdz8b2cywREdiYZOj8zNnLuzOTzx6ODp+'. + 'OaGaqwVzBFqz0Idhz2loE7YEwBLaAJLQcKbW8qjAcBF5Jh0AMP'. + 'IOHe6kxgtb3UMO2OxkF//ffK28nQqxfvm3szrtnDVa799Qb/+v'. + 'NtsbNSpm3tAv8B+w7Ub0FhAyoBcMPec9oK6raXk48ziQBXQcmC'. + 'pT3YqHa0mpEBkTR6wz/Jjo2cy04+fzwxdDquNfQKO7sFUbpu0c'. + 'wp3JoAYsA42Bbkl4GCryUNDEM7Avm6Z/CgSYBWG8pNuFuDu1Wo'. + 'tjoxKIJGeHIiM/jmK9NnX5ycuJQMtUcqXPvLDTa+qIie4hAJ1U'. + 'vdrmO2HaDfB931twJgAn1A4lGT96obPHPLBbhVgUoTHHWo9aAA'. + 'JVAKpyKEmQNzWRENAsL18ycKjAFN/9gCNvzLB/390MMmE7pnDi'. + 'Bvwt0K5Jv3O+0oB22nJ1Vvjb/UMhOpcKknqN1OiMB2DNHU2G5s'. + 'sVndpGJVcZXjX1IAlvw9PmhRQcOFPhsSDkiBrQR1G7brgs0a7D'. + 'ag3FK4rguqBXarI4Nt1SJv5gls7TEWtJDRBO2GwnIs8maevFnA'. + 'Gx6awLZvzeTBu4kFbLigijC47pscpx0xyDfkvtUEnlarCDtrUC'. + 't2HGIhvPHVdVwqjTIrxRU2a5uUrYoP0QZ2gMvACl7+3V/LuKDq'. + 'sJuDy597516+CEezIHXv7vcgXQu2l+Bvn8He9Y4AE4kgk5P9DE'. + 'R6aFdq5Et5Nit3yTf3m9sBcsAN3+D98c0Fit5JawE25r1zg1Fo'. + '5B8GFD7g+nVYnu8EUEop9XTa0N/9dUbqcphP/rDJzbUClVbpgR'. + 'y2fXM3fND95qj75J8AC6BWPINfVSBieK+x+6cS5UCzCLu3oFV9'. + 'GqCMx2NGOp2Znpv7aXZudsool3T5J/179sxVlHJ4kGPrP2COBX'. + '/7DmiApWCjxIMXpYNznYuXM+6TAKWUMppOZzLvv//ery5cuDCT'. + 'SqVS336bCwr1JfAPB9r+2KAFwJS+OcETzZHz/7v3etl6ipz77X'. + 'GAMh6PG+l0OjM3NzczOzs3k0pNnFlbW43+e/GKtMqrblSsF03V'. + 'WHcJA0PjIAzvg9JTze2H67g9DjAwOTmZ+uCDD96anZ2dnZiYmF'. + '5dW41++Lvfa1fnr7qllVK9103mXNTnJgPA+YugsvB3HTaEl+Qs'. + 'AZ/yeHPPDCiTyaRx5syZbGoilV1dW00szC9oV+avusuLy0Xd0X'. + 'MgFkDM+zkYBZEHV8f7wwKu84zmngQoNU0LaZoWUa4K31y5qX/8'. + '4cfyyvwVN5/L10NOKNeg8UmDxoKF5Vfj1xXAgD0JrgAcvBDfel'. + 'a4g4AykUgY6XR6emJiIru2ttZXq9S0K19eUcuLy8WQE8o5OAsN'. + 'Ggsmpl+NpoL1g9X4UBU+C9xDgEKIwNTUVOqdd955M9mbnJ3/cj'. + '6Vu5aTheXCQXNdVeMzAwJSCGEA2XKpnF1cXIzlFnOVhJPIKdR+'. + 'c88ctq4AlVKsrKzw0UcfKcC5uXqzXnNqSzb2pwLxOHP/l7Z/BN'. + 'eB01LKt4HTrusKvGr8jB+hGn8MQAkYQMrfw4Nq/MFPtf+rdvDb'. + 'k8QL+/5Z4Uepxm7bfwHuTAVUWpWaqAAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: ppl_green.png +//========================================================== + $this->imgdata_large[4][0]= 2854 ; + $this->imgdata_large[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsRAAALEQF/ZF+RAAAA'. + 'B3RJTUUH0wMLFQ4hANhluwAACrNJREFUeJytmF1zE1eagJ+3u9'. + 'XdkvUty2AbmLEtEzDBgZ0UpDBOalNTUzU3czl7tct/2n+wt3M/'. + 'NVM12SSTQQSyW2TA+QAJQogtYYFtyfrqL3WfvWj5g8AEjzfvhS'. + 'SXjk8//Zz3Pf3qCMcJAWxMKlT4kH+jwu/FknnJSUItKFHzCrKA'. + 'BggBQx5ziz/wn/yBz3hED4/oaJfSjgVoYjJJgTLTZCjohp7IGT'. + 'k5aZ4kb+bRTR30Q7djj8f/kpPMUSCFedRL6W8e8qMQNE6S4xpv'. + 'c5HrTPFubiJ3ZnlyOXV59rJYU5Z00h1c3d0brxAiUkScRijisk'. + '6XLTyiN3s8HuAJpniXa/q8/pt8Or+0kF8oXJm5YiydWcIpOrJu'. + 'rjOQwd54AQwsMpTJYhPSoYuLQ58An/DnBQSdImXO8avsTPbqpc'. + 'lLp67OXDVzMznZLGxSs2qyIRu4at8gKHQEC50kE1icxqCAdxST'. + 'xjEA44tqaJlERl8uLWvvnX5PHuQfcCdxh5qq0aX76vj4WgWyXO'. + 'QiNgBP8IAaddr08X8+wHFmJSQhBbPAZGoSZSt5wQs6qoNC7UEd'. + '4AEoLIQSCaCCy78Dv8Tiv1hjjW1CRj8XIAgEKqDtt9keboMJZa'. + 'vMjuzQVd3Xr9prTJo+GF/jKZea95R25Lxs8jg5qFGiwDnOS0mW'. + 'NE0rjNRIt3WbklUCA9mV3Zdz8OBT/JfCQLB0SKYVVjGFYSfx/E'. + '26ow4e6uDujlPFQpE0FU6P8qNTHdXJdEdda0qf0itWBVM3pa/3'. + 'ccUlIECJet0cAJoeYk5EZCeS5IwEoerSxccJBwRqFFf38QCTaO'. + 'TRVFKJm3NTbtLNSyh2IkhIXsvLCesEGNCWdmwyruSD/z9kUlRc'. + '3bqNlSxhJNJ43p5JITrOEis8Qtr0cXEpU/JT/pmO18n2vb42pU'. + '3JnDnHMBqyPlpnoAaxhr2llv1ZUBqEGlqYwDQMsskMOcMgVL3Y'. + 'ZOQTHAcQQiIGjHCwCaiovjrv4hbcpKuJJjIcDHm685RGr4GLCx'. + 'YHkAcrLoAoDSLBiAQrMkjqybHJCbxgh+7xAC1MpsgzwRwD3qHL'. + 'WyTIBdlAa6u2rHfXaew06PV78ZZjAwleNnkolECoH5i090wOcY'. + '+TgwYzFHiPi1zkOkXexeAMASnVU+LiyiA1wFUuaqggACLizeWw'. + 'ycMzyssmVYKkbpGyC5T+OUALk2mKLHKWf+ED/az+YW42d66YL+'. + 'aNrmEEzQCFEnKw368EgEvcN1m80eTIQIt0TFOjMJHkzNEBBYPp'. + 'sblf8QHzrORO5JaWZ5ZLl6cuJyyxpNPv4PZdoT+GyIxBfI5uUg'. + 'eJMCwP2/bIHO1JEudcgUUWOceKNq99mCvnzs5PzRcuTV4y5mRO'. + 'SMIjo47z5S7a94oQCNKgJsZwO7D/IDNg3/LLhRNXt4JohBb4aG'. + '82GLdXcf93mQ+Y43r2RHZp+cRy6cqJK4l8MS+tdItaqiYtc0Mm'. + 'QpfJARh98HYh9IiXVcaAo58wGb+LBAjbSPgCOcoSa0wzxXtc08'. + '/pv8mfyL+9MLVQvDJ1JVHJV6SZbFI1qtTsB+KlehRtRTGE8Afo'. + 'P4DRcAxiEudhAHjjzz+ubgX4oHowakHQOlqzICQwyVPITGVOXi'. + 'xfLF6aumzmczl5lHzMff2+fCdPaGttEkXoLQAO9B7C6EugPYby'. + 'gVPjGXc5eIbNAJPjGwiAbaAJUQv8wVG7GROkJFpyOqn/ovgLba'. + '44L0+sDaraXb6jzq7aBQWjBOyUoHcaopOgmaA3IRyNDZnA1HjO'. + 'HSBkr7eEFDAEngHrQCf+/s2A8cSiSkqcKUeeTjwFy2Jd78t3+L'. + 'TR4itIiBLwLQhzkJyB5Cx4HXDaENVQCBAQcRqFIHTRaBIvuYXg'. + 'AdsouuNxEL0ZUBHnSQp66R73zYfUtQ6OytKT8RckQAJQoLtgO5'. + 'BJgj0D/WfgdyHaAHx8THoUcbGx8ciwhUl3bDEiToURPooeI7pH'. + 'MziK9Yd9nU5a6GgKjOH41vsgI4hAcyC5AZkapF+AoYNrjjsuhx'. + 'FbtPmeB5ykyQQzTPAWAQWC8S9oAI0QRRuPb9jkmyMZNAOTklvC'. + 'GGYZaFkGmkVAh8h4DtKFMIBunG+pB5B5AIkGBDsQ+qBiL20caj'. + 'zhJknq5KlgMkLjJHJos4kYEbFJi5vc5eYbATVN02bNWe19+32t'. + 'aJWlFm3wbf8Rz5NbDFJdlOFBF/g7cBf0JkrbBb+F6j1DOduEkU'. + '8bWCOiSofPWadBnSZDWmgUkEMGhZCINut8S/0NBtPptFlZrBSu'. + 'vnt1+ndnflfIp9OJ/279Ubbbd+lP7KBKPoEBsgnqLph/BRzwdS'. + 'LnBUFvHcfdpRsGPAGqwMco6jynz+e0SPKYCHMfLX5VKHwcenR+'. + 'Igd1XTcqlUr+xn/cePv91fevzy8sLO2OtrOpWkqL7gXKSAVRdh'. + 'ZFEmEXoYkwBNqovoc/3GHH3aUR+jwC1oD/AWrANi4hGwyBzqEG'. + 'Vvb77Dgi0eT1VZzJZMxKpVJYXV1dXF1dXVm6sPSvruue3Xzcyj'. + '6/syvDzwj0lNazK6Fj5LFCRZouZpBABj6jXouu3+Np6HNvDHaf'. + 'g91t74msbMuOJicnSSaTKKUQEUQEpRSO69But1/dB0VEm5uby9'. + 'y4cWNpdXX1+sLCworrume//PuXpeqnVeOban0U1PW2kcx+O9L7'. + 'Te9sUB4lWFR9SqNtNGcHx+/RDD2+Am4D94CnQA8OjjlEhMnyJC'. + 'srK8zOzu7BiYioMAzZ2Njg9u3brwIqpSSXy2WXl5eXLly4sOo4'. + 'zoV6vV6oflrVP/7Tx8Hmw1Zb6ydqmpWp7ha8h4O3gjOhzVANmF'. + 'XPMNQWvdDnCXCXuHR+APqH4fbCtm2mp6eZn59H13WJuYXRaKSU'. + 'UiSTyVcBdV3XDcOwRaTU7/en19bWCn/79G+JL/76RbhZ22y7u+'. + '6ahl71nPDz/nO17m7wAxlabFOihy4+DvAcqAMbPzZ3OFzX5dmz'. + 'Z2iahoiosUUVhiGNRgPHcV4GzGQy5uLiYuH8+fMzo9FoslarJW'. + '9+elP75E+fBJu1zY7qqpqBUW3T/niohnVvy+1zm5aVtp+WE2XT'. + 'nrHFzbjh1tYLz3XdPjD4R3BKKba2tqhWq4dzUO3noBPn4H5PKy'. + 'LaO++8U7hx48byhQsXVne7u6tf3/v64t3P7mbq9+odt+OuaWi3'. + 'PLxbW2ytubjbQCgiMnt6VlaurWgz0zM0m02q1WrUaDSUUuqI56'. + 'ivDxE5MCgiYllWtlwuL5mmufLV/a/O/uXPf9Ff1F+80Lv6Yx29'. + '2qHzyZBh3cdvc7gaTZuZkzPh/Py8ACqVSv1/uPZDKXUAGEWRtF'. + 'qtxEcffZTL5XLF+2v39fqjeivshA/TpP83JLwzYFBzcA4370Cc'. + 'S81nTRBUs9lkOByi1GuOPI4Rh3+26JZlnSkWi781DOPXvV4v3+'. + '/2G0R8kSBxB/jew+tERK+c49m2TblcxrZtXNfl+fPneJ6HZVmU'. + 'y2VJJpNyaJ9TSinlOA5bW1u4rntkQA0oAG8D54gb9W3ianxM3A'. + 'e/cn73U3Hq1Cm5du2aPjs7a+ztcSIShmE4ajQa6tatWzQajZ+0'. + 'fbiKI+It4SvijVUj7kL2qvGfgkskEqTTaZmcnDROnTplJhIJTU'. + 'QiwPd9P/Q8T6XTaQzDIAiCfzjP/wFVfszuFqdHXgAAAABJRU5E'. + 'rkJggg==' ; + + +//========================================================== +// File: pp_red.png +//========================================================== + $this->imgdata_small[0][0]= 384 ; + $this->imgdata_small[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhouFobZrQAAAQ1JREFUeJyV1dFtwyAQBuD/og'. + 'xQdYxa8gRY6hJ0jK6QdohMkTEuE5wUj5ERen05IoLvID7Jkn2G'. + 'j8MgTMyMXqRlUQBYq9ydmaL2h1cwqD7l30t+L1iwlbYFRegY7I'. + 'SHjkEifGg4ww3aBa/l4+9AhxWWr/dLhEunXUGHq6yGniw3QkOw'. + '3jJ7UBd82n/VVAlAtvsfp98lAj2sAJOhU4AeQ7DC1ubVBODWDJ'. + 'TtCsEWa6u5M1NeFs1NzgdtuhHGtj+9Q2IDppQUAL6Cyrlz0gDN'. + 'ohSMiJCt861672EiAhEhESG3woJ9V9OKTkwRKbdqz4cHmFLSFg'. + 's69+LvAZKdeZ/n89uLnd2g0S+gjd5g8zzjH5Y/eLLi+NPEAAAA'. + 'AElFTkSuQmCC' ; + +//========================================================== +// File: pp_orange.png +//========================================================== + $this->imgdata_small[1][0]= 403 ; + $this->imgdata_small[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhwAnApz5AAAASBJREFUeJyN1dFthDAMBuDf7S'. + '3BCm2VCRKpS4QxbhikW6IewzcBqm6Fm6JyH7iEEByCn5AJH38g'. + 'BBIRHNUzBAWAGNfe/SrUGv92CtNt309BrfFdMGPjvt9CD8Fyml'. + 'ZZaDchRgA/59FDMD18pvNoNyHxMnUmgLmPHoJ+CqqfMaNAH22C'. + 'fgqKRwR+GRpxGjXBEiuXDBWQhTK3plxijyWWvtKVS5KNG1xM8I'. + 'OBr7geV1WupDqpmTAPKjCqLhxk/z0PImQmjKrAuI6vMXlhFroD'. + 'vfdqITXWqg2YMSJEAFcReoag6UXU2DzPG8w5t09YYsAyLWvHrL'. + 'HUy6D3XmvMAAhAay8kAJpBosX4vt0G4+4Jam6s6Rz1fgFG0ncA'. + 'f3XfOQcA+Acv5IUSdQw9hgAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: pp_pink.png +//========================================================== + $this->imgdata_small[2][0]= 419 ; + $this->imgdata_small[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhsQzvz1RwAAATBJREFUeJyd1MFthDAQheF/oi'. + 'gF+JYWQKICkCJRA1vGtrDbxFbhGvY0HVjCLeS2BeTiHFgTB2wg'. + 'eRISstCnmcG2qCpbuXf3ADBQzWsPfZfS9y9HsEu4/Fo33Wf4Fx'. + 'gxL3a1XkI3wbTNXHLoboVeLFUYDqObYBy+Fw/Uh9DdCmtOwIjF'. + 'YvG76CZoOhNGRmpO8zz30CJoOhMAqlDxFzQLppgXj2XaNlP7FF'. + 'GLL7ccMYCBgZERgCvXLBrfi2DEclmiKZwFY4tp6sW26bVfnede'. + 'e5Hc5dC2bUgrXGKqWrwcXnNYDjmCrcCIiQgDcFYV05kQ8SXmnB'. + 'NgPiVN06wrTDGAhz5EWY/FOccTk+cTnHM/YNu2YYllgFxCWuUM'. + 'ikzGx+2Gc+4N+CoJW8n+5a2UKm2aBoBvGA6L7wfl8aoAAAAASU'. + 'VORK5CYII=' ; + + +//========================================================== +// File: pp_blue.png +//========================================================== + $this->imgdata_small[3][0]= 883 ; + $this->imgdata_small[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAACi1'. + 'BMVEX///8AAAAAADMAAGYAAJkAAMwAAP8zAAAzADMzAGYzAJkz'. + 'AMwzAP9mAABmADNmAGZmAJlmAMxmAP+ZAACZADOZAGaZAJmZAM'. + 'yZAP/MAADMADPMAGbMAJnMAMzMAP//AAD/ADP/AGb/AJn/AMz/'. + 'AP8AMwAAMzMAM2YAM5kAM8wAM/8zMwAzMzMzM2YzM5kzM8wzM/'. + '9mMwBmMzNmM2ZmM5lmM8xmM/+ZMwCZMzOZM2aZM5mZM8yZM//M'. + 'MwDMMzPMM2bMM5nMM8zMM///MwD/MzP/M2b/M5n/M8z/M/8AZg'. + 'AAZjMAZmYAZpkAZswAZv8zZgAzZjMzZmYzZpkzZswzZv9mZgBm'. + 'ZjNmZmZmZplmZsxmZv+ZZgCZZjOZZmaZZpmZZsyZZv/MZgDMZj'. + 'PMZmbMZpnMZszMZv//ZgD/ZjP/Zmb/Zpn/Zsz/Zv8AmQAAmTMA'. + 'mWYAmZkAmcwAmf8zmQAzmTMzmWYzmZkzmcwzmf9mmQBmmTNmmW'. + 'ZmmZlmmcxmmf+ZmQCZmTOZmWaZmZmZmcyZmf/MmQDMmTPMmWbM'. + 'mZnMmczMmf//mQD/mTP/mWb/mZn/mcz/mf8AzAAAzDMAzGYAzJ'. + 'kAzMwAzP8zzAAzzDMzzGYzzJkzzMwzzP9mzABmzDNmzGZmzJlm'. + 'zMxmzP+ZzACZzDOZzGaZzJmZzMyZzP/MzADMzDPMzGbMzJnMzM'. + 'zMzP//zAD/zDP/zGb/zJn/zMz/zP8A/wAA/zMA/2YA/5kA/8wA'. + '//8z/wAz/zMz/2Yz/5kz/8wz//9m/wBm/zNm/2Zm/5lm/8xm//'. + '+Z/wCZ/zOZ/2aZ/5mZ/8yZ///M/wDM/zPM/2bM/5nM/8zM////'. + '/wD//zP//2b//5n//8z///9jJVUgAAAAAXRSTlMAQObYZgAAAA'. + 'FiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElN'. + 'RQfTAwkWGTNerea3AAAAYUlEQVR4nHXNwQ3AIAxDUUfyoROxRZ'. + 'icARin0EBTIP3Hp1gBRqSqYo0seqjZpnngojlWBir5+b8o06lM'. + 'ha5uFKEpDZulV8l52axhVzqaCdxQp32qVSSwC1wN3fYiw7b76w'. + 'bN4SMue4/KbwAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: pp_green.png +//========================================================== + $this->imgdata_small[4][0]= 447 ; + $this->imgdata_small[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABm'. + 'JLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wMJFhkLdq9eKQAAAUxJREFUeJyN1LFVwzAQxvH/8f'. + 'IeDS0FLKABlN6eIwPYAzCHB0gWYI2jj+i1ABUTQN4TRSQ7iiWZ'. + 'qxLn9Mt9ydmiqrSq930AYFiu6YdKrf/hP1gYQn6960PxwBaYMG'. + 'E9UA3dBFtVQjdBOQmBakLennK0CapRwbZRZ3N0O/IeEsqp3HKL'. + 'Smtt5pUZgTPg4gdDud+6xoS97wM2rsxxmRSoTgoVcMZsXJkBho'. + 'SmKqCuOuEtls6nmGMFPTUmxBKx/MeyNfQGLoOOiC2ddsxb1Kzv'. + 'ZzUqu5IXbGDvBJf+hDisi77qFSuhq7Xpuu66TyJLRGbsXVUPxV'. + 'SxsgkzDMt0mKT3/RcjL8C5hHnvJToXY0xYRZ4xnVKsV/S+a8YA'. + 'AvCb3s9g13UhYj+TTo93B3fApRV1FVlEAD6H42DjN9/WvzDYuJ'. + 'dL5b1/ji+/IX8EGWP4AwRii8PdFHTqAAAAAElFTkSuQmCC' ; + } +} + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_stars.inc b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_stars.inc new file mode 100644 index 0000000..0149c7c --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/imgdata_stars.inc @@ -0,0 +1,144 @@ + 'imgdata'); + + protected $colors = array('bluegreen','lightblue','purple','blue','green','pink','red','yellow'); + protected $index = array('bluegreen'=>3,'lightblue'=>4,'purple'=>1, + 'blue'=>5,'green'=>0,'pink'=>7,'red'=>2,'yellow'=>6); + protected $maxidx = 7 ; + protected $imgdata ; + + function ImgData_Stars() { +//========================================================== +// File: bstar_green_001.png +//========================================================== + $this->imgdata[0][0]= 329 ; + $this->imgdata[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAAUV'. + 'BMVEX///////+/v7+83rqcyY2Q/4R7/15y/1tp/05p/0lg/zdX'. + '/zdX/zVV/zdO/zFJ9TFJvDFD4yg+8Bw+3iU68hwurhYotxYosx'. + 'YokBoTfwANgQFUp7DWAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgF'. + 'HUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJj'. + 'CRyxgTAAAAcUlEQVR4nH3MSw6AIAwEUBL/IKBWwXL/g0pLojUS'. + 'ZzGLl8ko9Zumhr5iy66/GH0dp49llNPB5sTotDY5PVuLG6tnM9'. + 'CVKSIe1joSgPsAKSuANNaENFQvTAGzmheSkUpMBWeJZwqBT8wo'. + 'hmysD4bnnPsC/x8ItUdGPfAAAAAASUVORK5CYII=' ; +//========================================================== +// File: bstar_blred.png +//========================================================== + $this->imgdata[1][0]= 325 ; + $this->imgdata[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79uRJ6jWPOSUtKrb+ejWO+gWPaGTruJTr6rZvF2'. + 'RqC2ocqdVuCeV+egV/GsnLuIXL66rMSpcOyATbipY/OdWOp+VK'. + 'aTU9WhV+yJKBoLAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJwynv1'. + 'XVAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bstar_red_001.png +//========================================================== + $this->imgdata[2][0]= 325 ; + $this->imgdata[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+eRFHzWG3SUmHnb37vWGr2WHG7Tlm+TljxZneg'. + 'Rk3KoaXgVmXnV2nxV227nJ++XGzErK3scIS4TVzzY3fqWG2mVF'. + 'zVU2PsV2rJFw9VAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJzCI0C'. + 'lSAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bstar_blgr_001.png +//========================================================== + $this->imgdata[3][0]= 325 ; + $this->imgdata[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79Ehp5Yx/NSq9Jvw+dYwu9YzfZOmbtOmb5myPFG'. + 'gqChvcpWteBXvedXxvGcsbtcpb6su8RwzOxNmrhjyvNYwupUjK'. + 'ZTr9VXwOyJhmWNAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJTC65k'. + 'vQAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bstar_blgr_002.png +//========================================================== + $this->imgdata[4][0]= 325 ; + $this->imgdata[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79EnpxY8/FS0dJv5+dY7+9Y9vBOubtOur5m8fFG'. + 'nKChycpW3uBX5+ZX8e2curtcvrqswsRw7OdNuLZj8/BY6udUpK'. + 'ZT1dRX7OtNkrW5AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJgXHeN'. + 'wwAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bstar_blue_001.png +//========================================================== + $this->imgdata[5][0]= 325 ; + $this->imgdata[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v79EY55Yi/NSetJvledYiO9YkPZOb7tObr5mkvFG'. + 'X6ChrcpWgOBXhedXi/Gcpbtcf76sssRwnOxNcbhjk/NYiepUbK'. + 'ZTfdVXh+ynNEzzAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJhStyP'. + 'zCAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bstar_oy_007.png +//========================================================== + $this->imgdata[6][0]= 325 ; + $this->imgdata[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+ejUTz11jSvVLn02/v1lj21li7q06+r07x2mag'. + 'lUbKxKHgy1bnz1fx1Ve7t5y+qlzEwqzs03C4pE3z2WPqz1imml'. + 'TVv1Ps01dGRjeyAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJjsGGc'. + 'GbAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + +//========================================================== +// File: bstar_lred.png +//========================================================== + $this->imgdata[7][0]= 325 ; + $this->imgdata[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAMAAABsDg4iAAAATl'. + 'BMVEX///+/v7+eRJPzWN3SUr7nb9TvWNj2WOS7Tqi+TqnxZtyg'. + 'Ro/KocPgVsjnV9LxV927nLa+XLTErL7scN24TarzY9/qWNemVJ'. + 'jVU8LsV9VCwcc9AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgA'. + 'AAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTAxYTJxi9ZY'. + 'GoAAAAcElEQVR4nH3MyQ6AIAwEUFIqiwju2///qLQmWiJxDnN4'. + 'mYxSv5lqGCs2nvaLLtZx/VhGOW1MjnPJWp0zsw2wsUY2jd09BY'. + 'DFmESC+BwA5UCUxhqAhqrA4CGrLpCMVGK4sZe4B+/5RLdiyMb6'. + 'on/PuS9CdQNC7yBXEQAAAABJRU5ErkJggg==' ; + } +} + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpg-config.inc.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpg-config.inc.php new file mode 100644 index 0000000..aecd7a6 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpg-config.inc.php @@ -0,0 +1,227 @@ + diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php new file mode 100644 index 0000000..7f15448 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph.php @@ -0,0 +1,7896 @@ +Get(11,$file,$lineno); + die($msg); + } + else { + DEFINE('CACHE_DIR', $_SERVER['TEMP'] . '/'); + } + } else { + DEFINE('CACHE_DIR','/tmp/jpgraph_cache/'); + } + } +} +elseif( !defined('CACHE_DIR') ) { + DEFINE('CACHE_DIR', ''); +} + +if (!defined('TTF_DIR')) { + if (strstr( PHP_OS, 'WIN') ) { + $sroot = getenv('SystemRoot'); + if( empty($sroot) ) { + $t = new ErrMsgText(); + $msg = $t->Get(12,$file,$lineno); + die($msg); + } + else { + DEFINE('TTF_DIR', $sroot.'/fonts/'); + } + } else { + DEFINE('TTF_DIR','/usr/X11R6/lib/X11/fonts/truetype/'); + } +} + +//------------------------------------------------------------------ +// Constants which are used as parameters for the method calls +//------------------------------------------------------------------ + + +// Tick density +DEFINE("TICKD_DENSE",1); +DEFINE("TICKD_NORMAL",2); +DEFINE("TICKD_SPARSE",3); +DEFINE("TICKD_VERYSPARSE",4); + +// Side for ticks and labels. +DEFINE("SIDE_LEFT",-1); +DEFINE("SIDE_RIGHT",1); +DEFINE("SIDE_DOWN",-1); +DEFINE("SIDE_BOTTOM",-1); +DEFINE("SIDE_UP",1); +DEFINE("SIDE_TOP",1); + +// Legend type stacked vertical or horizontal +DEFINE("LEGEND_VERT",0); +DEFINE("LEGEND_HOR",1); + +// Mark types for plot marks +DEFINE("MARK_SQUARE",1); +DEFINE("MARK_UTRIANGLE",2); +DEFINE("MARK_DTRIANGLE",3); +DEFINE("MARK_DIAMOND",4); +DEFINE("MARK_CIRCLE",5); +DEFINE("MARK_FILLEDCIRCLE",6); +DEFINE("MARK_CROSS",7); +DEFINE("MARK_STAR",8); +DEFINE("MARK_X",9); +DEFINE("MARK_LEFTTRIANGLE",10); +DEFINE("MARK_RIGHTTRIANGLE",11); +DEFINE("MARK_FLASH",12); +DEFINE("MARK_IMG",13); +DEFINE("MARK_FLAG1",14); +DEFINE("MARK_FLAG2",15); +DEFINE("MARK_FLAG3",16); +DEFINE("MARK_FLAG4",17); + +// Builtin images +DEFINE("MARK_IMG_PUSHPIN",50); +DEFINE("MARK_IMG_SPUSHPIN",50); +DEFINE("MARK_IMG_LPUSHPIN",51); +DEFINE("MARK_IMG_DIAMOND",52); +DEFINE("MARK_IMG_SQUARE",53); +DEFINE("MARK_IMG_STAR",54); +DEFINE("MARK_IMG_BALL",55); +DEFINE("MARK_IMG_SBALL",55); +DEFINE("MARK_IMG_MBALL",56); +DEFINE("MARK_IMG_LBALL",57); +DEFINE("MARK_IMG_BEVEL",58); + +// Inline defines +DEFINE("INLINE_YES",1); +DEFINE("INLINE_NO",0); + +// Format for background images +DEFINE("BGIMG_FILLPLOT",1); +DEFINE("BGIMG_FILLFRAME",2); +DEFINE("BGIMG_COPY",3); +DEFINE("BGIMG_CENTER",4); + +// Depth of objects +DEFINE("DEPTH_BACK",0); +DEFINE("DEPTH_FRONT",1); + +// Direction +DEFINE("VERTICAL",1); +DEFINE("HORIZONTAL",0); + + +// Axis styles for scientific style axis +DEFINE('AXSTYLE_SIMPLE',1); +DEFINE('AXSTYLE_BOXIN',2); +DEFINE('AXSTYLE_BOXOUT',3); +DEFINE('AXSTYLE_YBOXIN',4); +DEFINE('AXSTYLE_YBOXOUT',5); + +// Style for title backgrounds +DEFINE('TITLEBKG_STYLE1',1); +DEFINE('TITLEBKG_STYLE2',2); +DEFINE('TITLEBKG_STYLE3',3); +DEFINE('TITLEBKG_FRAME_NONE',0); +DEFINE('TITLEBKG_FRAME_FULL',1); +DEFINE('TITLEBKG_FRAME_BOTTOM',2); +DEFINE('TITLEBKG_FRAME_BEVEL',3); +DEFINE('TITLEBKG_FILLSTYLE_HSTRIPED',1); +DEFINE('TITLEBKG_FILLSTYLE_VSTRIPED',2); +DEFINE('TITLEBKG_FILLSTYLE_SOLID',3); + +// Style for background gradient fills +DEFINE('BGRAD_FRAME',1); +DEFINE('BGRAD_MARGIN',2); +DEFINE('BGRAD_PLOT',3); + +// Width of tab titles +DEFINE('TABTITLE_WIDTHFIT',0); +DEFINE('TABTITLE_WIDTHFULL',-1); + +// Defines for 3D skew directions +DEFINE('SKEW3D_UP',0); +DEFINE('SKEW3D_DOWN',1); +DEFINE('SKEW3D_LEFT',2); +DEFINE('SKEW3D_RIGHT',3); + +// Line styles +DEFINE('LINESTYLE_DOTTED',1); +DEFINE('LINESTYLE_DASHED',2); +DEFINE('LINESTYLE_LONGDASH',3); +DEFINE('LINESTYLE_SOLID',4); + +// For internal use only +DEFINE("_JPG_DEBUG",false); +DEFINE("_FORCE_IMGTOFILE",false); +DEFINE("_FORCE_IMGDIR",'/tmp/jpgimg/'); + +function CheckPHPVersion($aMinVersion) +{ + list($majorC, $minorC, $editC) = split('[/.-]', PHP_VERSION); + list($majorR, $minorR, $editR) = split('[/.-]', $aMinVersion); + + if ($majorC > $majorR) return true; + if ($majorC < $majorR) return false; + // same major - check ninor + if ($minorC > $minorR) return true; + if ($minorC < $minorR) return false; + // and same minor + if ($editC >= $editR) return true; + return true; +} + +// +// Make sure PHP version is high enough +// +if( !CheckPHPVersion(MIN_PHPVERSION) ) { + JpGraphError::RaiseL(13,PHP_VERSION,MIN_PHPVERSION); +} + + +// +// Make GD sanity check +// +if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) { + JpGraphError::RaiseL(25001); +//("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)"); +} + +// +// Setup PHP error handler +// +function _phpErrorHandler($errno,$errmsg,$filename, $linenum, $vars) { + // Respect current error level + if( $errno & error_reporting() ) { + JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); + } +} + +if( INSTALL_PHP_ERR_HANDLER ) { + set_error_handler("_phpErrorHandler"); +} + +// +//Check if there were any warnings, perhaps some wrong includes by the +//user +// +if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && + !preg_match('|Deprecated|', $GLOBALS['php_errormsg']) ) { + JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']); +} + + +// Useful mathematical function +function sign($a) {return $a >= 0 ? 1 : -1;} + +// Utility function to generate an image name based on the filename we +// are running from and assuming we use auto detection of graphic format +// (top level), i.e it is safe to call this function +// from a script that uses JpGraph +function GenImgName() { + // Determine what format we should use when we save the images + $supported = imagetypes(); + if( $supported & IMG_PNG ) $img_format="png"; + elseif( $supported & IMG_GIF ) $img_format="gif"; + elseif( $supported & IMG_JPG ) $img_format="jpeg"; + elseif( $supported & IMG_WBMP ) $img_format="wbmp"; + elseif( $supported & IMG_XPM ) $img_format="xpm"; + + + if( !isset($_SERVER['PHP_SELF']) ) + JpGraphError::RaiseL(25005); +//(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files."); + $fname = basename($_SERVER['PHP_SELF']); + if( !empty($_SERVER['QUERY_STRING']) ) { + $q = @$_SERVER['QUERY_STRING']; + $fname .= '_'.preg_replace("/\W/", "_", $q).'.'.$img_format; + } + else { + $fname = substr($fname,0,strlen($fname)-4).'.'.$img_format; + } + return $fname; +} + + +//=================================================== +// CLASS JpgTimer +// Description: General timing utility class to handle +// time measurement of generating graphs. Multiple +// timers can be started. +//=================================================== +class JpgTimer { + private $start, $idx; +//--------------- +// CONSTRUCTOR + function JpgTimer() { + $this->idx=0; + } + +//--------------- +// PUBLIC METHODS + + // Push a new timer start on stack + function Push() { + list($ms,$s)=explode(" ",microtime()); + $this->start[$this->idx++]=floor($ms*1000) + 1000*$s; + } + + // Pop the latest timer start and return the diff with the + // current time + function Pop() { + assert($this->idx>0); + list($ms,$s)=explode(" ",microtime()); + $etime=floor($ms*1000) + (1000*$s); + $this->idx--; + return $etime-$this->start[$this->idx]; + } +} // Class + +$gJpgBrandTiming = BRAND_TIMING; +//=================================================== +// CLASS DateLocale +// Description: Hold localized text used in dates +//=================================================== +class DateLocale { + + public $iLocale = 'C'; // environmental locale be used by default + private $iDayAbb = null, $iShortDay = null, $iShortMonth = null, $iMonthName = null; + +//--------------- +// CONSTRUCTOR + function DateLocale() { + settype($this->iDayAbb, 'array'); + settype($this->iShortDay, 'array'); + settype($this->iShortMonth, 'array'); + settype($this->iMonthName, 'array'); + + + $this->Set('C'); + } + +//--------------- +// PUBLIC METHODS + function Set($aLocale) { + if ( in_array($aLocale, array_keys($this->iDayAbb)) ){ + $this->iLocale = $aLocale; + return TRUE; // already cached nothing else to do! + } + + $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME + + if (is_array($aLocale)) { + foreach ($aLocale as $loc) { + $res = @setlocale(LC_TIME, $loc); + if ( $res ) { + $aLocale = $loc; + break; + } + } + } + else { + $res = @setlocale(LC_TIME, $aLocale); + } + + if ( ! $res ){ + JpGraphError::RaiseL(25007,$aLocale); +//("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region."); + return FALSE; + } + + $this->iLocale = $aLocale; + for ( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ){ + $day = strftime('%a', strtotime("$ofs day")); + $day[0] = strtoupper($day[0]); + $this->iDayAbb[$aLocale][]= $day[0]; + $this->iShortDay[$aLocale][]= $day; + } + + for($i=1; $i<=12; ++$i) { + list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01"))); + $this->iShortMonth[$aLocale][] = ucfirst($short); + $this->iMonthName [$aLocale][] = ucfirst($full); + } + + setlocale(LC_TIME, $pLocale); + + return TRUE; + } + + + function GetDayAbb() { + return $this->iDayAbb[$this->iLocale]; + } + + function GetShortDay() { + return $this->iShortDay[$this->iLocale]; + } + + function GetShortMonth() { + return $this->iShortMonth[$this->iLocale]; + } + + function GetShortMonthName($aNbr) { + return $this->iShortMonth[$this->iLocale][$aNbr]; + } + + function GetLongMonthName($aNbr) { + return $this->iMonthName[$this->iLocale][$aNbr]; + } + + function GetMonth() { + return $this->iMonthName[$this->iLocale]; + } +} + +$gDateLocale = new DateLocale(); +$gJpgDateLocale = new DateLocale(); + +//======================================================= +// CLASS Footer +// Description: Encapsulates the footer line in the Graph +//======================================================= +class Footer { + public $iLeftMargin = 3, $iRightMargin = 3, $iBottomMargin = 3 ; + public $left,$center,$right; + + function Footer() { + $this->left = new Text(); + $this->left->ParagraphAlign('left'); + $this->center = new Text(); + $this->center->ParagraphAlign('center'); + $this->right = new Text(); + $this->right->ParagraphAlign('right'); + } + + function SetMargin($aLeft=3,$aRight=3,$aBottom=3) { + $this->iLeftMargin = $aLeft; + $this->iRightMargin = $aRight; + $this->iBottomMargin = $aBottom; + } + + function Stroke($aImg) { + $y = $aImg->height - $this->iBottomMargin; + $x = $this->iLeftMargin; + $this->left->Align('left','bottom'); + $this->left->Stroke($aImg,$x,$y); + + $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2; + $this->center->Align('center','bottom'); + $this->center->Stroke($aImg,$x,$y); + + $x = $aImg->width - $this->iRightMargin; + $this->right->Align('right','bottom'); + $this->right->Stroke($aImg,$x,$y); + } +} + + +//=================================================== +// CLASS Graph +// Description: Main class to handle graphs +//=================================================== +class Graph { + public $cache=null; // Cache object (singleton) + public $img=null; // Img object (singleton) + public $plots=array(); // Array of all plot object in the graph (for Y 1 axis) + public $y2plots=array();// Array of all plot object in the graph (for Y 2 axis) + public $ynplots=array(); + public $xscale=null; // X Scale object (could be instance of LinearScale or LogScale + public $yscale=null,$y2scale=null, $ynscale=array(); + public $iIcons = array(); // Array of Icons to add to + public $cache_name; // File name to be used for the current graph in the cache directory + public $xgrid=null; // X Grid object (linear or logarithmic) + public $ygrid=null,$y2grid=null; //dito for Y + public $doframe=true,$frame_color=array(0,0,0), $frame_weight=1; // Frame around graph + public $boxed=false, $box_color=array(0,0,0), $box_weight=1; // Box around plot area + public $doshadow=false,$shadow_width=4,$shadow_color=array(102,102,102); // Shadow for graph + public $xaxis=null; // X-axis (instane of Axis class) + public $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class) + public $margin_color=array(200,200,200); // Margin color of graph + public $plotarea_color=array(255,255,255); // Plot area color + public $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object + public $axtype="linlin"; // Type of axis + public $xtick_factor,$ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width + public $texts=null, $y2texts=null; // Text object to ge shown in the graph + public $lines=null, $y2lines=null; + public $bands=null, $y2bands=null; + public $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale in fractions and for centering bars + public $background_image="",$background_image_type=-1,$background_image_format="png"; + public $background_image_bright=0,$background_image_contr=0,$background_image_sat=0; + public $image_bright=0, $image_contr=0, $image_sat=0; + public $inline; + public $showcsim=0,$csimcolor="red"; //debug stuff, draw the csim boundaris on the image if <>0 + public $grid_depth=DEPTH_BACK; // Draw grid under all plots as default + public $iAxisStyle = AXSTYLE_SIMPLE; + public $iCSIMdisplay=false,$iHasStroked = false; + public $footer; + public $csimcachename = '', $csimcachetimeout = 0, $iCSIMImgAlt=''; + public $iDoClipping = false; + public $y2orderback=true; + public $tabtitle; + public $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN; + public $bkg_gradfrom='navy', $bkg_gradto='silver'; + public $titlebackground = false; + public $titlebackground_color = 'lightblue', + $titlebackground_style = 1, + $titlebackground_framecolor = 'blue', + $titlebackground_framestyle = 2, + $titlebackground_frameweight = 1, + $titlebackground_bevelheight = 3 ; + public $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID; + public $titlebkg_scolor1='black',$titlebkg_scolor2='white'; + public $framebevel = false, $framebeveldepth = 2 ; + public $framebevelborder = false, $framebevelbordercolor='black'; + public $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4'; + public $background_image_mix=100; + public $background_cflag = ''; + public $background_cflag_type = BGIMG_FILLPLOT; + public $background_cflag_mix = 100; + public $iImgTrans=false, + $iImgTransHorizon = 100,$iImgTransSkewDist=150, + $iImgTransDirection = 1, $iImgTransMinSize = true, + $iImgTransFillColor='white',$iImgTransHighQ=false, + $iImgTransBorder=false,$iImgTransHorizonPos=0.5; + public $legend; + protected $iYAxisDeltaPos=50; + protected $iIconDepth=DEPTH_BACK; + protected $iAxisLblBgType = 0, + $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black', + $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black'; + protected $iTables=NULL; + +//--------------- +// CONSTRUCTOR + + // aWIdth Width in pixels of image + // aHeight Height in pixels of image + // aCachedName Name for image file in cache directory + // aTimeOut Timeout in minutes for image in cache + // aInline If true the image is streamed back in the call to Stroke() + // If false the image is just created in the cache + function Graph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { + GLOBAL $gJpgBrandTiming; + // If timing is used create a new timing object + if( $gJpgBrandTiming ) { + global $tim; + $tim = new JpgTimer(); + $tim->Push(); + } + + if( !is_numeric($aWidth) || !is_numeric($aHeight) ) { + JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric'); + } + + // Automatically generate the image file name based on the name of the script that + // generates the graph + if( $aCachedName=="auto" ) + $aCachedName=GenImgName(); + + // Should the image be streamed back to the browser or only to the cache? + $this->inline=$aInline; + + $this->img = new RotImage($aWidth,$aHeight); + + $this->cache = new ImgStreamCache($this->img); + $this->cache->SetTimeOut($aTimeOut); + + $this->title = new Text(); + $this->title->ParagraphAlign('center'); + $this->title->SetFont(FF_FONT2,FS_BOLD); + $this->title->SetMargin(3); + $this->title->SetAlign('center'); + + $this->subtitle = new Text(); + $this->subtitle->ParagraphAlign('center'); + $this->subtitle->SetMargin(2); + $this->subtitle->SetAlign('center'); + + $this->subsubtitle = new Text(); + $this->subsubtitle->ParagraphAlign('center'); + $this->subsubtitle->SetMargin(2); + $this->subsubtitle->SetAlign('center'); + + $this->legend = new Legend(); + $this->footer = new Footer(); + + // Window doesn't like '?' in the file name so replace it with an '_' + $aCachedName = str_replace("?","_",$aCachedName); + + // If the cached version exist just read it directly from the + // cache, stream it back to browser and exit + if( $aCachedName!="" && READ_CACHE && $aInline ) + if( $this->cache->GetAndStream($aCachedName) ) { + exit(); + } + + $this->cache_name = $aCachedName; + $this->SetTickDensity(); // Normal density + + $this->tabtitle = new GraphTabTitle(); + } +//--------------- +// PUBLIC METHODS + + // Enable final image perspective transformation + function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) { + $this->iImgTrans = true; + $this->iImgTransHorizon = $aHorizon; + $this->iImgTransSkewDist= $aSkewDist; + $this->iImgTransDirection = $aDir; + $this->iImgTransMinSize = $aMinSize; + $this->iImgTransFillColor=$aFillColor; + $this->iImgTransHighQ=$aQuality; + $this->iImgTransBorder=$aBorder; + $this->iImgTransHorizonPos=$aHorizonPos; + } + + // Set Image format and optional quality + function SetImgFormat($aFormat,$aQuality=75) { + $this->img->SetImgFormat($aFormat,$aQuality); + } + + // Should the grid be in front or back of the plot? + function SetGridDepth($aDepth) { + $this->grid_depth=$aDepth; + } + + function SetIconDepth($aDepth) { + $this->iIconDepth=$aDepth; + } + + // Specify graph angle 0-360 degrees. + function SetAngle($aAngle) { + $this->img->SetAngle($aAngle); + } + + function SetAlphaBlending($aFlg=true) { + $this->img->SetAlphaBlending($aFlg); + } + + // Shortcut to image margin + function SetMargin($lm,$rm,$tm,$bm) { + $this->img->SetMargin($lm,$rm,$tm,$bm); + } + + function SetY2OrderBack($aBack=true) { + $this->y2orderback = $aBack; + } + + // Rotate the graph 90 degrees and set the margin + // when we have done a 90 degree rotation + function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { + $lm = $lm ==0 ? floor(0.2 * $this->img->width) : $lm ; + $rm = $rm ==0 ? floor(0.1 * $this->img->width) : $rm ; + $tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ; + $bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ; + + $adj = ($this->img->height - $this->img->width)/2; + $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj); + $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2)); + $this->SetAngle(90); + if( empty($this->yaxis) || empty($this->xaxis) ) { + JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()'); + } + $this->xaxis->SetLabelAlign('right','center'); + $this->yaxis->SetLabelAlign('center','bottom'); + } + + function SetClipping($aFlg=true) { + $this->iDoClipping = $aFlg ; + } + + // Add a plot object to the graph + function Add($aPlot) { + if( $aPlot == null ) + JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); + if( is_array($aPlot) && count($aPlot) > 0 ) + $cl = $aPlot[0]; + else + $cl = $aPlot; + + if( $cl instanceof Text ) + $this->AddText($aPlot); + elseif( $cl instanceof PlotLine ) + $this->AddLine($aPlot); + elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) + $this->AddBand($aPlot); + elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) + $this->AddIcon($aPlot); + elseif( class_exists('GTextTable',false) && ($cl instanceof GTextTable) ) + $this->AddTable($aPlot); + else + $this->plots[] = $aPlot; + } + + function AddTable($aTable) { + if( is_array($aTable) ) { + for($i=0; $i < count($aTable); ++$i ) + $this->iTables[]=$aTable[$i]; + } + else { + $this->iTables[] = $aTable ; + } + } + + function AddIcon($aIcon) { + if( is_array($aIcon) ) { + for($i=0; $i < count($aIcon); ++$i ) + $this->iIcons[]=$aIcon[$i]; + } + else { + $this->iIcons[] = $aIcon ; + } + } + + // Add plot to second Y-scale + function AddY2($aPlot) { + if( $aPlot == null ) + JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph."); + + if( is_array($aPlot) && count($aPlot) > 0 ) + $cl = $aPlot[0]; + else + $cl = $aPlot; + + if( $cl instanceof Text ) + $this->AddText($aPlot,true); + elseif( $cl instanceof PlotLine ) + $this->AddLine($aPlot,true); + elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) + $this->AddBand($aPlot,true); + else + $this->y2plots[] = $aPlot; + } + + // Add plot to the extra Y-axises + function AddY($aN,$aPlot) { + + if( $aPlot == null ) + JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph."); + + if( is_array($aPlot) && count($aPlot) > 0 ) + $cl = $aPlot[0]; + else + $cl = $aPlot; + + if( ($cl instanceof Text) || ($cl instanceof PlotLine) || + (class_exists('PlotBand',false) && ($cl instanceof PlotBand)) ) + JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis'); + else + $this->ynplots[$aN][] = $aPlot; + } + + // Add text object to the graph + function AddText($aTxt,$aToY2=false) { + if( $aTxt == null ) + JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph."); + if( $aToY2 ) { + if( is_array($aTxt) ) { + for($i=0; $i < count($aTxt); ++$i ) + $this->y2texts[]=$aTxt[$i]; + } + else + $this->y2texts[] = $aTxt; + } + else { + if( is_array($aTxt) ) { + for($i=0; $i < count($aTxt); ++$i ) + $this->texts[]=$aTxt[$i]; + } + else + $this->texts[] = $aTxt; + } + } + + // Add a line object (class PlotLine) to the graph + function AddLine($aLine,$aToY2=false) { + if( $aLine == null ) + JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph."); + + if( $aToY2 ) { + if( is_array($aLine) ) { + for($i=0; $i < count($aLine); ++$i ) + $this->y2lines[]=$aLine[$i]; + } + else + $this->y2lines[] = $aLine; + } + else { + if( is_array($aLine) ) { + for($i=0; $ilines[]=$aLine[$i]; + } + else + $this->lines[] = $aLine; + } + } + + // Add vertical or horizontal band + function AddBand($aBand,$aToY2=false) { + if( $aBand == null ) + JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph."); + + if( $aToY2 ) { + if( is_array($aBand) ) { + for($i=0; $i < count($aBand); ++$i ) + $this->y2bands[] = $aBand[$i]; + } + else + $this->y2bands[] = $aBand; + } + else { + if( is_array($aBand) ) { + for($i=0; $i < count($aBand); ++$i ) + $this->bands[] = $aBand[$i]; + } + else + $this->bands[] = $aBand; + } + } + + function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) { + $this->bkg_gradtype=$aGradType; + $this->bkg_gradstyle=$aStyle; + $this->bkg_gradfrom = $aFrom; + $this->bkg_gradto = $aTo; + } + + // Set a country flag in the background + function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { + $this->background_cflag = $aName; + $this->background_cflag_type = $aBgType; + $this->background_cflag_mix = $aMix; + } + + // Alias for the above method + function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { + $this->background_cflag = $aName; + $this->background_cflag_type = $aBgType; + $this->background_cflag_mix = $aMix; + } + + + // Specify a background image + function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat="auto") { + + if( !USE_TRUECOLOR ) { + JpGraphError::RaiseL(25017);//("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x you must enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts."); + } + + // Get extension to determine image type + if( $aImgFormat == "auto" ) { + $e = explode('.',$aFileName); + if( !$e ) { + JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); + } + + $valid_formats = array('png', 'jpg', 'gif'); + $aImgFormat = strtolower($e[count($e)-1]); + if ($aImgFormat == 'jpeg') { + $aImgFormat = 'jpg'; + } + elseif (!in_array($aImgFormat, $valid_formats) ) { + JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName); + } + } + + $this->background_image = $aFileName; + $this->background_image_type=$aBgType; + $this->background_image_format=$aImgFormat; + } + + function SetBackgroundImageMix($aMix) { + $this->background_image_mix = $aMix ; + } + + // Specify axis style (boxed or single) + function SetAxisStyle($aStyle) { + $this->iAxisStyle = $aStyle ; + } + + // Set a frame around the plot area + function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) { + $this->boxed = $aDrawPlotFrame; + $this->box_weight = $aPlotFrameWeight; + $this->box_color = $aPlotFrameColor; + } + + // Specify color for the plotarea (not the margins) + function SetColor($aColor) { + $this->plotarea_color=$aColor; + } + + // Specify color for the margins (all areas outside the plotarea) + function SetMarginColor($aColor) { + $this->margin_color=$aColor; + } + + // Set a frame around the entire image + function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) { + $this->doframe = $aDrawImgFrame; + $this->frame_color = $aImgFrameColor; + $this->frame_weight = $aImgFrameWeight; + } + + function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) { + $this->framebevel = $aFlg ; + $this->framebeveldepth = $aDepth ; + $this->framebevelborder = $aBorder ; + $this->framebevelbordercolor = $aBorderColor ; + $this->framebevelcolor1 = $aColor1 ; + $this->framebevelcolor2 = $aColor2 ; + + $this->doshadow = false ; + } + + // Set the shadow around the whole image + function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor=array(102,102,102)) { + $this->doshadow = $aShowShadow; + $this->shadow_color = $aShadowColor; + $this->shadow_width = $aShadowWidth; + $this->footer->iBottomMargin += $aShadowWidth; + $this->footer->iRightMargin += $aShadowWidth; + } + + // Specify x,y scale. Note that if you manually specify the scale + // you must also specify the tick distance with a call to Ticks::Set() + function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { + $this->axtype = $aAxisType; + + if( $aYMax < $aYMin || $aXMax < $aXMin ) + JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.'); + + $yt=substr($aAxisType,-3,3); + if( $yt=="lin" ) + $this->yscale = new LinearScale($aYMin,$aYMax); + elseif( $yt == "int" ) { + $this->yscale = new LinearScale($aYMin,$aYMax); + $this->yscale->SetIntScale(); + } + elseif( $yt=="log" ) + $this->yscale = new LogScale($aYMin,$aYMax); + else + JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)"); + + $xt=substr($aAxisType,0,3); + if( $xt == "lin" || $xt == "tex" ) { + $this->xscale = new LinearScale($aXMin,$aXMax,"x"); + $this->xscale->textscale = ($xt == "tex"); + } + elseif( $xt == "int" ) { + $this->xscale = new LinearScale($aXMin,$aXMax,"x"); + $this->xscale->SetIntScale(); + } + elseif( $xt == "dat" ) { + $this->xscale = new DateScale($aXMin,$aXMax,"x"); + } + elseif( $xt == "log" ) + $this->xscale = new LogScale($aXMin,$aXMax,"x"); + else + JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)"); + + $this->xaxis = new Axis($this->img,$this->xscale); + $this->yaxis = new Axis($this->img,$this->yscale); + $this->xgrid = new Grid($this->xaxis); + $this->ygrid = new Grid($this->yaxis); + $this->ygrid->Show(); + } + + // Specify secondary Y scale + function SetY2Scale($aAxisType="lin",$aY2Min=1,$aY2Max=1) { + if( $aAxisType=="lin" ) + $this->y2scale = new LinearScale($aY2Min,$aY2Max); + elseif( $aAxisType == "int" ) { + $this->y2scale = new LinearScale($aY2Min,$aY2Max); + $this->y2scale->SetIntScale(); + } + elseif( $aAxisType=="log" ) { + $this->y2scale = new LogScale($aY2Min,$aY2Max); + } + else JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)"); + + $this->y2axis = new Axis($this->img,$this->y2scale); + $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); + $this->y2axis->SetLabelSide(SIDE_RIGHT); + $this->y2axis->SetPos('max'); + $this->y2axis->SetTitleSide(SIDE_RIGHT); + + // Deafult position is the max x-value + $this->y2grid = new Grid($this->y2axis); + } + + // Set the delta position (in pixels) between the multiple Y-axis + function SetYDeltaDist($aDist) { + $this->iYAxisDeltaPos = $aDist; + } + + // Specify secondary Y scale + function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) { + + if( $aAxisType=="lin" ) + $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); + elseif( $aAxisType == "int" ) { + $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); + $this->ynscale[$aN]->SetIntScale(); + } + elseif( $aAxisType=="log" ) { + $this->ynscale[$aN] = new LogScale($aYMin,$aYMax); + } + else JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)"); + + $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]); + $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); + $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); + } + + // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse' + // The dividing factor have been determined heuristically according to my aesthetic + // sense (or lack off) y.m.m.v ! + function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) { + $this->xtick_factor=30; + $this->ytick_factor=25; + switch( $aYDensity ) { + case TICKD_DENSE: + $this->ytick_factor=12; + break; + case TICKD_NORMAL: + $this->ytick_factor=25; + break; + case TICKD_SPARSE: + $this->ytick_factor=40; + break; + case TICKD_VERYSPARSE: + $this->ytick_factor=100; + break; + default: + JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy"); + } + switch( $aXDensity ) { + case TICKD_DENSE: + $this->xtick_factor=15; + break; + case TICKD_NORMAL: + $this->xtick_factor=30; + break; + case TICKD_SPARSE: + $this->xtick_factor=45; + break; + case TICKD_VERYSPARSE: + $this->xtick_factor=60; + break; + default: + JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx"); + } + } + + + // Get a string of all image map areas + function GetCSIMareas() { + if( !$this->iHasStroked ) + $this->Stroke(_CSIM_SPECIALFILE); + + $csim = $this->title->GetCSIMAreas(); + $csim .= $this->subtitle->GetCSIMAreas(); + $csim .= $this->subsubtitle->GetCSIMAreas(); + $csim .= $this->legend->GetCSIMAreas(); + + if( $this->y2axis != NULL ) { + $csim .= $this->y2axis->title->GetCSIMAreas(); + } + + if( $this->texts != null ) { + $n = count($this->texts); + for($i=0; $i < $n; ++$i ) { + $csim .= $this->texts[$i]->GetCSIMAreas(); + } + } + + if( $this->y2texts != null && $this->y2scale != null ) { + $n = count($this->y2texts); + for($i=0; $i < $n; ++$i ) { + $csim .= $this->y2texts[$i]->GetCSIMAreas(); + } + } + + if( $this->yaxis != null && $this->xaxis != null ) { + $csim .= $this->yaxis->title->GetCSIMAreas(); + $csim .= $this->xaxis->title->GetCSIMAreas(); + } + + $n = count($this->plots); + for( $i=0; $i < $n; ++$i ) + $csim .= $this->plots[$i]->GetCSIMareas(); + + $n = count($this->y2plots); + for( $i=0; $i < $n; ++$i ) + $csim .= $this->y2plots[$i]->GetCSIMareas(); + + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + $m = count($this->ynplots[$i]); + for($j=0; $j < $m; ++$j ) { + $csim .= $this->ynplots[$i][$j]->GetCSIMareas(); + } + } + + $n = count($this->iTables); + for( $i=0; $i < $n; ++$i ) { + $csim .= $this->iTables[$i]->GetCSIMareas(); + } + + return $csim; + } + + // Get a complete .. tag for the final image map + function GetHTMLImageMap($aMapName) { + $im = "\n"; + $im .= $this->GetCSIMareas(); + $im .= ""; + return $im; + } + + function CheckCSIMCache($aCacheName,$aTimeOut=60) { + global $_SERVER; + + if( $aCacheName=='auto' ) + $aCacheName=basename($_SERVER['PHP_SELF']); + + $urlarg = $this->GetURLArguments(); + $this->csimcachename = CSIMCACHE_DIR.$aCacheName.$urlarg; + $this->csimcachetimeout = $aTimeOut; + + // First determine if we need to check for a cached version + // This differs from the standard cache in the sense that the + // image and CSIM map HTML file is written relative to the directory + // the script executes in and not the specified cache directory. + // The reason for this is that the cache directory is not necessarily + // accessible from the HTTP server. + if( $this->csimcachename != '' ) { + $dir = dirname($this->csimcachename); + $base = basename($this->csimcachename); + $base = strtok($base,'.'); + $suffix = strtok('.'); + $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; + $baseimg = $dir.'/'.$base.'?'.$urlarg.'.'.$this->img->img_format; + + $timedout=false; + // Does it exist at all ? + + if( file_exists($basecsim) && file_exists($baseimg) ) { + // Check that it hasn't timed out + $diff=time()-filemtime($basecsim); + if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) { + $timedout=true; + @unlink($basecsim); + @unlink($baseimg); + } + else { + if ($fh = @fopen($basecsim, "r")) { + fpassthru($fh); + return true; + } + else + JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading."); + } + } + } + return false; + } + + // Build the argument string to be used with the csim images + function GetURLArguments() { + + // This is a JPGRAPH internal defined that prevents + // us from recursively coming here again + $urlarg = _CSIM_DISPLAY.'=1'; + + // Now reconstruct any user URL argument + reset($_GET); + while( list($key,$value) = each($_GET) ) { + if( is_array($value) ) { + $n = count($value); + for( $i=0; $i < $n; ++$i ) { + $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]); + } + } + else { + $urlarg .= '&'.$key.'='.urlencode($value); + } + } + + // It's not ideal to convert POST argument to GET arguments + // but there is little else we can do. One idea for the + // future might be recreate the POST header in case. + reset($_POST); + while( list($key,$value) = each($_POST) ) { + if( is_array($value) ) { + $n = count($value); + for( $i=0; $i < $n; ++$i ) { + $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]); + } + } + else { + $urlarg .= '&'.$key.'='.urlencode($value); + } + } + + return $urlarg; + } + + function SetCSIMImgAlt($aAlt) { + $this->iCSIMImgAlt = $aAlt; + } + + function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) { + if( $aCSIMName=='' ) { + // create a random map name + srand ((double) microtime() * 1000000); + $r = rand(0,100000); + $aCSIMName='__mapname'.$r.'__'; + } + + if( $aScriptName=='auto' ) + $aScriptName=basename($_SERVER['PHP_SELF']); + + $urlarg = $this->GetURLArguments(); + + if( empty($_GET[_CSIM_DISPLAY]) ) { + // First determine if we need to check for a cached version + // This differs from the standard cache in the sense that the + // image and CSIM map HTML file is written relative to the directory + // the script executes in and not the specified cache directory. + // The reason for this is that the cache directory is not necessarily + // accessible from the HTTP server. + if( $this->csimcachename != '' ) { + $dir = dirname($this->csimcachename); + $base = basename($this->csimcachename); + $base = strtok($base,'.'); + $suffix = strtok('.'); + $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; + $baseimg = $base.'?'.$urlarg.'.'.$this->img->img_format; + + // Check that apache can write to directory specified + + if( file_exists($dir) && !is_writeable($dir) ) { + JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.'); + } + + // Make sure directory exists + $this->cache->MakeDirs($dir); + + // Write the image file + $this->Stroke(CSIMCACHE_DIR.$baseimg); + + // Construct wrapper HTML and write to file and send it back to browser + + // In the src URL we must replace the '?' with its encoding to prevent the arguments + // to be converted to real arguments. + $tmp = str_replace('?','%3f',$baseimg); + $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n". + '\"".$this-iCSIMImgAlt."\" />\n"; + + if($fh = @fopen($basecsim,'w') ) { + fwrite($fh,$htmlwrap); + fclose($fh); + echo $htmlwrap; + } + else + JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions."); + } + else { + + if( $aScriptName=='' ) { + JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().'); + } + echo $this->GetHTMLImageMap($aCSIMName); + echo "\"".$this-iCSIMImgAlt."\" />\n"; + } + } + else { + $this->Stroke(); + } + } + + function GetTextsYMinMax($aY2=false) { + if( $aY2 ) + $txts = $this->y2texts; + else + $txts = $this->texts; + $n = count($txts); + $min=null; + $max=null; + for( $i=0; $i < $n; ++$i ) { + if( $txts[$i]->iScalePosY !== null && + $txts[$i]->iScalePosX !== null ) { + if( $min === null ) { + $min = $max = $txts[$i]->iScalePosY ; + } + else { + $min = min($min,$txts[$i]->iScalePosY); + $max = max($max,$txts[$i]->iScalePosY); + } + } + } + if( $min !== null ) { + return array($min,$max); + } + else + return null; + } + + function GetTextsXMinMax($aY2=false) { + if( $aY2 ) + $txts = $this->y2texts; + else + $txts = $this->texts; + $n = count($txts); + $min=null; + $max=null; + for( $i=0; $i < $n; ++$i ) { + if( $txts[$i]->iScalePosY !== null && + $txts[$i]->iScalePosX !== null ) { + if( $min === null ) { + $min = $max = $txts[$i]->iScalePosX ; + } + else { + $min = min($min,$txts[$i]->iScalePosX); + $max = max($max,$txts[$i]->iScalePosX); + } + } + } + if( $min !== null ) { + return array($min,$max); + } + else + return null; + } + + function GetXMinMax() { + list($min,$ymin) = $this->plots[0]->Min(); + list($max,$ymax) = $this->plots[0]->Max(); + foreach( $this->plots as $p ) { + list($xmin,$ymin) = $p->Min(); + list($xmax,$ymax) = $p->Max(); + $min = Min($xmin,$min); + $max = Max($xmax,$max); + } + + if( $this->y2axis != null ) { + foreach( $this->y2plots as $p ) { + list($xmin,$ymin) = $p->Min(); + list($xmax,$ymax) = $p->Max(); + $min = Min($xmin,$min); + $max = Max($xmax,$max); + } + } + + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + if( $this->ynaxis[$i] != null) { + foreach( $this->ynplots[$i] as $p ) { + list($xmin,$ymin) = $p->Min(); + list($xmax,$ymax) = $p->Max(); + $min = Min($xmin,$min); + $max = Max($xmax,$max); + } + } + } + return array($min,$max); + } + + function AdjustMarginsForTitles() { + $totrequired = + ($this->title->t != '' ? + $this->title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) + + ($this->subtitle->t != '' ? + $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) + + ($this->subsubtitle->t != '' ? + $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ; + + + $btotrequired = 0; + if($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels ) { + // Minimum bottom margin + if( $this->xaxis->title->t != '' ) { + if( $this->img->a == 90 ) + $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 5 ; + else + $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 5 ; + } + else + $btotrequired = 0; + + if( $this->img->a == 90 ) { + $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style, + $this->yaxis->font_size); + $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle); + } + else { + $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style, + $this->xaxis->font_size); + $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle); + } + + $btotrequired += $lh + 5; + } + + if( $this->img->a == 90 ) { + // DO Nothing. It gets too messy to do this properly for 90 deg... + } + else{ + if( $this->img->top_margin < $totrequired ) { + $this->SetMargin($this->img->left_margin,$this->img->right_margin, + $totrequired,$this->img->bottom_margin); + } + if( $this->img->bottom_margin < $btotrequired ) { + $this->SetMargin($this->img->left_margin,$this->img->right_margin, + $this->img->top_margin,$btotrequired); + } + } + } + + // Stroke the graph + // $aStrokeFileName If != "" the image will be written to this file and NOT + // streamed back to the browser + function Stroke($aStrokeFileName="") { + + // Fist make a sanity check that user has specified a scale + if( empty($this->yscale) ) { + JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().'); + } + + // Start by adjusting the margin so that potential titles will fit. + $this->AdjustMarginsForTitles(); + + // Setup scale constants + if( $this->yscale ) $this->yscale->InitConstants($this->img); + if( $this->xscale ) $this->xscale->InitConstants($this->img); + if( $this->y2scale ) $this->y2scale->InitConstants($this->img); + + $n=count($this->ynscale); + for($i=0; $i < $n; ++$i) { + if( $this->ynscale[$i] ) $this->ynscale[$i]->InitConstants($this->img); + } + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + // Do any pre-stroke adjustment that is needed by the different plot types + // (i.e bar plots want's to add an offset to the x-labels etc) + for($i=0; $i < count($this->plots) ; ++$i ) { + $this->plots[$i]->PreStrokeAdjust($this); + $this->plots[$i]->DoLegend($this); + } + + // Any plots on the second Y scale? + if( $this->y2scale != null ) { + for($i=0; $iy2plots) ; ++$i ) { + $this->y2plots[$i]->PreStrokeAdjust($this); + $this->y2plots[$i]->DoLegend($this); + } + } + + // Any plots on the extra Y axises? + $n = count($this->ynaxis); + for($i=0; $i<$n ; ++$i ) { + if( $this->ynplots == null || $this->ynplots[$i] == null) { + JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i"); + } + $m = count($this->ynplots[$i]); + for($j=0; $j < $m; ++$j ) { + $this->ynplots[$i][$j]->PreStrokeAdjust($this); + $this->ynplots[$i][$j]->DoLegend($this); + } + } + + // Bail out if any of the Y-axis not been specified and + // has no plots. (This means it is impossible to do autoscaling and + // no other scale was given so we can't possible draw anything). If you use manual + // scaling you also have to supply the tick steps as well. + if( (!$this->yscale->IsSpecified() && count($this->plots)==0) || + ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) { + //$e = "n=".count($this->y2plots)."\n"; + // $e = "Can't draw unspecified Y-scale.
    \nYou have either:
    \n"; + // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots
    \n"; + // $e .= "2. Specified a scale manually but have forgot to specify the tick steps"; + JpGraphError::RaiseL(25026); + } + + // Bail out if no plots and no specified X-scale + if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) + JpGraphError::RaiseL(25034);//("JpGraph: Can't draw unspecified X-scale.
    No plots.
    "); + + //Check if we should autoscale y-axis + if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->plots); + $lres = $this->GetLinesYMinMax($this->lines); + if( is_array($lres) ) { + list($linmin,$linmax) = $lres ; + $min = min($min,$linmin); + $max = max($max,$linmax); + } + $tres = $this->GetTextsYMinMax(); + if( is_array($tres) ) { + list($tmin,$tmax) = $tres ; + $min = min($min,$tmin); + $max = max($max,$tmax); + } + $this->yscale->AutoScale($this->img,$min,$max, + $this->img->plotheight/$this->ytick_factor); + } + elseif( $this->yscale->IsSpecified() && + ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->yscale->scale[0]; + $max = $this->yscale->scale[1]; + $this->yscale->AutoScale($this->img,$min,$max, + $this->img->plotheight/$this->ytick_factor, + $this->yscale->auto_ticks); + } + + if( $this->y2scale != null) { + if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->y2plots); + + $lres = $this->GetLinesYMinMax($this->y2lines); + if( is_array($lres) ) { + list($linmin,$linmax) = $lres ; + $min = min($min,$linmin); + $max = max($max,$linmax); + } + $tres = $this->GetTextsYMinMax(true); + if( is_array($tres) ) { + list($tmin,$tmax) = $tres ; + $min = min($min,$tmin); + $max = max($max,$tmax); + } + $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); + } + elseif( $this->y2scale->IsSpecified() && + ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->y2scale->scale[0]; + $max = $this->y2scale->scale[1]; + $this->y2scale->AutoScale($this->img,$min,$max, + $this->img->plotheight/$this->ytick_factor, + $this->y2scale->auto_ticks); + } + } + + // + // Autoscale the extra Y-axises + // + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + if( $this->ynscale[$i] != null) { + if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]); + $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); + } + elseif( $this->ynscale[$i]->IsSpecified() && + ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->ynscale[$i]->scale[0]; + $max = $this->ynscale[$i]->scale[1]; + $this->ynscale[$i]->AutoScale($this->img,$min,$max, + $this->img->plotheight/$this->ytick_factor, + $this->ynscale[$i]->auto_ticks); + } + } + } + + //Check if we should autoscale x-axis + if( !$this->xscale->IsSpecified() ) { + if( substr($this->axtype,0,4) == "text" ) { + $max=0; + $n = count($this->plots); + for($i=0; $i < $n; ++$i ) { + $p = $this->plots[$i]; + // We need some unfortunate sub class knowledge here in order + // to increase number of data points in case it is a line plot + // which has the barcenter set. If not it could mean that the + // last point of the data is outside the scale since the barcenter + // settings means that we will shift the entire plot half a tick step + // to the right in oder to align with the center of the bars. + if( class_exists('BarPlot',false) ) { + $cl = strtolower(get_class($p)); + if( (class_exists('BarPlot',false) && ($p instanceof BarPlot)) || + empty($p->barcenter) ) + $max=max($max,$p->numpoints-1); + else { + $max=max($max,$p->numpoints); + } + } + else { + if( empty($p->barcenter) ) { + $max=max($max,$p->numpoints-1); + } + else { + $max=max($max,$p->numpoints); + } + } + } + $min=0; + if( $this->y2axis != null ) { + foreach( $this->y2plots as $p ) { + $max=max($max,$p->numpoints-1); + } + } + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + if( $this->ynaxis[$i] != null) { + foreach( $this->ynplots[$i] as $p ) { + $max=max($max,$p->numpoints-1); + } + } + } + + $this->xscale->Update($this->img,$min,$max); + $this->xscale->ticks->Set($this->xaxis->tick_step,1); + $this->xscale->ticks->SupressMinorTickMarks(); + } + else { + list($min,$max) = $this->GetXMinMax(); + + $lres = $this->GetLinesXMinMax($this->lines); + if( $lres ) { + list($linmin,$linmax) = $lres ; + $min = min($min,$linmin); + $max = max($max,$linmax); + } + + $lres = $this->GetLinesXMinMax($this->y2lines); + if( $lres ) { + list($linmin,$linmax) = $lres ; + $min = min($min,$linmin); + $max = max($max,$linmax); + } + + $tres = $this->GetTextsXMinMax(); + if( $tres ) { + list($tmin,$tmax) = $tres ; + $min = min($min,$tmin); + $max = max($max,$tmax); + } + + $tres = $this->GetTextsXMinMax(true); + if( $tres ) { + list($tmin,$tmax) = $tres ; + $min = min($min,$tmin); + $max = max($max,$tmax); + } + + $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor)); + } + + //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale + if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) ) + $this->yaxis->SetPos($this->xscale->GetMinVal()); + if( $this->y2axis != null ) { + if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) + $this->y2axis->SetPos($this->xscale->GetMaxVal()); + $this->y2axis->SetTitleSide(SIDE_RIGHT); + } + $n = count($this->ynaxis); + $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0; + for( $i=0; $i < $n; ++$i ) { + if( $this->ynaxis[$i] != null ) { + if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) { + $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal()); + $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj); + } + $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT); + } + } + + } + elseif( $this->xscale->IsSpecified() && + ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->xscale->scale[0]; + $max = $this->xscale->scale[1]; + $this->xscale->AutoScale($this->img,$min,$max, + round($this->img->plotwidth/$this->xtick_factor), + false); + + if( $this->y2axis != null ) { + if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) + $this->y2axis->SetPos($this->xscale->GetMaxVal()); + $this->y2axis->SetTitleSide(SIDE_RIGHT); + } + + } + + // If we have a negative values and x-axis position is at 0 + // we need to supress the first and possible the last tick since + // they will be drawn on top of the y-axis (and possible y2 axis) + // The test below might seem strange the reasone being that if + // the user hasn't specified a value for position this will not + // be set until we do the stroke for the axis so as of now it + // is undefined. + // For X-text scale we ignore all this since the tick are usually + // much further in and not close to the Y-axis. Hence the test + // for 'text' + + if( ($this->yaxis->pos==$this->xscale->GetMinVal() || + (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) && + !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 && + substr($this->axtype,0,4) != 'text' && $this->xaxis->pos!="min" ) { + + //$this->yscale->ticks->SupressZeroLabel(false); + $this->xscale->ticks->SupressFirst(); + if( $this->y2axis != null ) { + $this->xscale->ticks->SupressLast(); + } + } + elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) { + $this->xscale->ticks->SupressLast(); + } + + + if( !$_csim ) { + $this->StrokePlotArea(); + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + } + $this->StrokeAxis(false); + + // Stroke bands + if( $this->bands != null && !$_csim) + for($i=0; $i < count($this->bands); ++$i) { + // Stroke all bands that asks to be in the background + if( $this->bands[$i]->depth == DEPTH_BACK ) + $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); + } + + if( $this->y2bands != null && $this->y2scale != null && !$_csim ) + for($i=0; $i < count($this->y2bands); ++$i) { + // Stroke all bands that asks to be in the foreground + if( $this->y2bands[$i]->depth == DEPTH_BACK ) + $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); + } + + + if( $this->grid_depth == DEPTH_BACK && !$_csim) { + $this->ygrid->Stroke(); + $this->xgrid->Stroke(); + } + + // Stroke Y2-axis + if( $this->y2axis != null && !$_csim) { + $this->y2axis->Stroke($this->xscale); + $this->y2grid->Stroke(); + } + + // Stroke yn-axis + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + $this->ynaxis[$i]->Stroke($this->xscale); + } + + $oldoff=$this->xscale->off; + if(substr($this->axtype,0,4)=="text") { + if( $this->text_scale_abscenteroff > -1 ) { + // For a text scale the scale factor is the number of pixel per step. + // Hence we can use the scale factor as a substitute for number of pixels + // per major scale step and use that in order to adjust the offset so that + // an object of width "abscenteroff" becomes centered. + $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2); + } + else { + $this->xscale->off += + ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step); + } + } + + if( $this->iDoClipping ) { + $oldimage = $this->img->CloneCanvasH(); + } + + if( ! $this->y2orderback ) { + // Stroke all plots for Y1 axis + for($i=0; $i < count($this->plots); ++$i) { + $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); + $this->plots[$i]->StrokeMargin($this->img); + } + } + + // Stroke all plots for Y2 axis + if( $this->y2scale != null ) + for($i=0; $i< count($this->y2plots); ++$i ) { + $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale); + } + + if( $this->y2orderback ) { + // Stroke all plots for Y1 axis + for($i=0; $i < count($this->plots); ++$i) { + $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); + $this->plots[$i]->StrokeMargin($this->img); + } + } + + $n = count($this->ynaxis); + for( $i=0; $i < $n; ++$i ) { + $m = count($this->ynplots[$i]); + for( $j=0; $j < $m; ++$j ) { + $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]); + $this->ynplots[$i][$j]->StrokeMargin($this->img); + } + } + + if( $this->iIconDepth == DEPTH_FRONT) { + $this->StrokeIcons(); + } + + if( $this->iDoClipping ) { + // Clipping only supports graphs at 0 and 90 degrees + if( $this->img->a == 0 ) { + $this->img->CopyCanvasH($oldimage,$this->img->img, + $this->img->left_margin,$this->img->top_margin, + $this->img->left_margin,$this->img->top_margin, + $this->img->plotwidth+1,$this->img->plotheight); + } + elseif( $this->img->a == 90 ) { + $adj = ($this->img->height - $this->img->width)/2; + $this->img->CopyCanvasH($oldimage,$this->img->img, + $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, + $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, + $this->img->plotheight+1,$this->img->plotwidth); + } + else { + JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.'); + } + $this->img->Destroy(); + $this->img->SetCanvasH($oldimage); + } + + $this->xscale->off=$oldoff; + + if( $this->grid_depth == DEPTH_FRONT && !$_csim ) { + $this->ygrid->Stroke(); + $this->xgrid->Stroke(); + } + + // Stroke bands + if( $this->bands!= null ) + for($i=0; $i < count($this->bands); ++$i) { + // Stroke all bands that asks to be in the foreground + if( $this->bands[$i]->depth == DEPTH_FRONT ) + $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); + } + + if( $this->y2bands!= null && $this->y2scale != null ) + for($i=0; $i < count($this->y2bands); ++$i) { + // Stroke all bands that asks to be in the foreground + if( $this->y2bands[$i]->depth == DEPTH_FRONT ) + $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); + } + + + // Stroke any lines added + if( $this->lines != null ) { + for($i=0; $i < count($this->lines); ++$i) { + $this->lines[$i]->Stroke($this->img,$this->xscale,$this->yscale); + $this->lines[$i]->DoLegend($this); + } + } + + if( $this->y2lines != null && $this->y2scale != null ) { + for($i=0; $i < count($this->y2lines); ++$i) { + $this->y2lines[$i]->Stroke($this->img,$this->xscale,$this->y2scale); + $this->y2lines[$i]->DoLegend($this); + } + } + + // Finally draw the axis again since some plots may have nagged + // the axis in the edges. + if( !$_csim ) { + $this->StrokeAxis(); + } + + if( $this->y2scale != null && !$_csim ) + $this->y2axis->Stroke($this->xscale,false); + + if( !$_csim ) { + $this->StrokePlotBox(); + } + + // The titles and legends never gets rotated so make sure + // that the angle is 0 before stroking them + $aa = $this->img->SetAngle(0); + $this->StrokeTitles(); + $this->footer->Stroke($this->img); + $this->legend->Stroke($this->img); + $this->img->SetAngle($aa); + $this->StrokeTexts(); + $this->StrokeTables(); + + if( !$_csim ) { + + $this->img->SetAngle($aa); + + // Draw an outline around the image map + if(_JPG_DEBUG) { + $this->DisplayClientSideaImageMapAreas(); + } + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + } + } + } + + function SetAxisLabelBackground($aType,$aXFColor='lightgray',$aXColor='black',$aYFColor='lightgray',$aYColor='black') { + $this->iAxisLblBgType = $aType; + $this->iXAxisLblBgFillColor = $aXFColor; + $this->iXAxisLblBgColor = $aXColor; + $this->iYAxisLblBgFillColor = $aYFColor; + $this->iYAxisLblBgColor = $aYColor; + } + +//--------------- +// PRIVATE METHODS + + function StrokeAxisLabelBackground() { + // Types + // 0 = No background + // 1 = Only X-labels, length of axis + // 2 = Only Y-labels, length of axis + // 3 = As 1 but extends to width of graph + // 4 = As 2 but extends to height of graph + // 5 = Combination of 3 & 4 + // 6 = Combination of 1 & 2 + + $t = $this->iAxisLblBgType ; + if( $t < 1 ) return; + // Stroke optional X-axis label background color + if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) { + $this->img->PushColor($this->iXAxisLblBgFillColor); + if( $t == 1 || $t == 6 ) { + $xl = $this->img->left_margin; + $yu = $this->img->height - $this->img->bottom_margin + 1; + $xr = $this->img->width - $this->img->right_margin ; + $yl = $this->img->height-1-$this->frame_weight; + } + else { // t==3 || t==5 + $xl = $this->frame_weight; + $yu = $this->img->height - $this->img->bottom_margin + 1; + $xr = $this->img->width - 1 - $this->frame_weight; + $yl = $this->img->height-1-$this->frame_weight; + } + + $this->img->FilledRectangle($xl,$yu,$xr,$yl); + $this->img->PopColor(); + + // Check if we should add the vertical lines at left and right edge + if( $this->iXAxisLblBgColor !== '' ) { + $this->img->PushColor($this->iXAxisLblBgColor); + if( $t == 1 || $t == 6 ) { + $this->img->Line($xl,$yu,$xl,$yl); + $this->img->Line($xr,$yu,$xr,$yl); + } + else { + $xl = $this->img->width - $this->img->right_margin ; + $this->img->Line($xl,$yu-1,$xr,$yu-1); + } + $this->img->PopColor(); + } + } + + if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) { + $this->img->PushColor($this->iYAxisLblBgFillColor); + if( $t == 2 || $t == 6 ) { + $xl = $this->frame_weight; + $yu = $this->frame_weight+$this->img->top_margin; + $xr = $this->img->left_margin - 1; + $yl = $this->img->height - $this->img->bottom_margin + 1; + } + else { + $xl = $this->frame_weight; + $yu = $this->frame_weight; + $xr = $this->img->left_margin - 1; + $yl = $this->img->height-1-$this->frame_weight; + } + + $this->img->FilledRectangle($xl,$yu,$xr,$yl); + $this->img->PopColor(); + + // Check if we should add the vertical lines at left and right edge + if( $this->iXAxisLblBgColor !== '' ) { + $this->img->PushColor($this->iXAxisLblBgColor); + if( $t == 2 || $t == 6 ) { + $this->img->Line($xl,$yu-1,$xr,$yu-1); + $this->img->Line($xl,$yl-1,$xr,$yl-1); + } + else { + $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin); + } + $this->img->PopColor(); + } + + } + } + + function StrokeAxis($aStrokeLabels=true) { + + if( $aStrokeLabels ) { + $this->StrokeAxisLabelBackground(); + } + + // Stroke axis + if( $this->iAxisStyle != AXSTYLE_SIMPLE ) { + switch( $this->iAxisStyle ) { + case AXSTYLE_BOXIN : + $toppos = SIDE_DOWN; + $bottompos = SIDE_UP; + $leftpos = SIDE_RIGHT; + $rightpos = SIDE_LEFT; + break; + case AXSTYLE_BOXOUT : + $toppos = SIDE_UP; + $bottompos = SIDE_DOWN; + $leftpos = SIDE_LEFT; + $rightpos = SIDE_RIGHT; + break; + case AXSTYLE_YBOXIN: + $toppos = FALSE; + $bottompos = SIDE_UP; + $leftpos = SIDE_RIGHT; + $rightpos = SIDE_LEFT; + break; + case AXSTYLE_YBOXOUT: + $toppos = FALSE; + $bottompos = SIDE_DOWN; + $leftpos = SIDE_LEFT; + $rightpos = SIDE_RIGHT; + break; + default: + JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle); + break; + } + + // By default we hide the first label so it doesn't cross the + // Y-axis in case the positon hasn't been set by the user. + // However, if we use a box we always want the first value + // displayed so we make sure it will be displayed. + $this->xscale->ticks->SupressFirst(false); + + // Now draw the bottom X-axis + $this->xaxis->SetPos('min'); + $this->xaxis->SetLabelSide(SIDE_DOWN); + $this->xaxis->scale->ticks->SetSide($bottompos); + $this->xaxis->Stroke($this->yscale,$aStrokeLabels); + + if( $toppos !== FALSE ) { + // We also want a top X-axis + $this->xaxis = $this->xaxis; + $this->xaxis->SetPos('max'); + $this->xaxis->SetLabelSide(SIDE_UP); + // No title for the top X-axis + if( $aStrokeLabels ) { + $this->xaxis->title->Set(''); + } + $this->xaxis->scale->ticks->SetSide($toppos); + $this->xaxis->Stroke($this->yscale,$aStrokeLabels); + } + + // Stroke the left Y-axis + $this->yaxis->SetPos('min'); + $this->yaxis->SetLabelSide(SIDE_LEFT); + $this->yaxis->scale->ticks->SetSide($leftpos); + $this->yaxis->Stroke($this->xscale,$aStrokeLabels); + + // Stroke the right Y-axis + $this->yaxis->SetPos('max'); + // No title for the right side + if( $aStrokeLabels ) { + $this->yaxis->title->Set(''); + } + $this->yaxis->SetLabelSide(SIDE_RIGHT); + $this->yaxis->scale->ticks->SetSide($rightpos); + $this->yaxis->Stroke($this->xscale,$aStrokeLabels); + } + else { + $this->xaxis->Stroke($this->yscale,$aStrokeLabels); + $this->yaxis->Stroke($this->xscale,$aStrokeLabels); + } + } + + + // Private helper function for backgound image + static function LoadBkgImage($aImgFormat='',$aFile='',$aImgStr='') { + if( $aImgStr != '' ) { + return Image::CreateFromString($aImgStr); + } + + // Remove case sensitivity and setup appropriate function to create image + // Get file extension. This should be the LAST '.' separated part of the filename + $e = explode('.',$aFile); + $ext = strtolower($e[count($e)-1]); + if ($ext == "jpeg") { + $ext = "jpg"; + } + + if( trim($ext) == '' ) + $ext = 'png'; // Assume PNG if no extension specified + + if( $aImgFormat == '' ) + $imgtag = $ext; + else + $imgtag = $aImgFormat; + + $supported = imagetypes(); + if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) || + ( $ext == 'gif' && !($supported & IMG_GIF) ) || + ( $ext == 'png' && !($supported & IMG_PNG) ) || + ( $ext == 'bmp' && !($supported & IMG_WBMP) ) || + ( $ext == 'xpm' && !($supported & IMG_XPM) ) ) { + + JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. '); + } + + + if( $imgtag == "jpg" || $imgtag == "jpeg") + { + $f = "imagecreatefromjpeg"; + $imgtag = "jpg"; + } + else + { + $f = "imagecreatefrom".$imgtag; + } + + // Compare specified image type and file extension + if( $imgtag != $ext ) { + //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'"; + JpGraphError::RaiseL(25038, $aImgFormat, $aFile); + } + + $img = @$f($aFile); + if( !$img ) { + JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'"); + } + return $img; + } + + function StrokeBackgroundGrad() { + if( $this->bkg_gradtype < 0 ) + return; + $grad = new Gradient($this->img); + if( $this->bkg_gradstyle == BGRAD_PLOT ) { + $xl = $this->img->left_margin; + $yt = $this->img->top_margin; + $xr = $xl + $this->img->plotwidth+1 ; + $yb = $yt + $this->img->plotheight ; + $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); + } + else { + $xl = 0; + $yt = 0; + $xr = $xl + $this->img->width - 1; + $yb = $yt + $this->img->height ; + if( $this->doshadow ) { + $xr -= $this->shadow_width; + $yb -= $this->shadow_width; + } + if( $this->doframe ) { + $yt += $this->frame_weight; + $yb -= $this->frame_weight; + $xl += $this->frame_weight; + $xr -= $this->frame_weight; + } + $aa = $this->img->SetAngle(0); + $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); + $aa = $this->img->SetAngle($aa); + } + } + + function StrokeFrameBackground() { + if( $this->background_image != "" && $this->background_cflag != "" ) { + JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.'); + } + if( $this->background_image != "" ) { + $bkgimg = $this->LoadBkgImage($this->background_image_format,$this->background_image); + } + elseif( $this->background_cflag != "" ) { + if( ! class_exists('FlagImages',false) ) { + JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.'); + } + $fobj = new FlagImages(FLAGSIZE4); + $dummy=''; + $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy); + $this->background_image_mix = $this->background_cflag_mix; + $this->background_image_type = $this->background_cflag_type; + } + else { + return ; + } + + $bw = ImageSX($bkgimg); + $bh = ImageSY($bkgimg); + + // No matter what the angle is we always stroke the image and frame + // assuming it is 0 degree + $aa = $this->img->SetAngle(0); + + switch( $this->background_image_type ) { + case BGIMG_FILLPLOT: // Resize to just fill the plotarea + $this->FillMarginArea(); + $this->StrokeFrame(); + // Special case to hande 90 degree rotated graph corectly + if( $aa == 90 ) { + $this->img->SetAngle(90); + $this->FillPlotArea(); + $aa = $this->img->SetAngle(0); + $adj = ($this->img->height - $this->img->width)/2; + $this->img->CopyMerge($bkgimg, + $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, + 0,0, + $this->img->plotheight+1,$this->img->plotwidth, + $bw,$bh,$this->background_image_mix); + + } + else { + $this->FillPlotArea(); + $this->img->CopyMerge($bkgimg, + $this->img->left_margin,$this->img->top_margin, + 0,0,$this->img->plotwidth+1,$this->img->plotheight, + $bw,$bh,$this->background_image_mix); + } + break; + case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit + $hadj=0; $vadj=0; + if( $this->doshadow ) { + $hadj = $this->shadow_width; + $vadj = $this->shadow_width; + } + $this->FillMarginArea(); + $this->FillPlotArea(); + $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj, + $bw,$bh,$this->background_image_mix); + $this->StrokeFrame(); + break; + case BGIMG_COPY: // Just copy the image from left corner, no resizing + $this->FillMarginArea(); + $this->FillPlotArea(); + $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh, + $bw,$bh,$this->background_image_mix); + $this->StrokeFrame(); + break; + case BGIMG_CENTER: // Center original image in the plot area + $this->FillMarginArea(); + $this->FillPlotArea(); + $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2); + $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2); + $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh, + $bw,$bh,$this->background_image_mix); + $this->StrokeFrame(); + break; + default: + JpGraphError::RaiseL(25042);//(" Unknown background image layout"); + } + $this->img->SetAngle($aa); + } + + // Private + // Draw a frame around the image + function StrokeFrame() { + if( !$this->doframe ) return; + + if( $this->background_image_type <= 1 && + ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) { + $c = $this->margin_color; + } + else { + $c = false; + } + + if( $this->doshadow ) { + $this->img->SetColor($this->frame_color); + $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height, + $c,$this->shadow_width,$this->shadow_color); + } + elseif( $this->framebevel ) { + if( $c ) { + $this->img->SetColor($this->margin_color); + $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); + } + $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, + $this->framebeveldepth, + $this->framebevelcolor1,$this->framebevelcolor2); + if( $this->framebevelborder ) { + $this->img->SetColor($this->framebevelbordercolor); + $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); + } + } + else { + $this->img->SetLineWeight($this->frame_weight); + if( $c ) { + $this->img->SetColor($this->margin_color); + $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); + } + $this->img->SetColor($this->frame_color); + $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); + } + } + + function FillMarginArea() { + $hadj=0; $vadj=0; + if( $this->doshadow ) { + $hadj = $this->shadow_width; + $vadj = $this->shadow_width; + } + + $this->img->SetColor($this->margin_color); +// $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); + + $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin); + $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj); + $this->img->FilledRectangle($this->img->left_margin+1, + $this->img->height-$this->img->bottom_margin, + $this->img->width-1-$hadj, + $this->img->height-1-$hadj); + $this->img->FilledRectangle($this->img->width-$this->img->right_margin, + $this->img->top_margin+1, + $this->img->width-1-$hadj, + $this->img->height-$this->img->bottom_margin-1); + } + + function FillPlotArea() { + $this->img->PushColor($this->plotarea_color); + $this->img->FilledRectangle($this->img->left_margin, + $this->img->top_margin, + $this->img->width-$this->img->right_margin, + $this->img->height-$this->img->bottom_margin); + $this->img->PopColor(); + } + + // Stroke the plot area with either a solid color or a background image + function StrokePlotArea() { + // Note: To be consistent we really should take a possible shadow + // into account. However, that causes some problem for the LinearScale class + // since in the current design it does not have any links to class Graph which + // means it has no way of compensating for the adjusted plotarea in case of a + // shadow. So, until I redesign LinearScale we can't compensate for this. + // So just set the two adjustment parameters to zero for now. + $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ; + $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ; + + if( $this->background_image != "" || $this->background_cflag != "" ) { + $this->StrokeFrameBackground(); + } + else { + $aa = $this->img->SetAngle(0); + $this->StrokeFrame(); + $aa = $this->img->SetAngle($aa); + $this->StrokeBackgroundGrad(); + if( $this->bkg_gradtype < 0 || + ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) { + $this->FillPlotArea(); + } + } + } + + function StrokeIcons() { + $n = count($this->iIcons); + for( $i=0; $i < $n; ++$i ) { + $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); + } + } + + function StrokePlotBox() { + // Should we draw a box around the plot area? + if( $this->boxed ) { + $this->img->SetLineWeight(1); + $this->img->SetLineStyle('solid'); + $this->img->SetColor($this->box_color); + for($i=0; $i < $this->box_weight; ++$i ) { + $this->img->Rectangle( + $this->img->left_margin-$i,$this->img->top_margin-$i, + $this->img->width-$this->img->right_margin+$i, + $this->img->height-$this->img->bottom_margin+$i); + } + } + } + + function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') { + $this->titlebkg_fillstyle = $aStyle; + $this->titlebkg_scolor1 = $aColor1; + $this->titlebkg_scolor2 = $aColor2; + } + + function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) { + $this->titlebackground = $aEnable; + $this->titlebackground_color = $aBackColor; + $this->titlebackground_style = $aStyle; + $this->titlebackground_framecolor = $aFrameColor; + $this->titlebackground_framestyle = $aFrameStyle; + $this->titlebackground_frameweight = $aFrameWeight; + $this->titlebackground_bevelheight = $aBevelHeight ; + } + + + function StrokeTitles() { + + $margin=3; + + if( $this->titlebackground ) { + + // Find out height + $this->title->margin += 2 ; + $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin; + if( $this->subtitle->t != "" && !$this->subtitle->hide ) { + $h += $this->subtitle->GetTextHeight($this->img)+$margin+ + $this->subtitle->margin; + $h += 2; + } + if( $this->subsubtitle->t != "" && !$this->subsubtitle->hide ) { + $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+ + $this->subsubtitle->margin; + $h += 2; + } + $this->img->PushColor($this->titlebackground_color); + if( $this->titlebackground_style === TITLEBKG_STYLE1 ) { + // Inside the frame + if( $this->framebevel ) { + $x1 = $y1 = $this->framebeveldepth + 1 ; + $x2 = $this->img->width - $this->framebeveldepth - 2 ; + $this->title->margin += $this->framebeveldepth + 1 ; + $h += $y1 ; + $h += 2; + } + else { + $x1 = $y1 = $this->frame_weight; + $x2 = $this->img->width - 2*$x1; + } + } + elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) { + // Cover the frame as well + $x1 = $y1 = 0; + $x2 = $this->img->width - 1 ; + } + elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) { + // Cover the frame as well (the difference is that + // for style==3 a bevel frame border is on top + // of the title background) + $x1 = $y1 = 0; + $x2 = $this->img->width - 1 ; + $h += $this->framebeveldepth ; + $this->title->margin += $this->framebeveldepth ; + } + else { + JpGraphError::RaiseL(25043);//('Unknown title background style.'); + } + + if( $this->titlebackground_framestyle === 3 ) { + $h += $this->titlebackground_bevelheight*2 + 1 ; + $this->title->margin += $this->titlebackground_bevelheight ; + } + + if( $this->doshadow ) { + $x2 -= $this->shadow_width ; + } + + $indent=0; + if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { + $ind = $this->titlebackground_bevelheight; + } + + if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) { + $this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind, + $this->titlebkg_scolor1, + $this->titlebkg_scolor2); + } + elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) { + $this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind, + $this->titlebkg_scolor1, + $this->titlebkg_scolor2,2); + } + else { + // Solid fill + $this->img->FilledRectangle($x1,$y1,$x2,$h); + } + $this->img->PopColor(); + + $this->img->PushColor($this->titlebackground_framecolor); + $this->img->SetLineWeight($this->titlebackground_frameweight); + if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) { + // Frame background + $this->img->Rectangle($x1,$y1,$x2,$h); + } + elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) { + // Bottom line only + $this->img->Line($x1,$h,$x2,$h); + } + elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { + $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight); + } + $this->img->PopColor(); + + // This is clumsy. But we neeed to stroke the whole graph frame if it is + // set to bevel to get the bevel shading on top of the text background + if( $this->framebevel && $this->doframe && + $this->titlebackground_style === 3 ) { + $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, + $this->framebeveldepth, + $this->framebevelcolor1,$this->framebevelcolor2); + if( $this->framebevelborder ) { + $this->img->SetColor($this->framebevelbordercolor); + $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); + } + } + } + + // Stroke title + $y = $this->title->margin; + if( $this->title->halign == 'center' ) + $this->title->Center(0,$this->img->width,$y); + elseif( $this->title->halign == 'left' ) { + $this->title->SetPos($this->title->margin+2,$y); + } + elseif( $this->title->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) + $indent = $this->shadow_width+2; + $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right'); + } + $this->title->Stroke($this->img); + + // ... and subtitle + $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin; + if( $this->subtitle->halign == 'center' ) + $this->subtitle->Center(0,$this->img->width,$y); + elseif( $this->subtitle->halign == 'left' ) { + $this->subtitle->SetPos($this->subtitle->margin+2,$y); + } + elseif( $this->subtitle->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) + $indent = $this->shadow_width+2; + $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); + } + $this->subtitle->Stroke($this->img); + + // ... and subsubtitle + $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin; + if( $this->subsubtitle->halign == 'center' ) + $this->subsubtitle->Center(0,$this->img->width,$y); + elseif( $this->subsubtitle->halign == 'left' ) { + $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); + } + elseif( $this->subsubtitle->halign == 'right' ) { + $indent = 0; + if( $this->doshadow ) + $indent = $this->shadow_width+2; + $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right'); + } + $this->subsubtitle->Stroke($this->img); + + // ... and fancy title + $this->tabtitle->Stroke($this->img); + + } + + function StrokeTexts() { + // Stroke any user added text objects + if( $this->texts != null ) { + for($i=0; $i < count($this->texts); ++$i) { + $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); + } + } + + if( $this->y2texts != null && $this->y2scale != null ) { + for($i=0; $i < count($this->y2texts); ++$i) { + $this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale); + } + } + + } + + function StrokeTables() { + if( $this->iTables != null ) { + $n = count($this->iTables); + for( $i=0; $i < $n; ++$i ) { + $this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); + } + } + } + + function DisplayClientSideaImageMapAreas() { + // Debug stuff - display the outline of the image map areas + $csim=''; + foreach ($this->plots as $p) { + $csim.= $p->GetCSIMareas(); + } + $csim .= $this->legend->GetCSIMareas(); + if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { + $this->img->SetColor($this->csimcolor); + $n = count($coords[0]); + for ($i=0; $i < $n; $i++) { + if ($coords[1][$i]=="poly") { + preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); + $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); + $m = count($pts[0]); + for ($j=0; $j < $m; $j++) { + $this->img->LineTo($pts[1][$j],$pts[2][$j]); + } + } else if ($coords[1][$i]=="rect") { + $pts = preg_split('/,/', $coords[2][$i]); + $this->img->SetStartPoint($pts[0],$pts[1]); + $this->img->LineTo($pts[2],$pts[1]); + $this->img->LineTo($pts[2],$pts[3]); + $this->img->LineTo($pts[0],$pts[3]); + $this->img->LineTo($pts[0],$pts[1]); + } + } + } + } + + // Text scale offset in world coordinates + function SetTextScaleOff($aOff) { + $this->text_scale_off = $aOff; + $this->xscale->text_scale_off = $aOff; + } + + // Text width of bar to be centered in absolute pixels + function SetTextScaleAbsCenterOff($aOff) { + $this->text_scale_abscenteroff = $aOff; + } + + // Get Y min and max values for added lines + function GetLinesYMinMax( $aLines ) { + $n = count($aLines); + if( $n == 0 ) return false; + $min = $aLines[0]->scaleposition ; + $max = $min ; + $flg = false; + for( $i=0; $i < $n; ++$i ) { + if( $aLines[$i]->direction == HORIZONTAL ) { + $flg = true ; + $v = $aLines[$i]->scaleposition ; + if( $min > $v ) $min = $v ; + if( $max < $v ) $max = $v ; + } + } + return $flg ? array($min,$max) : false ; + } + + // Get X min and max values for added lines + function GetLinesXMinMax( $aLines ) { + $n = count($aLines); + if( $n == 0 ) return false ; + $min = $aLines[0]->scaleposition ; + $max = $min ; + $flg = false; + for( $i=0; $i < $n; ++$i ) { + if( $aLines[$i]->direction == VERTICAL ) { + $flg = true ; + $v = $aLines[$i]->scaleposition ; + if( $min > $v ) $min = $v ; + if( $max < $v ) $max = $v ; + } + } + return $flg ? array($min,$max) : false ; + } + + // Get min and max values for all included plots + function GetPlotsYMinMax($aPlots) { + $n = count($aPlots); + $i=0; + do { + list($xmax,$max) = $aPlots[$i]->Max(); + } while( ++$i < $n && !is_numeric($max) ); + + $i=0; + do { + list($xmin,$min) = $aPlots[$i]->Min(); + } while( ++$i < $n && !is_numeric($min) ); + + if( !is_numeric($min) || !is_numeric($max) ) { + JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).'); + } + + for($i=0; $i < $n; ++$i ) { + list($xmax,$ymax)=$aPlots[$i]->Max(); + list($xmin,$ymin)=$aPlots[$i]->Min(); + if (is_numeric($ymax)) $max=max($max,$ymax); + if (is_numeric($ymin)) $min=min($min,$ymin); + } + if( $min == '' ) $min = 0; + if( $max == '' ) $max = 0; + if( $min == 0 && $max == 0 ) { + // Special case if all values are 0 + $min=0;$max=1; + } + return array($min,$max); + } + +} // Class + +//=================================================== +// CLASS LineProperty +// Description: Holds properties for a line +//=================================================== +class LineProperty { + public $iWeight=1, $iColor="black",$iStyle="solid",$iShow=true; + +//--------------- +// PUBLIC METHODS + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetWeight($aWeight) { + $this->iWeight = $aWeight; + } + + function SetStyle($aStyle) { + $this->iStyle = $aStyle; + } + + function Show($aShow=true) { + $this->iShow=$aShow; + } + + function Stroke($aImg,$aX1,$aY1,$aX2,$aY2) { + if( $this->iShow ) { + $aImg->PushColor($this->iColor); + $oldls = $aImg->line_style; + $oldlw = $aImg->line_weight; + $aImg->SetLineWeight($this->iWeight); + $aImg->SetLineStyle($this->iStyle); + $aImg->StyleLine($aX1,$aY1,$aX2,$aY2); + $aImg->PopColor($this->iColor); + $aImg->line_style = $oldls; + $aImg->line_weight = $oldlw; + + } + } +} + + +//=================================================== +// CLASS Text +// Description: Arbitrary text object that can be added to the graph +//=================================================== +class Text { + public $t,$margin=0; + public $x=0,$y=0,$halign="left",$valign="top",$color=array(0,0,0); + public $hide=false, $dir=0; + public $iScalePosY=null,$iScalePosX=null; + public $iWordwrap=0; + protected $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12; + protected $boxed=false; // Should the text be boxed + protected $paragraph_align="left"; + protected $icornerradius=0,$ishadowwidth=3; + protected $fcolor='white',$bcolor='black',$shadow=false; + protected $iCSIMarea='',$iCSIMalt='',$iCSIMtarget='',$iCSIMWinTarget=''; + +//--------------- +// CONSTRUCTOR + + // Create new text at absolute pixel coordinates + function Text($aTxt="",$aXAbsPos=0,$aYAbsPos=0) { + if( ! is_string($aTxt) ) { + JpGraphError::RaiseL(25050);//('First argument to Text::Text() must be s atring.'); + } + $this->t = $aTxt; + $this->x = round($aXAbsPos); + $this->y = round($aYAbsPos); + $this->margin = 0; + } +//--------------- +// PUBLIC METHODS + // Set the string in the text object + function Set($aTxt) { + $this->t = $aTxt; + } + + // Alias for Pos() + function SetPos($aXAbsPos=0,$aYAbsPos=0,$aHAlign="left",$aVAlign="top") { + //$this->Pos($aXAbsPos,$aYAbsPos,$aHAlign,$aVAlign); + $this->x = $aXAbsPos; + $this->y = $aYAbsPos; + $this->halign = $aHAlign; + $this->valign = $aVAlign; + } + + function SetScalePos($aX,$aY) { + $this->iScalePosX = $aX; + $this->iScalePosY = $aY; + } + + // Specify alignment for the text + function Align($aHAlign,$aVAlign="top",$aParagraphAlign="") { + $this->halign = $aHAlign; + $this->valign = $aVAlign; + if( $aParagraphAlign != "" ) + $this->paragraph_align = $aParagraphAlign; + } + + // Alias + function SetAlign($aHAlign,$aVAlign="top",$aParagraphAlign="") { + $this->Align($aHAlign,$aVAlign,$aParagraphAlign); + } + + // Specifies the alignment for a multi line text + function ParagraphAlign($aAlign) { + $this->paragraph_align = $aAlign; + } + + // Specifies the alignment for a multi line text + function SetParagraphAlign($aAlign) { + $this->paragraph_align = $aAlign; + } + + function SetShadow($aShadowColor='gray',$aShadowWidth=3) { + $this->ishadowwidth=$aShadowWidth; + $this->shadow=$aShadowColor; + $this->boxed=true; + } + + function SetWordWrap($aCol) { + $this->iWordwrap = $aCol ; + } + + // Specify that the text should be boxed. fcolor=frame color, bcolor=border color, + // $shadow=drop shadow should be added around the text. + function SetBox($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadowColor=false,$aCornerRadius=4,$aShadowWidth=3) { + if( $aFrameColor==false ) + $this->boxed=false; + else + $this->boxed=true; + $this->fcolor=$aFrameColor; + $this->bcolor=$aBorderColor; + // For backwards compatibility when shadow was just true or false + if( $aShadowColor === true ) + $aShadowColor = 'gray'; + $this->shadow=$aShadowColor; + $this->icornerradius=$aCornerRadius; + $this->ishadowwidth=$aShadowWidth; + } + + // Hide the text + function Hide($aHide=true) { + $this->hide=$aHide; + } + + // This looks ugly since it's not a very orthogonal design + // but I added this "inverse" of Hide() to harmonize + // with some classes which I designed more recently (especially) + // jpgraph_gantt + function Show($aShow=true) { + $this->hide=!$aShow; + } + + // Specify font + function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { + $this->font_family=$aFamily; + $this->font_style=$aStyle; + $this->font_size=$aSize; + } + + // Center the text between $left and $right coordinates + function Center($aLeft,$aRight,$aYAbsPos=false) { + $this->x = $aLeft + ($aRight-$aLeft )/2; + $this->halign = "center"; + if( is_numeric($aYAbsPos) ) + $this->y = $aYAbsPos; + } + + // Set text color + function SetColor($aColor) { + $this->color = $aColor; + } + + function SetAngle($aAngle) { + $this->SetOrientation($aAngle); + } + + // Orientation of text. Note only TTF fonts can have an arbitrary angle + function SetOrientation($aDirection=0) { + if( is_numeric($aDirection) ) + $this->dir=$aDirection; + elseif( $aDirection=="h" ) + $this->dir = 0; + elseif( $aDirection=="v" ) + $this->dir = 90; + else JpGraphError::RaiseL(25051);//(" Invalid direction specified for text."); + } + + // Total width of text + function GetWidth($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $w = $aImg->GetTextWidth($this->t,$this->dir); + return $w; + } + + // Hight of font + function GetFontHeight($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetFontHeight(); + return $h; + + } + + function GetTextHeight($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetTextHeight($this->t,$this->dir); + return $h; + } + + function GetHeight($aImg) { + // Synonym for GetTextHeight() + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetTextHeight($this->t,$this->dir); + return $h; + } + + // Set the margin which will be interpretated differently depending + // on the context. + function SetMargin($aMarg) { + $this->margin = $aMarg; + } + + function StrokeWithScale($aImg,$axscale,$ayscale) { + if( $this->iScalePosX === null || + $this->iScalePosY === null ) { + $this->Stroke($aImg); + } + else { + $this->Stroke($aImg, + round($axscale->Translate($this->iScalePosX)), + round($ayscale->Translate($this->iScalePosY))); + } + } + + function SetCSIMTarget($aURITarget,$aAlt='',$aWinTarget='') { + $this->iCSIMtarget = $aURITarget; + $this->iCSIMalt = $aAlt; + $this->iCSIMWinTarget = $aWinTarget; + } + + function GetCSIMareas() { + if( $this->iCSIMtarget !== '' ) + return $this->iCSIMarea; + else + return ''; + } + + // Display text in image + function Stroke($aImg,$x=null,$y=null) { + + if( !empty($x) ) $this->x = round($x); + if( !empty($y) ) $this->y = round($y); + + // Insert newlines + if( $this->iWordwrap > 0 ) { + $this->t = wordwrap($this->t,$this->iWordwrap,"\n"); + } + + // If position been given as a fraction of the image size + // calculate the absolute position + if( $this->x < 1 && $this->x > 0 ) $this->x *= $aImg->width; + if( $this->y < 1 && $this->y > 0 ) $this->y *= $aImg->height; + + $aImg->PushColor($this->color); + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetTextAlign($this->halign,$this->valign); + if( $this->boxed ) { + if( $this->fcolor=="nofill" ) + $this->fcolor=false; + $aImg->SetLineWeight(1); + $bbox = $aImg->StrokeBoxedText($this->x,$this->y,$this->t, + $this->dir,$this->fcolor,$this->bcolor,$this->shadow, + $this->paragraph_align,5,5,$this->icornerradius, + $this->ishadowwidth); + } + else { + $bbox = $aImg->StrokeText($this->x,$this->y,$this->t,$this->dir,$this->paragraph_align); + } + + // Create CSIM targets + $coords = $bbox[0].','.$bbox[1].','.$bbox[2].','.$bbox[3].','.$bbox[4].','.$bbox[5].','.$bbox[6].','.$bbox[7]; + $this->iCSIMarea = "iCSIMtarget)."\" "; + if( trim($this->iCSIMalt) != '' ) { + $this->iCSIMarea .= " alt=\"".$this->iCSIMalt."\" "; + $this->iCSIMarea .= " title=\"".$this->iCSIMalt."\" "; + } + if( trim($this->iCSIMWinTarget) != '' ) { + $this->iCSIMarea .= " target=\"".$this->iCSIMWinTarget."\" "; + } + $this->iCSIMarea .= " />\n"; + + $aImg->PopColor($this->color); + + } +} // Class + +class GraphTabTitle extends Text{ + private $corner = 6 , $posx = 7, $posy = 4; + private $fillcolor='lightyellow',$bordercolor='black'; + private $align = 'left', $width=TABTITLE_WIDTHFIT; + function GraphTabTitle() { + $this->t = ''; + $this->font_style = FS_BOLD; + $this->hide = true; + $this->color = 'darkred'; + } + + function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') { + $this->color = $aTxtColor; + $this->fillcolor = $aFillColor; + $this->bordercolor = $aBorderColor; + } + + function SetFillColor($aFillColor) { + $this->fillcolor = $aFillColor; + } + + function SetTabAlign($aAlign) { + $this->align = $aAlign; + } + + function SetWidth($aWidth) { + $this->width = $aWidth ; + } + + function Set($t) { + $this->t = $t; + $this->hide = false; + } + + function SetCorner($aD) { + $this->corner = $aD ; + } + + function Stroke($aImg,$aDummy1=null,$aDummy2=null) { + if( $this->hide ) + return; + $this->boxed = false; + $w = $this->GetWidth($aImg) + 2*$this->posx; + $h = $this->GetTextHeight($aImg) + 2*$this->posy; + + $x = $aImg->left_margin; + $y = $aImg->top_margin; + + if( $this->width === TABTITLE_WIDTHFIT ) { + if( $this->align == 'left' ) { + $p = array($x, $y, + $x, $y-$h+$this->corner, + $x + $this->corner,$y-$h, + $x + $w - $this->corner, $y-$h, + $x + $w, $y-$h+$this->corner, + $x + $w, $y); + } + elseif( $this->align == 'center' ) { + $x += round($aImg->plotwidth/2) - round($w/2); + $p = array($x, $y, + $x, $y-$h+$this->corner, + $x + $this->corner, $y-$h, + $x + $w - $this->corner, $y-$h, + $x + $w, $y-$h+$this->corner, + $x + $w, $y); + } + else { + $x += $aImg->plotwidth -$w; + $p = array($x, $y, + $x, $y-$h+$this->corner, + $x + $this->corner,$y-$h, + $x + $w - $this->corner, $y-$h, + $x + $w, $y-$h+$this->corner, + $x + $w, $y); + } + } + else { + if( $this->width === TABTITLE_WIDTHFULL ) + $w = $aImg->plotwidth ; + else + $w = $this->width ; + + // Make the tab fit the width of the plot area + $p = array($x, $y, + $x, $y-$h+$this->corner, + $x + $this->corner,$y-$h, + $x + $w - $this->corner, $y-$h, + $x + $w, $y-$h+$this->corner, + $x + $w, $y); + + } + if( $this->halign == 'left' ) { + $aImg->SetTextAlign('left','bottom'); + $x += $this->posx; + $y -= $this->posy; + } + elseif( $this->halign == 'center' ) { + $aImg->SetTextAlign('center','bottom'); + $x += $w/2; + $y -= $this->posy; + } + else { + $aImg->SetTextAlign('right','bottom'); + $x += $w - $this->posx; + $y -= $this->posy; + } + + $aImg->SetColor($this->fillcolor); + $aImg->FilledPolygon($p); + + $aImg->SetColor($this->bordercolor); + $aImg->Polygon($p,true); + + $aImg->SetColor($this->color); + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->StrokeText($x,$y,$this->t,0,'center'); + } + +} + +//=================================================== +// CLASS SuperScriptText +// Description: Format a superscript text +//=================================================== +class SuperScriptText extends Text { + private $iSuper=""; + private $sfont_family="",$sfont_style="",$sfont_size=8; + private $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65; + private $iSDir=0; + private $iSimple=false; + + function SuperScriptText($aTxt="",$aSuper="",$aXAbsPos=0,$aYAbsPos=0) { + parent::Text($aTxt,$aXAbsPos,$aYAbsPos); + $this->iSuper = $aSuper; + } + + function FromReal($aVal,$aPrecision=2) { + // Convert a floating point number to scientific notation + $neg=1.0; + if( $aVal < 0 ) { + $neg = -1.0; + $aVal = -$aVal; + } + + $l = floor(log10($aVal)); + $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision)); + $a *= $neg; + if( $this->iSimple && ($a == 1 || $a==-1) ) $a = ''; + + if( $a != '' ) + $this->t = $a.' * 10'; + else { + if( $neg == 1 ) + $this->t = '10'; + else + $this->t = '-10'; + } + $this->iSuper = $l; + } + + function Set($aTxt,$aSuper="") { + $this->t = $aTxt; + $this->iSuper = $aSuper; + } + + function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) { + $this->sfont_family = $aFontFam; + $this->sfont_style = $aFontStyle; + $this->sfont_size = $aFontSize; + } + + // Total width of text + function GetWidth($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $w = $aImg->GetTextWidth($this->t); + $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); + $w += $aImg->GetTextWidth($this->iSuper); + $w += $this->iSuperMargin; + return $w; + } + + // Hight of font (approximate the height of the text) + function GetFontHeight($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetFontHeight(); + $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); + $h += $aImg->GetFontHeight(); + return $h; + } + + // Hight of text + function GetTextHeight($aImg) { + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $h = $aImg->GetTextHeight($this->t); + $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); + $h += $aImg->GetTextHeight($this->iSuper); + return $h; + } + + function Stroke($aImg,$ax=-1,$ay=-1) { + + // To position the super script correctly we need different + // cases to handle the alignmewnt specified since that will + // determine how we can interpret the x,y coordinates + + $w = parent::GetWidth($aImg); + $h = parent::GetTextHeight($aImg); + switch( $this->valign ) { + case 'top': + $sy = $this->y; + break; + case 'center': + $sy = $this->y - $h/2; + break; + case 'bottom': + $sy = $this->y - $h; + break; + default: + JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text'); + break; + } + + switch( $this->halign ) { + case 'left': + $sx = $this->x + $w; + break; + case 'center': + $sx = $this->x + $w/2; + break; + case 'right': + $sx = $this->x; + break; + default: + JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text'); + break; + } + + $sx += $this->iSuperMargin; + $sy += $this->iVertOverlap; + + // Should we automatically determine the font or + // has the user specified it explicetly? + if( $this->sfont_family == "" ) { + if( $this->font_family <= FF_FONT2 ) { + if( $this->font_family == FF_FONT0 ) { + $sff = FF_FONT0; + } + elseif( $this->font_family == FF_FONT1 ) { + if( $this->font_style == FS_NORMAL ) + $sff = FF_FONT0; + else + $sff = FF_FONT1; + } + else { + $sff = FF_FONT1; + } + $sfs = $this->font_style; + $sfz = $this->font_size; + } + else { + // TTF fonts + $sff = $this->font_family; + $sfs = $this->font_style; + $sfz = floor($this->font_size*$this->iSuperScale); + if( $sfz < 8 ) $sfz = 8; + } + $this->sfont_family = $sff; + $this->sfont_style = $sfs; + $this->sfont_size = $sfz; + } + else { + $sff = $this->sfont_family; + $sfs = $this->sfont_style; + $sfz = $this->sfont_size; + } + + parent::Stroke($aImg,$ax,$ay); + + + // For the builtin fonts we need to reduce the margins + // since the bounding bx reported for the builtin fonts + // are much larger than for the TTF fonts. + if( $sff <= FF_FONT2 ) { + $sx -= 2; + $sy += 3; + } + + $aImg->SetTextAlign('left','bottom'); + $aImg->SetFont($sff,$sfs,$sfz); + $aImg->PushColor($this->color); + $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left'); + $aImg->PopColor(); + } +} + + +//=================================================== +// CLASS Grid +// Description: responsible for drawing grid lines in graph +//=================================================== +class Grid { + protected $img; + protected $scale; + protected $grid_color='#DDDDDD',$grid_mincolor='#DDDDDD'; + protected $type="solid"; + protected $show=false, $showMinor=false,$weight=1; + protected $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF'); +//--------------- +// CONSTRUCTOR + function Grid($aAxis) { + $this->scale = $aAxis->scale; + $this->img = $aAxis->img; + } +//--------------- +// PUBLIC METHODS + function SetColor($aMajColor,$aMinColor=false) { + $this->grid_color=$aMajColor; + if( $aMinColor === false ) + $aMinColor = $aMajColor ; + $this->grid_mincolor = $aMinColor; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + + // Specify if grid should be dashed, dotted or solid + function SetLineStyle($aType) { + $this->type = $aType; + } + + // Decide if both major and minor grid should be displayed + function Show($aShowMajor=true,$aShowMinor=false) { + $this->show=$aShowMajor; + $this->showMinor=$aShowMinor; + } + + function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') { + $this->fill = $aFlg; + $this->fillcolor = array( $aColor1, $aColor2 ); + } + + // Display the grid + function Stroke() { + if( $this->showMinor && !$this->scale->textscale ) { + $tmp = $this->grid_color; + $this->grid_color = $this->grid_mincolor; + $this->DoStroke($this->scale->ticks->ticks_pos); + + $this->grid_color = $tmp; + $this->DoStroke($this->scale->ticks->maj_ticks_pos); + } + else { + $this->DoStroke($this->scale->ticks->maj_ticks_pos); + } + } + +//-------------- +// Private methods + // Draw the grid + function DoStroke($aTicksPos) { + if( !$this->show ) + return; + $nbrgrids = count($aTicksPos); + + if( $this->scale->type=="y" ) { + $xl=$this->img->left_margin; + $xr=$this->img->width-$this->img->right_margin; + + if( $this->fill ) { + // Draw filled areas + $y2 = $aTicksPos[0]; + $i=1; + while( $i < $nbrgrids ) { + $y1 = $y2; + $y2 = $aTicksPos[$i++]; + $this->img->SetColor($this->fillcolor[$i & 1]); + $this->img->FilledRectangle($xl,$y1,$xr,$y2); + } + } + + $this->img->SetColor($this->grid_color); + $this->img->SetLineWeight($this->weight); + + // Draw grid lines + for($i=0; $i<$nbrgrids; ++$i) { + $y=$aTicksPos[$i]; + if( $this->type == "solid" ) + $this->img->Line($xl,$y,$xr,$y); + elseif( $this->type == "dotted" ) + $this->img->DashedLine($xl,$y,$xr,$y,1,6); + elseif( $this->type == "dashed" ) + $this->img->DashedLine($xl,$y,$xr,$y,2,4); + elseif( $this->type == "longdashed" ) + $this->img->DashedLine($xl,$y,$xr,$y,8,6); + } + } + elseif( $this->scale->type=="x" ) { + $yu=$this->img->top_margin; + $yl=$this->img->height-$this->img->bottom_margin; + $limit=$this->img->width-$this->img->right_margin; + + if( $this->fill ) { + // Draw filled areas + $x2 = $aTicksPos[0]; + $i=1; + while( $i < $nbrgrids ) { + $x1 = $x2; + $x2 = min($aTicksPos[$i++],$limit) ; + $this->img->SetColor($this->fillcolor[$i & 1]); + $this->img->FilledRectangle($x1,$yu,$x2,$yl); + } + } + + $this->img->SetColor($this->grid_color); + $this->img->SetLineWeight($this->weight); + + // We must also test for limit since we might have + // an offset and the number of ticks is calculated with + // assumption offset==0 so we might end up drawing one + // to many gridlines + $i=0; + $x=$aTicksPos[$i]; + while( $itype == "solid" ) + $this->img->Line($x,$yl,$x,$yu); + elseif( $this->type == "dotted" ) + $this->img->DashedLine($x,$yl,$x,$yu,1,6); + elseif( $this->type == "dashed" ) + $this->img->DashedLine($x,$yl,$x,$yu,2,4); + elseif( $this->type == "longdashed" ) + $this->img->DashedLine($x,$yl,$x,$yu,8,6); + ++$i; + } + } + else { + JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']'); + } + return true; + } +} // Class + +//=================================================== +// CLASS Axis +// Description: Defines X and Y axis. Notes that at the +// moment the code is not really good since the axis on +// several occasion must know wheter it's an X or Y axis. +// This was a design decision to make the code easier to +// follow. +//=================================================== +class AxisPrototype { + public $scale=null; + public $img=null; + public $hide=false,$hide_labels=false; + public $title=null; + public $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0; + public $tick_step=1; + public $pos = false; + public $ticks_label = array(); + + protected $weight=1; + protected $color=array(0,0,0),$label_color=array(0,0,0); + protected $ticks_label_colors=null; + protected $show_first_label=true,$show_last_label=true; + protected $label_step=1; // Used by a text axis to specify what multiple of major steps + // should be labeled. + protected $labelPos=0; // Which side of the axis should the labels be? + protected $title_adjust,$title_margin,$title_side=SIDE_LEFT; + protected $tick_label_margin=7; + protected $label_halign = '',$label_valign = '', $label_para_align='left'; + protected $hide_line=false; + protected $iDeltaAbsPos=0; + +//--------------- +// CONSTRUCTOR + function Axis($img,$aScale,$color=array(0,0,0)) { + $this->img = $img; + $this->scale = $aScale; + $this->color = $color; + $this->title=new Text(""); + + if( $aScale->type=="y" ) { + $this->title_margin = 25; + $this->title_adjust="middle"; + $this->title->SetOrientation(90); + $this->tick_label_margin=7; + $this->labelPos=SIDE_LEFT; + } + else { + $this->title_margin = 5; + $this->title_adjust="high"; + $this->title->SetOrientation(0); + $this->tick_label_margin=7; + $this->labelPos=SIDE_DOWN; + $this->title_side=SIDE_DOWN; + } + } +//--------------- +// PUBLIC METHODS + + function SetLabelFormat($aFormStr) { + $this->scale->ticks->SetLabelFormat($aFormStr); + } + + function SetLabelFormatString($aFormStr,$aDate=false) { + $this->scale->ticks->SetLabelFormat($aFormStr,$aDate); + } + + function SetLabelFormatCallback($aFuncName) { + $this->scale->ticks->SetFormatCallback($aFuncName); + } + + function SetLabelAlign($aHAlign,$aVAlign="top",$aParagraphAlign='left') { + $this->label_halign = $aHAlign; + $this->label_valign = $aVAlign; + $this->label_para_align = $aParagraphAlign; + } + + // Don't display the first label + function HideFirstTickLabel($aShow=false) { + $this->show_first_label=$aShow; + } + + function HideLastTickLabel($aShow=false) { + $this->show_last_label=$aShow; + } + + // Manually specify the major and (optional) minor tick position and labels + function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { + $this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels); + } + + // Manually specify major tick positions and optional labels + function SetMajTickPositions($aMajPos,$aLabels=NULL) { + $this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels); + } + + // Hide minor or major tick marks + function HideTicks($aHideMinor=true,$aHideMajor=true) { + $this->scale->ticks->SupressMinorTickMarks($aHideMinor); + $this->scale->ticks->SupressTickMarks($aHideMajor); + } + + // Hide zero label + function HideZeroLabel($aFlag=true) { + $this->scale->ticks->SupressZeroLabel(); + } + + function HideFirstLastLabel() { + // The two first calls to ticks method will supress + // automatically generated scale values. However, that + // will not affect manually specified value, e.g text-scales. + // therefor we also make a kludge here to supress manually + // specified scale labels. + $this->scale->ticks->SupressLast(); + $this->scale->ticks->SupressFirst(); + $this->show_first_label = false; + $this->show_last_label = false; + } + + // Hide the axis + function Hide($aHide=true) { + $this->hide=$aHide; + } + + // Hide the actual axis-line, but still print the labels + function HideLine($aHide=true) { + $this->hide_line = $aHide; + } + + function HideLabels($aHide=true) { + $this->hide_labels = $aHide; + } + + + // Weight of axis + function SetWeight($aWeight) { + $this->weight = $aWeight; + } + + // Axis color + function SetColor($aColor,$aLabelColor=false) { + $this->color = $aColor; + if( !$aLabelColor ) $this->label_color = $aColor; + else $this->label_color = $aLabelColor; + } + + // Title on axis + function SetTitle($aTitle,$aAdjustAlign="high") { + $this->title->Set($aTitle); + $this->title_adjust=$aAdjustAlign; + } + + // Specify distance from the axis + function SetTitleMargin($aMargin) { + $this->title_margin=$aMargin; + } + + // Which side of the axis should the axis title be? + function SetTitleSide($aSideOfAxis) { + $this->title_side = $aSideOfAxis; + } + + // Utility function to set the direction for tick marks + function SetTickDirection($aDir) { + // Will be deprecated from 1.7 + if( ERR_DEPRECATED ) + JpGraphError::RaiseL(25055);//('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead'); + $this->scale->ticks->SetSide($aDir); + } + + function SetTickSide($aDir) { + $this->scale->ticks->SetSide($aDir); + } + + // Specify text labels for the ticks. One label for each data point + function SetTickLabels($aLabelArray,$aLabelColorArray=null) { + $this->ticks_label = $aLabelArray; + $this->ticks_label_colors = $aLabelColorArray; + } + + // How far from the axis should the labels be drawn + function SetTickLabelMargin($aMargin) { + if( ERR_DEPRECATED ) + JpGraphError::RaiseL(25056);//('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.'); + $this->tick_label_margin=$aMargin; + } + + function SetLabelMargin($aMargin) { + $this->tick_label_margin=$aMargin; + } + + // Specify that every $step of the ticks should be displayed starting + // at $start + // DEPRECATED FUNCTION: USE SetTextTickInterval() INSTEAD + function SetTextTicks($step,$start=0) { + JpGraphError::RaiseL(25057);//(" SetTextTicks() is deprecated. Use SetTextTickInterval() instead."); + } + + // Specify that every $step of the ticks should be displayed starting + // at $start + function SetTextTickInterval($aStep,$aStart=0) { + $this->scale->ticks->SetTextLabelStart($aStart); + $this->tick_step=$aStep; + } + + // Specify that every $step tick mark should have a label + // should be displayed starting + function SetTextLabelInterval($aStep) { + if( $aStep < 1 ) + JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1."); + $this->label_step=$aStep; + } + + // Which side of the axis should the labels be on? + function SetLabelPos($aSidePos) { + // This will be deprecated from 1.7 + if( ERR_DEPRECATED ) + JpGraphError::RaiseL(25059);//('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.'); + $this->labelPos=$aSidePos; + } + + function SetLabelSide($aSidePos) { + $this->labelPos=$aSidePos; + } + + // Set the font + function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { + $this->font_family = $aFamily; + $this->font_style = $aStyle; + $this->font_size = $aSize; + } + + // Position for axis line on the "other" scale + function SetPos($aPosOnOtherScale) { + $this->pos=$aPosOnOtherScale; + } + + // Set the position of the axis to be X-pixels delta to the right + // of the max X-position (used to position the multiple Y-axis) + function SetPosAbsDelta($aDelta) { + $this->iDeltaAbsPos=$aDelta; + } + + // Specify the angle for the tick labels + function SetLabelAngle($aAngle) { + $this->label_angle = $aAngle; + } + +} // Class + + +//=================================================== +// CLASS Axis +// Description: Defines X and Y axis. Notes that at the +// moment the code is not really good since the axis on +// several occasion must know wheter it's an X or Y axis. +// This was a design decision to make the code easier to +// follow. +//=================================================== +class Axis extends AxisPrototype { + + function Axis($img,$aScale,$color=array(0,0,0)) { + parent::Axis($img,$aScale,$color); + } + + // Stroke the axis. + function Stroke($aOtherAxisScale,$aStrokeLabels=true) { + if( $this->hide ) return; + if( is_numeric($this->pos) ) { + $pos=$aOtherAxisScale->Translate($this->pos); + } + else { // Default to minimum of other scale if pos not set + if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos=="min" ) { + $pos = $aOtherAxisScale->scale_abs[0]; + } + elseif($this->pos == "max") { + $pos = $aOtherAxisScale->scale_abs[1]; + } + else { // If negative set x-axis at 0 + $this->pos=0; + $pos=$aOtherAxisScale->Translate(0); + } + } + $pos += $this->iDeltaAbsPos; + $this->img->SetLineWeight($this->weight); + $this->img->SetColor($this->color); + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + if( $this->scale->type == "x" ) { + if( !$this->hide_line ) + $this->img->FilledRectangle($this->img->left_margin,$pos, + $this->img->width-$this->img->right_margin,$pos+$this->weight-1); + if( $this->title_side == SIDE_DOWN ) { + $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin; + $yalign = 'top'; + } + else { + $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin; + $yalign = 'bottom'; + } + + if( $this->title_adjust=='high' ) + $this->title->SetPos($this->img->width-$this->img->right_margin,$y,'right',$yalign); + elseif( $this->title_adjust=='middle' || $this->title_adjust=='center' ) + $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,'center',$yalign); + elseif($this->title_adjust=='low') + $this->title->SetPos($this->img->left_margin,$y,'left',$yalign); + else { + JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); + } + } + elseif( $this->scale->type == "y" ) { + // Add line weight to the height of the axis since + // the x-axis could have a width>1 and we want the axis to fit nicely together. + if( !$this->hide_line ) + $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin, + $pos,$this->img->height-$this->img->bottom_margin+$this->weight-1); + $x=$pos ; + if( $this->title_side == SIDE_LEFT ) { + $x -= $this->title_margin; + $x -= $this->title->margin; + $halign="right"; + } + else { + $x += $this->title_margin; + $x += $this->title->margin; + $halign="left"; + } + // If the user has manually specified an hor. align + // then we override the automatic settings with this + // specifed setting. Since default is 'left' we compare + // with that. (This means a manually set 'left' align + // will have no effect.) + if( $this->title->halign != 'left' ) + $halign = $this->title->halign; + if( $this->title_adjust=="high" ) + $this->title->SetPos($x,$this->img->top_margin,$halign,"top"); + elseif($this->title_adjust=="middle" || $this->title_adjust=="center") + $this->title->SetPos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center"); + elseif($this->title_adjust=="low") + $this->title->SetPos($x,$this->img->height-$this->img->bottom_margin,$halign,"bottom"); + else + JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')'); + + } + $this->scale->ticks->Stroke($this->img,$this->scale,$pos); + if( $aStrokeLabels ) { + if( !$this->hide_labels ) + $this->StrokeLabels($pos); + $this->title->Stroke($this->img); + } + } + +//--------------- +// PRIVATE METHODS + // Draw all the tick labels on major tick marks + function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) { + + $this->img->SetColor($this->label_color); + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + $yoff=$this->img->GetFontHeight()/2; + + // Only draw labels at major tick marks + $nbr = count($this->scale->ticks->maj_ticks_label); + + // We have the option to not-display the very first mark + // (Usefull when the first label might interfere with another + // axis.) + $i = $this->show_first_label ? 0 : 1 ; + if( !$this->show_last_label ) --$nbr; + // Now run through all labels making sure we don't overshoot the end + // of the scale. + $ncolor=0; + if( isset($this->ticks_label_colors) ) + $ncolor=count($this->ticks_label_colors); + while( $i<$nbr ) { + // $tpos holds the absolute text position for the label + $tpos=$this->scale->ticks->maj_ticklabels_pos[$i]; + + // Note. the $limit is only used for the x axis since we + // might otherwise overshoot if the scale has been centered + // This is due to us "loosing" the last tick mark if we center. + if( $this->scale->type=="x" && $tpos > $this->img->width-$this->img->right_margin+1 ) { + return; + } + // we only draw every $label_step label + if( ($i % $this->label_step)==0 ) { + + // Set specific label color if specified + if( $ncolor > 0 ) + $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); + + // If the label has been specified use that and in other case + // just label the mark with the actual scale value + $m=$this->scale->ticks->GetMajor(); + + // ticks_label has an entry for each data point and is the array + // that holds the labels set by the user. If the user hasn't + // specified any values we use whats in the automatically asigned + // labels in the maj_ticks_label + if( isset($this->ticks_label[$i*$m]) ) + $label=$this->ticks_label[$i*$m]; + else { + if( $aAbsLabel ) + $label=abs($this->scale->ticks->maj_ticks_label[$i]); + else + $label=$this->scale->ticks->maj_ticks_label[$i]; + if( $this->scale->textscale && $this->scale->ticks->label_formfunc == '' ) { + ++$label; + } + } + + if( $this->scale->type == "x" ) { + if( $this->labelPos == SIDE_DOWN ) { + if( $this->label_angle==0 || $this->label_angle==90 ) { + if( $this->label_halign=='' && $this->label_valign=='') + $this->img->SetTextAlign('center','top'); + else + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + + } + else { + if( $this->label_halign=='' && $this->label_valign=='') + $this->img->SetTextAlign("right","top"); + else + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin+1,$label, + $this->label_angle,$this->label_para_align); + } + else { + if( $this->label_angle==0 || $this->label_angle==90 ) { + if( $this->label_halign=='' && $this->label_valign=='') + $this->img->SetTextAlign("center","bottom"); + else + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + else { + if( $this->label_halign=='' && $this->label_valign=='') + $this->img->SetTextAlign("right","bottom"); + else + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + } + $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin-1,$label, + $this->label_angle,$this->label_para_align); + } + } + else { + // scale->type == "y" + //if( $this->label_angle!=0 ) + //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis"); + if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis + if( $this->label_halign=='' && $this->label_valign=='') + $this->img->SetTextAlign("right","center"); + else + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); + } + else { // To the right of the y-axis + if( $this->label_halign=='' && $this->label_valign=='') + $this->img->SetTextAlign("left","center"); + else + $this->img->SetTextAlign($this->label_halign,$this->label_valign); + $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); + } + } + } + ++$i; + } + } + +} + + +//=================================================== +// CLASS Ticks +// Description: Abstract base class for drawing linear and logarithmic +// tick marks on axis +//=================================================== +class Ticks { + public $label_formatstr=''; // C-style format string to use for labels + public $label_formfunc=''; + public $direction=1; // Should ticks be in(=1) the plot area or outside (=-1) + public $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false; + public $maj_ticks_pos = array(), $maj_ticklabels_pos = array(), + $ticks_pos = array(), $maj_ticks_label = array(); + + protected $minor_abs_size=3, $major_abs_size=5; + protected $scale; + protected $is_set=false; + protected $precision; + protected $supress_zerolabel=false,$supress_first=false; + protected $mincolor="",$majcolor=""; + protected $weight=1; + protected $label_dateformatstr=''; + protected $label_usedateformat=FALSE; + +//--------------- +// CONSTRUCTOR + function Ticks($aScale) { + $this->scale=$aScale; + $this->precision = -1; + } + +//--------------- +// PUBLIC METHODS + // Set format string for automatic labels + function SetLabelFormat($aFormatString,$aDate=FALSE) { + $this->label_formatstr=$aFormatString; + $this->label_usedateformat=$aDate; + } + + function SetLabelDateFormat($aFormatString) { + $this->label_dateformatstr=$aFormatString; + } + + function SetFormatCallback($aCallbackFuncName) { + $this->label_formfunc = $aCallbackFuncName; + } + + // Don't display the first zero label + function SupressZeroLabel($aFlag=true) { + $this->supress_zerolabel=$aFlag; + } + + // Don't display minor tick marks + function SupressMinorTickMarks($aHide=true) { + $this->supress_minor_tickmarks=$aHide; + } + + // Don't display major tick marks + function SupressTickMarks($aHide=true) { + $this->supress_tickmarks=$aHide; + } + + // Hide the first tick mark + function SupressFirst($aHide=true) { + $this->supress_first=$aHide; + } + + // Hide the last tick mark + function SupressLast($aHide=true) { + $this->supress_last=$aHide; + } + + // Size (in pixels) of minor tick marks + function GetMinTickAbsSize() { + return $this->minor_abs_size; + } + + // Size (in pixels) of major tick marks + function GetMajTickAbsSize() { + return $this->major_abs_size; + } + + function SetSize($aMajSize,$aMinSize=3) { + $this->major_abs_size = $aMajSize; + $this->minor_abs_size = $aMinSize; + } + + // Have the ticks been specified + function IsSpecified() { + return $this->is_set; + } + + // Specify number of decimals in automatic labels + // Deprecated from 1.4. Use SetFormatString() instead + function SetPrecision($aPrecision) { + if( ERR_DEPRECATED ) + JpGraphError::RaiseL(25063);//('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead'); + $this->precision=$aPrecision; + } + + function SetSide($aSide) { + $this->direction=$aSide; + } + + // Which side of the axis should the ticks be on + function SetDirection($aSide=SIDE_RIGHT) { + $this->direction=$aSide; + } + + // Set colors for major and minor tick marks + function SetMarkColor($aMajorColor,$aMinorColor="") { + $this->SetColor($aMajorColor,$aMinorColor); + } + + function SetColor($aMajorColor,$aMinorColor="") { + $this->majcolor=$aMajorColor; + + // If not specified use same as major + if( $aMinorColor=="" ) + $this->mincolor=$aMajorColor; + else + $this->mincolor=$aMinorColor; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + +} // Class + +//=================================================== +// CLASS LinearTicks +// Description: Draw linear ticks on axis +//=================================================== +class LinearTicks extends Ticks { + public $minor_step=1, $major_step=2; + public $xlabel_offset=0,$xtick_offset=0; + private $label_offset=0; // What offset should the displayed label have + // i.e should we display 0,1,2 or 1,2,3,4 or 2,3,4 etc + private $text_label_start=0; + private $iManualTickPos = NULL, $iManualMinTickPos = NULL, $iManualTickLabels = NULL; + private $iAdjustForDST = false; // If a date falls within the DST period add one hour to the diaplyed time + +//--------------- +// CONSTRUCTOR + function LinearTicks() { + $this->precision = -1; + } + +//--------------- +// PUBLIC METHODS + + + // Return major step size in world coordinates + function GetMajor() { + return $this->major_step; + } + + // Return minor step size in world coordinates + function GetMinor() { + return $this->minor_step; + } + + // Set Minor and Major ticks (in world coordinates) + function Set($aMajStep,$aMinStep=false) { + if( $aMinStep==false ) + $aMinStep=$aMajStep; + + if( $aMajStep <= 0 || $aMinStep <= 0 ) { + JpGraphError::RaiseL(25064); +//(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); + } + + $this->major_step=$aMajStep; + $this->minor_step=$aMinStep; + $this->is_set = true; + } + + function SetMajTickPositions($aMajPos,$aLabels=NULL) { + $this->SetTickPositions($aMajPos,NULL,$aLabels); + } + + function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { + if( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) { + JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()'); + return; + } + $n=count($aMajPos); + if( is_array($aLabels) && (count($aLabels) != $n) ) { + JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.'); + return; + } + $this->iManualTickPos = $aMajPos; + $this->iManualMinTickPos = $aMinPos; + $this->iManualTickLabels = $aLabels; + } + + // Specify all the tick positions manually and possible also the exact labels + function _doManualTickPos($aScale) { + $n=count($this->iManualTickPos); + $m=count($this->iManualMinTickPos); + $doLbl=count($this->iManualTickLabels) > 0; + + $this->maj_ticks_pos = array(); + $this->maj_ticklabels_pos = array(); + $this->ticks_pos = array(); + + // Now loop through the supplied positions and translate them to screen coordinates + // and store them in the maj_label_positions + $minScale = $aScale->scale[0]; + $maxScale = $aScale->scale[1]; + $j=0; + for($i=0; $i < $n ; ++$i ) { + // First make sure that the first tick is not lower than the lower scale value + if( !isset($this->iManualTickPos[$i]) || + $this->iManualTickPos[$i] < $minScale || $this->iManualTickPos[$i] > $maxScale) { + continue; + } + + + $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]); + $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j]; + + // Set the minor tick marks the same as major if not specified + if( $m <= 0 ) { + $this->ticks_pos[$j] = $this->maj_ticks_pos[$j]; + } + + if( $doLbl ) { + $this->maj_ticks_label[$j] = $this->iManualTickLabels[$i]; + } + else { + $this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n); + } + ++$j; + } + + // Some sanity check + if( count($this->maj_ticks_pos) < 2 ) { + JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.'); + } + + // Setup the minor tick marks + $j=0; + for($i=0; $i < $m; ++$i ) { + if( empty($this->iManualMinTickPos[$i]) || + $this->iManualMinTickPos[$i] < $minScale || $this->iManualMinTickPos[$i] > $maxScale) + continue; + $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]); + ++$j; + } + } + + function _doAutoTickPos($aScale) { + $maj_step_abs = $aScale->scale_factor*$this->major_step; + $min_step_abs = $aScale->scale_factor*$this->minor_step; + + if( $min_step_abs==0 || $maj_step_abs==0 ) { + JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')"); + } + // We need to make this an int since comparing it below + // with the result from round() can give wrong result, such that + // (40 < 40) == TRUE !!! + $limit = (int)$aScale->scale_abs[1]; + + if( $aScale->textscale ) { + // This can only be true for a X-scale (horizontal) + // Define ticks for a text scale. This is slightly different from a + // normal linear type of scale since the position might be adjusted + // and the labels start at on + $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset; + $start_abs=$aScale->scale_factor*$this->text_label_start; + $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; + + $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs; + for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) { + // Apply format to label + $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks); + $label+=$this->major_step; + + // The x-position of the tick marks can be different from the labels. + // Note that we record the tick position (not the label) so that the grid + // happen upon tick marks and not labels. + $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs; + $this->maj_ticks_pos[$i]=$xtick; + $this->maj_ticklabels_pos[$i] = round($x); + $x += $maj_step_abs; + } + } + else { + $label = $aScale->GetMinVal(); + $abs_pos = $aScale->scale_abs[0]; + $j=0; $i=0; + $step = round($maj_step_abs/$min_step_abs); + if( $aScale->type == "x" ) { + // For a normal linear type of scale the major ticks will always be multiples + // of the minor ticks. In order to avoid any rounding issues the major ticks are + // defined as every "step" minor ticks and not calculated separately + $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; + while( round($abs_pos) <= $limit ) { + $this->ticks_pos[] = round($abs_pos); + $this->ticks_label[] = $label; + if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks ) { + $this->maj_ticks_pos[$j] = round($abs_pos); + $this->maj_ticklabels_pos[$j] = round($abs_pos); + $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); + ++$j; + } + ++$i; + $abs_pos += $min_step_abs; + $label+=$this->minor_step; + } + } + elseif( $aScale->type == "y" ) { + $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1; + while( round($abs_pos) >= $limit ) { + $this->ticks_pos[$i] = round($abs_pos); + $this->ticks_label[$i]=$label; + if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks) { + $this->maj_ticks_pos[$j] = round($abs_pos); + $this->maj_ticklabels_pos[$j] = round($abs_pos); + $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); + ++$j; + } + ++$i; + $abs_pos += $min_step_abs; + $label += $this->minor_step; + } + } + } + } + + function AdjustForDST($aFlg=true) { + $this->iAdjustForDST = $aFlg; + } + + + function _doLabelFormat($aVal,$aIdx,$aNbrTicks) { + + // If precision hasn't been specified set it to a sensible value + if( $this->precision==-1 ) { + $t = log10($this->minor_step); + if( $t > 0 ) + $precision = 0; + else + $precision = -floor($t); + } + else + $precision = $this->precision; + + if( $this->label_formfunc != '' ) { + $f=$this->label_formfunc; + $l = call_user_func($f,$aVal); + } + elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) { + if( $this->label_usedateformat ) { + // Adjust the value to take daylight savings into account + if (date("I",$aVal)==1 && $this->iAdjustForDST ) // DST + $aVal+=3600; + + $l = date($this->label_formatstr,$aVal); + if( $this->label_formatstr == 'W' ) { + // If we use week formatting then add a single 'w' in front of the + // week number to differentiate it from dates + $l = 'w'.$l; + } + } + else { + if( $this->label_dateformatstr !== '' ) { + // Adjust the value to take daylight savings into account + if (date("I",$aVal)==1 && $this->iAdjustForDST ) // DST + $aVal+=3600; + + $l = date($this->label_dateformatstr,$aVal); + if( $this->label_formatstr == 'W' ) { + // If we use week formatting then add a single 'w' in front of the + // week number to differentiate it from dates + $l = 'w'.$l; + } + } + else + $l = sprintf($this->label_formatstr,$aVal); + } + } + else { + $l = sprintf('%01.'.$precision.'f',round($aVal,$precision)); + } + + if( ($this->supress_zerolabel && $l==0) || ($this->supress_first && $aIdx==0) || + ($this->supress_last && $aIdx==$aNbrTicks-1) ) { + $l=''; + } + return $l; + } + + // Stroke ticks on either X or Y axis + function _StrokeTicks($aImg,$aScale,$aPos) { + $hor = $aScale->type == 'x'; + $aImg->SetLineWeight($this->weight); + + // We need to make this an int since comparing it below + // with the result from round() can give wrong result, such that + // (40 < 40) == TRUE !!! + $limit = (int)$aScale->scale_abs[1]; + + // A text scale doesn't have any minor ticks + if( !$aScale->textscale ) { + // Stroke minor ticks + $yu = $aPos - $this->direction*$this->GetMinTickAbsSize(); + $xr = $aPos + $this->direction*$this->GetMinTickAbsSize(); + $n = count($this->ticks_pos); + for($i=0; $i < $n; ++$i ) { + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); + if( $hor ) { + //if( $this->ticks_pos[$i] <= $limit ) + $aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu); + } + else { + //if( $this->ticks_pos[$i] >= $limit ) + $aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]); + } + if( $this->mincolor!="" ) $aImg->PopColor(); + } + } + } + + // Stroke major ticks + $yu = $aPos - $this->direction*$this->GetMajTickAbsSize(); + $xr = $aPos + $this->direction*$this->GetMajTickAbsSize(); + $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; + $n = count($this->maj_ticks_pos); + for($i=0; $i < $n ; ++$i ) { + if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) { + if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); + if( $hor ) { + //if( $this->maj_ticks_pos[$i] <= $limit ) + $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu); + } + else { + //if( $this->maj_ticks_pos[$i] >= $limit ) + $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]); + } + if( $this->majcolor!="" ) $aImg->PopColor(); + } + } + + } + + // Draw linear ticks + function Stroke($aImg,$aScale,$aPos) { + if( $this->iManualTickPos != NULL ) + $this->_doManualTickPos($aScale); + else + $this->_doAutoTickPos($aScale); + $this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' ); + } + +//--------------- +// PRIVATE METHODS + // Spoecify the offset of the displayed tick mark with the tick "space" + // Legal values for $o is [0,1] used to adjust where the tick marks and label + // should be positioned within the major tick-size + // $lo specifies the label offset and $to specifies the tick offset + // this comes in handy for example in bar graphs where we wont no offset for the + // tick but have the labels displayed halfway under the bars. + function SetXLabelOffset($aLabelOff,$aTickOff=-1) { + $this->xlabel_offset=$aLabelOff; + if( $aTickOff==-1 ) // Same as label offset + $this->xtick_offset=$aLabelOff; + else + $this->xtick_offset=$aTickOff; + if( $aLabelOff>0 ) + $this->SupressLast(); // The last tick wont fit + } + + // Which tick label should we start with? + function SetTextLabelStart($aTextLabelOff) { + $this->text_label_start=$aTextLabelOff; + } + +} // Class + +//=================================================== +// CLASS LinearScale +// Description: Handle linear scaling between screen and world +//=================================================== +class LinearScale { + public $textscale=false; // Just a flag to let the Plot class find out if + // we are a textscale or not. This is a cludge since + // this information is available in Graph::axtype but + // we don't have access to the graph object in the Plots + // stroke method. So we let graph store the status here + // when the linear scale is created. A real cludge... + public $type; // is this x or y scale ? + public $ticks=null; // Store ticks + public $text_scale_off = 0; + public $scale_abs=array(0,0); + public $scale_factor; // Scale factor between world and screen + public $off; // Offset between image edge and plot area + public $scale=array(0,0); + public $name = 'lin'; + public $auto_ticks=false; // When using manual scale should the ticks be automatically set? + public $world_abs_size; // Plot area size in pixels (Needed public in jpgraph_radar.php) + public $world_size; // Plot area size in world coordinates + public $intscale=false; // Restrict autoscale to integers + protected $autoscale_min=false; // Forced minimum value, auto determine max + protected $autoscale_max=false; // Forced maximum value, auto determine min + private $gracetop=0,$gracebottom=0; +//--------------- +// CONSTRUCTOR + function LinearScale($aMin=0,$aMax=0,$aType="y") { + assert($aType=="x" || $aType=="y" ); + assert($aMin<=$aMax); + + $this->type=$aType; + $this->scale=array($aMin,$aMax); + $this->world_size=$aMax-$aMin; + $this->ticks = new LinearTicks(); + } + +//--------------- +// PUBLIC METHODS + // Check if scale is set or if we should autoscale + // We should do this is either scale or ticks has not been set + function IsSpecified() { + if( $this->GetMinVal()==$this->GetMaxVal() ) { // Scale not set + return false; + } + return true; + } + + // Set the minimum data value when the autoscaling is used. + // Usefull if you want a fix minimum (like 0) but have an + // automatic maximum + function SetAutoMin($aMin) { + $this->autoscale_min=$aMin; + } + + // Set the minimum data value when the autoscaling is used. + // Usefull if you want a fix minimum (like 0) but have an + // automatic maximum + function SetAutoMax($aMax) { + $this->autoscale_max=$aMax; + } + + // If the user manually specifies a scale should the ticks + // still be set automatically? + function SetAutoTicks($aFlag=true) { + $this->auto_ticks = $aFlag; + } + + // Specify scale "grace" value (top and bottom) + function SetGrace($aGraceTop,$aGraceBottom=0) { + if( $aGraceTop<0 || $aGraceBottom < 0 ) + JpGraphError::RaiseL(25069);//(" Grace must be larger then 0"); + $this->gracetop=$aGraceTop; + $this->gracebottom=$aGraceBottom; + } + + // Get the minimum value in the scale + function GetMinVal() { + return $this->scale[0]; + } + + // get maximum value for scale + function GetMaxVal() { + return $this->scale[1]; + } + + // Specify a new min/max value for sclae + function Update($aImg,$aMin,$aMax) { + $this->scale=array($aMin,$aMax); + $this->world_size=$aMax-$aMin; + $this->InitConstants($aImg); + } + + // Translate between world and screen + function Translate($aCoord) { + if( !is_numeric($aCoord) ) { + if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) + JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); + return 0; + } + else { + return $this->off+($aCoord - $this->scale[0]) * $this->scale_factor; + } + } + + // Relative translate (don't include offset) usefull when we just want + // to know the relative position (in pixels) on the axis + function RelTranslate($aCoord) { + if( !is_numeric($aCoord) ) { + if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) + JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); + return 0; + } + else { + return ($aCoord - $this->scale[0]) * $this->scale_factor; + } + } + + // Restrict autoscaling to only use integers + function SetIntScale($aIntScale=true) { + $this->intscale=$aIntScale; + } + + // Calculate an integer autoscale + function IntAutoScale($img,$min,$max,$maxsteps,$majend=true) { + // Make sure limits are integers + $min=floor($min); + $max=ceil($max); + if( abs($min-$max)==0 ) { + --$min; ++$max; + } + $maxsteps = floor($maxsteps); + + $gracetop=round(($this->gracetop/100.0)*abs($max-$min)); + $gracebottom=round(($this->gracebottom/100.0)*abs($max-$min)); + if( is_numeric($this->autoscale_min) ) { + $min = ceil($this->autoscale_min); + if( $min >= $max ) { + JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); + } + } + + if( is_numeric($this->autoscale_max) ) { + $max = ceil($this->autoscale_max); + if( $min >= $max ) { + JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); + } + } + + if( abs($min-$max ) == 0 ) { + ++$max; + --$min; + } + + $min -= $gracebottom; + $max += $gracetop; + + // First get tickmarks as multiples of 1, 10, ... + if( $majend ) { + list($num1steps,$adj1min,$adj1max,$maj1step) = + $this->IntCalcTicks($maxsteps,$min,$max,1); + } + else { + $adj1min = $min; + $adj1max = $max; + list($num1steps,$maj1step) = + $this->IntCalcTicksFreeze($maxsteps,$min,$max,1); + } + + if( abs($min-$max) > 2 ) { + // Then get tick marks as 2:s 2, 20, ... + if( $majend ) { + list($num2steps,$adj2min,$adj2max,$maj2step) = + $this->IntCalcTicks($maxsteps,$min,$max,5); + } + else { + $adj2min = $min; + $adj2max = $max; + list($num2steps,$maj2step) = + $this->IntCalcTicksFreeze($maxsteps,$min,$max,5); + } + } + else { + $num2steps = 10000; // Dummy high value so we don't choose this + } + + if( abs($min-$max) > 5 ) { + // Then get tickmarks as 5:s 5, 50, 500, ... + if( $majend ) { + list($num5steps,$adj5min,$adj5max,$maj5step) = + $this->IntCalcTicks($maxsteps,$min,$max,2); + } + else { + $adj5min = $min; + $adj5max = $max; + list($num5steps,$maj5step) = + $this->IntCalcTicksFreeze($maxsteps,$min,$max,2); + } + } + else { + $num5steps = 10000; // Dummy high value so we don't choose this + } + + // Check to see whichof 1:s, 2:s or 5:s fit better with + // the requested number of major ticks + $match1=abs($num1steps-$maxsteps); + $match2=abs($num2steps-$maxsteps); + if( !empty($maj5step) && $maj5step > 1 ) + $match5=abs($num5steps-$maxsteps); + else + $match5=10000; // Dummy high value + + // Compare these three values and see which is the closest match + // We use a 0.6 weight to gravitate towards multiple of 5:s + if( $match1 < $match2 ) { + if( $match1 < $match5 ) + $r=1; + else + $r=3; + } + else { + if( $match2 < $match5 ) + $r=2; + else + $r=3; + } + // Minsteps are always the same as maxsteps for integer scale + switch( $r ) { + case 1: + $this->ticks->Set($maj1step,$maj1step); + $this->Update($img,$adj1min,$adj1max); + break; + case 2: + $this->ticks->Set($maj2step,$maj2step); + $this->Update($img,$adj2min,$adj2max); + break; + case 3: + $this->ticks->Set($maj5step,$maj5step); + $this->Update($img,$adj5min,$adj5max); + break; + default: + JpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)'); + } + } + + + // Calculate autoscale. Used if user hasn't given a scale and ticks + // $maxsteps is the maximum number of major tickmarks allowed. + function AutoScale($img,$min,$max,$maxsteps,$majend=true) { + if( $this->intscale ) { + $this->IntAutoScale($img,$min,$max,$maxsteps,$majend); + return; + } + if( abs($min-$max) < 0.00001 ) { + // We need some difference to be able to autoscale + // make it 5% above and 5% below value + if( $min==0 && $max==0 ) { // Special case + $min=-1; $max=1; + } + else { + $delta = (abs($max)+abs($min))*0.005; + $min -= $delta; + $max += $delta; + } + } + + $gracetop=($this->gracetop/100.0)*abs($max-$min); + $gracebottom=($this->gracebottom/100.0)*abs($max-$min); + if( is_numeric($this->autoscale_min) ) { + $min = $this->autoscale_min; + if( $min >= $max ) { + JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); + } + if( abs($min-$max ) < 0.00001 ) + $max *= 1.2; + } + + if( is_numeric($this->autoscale_max) ) { + $max = $this->autoscale_max; + if( $min >= $max ) { + JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); + } + if( abs($min-$max ) < 0.00001 ) + $min *= 0.8; + } + + + $min -= $gracebottom; + $max += $gracetop; + + // First get tickmarks as multiples of 0.1, 1, 10, ... + if( $majend ) { + list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = + $this->CalcTicks($maxsteps,$min,$max,1,2); + } + else { + $adj1min=$min; + $adj1max=$max; + list($num1steps,$min1step,$maj1step) = + $this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false); + } + + // Then get tick marks as 2:s 0.2, 2, 20, ... + if( $majend ) { + list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = + $this->CalcTicks($maxsteps,$min,$max,5,2); + } + else { + $adj2min=$min; + $adj2max=$max; + list($num2steps,$min2step,$maj2step) = + $this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false); + } + + // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ... + if( $majend ) { + list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = + $this->CalcTicks($maxsteps,$min,$max,2,5); + } + else { + $adj5min=$min; + $adj5max=$max; + list($num5steps,$min5step,$maj5step) = + $this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false); + } + + // Check to see whichof 1:s, 2:s or 5:s fit better with + // the requested number of major ticks + $match1=abs($num1steps-$maxsteps); + $match2=abs($num2steps-$maxsteps); + $match5=abs($num5steps-$maxsteps); + // Compare these three values and see which is the closest match + // We use a 0.8 weight to gravitate towards multiple of 5:s + $r=$this->MatchMin3($match1,$match2,$match5,0.8); + switch( $r ) { + case 1: + $this->Update($img,$adj1min,$adj1max); + $this->ticks->Set($maj1step,$min1step); + break; + case 2: + $this->Update($img,$adj2min,$adj2max); + $this->ticks->Set($maj2step,$min2step); + break; + case 3: + $this->Update($img,$adj5min,$adj5max); + $this->ticks->Set($maj5step,$min5step); + break; + } + } + +//--------------- +// PRIVATE METHODS + + // This method recalculates all constants that are depending on the + // margins in the image. If the margins in the image are changed + // this method should be called for every scale that is registred with + // that image. Should really be installed as an observer of that image. + function InitConstants($img) { + if( $this->type=="x" ) { + $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin; + $this->off=$img->left_margin; + $this->scale_factor = 0; + if( $this->world_size > 0 ) + $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); + } + else { // y scale + $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin; + $this->off=$img->top_margin+$this->world_abs_size; + $this->scale_factor = 0; + if( $this->world_size > 0 ) + $this->scale_factor=-$this->world_abs_size/($this->world_size*1.0); + } + $size = $this->world_size * $this->scale_factor; + $this->scale_abs=array($this->off,$this->off + $size); + } + + // Initialize the conversion constants for this scale + // This tries to pre-calculate as much as possible to speed up the + // actual conversion (with Translate()) later on + // $start =scale start in absolute pixels (for x-scale this is an y-position + // and for an y-scale this is an x-position + // $len =absolute length in pixels of scale + function SetConstants($aStart,$aLen) { + $this->world_abs_size=$aLen; + $this->off=$aStart; + + if( $this->world_size<=0 ) { + // This should never ever happen !! + JpGraphError::RaiseL(25074); +//("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale]
    Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); + + } + + // scale_factor = number of pixels per world unit + $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); + + // scale_abs = start and end points of scale in absolute pixels + $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor); + } + + + // Calculate number of ticks steps with a specific division + // $a is the divisor of 10**x to generate the first maj tick intervall + // $a=1, $b=2 give major ticks with multiple of 10, ...,0.1,1,10,... + // $a=5, $b=2 give major ticks with multiple of 2:s ...,0.2,2,20,... + // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,... + // We return a vector of + // [$numsteps,$adjmin,$adjmax,$minstep,$majstep] + // If $majend==true then the first and last marks on the axis will be major + // labeled tick marks otherwise it will be adjusted to the closest min tick mark + function CalcTicks($maxsteps,$min,$max,$a,$b,$majend=true) { + $diff=$max-$min; + if( $diff==0 ) + $ld=0; + else + $ld=floor(log10($diff)); + + // Gravitate min towards zero if we are close + if( $min>0 && $min < pow(10,$ld) ) $min=0; + + //$majstep=pow(10,$ld-1)/$a; + $majstep=pow(10,$ld)/$a; + $minstep=$majstep/$b; + + $adjmax=ceil($max/$minstep)*$minstep; + $adjmin=floor($min/$minstep)*$minstep; + $adjdiff = $adjmax-$adjmin; + $numsteps=$adjdiff/$majstep; + + while( $numsteps>$maxsteps ) { + $majstep=pow(10,$ld)/$a; + $numsteps=$adjdiff/$majstep; + ++$ld; + } + + $minstep=$majstep/$b; + $adjmin=floor($min/$minstep)*$minstep; + $adjdiff = $adjmax-$adjmin; + if( $majend ) { + $adjmin = floor($min/$majstep)*$majstep; + $adjdiff = $adjmax-$adjmin; + $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; + } + else + $adjmax=ceil($max/$minstep)*$minstep; + + return array($numsteps,$adjmin,$adjmax,$minstep,$majstep); + } + + function CalcTicksFreeze($maxsteps,$min,$max,$a,$b) { + // Same as CalcTicks but don't adjust min/max values + $diff=$max-$min; + if( $diff==0 ) + $ld=0; + else + $ld=floor(log10($diff)); + + //$majstep=pow(10,$ld-1)/$a; + $majstep=pow(10,$ld)/$a; + $minstep=$majstep/$b; + $numsteps=floor($diff/$majstep); + + while( $numsteps > $maxsteps ) { + $majstep=pow(10,$ld)/$a; + $numsteps=floor($diff/$majstep); + ++$ld; + } + $minstep=$majstep/$b; + return array($numsteps,$minstep,$majstep); + } + + + function IntCalcTicks($maxsteps,$min,$max,$a,$majend=true) { + $diff=$max-$min; + if( $diff==0 ) + JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); + else + $ld=floor(log10($diff)); + + // Gravitate min towards zero if we are close + if( $min>0 && $min < pow(10,$ld) ) $min=0; + + if( $ld == 0 ) $ld=1; + + if( $a == 1 ) + $majstep = 1; + else + $majstep=pow(10,$ld)/$a; + $adjmax=ceil($max/$majstep)*$majstep; + + $adjmin=floor($min/$majstep)*$majstep; + $adjdiff = $adjmax-$adjmin; + $numsteps=$adjdiff/$majstep; + while( $numsteps>$maxsteps ) { + $majstep=pow(10,$ld)/$a; + $numsteps=$adjdiff/$majstep; + ++$ld; + } + + $adjmin=floor($min/$majstep)*$majstep; + $adjdiff = $adjmax-$adjmin; + if( $majend ) { + $adjmin = floor($min/$majstep)*$majstep; + $adjdiff = $adjmax-$adjmin; + $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; + } + else + $adjmax=ceil($max/$majstep)*$majstep; + + return array($numsteps,$adjmin,$adjmax,$majstep); + } + + + function IntCalcTicksFreeze($maxsteps,$min,$max,$a) { + // Same as IntCalcTick but don't change min/max values + $diff=$max-$min; + if( $diff==0 ) + JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); + else + $ld=floor(log10($diff)); + + if( $ld == 0 ) $ld=1; + + if( $a == 1 ) + $majstep = 1; + else + $majstep=pow(10,$ld)/$a; + + $numsteps=floor($diff/$majstep); + while( $numsteps > $maxsteps ) { + $majstep=pow(10,$ld)/$a; + $numsteps=floor($diff/$majstep); + ++$ld; + } + + return array($numsteps,$majstep); + } + + + + // Determine the minimum of three values witha weight for last value + function MatchMin3($a,$b,$c,$weight) { + if( $a < $b ) { + if( $a < ($c*$weight) ) + return 1; // $a smallest + else + return 3; // $c smallest + } + elseif( $b < ($c*$weight) ) + return 2; // $b smallest + return 3; // $c smallest + } +} // Class + +//=================================================== +// CLASS RGB +// Description: Color definitions as RGB triples +//=================================================== +class RGB { + public $rgb_table; + public $img; + + function RGB($aImg=null) { + $this->img = $aImg; + + // Conversion array between color names and RGB + $this->rgb_table = array( + "aqua"=> array(0,255,255), + "lime"=> array(0,255,0), + "teal"=> array(0,128,128), + "whitesmoke"=>array(245,245,245), + "gainsboro"=>array(220,220,220), + "oldlace"=>array(253,245,230), + "linen"=>array(250,240,230), + "antiquewhite"=>array(250,235,215), + "papayawhip"=>array(255,239,213), + "blanchedalmond"=>array(255,235,205), + "bisque"=>array(255,228,196), + "peachpuff"=>array(255,218,185), + "navajowhite"=>array(255,222,173), + "moccasin"=>array(255,228,181), + "cornsilk"=>array(255,248,220), + "ivory"=>array(255,255,240), + "lemonchiffon"=>array(255,250,205), + "seashell"=>array(255,245,238), + "mintcream"=>array(245,255,250), + "azure"=>array(240,255,255), + "aliceblue"=>array(240,248,255), + "lavender"=>array(230,230,250), + "lavenderblush"=>array(255,240,245), + "mistyrose"=>array(255,228,225), + "white"=>array(255,255,255), + "black"=>array(0,0,0), + "darkslategray"=>array(47,79,79), + "dimgray"=>array(105,105,105), + "slategray"=>array(112,128,144), + "lightslategray"=>array(119,136,153), + "gray"=>array(190,190,190), + "lightgray"=>array(211,211,211), + "midnightblue"=>array(25,25,112), + "navy"=>array(0,0,128), + "cornflowerblue"=>array(100,149,237), + "darkslateblue"=>array(72,61,139), + "slateblue"=>array(106,90,205), + "mediumslateblue"=>array(123,104,238), + "lightslateblue"=>array(132,112,255), + "mediumblue"=>array(0,0,205), + "royalblue"=>array(65,105,225), + "blue"=>array(0,0,255), + "dodgerblue"=>array(30,144,255), + "deepskyblue"=>array(0,191,255), + "skyblue"=>array(135,206,235), + "lightskyblue"=>array(135,206,250), + "steelblue"=>array(70,130,180), + "lightred"=>array(211,167,168), + "lightsteelblue"=>array(176,196,222), + "lightblue"=>array(173,216,230), + "powderblue"=>array(176,224,230), + "paleturquoise"=>array(175,238,238), + "darkturquoise"=>array(0,206,209), + "mediumturquoise"=>array(72,209,204), + "turquoise"=>array(64,224,208), + "cyan"=>array(0,255,255), + "lightcyan"=>array(224,255,255), + "cadetblue"=>array(95,158,160), + "mediumaquamarine"=>array(102,205,170), + "aquamarine"=>array(127,255,212), + "darkgreen"=>array(0,100,0), + "darkolivegreen"=>array(85,107,47), + "darkseagreen"=>array(143,188,143), + "seagreen"=>array(46,139,87), + "mediumseagreen"=>array(60,179,113), + "lightseagreen"=>array(32,178,170), + "palegreen"=>array(152,251,152), + "springgreen"=>array(0,255,127), + "lawngreen"=>array(124,252,0), + "green"=>array(0,255,0), + "chartreuse"=>array(127,255,0), + "mediumspringgreen"=>array(0,250,154), + "greenyellow"=>array(173,255,47), + "limegreen"=>array(50,205,50), + "yellowgreen"=>array(154,205,50), + "forestgreen"=>array(34,139,34), + "olivedrab"=>array(107,142,35), + "darkkhaki"=>array(189,183,107), + "khaki"=>array(240,230,140), + "palegoldenrod"=>array(238,232,170), + "lightgoldenrodyellow"=>array(250,250,210), + "lightyellow"=>array(255,255,200), + "yellow"=>array(255,255,0), + "gold"=>array(255,215,0), + "lightgoldenrod"=>array(238,221,130), + "goldenrod"=>array(218,165,32), + "darkgoldenrod"=>array(184,134,11), + "rosybrown"=>array(188,143,143), + "indianred"=>array(205,92,92), + "saddlebrown"=>array(139,69,19), + "sienna"=>array(160,82,45), + "peru"=>array(205,133,63), + "burlywood"=>array(222,184,135), + "beige"=>array(245,245,220), + "wheat"=>array(245,222,179), + "sandybrown"=>array(244,164,96), + "tan"=>array(210,180,140), + "chocolate"=>array(210,105,30), + "firebrick"=>array(178,34,34), + "brown"=>array(165,42,42), + "darksalmon"=>array(233,150,122), + "salmon"=>array(250,128,114), + "lightsalmon"=>array(255,160,122), + "orange"=>array(255,165,0), + "darkorange"=>array(255,140,0), + "coral"=>array(255,127,80), + "lightcoral"=>array(240,128,128), + "tomato"=>array(255,99,71), + "orangered"=>array(255,69,0), + "red"=>array(255,0,0), + "hotpink"=>array(255,105,180), + "deeppink"=>array(255,20,147), + "pink"=>array(255,192,203), + "lightpink"=>array(255,182,193), + "palevioletred"=>array(219,112,147), + "maroon"=>array(176,48,96), + "mediumvioletred"=>array(199,21,133), + "violetred"=>array(208,32,144), + "magenta"=>array(255,0,255), + "violet"=>array(238,130,238), + "plum"=>array(221,160,221), + "orchid"=>array(218,112,214), + "mediumorchid"=>array(186,85,211), + "darkorchid"=>array(153,50,204), + "darkviolet"=>array(148,0,211), + "blueviolet"=>array(138,43,226), + "purple"=>array(160,32,240), + "mediumpurple"=>array(147,112,219), + "thistle"=>array(216,191,216), + "snow1"=>array(255,250,250), + "snow2"=>array(238,233,233), + "snow3"=>array(205,201,201), + "snow4"=>array(139,137,137), + "seashell1"=>array(255,245,238), + "seashell2"=>array(238,229,222), + "seashell3"=>array(205,197,191), + "seashell4"=>array(139,134,130), + "AntiqueWhite1"=>array(255,239,219), + "AntiqueWhite2"=>array(238,223,204), + "AntiqueWhite3"=>array(205,192,176), + "AntiqueWhite4"=>array(139,131,120), + "bisque1"=>array(255,228,196), + "bisque2"=>array(238,213,183), + "bisque3"=>array(205,183,158), + "bisque4"=>array(139,125,107), + "peachPuff1"=>array(255,218,185), + "peachpuff2"=>array(238,203,173), + "peachpuff3"=>array(205,175,149), + "peachpuff4"=>array(139,119,101), + "navajowhite1"=>array(255,222,173), + "navajowhite2"=>array(238,207,161), + "navajowhite3"=>array(205,179,139), + "navajowhite4"=>array(139,121,94), + "lemonchiffon1"=>array(255,250,205), + "lemonchiffon2"=>array(238,233,191), + "lemonchiffon3"=>array(205,201,165), + "lemonchiffon4"=>array(139,137,112), + "ivory1"=>array(255,255,240), + "ivory2"=>array(238,238,224), + "ivory3"=>array(205,205,193), + "ivory4"=>array(139,139,131), + "honeydew"=>array(193,205,193), + "lavenderblush1"=>array(255,240,245), + "lavenderblush2"=>array(238,224,229), + "lavenderblush3"=>array(205,193,197), + "lavenderblush4"=>array(139,131,134), + "mistyrose1"=>array(255,228,225), + "mistyrose2"=>array(238,213,210), + "mistyrose3"=>array(205,183,181), + "mistyrose4"=>array(139,125,123), + "azure1"=>array(240,255,255), + "azure2"=>array(224,238,238), + "azure3"=>array(193,205,205), + "azure4"=>array(131,139,139), + "slateblue1"=>array(131,111,255), + "slateblue2"=>array(122,103,238), + "slateblue3"=>array(105,89,205), + "slateblue4"=>array(71,60,139), + "royalblue1"=>array(72,118,255), + "royalblue2"=>array(67,110,238), + "royalblue3"=>array(58,95,205), + "royalblue4"=>array(39,64,139), + "dodgerblue1"=>array(30,144,255), + "dodgerblue2"=>array(28,134,238), + "dodgerblue3"=>array(24,116,205), + "dodgerblue4"=>array(16,78,139), + "steelblue1"=>array(99,184,255), + "steelblue2"=>array(92,172,238), + "steelblue3"=>array(79,148,205), + "steelblue4"=>array(54,100,139), + "deepskyblue1"=>array(0,191,255), + "deepskyblue2"=>array(0,178,238), + "deepskyblue3"=>array(0,154,205), + "deepskyblue4"=>array(0,104,139), + "skyblue1"=>array(135,206,255), + "skyblue2"=>array(126,192,238), + "skyblue3"=>array(108,166,205), + "skyblue4"=>array(74,112,139), + "lightskyblue1"=>array(176,226,255), + "lightskyblue2"=>array(164,211,238), + "lightskyblue3"=>array(141,182,205), + "lightskyblue4"=>array(96,123,139), + "slategray1"=>array(198,226,255), + "slategray2"=>array(185,211,238), + "slategray3"=>array(159,182,205), + "slategray4"=>array(108,123,139), + "lightsteelblue1"=>array(202,225,255), + "lightsteelblue2"=>array(188,210,238), + "lightsteelblue3"=>array(162,181,205), + "lightsteelblue4"=>array(110,123,139), + "lightblue1"=>array(191,239,255), + "lightblue2"=>array(178,223,238), + "lightblue3"=>array(154,192,205), + "lightblue4"=>array(104,131,139), + "lightcyan1"=>array(224,255,255), + "lightcyan2"=>array(209,238,238), + "lightcyan3"=>array(180,205,205), + "lightcyan4"=>array(122,139,139), + "paleturquoise1"=>array(187,255,255), + "paleturquoise2"=>array(174,238,238), + "paleturquoise3"=>array(150,205,205), + "paleturquoise4"=>array(102,139,139), + "cadetblue1"=>array(152,245,255), + "cadetblue2"=>array(142,229,238), + "cadetblue3"=>array(122,197,205), + "cadetblue4"=>array(83,134,139), + "turquoise1"=>array(0,245,255), + "turquoise2"=>array(0,229,238), + "turquoise3"=>array(0,197,205), + "turquoise4"=>array(0,134,139), + "cyan1"=>array(0,255,255), + "cyan2"=>array(0,238,238), + "cyan3"=>array(0,205,205), + "cyan4"=>array(0,139,139), + "darkslategray1"=>array(151,255,255), + "darkslategray2"=>array(141,238,238), + "darkslategray3"=>array(121,205,205), + "darkslategray4"=>array(82,139,139), + "aquamarine1"=>array(127,255,212), + "aquamarine2"=>array(118,238,198), + "aquamarine3"=>array(102,205,170), + "aquamarine4"=>array(69,139,116), + "darkseagreen1"=>array(193,255,193), + "darkseagreen2"=>array(180,238,180), + "darkseagreen3"=>array(155,205,155), + "darkseagreen4"=>array(105,139,105), + "seagreen1"=>array(84,255,159), + "seagreen2"=>array(78,238,148), + "seagreen3"=>array(67,205,128), + "seagreen4"=>array(46,139,87), + "palegreen1"=>array(154,255,154), + "palegreen2"=>array(144,238,144), + "palegreen3"=>array(124,205,124), + "palegreen4"=>array(84,139,84), + "springgreen1"=>array(0,255,127), + "springgreen2"=>array(0,238,118), + "springgreen3"=>array(0,205,102), + "springgreen4"=>array(0,139,69), + "chartreuse1"=>array(127,255,0), + "chartreuse2"=>array(118,238,0), + "chartreuse3"=>array(102,205,0), + "chartreuse4"=>array(69,139,0), + "olivedrab1"=>array(192,255,62), + "olivedrab2"=>array(179,238,58), + "olivedrab3"=>array(154,205,50), + "olivedrab4"=>array(105,139,34), + "darkolivegreen1"=>array(202,255,112), + "darkolivegreen2"=>array(188,238,104), + "darkolivegreen3"=>array(162,205,90), + "darkolivegreen4"=>array(110,139,61), + "khaki1"=>array(255,246,143), + "khaki2"=>array(238,230,133), + "khaki3"=>array(205,198,115), + "khaki4"=>array(139,134,78), + "lightgoldenrod1"=>array(255,236,139), + "lightgoldenrod2"=>array(238,220,130), + "lightgoldenrod3"=>array(205,190,112), + "lightgoldenrod4"=>array(139,129,76), + "yellow1"=>array(255,255,0), + "yellow2"=>array(238,238,0), + "yellow3"=>array(205,205,0), + "yellow4"=>array(139,139,0), + "gold1"=>array(255,215,0), + "gold2"=>array(238,201,0), + "gold3"=>array(205,173,0), + "gold4"=>array(139,117,0), + "goldenrod1"=>array(255,193,37), + "goldenrod2"=>array(238,180,34), + "goldenrod3"=>array(205,155,29), + "goldenrod4"=>array(139,105,20), + "darkgoldenrod1"=>array(255,185,15), + "darkgoldenrod2"=>array(238,173,14), + "darkgoldenrod3"=>array(205,149,12), + "darkgoldenrod4"=>array(139,101,8), + "rosybrown1"=>array(255,193,193), + "rosybrown2"=>array(238,180,180), + "rosybrown3"=>array(205,155,155), + "rosybrown4"=>array(139,105,105), + "indianred1"=>array(255,106,106), + "indianred2"=>array(238,99,99), + "indianred3"=>array(205,85,85), + "indianred4"=>array(139,58,58), + "sienna1"=>array(255,130,71), + "sienna2"=>array(238,121,66), + "sienna3"=>array(205,104,57), + "sienna4"=>array(139,71,38), + "burlywood1"=>array(255,211,155), + "burlywood2"=>array(238,197,145), + "burlywood3"=>array(205,170,125), + "burlywood4"=>array(139,115,85), + "wheat1"=>array(255,231,186), + "wheat2"=>array(238,216,174), + "wheat3"=>array(205,186,150), + "wheat4"=>array(139,126,102), + "tan1"=>array(255,165,79), + "tan2"=>array(238,154,73), + "tan3"=>array(205,133,63), + "tan4"=>array(139,90,43), + "chocolate1"=>array(255,127,36), + "chocolate2"=>array(238,118,33), + "chocolate3"=>array(205,102,29), + "chocolate4"=>array(139,69,19), + "firebrick1"=>array(255,48,48), + "firebrick2"=>array(238,44,44), + "firebrick3"=>array(205,38,38), + "firebrick4"=>array(139,26,26), + "brown1"=>array(255,64,64), + "brown2"=>array(238,59,59), + "brown3"=>array(205,51,51), + "brown4"=>array(139,35,35), + "salmon1"=>array(255,140,105), + "salmon2"=>array(238,130,98), + "salmon3"=>array(205,112,84), + "salmon4"=>array(139,76,57), + "lightsalmon1"=>array(255,160,122), + "lightsalmon2"=>array(238,149,114), + "lightsalmon3"=>array(205,129,98), + "lightsalmon4"=>array(139,87,66), + "orange1"=>array(255,165,0), + "orange2"=>array(238,154,0), + "orange3"=>array(205,133,0), + "orange4"=>array(139,90,0), + "darkorange1"=>array(255,127,0), + "darkorange2"=>array(238,118,0), + "darkorange3"=>array(205,102,0), + "darkorange4"=>array(139,69,0), + "coral1"=>array(255,114,86), + "coral2"=>array(238,106,80), + "coral3"=>array(205,91,69), + "coral4"=>array(139,62,47), + "tomato1"=>array(255,99,71), + "tomato2"=>array(238,92,66), + "tomato3"=>array(205,79,57), + "tomato4"=>array(139,54,38), + "orangered1"=>array(255,69,0), + "orangered2"=>array(238,64,0), + "orangered3"=>array(205,55,0), + "orangered4"=>array(139,37,0), + "deeppink1"=>array(255,20,147), + "deeppink2"=>array(238,18,137), + "deeppink3"=>array(205,16,118), + "deeppink4"=>array(139,10,80), + "hotpink1"=>array(255,110,180), + "hotpink2"=>array(238,106,167), + "hotpink3"=>array(205,96,144), + "hotpink4"=>array(139,58,98), + "pink1"=>array(255,181,197), + "pink2"=>array(238,169,184), + "pink3"=>array(205,145,158), + "pink4"=>array(139,99,108), + "lightpink1"=>array(255,174,185), + "lightpink2"=>array(238,162,173), + "lightpink3"=>array(205,140,149), + "lightpink4"=>array(139,95,101), + "palevioletred1"=>array(255,130,171), + "palevioletred2"=>array(238,121,159), + "palevioletred3"=>array(205,104,137), + "palevioletred4"=>array(139,71,93), + "maroon1"=>array(255,52,179), + "maroon2"=>array(238,48,167), + "maroon3"=>array(205,41,144), + "maroon4"=>array(139,28,98), + "violetred1"=>array(255,62,150), + "violetred2"=>array(238,58,140), + "violetred3"=>array(205,50,120), + "violetred4"=>array(139,34,82), + "magenta1"=>array(255,0,255), + "magenta2"=>array(238,0,238), + "magenta3"=>array(205,0,205), + "magenta4"=>array(139,0,139), + "mediumred"=>array(140,34,34), + "orchid1"=>array(255,131,250), + "orchid2"=>array(238,122,233), + "orchid3"=>array(205,105,201), + "orchid4"=>array(139,71,137), + "plum1"=>array(255,187,255), + "plum2"=>array(238,174,238), + "plum3"=>array(205,150,205), + "plum4"=>array(139,102,139), + "mediumorchid1"=>array(224,102,255), + "mediumorchid2"=>array(209,95,238), + "mediumorchid3"=>array(180,82,205), + "mediumorchid4"=>array(122,55,139), + "darkorchid1"=>array(191,62,255), + "darkorchid2"=>array(178,58,238), + "darkorchid3"=>array(154,50,205), + "darkorchid4"=>array(104,34,139), + "purple1"=>array(155,48,255), + "purple2"=>array(145,44,238), + "purple3"=>array(125,38,205), + "purple4"=>array(85,26,139), + "mediumpurple1"=>array(171,130,255), + "mediumpurple2"=>array(159,121,238), + "mediumpurple3"=>array(137,104,205), + "mediumpurple4"=>array(93,71,139), + "thistle1"=>array(255,225,255), + "thistle2"=>array(238,210,238), + "thistle3"=>array(205,181,205), + "thistle4"=>array(139,123,139), + "gray1"=>array(10,10,10), + "gray2"=>array(40,40,30), + "gray3"=>array(70,70,70), + "gray4"=>array(100,100,100), + "gray5"=>array(130,130,130), + "gray6"=>array(160,160,160), + "gray7"=>array(190,190,190), + "gray8"=>array(210,210,210), + "gray9"=>array(240,240,240), + "darkgray"=>array(100,100,100), + "darkblue"=>array(0,0,139), + "darkcyan"=>array(0,139,139), + "darkmagenta"=>array(139,0,139), + "darkred"=>array(139,0,0), + "silver"=>array(192, 192, 192), + "eggplant"=>array(144,176,168), + "lightgreen"=>array(144,238,144)); + } +//---------------- +// PUBLIC METHODS + // Colors can be specified as either + // 1. #xxxxxx HTML style + // 2. "colorname" as a named color + // 3. array(r,g,b) RGB triple + // This function translates this to a native RGB format and returns an + // RGB triple. + function Color($aColor) { + if (is_string($aColor)) { + // Strip of any alpha factor + $pos = strpos($aColor,'@'); + if( $pos === false ) { + $alpha = 0; + } + else { + $pos2 = strpos($aColor,':'); + if( $pos2===false ) + $pos2 = $pos-1; // Sentinel + if( $pos > $pos2 ) { + $alpha = substr($aColor,$pos+1); + $aColor = substr($aColor,0,$pos); + } + else { + $alpha = substr($aColor,$pos+1,$pos2-$pos-1); + $aColor = substr($aColor,0,$pos).substr($aColor,$pos2); + } + } + + // Extract potential adjustment figure at end of color + // specification + $pos = strpos($aColor,":"); + if( $pos === false ) { + $adj = 1.0; + } + else { + $adj = 0.0 + substr($aColor,$pos+1); + $aColor = substr($aColor,0,$pos); + } + if( $adj < 0 ) + JpGraphError::RaiseL(25077);//('Adjustment factor for color must be > 0'); + + if (substr($aColor, 0, 1) == "#") { + $r = hexdec(substr($aColor, 1, 2)); + $g = hexdec(substr($aColor, 3, 2)); + $b = hexdec(substr($aColor, 5, 2)); + } else { + if(!isset($this->rgb_table[$aColor]) ) + JpGraphError::RaiseL(25078,$aColor);//(" Unknown color: $aColor"); + $tmp=$this->rgb_table[$aColor]; + $r = $tmp[0]; + $g = $tmp[1]; + $b = $tmp[2]; + } + // Scale adj so that an adj=2 always + // makes the color 100% white (i.e. 255,255,255. + // and adj=1 neutral and adj=0 black. + if( $adj > 1 ) { + $m = ($adj-1.0)*(255-min(255,min($r,min($g,$b)))); + return array(min(255,$r+$m), min(255,$g+$m), min(255,$b+$m),$alpha); + } + elseif( $adj < 1 ) { + $m = ($adj-1.0)*max(255,max($r,max($g,$b))); + return array(max(0,$r+$m), max(0,$g+$m), max(0,$b+$m),$alpha); + } + else { + return array($r,$g,$b,$alpha); + } + + } elseif( is_array($aColor) ) { + if( count($aColor)==3 ) { + $aColor[3]=0; + return $aColor; + } + else + return $aColor; + } + else + JpGraphError::RaiseL(25079,$aColor,count($aColor));//(" Unknown color specification: $aColor , size=".count($aColor)); + } + + // Compare two colors + // return true if equal + function Equal($aCol1,$aCol2) { + $c1 = $this->Color($aCol1); + $c2 = $this->Color($aCol2); + if( $c1[0]==$c2[0] && $c1[1]==$c2[1] && $c1[2]==$c2[2] ) + return true; + else + return false; + } + + // Allocate a new color in the current image + // Return new color index, -1 if no more colors could be allocated + function Allocate($aColor,$aAlpha=0.0) { + list ($r, $g, $b, $a) = $this->color($aColor); + // If alpha is specified in the color string then this + // takes precedence over the second argument + if( $a > 0 ) + $aAlpha = $a; + if( $aAlpha < 0 || $aAlpha > 1 ) { + JpGraphError::RaiseL(25080);//('Alpha parameter for color must be between 0.0 and 1.0'); + } + return imagecolorresolvealpha($this->img, $r, $g, $b, round($aAlpha * 127)); + } +} // Class + + +//=================================================== +// CLASS Image +// Description: Wrapper class with some goodies to form the +// Interface to low level image drawing routines. +//=================================================== +class Image { + public $left_margin=30,$right_margin=30,$top_margin=20,$bottom_margin=30; + public $img=null; + public $plotwidth=0,$plotheight=0; + public $width=0, $height=0; + public $rgb=null; + public $current_color,$current_color_name; + public $line_weight=1, $line_style=1; // Default line style is solid + public $img_format; + protected $expired=true; + protected $lastx=0, $lasty=0; + protected $obs_list=array(); + protected $font_size=12,$font_family=FF_FONT1, $font_style=FS_NORMAL; + protected $font_file=''; + protected $text_halign="left",$text_valign="bottom"; + protected $ttf=null; + protected $use_anti_aliasing=false; + protected $quality=null; + protected $colorstack=array(),$colorstackidx=0; + protected $canvascolor = 'white' ; + protected $langconv = null ; + protected $iInterlace=false; + //--------------- + // CONSTRUCTOR + function Image($aWidth,$aHeight,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) { + $this->CreateImgCanvas($aWidth,$aHeight); + if( $aSetAutoMargin ) + $this->SetAutoMargin(); + + if( !$this->SetImgFormat($aFormat) ) { + JpGraphError::RaiseL(25081,$aFormat);//("JpGraph: Selected graphic format is either not supported or unknown [$aFormat]"); + } + $this->ttf = new TTF(); + $this->langconv = new LanguageConv(); + } + + // Enable interlacing in images + function SetInterlace($aFlg=true) { + $this->iInterlace=$aFlg; + } + + // Should we use anti-aliasing. Note: This really slows down graphics! + function SetAntiAliasing($aFlg=true) { + $this->use_anti_aliasing = $aFlg; + if( function_exists('imageantialias') ) { + imageantialias($this->img,$aFlg); + } + else { + JpGraphError::RaiseL(25128);//('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.') + } + } + + function CreateRawCanvas($aWidth=0,$aHeight=0) { + if( $aWidth <= 1 || $aHeight <= 1 ) { + JpGraphError::RaiseL(25082,$aWidth,$aHeight);//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)"); + } + + if( USE_TRUECOLOR ) { + $this->img = @imagecreatetruecolor($aWidth, $aHeight); + if( $this->img < 1 ) { + JpGraphError::RaiseL(25126); + //die("Can't create truecolor image. Check that you really have GD2 library installed."); + } + $this->SetAlphaBlending(); + } else { + $this->img = @imagecreate($aWidth, $aHeight); + if( $this->img < 1 ) { + JpGraphError::RaiseL(25126); + //die("JpGraph Error: Can't create image. Check that you really have the GD library installed."); + } + } + + if( $this->iInterlace ) { + imageinterlace($this->img,1); + } + if( $this->rgb != null ) + $this->rgb->img = $this->img ; + else + $this->rgb = new RGB($this->img); + } + + function CloneCanvasH() { + $oldimage = $this->img; + $this->CreateRawCanvas($this->width,$this->height); + imagecopy($this->img,$oldimage,0,0,0,0,$this->width,$this->height); + return $oldimage; + } + + function CreateImgCanvas($aWidth=0,$aHeight=0) { + + $old = array($this->img,$this->width,$this->height); + + $aWidth = round($aWidth); + $aHeight = round($aHeight); + + $this->width=$aWidth; + $this->height=$aHeight; + + + if( $aWidth==0 || $aHeight==0 ) { + // We will set the final size later. + // Note: The size must be specified before any other + // img routines that stroke anything are called. + $this->img = null; + $this->rgb = null; + return $old; + } + + $this->CreateRawCanvas($aWidth,$aHeight); + // Set canvas color (will also be the background color for a + // a pallett image + $this->SetColor($this->canvascolor); + $this->FilledRectangle(0,0,$aWidth,$aHeight); + + return $old ; + } + + function CopyCanvasH($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY,$aWidth,$aHeight,$aw=-1,$ah=-1) { + if( $aw === -1 ) { + $aw = $aWidth; + $ah = $aHeight; + $f = 'imagecopyresized'; + } + else { + $f = 'imagecopyresampled'; + } + $f($aToHdl,$aFromHdl,$aToX,$aToY,$aFromX,$aFromY, $aWidth,$aHeight,$aw,$ah); + } + + function Copy($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1) { + $this->CopyCanvasH($this->img,$fromImg,$toX,$toY,$fromX,$fromY, + $toWidth,$toHeight,$fromWidth,$fromHeight); + } + + function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { + if( $aMix == 100 ) { + $this->CopyCanvasH($this->img,$fromImg, + $toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight); + } + else { + if( ($fromWidth != -1 && ($fromWidth != $toWidth)) || + ($fromHeight != -1 && ($fromHeight != $fromHeight)) ) { + // Create a new canvas that will hold the re-scaled original from image + if( $toWidth <= 1 || $toHeight <= 1 ) { + JpGraphError::RaiseL(25083);//('Illegal image size when copying image. Size for copied to image is 1 pixel or less.'); + } + if( USE_TRUECOLOR ) { + $tmpimg = @imagecreatetruecolor($toWidth, $toHeight); + } else { + $tmpimg = @imagecreate($toWidth, $toHeight); + } + if( $tmpimg < 1 ) { + JpGraphError::RaiseL(25084);//('Failed to create temporary GD canvas. Out of memory ?'); + } + $this->CopyCanvasH($tmpimg,$fromImg,0,0,0,0, + $toWidth,$toHeight,$fromWidth,$fromHeight); + $fromImg = $tmpimg; + } + imagecopymerge($this->img,$fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$aMix); + } + } + + static function GetWidth($aImg=null) { + if( $aImg === null ) + $aImg = $this->img; + return imagesx($aImg); + } + + static function GetHeight($aImg=null) { + if( $aImg === null ) + $aImg = $this->img; + return imagesy($aImg); + } + + static function CreateFromString($aStr) { + $img = imagecreatefromstring($aStr); + if( $img === false ) { + JpGraphError::RaiseL(25085);//('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.'); + } + return $img; + } + + function SetCanvasH($aHdl) { + $this->img = $aHdl; + $this->rgb->img = $aHdl; + } + + function SetCanvasColor($aColor) { + $this->canvascolor = $aColor ; + } + + function SetAlphaBlending($aFlg=true) { + ImageAlphaBlending($this->img,$aFlg); + } + + + function SetAutoMargin() { + GLOBAL $gJpgBrandTiming; + $min_bm=5; + /* + if( $gJpgBrandTiming ) + $min_bm=15; + */ + $lm = min(40,$this->width/7); + $rm = min(20,$this->width/10); + $tm = max(5,$this->height/7); + $bm = max($min_bm,$this->height/7); + $this->SetMargin($lm,$rm,$tm,$bm); + } + + + //--------------- + // PUBLIC METHODS + + function SetFont($family,$style=FS_NORMAL,$size=10) { + $this->font_family=$family; + $this->font_style=$style; + $this->font_size=$size; + $this->font_file=''; + if( ($this->font_family==FF_FONT1 || $this->font_family==FF_FONT2) && $this->font_style==FS_BOLD ){ + ++$this->font_family; + } + if( $this->font_family > FF_FONT2+1 ) { // A TTF font so get the font file + + // Check that this PHP has support for TTF fonts + if( !function_exists('imagettfbbox') ) { + JpGraphError::RaiseL(25087);//('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.'); + } + $this->font_file = $this->ttf->File($this->font_family,$this->font_style); + } + } + + // Get the specific height for a text string + function GetTextHeight($txt="",$angle=0) { + $tmp = split("\n",$txt); + $n = count($tmp); + $m=0; + for($i=0; $i< $n; ++$i) + $m = max($m,strlen($tmp[$i])); + + if( $this->font_family <= FF_FONT2+1 ) { + if( $angle==0 ) { + $h = imagefontheight($this->font_family); + if( $h === false ) { + JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); + } + + return $n*$h; + } + else { + $w = @imagefontwidth($this->font_family); + if( $w === false ) { + JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); + } + + return $m*$w; + } + } + else { + $bbox = $this->GetTTFBBox($txt,$angle); + return $bbox[1]-$bbox[5]; + } + } + + // Estimate font height + function GetFontHeight($angle=0) { + $txt = "XOMg"; + return $this->GetTextHeight($txt,$angle); + } + + // Approximate font width with width of letter "O" + function GetFontWidth($angle=0) { + $txt = 'O'; + return $this->GetTextWidth($txt,$angle); + } + + // Get actual width of text in absolute pixels + function GetTextWidth($txt,$angle=0) { + + $tmp = split("\n",$txt); + $n = count($tmp); + if( $this->font_family <= FF_FONT2+1 ) { + + $m=0; + for($i=0; $i < $n; ++$i) { + $l=strlen($tmp[$i]); + if( $l > $m ) { + $m = $l; + } + } + + if( $angle==0 ) { + $w = @imagefontwidth($this->font_family); + if( $w === false ) { + JpGraphError::RaiseL(25088);//('You have a misconfigured GD font support. The call to imagefontwidth() fails.'); + } + return $m*$w; + } + else { + // 90 degrees internal so height becomes width + $h = @imagefontheight($this->font_family); + if( $h === false ) { + JpGraphError::RaiseL(25089);//('You have a misconfigured GD font support. The call to imagefontheight() fails.'); + } + return $n*$h; + } + } + else { + // For TTF fonts we must walk through a lines and find the + // widest one which we use as the width of the multi-line + // paragraph + $m=0; + for( $i=0; $i < $n; ++$i ) { + $bbox = $this->GetTTFBBox($tmp[$i],$angle); + $mm = $bbox[2] - $bbox[0]; + if( $mm > $m ) + $m = $mm; + } + return $m; + } + } + + // Draw text with a box around it + function StrokeBoxedText($x,$y,$txt,$dir=0,$fcolor="white",$bcolor="black", + $shadowcolor=false,$paragraph_align="left", + $xmarg=6,$ymarg=4,$cornerradius=0,$dropwidth=3) { + + if( !is_numeric($dir) ) { + if( $dir=="h" ) $dir=0; + elseif( $dir=="v" ) $dir=90; + else JpGraphError::RaiseL(25090,$dir);//(" Unknown direction specified in call to StrokeBoxedText() [$dir]"); + } + + if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { + $width=$this->GetTextWidth($txt,$dir) ; + $height=$this->GetTextHeight($txt,$dir) ; + } + else { + $width=$this->GetBBoxWidth($txt,$dir) ; + $height=$this->GetBBoxHeight($txt,$dir) ; + } + + $height += 2*$ymarg; + $width += 2*$xmarg; + + if( $this->text_halign=="right" ) $x -= $width; + elseif( $this->text_halign=="center" ) $x -= $width/2; + if( $this->text_valign=="bottom" ) $y -= $height; + elseif( $this->text_valign=="center" ) $y -= $height/2; + + $olda = $this->SetAngle(0); + + if( $shadowcolor ) { + $this->PushColor($shadowcolor); + $this->FilledRoundedRectangle($x-$xmarg+$dropwidth,$y-$ymarg+$dropwidth, + $x+$width+$dropwidth,$y+$height-$ymarg+$dropwidth, + $cornerradius); + $this->PopColor(); + $this->PushColor($fcolor); + $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg, + $x+$width,$y+$height-$ymarg, + $cornerradius); + $this->PopColor(); + $this->PushColor($bcolor); + $this->RoundedRectangle($x-$xmarg,$y-$ymarg, + $x+$width,$y+$height-$ymarg,$cornerradius); + $this->PopColor(); + } + else { + if( $fcolor ) { + $oc=$this->current_color; + $this->SetColor($fcolor); + $this->FilledRoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); + $this->current_color=$oc; + } + if( $bcolor ) { + $oc=$this->current_color; + $this->SetColor($bcolor); + $this->RoundedRectangle($x-$xmarg,$y-$ymarg,$x+$width,$y+$height-$ymarg,$cornerradius); + $this->current_color=$oc; + } + } + + $h=$this->text_halign; + $v=$this->text_valign; + $this->SetTextAlign("left","top"); + $this->StrokeText($x, $y, $txt, $dir, $paragraph_align); + $bb = array($x-$xmarg,$y+$height-$ymarg,$x+$width,$y+$height-$ymarg, + $x+$width,$y-$ymarg,$x-$xmarg,$y-$ymarg); + $this->SetTextAlign($h,$v); + + $this->SetAngle($olda); + + return $bb; + } + + // Set text alignment + function SetTextAlign($halign,$valign="bottom") { + $this->text_halign=$halign; + $this->text_valign=$valign; + } + + + function _StrokeBuiltinFont($x,$y,$txt,$dir=0,$paragraph_align="left",&$aBoundingBox,$aDebug=false) { + + if( is_numeric($dir) && $dir!=90 && $dir!=0) + JpGraphError::RaiseL(25091);//(" Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead."); + + $h=$this->GetTextHeight($txt); + $fh=$this->GetFontHeight(); + $w=$this->GetTextWidth($txt); + + if( $this->text_halign=="right") + $x -= $dir==0 ? $w : $h; + elseif( $this->text_halign=="center" ) { + // For center we subtract 1 pixel since this makes the middle + // be prefectly in the middle + $x -= $dir==0 ? $w/2-1 : $h/2; + } + if( $this->text_valign=="top" ) + $y += $dir==0 ? $h : $w; + elseif( $this->text_valign=="center" ) + $y += $dir==0 ? $h/2 : $w/2; + + if( $dir==90 ) { + imagestringup($this->img,$this->font_family,$x,$y,$txt,$this->current_color); + $aBoundingBox = array(round($x),round($y),round($x),round($y-$w),round($x+$h),round($y-$w),round($x+$h),round($y)); + if( $aDebug ) { + // Draw bounding box + $this->PushColor('green'); + $this->Polygon($aBoundingBox,true); + $this->PopColor(); + } + } + else { + if( ereg("\n",$txt) ) { + $tmp = split("\n",$txt); + for($i=0; $i < count($tmp); ++$i) { + $w1 = $this->GetTextWidth($tmp[$i]); + if( $paragraph_align=="left" ) { + imagestring($this->img,$this->font_family,$x,$y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + } + elseif( $paragraph_align=="right" ) { + imagestring($this->img,$this->font_family,$x+($w-$w1), + $y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + } + else { + imagestring($this->img,$this->font_family,$x+$w/2-$w1/2, + $y-$h+1+$i*$fh,$tmp[$i],$this->current_color); + } + } + } + else { + //Put the text + imagestring($this->img,$this->font_family,$x,$y-$h+1,$txt,$this->current_color); + } + if( $aDebug ) { + // Draw the bounding rectangle and the bounding box + $p1 = array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); + + // Draw bounding box + $this->PushColor('green'); + $this->Polygon($p1,true); + $this->PopColor(); + + } + $aBoundingBox=array(round($x),round($y),round($x),round($y-$h),round($x+$w),round($y-$h),round($x+$w),round($y)); + } + } + + function AddTxtCR($aTxt) { + // If the user has just specified a '\n' + // instead of '\n\t' we have to add '\r' since + // the width will be too muchy otherwise since when + // we print we stroke the individually lines by hand. + $e = explode("\n",$aTxt); + $n = count($e); + for($i=0; $i<$n; ++$i) { + $e[$i]=str_replace("\r","",$e[$i]); + } + return implode("\n\r",$e); + } + + function GetTTFBBox($aTxt,$aAngle=0) { + $bbox = @ImageTTFBBox($this->font_size,$aAngle,$this->font_file,$aTxt); + if( $bbox === false ) { + JpGraphError::RaiseL(25092,$this->font_file); +//("There is either a configuration problem with TrueType or a problem reading font file (".$this->font_file."). Make sure file exists and is in a readable place for the HTTP process. (If 'basedir' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try uppgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library."); + } + return $bbox; + } + + function GetBBoxTTF($aTxt,$aAngle=0) { + // Normalize the bounding box to become a minimum + // enscribing rectangle + + $aTxt = $this->AddTxtCR($aTxt); + + if( !is_readable($this->font_file) ) { + JpGraphError::RaiseL(25093,$this->font_file); +//('Can not read font file ('.$this->font_file.') in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.'); + } + $bbox = $this->GetTTFBBox($aTxt,$aAngle); + + if( $aAngle==0 ) + return $bbox; + if( $aAngle >= 0 ) { + if( $aAngle <= 90 ) { //<=0 + $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], + $bbox[2],$bbox[5],$bbox[6],$bbox[5]); + } + elseif( $aAngle <= 180 ) { //<= 2 + $bbox = array($bbox[4],$bbox[7],$bbox[0],$bbox[7], + $bbox[0],$bbox[3],$bbox[4],$bbox[3]); + } + elseif( $aAngle <= 270 ) { //<= 3 + $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], + $bbox[6],$bbox[1],$bbox[2],$bbox[1]); + } + else { + $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], + $bbox[4],$bbox[7],$bbox[0],$bbox[7]); + } + } + elseif( $aAngle < 0 ) { + if( $aAngle <= -270 ) { // <= -3 + $bbox = array($bbox[6],$bbox[1],$bbox[2],$bbox[1], + $bbox[2],$bbox[5],$bbox[6],$bbox[5]); + } + elseif( $aAngle <= -180 ) { // <= -2 + $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], + $bbox[4],$bbox[7],$bbox[0],$bbox[7]); + } + elseif( $aAngle <= -90 ) { // <= -1 + $bbox = array($bbox[2],$bbox[5],$bbox[6],$bbox[5], + $bbox[6],$bbox[1],$bbox[2],$bbox[1]); + } + else { + $bbox = array($bbox[0],$bbox[3],$bbox[4],$bbox[3], + $bbox[4],$bbox[7],$bbox[0],$bbox[7]); + } + } + return $bbox; + } + + function GetBBoxHeight($aTxt,$aAngle=0) { + $box = $this->GetBBoxTTF($aTxt,$aAngle); + return $box[1]-$box[7]+1; + } + + function GetBBoxWidth($aTxt,$aAngle=0) { + $box = $this->GetBBoxTTF($aTxt,$aAngle); + return $box[2]-$box[0]+1; + } + + function _StrokeTTF($x,$y,$txt,$dir=0,$paragraph_align="left",&$aBoundingBox,$debug=false) { + + // Setupo default inter line margin for paragraphs to + // 25% of the font height. + $ConstLineSpacing = 0.25 ; + + // Remember the anchor point before adjustment + if( $debug ) { + $ox=$x; + $oy=$y; + } + + if( !ereg("\n",$txt) || ($dir>0 && ereg("\n",$txt)) ) { + // Format a single line + + $txt = $this->AddTxtCR($txt); + + $bbox=$this->GetBBoxTTF($txt,$dir); + + // Align x,y ot lower left corner of bbox + $x -= $bbox[0]; + $y -= $bbox[1]; + + // Note to self: "topanchor" is deprecated after we changed the + // bopunding box stuff. + if( $this->text_halign=="right" || $this->text_halign=="topanchor" ) + $x -= $bbox[2]-$bbox[0]; + elseif( $this->text_halign=="center" ) $x -= ($bbox[2]-$bbox[0])/2; + + if( $this->text_valign=="top" ) $y += abs($bbox[5])+$bbox[1]; + elseif( $this->text_valign=="center" ) $y -= ($bbox[5]-$bbox[1])/2; + + ImageTTFText ($this->img, $this->font_size, $dir, $x, $y, + $this->current_color,$this->font_file,$txt); + + // Calculate and return the co-ordinates for the bounding box + $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$txt); + $p1 = array(); + + + for($i=0; $i < 4; ++$i) { + $p1[] = round($box[$i*2]+$x); + $p1[] = round($box[$i*2+1]+$y); + } + $aBoundingBox = $p1; + + // Debugging code to highlight the bonding box and bounding rectangle + // For text at 0 degrees the bounding box and bounding rectangle are the + // same + if( $debug ) { + // Draw the bounding rectangle and the bounding box + $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$txt); + $p = array(); + $p1 = array(); + for($i=0; $i < 4; ++$i) { + $p[] = $bbox[$i*2]+$x; + $p[] = $bbox[$i*2+1]+$y; + $p1[] = $box[$i*2]+$x; + $p1[] = $box[$i*2+1]+$y; + } + + // Draw bounding box + $this->PushColor('green'); + $this->Polygon($p1,true); + $this->PopColor(); + + // Draw bounding rectangle + $this->PushColor('darkgreen'); + $this->Polygon($p,true); + $this->PopColor(); + + // Draw a cross at the anchor point + $this->PushColor('red'); + $this->Line($ox-15,$oy,$ox+15,$oy); + $this->Line($ox,$oy-15,$ox,$oy+15); + $this->PopColor(); + } + } + else { + // Format a text paragraph + $fh=$this->GetFontHeight(); + + // Line margin is 25% of font height + $linemargin=round($fh*$ConstLineSpacing); + $fh += $linemargin; + $w=$this->GetTextWidth($txt); + + $y -= $linemargin/2; + $tmp = split("\n",$txt); + $nl = count($tmp); + $h = $nl * $fh; + + if( $this->text_halign=="right") + $x -= $dir==0 ? $w : $h; + elseif( $this->text_halign=="center" ) { + $x -= $dir==0 ? $w/2 : $h/2; + } + + if( $this->text_valign=="top" ) + $y += $dir==0 ? $h : $w; + elseif( $this->text_valign=="center" ) + $y += $dir==0 ? $h/2 : $w/2; + + // Here comes a tricky bit. + // Since we have to give the position for the string at the + // baseline this means thaht text will move slightly up + // and down depending on any of it's character descend below + // the baseline, for example a 'g'. To adjust the Y-position + // we therefore adjust the text with the baseline Y-offset + // as used for the current font and size. This will keep the + // baseline at a fixed positoned disregarding the actual + // characters in the string. + $standardbox = $this->GetTTFBBox('Gg',$dir); + $yadj = $standardbox[1]; + $xadj = $standardbox[0]; + $aBoundingBox = array(); + for($i=0; $i < $nl; ++$i) { + $wl = $this->GetTextWidth($tmp[$i]); + $bbox = $this->GetTTFBBox($tmp[$i],$dir); + if( $paragraph_align=="left" ) { + $xl = $x; + } + elseif( $paragraph_align=="right" ) { + $xl = $x + ($w-$wl); + } + else { + // Center + $xl = $x + $w/2 - $wl/2 ; + } + + $xl -= $bbox[0]; + $yl = $y - $yadj; + $xl = $xl - $xadj; + ImageTTFText ($this->img, $this->font_size, $dir, + $xl, $yl-($h-$fh)+$fh*$i, + $this->current_color,$this->font_file,$tmp[$i]); + + if( $debug ) { + // Draw the bounding rectangle around each line + $box=@ImageTTFBBox($this->font_size,$dir,$this->font_file,$tmp[$i]); + $p = array(); + for($j=0; $j < 4; ++$j) { + $p[] = $bbox[$j*2]+$xl; + $p[] = $bbox[$j*2+1]+$yl-($h-$fh)+$fh*$i; + } + + // Draw bounding rectangle + $this->PushColor('darkgreen'); + $this->Polygon($p,true); + $this->PopColor(); + } + } + + // Get the bounding box + $bbox = $this->GetBBoxTTF($txt,$dir); + for($j=0; $j < 4; ++$j) { + $bbox[$j*2]+= round($x); + $bbox[$j*2+1]+= round($y - ($h-$fh) - $yadj); + } + $aBoundingBox = $bbox; + + if( $debug ) { + // Draw a cross at the anchor point + $this->PushColor('red'); + $this->Line($ox-25,$oy,$ox+25,$oy); + $this->Line($ox,$oy-25,$ox,$oy+25); + $this->PopColor(); + } + + } + } + + function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { + + $x = round($x); + $y = round($y); + + // Do special language encoding + $txt = $this->langconv->Convert($txt,$this->font_family); + + if( !is_numeric($dir) ) + JpGraphError::RaiseL(25094);//(" Direction for text most be given as an angle between 0 and 90."); + + if( $this->font_family >= FF_FONT0 && $this->font_family <= FF_FONT2+1) { + $this->_StrokeBuiltinFont($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); + } + elseif($this->font_family >= _FIRST_FONT && $this->font_family <= _LAST_FONT) { + $this->_StrokeTTF($x,$y,$txt,$dir,$paragraph_align,$boundingbox,$debug); + } + else + JpGraphError::RaiseL(25095);//(" Unknown font font family specification. "); + return $boundingbox; + } + + function SetMargin($lm,$rm,$tm,$bm) { + $this->left_margin=$lm; + $this->right_margin=$rm; + $this->top_margin=$tm; + $this->bottom_margin=$bm; + $this->plotwidth=$this->width - $this->left_margin-$this->right_margin ; + $this->plotheight=$this->height - $this->top_margin-$this->bottom_margin ; + if( $this->width > 0 && $this->height > 0 ) { + if( $this->plotwidth < 0 || $this->plotheight < 0 ) + JpGraphError::raise("To small plot area. ($lm,$rm,$tm,$bm : $this->plotwidth x $this->plotheight). With the given image size and margins there is to little space left for the plot. Increase the plot size or reduce the margins."); + } + } + + function SetTransparent($color) { + imagecolortransparent ($this->img,$this->rgb->allocate($color)); + } + + function SetColor($color,$aAlpha=0) { + $this->current_color_name = $color; + $this->current_color=$this->rgb->allocate($color,$aAlpha); + if( $this->current_color == -1 ) { + $tc=imagecolorstotal($this->img); + JpGraphError::RaiseL(25096); +//("Can't allocate any more colors. Image has already allocated maximum of $tc colors. This might happen if you have anti-aliasing turned on together with a background image or perhaps gradient fill since this requires many, many colors. Try to turn off anti-aliasing. If there is still a problem try downgrading the quality of the background image to use a smaller pallete to leave some entries for your graphs. You should try to limit the number of colors in your background image to 64. If there is still problem set the constant DEFINE(\"USE_APPROX_COLORS\",true); in jpgraph.php This will use approximative colors when the palette is full. Unfortunately there is not much JpGraph can do about this since the palette size is a limitation of current graphic format and what the underlying GD library suppports."); + } + return $this->current_color; + } + + function PushColor($color) { + if( $color != "" ) { + $this->colorstack[$this->colorstackidx]=$this->current_color_name; + $this->colorstack[$this->colorstackidx+1]=$this->current_color; + $this->colorstackidx+=2; + $this->SetColor($color); + } + else { + JpGraphError::RaiseL(25097);//("Color specified as empty string in PushColor()."); + } + } + + function PopColor() { + if($this->colorstackidx<1) + JpGraphError::RaiseL(25098);//(" Negative Color stack index. Unmatched call to PopColor()"); + $this->current_color=$this->colorstack[--$this->colorstackidx]; + $this->current_color_name=$this->colorstack[--$this->colorstackidx]; + } + + + function SetLineWeight($weight) { + imagesetthickness($this->img,$weight); + $this->line_weight = $weight; + } + + function SetStartPoint($x,$y) { + $this->lastx=round($x); + $this->lasty=round($y); + } + + function Arc($cx,$cy,$w,$h,$s,$e) { + // GD Arc doesn't like negative angles + while( $s < 0) $s += 360; + while( $e < 0) $e += 360; + + imagearc($this->img,round($cx),round($cy),round($w),round($h), + $s,$e,$this->current_color); + } + + function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') { + while( $s < 0 ) $s += 360; + while( $e < 0 ) $e += 360; + if( $style=='' ) + $style=IMG_ARC_PIE; + if( abs($s-$e) > 0.001 ) { + imagefilledarc($this->img,round($xc),round($yc),round($w),round($h), + round($s),round($e),$this->current_color,$style); + } + } + + function FilledCakeSlice($cx,$cy,$w,$h,$s,$e) { + $this->CakeSlice($cx,$cy,$w,$h,$s,$e,$this->current_color_name); + } + + function CakeSlice($xc,$yc,$w,$h,$s,$e,$fillcolor="",$arccolor="") { + $s = round($s); $e = round($e); + $w = round($w); $h = round($h); + $xc = round($xc); $yc = round($yc); + $this->PushColor($fillcolor); + $this->FilledArc($xc,$yc,2*$w,2*$h,$s,$e); + $this->PopColor(); + if( $arccolor != "" ) { + $this->PushColor($arccolor); + // We add 2 pixels to make the Arc() better aligned with + // the filled arc. + imagefilledarc($this->img,$xc,$yc,2*$w,2*$h,$s,$e,$this->current_color,IMG_ARC_NOFILL | IMG_ARC_EDGED ) ; + $this->PopColor(); + } + } + + function Ellipse($xc,$yc,$w,$h) { + $this->Arc($xc,$yc,$w,$h,0,360); + } + + function Circle($xc,$yc,$r) { + imageellipse($this->img,round($xc),round($yc),$r*2,$r*2,$this->current_color); + } + + function FilledCircle($xc,$yc,$r) { + imagefilledellipse($this->img,round($xc),round($yc),2*$r,2*$r,$this->current_color); + } + + // Linear Color InterPolation + function lip($f,$t,$p) { + $p = round($p,1); + $r = $f[0] + ($t[0]-$f[0])*$p; + $g = $f[1] + ($t[1]-$f[1])*$p; + $b = $f[2] + ($t[2]-$f[2])*$p; + return array($r,$g,$b); + } + + // Set line style dashed, dotted etc + function SetLineStyle($s) { + if( is_numeric($s) ) { + if( $s<1 || $s>4 ) + JpGraphError::RaiseL(25101,$s);//(" Illegal numeric argument to SetLineStyle(): ($s)"); + } + elseif( is_string($s) ) { + if( $s == "solid" ) $s=1; + elseif( $s == "dotted" ) $s=2; + elseif( $s == "dashed" ) $s=3; + elseif( $s == "longdashed" ) $s=4; + else JpGraphError::RaiseL(25102,$s);//(" Illegal string argument to SetLineStyle(): $s"); + } + else JpGraphError::RaiseL(25103,$s);//(" Illegal argument to SetLineStyle $s"); + $this->line_style=$s; + } + + // Same as Line but take the line_style into account + function StyleLine($x1,$y1,$x2,$y2) { + if( $this->line_weight <= 0 ) + return; + + switch( $this->line_style ) { + case 1:// Solid + $this->Line($x1,$y1,$x2,$y2); + break; + case 2: // Dotted + $this->DashedLine($x1,$y1,$x2,$y2,1,3); + break; + case 3: // Dashed + $this->DashedLine($x1,$y1,$x2,$y2,2,4); + break; + case 4: // Longdashes + $this->DashedLine($x1,$y1,$x2,$y2,8,6); + break; + default: + JpGraphError::RaiseL(25104,$this->line_style);//(" Unknown line style: $this->line_style "); + break; + } + } + + function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { + + if( $this->line_weight <= 0 ) + return; + + $x1 = round($x1); + $x2 = round($x2); + $y1 = round($y1); + $y2 = round($y2); + + $style = array_fill(0,$dash_length,$this->current_color); + $style = array_pad($style,$dash_length+$dash_space,IMG_COLOR_TRANSPARENT); + imagesetstyle($this->img, $style); + imageline($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED); + $this->lastx=$x2; $this->lasty=$y2; + } + + function Line($x1,$y1,$x2,$y2) { + + if( $this->line_weight <= 0 ) + return; + + $x1 = round($x1); + $x2 = round($x2); + $y1 = round($y1); + $y2 = round($y2); + + imageline($this->img,$x1,$y1,$x2,$y2,$this->current_color); + $this->lastx=$x2; $this->lasty=$y2; + } + + function Polygon($p,$closed=FALSE,$fast=FALSE) { + + if( $this->line_weight <= 0 ) + return; + + $n=count($p); + $oldx = $p[0]; + $oldy = $p[1]; + if( $fast ) { + for( $i=2; $i < $n; $i+=2 ) { + imageline($this->img,$oldx,$oldy,$p[$i],$p[$i+1],$this->current_color); + $oldx = $p[$i]; + $oldy = $p[$i+1]; + } + if( $closed ) { + imageline($this->img,$p[$n*2-2],$p[$n*2-1],$p[0],$p[1],$this->current_color); + } + } + else { + for( $i=2; $i < $n; $i+=2 ) { + $this->StyleLine($oldx,$oldy,$p[$i],$p[$i+1]); + $oldx = $p[$i]; + $oldy = $p[$i+1]; + } + if( $closed ) + $this->StyleLine($oldx,$oldy,$p[0],$p[1]); + } + } + + function FilledPolygon($pts) { + $n=count($pts); + if( $n == 0 ) { + JpGraphError::RaiseL(25105);//('NULL data specified for a filled polygon. Check that your data is not NULL.'); + } + for($i=0; $i < $n; ++$i) + $pts[$i] = round($pts[$i]); + imagefilledpolygon($this->img,$pts,count($pts)/2,$this->current_color); + } + + function Rectangle($xl,$yu,$xr,$yl) { + $this->Polygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl,$xl,$yu)); + } + + function FilledRectangle($xl,$yu,$xr,$yl) { + $this->FilledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl)); + } + + function FilledRectangle2($xl,$yu,$xr,$yl,$color1,$color2,$style=1) { + // Fill a rectangle with lines of two colors + if( $style===1 ) { + // Horizontal stripe + if( $yl < $yu ) { + $t = $yl; $yl=$yu; $yu=$t; + } + for( $y=$yu; $y <= $yl; ++$y) { + $this->SetColor($color1); + $this->Line($xl,$y,$xr,$y); + ++$y; + $this->SetColor($color2); + $this->Line($xl,$y,$xr,$y); + } + } + else { + if( $xl < $xl ) { + $t = $xl; $xl=$xr; $xr=$t; + } + for( $x=$xl; $x <= $xr; ++$x) { + $this->SetColor($color1); + $this->Line($x,$yu,$x,$yl); + ++$x; + $this->SetColor($color2); + $this->Line($x,$yu,$x,$yl); + } + } + } + + function ShadowRectangle($xl,$yu,$xr,$yl,$fcolor=false,$shadow_width=3,$shadow_color=array(102,102,102)) { + // This is complicated by the fact that we must also handle the case where + // the reactangle has no fill color + $this->PushColor($shadow_color); + $this->FilledRectangle($xr-$shadow_width,$yu+$shadow_width,$xr,$yl-$shadow_width-1); + $this->FilledRectangle($xl+$shadow_width,$yl-$shadow_width,$xr,$yl); + //$this->FilledRectangle($xl+$shadow_width,$yu+$shadow_width,$xr,$yl); + $this->PopColor(); + if( $fcolor==false ) + $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); + else { + $this->PushColor($fcolor); + $this->FilledRectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); + $this->PopColor(); + $this->Rectangle($xl,$yu,$xr-$shadow_width-1,$yl-$shadow_width-1); + } + } + + function FilledRoundedRectangle($xt,$yt,$xr,$yl,$r=5) { + if( $r==0 ) { + $this->FilledRectangle($xt,$yt,$xr,$yl); + return; + } + + // To avoid overlapping fillings (which will look strange + // when alphablending is enabled) we have no choice but + // to fill the five distinct areas one by one. + + // Center square + $this->FilledRectangle($xt+$r,$yt+$r,$xr-$r,$yl-$r); + // Top band + $this->FilledRectangle($xt+$r,$yt,$xr-$r,$yt+$r-1); + // Bottom band + $this->FilledRectangle($xt+$r,$yl-$r+1,$xr-$r,$yl); + // Left band + $this->FilledRectangle($xt,$yt+$r+1,$xt+$r-1,$yl-$r); + // Right band + $this->FilledRectangle($xr-$r+1,$yt+$r,$xr,$yl-$r); + + // Topleft & Topright arc + $this->FilledArc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->FilledArc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Bottomleft & Bottom right arc + $this->FilledArc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->FilledArc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + } + + function RoundedRectangle($xt,$yt,$xr,$yl,$r=5) { + + if( $r==0 ) { + $this->Rectangle($xt,$yt,$xr,$yl); + return; + } + + // Top & Bottom line + $this->Line($xt+$r,$yt,$xr-$r,$yt); + $this->Line($xt+$r,$yl,$xr-$r,$yl); + + // Left & Right line + $this->Line($xt,$yt+$r,$xt,$yl-$r); + $this->Line($xr,$yt+$r,$xr,$yl-$r); + + // Topleft & Topright arc + $this->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Bottomleft & Bottomright arc + $this->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + } + + function FilledBevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='darkgray@0.4') { + $this->FilledRectangle($x1,$y1,$x2,$y2); + $this->Bevel($x1,$y1,$x2,$y2,$depth,$color1,$color2); + } + + function Bevel($x1,$y1,$x2,$y2,$depth=2,$color1='white@0.4',$color2='black@0.5') { + $this->PushColor($color1); + for( $i=0; $i < $depth; ++$i ) { + $this->Line($x1+$i,$y1+$i,$x1+$i,$y2-$i); + $this->Line($x1+$i,$y1+$i,$x2-$i,$y1+$i); + } + $this->PopColor(); + + $this->PushColor($color2); + for( $i=0; $i < $depth; ++$i ) { + $this->Line($x1+$i,$y2-$i,$x2-$i,$y2-$i); + $this->Line($x2-$i,$y1+$i,$x2-$i,$y2-$i-1); + } + $this->PopColor(); + } + + function StyleLineTo($x,$y) { + $this->StyleLine($this->lastx,$this->lasty,$x,$y); + $this->lastx=$x; + $this->lasty=$y; + } + + function LineTo($x,$y) { + $this->Line($this->lastx,$this->lasty,$x,$y); + $this->lastx=$x; + $this->lasty=$y; + } + + function Point($x,$y) { + imagesetpixel($this->img,round($x),round($y),$this->current_color); + } + + function Fill($x,$y) { + imagefill($this->img,round($x),round($y),$this->current_color); + } + + function FillToBorder($x,$y,$aBordColor) { + $bc = $this->rgb->allocate($aBordColor); + if( $bc == -1 ) { + JpGraphError::RaiseL(25106);//('Image::FillToBorder : Can not allocate more colors'); + } + imagefilltoborder($this->img,round($x),round($y),$bc,$this->current_color); + } + + function SetExpired($aFlg=true) { + $this->expired = $aFlg; + } + + // Generate image header + function Headers() { + + // In case we are running from the command line with the client version of + // PHP we can't send any headers. + $sapi = php_sapi_name(); + if( $sapi == 'cli' ) + return; + + if( headers_sent($file,$lineno) ) { + $file=basename($file); + $t = new ErrMsgText(); + $msg = $t->Get(10,$file,$lineno); + die($msg); + } + + if ($this->expired) { + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); + header("Cache-Control: no-cache, must-revalidate"); + header("Pragma: no-cache"); + } + header("Content-type: image/$this->img_format"); + } + + // Adjust image quality for formats that allow this + function SetQuality($q) { + $this->quality = $q; + } + + // Stream image to browser or to file + function Stream($aFile="") { + $func="image".$this->img_format; + if( $this->img_format=="jpeg" && $this->quality != null ) { + $res = @$func($this->img,$aFile,$this->quality); + } + else { + if( $aFile != "" ) { + $res = @$func($this->img,$aFile); + if( !$res ) + JpGraphError::RaiseL(25107,$aFile);//("Can't write to file '$aFile'. Check that the process running PHP has enough permission."); + } + else { + $res = @$func($this->img); + if( !$res ) + JpGraphError::RaiseL(25108);//("Can't stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP."); + + } + } + } + + // Clear resource tide up by image + function Destroy() { + imagedestroy($this->img); + } + + // Specify image format. Note depending on your installation + // of PHP not all formats may be supported. + function SetImgFormat($aFormat,$aQuality=75) { + $this->quality = $aQuality; + $aFormat = strtolower($aFormat); + $tst = true; + $supported = imagetypes(); + if( $aFormat=="auto" ) { + if( $supported & IMG_PNG ) + $this->img_format="png"; + elseif( $supported & IMG_JPG ) + $this->img_format="jpeg"; + elseif( $supported & IMG_GIF ) + $this->img_format="gif"; + elseif( $supported & IMG_WBMP ) + $this->img_format="wbmp"; + elseif( $supported & IMG_XPM ) + $this->img_format="xpm"; + else + JpGraphError::RaiseL(25109);//("Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details."); + + return true; + } + else { + if( $aFormat=="jpeg" || $aFormat=="png" || $aFormat=="gif" ) { + if( $aFormat=="jpeg" && !($supported & IMG_JPG) ) + $tst=false; + elseif( $aFormat=="png" && !($supported & IMG_PNG) ) + $tst=false; + elseif( $aFormat=="gif" && !($supported & IMG_GIF) ) + $tst=false; + elseif( $aFormat=="wbmp" && !($supported & IMG_WBMP) ) + $tst=false; + elseif( $aFormat=="xpm" && !($supported & IMG_XPM) ) + $tst=false; + else { + $this->img_format=$aFormat; + return true; + } + } + else + $tst=false; + if( !$tst ) + JpGraphError::RaiseL(25110,$aFormat);//(" Your PHP installation does not support the chosen graphic format: $aFormat"); + } + } +} // CLASS + +//=================================================== +// CLASS RotImage +// Description: Exactly as Image but draws the image at +// a specified angle around a specified rotation point. +//=================================================== +class RotImage extends Image { + public $a=0; + public $dx=0,$dy=0,$transx=0,$transy=0; + private $m=array(); + + function RotImage($aWidth,$aHeight,$a=0,$aFormat=DEFAULT_GFORMAT,$aSetAutoMargin=true) { + $this->Image($aWidth,$aHeight,$aFormat,$aSetAutoMargin); + $this->dx=$this->left_margin+$this->plotwidth/2; + $this->dy=$this->top_margin+$this->plotheight/2; + $this->SetAngle($a); + } + + function SetCenter($dx,$dy) { + $old_dx = $this->dx; + $old_dy = $this->dy; + $this->dx=$dx; + $this->dy=$dy; + $this->SetAngle($this->a); + return array($old_dx,$old_dy); + } + + function SetTranslation($dx,$dy) { + $old = array($this->transx,$this->transy); + $this->transx = $dx; + $this->transy = $dy; + return $old; + } + + function UpdateRotMatrice() { + $a = $this->a; + $a *= M_PI/180; + $sa=sin($a); $ca=cos($a); + // Create the rotation matrix + $this->m[0][0] = $ca; + $this->m[0][1] = -$sa; + $this->m[0][2] = $this->dx*(1-$ca) + $sa*$this->dy ; + $this->m[1][0] = $sa; + $this->m[1][1] = $ca; + $this->m[1][2] = $this->dy*(1-$ca) - $sa*$this->dx ; + } + + function SetAngle($a) { + $tmp = $this->a; + $this->a = $a; + $this->UpdateRotMatrice(); + return $tmp; + } + + function Circle($xc,$yc,$r) { + list($xc,$yc) = $this->Rotate($xc,$yc); + parent::Circle($xc,$yc,$r); + } + + function FilledCircle($xc,$yc,$r) { + list($xc,$yc) = $this->Rotate($xc,$yc); + parent::FilledCircle($xc,$yc,$r); + } + + + function Arc($xc,$yc,$w,$h,$s,$e) { + list($xc,$yc) = $this->Rotate($xc,$yc); + $s += $this->a; + $e += $this->a; + parent::Arc($xc,$yc,$w,$h,$s,$e); + } + + function FilledArc($xc,$yc,$w,$h,$s,$e,$style='') { + list($xc,$yc) = $this->Rotate($xc,$yc); + $s += $this->a; + $e += $this->a; + parent::FilledArc($xc,$yc,$w,$h,$s,$e); + } + + function SetMargin($lm,$rm,$tm,$bm) { + parent::SetMargin($lm,$rm,$tm,$bm); + $this->dx=$this->left_margin+$this->plotwidth/2; + $this->dy=$this->top_margin+$this->plotheight/2; + $this->UpdateRotMatrice(); + } + + function Rotate($x,$y) { + // Optimization. Ignore rotation if Angle==0 || Angle==360 + if( $this->a == 0 || $this->a == 360 ) { + return array($x + $this->transx, $y + $this->transy ); + } + else { + $x1=round($this->m[0][0]*$x + $this->m[0][1]*$y,1) + $this->m[0][2] + $this->transx; + $y1=round($this->m[1][0]*$x + $this->m[1][1]*$y,1) + $this->m[1][2] + $this->transy; + return array($x1,$y1); + } + } + + function CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth=-1,$fromHeight=-1,$aMix=100) { + list($toX,$toY) = $this->Rotate($toX,$toY); + parent::CopyMerge($fromImg,$toX,$toY,$fromX,$fromY,$toWidth,$toHeight,$fromWidth,$fromHeight,$aMix); + + } + + function ArrRotate($pnts) { + $n = count($pnts)-1; + for($i=0; $i < $n; $i+=2) { + list ($x,$y) = $this->Rotate($pnts[$i],$pnts[$i+1]); + $pnts[$i] = $x; $pnts[$i+1] = $y; + } + return $pnts; + } + + function DashedLine($x1,$y1,$x2,$y2,$dash_length=1,$dash_space=4) { + list($x1,$y1) = $this->Rotate($x1,$y1); + list($x2,$y2) = $this->Rotate($x2,$y2); + parent::DashedLine($x1,$y1,$x2,$y2,$dash_length,$dash_space); + } + + function Line($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->Rotate($x1,$y1); + list($x2,$y2) = $this->Rotate($x2,$y2); + parent::Line($x1,$y1,$x2,$y2); + } + + function Rectangle($x1,$y1,$x2,$y2) { + // Rectangle uses Line() so it will be rotated through that call + parent::Rectangle($x1,$y1,$x2,$y2); + } + + function FilledRectangle($x1,$y1,$x2,$y2) { + if( $y1==$y2 || $x1==$x2 ) + $this->Line($x1,$y1,$x2,$y2); + else + $this->FilledPolygon(array($x1,$y1,$x2,$y1,$x2,$y2,$x1,$y2)); + } + + function Polygon($pnts,$closed=FALSE,$fast=FALSE) { + // Polygon uses Line() so it will be rotated through that call unless + // fast drawing routines are used in which case a rotate is needed + if( $fast ) { + parent::Polygon($this->ArrRotate($pnts)); + } + else + parent::Polygon($pnts,$closed,$fast); + } + + function FilledPolygon($pnts) { + parent::FilledPolygon($this->ArrRotate($pnts)); + } + + function Point($x,$y) { + list($xp,$yp) = $this->Rotate($x,$y); + parent::Point($xp,$yp); + } + + function StrokeText($x,$y,$txt,$dir=0,$paragraph_align="left",$debug=false) { + list($xp,$yp) = $this->Rotate($x,$y); + return parent::StrokeText($xp,$yp,$txt,$dir,$paragraph_align,$debug); + } +} + +//=================================================== +// CLASS ImgStreamCache +// Description: Handle caching of graphs to files +//=================================================== +class ImgStreamCache { + private $cache_dir, $img=null, $timeout=0; // Infinite timeout + //--------------- + // CONSTRUCTOR + function ImgStreamCache($aImg, $aCacheDir=CACHE_DIR) { + $this->img = $aImg; + $this->cache_dir = $aCacheDir; + } + +//--------------- +// PUBLIC METHODS + + // Specify a timeout (in minutes) for the file. If the file is older then the + // timeout value it will be overwritten with a newer version. + // If timeout is set to 0 this is the same as infinite large timeout and if + // timeout is set to -1 this is the same as infinite small timeout + function SetTimeout($aTimeout) { + $this->timeout=$aTimeout; + } + + // Output image to browser and also write it to the cache + function PutAndStream($aImage,$aCacheFileName,$aInline,$aStrokeFileName) { + // Some debugging code to brand the image with numbe of colors + // used + GLOBAL $gJpgBrandTiming; + + if( $gJpgBrandTiming ) { + global $tim; + $t=$tim->Pop()/1000.0; + $c=$aImage->SetColor("black"); + $t=sprintf(BRAND_TIME_FORMAT,round($t,3)); + imagestring($this->img->img,2,5,$this->img->height-20,$t,$c); + } + + // Check if we should stroke the image to an arbitrary file + if( _FORCE_IMGTOFILE ) { + $aStrokeFileName = _FORCE_IMGDIR.GenImgName(); + } + + if( $aStrokeFileName!="" ) { + if( $aStrokeFileName == "auto" ) + $aStrokeFileName = GenImgName(); + if( file_exists($aStrokeFileName) ) { + // Delete the old file + if( !@unlink($aStrokeFileName) ) + JpGraphError::RaiseL(25111,$aStrokeFileName);//(" Can't delete cached image $aStrokeFileName. Permission problem?"); + } + $aImage->Stream($aStrokeFileName); + return; + } + + if( $aCacheFileName != "" && USE_CACHE) { + + $aCacheFileName = $this->cache_dir . $aCacheFileName; + if( file_exists($aCacheFileName) ) { + if( !$aInline ) { + // If we are generating image off-line (just writing to the cache) + // and the file exists and is still valid (no timeout) + // then do nothing, just return. + $diff=time()-filemtime($aCacheFileName); + if( $diff < 0 ) + JpGraphError::RaiseL(25112,$aCacheFileName);//(" Cached imagefile ($aCacheFileName) has file date in the future!!"); + if( $this->timeout>0 && ($diff <= $this->timeout*60) ) + return; + } + if( !@unlink($aCacheFileName) ) + JpGraphError::RaiseL(25113,$aStrokeFileName);//(" Can't delete cached image $aStrokeFileName. Permission problem?"); + $aImage->Stream($aCacheFileName); + } + else { + $this->MakeDirs(dirname($aCacheFileName)); + if( !is_writeable(dirname($aCacheFileName)) ) { + JpGraphError::RaiseL(25114,$aCacheFileName);//('PHP has not enough permissions to write to the cache file '.$aCacheFileName.'. Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.'); + } + $aImage->Stream($aCacheFileName); + } + + $res=true; + // Set group to specified + if( CACHE_FILE_GROUP != "" ) + $res = @chgrp($aCacheFileName,CACHE_FILE_GROUP); + if( CACHE_FILE_MOD != "" ) + $res = @chmod($aCacheFileName,CACHE_FILE_MOD); + if( !$res ) + JpGraphError::RaiseL(25115,$aStrokeFileName);//(" Can't set permission for cached image $aStrokeFileName. Permission problem?"); + + $aImage->Destroy(); + if( $aInline ) { + if ($fh = @fopen($aCacheFileName, "rb") ) { + $this->img->Headers(); + fpassthru($fh); + return; + } + else + JpGraphError::RaiseL(25116,$aFile);//(" Cant open file from cache [$aFile]"); + } + } + elseif( $aInline ) { + $this->img->Headers(); + $aImage->Stream(); + return; + } + } + + // Check if a given image is in cache and in that case + // pass it directly on to web browser. Return false if the + // image file doesn't exist or exists but is to old + function GetAndStream($aCacheFileName) { + $aCacheFileName = $this->cache_dir.$aCacheFileName; + if ( USE_CACHE && file_exists($aCacheFileName) && $this->timeout>=0 ) { + $diff=time()-filemtime($aCacheFileName); + if( $this->timeout>0 && ($diff > $this->timeout*60) ) { + return false; + } + else { + if ($fh = @fopen($aCacheFileName, "rb")) { + $this->img->Headers(); + fpassthru($fh); + return true; + } + else + JpGraphError::RaiseL(25117,$aCacheFileName);//(" Can't open cached image \"$aCacheFileName\" for reading."); + } + } + return false; + } + + //--------------- + // PRIVATE METHODS + // Create all necessary directories in a path + function MakeDirs($aFile) { + $dirs = array(); + while ( !(file_exists($aFile)) ) { + $dirs[] = $aFile; + $aFile = dirname($aFile); + } + for ($i = sizeof($dirs)-1; $i>=0; $i--) { + if(! @mkdir($dirs[$i],0777) ) + JpGraphError::RaiseL(25118,$aFile);//(" Can't create directory $aFile. Make sure PHP has write permission to this directory."); + // We also specify mode here after we have changed group. + // This is necessary if Apache user doesn't belong the + // default group and hence can't specify group permission + // in the previous mkdir() call + if( CACHE_FILE_GROUP != "" ) { + $res=true; + $res =@chgrp($dirs[$i],CACHE_FILE_GROUP); + $res = @chmod($dirs[$i],0777); + if( !$res ) + JpGraphError::RaiseL(25119,$aFile);//(" Can't set permissions for $aFile. Permission problems?"); + } + } + return true; + } +} // CLASS Cache + +//=================================================== +// CLASS Legend +// Description: Responsible for drawing the box containing +// all the legend text for the graph +//=================================================== +DEFINE('_DEFAULT_LPM_SIZE',8); +class Legend { + public $txtcol=array(); + private $color=array(0,0,0); // Default fram color + private $fill_color=array(235,235,235); // Default fill color + private $shadow=true; // Shadow around legend "box" + private $shadow_color='darkgray@0.5'; + private $mark_abs_hsize=_DEFAULT_LPM_SIZE,$mark_abs_vsize=_DEFAULT_LPM_SIZE; + private $xmargin=10,$ymargin=3,$shadow_width=2; + private $xlmargin=2, $ylmargin=''; + private $xpos=0.05, $ypos=0.15, $xabspos=-1, $yabspos=-1; + private $halign="right", $valign="top"; + private $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12; + private $font_color='black'; + private $hide=false,$layout_n=1; + private $weight=1,$frameweight=1; + private $csimareas=''; + private $reverse = false ; +//--------------- +// CONSTRUCTOR + function Legend() { + // Empty + } +//--------------- +// PUBLIC METHODS + function Hide($aHide=true) { + $this->hide=$aHide; + } + + function SetHColMargin($aXMarg) { + $this->xmargin = $aXMarg; + } + + function SetVColMargin($aSpacing) { + $this->ymargin = $aSpacing ; + } + + function SetLeftMargin($aXMarg) { + $this->xlmargin = $aXMarg; + } + + + // Synonym + function SetLineSpacing($aSpacing) { + $this->ymargin = $aSpacing ; + } + + function SetShadow($aShow='gray',$aWidth=2) { + if( is_string($aShow) ) { + $this->shadow_color = $aShow; + $this->shadow=true; + } + else + $this->shadow=$aShow; + $this->shadow_width=$aWidth; + } + + function SetMarkAbsSize($aSize) { + $this->mark_abs_vsize = $aSize ; + $this->mark_abs_hsize = $aSize ; + } + + function SetMarkAbsVSize($aSize) { + $this->mark_abs_vsize = $aSize ; + } + + function SetMarkAbsHSize($aSize) { + $this->mark_abs_hsize = $aSize ; + } + + function SetLineWeight($aWeight) { + $this->weight = $aWeight; + } + + function SetFrameWeight($aWeight) { + $this->frameweight = $aWeight; + } + + function SetLayout($aDirection=LEGEND_VERT) { + $this->layout_n = $aDirection==LEGEND_VERT ? 1 : 99 ; + } + + function SetColumns($aCols) { + $this->layout_n = $aCols ; + } + + function SetReverse($f=true) { + $this->reverse = $f ; + } + + // Set color on frame around box + function SetColor($aFontColor,$aColor='black') { + $this->font_color=$aFontColor; + $this->color=$aColor; + } + + function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { + $this->font_family = $aFamily; + $this->font_style = $aStyle; + $this->font_size = $aSize; + } + + function SetPos($aX,$aY,$aHAlign="right",$aVAlign="top") { + $this->Pos($aX,$aY,$aHAlign,$aVAlign); + } + + function SetAbsPos($aX,$aY,$aHAlign="right",$aVAlign="top") { + $this->xabspos=$aX; + $this->yabspos=$aY; + $this->halign=$aHAlign; + $this->valign=$aVAlign; + } + + + function Pos($aX,$aY,$aHAlign="right",$aVAlign="top") { + if( !($aX<1 && $aY<1) ) + JpGraphError::RaiseL(25120);//(" Position for legend must be given as percentage in range 0-1"); + $this->xpos=$aX; + $this->ypos=$aY; + $this->halign=$aHAlign; + $this->valign=$aVAlign; + } + + function SetFillColor($aColor) { + $this->fill_color=$aColor; + } + + function Add($aTxt,$aColor,$aPlotmark='',$aLinestyle=0,$csimtarget='',$csimalt='',$csimwintarget='') { + $this->txtcol[]=array($aTxt,$aColor,$aPlotmark,$aLinestyle,$csimtarget,$csimalt,$csimwintarget); + } + + function GetCSIMAreas() { + return $this->csimareas; + } + + function Stroke(&$aImg) { + // Constant + $fillBoxFrameWeight=1; + + if( $this->hide ) return; + + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + + if( $this->reverse ) { + $this->txtcol = array_reverse($this->txtcol); + } + + $n=count($this->txtcol); + if( $n == 0 ) return; + + // Find out the max width and height of each column to be able + // to size the legend box. + $numcolumns = ($n > $this->layout_n ? $this->layout_n : $n); + for( $i=0; $i < $numcolumns; ++$i ) { + $colwidth[$i] = $aImg->GetTextWidth($this->txtcol[$i][0]) + + 2*$this->xmargin + 2*$this->mark_abs_hsize; + $colheight[$i] = 0; + } + + // Find our maximum height in each row + $rows = 0 ; $rowheight[0] = 0; + for( $i=0; $i < $n; ++$i ) { + $h = max($this->mark_abs_vsize,$aImg->GetTextHeight($this->txtcol[$i][0]))+$this->ymargin; + if( $i % $numcolumns == 0 ) { + $rows++; + $rowheight[$rows-1] = 0; + } + $rowheight[$rows-1] = max($rowheight[$rows-1],$h); + } + + $abs_height = 0; + for( $i=0; $i < $rows; ++$i ) { + $abs_height += $rowheight[$i] ; + } + + // Make sure that the height is at least as high as mark size + ymargin + $abs_height = max($abs_height,$this->mark_abs_vsize); + + // We add 3 extra pixels height to compensate for the difficult in + // calculating font height + $abs_height += $this->ymargin+3; + + // Find out the maximum width in each column + for( $i=$numcolumns; $i < $n; ++$i ) { + $colwidth[$i % $numcolumns] = max( + $aImg->GetTextWidth($this->txtcol[$i][0])+2*$this->xmargin+2*$this->mark_abs_hsize,$colwidth[$i % $numcolumns]); + } + + // Get the total width + $mtw = 0; + for( $i=0; $i < $numcolumns; ++$i ) { + $mtw += $colwidth[$i] ; + } + + // Find out maximum width we need for legend box + $abs_width = $mtw+$this->xlmargin; + + if( $this->xabspos === -1 && $this->yabspos === -1 ) { + $this->xabspos = $this->xpos*$aImg->width ; + $this->yabspos = $this->ypos*$aImg->height ; + } + + // Positioning of the legend box + if( $this->halign == 'left' ) + $xp = $this->xabspos; + elseif( $this->halign == 'center' ) + $xp = $this->xabspos - $abs_width/2; + else + $xp = $aImg->width - $this->xabspos - $abs_width; + + $yp=$this->yabspos; + if( $this->valign == 'center' ) + $yp-=$abs_height/2; + elseif( $this->valign == 'bottom' ) + $yp-=$abs_height; + + // Stroke legend box + $aImg->SetColor($this->color); + $aImg->SetLineWeight($this->frameweight); + $aImg->SetLineStyle('solid'); + + if( $this->shadow ) + $aImg->ShadowRectangle($xp,$yp,$xp+$abs_width+$this->shadow_width, + $yp+$abs_height+$this->shadow_width, + $this->fill_color,$this->shadow_width,$this->shadow_color); + else { + $aImg->SetColor($this->fill_color); + $aImg->FilledRectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); + $aImg->SetColor($this->color); + $aImg->Rectangle($xp,$yp,$xp+$abs_width,$yp+$abs_height); + } + + // x1,y1 is the position for the legend mark + $x1=$xp+$this->mark_abs_hsize+$this->xlmargin; + $y1=$yp + $this->ymargin; + + $f2 = round($aImg->GetTextHeight('X')/2); + + $grad = new Gradient($aImg); + $patternFactory = null; + + // Now stroke each legend in turn + // Each plot has added the following information to the legend + // p[0] = Legend text + // p[1] = Color, + // p[2] = For markers a reference to the PlotMark object + // p[3] = For lines the line style, for gradient the negative gradient style + // p[4] = CSIM target + // p[5] = CSIM Alt text + $i = 1 ; $row = 0; + foreach($this->txtcol as $p) { + + // STROKE DEBUG BOX + if( _JPG_DEBUG ) { + $aImg->SetLineWeight(1); + $aImg->SetColor('red'); + $aImg->SetLineStyle('solid'); + $aImg->Rectangle($xp,$y1,$xp+$abs_width,$y1+$rowheight[$row]); + } + + $aImg->SetLineWeight($this->weight); + $x1 = round($x1); $y1=round($y1); + if ( !empty($p[2]) && $p[2]->GetType() > -1 ) { + // Make a plot mark legend + $aImg->SetColor($p[1]); + if( is_string($p[3]) || $p[3]>0 ) { + $aImg->SetLineStyle($p[3]); + $aImg->StyleLine($x1-$this->mark_abs_hsize,$y1+$f2,$x1+$this->mark_abs_hsize,$y1+$f2); + } + // Stroke a mark with the standard size + // (As long as it is not an image mark ) + if( $p[2]->GetType() != MARK_IMG ) { + + // Clear any user callbacks since we ont want them called for + // the legend marks + $p[2]->iFormatCallback = ''; + $p[2]->iFormatCallback2 = ''; + + // Since size for circles is specified as the radius + // this means that we must half the size to make the total + // width behave as the other marks + if( $p[2]->GetType() == MARK_FILLEDCIRCLE || $p[2]->GetType() == MARK_CIRCLE ) { + $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)/2); + $p[2]->Stroke($aImg,$x1,$y1+$f2); + } + else { + $p[2]->SetSize(min($this->mark_abs_vsize,$this->mark_abs_hsize)); + $p[2]->Stroke($aImg,$x1,$y1+$f2); + } + } + } + elseif ( !empty($p[2]) && (is_string($p[3]) || $p[3]>0 ) ) { + // Draw a styled line + $aImg->SetColor($p[1]); + $aImg->SetLineStyle($p[3]); + $aImg->StyleLine($x1-1,$y1+$f2,$x1+$this->mark_abs_hsize,$y1+$f2); + $aImg->StyleLine($x1-1,$y1+$f2+1,$x1+$this->mark_abs_hsize,$y1+$f2+1); + } + else { + // Draw a colored box + $color = $p[1] ; + // We make boxes slightly larger to better show + $boxsize = min($this->mark_abs_vsize,$this->mark_abs_hsize) + 2 ; + $ym = round($y1 + $f2 - $boxsize/2); + // We either need to plot a gradient or a + // pattern. To differentiate we use a kludge. + // Patterns have a p[3] value of < -100 + if( $p[3] < -100 ) { + // p[1][0] == iPattern, p[1][1] == iPatternColor, p[1][2] == iPatternDensity + if( $patternFactory == null ) { + $patternFactory = new RectPatternFactory(); + } + $prect = $patternFactory->Create($p[1][0],$p[1][1],1); + $prect->SetBackground($p[1][3]); + $prect->SetDensity($p[1][2]+1); + $prect->SetPos(new Rectangle($x1,$ym,$boxsize,$boxsize)); + $prect->Stroke($aImg); + $prect=null; + } + else { + if( is_array($color) && count($color)==2 ) { + // The client want a gradient color + $grad->FilledRectangle($x1,$ym, + $x1+$boxsize,$ym+$boxsize, + $color[0],$color[1],-$p[3]); + } + else { + $aImg->SetColor($p[1]); + $aImg->FilledRectangle($x1,$ym,$x1+$boxsize,$ym+$boxsize); + } + $aImg->SetColor($this->color); + $aImg->SetLineWeight($fillBoxFrameWeight); + $aImg->Rectangle($x1,$ym,$x1+$boxsize,$ym+$boxsize); + } + } + $aImg->SetColor($this->font_color); + $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); + $aImg->SetTextAlign("left","top"); + $aImg->StrokeText(round($x1+$this->mark_abs_hsize+$this->xmargin),$y1,$p[0]); + + // Add CSIM for Legend if defined + if( !empty($p[4]) ) { + + $xe = $x1 + $this->xmargin+$this->mark_abs_hsize+$aImg->GetTextWidth($p[0]); + $ye = $y1 + max($this->mark_abs_vsize,$aImg->GetTextHeight($p[0])); + $coords = "$x1,$y1,$xe,$y1,$xe,$ye,$x1,$ye"; + if( ! empty($p[4]) ) { + $this->csimareas .= "csimareas .= " target=\"".$p[6]."\""; + } + + if( !empty($p[5]) ) { + $tmp=sprintf($p[5],$p[0]); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + } + if( $i >= $this->layout_n ) { + $x1 = $xp+$this->mark_abs_hsize+$this->xlmargin; + $y1 += $rowheight[$row++]; + $i = 1; + } + else { + $x1 += $colwidth[($i-1) % $numcolumns] ; + ++$i; + } + } + } +} // Class + + +//=================================================== +// CLASS DisplayValue +// Description: Used to print data values at data points +//=================================================== +class DisplayValue { + public $margin=5; + public $show=false; + public $valign="",$halign="center"; + public $format="%.1f",$negformat=""; + private $ff=FF_FONT1,$fs=FS_NORMAL,$fsize=10; + private $iFormCallback=''; + private $angle=0; + private $color="navy",$negcolor=""; + private $iHideZero=false; + + function Show($aFlag=true) { + $this->show=$aFlag; + } + + function SetColor($aColor,$aNegcolor="") { + $this->color = $aColor; + $this->negcolor = $aNegcolor; + } + + function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->ff=$aFontFamily; + $this->fs=$aFontStyle; + $this->fsize=$aFontSize; + } + + function ApplyFont($aImg) { + $aImg->SetFont($this->ff,$this->fs,$this->fsize); + } + + function SetMargin($aMargin) { + $this->margin = $aMargin; + } + + function SetAngle($aAngle) { + $this->angle = $aAngle; + } + + function SetAlign($aHAlign,$aVAlign='') { + $this->halign = $aHAlign; + $this->valign = $aVAlign; + } + + function SetFormat($aFormat,$aNegFormat="") { + $this->format= $aFormat; + $this->negformat= $aNegFormat; + } + + function SetFormatCallback($aFunc) { + $this->iFormCallback = $aFunc; + } + + function HideZero($aFlag=true) { + $this->iHideZero=$aFlag; + } + + function Stroke($img,$aVal,$x,$y) { + + if( $this->show ) + { + if( $this->negformat=="" ) $this->negformat=$this->format; + if( $this->negcolor=="" ) $this->negcolor=$this->color; + + if( $aVal===NULL || (is_string($aVal) && ($aVal=="" || $aVal=="-" || $aVal=="x" ) ) ) + return; + + if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) { + return; + } + + // Since the value is used in different cirumstances we need to check what + // kind of formatting we shall use. For example, to display values in a line + // graph we simply display the formatted value, but in the case where the user + // has already specified a text string we don't fo anything. + if( $this->iFormCallback != '' ) { + $f = $this->iFormCallback; + $sval = call_user_func($f,$aVal); + } + elseif( is_numeric($aVal) ) { + if( $aVal >= 0 ) + $sval=sprintf($this->format,$aVal); + else + $sval=sprintf($this->negformat,$aVal); + } + else + $sval=$aVal; + + $y = $y-sign($aVal)*$this->margin; + + $txt = new Text($sval,$x,$y); + $txt->SetFont($this->ff,$this->fs,$this->fsize); + if( $this->valign == "" ) { + if( $aVal >= 0 ) + $valign = "bottom"; + else + $valign = "top"; + } + else + $valign = $this->valign; + $txt->Align($this->halign,$valign); + + $txt->SetOrientation($this->angle); + if( $aVal > 0 ) + $txt->SetColor($this->color); + else + $txt->SetColor($this->negcolor); + $txt->Stroke($img); + } + } +} + +//=================================================== +// CLASS Plot +// Description: Abstract base class for all concrete plot classes +//=================================================== +class Plot { + public $numpoints=0; + public $value; + public $legend=''; + public $coords=array(); + public $color="black"; + public $hidelegend=false; + public $line_weight=1; + public $csimtargets=array(),$csimwintargets=array(); // Array of targets for CSIM + public $csimareas=""; // Resultant CSIM area tags + public $csimalts=null; // ALT:s for corresponding target + public $legendcsimtarget='',$legendcsimwintarget=''; + public $legendcsimalt=''; + protected $weight=1; + protected $center=false; +//--------------- +// CONSTRUCTOR + function Plot($aDatay,$aDatax=false) { + $this->numpoints = count($aDatay); + if( $this->numpoints==0 ) + JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point."); + $this->coords[0]=$aDatay; + if( is_array($aDatax) ) { + $this->coords[1]=$aDatax; + $n = count($aDatax); + for($i=0; $i < $n; ++$i ) { + if( !is_numeric($aDatax[$i]) ) { + JpGraphError::RaiseL(25070); + } + } + } + $this->value = new DisplayValue(); + } + +//--------------- +// PUBLIC METHODS + + // Stroke the plot + // "virtual" function which must be implemented by + // the subclasses + function Stroke($aImg,$aXScale,$aYScale) { + JpGraphError::RaiseL(25122);//("JpGraph: Stroke() must be implemented by concrete subclass to class Plot"); + } + + function HideLegend($f=true) { + $this->hidelegend = $f; + } + + function DoLegend($graph) { + if( !$this->hidelegend ) + $this->Legend($graph); + } + + function StrokeDataValue($img,$aVal,$x,$y) { + $this->value->Stroke($img,$aVal,$x,$y); + } + + // Set href targets for CSIM + function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { + $this->csimtargets=$aTargets; + $this->csimwintargets=$aWinTargets; + $this->csimalts=$aAlts; + } + + // Get all created areas + function GetCSIMareas() { + return $this->csimareas; + } + + // "Virtual" function which gets called before any scale + // or axis are stroked used to do any plot specific adjustment + function PreStrokeAdjust($aGraph) { + if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) ) + JpGraphError::RaiseL(25123);//("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead."); + return true; + } + + // Get minimum values in plot + function Min() { + if( isset($this->coords[1]) ) + $x=$this->coords[1]; + else + $x=""; + if( $x != "" && count($x) > 0 ) { + $xm=min($x); + } + else + $xm=0; + $y=$this->coords[0]; + $cnt = count($y); + if( $cnt > 0 ) { + /* + if( ! isset($y[0]) ) { + JpGraphError('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)'); + } + $ym = $y[0]; + */ + $i=0; + while( $i<$cnt && !is_numeric($ym=$y[$i]) ) + $i++; + while( $i < $cnt) { + if( is_numeric($y[$i]) ) + $ym=min($ym,$y[$i]); + ++$i; + } + } + else + $ym=""; + return array($xm,$ym); + } + + // Get maximum value in plot + function Max() { + if( isset($this->coords[1]) ) + $x=$this->coords[1]; + else + $x=""; + + if( $x!="" && count($x) > 0 ) + $xm=max($x); + else { + $xm = $this->numpoints-1; + } + $y=$this->coords[0]; + if( count($y) > 0 ) { + /* + if( !isset($y[0]) ) { + JpGraphError::Raise('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)'); +// $y[0] = 0; +// Change in 1.5.1 Don't treat this as an error any more. Just silently convert to 0 +// Change in 1.17 Treat his as an error again !! This is the right way to do !! + } + */ + $cnt = count($y); + $i=0; + while( $i<$cnt && !is_numeric($ym=$y[$i]) ) + $i++; + while( $i < $cnt ) { + if( is_numeric($y[$i]) ) + $ym=max($ym,$y[$i]); + ++$i; + } + } + else + $ym=""; + return array($xm,$ym); + } + + function SetColor($aColor) { + $this->color=$aColor; + } + + function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { + $this->legend = $aLegend; + $this->legendcsimtarget = $aCSIM; + $this->legendcsimwintarget = $aCSIMWinTarget; + $this->legendcsimalt = $aCSIMAlt; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + + function SetLineWeight($aWeight=1) { + $this->line_weight=$aWeight; + } + + function SetCenter($aCenter=true) { + $this->center = $aCenter; + } + + // This method gets called by Graph class to plot anything that should go + // into the margin after the margin color has been set. + function StrokeMargin($aImg) { + return true; + } + + // Framework function the chance for each plot class to set a legend + function Legend($aGraph) { + if( $this->legend != "" ) + $aGraph->legend->Add($this->legend,$this->color,"",0,$this->legendcsimtarget, + $this->legendcsimalt,$this->legendcsimwintarget); + } + +} // Class + + +//=================================================== +// CLASS PlotLine +// Description: +// Data container class to hold properties for a static +// line that is drawn directly in the plot area. +// Usefull to add static borders inside a plot to show +// for example set-values +//=================================================== +class PlotLine { + public $scaleposition, $direction=-1; + protected $weight=1; + protected $color="black"; + private $legend='',$hidelegend=false, $legendcsimtarget='', $legendcsimalt='',$legendcsimwintarget=''; + +//--------------- +// CONSTRUCTOR + function PlotLine($aDir=HORIZONTAL,$aPos=0,$aColor="black",$aWeight=1) { + $this->direction = $aDir; + $this->color=$aColor; + $this->weight=$aWeight; + $this->scaleposition=$aPos; + } + +//--------------- +// PUBLIC METHODS + + function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { + $this->legend = $aLegend; + $this->legendcsimtarget = $aCSIM; + $this->legendcsimwintarget = $aCSIMWinTarget; + $this->legendcsimalt = $aCSIMAlt; + } + + function HideLegend($f=true) { + $this->hidelegend = $f; + } + + function SetPosition($aScalePosition) { + $this->scaleposition=$aScalePosition; + } + + function SetDirection($aDir) { + $this->direction = $aDir; + } + + function SetColor($aColor) { + $this->color=$aColor; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + +//--------------- +// PRIVATE METHODS + + function DoLegend(&$graph) { + if( !$this->hidelegend ) + $this->Legend($graph); + } + + // Framework function the chance for each plot class to set a legend + function Legend(&$aGraph) { + if( $this->legend != "" ) { + $dummyPlotMark = new PlotMark(); + $lineStyle = 1; + $aGraph->legend->Add($this->legend,$this->color,$dummyPlotMark,$lineStyle, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do + } + + function Stroke($aImg,$aXScale,$aYScale) { + $aImg->SetColor($this->color); + $aImg->SetLineWeight($this->weight); + if( $this->direction == VERTICAL ) { + $ymin_abs=$aYScale->Translate($aYScale->GetMinVal()); + $ymax_abs=$aYScale->Translate($aYScale->GetMaxVal()); + $xpos_abs=$aXScale->Translate($this->scaleposition); + $aImg->Line($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs); + } + elseif( $this->direction == HORIZONTAL ) { + $xmin_abs=$aXScale->Translate($aXScale->GetMinVal()); + $xmax_abs=$aXScale->Translate($aXScale->GetMaxVal()); + $ypos_abs=$aYScale->Translate($this->scaleposition); + $aImg->Line($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs); + } + else + JpGraphError::RaiseL(25125);//(" Illegal direction for static line"); + } +} + +// +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam-digits.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam-digits.php new file mode 100644 index 0000000..ffc1c8b --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam-digits.php @@ -0,0 +1,205 @@ +digits['6'][0]= 645 ; + $this->digits['6'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. + 'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. + 'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. + 'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. + 'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. + 'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. + 'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; + +//========================================================== +// d2-small.jpg +//========================================================== + $this->digits['2'][0]= 606 ; + $this->digits['2'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. + 'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. + 'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. + 'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. + 'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. + '7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. + 'DLZ6f//Z' ; + +//========================================================== +// d9-small.jpg +//========================================================== + $this->digits['9'][0]= 680 ; + $this->digits['9'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. + 'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. + 'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. + 'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. + 'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. + 'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. + 'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. + '1V1//9k=' ; + +//========================================================== +// d5-small.jpg +//========================================================== + $this->digits['5'][0]= 632 ; + $this->digits['5'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. + 'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. + 'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. + 'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. + 'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. + 'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. + '8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; + +//========================================================== +// d1-small.jpg +//========================================================== + $this->digits['1'][0]= 646 ; + $this->digits['1'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. + 'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. + 'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. + 'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. + 'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. + 'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. + 'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; + +//========================================================== +// d8-small.jpg +//========================================================== + $this->digits['8'][0]= 694 ; + $this->digits['8'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. + 'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. + 'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. + 'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. + '44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. + 'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. + 'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. + 'EylmLHQltptPZKQOBo1FzH//2Q==' ; + +//========================================================== +// d4-small.jpg +//========================================================== + $this->digits['4'][0]= 643 ; + $this->digits['4'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. + 'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. + 'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. + 'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. + 'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. + '27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. + 'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; + +//========================================================== +// d7-small.jpg +//========================================================== + $this->digits['7'][0]= 658 ; + $this->digits['7'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. + 'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. + 'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. + '19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. + 'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. + '8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. + 'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; + +//========================================================== +// d3-small.jpg +//========================================================== + $this->digits['3'][0]= 662 ; + $this->digits['3'][1]= + '/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. + 'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. + 'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. + 'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. + 'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. + 'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. + 'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. + 'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. + 'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; + } +} + +class AntiSpam { + + var $iNumber=''; + + function AntiSpam($aNumber='') { + $this->iNumber = $aNumber; + } + + function Rand($aLen) { + $d=''; + for($i=0; $i < $aLen; ++$i) { + $d .= rand(1,9); + } + $this->iNumber = $d; + return $d; + } + + function Stroke() { + + $n=strlen($this->iNumber); + for($i=0; $i < $n; ++$i ) { + if( !is_numeric($this->iNumber[$i]) || $this->iNumber[$i]==0 ) { + return false; + } + } + + $dd = new HandDigits(); + $n = strlen($this->iNumber); + $img = @imagecreatetruecolor($n*$dd->iWidth, $dd->iHeight); + if( $img < 1 ) { + return false; + } + $start=0; + for($i=0; $i < $n; ++$i ) { + $size = $dd->digits[$this->iNumber[$i]][0]; + $dimg = imagecreatefromstring(base64_decode($dd->digits[$this->iNumber[$i]][1])); + imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $dd->iHeight); + $start += imagesx($dimg); + } + $resimg = @imagecreatetruecolor($start+4, $dd->iHeight+4); + if( $resimg < 1 ) { + return false; + } + imagecopy($resimg,$img,2,2,0,0,$start, $dd->iHeight); + header("Content-type: image/jpeg"); + imagejpeg($resimg); + return true; + } +} + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam.php new file mode 100644 index 0000000..81cd867 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_antispam.php @@ -0,0 +1,615 @@ +chars['j'][0]= 658 ; +$this->chars['j'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUGBAf/xAAsEAACAQMDAwMBCQAAAAAAAAAB'. +'AgMEBREAEjEGIUEUUXGBBxMVIiNSYWKC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/8QAGhEAAwADAQAAAAAAAAAAAAAAAAECERIh'. +'Mv/aAAwDAQACEQMRAD8A6veK2st8zRWSyV1dUBfvHaGVI4hknsS7AFv4AyM57ayWbqeS+11xtT2etttwo4YqhEqnQs5bcAfyk4AZ'. +'SOeD441TKRTyingUBG4/ah8j684+dSFzh/BvtaslejMUu9DPQTDnLx4lQ/ONw1TGBm0jdRWqguEMghEisWilgDmNs4Ze+MEEEH40'. +'aUVFTa7JeLjRXu4GjhmnNbSfqFQVlA3rkckOjH/Q99Glmkl0C/Q06pvsvT9vttXHDF6T1KrWbs5gRgQJM+FDlQxPhjpF1XcVq+qe'. +'jEoKiOecXBqh2TDDYIXLKuP6549xk8auI6aJqV45oknWdNswkAIkGMYIxjGO2NR1F0LZY5qkWqkS1xrM0M8lMSJpY+TGrnJiQ577'. +'cEgeNHhi7D3qC3UN69M8tIakRhgrh9o748+eNGtcCiKjjpkQKlMTEg3ZwoxtHHtgfTRpYXArvp//2Q==' ; + +//========================================================== +// lf-small.jpg +//========================================================== +$this->chars['f'][0]= 633 ; +$this->chars['f'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQFBgcC/8QAKxAAAgEDAwMCBQUAAAAAAAAA'. +'AQIDBBEhAAUGEjFBEyIHFFFhoRUzYnGS/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQP/xAAaEQACAwEBAAAAAAAAAAAAAAAAAQIRMRIh'. +'/9oADAMBAAIRAxEAPwDcnmLoIkiSYsouC3tA++O2lU9WkqVjJ+YdhZLsQI/4/YfQm50kZP0vbmaCSU0SRNIH6sghb9INs3t38dvp'. +'akUuz8x5DwdN5peS1jV1dSipSiVUigIcdQjQ26lIB/c6r3F86SZpE/zCFJaqsihQNhRgdj3Jyfxo0jDSbXHt9Oph9RAoV3qJGltY'. +'HDOxyb/nRpV0D3RXle21m48XraOk3IUSemUaV4g4Zc9ShcDtgff+tQfwvjq34Dtku7buamFqeJKemCCMxKFsEJU+/FrX8d76sEHG'. +'aNItzr4usVNdG3S0rmRYAVwEUmyjyQLZ11x7aF4zs9DQOyzml29I2cLa/pixIHi99DFCtU9dFuLIaijo9qiYPmR2mZmB9thgAHOD'. +'4+mjUrURyrUNMZFEkkIOFuFAbsP9d/OjVIQ6Vh4tP//Z' ; + +//========================================================== +// lb-small.jpg +//========================================================== +$this->chars['b'][0]= 645 ; +$this->chars['b'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYCAwUH/8QAKxAAAQMDAwMDAwUAAAAAAAAA'. +'AQIDBAAFEQYSIRMxUSJBYQcVI2JxgqHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/xAAYEQEBAQEBAAAAAAAAAAAAAAAAATERYf/a'. +'AAwDAQACEQMRAD8A6H95mxNYwLXcX+pCuilSLXJ6YSplaUELjqxwe4IJ5PIPamJ2V0bPcS7+NxCX1cHggAnIP+xSd9RyzHh2m7FQ'. +'Q1CvMNQWTjCt+HFD+PB/Y1fI1PL1HFFt0zaGblFdJQ9cJjpZiqPJUlBAKnPcEpGB5NNRKdrOl1NlgiQol4R2w4Sc5VtGf7opZteo'. +'LhdorjUSM5FnQnlR50NeHQysYxtVxlJHIPgjtRRD3xkaghs6juumdHz4+Y7RVPnt59K2mk7W+fcKWsZ7djTXMkW+xMP3GRJjwIEN'. +'HTG/CWx5wPY8AADx2NYk3SL9wukvUjGobnBkORksIbjdMANozgEqSo8qJPGO/wAVO36IsjUmBIfZfuM7epZk3F9UhSSk5O0K9Kcq'. +'8AcU3UzFuhUSBFud6nRXoz96mqmJZWg7m2dqUNhWBwdqQSP1UU5c/FFCn//Z' ; + +//========================================================== +// d6-small.jpg +//========================================================== +$this->chars['6'][0]= 645 ; +$this->chars['6'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAEBAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwMC'. +'BAQEBwAAAAAAAAABAgMEAAURBiESIjFRBxMUQRUWMmFTYnGRkrHC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFhEBAQEAAAAA'. +'AAAAAAAAAAAAAAER/9oADAMBAAIRAxEAPwDslwiR3oDku8ONttsAvDiVyMcO/ET7ke5/aoOz6k1Vr5htNjW7a7M1yO3NTQU9JUDu'. +'GgrlSn8xyf6p4gXaHJvNps9/mKZtSkGdMjRwpfqAFBLLACRlZUrJONsI2717No1lbZ10kx7XGnRpKWQ/6GVGMfzEJ5VFIVtsOH6e'. +'wyKVhYsia0y22pLThSkJK1uniVgdThOM0ol+StIUhpopIyCFq3H8aUVCwnG3PGe4Rp6fLXJtMdyM0ojcIWvIz3HFnAPfrWTXb6GN'. +'WaLXDwZjVz8pKEfhuIUFg/bAz9sVJ61nt61mxJFslLtq7e5yPqiBT4UDklKw4MDpt+u+9bFiu9riXNu83R+fcr6tohuQ5HQhmK37'. +'paaC8DruScmg6X8KkjZEhbaB9KEyFYSOw26Uqd+e7Qerl5z74DY/1SomP//Z' ; + +//========================================================== +// lx-small.jpg +//========================================================== +$this->chars['x'][0]= 650 ; +$this->chars['x'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABMDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUHBgj/xAApEAABAwMDAwQCAwAAAAAAAAAB'. +'AgMEBQYRACFBBxIxFCJRgRNxkcHw/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAMAwEA'. +'AhEDEQA/AH9t3pKvO14UykVARa/HfAlxlDKXR24V2p3z7RlPwdtMep91uWdRGHWELjuTFFtLvcC4SNznnH+21O7ttiodOq1BvC0E'. +'p9I0lSX2kgqCSklK+5PKCMAng6zV2XRO6u3lSIURtbDRShltlZHa0tW7q/0MeTwnjxq1Jiw2xc9xTLbhSVU5iaXUFfqFFILgJOCd'. +'9Gt3SXabR6REpkL8yo0RpLCFNx1qBCRjOQMHxo0pEr6o3um2LVYpMEpTVqg25lHn08dfcB9kEgfZ1LIFDuawqZRb7aQlLTzqglsg'. +'9wQdveOEqBIB425xqhQuk8qo9UKlPrlRblw2ZBeCSVKW6CcoSrI2AGOT41SKzT4dYtmdS5bIXDZhNoWgbZJ94x8AYT/GkM03oNUc'. +'uKgwqtTZDTMOU0FttqRkoHggnPkEEHRrkJ6t1SlSHYUOc6zHaWrsbQrATk5/vRqK/9k=' ; + +//========================================================== +// d2-small.jpg +//========================================================== +$this->chars['2'][0]= 606 ; +$this->chars['2'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEQMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAFAAQHAv/EACsQAAEDBAEC'. +'BAYDAAAAAAAAAAIBAwQABQYRIRIxQVFhcQcTFSJSU5GU0f/EABcBAAMBAAAAAAAAAAAAAAAAAAECAwT/xAAZEQACAwEAAAAAAAAA'. +'AAAAAAAAARESUUH/2gAMAwEAAhEDEQA/AOqXm/Q8dxmOL4PPSnCSNFixx6nXnkXgRT3Te17JWbGsveueSyLZdbPItNxOKLzTLjou'. +'gYCSoSoY8ISKSbFeUrzkdlnTL1YshskiErkQnFEZaF8kkdBBVdjyi6RNL5+9F486eS/ECVkcBtDt1vZcho5viS8ZCp9C9tAIAm/F'. +'VoPRU+HRtJ5JVRP1kP0PfwP+1VKrHBMliXG4Nw8VgE4xGkuqk2S1wTUNEVdIvgpL9iL6KtNxY7WOwo9tt0RCitj0sR2uCbFPPzH1'. +'7+6rRuSRcljMBMsUy2tky045KOawZk5xtEFBJEROO3hx61kh2rPCIX3MhsyC4QmfTbC6lH8dq5212qwkiG5H6Y/9R2qm+ofxqqsL'. +'DLZ6f//Z' ; + +//========================================================== +// lm-small.jpg +//========================================================== +$this->chars['m'][0]= 649 ; +$this->chars['m'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAcDBAUCBv/EAC0QAAICAQMCBAMJAAAAAAAA'. +'AAECAwQRAAUSBiETMVFhB2KhFSIyQVJxgZHB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREBAQEAAwAAAAAAAAAAAAAAAQAR'. +'EiEx/9oADAMBAAIRAxEAPwB0MI2lIdgI0Cly3kFXLEn2zx1FDdp7rbpbjUtRWKio3hyxOGQllJzkegX66rQ2qW87Zuk9S5FNVmru'. +'iywyBhjDKTkeXfSr+GRfYtq2KAO32b1BGxAZu0dyJ2DKPTxY1wPddVszycUq2Golq8jRWbcnJWwCVGMjz+VQP50atxMtm2ZUOY4l'. +'4qfUnBP0x/Z0amy4jJm10Tt2yddWasFmfaRfdrlG3UcgArnxKzJ+Fu4DqCMkcgNem2DoWav8PLfTm+FPEkuSNTnqueS5bnHIv6CG'. +'LNjJwM99bm67NB1Ht89KSxNXnr2hNDbiUc47K4KyD2GQMfmMjUnS+7vuIktTqPCaaWCqAMMojPFyw8hyYMQBnAwNJHYGXPTsW9VN'. +'jg2zf50W9zk524GAEihuz+xbIOD82jW5TkjtRPZkTkJ+4VgDhQfuj/f3OjUxl1f/2Q==' ; + +//========================================================== +// lt-small.jpg +//========================================================== +$this->chars['t'][0]= 648 ; +$this->chars['t'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAJxAAAQMDAgYDAQEAAAAAAAAA'. +'AQIDBAUGEQASEyExQVFhIjJxFSP/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAP/xAAZEQADAQEBAAAAAAAAAAAAAAAAAREhMUH/2gAM'. +'AwEAAhEDEQA/AO4BLEiEy7uG4IGxxs5IOOx76wd2XYidSp1HoD70240gcNNPbDyI6wQQpaz8E9MczkdhqtbsKYLieDk6WLKmZmmL'. +'Hk7AHVkbkLI+RQc7uRxgkfr1tx2rGu6VbToLVKkhU+kbugGf9WfaknCk5ycaX0zmaa+3JkqvW/CmzojsB9xoF6OoFK0r6HOcEDI0'. +'aefTuKX5ScMdC14HYq8n12zo1DEUcKTGg1Z+hyBwoPBVIiA/VQyOIgedhUCB4WMfXSV3UufVLcTUIqVf26K6mXDbPVRRzKT54iMg'. +'+zjtq6mtsyJjclxpKlUhSXEbkgkqWnBx4+J5e/zU0pZemPvJJQzEPDfQOrwwFY9AZ5eeYPLV6FwhoFYZuigxpkJeIjqAeIoAk9wA'. +'D46EnuD+6Nc1smDNrTlRkxqtMo1vzKhIdYgU9YDqVpISrLhHxSSd21I0aYyqP//Z' ; + +//========================================================== +// li-small.jpg +//========================================================== +$this->chars['i'][0]= 639 ; +$this->chars['i'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABwAGBP/EACcQAAEEAQMEAgIDAAAAAAAAAAEC'. +'AwQRBQAGEiExQVEHExSBFWFx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgMB/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECMRH/2gAMAwEA'. +'AhEDEQA/AE7c+5M9BeRG29t1WUfKFFYW+GvrI7WD3B9g140YD5T36rcErDjbUR6dCBdejsKUpxITXI2FUrooCh70yvxzHyIlMvuK'. +'eVSH7IKEpJoKqu/ahddLryR/aMiO187bsmrWShhp1AZS2XHHrWhNJrzdf7f7GiVcHk3sptmHkJcJ2DIftS2FrKlJPXudWuLGYeQp'. +'t2fmEIckqIZaaKuSGG0lQ4gduRoFRHQ9AOgs2lOJbk9aSUlpjGvAWeSVH2VKq/2dFPw3IjyJe8s281ct3I9UoHJXGiQkD2STrSZ7'. +'Yf8AOl7JTdw5eOCz0jw3+LbYCfA9nz71msb8KMxoTGTw+5srjsipAdDqFBQBIuiOl6KrdYyJMyTCshlw2G3Fr/HiNqNNAqJJUoGl'. +'KND+h47km1bZwsvCbYYjycxIyK1qDv2yEi0hQviK8atKDcy9j//Z' ; + + +//========================================================== +// lp-small.jpg +//========================================================== +$this->chars['p'][0]= 700 ; +$this->chars['p'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAECBAUGB//EAC8QAAEDAwMCBAMJAAAAAAAA'. +'AAECAwQFESEABhIiMRMVUWEHFEEWIzIzcYGRocH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAcEQACAgIDAAAAAAAAAAAAAAAA'. +'AQIxAxESIUH/2gAMAwEAAhEDEQA/AOh703xG21DMeOyqoVNDjSzERiwU6Ep5qtZNycA97HTF13d33KWtmlt9xwkLl1NkXVxIuQgK'. +'wLj+hqBvel0qmbR8GnR22nJNZiLeeKr8nDIT1OLJucX+uPbWom7iocRpafOac5MX1ALltp/Cbi+cJH++utdh+WVNL3PNdNYpdWgx'. +'Y0qmLZSrwJJcQoOJ5XKlJFu4HbJOjVbt+V5nu7eopNRivqcdhK+bFnWwA1Y2AOcgjvj9dGlxy0g5y0xd+hNXoG24C4obizq3HZUh'. +'YHqtRHD06bG/8a0MbbG1mqekxaBSGmgkrcdcitlLfrckZIz7DUatbeFak0tyRLUwzT5vmiGm0cufEkFBJItfkD+59tKmiO12atFa'. +'eQukO3ejUxgENqTcfnE5WbkHiOnJ76N2IqI1DibabptS+zkZhtp90F2Y0S026EkAFK/qL46cXv65NVZDfxHmVCK4DE2/RX/lRFbA'. +'C5LwAyq2EtpHZI7mxPYDRqoctdESimz/2Q==' ; + +//========================================================== +// le-small.jpg +//========================================================== +$this->chars['e'][0]= 700 ; +$this->chars['e'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABgDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYEBQcB/8QAKhAAAQMCBAUEAwEAAAAAAAAA'. +'AgEDBAURAAYSIQciMTJBE0JRYRQVFoH/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAgED/8QAGREAAwEBAQAAAAAAAAAAAAAAAAERAjFB'. +'/9oADAMBAAIRAxEAPwDTszvhEYCoS80BTm2bCjQRwdAzVe2yopkpJtpRUVfjEIc4V2oMerByg5Ji30oMyS3GeMunK0upfnu09MdJ'. +'p2scTmWnnGfx6HThktgLfKj7xEOqyr7QBbL41LhBzpxbcOru0LKDLdSnOHoaltNqSC4qWL0x9xbJYum69caczSaHmGmTmpDUYn4l'. +'UiqjkynzAVtwV23Ud+X4Ibpa2DCPkjhfUaRO/p8yzpb+YHhUmhbev6ZEll1lvqK3jt2XrbBgp6HVwsK3THpfEubGSoOUyFMpbJmL'. +'Deh6SgOGKti57EuY6l62JMWdJy7k3hg1LkOozEbVm7suQSkTiKtkEfP1pH664Za/QItccgI4bseTHdNxiXHLQ8yVl7V32XyioqL5'. +'TGc1ng6eYs0idczXUZscBBABWgEhEtfKNuUezwPnBhEuj8X2M21z9BR6NUX211Kk/UKKAjuhkPhL7XVf8vtgw7UPJlEyrDWFSYLb'. +'LBNF6qrzG6t0spEu6+fpL7YMXhUndp//2Q==' ; + +//========================================================== +// la-small.jpg +//========================================================== +$this->chars['a'][0]= 730 ; +$this->chars['a'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABoDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAABgMEBwX/xAAvEAABAwIFAQcCBwAAAAAAAAAB'. +'AgMEBREAEiExQQYHFBUiUXGBE2EyQkNSgpHh/8QAFwEBAQEBAAAAAAAAAAAAAAAAAAMBAv/EABkRAAMBAQEAAAAAAAAAAAAAAAAB'. +'IQIRMf/aAAwDAQACEQMRAD8AfdQ1pxjqZMSn0mRUZRYDaklJCE3OawO2ttTxY4hl07qFMVs1Ku02kpPnRGhsAqz8W9T9wDjozq6o'. +'Q1lDrcZLGVcmUoZg0obpufxK3Ftt9ccqB1GgBcmLSqtVEqOZcr6ARm/kbXHt7DEtc7WTJKTJqEWvRKfLqL9QplSjuPtGVYOJKBrm'. +'t+U+n94WGStZzNypmRWqckUKTbixy6jAfxPxHtCgKqFNlU5huK6pLMndSlegG4J45N8aKmTMKQRBsCNMzwB+RbHWHGEAZlPZX2hx'. +'qZIC34ygZoYUbB50JSkFXFhZR9BrpheR4fIbQ6gvurJ7q02bIQTuAOAN8x40HAxRr3TrNRpBmSHVt1KMlTyJTCsqkKAPlSf28W+c'. +'UGaD1c9HSR1HFUh9tJU45EBcAtcC9+P9wqbg8IAto9o81yputrVGpiUkgHKkqUTZI32+cKm1z1tIUgPBBAKQ4UBQH3uL3xmXSXep'. +'HVDtXStE5K5jlPU7PF3Q41+okJFkjgC+3OuNSYiSzHaLtRcW4UDMpLYSCbakDW3thhum5p//2Q==' ; + +//========================================================== +// d9-small.jpg +//========================================================== +$this->chars['9'][0]= 680 ; +$this->chars['9'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwP/xAArEAABAwMD'. +'AgYBBQAAAAAAAAABAgMEBQYRABIhE1EUIjEzQUIHMlJhcdH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAYEQEAAwEAAAAAAAAA'. +'AAAAAAAAAREhQf/aAAwDAQACEQMRAD8AkK7brF6X7XpMeGoKhFMLEeT4ZUheEhanF4OcZ2pTgDykk92bZpdCsi7aezLjxkIPUZiV'. +'RSCy8hah7EkZ27yM7V+iscal5bE22Lon1qNDmSKROd8Sl+Ix1lMOlIS4HGgQpbStoUCnlJz8HmsXtW3Lst2rmBAelLMRRekOwnYz'. +'Edls9QKKnOVLyk7UgcbzzrdBthqEJJwZbAI4x1U/7o1TaFa9lG36aXaZTy54VrcXUgrzsGdx+T30aNydweqVw1GS87T6Lb86Q4ha'. +'my/IAYjZBx+snKk99oOQMf1AViE65SY348hzFy6hPKnqtKz7DC1lbqyPrvJKUJ7H+M6Wrt3InP7o1brFNp4bCDGhxGAsqz69VSiQ'. +'ORwBxrrQ7itm1ac7Hp0WoGTIc3PSn0pccdcP2WorycfA1RaRHjxosZqOyhtDTSAhCf2gDAGjVHTd9sKSCumynFEZK1tIJUe58/ro'. +'1V1//9k=' ; + +//========================================================== +// d5-small.jpg +//========================================================== +$this->chars['5'][0]= 632 ; +$this->chars['5'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgIFBwT/xAAoEAABAwME'. +'AQQCAwAAAAAAAAABAgMEBQYRABIhIkEUMVFhBxNCgaH/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/EABcRAQEBAQAAAAAAAAAAAAAA'. +'AAABEUH/2gAMAwEAAhEDEQA/ANGvW4YVOeiRX5b4mv5Sin05IdlupPKdo/j2SO3+6TbPNQvOsTVz33KRT4csR3YUF7Dsh5OSFvug'. +'kqG4FPBxnjxpvvi4KZb1pTpU+QwxUi2Y7ZIAefUk5ATxnB9/gbtL/wCH1UpuhPUlZlMVaQ0mS8zJjqZOPfc2TwpIUonI9tw40R1r'. +'WNGq/wBdJR1XT3lqHBUnGCfkfWjRWs1ve249erQqQYjOtN1FqPUpCXQ4WIzQSsJwT0UpRwQPG0nzqyuNHobjsl9kBuWqoOoXtT1/'. +'WppZcA8lKRj64HxqU+3KpAr6plElRVKef3S4E0K9O8pLXVzKcqSsJAB9wSAca6bSoNXeuA1+5pEV+SGFNU1iKVFqI0Vdx2AJUeoz'. +'8DGlTDwG3CAf3q/pI0ah6MDhLz6U+EpXwPoaNMU//9k=' ; + +//========================================================== +// d1-small.jpg +//========================================================== +$this->chars['1'][0]= 646 ; +$this->chars['1'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEwMBIgACEQEDEQH/xAAZAAADAAMAAAAAAAAAAAAAAAAABQYCBAf/xAApEAACAQMD'. +'AwQBBQAAAAAAAAABAgMEBREABiESMUEHEyJRkSNCYXGB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAA'. +'AAAAAAEREv/aAAwDAQACEQMRAD8A6jdd4WLbstILnc4Uq0VoWpkJknb6IjXLHJUePOlez923fcW4r1SxWlqC2UbdKirQif3Xw3yA'. +'OFAGT09/kO3OmV3a20MFRf6lIYPcpy7yRRAzgxjIy2M8YwcdiBzpX6d22VNvUlTXsFkuwkrKqNSfnK7F8OTzwrAY+l5zoxKskudN'. +'EgQPUT9PBkWF3DH+1GPxo1mLnRoAqF2VRgGOFmX/AAgY/GjRUP6hVMFv2FuFqUvUGrpDFJMBnpdyF5bsAQew7Hxzp6LZNT0yQ1DI'. +'wp0QCFBhD0jCsfLZHxbx5xxpTuvb1+v9PV7Ztk9roLPLCjmSSN3mX5ZwqjCgZX7PfWxDQb2in96pv9qq46aTE0bW4x9ceAWAYPwS'. +'PsYzoixgmheBGjIVcYCnjp/jHjHbRpe1JLn9OnopE/a0ykvjwDx47aNMXqP/2Q==' ; + +//========================================================== +// ll-small.jpg +//========================================================== +$this->chars['l'][0]= 626 ; +$this->chars['l'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYEBQf/xAArEAACAQIFAwIGAwAAAAAAAAAB'. +'AgMEEQAFBhIhFEFREzEHFSIyYcFxgZH/xAAXAQEAAwAAAAAAAAAAAAAAAAACAAED/8QAGhEAAwEAAwAAAAAAAAAAAAAAAAECMREh'. +'Qf/aAAwDAQACEQMRAD8A15Zfm1VURj1Fp5AqLKv3OARcL4W5Nzx+MLWjdRz5hqXU6TSb6OCr6WghiQbrJ91gOTy1yT5xZ55myZFk'. +'Gb5ozX6Ondm28XYqpQDwu7jEH4c5S2UaDy4xxrLmlUDWzk8XaQ3O49hbj+RiB85HNg8Ee3aqwIqhDuux7G/HHbvzgxEqaWOvy09R'. +'O0o3hjdQoUji20g+fY3wYSM6pJ4Ylr7V+Zz5PSaezHTlTRNWzxySSxt6q1MSkH6AOT2Fu3Aw7RfF/T9DEkLUeawuF2mKSgdWQj2/'. +'q3+fnDZDlqRZzQGaOGcpTOaeR1u8R+ncN3gj94so2jNWHeMNNKzorEX2qp9v3imNPoRE1zpjUtZ09HJmYq5lury0benZeTww23t3'. +'Ivgw+T0yRRyyxIqNfkLcA8jt7YMKcBWn/9k=' ; + + +//========================================================== +// ls-small.jpg +//========================================================== +$this->chars['s'][0]= 701 ; +$this->chars['s'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGgAAAgMBAQAAAAAAAAAAAAAAAAMCBAUGB//EACwQAAEEAQIFAgUFAAAAAAAA'. +'AAECAwQFEQAGEhMUITEiYQcjQVFxFRZCUoH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAgH/xAAZEQADAQEBAAAAAAAAAAAAAAAAAQIR'. +'EiH/2gAMAwEAAhEDEQA/APWZMhmFXSJU+SGmWFiQtAWMJQAnJUr8Z+w/OuQk71uZnMsqnbjy9s8st9UMCQ6kZJdZaIHEkZ/JHceN'. +'N3HtizuY1JLrG48yLBSC9UTFKQiY4nACir+wAOOMEe2rm2bTbzlqtE1MyBuZAPybpw85KSfDRJ4Cg+Pl/wC61hJeGjV31VuuKqwr'. +'LGU+whZZK+Rw+oYJAyj3GjS4dZFpZVkqPLktdfMXNcaU2kBC1BIITkdx6c599GlnvPAa3TL2vNvU76n0063acr3YSLCEjpUpUQtW'. +'Dhf14SMEnOc57aZ8Tegm7dbrEQGZt1PeTDgc1PEW3FeXAvyAkZVkeMDOm2G3f3O7Cl/qEuqkQg4lp6CRxraWfUlRUD24kZA741Ko'. +'2k1HvlT3ri2sLOCgtsyJz6XEtBwZPAgJAGQMHUNPWKqWItsqh0UCFVyLeKhyLHQ2TMdHNVj+RKlAnJyfto1FW2ahgjrq6LYTFjjf'. +'lymUOLdWfJyoHA+gA7AAAaNPE3ysJdLT/9k=' ; + +//========================================================== +// lh-small.jpg +//========================================================== +$this->chars['h'][0]= 677 ; +$this->chars['h'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAIDBAUGB//EACwQAAIBAwMCBQIHAAAAAAAA'. +'AAECAwQFEQAGEiExExQiQVEVggcyU2GRocH/xAAXAQADAQAAAAAAAAAAAAAAAAAAAwQB/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQAC'. +'AyEyMf/aAAwDAQACEQMRAD8A6DZb95q9bmpK6ieOCzNHJTxmE+NMhQ5fr1fLq3Ejvkak2e7ipiFsqb3R0m4qkPPJRiRXenU9VjKE'. +'5JVcA9R7nWc3/BUbfoKTdO3VRXhpjbZ2D8Rwk6RyZH6chB+46m7i2hDYtgA2ePlV2VkuKysoLzzRnlIScZJZeeevvjtrX7LK2rp7'. +'tTwwJ9WjhILDrTKnIdMEDl2+P80aVdJZb1QW+vgqENLPH4sBCDLIwUgnOf4GjVvDnLgUk79T81voqjb8NnuUx8pVRCiEaYUSuynl'. +'jHU9mOfnOoOx6hqz8PrbNdfEkMUXg1LSM3rKOUywJ7YAJ1ZTWmSpvdvlaVTDSUzJAhH5ZJBgv0x2RSAPlz21WXqoet3ba9nuW8n4'. +'Jr6qTPqnUNxSM/f6mPvxA9zqJnExTbR+h0nkhVu1uE8j0UBRQ9PGxBKFjnkAScdsDp10a0lc7z0tI7Y5YYN+5GAf7GjVXF4Icj3f'. +'/9k=' ; + + +//========================================================== +// ld-small.jpg +//========================================================== +$this->chars['d'][0]= 681 ; +$this->chars['d'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFBgH/xAAsEAABAwMEAAQFBQAAAAAAAAAB'. +'AgMEBQYRABIhMQcTI0EUMlFhkRgicaGx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgEA/8QAGBEBAQEBAQAAAAAAAAAAAAAAAAECETH/'. +'2gAMAwEAAhEDEQA/ALUhp6h3W/X63UlypbhCY0WMjLqGzwDtPCfv/WtealNpVInuVBBqCogcdbU36YUkAkJWVHG8YPXBxxzxqPcN'. +'YtWyWnIlUeW05VEOAvrCnnSkftK1H5lKJPHsMDoDUWq+KdrSbIqsalVsImiEtLUZ2MU71bcYJWkhZ/36ayLHhi/IXZVOmzKqp5uU'. +'688hTyjuGVEFJKvoQesD86NL2jGZp1EoLDSmk+ZAQ8d7oPzp3YGesFWMfxo1YGvSzLsT9QExVX8phTlMaFOExAJIBGQjJwCcL+/e'. +'rd+W7GuO0Kw05CQ6+ww69Gfdb2kFIKk7DgEkjgnr86rXRa9HuyP8LV4SH0sIBbWFFDiFEgDaocgdkjo8ccay0qw7ut5nyrcviQqC'. +'slsRKo0HwlODkBRzxj2AGoXTtpzIdQ8MbffUChz4NCPRaClAo9Mn6c7T3o13wytmo0K05VIqkiPJbizFiMWs4CTgnIIHOST796NL'. +'Ia1JX//Z' ; + +//========================================================== +// d8-small.jpg +//========================================================== +$this->chars['8'][0]= 694 ; +$this->chars['8'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AFQMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABgcEBf/EACsQAAEDAwMD'. +'AwMFAAAAAAAAAAECAwQFBhEAEiEUMVEHE0EVYYEiIzJCsf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/EABcRAQEBAQAAAAAAAAAA'. +'AAAAAAABERL/2gAMAwEAAhEDEQA/AKL6gVVUa0i1T5QjvTprUJMlxW4R9zgQXe/AH+kaWrntqlWjaq7gpcmotXAw82ht9yY4tch8'. +'uAFC0k7VBXPGMY51ruiaue+bThIj+7NbWqS+7HDxajFf6AlB/k44o8ZOABk4xkL0X0tZiojKrlRuGRJjugqldSlKGf6t7BuUQe3J'. +'44xxxrA1a4KVJipLidri8uLHgqOcfjOPxo0o2hdDvS1CmV2Yl6fS5ioipIQR1CAlKkLKR2UUqAI8g6NRSwuuyHab6s1ufLI/Zai7'. +'UBJOxhTS0+6B32pWSFH4CidOdWU0ukLiN1BLr0zG5Sdm3GRvcPhIT858DvjXNrVsSLnm/VIdTXS6tTnFsxZTSN3jchaTwps+O/z9'. +'tcBVq3hIX0tYqlIiQHdy5CqRHKHXEjAOMgBKjnvyRk4xrQa7OiGt1K5biYZL8SoVEpjOqkFsONtJCNwASeCQrn7aNUKnQYtLp7EC'. +'EylmLHQltptPZKQOBo1FzH//2Q==' ; + +//========================================================== +// lz-small.jpg +//========================================================== +$this->chars['z'][0]= 690 ; +$this->chars['z'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgAHA//EACsQAAEDAwQBAwIHAAAAAAAAAAEC'. +'AwQFESEABhIxBxMiQVFxCCM0UmGRof/EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/EABgRAAMBAQAAAAAAAAAAAAAAAAABEVEC/9oA'. +'DAMBAAIRAxEAPwBTWfLu1KXXZDbM4uewNvLajlwhaCbBAwDe5uehYd3xm6t6bi3jvulwqc7KgxXZZeYQLNLeF73WRg4HEdgfzrSa'. +'P45pNEkznITDc9ypLShtyWhJDJyXC2qxJHZvjoZOjyVv1v8AESt6FFS4ijxvTLbawEApSccrYHJf0+OtJMQ2rNXk7GZMufJgJjTH'. +'Un9M4qzxT7hyCiThIyRnPXWrRvyLElVBUF6vlhl0lwRYCFKcQhAtyWpVhyWTx+w++rUvp4EWjOvbniUOnVatcS43BYDbJSPZyIBw'. +'ejclIx+3Wa+J63T6DQanuGszI0eZVJJV60p0Jum5GEi6le7l0PjvSjyRsaTvJqI1BqhhR46ksuMrQVJcUSEoUbHNr/7o7C8L7eiz'. +'4lLlyJk2cEqW+6V+m0AE9ISLnsj5+O9UhsFK92bZZqb9SRu9p2c4A0OCEqDbYAJSlJwAVZv3fBvbFrg/462btlhuS1RG5nL8pYkq'. +'KrnsKH06I/rVrQKkf//Z' ; + +//========================================================== +// d4-small.jpg +//========================================================== +$this->chars['4'][0]= 643 ; +$this->chars['4'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABAYHAv/EAC0QAAIBAwQA'. +'BAMJAAAAAAAAAAECAwQFEQAGEiETFDFBUmGBByIjUVNxobHR/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAIB/8QAGBEBAAMBAAAAAAAA'. +'AAAAAAAAAAERIVH/2gAMAwEAAhEDEQA/ANjM00Nxmt1xiWW31CZp5uJwoAAaOQ/n7qfcZHqO5my3q5XX7R6ijiqnNut9u4NyJ4yv'. +'JJyjYr8Xhrn5g599J7x3ulBNU7Zo7dXXXcLQ8kURYi4epYtkALjOePv1nUvbLvV7P3BZm3DR3eh88Kp7pVzBZI6iUhGWRRGWwE44'. +'HX3V+uiL1uHgt+vL/H+aNJQ3CSeCOaFqSaJ1DJKs/TqRkMOvQjvRorHE4pRDLNWLGlRHGUeYIORXs9e5B7OP31E0fmdyb/t0DJ4Q'. +'27bfx3YZzPUIoAAz7IpOD6cuxq0uNumqLfVNDOqXBoZEjnZcqhIPXH4c46+WkdoWOltu3IDDLLLVVR83UVcuPEmmcZZ2/rHoAANG'. +'GI7KIY1ijoLeEQBVCwIoAHpgY6Hy0aZe7mJ2jeHLKcEhusj6aNKgzr//2Q==' ; + +//========================================================== +// lv-small.jpg +//========================================================== +$this->chars['v'][0]= 648 ; +$this->chars['v'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYH/8QAKBAAAQQBAwMEAgMAAAAAAAAA'. +'AQIDBBEFAAYhEzFBEhQiYQdRFTKB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/8QAFxEBAQEBAAAAAAAAAAAAAAAAAAERIf/aAAwD'. +'AQACEQMRAD8A6Ngt1SZ4yrYgrecgTFsFJA9aGwAUrUaF2D2Avjzq6CIjiBPkB9bwQVIkIYIDae/wq+P9N+dY4SGMf+Txlev7KBmY'. +'PoadKRy4zxSgRxaTwO/x09u7KPYnasmHjlsyFZZXt4K23ezjvBpNGgLUrvXfVZyLLbWambiwEbKvvxYAkeotNlIJW2FEJWb7WBda'. +'NSQI0fHYyJjkrjKRDZQwnpQ1vgBIr+w8+a+9GocZr8iKkuY1eXhsKH8U8iZE9BHz6ZHUc48UfSPqzqH3kfeO9kTTDQYGGietpTaO'. +'shyW6AocpHNIrv8AvWzk9BUSdPdYS4BcRlomkhIV6KP0VE39V+tU2wdlRMHtZUB8NuTQ+51X27+Kr46ZPIAFV540D8zeLsJ5LMHa'. +'ubmMBCVJdjx0pRyLoWR4I8aNIQ8BvZMNtMTeUcsptKfc4tC1gAkCyFC+K0aJtf/Z' ; + +//========================================================== +// lk-small.jpg +//========================================================== +$this->chars['k'][0]= 680 ; +$this->chars['k'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABUDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBAMH/8QALhAAAQMDAwIEBAcAAAAAAAAA'. +'AQIDBAUREgAGITFBEyIyYQcVUYEUIzNicZHx/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEE/8QAGxEAAwACAwAAAAAAAAAAAAAAAAEC'. +'AxESMeH/2gAMAwEAAhEDEQA/APVK/V36dU6NSJDTT8esPLiqfK8S2cCoeTkKvZQ6jm2ldSqKqbu+OgMOvSX3m4UBrLnDlbqiefKl'. +'Nzz2x1m+IwNP27CkJQ7JkR6rCkMJbP5jp8S2CPfkgD6H+dJ6Ca0nerr+64rTNSqMYrg+C9mmOwhVpDfsuxSbi97DmybaoZeQ5jTl'. +'PEp18JTIfeW3kq3ly4H26aNZqvTWZsjFcZTsVtSg0G8Rio+vr2vb7g6NLPRnuXy8F+8kl+obUh4KXJdqSJJQnohlkZqJPYBXh3P+'. +'a4b5Hyp6k1bO7sOotPyXkj9NlwFl0ewstJA9ifrqkVSmET4csoS7UTHXFQ+6SQlskKUMb/tH9ddLVUmS7DqdBqD7U6OsqfS46jzl'. +'hQ5bXb1K9Scuybdxo2OTu92dwSZkWn0Sb8viQWyn8Qq5D6ifSLd0BIv7q0arTBRSKPToMZbi2GWylsvLK148Wue/XRrRjxOpT2R2'. +'k9aP/9k=' ; + +//========================================================== +// lr-small.jpg +//========================================================== +$this->chars['r'][0]= 681 ; +$this->chars['r'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABYDASIAAhEBAxEB/8QAGgAAAgIDAAAAAAAAAAAAAAAAAAYCBQMEB//EAC4QAAICAQIFAgMJAQAAAAAA'. +'AAECAwQRBQYAEiExQQdRFGFxEyIyM0JSYoGC8P/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/EABcRAQEBAQAAAAAAAAAAAAAAAAAB'. +'EUH/2gAMAwEAAhEDEQA/AOs0ZdETU54Gt1INSmlPJEsyo7J+jlXPUYBPY9c+eE/dO9tY0a7ren6BVrW7VJTZtW5kZkjXkBSIKveQ'. +'gHp0AAJ4w+q2hVdT2Md0h46+saS4mr3EUK0gWTAB+vQj2PboeL/ZVOqmhaZVjkFmxdC6tctt3tM2G5/7bAx4C4+qxiWwd3prWzKe'. +'r3IBAth5OYxozKsgc8y4GTgnJB9uncdTi6tXq2140rRVM13JMEMAVAg7sMdBjJB/18uDgRO9R2Oo6FX2vShkFzURFUq1whIj+8DI'. +'7EdAFjXv7MeNb0kuStsFEmIaajZaos2fy2Q4VGH7SGxn+Rzw9yMLOm/FzRhZazmOTkP4grYyD3B8j2PTyeFfZ+z7G3BeSS8lmprl'. +'2K2qcnK0Z5S8gPjrgAY8cNEWmq7u23pEos6/Zji+Kd0rLLGWwseA3joeZj/w4OET1g0vlmrWV+ydFnkUxSgsvM4V+YYIwfHz6cHB'. +'ZeKZ1//Z' ; + +//========================================================== +// lg-small.jpg +//========================================================== +$this->chars['g'][0]= 655 ; +$this->chars['g'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQCBQYH/8QAJxAAAQQBAwQCAgMAAAAAAAAA'. +'AQIDBBEFAAYhBxIxQRNhcYEiQlH/xAAYAQACAwAAAAAAAAAAAAAAAAACAwABBP/EABkRAAMBAQEAAAAAAAAAAAAAAAABAhEhIv/a'. +'AAwDAQACEQMRAD8AayO4t6bq3hmMHtxyLi4OKeKH5jyASiiQCCQeTRNAeB61FrBb+jTGpLO+BMW24EFMhkhpQru8m7B/H70x09Yi'. +'q3nv/vLfwpnJ7UNkqSRbngf2ofWkpXV7brymC2malLfagurjW0aHk89xPJ9cX9aprURHWbYEaMHHEBfwpv8AnXPk+/8AdGqGJOxO'. +'4YbOSxK4y4boIStUWysgkEmxY54r60aOI8oTV9MHtjJwunPUbO46WWo0HLlD8KY4goboFVoquOVEVwLT963WdnxYfT6ZJyz0JvHm'. +'KvtaSkW4tYNVSqKiTwB+fw5n9sY/cuOXCzDDcluyW3Ckd7V+0n0eNZTH9DdouFalHIOJBUhtDki0pNV3UALo81ehG6IdKjPZ6d47'. +'4ywltanVJvuJI+RQs/sHRqy2r003JhsImEc/CUyhxRZBjKV2oJ8eRXNmufPnRo1WIz3DdNn/2Q==' ; + +//========================================================== +// lc-small.jpg +//========================================================== +$this->chars['c'][0]= 629 ; +$this->chars['c'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAUGBwID/8QALRAAAgICAQIEBAYDAAAAAAAA'. +'AQIDBAURACExBhIiQRMVUWEHMkJScYFykaH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgP/xAAXEQEBAQEAAAAAAAAAAAAAAAAAATER'. +'/9oADAMBAAIRAxEAPwDcoGkmiT4Q8kWvzuPU38D2/v8A1zwrCFayq1qTaFk2H7aJHt05MeMvENzC4upDWkjW9kJXiricAJCigvJN'. +'IB1IVQT5frrv24twPgunk6a288crbklUSJNNdnSTZ2STHHqOP/Eb17njdZtAoqwEvrEiGVyG117/AG6HhyV8H1sljMldoxXTksGC'. +'zV7M0oaWGQOVeGQ92I6EMR22D11w4LmEPjaOL51iL8ssc9Z69zHtZkYCGGeQK0ez2UEoU39wCeX1S/LLiEt+mPSbMLxsGVv2kEjR'. +'305xkaEV/GTULMUT1LD/AAGh8gIZS2jv+vpybb8NMIb0dVLWYWgiiU0vmMphOj6V0TvQI3rfsON1E6dYjGtisa0F1mAWR2NhG0WZ'. +'3Ls3TqNs5Hc9h23w49NWL9K+Q/VD5T/zhwPH/9k=' ; + +//========================================================== +// d7-small.jpg +//========================================================== +$this->chars['7'][0]= 658 ; +$this->chars['7'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABgEFBwT/xAAuEAABAwIE'. +'BAQGAwAAAAAAAAABAgMEBREABiExEhMiQSMyUXEHFBclVJFhk9L/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/8QAGREBAQEAAwAA'. +'AAAAAAAAAAAAAAEREiFR/9oADAMBAAIRAxEAPwDXq9mCjZeQ05VZ5ZST4bfEpa3VdglCbqUe+g9MZ5Uq7V8415WXoMSdQ6etgSps'. +'19wpkCMDZKUpv0FZvbi1NzpYasMDLDUbMVXrtQdbeeU23xLWkj5RlLYK0J7anW9gbAjCzkOtsVSUJUdtc6dVZK51UeaFm4LKbhpC'. +'l7EhIFkDW974GbRI2XorUVls1OTdKAOqUpR0Hc3198GITQ6k+hLwrEpoODiDenRfW23bBicg78JXxPpD0mgVOW5PAivNNpahsPW5'. +'8xxQaSVkboQnhsnYm5OHqDGp1IpsalMKjMsMIC3+XZKbJFth62/QOEfMOZqZXp9JcKZTcGmTky3meSi7xQklI81vMR+sXIz/AEgp'. +'Q0qPNu6ea8Q2jqtbp8+2w9h/OKORc/cpHjt1dDSHOtLZ4ekHW23bBjj+o9H/AB539aP94MG0+L//2Q==' ; + +//========================================================== +// ly-small.jpg +//========================================================== +$this->chars['y'][0]= 672 ; +$this->chars['y'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQGBQf/xAArEAABAwMEAQIFBQAAAAAAAAAB'. +'AgMEBREhAAYSEzEHIhQkQVGxQmFxgaH/xAAWAQEBAQAAAAAAAAAAAAAAAAADAQL/xAAeEQEAAgEEAwAAAAAAAAAAAAABABECAxIh'. +'MUGR8P/aAAwDAQACEQMRAD8Ar3tys07dVHohemz5dWQ7fk91MsA3IIRY8rkKFySceTqw3JVV0KhyKw+0C1CQp9aUOFSiAk4AIAvn'. +'76xtz0ioVvbcJ6msx2JtOfZmw1PKI5LQcJNh7UqBKcn6+NRfqPu6s1fYc6GxSJsRfWDUVSGA22ygEckJWSexRNgOP0udXzDKOJ0I'. +'yo62mHm25Sy80l1Z4lSgpQvZRGLgWwPGjTjbchyLH+Ejx22EtJSgO8kki3kADA/nOjWjGzv73CyQZjUWNVp7bNSrj7qJDqflqUlQ'. +'DMds24l3HvcNr3Pi9gME6T9WWVsemdYWswwC2lPta4m5WMA3OdUExCmozUJD6g84ntMjrHIFBTdQz5yLDx/WDNytpwW6nAkViqVe'. +'uvmXdlme6n4dCwlRBKEgA2tj99QG7Ilncp5QqpU31PMsJ6x7A32f6SPxo0hPVCD45oVyKf0MtgeT97/nRrO7UOCFla3tn//Z' ; + +//========================================================== +// d3-small.jpg +//========================================================== +$this->chars['3'][0]= 662 ; +$this->chars['3'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD//gAJSnBHcmFwaP/bAEMACAYGBwYFCAcHBwkJCAoMFA0MCwsMGRITDxQdGh8eHRocHCAkLicg'. +'IiwjHBwoNyksMDE0NDQfJzk9ODI8LjM0Mv/bAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAB4AEgMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAAABAUGBwL/xAArEAABBAED'. +'AwMDBQEAAAAAAAABAgMEBREABhIhMUEiMmETFZEHFkJDUdH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/xAAYEQEBAQEBAAAAAAAA'. +'AAAAAAAAEQExQf/aAAwDAQACEQMRAD8A0vclruBdk3VVLLUNssGRJsZSCtqOjlgJAHvcOD6c4HnOdIbcttw1W5P29cFEhuawqTXS'. +'VsJjnCMBxKkJJx7goAde+ceJfdNxU0UNlyymyXHi6kxWUNl1S3EnkAEIHX2nv86qtTuZr9Q9+1VhRsOoYpYcgSVyAE/TdewkJxnK'. +'sBCjkdPGpnOtFMd3PqsXgfOAgD8Y0aX+11H9rDDjn8lr9yj5J+dGqsqxaw6Cc9cQZU4Sp7zTJsIrKlcUEKwhSin1JABI45GUjqOu'. +'lbOvjbc3Ts9ynjGCy445UuFLYRzbWgrT6fhSCQSMDke+pew2zYVly/d7YchNqkMJZnQpgV9J8IzwWFJyUrAJHYgjvpLbu37G5nR7'. +'vck5C3YRKYEOEVJZj8kjKypXqWvirjk9h+dB9i4faa89TDZUfKlIyT8k+To10a6KTkpcJ/0vL/7o0TS//9k=' ; + +//========================================================== +// ln-small.jpg +//========================================================== +$this->chars['n'][0]= 643 ; +$this->chars['n'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGwAAAgEFAAAAAAAAAAAAAAAAAAYCAQMEBQf/xAAtEAACAQMCBAUCBwAAAAAA'. +'AAABAgMEBREAIQYSE0EHIjFRcWGRIzIzQoGCwf/EABYBAQEBAAAAAAAAAAAAAAAAAAMEAP/EABkRAQEBAQEBAAAAAAAAAAAAAAEA'. +'AhEhUf/aAAwDAQACEQMRAD8A6FR3p7v4oV9rlkMQsjL00RyOss0KkFxnDcrc2PbI1NOJKyTjW+W5OmKeA0UEJx5meRZS2/8AUfbS'. +'LVGS1+K16vCzfiR3GmoqqXGyxz06hWPsFlVMfOmq1iNvE69KjBYo3oJMZ3GKeYYPxg/fW+xzZX1FLQyxwSTcpWNceu4G3+aNSmpY'. +'qmQzzwh2k8yhv2r2H23/AJ0aoy+EWh7I1ntacR3PxDtEzhjWy0wkkIwYmanU5GO6sNh7rrU8AVdTceNbhDXxNHUQvS0tZ3DzwxVA'. +'fB7hj59/XJ08cPWaKj4gvlwSQiG7dCboqvLy9NOmQT9SM7ayJrBa6K5V91hjlWorp4JGUOAglRSiMMDb82/vgaBGTpVvtNUVtyJg'. +'5+WNAh5ZCu/r2+dGrgq0pi0DhmlRsSSAfqMd+b6ZyNu3po1Rk1yNBe3/2Q==' ; + +//========================================================== +// lu-small.jpg +//========================================================== +$this->chars['u'][0]= 671 ; +$this->chars['u'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYDBAUH/8QAJRAAAQQBAwQDAQEAAAAAAAAA'. +'AQIDBBEFAAYhBxMxYRJBURSB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAD/8QAGhEBAQEAAwEAAAAAAAAAAAAAAQARITFBAv/aAAwD'. +'AQACEQMRAD8A6dLkQmJzu3WVtHIqjf0duKFNuBr5UTQ45F1R8/XI1PMmsYoJyjhS9iI7BKHeKjkXZVXqhyLHP+rrHeR1pZlx1W1M'. +'wTiW0ukkrS28nn5fV2SPPFfurHUKQhzYG7pLYKEfyBhaSOS7dG/YCki/uvWn3LPDOJrwa4kyEzOYeakqkpC3Hk0bNePQHgDRpchY'. +'leIZwzUWauKtuPctTSUlCAUmrBHIKuAPV/ujQsmHdm7hya43UbbD3ZVElOQJsdTS6IQaQUqBHCk8E2Pocgam6oYwObHy0Zm0oi45'. +'T1KBPdpV2f0pom/1Ws7cmPazu98Ltvcq3VzRHfehz8a4pirFEKRZo8eQT+eCdWYfS/b+WYnxpbuVcDRMdHcyTqg2fiAfiLoi+Rf+'. +'jT7Xc74HtOYnHyUOh8yWUvKeHhy0CiPVUAPoDRrm+OeznTva6lzsyMjCYbbaiNJjJSWElagD5tRpNUSALFeNGoOCH7Bv/9k=' ; + +//========================================================== +// lw-small.jpg +//========================================================== +$this->chars['w'][0]= 673 ; +$this->chars['w'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABcDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYDBAX/xAAtEAACAQMDAgMHBQAAAAAAAAAB'. +'AgMEBREABhIhMRMUQRUiIzJRYZEWNIGx0f/EABYBAQEBAAAAAAAAAAAAAAAAAAABA//EABoRAAICAwAAAAAAAAAAAAAAAAABERIh'. +'MVH/2gAMAwEAAhEDEQA/AHXbV13ZLu6t2/uaa1JijWopVp4XUTKSAXRyc+6ehBGeoPbTSlwpql0K3GneqpZViqUhI5JzGMEZJGeh'. +'GlXfaFILDf7FQzXC426rDLTojs8sLqVkXBGcfKf40twWbdWzZY75R0s90ul3jPtKjVMJDNn4DDp8iEhW+wJ1WZG2KWt3Lv26U1tv'. +'92o7PaYkgYUbqVepYlmUBlIwqnB++O2jTDt/bBtth9jcpvEWNGqalZQryTlmeR8jPct6+mNGmRC4a1U13htzVFItB5nA/cyOUVfp'. +'7oz/ALqitJulYJKuqvFsppHALLFb3cp9FBaXr+O51bq0q6i38KK5PDVAAxSzU6SIpz3Kjjn8jUFoS7uFmut1gq17xLFQ+DxOccj8'. +'Rsn+tVpiyJnqv09YfOXu5AycgZZQEhBZjgDBOOgwO/po0sttWHdNzqLruioa4UwmdaC3kYp4IwSvJlBHKQ4OSe3po0qxM6P/2Q==' ; + +//========================================================== +// lq-small.jpg +//========================================================== +$this->chars['q'][0]= 671 ; +$this->chars['q'][1]= +'/9j/4AAQSkZJRgABAQEASgBKAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAx'. +'NDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy'. +'MjIyMjIyMjL/wAARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAcDBAUG/8QAKRAAAQQBBAICAQQDAAAAAAAA'. +'AQIDBBEFAAYSIQcxIlETCBQVgSNBYf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oADAMB'. +'AAIRAxEAPwDT3H5Qz+O3LN2vtrF/y86NYLzzVlAABJITQPv2a/17vXMboz3lDEYWPuafNx7CFrS03+2jpK2bs0CUkUa7pRvrUu63'. +'sr438yv7pLEo4XIK5Kcji0uJUkckm+uQUOVH6GsnyJv7A5vaJwuFdkONLmolgONFH4vioKRXYqyCADXvRMh0yspmZ4jyIEtDTK47'. +'aiA0lQUopBJBI/7X9aNT7amRo228e3a31iO3yUzCcdSPiKAIFdCho0TIswZ7GQlO/hlRxBooih1YXzAoKUkX0LPEBX110dJ7zbuv'. +'AORpO04cIpmxH23FSEIRwKuNnsdk0o31702XhFMKbuRUZJWP8LTQ6HBCuIB+iVWSR2BXuqK93/hDlvGzEphmG3Ml5JpDi1I7TzNA'. +'BYFlPafY+/7LBiv1CYDH4iFDOGySlMR22lFP4wCUpANfL11o1r4bxXlWMNEaE/bqlIbCFl/ANPK5Do/M0VDr2Rf3o0TX/9k=' ; + + + + } +} + +class AntiSpam { + + private $iData=''; + private $iDD=null; + + function AntiSpam($aData='') { + $this->iData = $aData; + $this->iDD = new HandDigits(); + } + + function Set($aData) { + $this->iData = $aData; + } + + function Rand($aLen) { + $d=''; + for($i=0; $i < $aLen; ++$i) { + if( rand(0,9) < 6 ) { + // Digits + $d .= chr( ord('1') + rand(0,8) ); + } + else { + // Letters + do { + $offset = rand(0,25); + } while ( $offset==14 ); + $d .= chr( ord('a') + $offset ); + } + } + $this->iData = $d; + return $d; + } + + function Stroke() { + + $n=strlen($this->iData); + if( $n==0 ) { + return false; + } + + for($i=0; $i < $n; ++$i ) { + if( $this->iData[$i]==='0' || strtolower($this->iData[$i])==='o') { + return false; + } + } + + $img = @imagecreatetruecolor($n*$this->iDD->iWidth, $this->iDD->iHeight); + if( $img < 1 ) { + return false; + } + + $start=0; + for($i=0; $i < $n; ++$i ) { + $dimg = imagecreatefromstring(base64_decode($this->iDD->chars[strtolower($this->iData[$i])][1])); + imagecopy($img,$dimg,$start,0,0,0,imagesx($dimg), $this->iDD->iHeight); + $start += imagesx($dimg); + } + $resimg = @imagecreatetruecolor($start+4, $this->iDD->iHeight+4); + if( $resimg < 1 ) { + return false; + } + + imagecopy($resimg,$img,2,2,0,0,$start, $this->iDD->iHeight); + header("Content-type: image/jpeg"); + imagejpeg($resimg); + return true; + } +} + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_bar.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_bar.php new file mode 100644 index 0000000..2dbea6d --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_bar.php @@ -0,0 +1,1009 @@ +Plot($datay,$datax); + ++$this->numpoints; + } + +//--------------- +// PUBLIC METHODS + + // Set a drop shadow for the bar (or rather an "up-right" shadow) + function SetShadow($color="black",$hsize=3,$vsize=3,$show=true) { + $this->bar_shadow=$show; + $this->bar_shadow_color=$color; + $this->bar_shadow_vsize=$vsize; + $this->bar_shadow_hsize=$hsize; + + // Adjust the value margin to compensate for shadow + $this->value->margin += $vsize; + } + + // DEPRECATED use SetYBase instead + function SetYMin($aYStartValue) { + //die("JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead."); + $this->ybase=$aYStartValue; + } + + // Specify the base value for the bars + function SetYBase($aYStartValue) { + $this->ybase=$aYStartValue; + } + + function Legend($graph) { + if( $this->grad && $this->legend!="" && !$this->fill ) { + $color=array($this->grad_fromcolor,$this->grad_tocolor); + // In order to differentiate between gradients and cooors specified as an RGB triple + $graph->legend->Add($this->legend,$color,"",-$this->grad_style, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + elseif( $this->legend!="" && ($this->iPattern > -1 || is_array($this->iPattern)) ) { + if( is_array($this->iPattern) ) { + $p1 = $this->iPattern[0]; + $p2 = $this->iPatternColor[0]; + $p3 = $this->iPatternDensity[0]; + } + else { + $p1 = $this->iPattern; + $p2 = $this->iPatternColor; + $p3 = $this->iPatternDensity; + } + $color = array($p1,$p2,$p3,$this->fill_color); + // A kludge: Too mark that we add a pattern we use a type value of < 100 + $graph->legend->Add($this->legend,$color,"",-101, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + elseif( $this->fill_color && $this->legend!="" ) { + if( is_array($this->fill_color) ) { + $graph->legend->Add($this->legend,$this->fill_color[0],"",0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + else { + $graph->legend->Add($this->legend,$this->fill_color,"",0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + parent::PreStrokeAdjust($graph); + + // If we are using a log Y-scale we want the base to be at the + // minimum Y-value unless the user have specifically set some other + // value than the default. + if( substr($graph->axtype,-3,3)=="log" && $this->ybase==0 ) + $this->ybase = $graph->yaxis->scale->GetMinVal(); + + // For a "text" X-axis scale we will adjust the + // display of the bars a little bit. + if( substr($graph->axtype,0,3)=="tex" ) { + // Position the ticks between the bars + $graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0); + + // Center the bars + if( $this->abswidth > -1 ) { + $graph->SetTextScaleAbsCenterOff($this->abswidth); + } + else { + if( $this->align == "center" ) + $graph->SetTextScaleOff(0.5-$this->width/2); + elseif( $this->align == "right" ) + $graph->SetTextScaleOff(1-$this->width); + } + } + elseif( ($this instanceof AccBarPlot) || ($this instanceof GroupBarPlot) ) { + // We only set an absolute width for linear and int scale + // for text scale the width will be set to a fraction of + // the majstep width. + if( $this->abswidth == -1 ) { + // Not set + // set width to a visuable sensible default + $this->abswidth = $graph->img->plotwidth/(2*count($this->coords[0])); + } + } + } + + function Min() { + $m = parent::Min(); + if( $m[1] >= $this->ybase ) + $m[1] = $this->ybase; + return $m; + } + + function Max() { + $m = parent::Max(); + if( $m[1] <= $this->ybase ) + $m[1] = $this->ybase; + return $m; + } + + // Specify width as fractions of the major stepo size + function SetWidth($aWidth) { + if( $aWidth > 1 ) { + // Interpret this as absolute width + $this->abswidth=$aWidth; + } + else + $this->width=$aWidth; + } + + // Specify width in absolute pixels. If specified this + // overrides SetWidth() + function SetAbsWidth($aWidth) { + $this->abswidth=$aWidth; + } + + function SetAlign($aAlign) { + $this->align=$aAlign; + } + + function SetNoFill() { + $this->grad = false; + $this->fill_color=false; + $this->fill=false; + } + + function SetFillColor($aColor) { + $this->fill = true ; + $this->fill_color=$aColor; + } + + function SetFillGradient($aFromColor,$aToColor=null,$aStyle=null) { + $this->grad = true; + $this->grad_fromcolor = $aFromColor; + $this->grad_tocolor = $aToColor; + $this->grad_style = $aStyle; + } + + function SetValuePos($aPos) { + $this->valuepos = $aPos; + } + + function SetPattern($aPattern, $aColor='black'){ + if( is_array($aPattern) ) { + $n = count($aPattern); + $this->iPattern = array(); + $this->iPatternDensity = array(); + if( is_array($aColor) ) { + $this->iPatternColor = array(); + if( count($aColor) != $n ) { + JpGraphError::Raise('NUmber of colors is not the same as the number of patterns in BarPlot::SetPattern()'); + } + } + else + $this->iPatternColor = $aColor; + for( $i=0; $i < $n; ++$i ) { + $this->_SetPatternHelper($aPattern[$i], $this->iPattern[$i], $this->iPatternDensity[$i]); + if( is_array($aColor) ) { + $this->iPatternColor[$i] = $aColor[$i]; + } + } + } + else { + $this->_SetPatternHelper($aPattern, $this->iPattern, $this->iPatternDensity); + $this->iPatternColor = $aColor; + } + } + + function _SetPatternHelper($aPattern, &$aPatternValue, &$aDensity){ + switch( $aPattern ) { + case PATTERN_DIAG1: + $aPatternValue= 1; + $aDensity = 90; + break; + case PATTERN_DIAG2: + $aPatternValue= 1; + $aDensity = 75; + break; + case PATTERN_DIAG3: + $aPatternValue= 2; + $aDensity = 90; + break; + case PATTERN_DIAG4: + $aPatternValue= 2; + $aDensity = 75; + break; + case PATTERN_CROSS1: + $aPatternValue= 8; + $aDensity = 90; + break; + case PATTERN_CROSS2: + $aPatternValue= 8; + $aDensity = 78; + break; + case PATTERN_CROSS3: + $aPatternValue= 8; + $aDensity = 65; + break; + case PATTERN_CROSS4: + $aPatternValue= 7; + $aDensity = 90; + break; + case PATTERN_STRIPE1: + $aPatternValue= 5; + $aDensity = 90; + break; + case PATTERN_STRIPE2: + $aPatternValue= 5; + $aDensity = 75; + break; + default: + JpGraphError::Raise('Unknown pattern specified in call to BarPlot::SetPattern()'); + } + } + + function Stroke($img,$xscale,$yscale) { + + $numpoints = count($this->coords[0]); + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$numpoints ) + JpGraphError::Raise("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])."Number of Y-points:$numpoints"); + else + $exist_x = true; + } + else + $exist_x = false; + + + $numbars=count($this->coords[0]); + + // Use GetMinVal() instead of scale[0] directly since in the case + // of log scale we get a correct value. Log scales will have negative + // values for values < 1 while still not representing negative numbers. + if( $yscale->GetMinVal() >= 0 ) + $zp=$yscale->scale_abs[0]; + else { + $zp=$yscale->Translate(0); + } + + if( $this->abswidth > -1 ) { + $abswidth=$this->abswidth; + } + else + $abswidth=round($this->width*$xscale->scale_factor,0); + + // Count pontetial pattern array to avoid doing the count for each iteration + if( is_array($this->iPattern) ) { + $np = count($this->iPattern); + } + + $grad = null; + for($i=0; $i < $numbars; ++$i) { + + // If value is NULL, or 0 then don't draw a bar at all + if ($this->coords[0][$i] === null || $this->coords[0][$i] === '' ) + continue; + + if( $exist_x ) $x=$this->coords[1][$i]; + else $x=$i; + + $x=$xscale->Translate($x); + +// Comment Note: This confuses the positioning when using acc together with +// grouped bars. Workaround for fixing #191 +/* + if( !$xscale->textscale ) { + if($this->align=="center") + $x -= $abswidth/2; + elseif($this->align=="right") + $x -= $abswidth; + } +*/ + // Stroke fill color and fill gradient + $pts=array( + $x,$zp, + $x,$yscale->Translate($this->coords[0][$i]), + $x+$abswidth,$yscale->Translate($this->coords[0][$i]), + $x+$abswidth,$zp); + if( $this->grad ) { + if( $grad === null ) + $grad = new Gradient($img); + if( is_array($this->grad_fromcolor) ) { + // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array + // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be + // an array to specify both (from, to style) for each individual bar. The way to know the difference is + // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB + // triple. + $ng = count($this->grad_fromcolor); + if( $ng === 3 ) { + if( is_numeric($this->grad_fromcolor[0]) && $this->grad_fromcolor[0] > 0 && $this->grad_fromcolor[0] < 256 ) { + // RGB Triple + $fromcolor = $this->grad_fromcolor; + $tocolor = $this->grad_tocolor; + $style = $this->grad_style; + } + } + else { + $fromcolor = $this->grad_fromcolor[$i % $ng][0]; + $tocolor = $this->grad_fromcolor[$i % $ng][1]; + $style = $this->grad_fromcolor[$i % $ng][2]; + } + $grad->FilledRectangle($pts[2],$pts[3], + $pts[6],$pts[7], + $fromcolor,$tocolor,$style); + } + else { + $grad->FilledRectangle($pts[2],$pts[3], + $pts[6],$pts[7], + $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style); + } + } + elseif( !empty($this->fill_color) ) { + if(is_array($this->fill_color)) { + $img->PushColor($this->fill_color[$i % count($this->fill_color)]); + } else { + $img->PushColor($this->fill_color); + } + $img->FilledPolygon($pts); + $img->PopColor(); + } + + + // Remember value of this bar + $val=$this->coords[0][$i]; + + if( !empty($val) && !is_numeric($val) ) { + JpGraphError::Raise('All values for a barplot must be numeric. You have specified value['.$i.'] == \''.$val.'\''); + } + + // Determine the shadow + if( $this->bar_shadow && $val != 0) { + + $ssh = $this->bar_shadow_hsize; + $ssv = $this->bar_shadow_vsize; + // Create points to create a "upper-right" shadow + if( $val > 0 ) { + $sp[0]=$pts[6]; $sp[1]=$pts[7]; + $sp[2]=$pts[4]; $sp[3]=$pts[5]; + $sp[4]=$pts[2]; $sp[5]=$pts[3]; + $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; + $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; + $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; + } + elseif( $val < 0 ) { + $sp[0]=$pts[4]; $sp[1]=$pts[5]; + $sp[2]=$pts[6]; $sp[3]=$pts[7]; + $sp[4]=$pts[0]; $sp[5]=$pts[1]; + $sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv; + $sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv; + $sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv; + } + if( is_array($this->bar_shadow_color) ) { + $numcolors = count($this->bar_shadow_color); + if( $numcolors == 0 ) { + JpGraphError::Raise('You have specified an empty array for shadow colors in the bar plot.'); + } + $img->PushColor($this->bar_shadow_color[$i % $numcolors]); + } + else { + $img->PushColor($this->bar_shadow_color); + } + $img->FilledPolygon($sp); + $img->PopColor(); + } + + // Stroke the pattern + if( is_array($this->iPattern) ) { + $f = new RectPatternFactory(); + if( is_array($this->iPatternColor) ) { + $pcolor = $this->iPatternColor[$i % $np]; + } + else + $pcolor = $this->iPatternColor; + $prect = $f->Create($this->iPattern[$i % $np],$pcolor,1); + $prect->SetDensity($this->iPatternDensity[$i % $np]); + + if( $val < 0 ) { + $rx = $pts[0]; + $ry = $pts[1]; + } + else { + $rx = $pts[2]; + $ry = $pts[3]; + } + $width = abs($pts[4]-$pts[0])+1; + $height = abs($pts[1]-$pts[3])+1; + $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); + $prect->Stroke($img); + } + else { + if( $this->iPattern > -1 ) { + $f = new RectPatternFactory(); + $prect = $f->Create($this->iPattern,$this->iPatternColor,1); + $prect->SetDensity($this->iPatternDensity); + if( $val < 0 ) { + $rx = $pts[0]; + $ry = $pts[1]; + } + else { + $rx = $pts[2]; + $ry = $pts[3]; + } + $width = abs($pts[4]-$pts[0])+1; + $height = abs($pts[1]-$pts[3])+1; + $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); + $prect->Stroke($img); + } + } + // Stroke the outline of the bar + if( is_array($this->color) ) + $img->SetColor($this->color[$i % count($this->color)]); + else + $img->SetColor($this->color); + + $pts[] = $pts[0]; + $pts[] = $pts[1]; + + if( $this->weight > 0 ) { + $img->SetLineWeight($this->weight); + $img->Polygon($pts); + } + + // Determine how to best position the values of the individual bars + $x=$pts[2]+($pts[4]-$pts[2])/2; + if( $this->valuepos=='top' ) { + $y=$pts[3]; + if( $img->a === 90 ) { + if( $val < 0 ) + $this->value->SetAlign('right','center'); + else + $this->value->SetAlign('left','center'); + + } + $this->value->Stroke($img,$val,$x,$y); + } + elseif( $this->valuepos=='max' ) { + $y=$pts[3]; + if( $img->a === 90 ) { + if( $val < 0 ) + $this->value->SetAlign('left','center'); + else + $this->value->SetAlign('right','center'); + } + else { + $this->value->SetAlign('center','top'); + } + $this->value->SetMargin(-3); + $this->value->Stroke($img,$val,$x,$y); + } + elseif( $this->valuepos=='center' ) { + $y = ($pts[3] + $pts[1])/2; + $this->value->SetAlign('center','center'); + $this->value->SetMargin(0); + $this->value->Stroke($img,$val,$x,$y); + } + elseif( $this->valuepos=='bottom' || $this->valuepos=='min' ) { + $y=$pts[1]; + if( $img->a === 90 ) { + if( $val < 0 ) + $this->value->SetAlign('right','center'); + else + $this->value->SetAlign('left','center'); + } + $this->value->SetMargin(3); + $this->value->Stroke($img,$val,$x,$y); + } + else { + JpGraphError::Raise('Unknown position for values on bars :'.$this->valuepos); + } + // Create the client side image map + $rpts = $img->ArrRotate($pts); + $csimcoord=round($rpts[0]).", ".round($rpts[1]); + for( $j=1; $j < 4; ++$j){ + $csimcoord .= ", ".round($rpts[2*$j]).", ".round($rpts[2*$j+1]); + } + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas .= 'csimareas .= " href=\"".htmlentities($this->csimtargets[$i])."\""; + + if( !empty($this->csimwintargets[$i]) ) { + $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; + } + + $sval=''; + if( !empty($this->csimalts[$i]) ) { + $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]); + $this->csimareas .= " title=\"$sval\" alt=\"$sval\" "; + } + $this->csimareas .= " />\n"; + } + } + return true; + } +} // Class + +//=================================================== +// CLASS GroupBarPlot +// Description: Produce grouped bar plots +//=================================================== +class GroupBarPlot extends BarPlot { + private $plots, $nbrplots=0; +//--------------- +// CONSTRUCTOR + function GroupBarPlot($plots) { + $this->width=0.7; + $this->plots = $plots; + $this->nbrplots = count($plots); + if( $this->nbrplots < 1 ) { + JpGraphError::Raise('Cannot create GroupBarPlot from empty plot array.'); + } + for($i=0; $i < $this->nbrplots; ++$i ) { + if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { + JpGraphError::Raise("Group bar plot element nbr $i is undefined or empty."); + } + } + $this->numpoints = $plots[0]->numpoints; + $this->width=0.7; + } + +//--------------- +// PUBLIC METHODS + function Legend($graph) { + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + $c = get_class($this->plots[$i]); + if( !($this->plots[$i] instanceof BarPlot) ) { + JpGraphError::Raise('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the Group Bar plot from an array of BarPlot or AccBarPlot objects. (Class = '.$c.')'); + } + $this->plots[$i]->DoLegend($graph); + } + } + + function Min() { + list($xmin,$ymin) = $this->plots[0]->Min(); + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + list($xm,$ym) = $this->plots[$i]->Min(); + $xmin = max($xmin,$xm); + $ymin = min($ymin,$ym); + } + return array($xmin,$ymin); + } + + function Max() { + list($xmax,$ymax) = $this->plots[0]->Max(); + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + list($xm,$ym) = $this->plots[$i]->Max(); + $xmax = max($xmax,$xm); + $ymax = max($ymax,$ym); + } + return array($xmax,$ymax); + } + + function GetCSIMareas() { + $n = count($this->plots); + $csimareas=''; + for($i=0; $i < $n; ++$i) { + $csimareas .= $this->plots[$i]->csimareas; + } + return $csimareas; + } + + // Stroke all the bars next to each other + function Stroke($img,$xscale,$yscale) { + $tmp=$xscale->off; + $n = count($this->plots); + $subwidth = $this->width/$this->nbrplots ; + + for( $i=0; $i < $n; ++$i ) { + $this->plots[$i]->ymin=$this->ybase; + $this->plots[$i]->SetWidth($subwidth); + + // If the client have used SetTextTickInterval() then + // major_step will be > 1 and the positioning will fail. + // If we assume it is always one the positioning will work + // fine with a text scale but this will not work with + // arbitrary linear scale + $xscale->off = $tmp+$i*round($xscale->scale_factor* $subwidth); + $this->plots[$i]->Stroke($img,$xscale,$yscale); + } + $xscale->off=$tmp; + } +} // Class + +//=================================================== +// CLASS AccBarPlot +// Description: Produce accumulated bar plots +//=================================================== +class AccBarPlot extends BarPlot { + private $plots=null,$nbrplots=0; +//--------------- +// CONSTRUCTOR + function AccBarPlot($plots) { + $this->plots = $plots; + $this->nbrplots = count($plots); + if( $this->nbrplots < 1 ) { + JpGraphError::Raise('Cannot create AccBarPlot from empty plot array.'); + } + for($i=0; $i < $this->nbrplots; ++$i ) { + if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) { + JpGraphError::Raise("Acc bar plot element nbr $i is undefined or empty."); + } + } + $this->numpoints = $plots[0]->numpoints; + $this->value = new DisplayValue(); + } + +//--------------- +// PUBLIC METHODS + function Legend($graph) { + $n = count($this->plots); + for( $i=$n-1; $i >= 0; --$i ) { + $c = get_class($this->plots[$i]); + if( !($this->plots[$i] instanceof BarPlot) ) { + JpGraphError::Raise('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects.(Class='.$c.')'); + } + $this->plots[$i]->DoLegend($graph); + } + } + + function Max() { + list($xmax) = $this->plots[0]->Max(); + $nmax=0; + for($i=0; $i < count($this->plots); ++$i) { + $n = count($this->plots[$i]->coords[0]); + $nmax = max($nmax,$n); + list($x) = $this->plots[$i]->Max(); + $xmax = max($xmax,$x); + } + for( $i = 0; $i < $nmax; $i++ ) { + // Get y-value for bar $i by adding the + // individual bars from all the plots added. + // It would be wrong to just add the + // individual plots max y-value since that + // would in most cases give to large y-value. + $y=0; + if( !isset($this->plots[0]->coords[0][$i]) ) { + JpGraphError::RaiseL(2014); + } + if( $this->plots[0]->coords[0][$i] > 0 ) + $y=$this->plots[0]->coords[0][$i]; + for( $j = 1; $j < $this->nbrplots; $j++ ) { + if( !isset($this->plots[$j]->coords[0][$i]) ) { + JpGraphError::RaiseL(2014); + } + if( $this->plots[$j]->coords[0][$i] > 0 ) + $y += $this->plots[$j]->coords[0][$i]; + } + $ymax[$i] = $y; + } + $ymax = max($ymax); + + // Bar always start at baseline + if( $ymax <= $this->ybase ) + $ymax = $this->ybase; + return array($xmax,$ymax); + } + + function Min() { + $nmax=0; + list($xmin,$ysetmin) = $this->plots[0]->Min(); + for($i=0; $i < count($this->plots); ++$i) { + $n = count($this->plots[$i]->coords[0]); + $nmax = max($nmax,$n); + list($x,$y) = $this->plots[$i]->Min(); + $xmin = Min($xmin,$x); + $ysetmin = Min($y,$ysetmin); + } + for( $i = 0; $i < $nmax; $i++ ) { + // Get y-value for bar $i by adding the + // individual bars from all the plots added. + // It would be wrong to just add the + // individual plots max y-value since that + // would in most cases give to large y-value. + $y=0; + if( $this->plots[0]->coords[0][$i] < 0 ) + $y=$this->plots[0]->coords[0][$i]; + for( $j = 1; $j < $this->nbrplots; $j++ ) { + if( $this->plots[$j]->coords[0][$i] < 0 ) + $y += $this->plots[ $j ]->coords[0][$i]; + } + $ymin[$i] = $y; + } + $ymin = Min($ysetmin,Min($ymin)); + // Bar always start at baseline + if( $ymin >= $this->ybase ) + $ymin = $this->ybase; + return array($xmin,$ymin); + } + + // Stroke acc bar plot + function Stroke($img,$xscale,$yscale) { + $pattern=NULL; + $img->SetLineWeight($this->weight); + for($i=0; $i < $this->numpoints-1; $i++) { + $accy = 0; + $accy_neg = 0; + for($j=0; $j < $this->nbrplots; ++$j ) { + $img->SetColor($this->plots[$j]->color); + + if ( $this->plots[$j]->coords[0][$i] >= 0) { + $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); + $accyt=$yscale->Translate($accy); + $accy+=$this->plots[$j]->coords[0][$i]; + } + else { + //if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) { + $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); + $accyt=$yscale->Translate($accy_neg); + $accy_neg+=$this->plots[$j]->coords[0][$i]; + } + + $xt=$xscale->Translate($i); + + if( $this->abswidth > -1 ) + $abswidth=$this->abswidth; + else + $abswidth=round($this->width*$xscale->scale_factor,0); + + $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt); + + if( $this->bar_shadow ) { + $ssh = $this->bar_shadow_hsize; + $ssv = $this->bar_shadow_vsize; + + // We must also differ if we are a positive or negative bar. + if( $j === 0 ) { + // This gets extra complicated since we have to + // see all plots to see if we are negative. It could + // for example be that all plots are 0 until the very + // last one. We therefore need to save the initial setup + // for both the negative and positive case + + // In case the final bar is positive + $sp[0]=$pts[6]+1; $sp[1]=$pts[7]; + $sp[2]=$pts[6]+$ssh; $sp[3]=$pts[7]-$ssv; + + // In case the final bar is negative + $nsp[0]=$pts[0]; $nsp[1]=$pts[1]; + $nsp[2]=$pts[0]+$ssh; $nsp[3]=$pts[1]-$ssv; + $nsp[4]=$pts[6]+$ssh; $nsp[5]=$pts[7]-$ssv; + $nsp[10]=$pts[6]+1; $nsp[11]=$pts[7]; + } + + if( $j === $this->nbrplots-1 ) { + // If this is the last plot of the bar and + // the total value is larger than 0 then we + // add the shadow. + if( is_array($this->bar_shadow_color) ) { + $numcolors = count($this->bar_shadow_color); + if( $numcolors == 0 ) { + JpGraphError::Raise('You have specified an empty array for shadow colors in the bar plot.'); + } + $img->PushColor($this->bar_shadow_color[$i % $numcolors]); + } + else { + $img->PushColor($this->bar_shadow_color); + } + + if( $accy > 0 ) { + $sp[4]=$pts[4]+$ssh; $sp[5]=$pts[5]-$ssv; + $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; + $sp[8]=$pts[2]; $sp[9]=$pts[3]-1; + $sp[10]=$pts[4]+1; $sp[11]=$pts[5]; + $img->FilledPolygon($sp,4); + } + elseif( $accy_neg < 0 ) { + $nsp[6]=$pts[4]+$ssh; $nsp[7]=$pts[5]-$ssv; + $nsp[8]=$pts[4]+1; $nsp[9]=$pts[5]; + $img->FilledPolygon($nsp,4); + } + $img->PopColor(); + } + } + + + // If value is NULL or 0, then don't draw a bar at all + if ($this->plots[$j]->coords[0][$i] == 0 ) continue; + + if( $this->plots[$j]->grad ) { + $grad = new Gradient($img); + $grad->FilledRectangle( + $pts[2],$pts[3], + $pts[6],$pts[7], + $this->plots[$j]->grad_fromcolor, + $this->plots[$j]->grad_tocolor, + $this->plots[$j]->grad_style); + } else { + if (is_array($this->plots[$j]->fill_color) ) { + $numcolors = count($this->plots[$j]->fill_color); + $fillcolor = $this->plots[$j]->fill_color[$i % $numcolors]; + // If the bar is specified to be non filled then the fill color is false + if( $fillcolor !== false ) + $img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]); + } + else { + $fillcolor = $this->plots[$j]->fill_color; + if( $fillcolor !== false ) + $img->SetColor($this->plots[$j]->fill_color); + } + if( $fillcolor !== false ) + $img->FilledPolygon($pts); + $img->SetColor($this->plots[$j]->color); + } + + // Stroke the pattern + if( $this->plots[$j]->iPattern > -1 ) { + if( $pattern===NULL ) + $pattern = new RectPatternFactory(); + + $prect = $pattern->Create($this->plots[$j]->iPattern,$this->plots[$j]->iPatternColor,1); + $prect->SetDensity($this->plots[$j]->iPatternDensity); + if( $this->plots[$j]->coords[0][$i] < 0 ) { + $rx = $pts[0]; + $ry = $pts[1]; + } + else { + $rx = $pts[2]; + $ry = $pts[3]; + } + $width = abs($pts[4]-$pts[0])+1; + $height = abs($pts[1]-$pts[3])+1; + $prect->SetPos(new Rectangle($rx,$ry,$width,$height)); + $prect->Stroke($img); + } + + + // CSIM array + + if( $i < count($this->plots[$j]->csimtargets) ) { + // Create the client side image map + $rpts = $img->ArrRotate($pts); + $csimcoord=round($rpts[0]).", ".round($rpts[1]); + for( $k=1; $k < 4; ++$k){ + $csimcoord .= ", ".round($rpts[2*$k]).", ".round($rpts[2*$k+1]); + } + if( ! empty($this->plots[$j]->csimtargets[$i]) ) { + $this->csimareas.= 'csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\" "; + + if( ! empty($this->plots[$j]->csimwintargets[$i]) ) { + $this->csimareas.= " target=\"".$this->plots[$j]->csimwintargets[$i]."\" "; + } + + $sval=''; + if( !empty($this->plots[$j]->csimalts[$i]) ) { + $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]); + $this->csimareas .= " title=\"$sval\" "; + } + $this->csimareas .= " alt=\"$sval\" />\n"; + } + } + + $pts[] = $pts[0]; + $pts[] = $pts[1]; + $img->SetLineWeight($this->plots[$j]->line_weight); + $img->Polygon($pts); + $img->SetLineWeight(1); + } + + // Draw labels for each acc.bar + + $x=$pts[2]+($pts[4]-$pts[2])/2; + if($this->bar_shadow) $x += $ssh; + + // First stroke the accumulated value for the entire bar + // This value is always placed at the top/bottom of the bars + if( $accy_neg < 0 ) { + $y=$yscale->Translate($accy_neg); + $this->value->Stroke($img,$accy_neg,$x,$y); + } + else { + $y=$yscale->Translate($accy); + $this->value->Stroke($img,$accy,$x,$y); + } + + $accy = 0; + $accy_neg = 0; + for($j=0; $j < $this->nbrplots; ++$j ) { + + // We don't print 0 values in an accumulated bar plot + if( $this->plots[$j]->coords[0][$i] == 0 ) continue; + + if ($this->plots[$j]->coords[0][$i] > 0) { + $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); + $accyt=$yscale->Translate($accy); + if( $this->plots[$j]->valuepos=='center' ) { + $y = $accyt-($accyt-$yt)/2; + } + elseif( $this->plots[$j]->valuepos=='bottom' ) { + $y = $accyt; + } + else { // top or max + $y = $accyt-($accyt-$yt); + } + $accy+=$this->plots[$j]->coords[0][$i]; + if( $this->plots[$j]->valuepos=='center' ) { + $this->plots[$j]->value->SetAlign("center","center"); + $this->plots[$j]->value->SetMargin(0); + } + elseif( $this->plots[$j]->valuepos=='bottom' ) { + $this->plots[$j]->value->SetAlign('center','bottom'); + $this->plots[$j]->value->SetMargin(2); + } + else { + $this->plots[$j]->value->SetAlign('center','top'); + $this->plots[$j]->value->SetMargin(1); + } + } else { + $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); + $accyt=$yscale->Translate($accy_neg); + $accy_neg+=$this->plots[$j]->coords[0][$i]; + if( $this->plots[$j]->valuepos=='center' ) { + $y = $accyt-($accyt-$yt)/2; + } + elseif( $this->plots[$j]->valuepos=='bottom' ) { + $y = $accyt; + } + else { + $y = $accyt-($accyt-$yt); + } + if( $this->plots[$j]->valuepos=='center' ) { + $this->plots[$j]->value->SetAlign("center","center"); + $this->plots[$j]->value->SetMargin(0); + } + elseif( $this->plots[$j]->valuepos=='bottom' ) { + $this->plots[$j]->value->SetAlign('center',$j==0 ? 'bottom':'top'); + $this->plots[$j]->value->SetMargin(-2); + } + else { + $this->plots[$j]->value->SetAlign('center','bottom'); + $this->plots[$j]->value->SetMargin(-1); + } + } + $this->plots[$j]->value->Stroke($img,$this->plots[$j]->coords[0][$i],$x,$y); + } + + } + return true; + } +} // Class + +/* EOF */ +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvas.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvas.php new file mode 100644 index 0000000..123220c --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvas.php @@ -0,0 +1,95 @@ +Graph($aWidth,$aHeight,$aCachedName,$timeout,$inline); + } + +//--------------- +// PUBLIC METHODS + + function InitFrame() { + $this->StrokePlotArea(); + } + + // Method description + function Stroke($aStrokeFileName="") { + if( $this->texts != null ) { + for($i=0; $i < count($this->texts); ++$i) { + $this->texts[$i]->Stroke($this->img); + } + } + if( $this->iTables !== null ) { + for($i=0; $i < count($this->iTables); ++$i) { + $this->iTables[$i]->Stroke($this->img); + } + } + $this->StrokeTitles(); + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + if( !$_csim ) { + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans') ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + + // If the filename is given as the special _IMG_HANDLER + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); + return true; + } + } + } +} // Class + +/* EOF */ +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvtools.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvtools.php new file mode 100644 index 0000000..c557375 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_canvtools.php @@ -0,0 +1,515 @@ +g = $graph; + $this->w = $graph->img->width; + $this->h = $graph->img->height; + $this->ixmin = $xmin; + $this->ixmax = $xmax; + $this->iymin = $ymin; + $this->iymax = $ymax; + } + + function Set($xmin=0,$xmax=10,$ymin=0,$ymax=10) { + $this->ixmin = $xmin; + $this->ixmax = $xmax; + $this->iymin = $ymin; + $this->iymax = $ymax; + } + + function Translate($x,$y) { + $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); + $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); + return array($xp,$yp); + } + + function TranslateX($x) { + $xp = round(($x-$this->ixmin)/($this->ixmax - $this->ixmin) * $this->w); + return $xp; + } + + function TranslateY($y) { + $yp = round(($y-$this->iymin)/($this->iymax - $this->iymin) * $this->h); + return $yp; + } + +} + + +//=================================================== +// CLASS Shape +// Description: Methods to draw shapes on canvas +//=================================================== +class Shape { + private $img,$scale; + + function Shape($aGraph,$scale) { + $this->img = $aGraph->img; + $this->img->SetColor('black'); + $this->scale = $scale; + } + + function SetColor($aColor) { + $this->img->SetColor($aColor); + } + + function Line($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->Line($x1,$y1,$x2,$y2); + } + + function Polygon($p,$aClosed=false) { + $n=count($p); + for($i=0; $i < $n; $i+=2 ) { + $p[$i] = $this->scale->TranslateX($p[$i]); + $p[$i+1] = $this->scale->TranslateY($p[$i+1]); + } + $this->img->Polygon($p,$aClosed); + } + + function FilledPolygon($p) { + $n=count($p); + for($i=0; $i < $n; $i+=2 ) { + $p[$i] = $this->scale->TranslateX($p[$i]); + $p[$i+1] = $this->scale->TranslateY($p[$i+1]); + } + $this->img->FilledPolygon($p); + } + + + // Draw a bezier curve with defining points in the $aPnts array + // using $aSteps steps. + // 0=x0, 1=y0 + // 2=x1, 3=y1 + // 4=x2, 5=y2 + // 6=x3, 7=y3 + function Bezier($p,$aSteps=40) { + $x0 = $p[0]; + $y0 = $p[1]; + // Calculate coefficients + $cx = 3*($p[2]-$p[0]); + $bx = 3*($p[4]-$p[2])-$cx; + $ax = $p[6]-$p[0]-$cx-$bx; + $cy = 3*($p[3]-$p[1]); + $by = 3*($p[5]-$p[3])-$cy; + $ay = $p[7]-$p[1]-$cy-$by; + + // Step size + $delta = 1.0/$aSteps; + + $x_old = $x0; + $y_old = $y0; + for($t=$delta; $t<=1.0; $t+=$delta) { + $tt = $t*$t; $ttt=$tt*$t; + $x = $ax*$ttt + $bx*$tt + $cx*$t + $x0; + $y = $ay*$ttt + $by*$tt + $cy*$t + $y0; + $this->Line($x_old,$y_old,$x,$y); + $x_old = $x; + $y_old = $y; + } + $this->Line($x_old,$y_old,$p[6],$p[7]); + } + + function Rectangle($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->Rectangle($x1,$y1,$x2,$y2); + } + + function FilledRectangle($x1,$y1,$x2,$y2) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + $this->img->FilledRectangle($x1,$y1,$x2,$y2); + } + + function Circle($x1,$y1,$r) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + if( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->Circle($x1,$y1,$r); + } + + function FilledCircle($x1,$y1,$r) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + if( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->FilledCircle($x1,$y1,$r); + } + + function RoundedRectangle($x1,$y1,$x2,$y2,$r=null) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + + if( $r == null ) + $r = 5; + elseif( $r >= 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->RoundedRectangle($x1,$y1,$x2,$y2,$r); + } + + function FilledRoundedRectangle($x1,$y1,$x2,$y2,$r=null) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + + if( $r == null ) + $r = 5; + elseif( $r > 0 ) + $r = $this->scale->TranslateX($r); + else + $r = -$r; + $this->img->FilledRoundedRectangle($x1,$y1,$x2,$y2,$r); + } + + function ShadowRectangle($x1,$y1,$x2,$y2,$fcolor=false,$shadow_width=null,$shadow_color=array(102,102,102)) { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + list($x2,$y2) = $this->scale->Translate($x2,$y2); + if( $shadow_width == null ) + $shadow_width=4; + else + $shadow_width=$this->scale->TranslateX($shadow_width); + $this->img->ShadowRectangle($x1,$y1,$x2,$y2,$fcolor,$shadow_width,$shadow_color); + } + + function SetTextAlign($halign,$valign="bottom") { + $this->img->SetTextAlign($halign,$valign="bottom"); + } + + function StrokeText($x1,$y1,$txt,$dir=0,$paragraph_align="left") { + list($x1,$y1) = $this->scale->Translate($x1,$y1); + $this->img->StrokeText($x1,$y1,$txt,$dir,$paragraph_align); + } + + // A rounded rectangle where one of the corner has been moved "into" the + // rectangle 'iw' width and 'ih' height. Corners: + // 0=Top left, 1=top right, 2=bottom right, 3=bottom left + function IndentedRectangle($xt,$yt,$w,$h,$iw=0,$ih=0,$aCorner=3,$aFillColor="",$r=4) { + + list($xt,$yt) = $this->scale->Translate($xt,$yt); + list($w,$h) = $this->scale->Translate($w,$h); + list($iw,$ih) = $this->scale->Translate($iw,$ih); + + $xr = $xt + $w - 0; + $yl = $yt + $h - 0; + + switch( $aCorner ) { + case 0: // Upper left + + // Bottom line, left & right arc + $this->img->Line($xt+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Right line, Top right arc + $this->img->Line($xr,$yt+$r,$xr,$yl-$r); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Top line, Top left arc + $this->img->Line($xt+$iw+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$iw+$r,$yt+$r,$r*2,$r*2,180,270); + + // Left line + $this->img->Line($xt,$yt+$ih+$r,$xt,$yl-$r); + + // Indent horizontal, Lower left arc + $this->img->Line($xt+$r,$yt+$ih,$xt+$iw-$r,$yt+$ih); + $this->img->Arc($xt+$r,$yt+$ih+$r,$r*2,$r*2,180,270); + + // Indent vertical, Indent arc + $this->img->Line($xt+$iw,$yt+$r,$xt+$iw,$yt+$ih-$r); + $this->img->Arc($xt+$iw-$r,$yt+$ih-$r,$r*2,$r*2,0,90); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xr-$r,$yl-$r,$bc); + $this->img->PopColor(); + } + + break; + + case 1: // Upper right + + // Bottom line, left & right arc + $this->img->Line($xt+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Left line, Top left arc + $this->img->Line($xt,$yt+$r,$xt,$yl-$r); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + + // Top line, Top right arc + $this->img->Line($xt+$r,$yt,$xr-$iw-$r,$yt); + $this->img->Arc($xr-$iw-$r,$yt+$r,$r*2,$r*2,270,360); + + // Right line + $this->img->Line($xr,$yt+$ih+$r,$xr,$yl-$r); + + // Indent horizontal, Lower right arc + $this->img->Line($xr-$iw+$r,$yt+$ih,$xr-$r,$yt+$ih); + $this->img->Arc($xr-$r,$yt+$ih+$r,$r*2,$r*2,270,360); + + // Indent vertical, Indent arc + $this->img->Line($xr-$iw,$yt+$r,$xr-$iw,$yt+$ih-$r); + $this->img->Arc($xr-$iw+$r,$yt+$ih-$r,$r*2,$r*2,90,180); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xt+$r,$yl-$r,$bc); + $this->img->PopColor(); + } + + break; + + case 2: // Lower right + // Top line, Top left & Top right arc + $this->img->Line($xt+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Left line, Bottom left arc + $this->img->Line($xt,$yt+$r,$xt,$yl-$r); + $this->img->Arc($xt+$r,$yl-$r,$r*2,$r*2,90,180); + + // Bottom line, Bottom right arc + $this->img->Line($xt+$r,$yl,$xr-$iw-$r,$yl); + $this->img->Arc($xr-$iw-$r,$yl-$r,$r*2,$r*2,0,90); + + // Right line + $this->img->Line($xr,$yt+$r,$xr,$yl-$ih-$r); + + // Indent horizontal, Lower right arc + $this->img->Line($xr-$r,$yl-$ih,$xr-$iw+$r,$yl-$ih); + $this->img->Arc($xr-$r,$yl-$ih-$r,$r*2,$r*2,0,90); + + // Indent vertical, Indent arc + $this->img->Line($xr-$iw,$yl-$r,$xr-$iw,$yl-$ih+$r); + $this->img->Arc($xr-$iw+$r,$yl-$ih+$r,$r*2,$r*2,180,270); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xt+$r,$yt+$r,$bc); + $this->img->PopColor(); + } + + break; + + case 3: // Lower left + // Top line, Top left & Top right arc + $this->img->Line($xt+$r,$yt,$xr-$r,$yt); + $this->img->Arc($xt+$r,$yt+$r,$r*2,$r*2,180,270); + $this->img->Arc($xr-$r,$yt+$r,$r*2,$r*2,270,360); + + // Right line, Bottom right arc + $this->img->Line($xr,$yt+$r,$xr,$yl-$r); + $this->img->Arc($xr-$r,$yl-$r,$r*2,$r*2,0,90); + + // Bottom line, Bottom left arc + $this->img->Line($xt+$iw+$r,$yl,$xr-$r,$yl); + $this->img->Arc($xt+$iw+$r,$yl-$r,$r*2,$r*2,90,180); + + // Left line + $this->img->Line($xt,$yt+$r,$xt,$yl-$ih-$r); + + // Indent horizontal, Lower left arc + $this->img->Line($xt+$r,$yl-$ih,$xt+$iw-$r,$yl-$ih); + $this->img->Arc($xt+$r,$yl-$ih-$r,$r*2,$r*2,90,180); + + // Indent vertical, Indent arc + $this->img->Line($xt+$iw,$yl-$ih+$r,$xt+$iw,$yl-$r); + $this->img->Arc($xt+$iw-$r,$yl-$ih+$r,$r*2,$r*2,270,360); + + if( $aFillColor != '' ) { + $bc = $this->img->current_color_name; + $this->img->PushColor($aFillColor); + $this->img->FillToBorder($xr-$r,$yt+$r,$bc); + $this->img->PopColor(); + } + + break; + } + } +} + + +//=================================================== +// CLASS RectangleText +// Description: Draws a text paragraph inside a +// rounded, possible filled, rectangle. +//=================================================== +class CanvasRectangleText { + private $ix,$iy,$iw,$ih,$ir=4; + private $iTxt,$iColor='black',$iFillColor='',$iFontColor='black'; + private $iParaAlign='center'; + private $iAutoBoxMargin=5; + private $iShadowWidth=3,$iShadowColor=''; + + function CanvasRectangleText($aTxt='',$xl=0,$yt=0,$w=0,$h=0) { + $this->iTxt = new Text($aTxt); + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function SetShadow($aColor='gray',$aWidth=3) { + $this->iShadowColor = $aColor; + $this->iShadowWidth = $aWidth; + } + + function SetFont($FontFam,$aFontStyle,$aFontSize=12) { + $this->iTxt->SetFont($FontFam,$aFontStyle,$aFontSize); + } + + function SetTxt($aTxt) { + $this->iTxt->Set($aTxt); + } + + function ParagraphAlign($aParaAlign) { + $this->iParaAlign = $aParaAlign; + } + + function SetFillColor($aFillColor) { + $this->iFillColor = $aFillColor; + } + + function SetAutoMargin($aMargin) { + $this->iAutoBoxMargin=$aMargin; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetFontColor($aColor) { + $this->iFontColor = $aColor; + } + + function SetPos($xl=0,$yt=0,$w=0,$h=0) { + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function Pos($xl=0,$yt=0,$w=0,$h=0) { + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function Set($aTxt,$xl,$yt,$w=0,$h=0) { + $this->iTxt->Set($aTxt); + $this->ix = $xl; + $this->iy = $yt; + $this->iw = $w; + $this->ih = $h; + } + + function SetCornerRadius($aRad=5) { + $this->ir = $aRad; + } + + function Stroke($aImg,$scale) { + + // If coordinates are specifed as negative this means we should + // treat them as abolsute (pixels) coordinates + if( $this->ix > 0 ) { + $this->ix = $scale->TranslateX($this->ix) ; + } + else { + $this->ix = -$this->ix; + } + + if( $this->iy > 0 ) { + $this->iy = $scale->TranslateY($this->iy) ; + } + else { + $this->iy = -$this->iy; + } + + list($this->iw,$this->ih) = $scale->Translate($this->iw,$this->ih) ; + + if( $this->iw == 0 ) + $this->iw = round($this->iTxt->GetWidth($aImg) + $this->iAutoBoxMargin); + if( $this->ih == 0 ) { + $this->ih = round($this->iTxt->GetTextHeight($aImg) + $this->iAutoBoxMargin); + } + + if( $this->iShadowColor != '' ) { + $aImg->PushColor($this->iShadowColor); + $aImg->FilledRoundedRectangle($this->ix+$this->iShadowWidth, + $this->iy+$this->iShadowWidth, + $this->ix+$this->iw-1+$this->iShadowWidth, + $this->iy+$this->ih-1+$this->iShadowWidth, + $this->ir); + $aImg->PopColor(); + } + + if( $this->iFillColor != '' ) { + $aImg->PushColor($this->iFillColor); + $aImg->FilledRoundedRectangle($this->ix,$this->iy, + $this->ix+$this->iw-1, + $this->iy+$this->ih-1, + $this->ir); + $aImg->PopColor(); + } + + if( $this->iColor != '' ) { + $aImg->PushColor($this->iColor); + $aImg->RoundedRectangle($this->ix,$this->iy, + $this->ix+$this->iw-1, + $this->iy+$this->ih-1, + $this->ir); + $aImg->PopColor(); + } + + $this->iTxt->Align('center','center'); + $this->iTxt->ParagraphAlign($this->iParaAlign); + $this->iTxt->SetColor($this->iFontColor); + $this->iTxt->Stroke($aImg, $this->ix+$this->iw/2, $this->iy+$this->ih/2); + + return array($this->iw, $this->ih); + + } + +} + + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_date.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_date.php new file mode 100644 index 0000000..f0aac58 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_date.php @@ -0,0 +1,499 @@ +type=$aType; + $this->scale=array($aMin,$aMax); + $this->world_size=$aMax-$aMin; + $this->ticks = new LinearTicks(); + $this->intscale=true; + } + + +//------------------------------------------------------------------------------------------ +// Utility Function AdjDate() +// Description: Will round a given time stamp to an even year, month or day +// argument. +//------------------------------------------------------------------------------------------ + + function AdjDate($aTime,$aRound=0,$aYearType=false,$aMonthType=false,$aDayType=false) { + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h=0;$i=0;$s=0; + if( $aYearType !== false ) { + $yearAdj = array(0=>1, 1=>2, 2=>5); + if( $aRound == 0 ) { + $y = floor($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; + } + else { + ++$y; + $y = ceil($y/$yearAdj[$aYearType])*$yearAdj[$aYearType]; + } + $m=1;$d=1; + } + elseif( $aMonthType !== false ) { + $monthAdj = array(0=>1, 1=>6); + if( $aRound == 0 ) { + $m = floor($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; + $d=1; + } + else { + ++$m; + $m = ceil($m/$monthAdj[$aMonthType])*$monthAdj[$aMonthType]; + $d=1; + } + } + elseif( $aDayType !== false ) { + if( $aDayType == 0 ) { + if( $aRound == 1 ) { + //++$d; + $h=23;$i=59;$s=59; + } + } + else { + // Adjust to an even week boundary. + $w = (int)date('w',$aTime); // Day of week 0=Sun, 6=Sat + if( true ) { // Adjust to start on Mon + if( $w==0 ) $w=6; + else --$w; + } + if( $aRound == 0 ) { + $d -= $w; + } + else { + $d += (7-$w); + $h=23;$i=59;$s=59; + } + } + } + return mktime($h,$i,$s,$m,$d,$y); + + } + +//------------------------------------------------------------------------------------------ +// Wrapper for AdjDate that will round a timestamp to an even date rounding +// it downwards. +//------------------------------------------------------------------------------------------ + function AdjStartDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { + return $this->AdjDate($aTime,0,$aYearType,$aMonthType,$aDayType); + } + +//------------------------------------------------------------------------------------------ +// Wrapper for AdjDate that will round a timestamp to an even date rounding +// it upwards +//------------------------------------------------------------------------------------------ + function AdjEndDate($aTime,$aYearType=false,$aMonthType=false,$aDayType=false) { + return $this->AdjDate($aTime,1,$aYearType,$aMonthType,$aDayType); + } + +//------------------------------------------------------------------------------------------ +// Utility Function AdjTime() +// Description: Will round a given time stamp to an even time according to +// argument. +//------------------------------------------------------------------------------------------ + + function AdjTime($aTime,$aRound=0,$aHourType=false,$aMinType=false,$aSecType=false) { + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); $s = (int)date('s',$aTime); + if( $aHourType !== false ) { + $aHourType %= 6; + $hourAdj = array(0=>1, 1=>2, 2=>3, 3=>4, 4=>6, 5=>12); + if( $aRound == 0 ) + $h = floor($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; + else { + if( ($h % $hourAdj[$aHourType]==0) && ($i > 0 || $s > 0) ) { + $h++; + } + $h = ceil($h/$hourAdj[$aHourType])*$hourAdj[$aHourType]; + if( $h >= 24 ) { + $aTime += 86400; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h -= 24; + } + } + $i=0;$s=0; + } + elseif( $aMinType !== false ) { + $aMinType %= 5; + $minAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); + if( $aRound == 0 ) { + $i = floor($i/$minAdj[$aMinType])*$minAdj[$aMinType]; + } + else { + if( ($i % $minAdj[$aMinType]==0) && $s > 0 ) { + $i++; + } + $i = ceil($i/$minAdj[$aMinType])*$minAdj[$aMinType]; + if( $i >= 60) { + $aTime += 3600; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = 0; + } + } + $s=0; + } + elseif( $aSecType !== false ) { + $aSecType %= 5; + $secAdj = array(0=>1, 1=>5, 2=>10, 3=>15, 4=>30); + if( $aRound == 0 ) { + $s = floor($s/$secAdj[$aSecType])*$secAdj[$aSecType]; + } + else { + $s = ceil($s/$secAdj[$aSecType]*1.0)*$secAdj[$aSecType]; + if( $s >= 60) { + $s=0; + $aTime += 60; + $y = (int)date('Y',$aTime); $m = (int)date('m',$aTime); $d = (int)date('d',$aTime); + $h = (int)date('H',$aTime); $i = (int)date('i',$aTime); + } + } + } + return mktime($h,$i,$s,$m,$d,$y); + } + +//------------------------------------------------------------------------------------------ +// Wrapper for AdjTime that will round a timestamp to an even time rounding +// it downwards. +// Example: AdjStartTime(mktime(18,27,13,2,22,2005),false,2) => 18:20 +//------------------------------------------------------------------------------------------ + function AdjStartTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { + return $this->AdjTime($aTime,0,$aHourType,$aMinType,$aSecType); + } + +//------------------------------------------------------------------------------------------ +// Wrapper for AdjTime that will round a timestamp to an even time rounding +// it upwards +// Example: AdjEndTime(mktime(18,27,13,2,22,2005),false,2) => 18:30 +//------------------------------------------------------------------------------------------ + function AdjEndTime($aTime,$aHourType=false,$aMinType=false,$aSecType=false) { + return $this->AdjTime($aTime,1,$aHourType,$aMinType,$aSecType); + } + +//------------------------------------------------------------------------------------------ +// DateAutoScale +// Autoscale a date axis given start and end time +// Returns an array ($start,$end,$major,$minor,$format) +//------------------------------------------------------------------------------------------ + function DoDateAutoScale($aStartTime,$aEndTime,$aDensity=0,$aAdjust=true) { + // Format of array + // array ( Decision point, array( array( Major-scale-step-array ), + // array( Minor-scale-step-array ), + // array( 0=date-adjust, 1=time-adjust, adjustment-alignment) ) + // + $scalePoints = + array( + /* Intervall larger than 10 years */ + SECPERYEAR*10,array(array(SECPERYEAR*5,SECPERYEAR*2), + array(SECPERYEAR), + array(0,YEARADJ_1, 0,YEARADJ_1) ), + + /* Intervall larger than 2 years */ + SECPERYEAR*2,array(array(SECPERYEAR),array(SECPERYEAR), + array(0,YEARADJ_1) ), + + /* Intervall larger than 90 days (approx 3 month) */ + SECPERDAY*90,array(array(SECPERDAY*30,SECPERDAY*14,SECPERDAY*7,SECPERDAY), + array(SECPERDAY*5,SECPERDAY*7,SECPERDAY,SECPERDAY), + array(0,MONTHADJ_1, 0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1)), + + /* Intervall larger than 30 days (approx 1 month) */ + SECPERDAY*30,array(array(SECPERDAY*14,SECPERDAY*7,SECPERDAY*2, SECPERDAY), + array(SECPERDAY,SECPERDAY,SECPERDAY,SECPERDAY), + array(0,DAYADJ_WEEK, 0,DAYADJ_1, 0,DAYADJ_1, 0,DAYADJ_1)), + + /* Intervall larger than 7 days */ + SECPERDAY*7,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2), + array(SECPERHOUR*6,SECPERHOUR*3,SECPERHOUR,SECPERHOUR), + array(0,DAYADJ_1, 1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1)), + + /* Intervall larger than 1 day */ + SECPERDAY,array(array(SECPERDAY,SECPERHOUR*12,SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR), + array(SECPERHOUR*6,SECPERHOUR*2,SECPERHOUR,SECPERHOUR,SECPERHOUR), + array(1,HOURADJ_12, 1,HOURADJ_6, 1,HOURADJ_1, 1,HOURADJ_1)), + + /* Intervall larger than 12 hours */ + SECPERHOUR*12,array(array(SECPERHOUR*2,SECPERHOUR,SECPERMIN*30,900,600), + array(1800,1800,900,300,300), + array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 2 hours */ + SECPERHOUR*2,array(array(SECPERHOUR,SECPERMIN*30,900,600,300), + array(1800,900,300,120,60), + array(1,HOURADJ_1, 1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 1 hours */ + SECPERHOUR,array(array(SECPERMIN*30,900,600,300),array(900,300,120,60), + array(1,MINADJ_30, 1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5) ), + + /* Intervall larger than 30 min */ + SECPERMIN*30,array(array(SECPERMIN*15,SECPERMIN*10,SECPERMIN*5,SECPERMIN), + array(300,300,60,10), + array(1,MINADJ_15, 1,MINADJ_10, 1,MINADJ_5, 1,MINADJ_1)), + + /* Intervall larger than 1 min */ + SECPERMIN,array(array(SECPERMIN,15,10,5), + array(15,5,2,1), + array(1,MINADJ_1, 1,SECADJ_15, 1,SECADJ_10, 1,SECADJ_5)), + + /* Intervall larger than 10 sec */ + 10,array(array(5,2), + array(1,1), + array(1,SECADJ_5, 1,SECADJ_1)), + + /* Intervall larger than 1 sec */ + 1,array(array(1), + array(1), + array(1,SECADJ_1)), + ); + + $ns = count($scalePoints); + // Establish major and minor scale units for the date scale + $diff = $aEndTime - $aStartTime; + if( $diff < 1 ) return false; + $done=false; + $i=0; + while( ! $done ) { + if( $diff > $scalePoints[2*$i] ) { + // Get major and minor scale for this intervall + $scaleSteps = $scalePoints[2*$i+1]; + $major = $scaleSteps[0][min($aDensity,count($scaleSteps[0])-1)]; + // Try to find out which minor step looks best + $minor = $scaleSteps[1][min($aDensity,count($scaleSteps[1])-1)]; + if( $aAdjust ) { + // Find out how we should align the start and end timestamps + $idx = 2*min($aDensity,floor(count($scaleSteps[2])/2)-1); + if( $scaleSteps[2][$idx] === 0 ) { + // Use date adjustment + $adj = $scaleSteps[2][$idx+1]; + if( $adj >= 30 ) { + $start = $this->AdjStartDate($aStartTime,$adj-30); + $end = $this->AdjEndDate($aEndTime,$adj-30); + } + elseif( $adj >= 20 ) { + $start = $this->AdjStartDate($aStartTime,false,$adj-20); + $end = $this->AdjEndDate($aEndTime,false,$adj-20); + } + else { + $start = $this->AdjStartDate($aStartTime,false,false,$adj); + $end = $this->AdjEndDate($aEndTime,false,false,$adj); + // We add 1 second for date adjustment to make sure we end on 00:00 the following day + // This makes the final major tick be srawn when we step day-by-day instead of ending + // on xx:59:59 which would not draw the final major tick + $end++; + } + } + else { + // Use time adjustment + $adj = $scaleSteps[2][$idx+1]; + if( $adj >= 30 ) { + $start = $this->AdjStartTime($aStartTime,$adj-30); + $end = $this->AdjEndTime($aEndTime,$adj-30); + } + elseif( $adj >= 20 ) { + $start = $this->AdjStartTime($aStartTime,false,$adj-20); + $end = $this->AdjEndTime($aEndTime,false,$adj-20); + } + else { + $start = $this->AdjStartTime($aStartTime,false,false,$adj); + $end = $this->AdjEndTime($aEndTime,false,false,$adj); + } + } + } + // If the overall date span is larger than 1 day ten we show date + $format = ''; + if( ($end-$start) > SECPERDAY ) { + $format = 'Y-m-d '; + } + // If the major step is less than 1 day we need to whow hours + min + if( $major < SECPERDAY ) { + $format .= 'H:i'; + } + // If the major step is less than 1 min we need to show sec + if( $major < 60 ) { + $format .= ':s'; + } + $done=true; + } + ++$i; + } + return array($start,$end,$major,$minor,$format); + } + + // Overrides the automatic determined date format. Must be a valid date() format string + function SetDateFormat($aFormat) { + $this->date_format = $aFormat; + $this->ticks->SetLabelDateFormat($this->date_format); + } + + function AdjustForDST($aFlg=true) { + $this->ticks->AdjustForDST($aFlg); + } + + + function SetDateAlign($aStartAlign,$aEndAlign=false) { + if( $aEndAlign === false ) { + $aEndAlign=$aStartAlign; + } + $this->iStartAlign = $aStartAlign; + $this->iEndAlign = $aEndAlign; + } + + function SetTimeAlign($aStartAlign,$aEndAlign=false) { + if( $aEndAlign === false ) { + $aEndAlign=$aStartAlign; + } + $this->iStartTimeAlign = $aStartAlign; + $this->iEndTimeAlign = $aEndAlign; + } + + + function AutoScale($img,$aStartTime,$aEndTime,$aNumSteps,$_adummy=false) { + // We need to have one dummy argument to make the signature of AutoScale() + // identical to LinearScale::AutoScale + if( $aStartTime == $aEndTime ) { + // Special case when we only have one data point. + // Create a small artifical intervall to do the autoscaling + $aStartTime -= 10; + $aEndTime += 10; + } + $done=false; + $i=0; + while( ! $done && $i < 5) { + list($adjstart,$adjend,$maj,$min,$format) = $this->DoDateAutoScale($aStartTime,$aEndTime,$i); + $n = floor(($adjend-$adjstart)/$maj); + if( $n * 1.7 > $aNumSteps ) { + $done=true; + } + $i++; + } + + /* + if( 0 ) { // DEBUG + echo " Start =".date("Y-m-d H:i:s",$aStartTime)."
    "; + echo " End =".date("Y-m-d H:i:s",$aEndTime)."
    "; + echo "Adj Start =".date("Y-m-d H:i:s",$adjstart)."
    "; + echo "Adj End =".date("Y-m-d H:i:s",$adjend)."

    "; + echo "Major = $maj s, ".floor($maj/60)."min, ".floor($maj/3600)."h, ".floor($maj/86400)."day
    "; + echo "Min = $min s, ".floor($min/60)."min, ".floor($min/3600)."h, ".floor($min/86400)."day
    "; + echo "Format=$format

    "; + } + */ + + if( $this->iStartTimeAlign !== false && $this->iStartAlign !== false ) { + JpGraphError::RaiseL(3001); +//('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both'); + } + + if( $this->iStartTimeAlign !== false ) { + if( $this->iStartTimeAlign >= 30 ) { + $adjstart = $this->AdjStartTime($aStartTime,$this->iStartTimeAlign-30); + } + elseif( $this->iStartTimeAlign >= 20 ) { + $adjstart = $this->AdjStartTime($aStartTime,false,$this->iStartTimeAlign-20); + } + else { + $adjstart = $this->AdjStartTime($aStartTime,false,false,$this->iStartTimeAlign); + } + } + if( $this->iEndTimeAlign !== false ) { + if( $this->iEndTimeAlign >= 30 ) { + $adjend = $this->AdjEndTime($aEndTime,$this->iEndTimeAlign-30); + } + elseif( $this->iEndTimeAlign >= 20 ) { + $adjend = $this->AdjEndTime($aEndTime,false,$this->iEndTimeAlign-20); + } + else { + $adjend = $this->AdjEndTime($aEndTime,false,false,$this->iEndTimeAlign); + } + } + + + + if( $this->iStartAlign !== false ) { + if( $this->iStartAlign >= 30 ) { + $adjstart = $this->AdjStartDate($aStartTime,$this->iStartAlign-30); + } + elseif( $this->iStartAlign >= 20 ) { + $adjstart = $this->AdjStartDate($aStartTime,false,$this->iStartAlign-20); + } + else { + $adjstart = $this->AdjStartDate($aStartTime,false,false,$this->iStartAlign); + } + } + if( $this->iEndAlign !== false ) { + if( $this->iEndAlign >= 30 ) { + $adjend = $this->AdjEndDate($aEndTime,$this->iEndAlign-30); + } + elseif( $this->iEndAlign >= 20 ) { + $adjend = $this->AdjEndDate($aEndTime,false,$this->iEndAlign-20); + } + else { + $adjend = $this->AdjEndDate($aEndTime,false,false,$this->iEndAlign); + } + } + $this->Update($img,$adjstart,$adjend); + if( ! $this->ticks->IsSpecified() ) + $this->ticks->Set($maj,$min); + if( $this->date_format == '' ) + $this->ticks->SetLabelDateFormat($format); + else + $this->ticks->SetLabelDateFormat($this->date_format); + } +} + + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_errhandler.inc.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_errhandler.inc.php new file mode 100644 index 0000000..04c47d2 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_errhandler.inc.php @@ -0,0 +1,278 @@ +lt = $_jpg_messages; + } + + function Get($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { + GLOBAL $__jpg_err_locale; + if( !isset($this->lt[$errnbr]) ) { + return 'Internal error: The specified error message ('.$errnbr.') does not exist in the chosen locale ('.$__jpg_err_locale.')'; + } + $ea = $this->lt[$errnbr]; + $j=0; + if( $a1 !== null ) { + $argv[$j++] = $a1; + if( $a2 !== null ) { + $argv[$j++] = $a2; + if( $a3 !== null ) { + $argv[$j++] = $a3; + if( $a4 !== null ) { + $argv[$j++] = $a4; + if( $a5 !== null ) { + $argv[$j++] = $a5; + } + } + } + } + } + $numargs = $j; + if( $ea[1] != $numargs ) { + // Error message argument count do not match. + // Just return the error message without arguments. + return $ea[0]; + } + switch( $numargs ) { + case 1: + $msg = sprintf($ea[0],$argv[0]); + break; + case 2: + $msg = sprintf($ea[0],$argv[0],$argv[1]); + break; + case 3: + $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2]); + break; + case 4: + $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3]); + break; + case 5: + $msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3],$argv[4]); + break; + case 0: + default: + $msg = sprintf($ea[0]); + break; + } + return $msg; + } +} + +// +// A wrapper class that is used to access the specified error object +// (to hide the global error parameter and avoid having a GLOBAL directive +// in all methods. +// +class JpGraphError { + private static $__jpg_err; + public static function Install($aErrObject) { + self::$__jpg_err = new $aErrObject; + } + public static function Raise($aMsg,$aHalt=true){ + self::$__jpg_err->Raise($aMsg,$aHalt); + } + public static function SetErrLocale($aLoc) { + GLOBAL $__jpg_err_locale ; + $__jpg_err_locale = $aLoc; + } + public static function RaiseL($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) { + $t = new ErrMsgText(); + $msg = $t->Get($errnbr,$a1,$a2,$a3,$a4,$a5); + self::$__jpg_err->Raise($msg); + } +} + +// +// First of all set up a default error handler +// + +//============================================================= +// The default trivial text error handler. +//============================================================= +class JpGraphErrObject { + + protected $iTitle = "JpGraph Error"; + protected $iDest = false; + + + function JpGraphErrObject() { + // Empty. Reserved for future use + } + + function SetTitle($aTitle) { + $this->iTitle = $aTitle; + } + + function SetStrokeDest($aDest) { + $this->iDest = $aDest; + } + + // If aHalt is true then execution can't continue. Typical used for fatal errors + function Raise($aMsg,$aHalt=true) { + $aMsg = $this->iTitle.' '.$aMsg; + if ($this->iDest) { + $f = @fopen($this->iDest,'a'); + if( $f ) { + @fwrite($f,$aMsg); + @fclose($f); + } + } + else { + echo $aMsg; + } + if( $aHalt ) + die(); + } +} + +//============================================================== +// An image based error handler +//============================================================== +class JpGraphErrObjectImg extends JpGraphErrObject { + + function Raise($aMsg,$aHalt=true) { + $img_iconerror = + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaV'. + 'BMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. + 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpY'. + 'iYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'. + 'IAAAsSAdLdfvwAAAAHdElNRQfTBgISOCqusfs5AAABLUlEQVR4'. + '2tWV3XKCMBBGWfkranCIVClKLd/7P2Q3QsgCxjDTq+6FE2cPH+'. + 'xJ0Ogn2lQbsT+Wrs+buAZAV4W5T6Bs0YXBBwpKgEuIu+JERAX6'. + 'wM2rHjmDdEITmsQEEmWADgZm6rAjhXsoMGY9B/NZBwJzBvn+e3'. + 'wHntCAJdGu9SviwIwoZVDxPB9+Rc0TSEbQr0j3SA1gwdSn6Db0'. + '6Tm1KfV6yzWGQO7zdpvyKLKBDmRFjzeB3LYgK7r6A/noDAfjtS'. + 'IXaIzbJSv6WgUebTMV4EoRB8a2mQiQjgtF91HdKDKZ1gtFtQjk'. + 'YcWaR5OKOhkYt+ZsTFdJRfPAApOpQYJTNHvCRSJR6SJngQadfc'. + 'vd69OLMddVOPCGVnmrFD8bVYd3JXfxXPtLR/+mtv59/ALWiiMx'. + 'qL72fwAAAABJRU5ErkJggg==' ; + + if( function_exists("imagetypes") ) + $supported = imagetypes(); + else + $supported = 0; + + if( !function_exists('imagecreatefromstring') ) + $supported = 0; + + if( ob_get_length() || headers_sent() || !($supported & IMG_PNG) ) { + // Special case for headers already sent or that the installation doesn't support + // the PNG format (which the error icon is encoded in). + // Dont return an image since it can't be displayed + die($this->iTitle.' '.$aMsg); + } + + $aMsg = wordwrap($aMsg,55); + $lines = substr_count($aMsg,"\n"); + + // Create the error icon GD + $erricon = Image::CreateFromString(base64_decode($img_iconerror)); + + // Create an image that contains the error text. + $w=400; + $h=100 + 15*max(0,$lines-3); + + $img = new Image($w,$h); + + + // Drop shadow + $img->SetColor("gray"); + $img->FilledRectangle(5,5,$w-1,$h-1,10); + $img->SetColor("gray:0.7"); + $img->FilledRectangle(5,5,$w-3,$h-3,10); + + // Window background + $img->SetColor("lightblue"); + $img->FilledRectangle(1,1,$w-5,$h-5); + $img->CopyCanvasH($img->img,$erricon,5,30,0,0,40,40); + + // Window border + $img->SetColor("black"); + $img->Rectangle(1,1,$w-5,$h-5); + $img->Rectangle(0,0,$w-4,$h-4); + + // Window top row + $img->SetColor("darkred"); + for($y=3; $y < 18; $y += 2 ) + $img->Line(1,$y,$w-6,$y); + + // "White shadow" + $img->SetColor("white"); + + // Left window edge + $img->Line(2,2,2,$h-5); + $img->Line(2,2,$w-6,2); + + // "Gray button shadow" + $img->SetColor("darkgray"); + + // Gray window shadow + $img->Line(2,$h-6,$w-5,$h-6); + $img->Line(3,$h-7,$w-5,$h-7); + + // Window title + $m = floor($w/2-5); + $l = 100; + $img->SetColor("lightgray:1.3"); + $img->FilledRectangle($m-$l,2,$m+$l,16); + + // Stroke text + $img->SetColor("darkred"); + $img->SetFont(FF_FONT2,FS_BOLD); + $img->StrokeText($m-50,15,$this->iTitle); + $img->SetColor("black"); + $img->SetFont(FF_FONT1,FS_NORMAL); + $txt = new Text($aMsg,52,25); + $txt->Align("left","top"); + $txt->Stroke($img); + if ($this->iDest) { + $img->Stream($this->iDest); + } else { + $img->Headers(); + $img->Stream(); + } + if( $aHalt ) + die(); + } +} + + +// Install the default error handler +if( USE_IMAGE_ERROR_HANDLER ) { + JpGraphError::Install("JpGraphErrObjectImg"); +} +else { + JpGraphError::Install("JpGraphErrObject"); +} + + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_error.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_error.php new file mode 100644 index 0000000..a9ed98b --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_error.php @@ -0,0 +1,156 @@ +Plot($datay,$datax); + $this->numpoints /= 2; + } +//--------------- +// PUBLIC METHODS + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + if( $this->center ) { + $a=0.5; $b=0.5; + ++$this->numpoints; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); + } + + // Method description + function Stroke($img,$xscale,$yscale) { + $numpoints=count($this->coords[0])/2; + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$numpoints ) + JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); +//("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); + else + $exist_x = true; + } + else + $exist_x = false; + + for( $i=0; $i<$numpoints; ++$i) { + if( $exist_x ) + $x=$this->coords[1][$i]; + else + $x=$i; + + if( !is_numeric($x) || + !is_numeric($this->coords[0][$i*2]) || !is_numeric($this->coords[0][$i*2+1]) ) { + continue; + } + + $xt = $xscale->Translate($x); + $yt1 = $yscale->Translate($this->coords[0][$i*2]); + $yt2 = $yscale->Translate($this->coords[0][$i*2+1]); + $img->Line($xt,$yt1,$xt,$yt2); + $img->Line($xt-$this->errwidth,$yt1,$xt+$this->errwidth,$yt1); + $img->Line($xt-$this->errwidth,$yt2,$xt+$this->errwidth,$yt2); + } + return true; + } +} // Class + + +//=================================================== +// CLASS ErrorLinePlot +// Description: Combine a line and error plot +// THIS IS A DEPRECATED PLOT TYPE JUST KEPT FOR +// BACKWARD COMPATIBILITY +//=================================================== +class ErrorLinePlot extends ErrorPlot { + public $line=null; +//--------------- +// CONSTRUCTOR + function ErrorLinePlot($datay,$datax=false) { + $this->ErrorPlot($datay,$datax); + // Calculate line coordinates as the average of the error limits + $n = count($datay); + for($i=0; $i < $n; $i+=2 ) { + $ly[]=($datay[$i]+$datay[$i+1])/2; + } + $this->line=new LinePlot($ly,$datax); + } + +//--------------- +// PUBLIC METHODS + function Legend($graph) { + if( $this->legend != "" ) + $graph->legend->Add($this->legend,$this->color); + $this->line->Legend($graph); + } + + function Stroke($img,$xscale,$yscale) { + parent::Stroke($img,$xscale,$yscale); + $this->line->Stroke($img,$xscale,$yscale); + } +} // Class + + +//=================================================== +// CLASS LineErrorPlot +// Description: Combine a line and error plot +//=================================================== +class LineErrorPlot extends ErrorPlot { + public $line=null; +//--------------- +// CONSTRUCTOR + // Data is (val, errdeltamin, errdeltamax) + function LineErrorPlot($datay,$datax=false) { + $ly=array(); $ey=array(); + $n = count($datay); + if( $n % 3 != 0 ) { + JpGraphError::RaiseL(4002); +//('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3'); + } + for($i=0; $i < $n; $i+=3 ) { + $ly[]=$datay[$i]; + $ey[]=$datay[$i]+$datay[$i+1]; + $ey[]=$datay[$i]+$datay[$i+2]; + } + $this->ErrorPlot($ey,$datax); + $this->line=new LinePlot($ly,$datax); + } + +//--------------- +// PUBLIC METHODS + function Legend($graph) { + if( $this->legend != "" ) + $graph->legend->Add($this->legend,$this->color); + $this->line->Legend($graph); + } + + function Stroke($img,$xscale,$yscale) { + parent::Stroke($img,$xscale,$yscale); + $this->line->Stroke($img,$xscale,$yscale); + } +} // Class + + +/* EOF */ +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_flags.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_flags.php new file mode 100644 index 0000000..740fe31 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_flags.php @@ -0,0 +1,376 @@ + 'afgh', + 'Republic of Angola' => 'agla', + 'Republic of Albania' => 'alba', + 'Alderney' => 'alde', + 'Democratic and Popular Republic of Algeria' => 'alge', + 'Territory of American Samoa' => 'amsa', + 'Principality of Andorra' => 'andr', + 'British Overseas Territory of Anguilla' => 'angu', + 'Antarctica' => 'anta', + 'Argentine Republic' => 'arge', + 'League of Arab States' => 'arle', + 'Republic of Armenia' => 'arme', + 'Aruba' => 'arub', + 'Commonwealth of Australia' => 'astl', + 'Republic of Austria' => 'aust', + 'Azerbaijani Republic' => 'azer', + 'Bangladesh' => 'bngl', + 'British Antarctic Territory' => 'bant', + 'Kingdom of Belgium' => 'belg', + 'British Overseas Territory of Bermuda' => 'berm', + 'Commonwealth of the Bahamas' => 'bhms', + 'Kingdom of Bahrain' => 'bhrn', + 'Republic of Belarus' => 'blru', + 'Republic of Bolivia' => 'blva', + 'Belize' => 'blze', + 'Republic of Benin' => 'bnin', + 'Republic of Botswana' => 'bots', + 'Federative Republic of Brazil' => 'braz', + 'Barbados' => 'brbd', + 'British Indian Ocean Territory' => 'brin', + 'Brunei Darussalam' => 'brun', + 'Republic of Burkina' => 'bufa', + 'Republic of Bulgaria' => 'bulg', + 'Republic of Burundi' => 'buru', + 'Overseas Territory of the British Virgin Islands' => 'bvis', + 'Central African Republic' => 'cafr', + 'Kingdom of Cambodia' => 'camb', + 'Republic of Cameroon' => 'came', + 'Dominion of Canada' => 'cana', + 'Caribbean Community' => 'cari', + 'Republic of Cape Verde' => 'cave', + 'Republic of Chad' => 'chad', + 'Republic of Chile' => 'chil', + 'Peoples Republic of China' => 'chin', + 'Territory of Christmas Island' => 'chms', + 'Commonwealth of Independent States' => 'cins', + 'Cook Islands' => 'ckis', + 'Republic of Colombia' => 'clmb', + 'Territory of Cocos Islands' => 'cois', + 'Commonwealth' => 'comn', + 'Union of the Comoros' => 'como', + 'Republic of the Congo' => 'cong', + 'Republic of Costa Rica' => 'corc', + 'Republic of Croatia' => 'croa', + 'Republic of Cuba' => 'cuba', + 'British Overseas Territory of the Cayman Islands' => 'cyis', + 'Republic of Cyprus' => 'cypr', + 'The Czech Republic' => 'czec', + 'Kingdom of Denmark' => 'denm', + 'Republic of Djibouti' => 'djib', + 'Commonwealth of Dominica' => 'domn', + 'Dominican Republic' => 'dore', + 'Republic of Ecuador' => 'ecua', + 'Arab Republic of Egypt' => 'egyp', + 'Republic of El Salvador' => 'elsa', + 'England' => 'engl', + 'Republic of Equatorial Guinea' => 'eqgu', + 'State of Eritrea' => 'erit', + 'Republic of Estonia' => 'estn', + 'Ethiopia' => 'ethp', + 'European Union' => 'euun', + 'British Overseas Territory of the Falkland Islands' => 'fais', + 'International Federation of Vexillological Associations' => 'fiav', + 'Republic of Fiji' => 'fiji', + 'Republic of Finland' => 'finl', + 'Territory of French Polynesia' => 'fpol', + 'French Republic' => 'fran', + 'Overseas Department of French Guiana' => 'frgu', + 'Gabonese Republic' => 'gabn', + 'Republic of the Gambia' => 'gamb', + 'Republic of Georgia' => 'geor', + 'Federal Republic of Germany' => 'germ', + 'Republic of Ghana' => 'ghan', + 'Gibraltar' => 'gibr', + 'Hellenic Republic' => 'grec', + 'State of Grenada' => 'gren', + 'Overseas Department of Guadeloupe' => 'guad', + 'Territory of Guam' => 'guam', + 'Republic of Guatemala' => 'guat', + 'The Bailiwick of Guernsey' => 'guer', + 'Republic of Guinea' => 'guin', + 'Republic of Haiti' => 'hait', + 'Hong Kong Special Administrative Region' => 'hokn', + 'Republic of Honduras' => 'hond', + 'Republic of Hungary' => 'hung', + 'Republic of Iceland' => 'icel', + 'International Committee of the Red Cross' => 'icrc', + 'Republic of India' => 'inda', + 'Republic of Indonesia' => 'indn', + 'Republic of Iraq' => 'iraq', + 'Republic of Ireland' => 'irel', + 'Organization of the Islamic Conference' => 'isco', + 'Isle of Man' => 'isma', + 'State of Israel' => 'isra', + 'Italian Republic' => 'ital', + 'Jamaica' => 'jama', + 'Japan' => 'japa', + 'The Bailiwick of Jersey' => 'jers', + 'Hashemite Kingdom of Jordan' => 'jord', + 'Republic of Kazakhstan' => 'kazk', + 'Republic of Kenya' => 'keny', + 'Republic of Kiribati' => 'kirb', + 'State of Kuwait' => 'kuwa', + 'Kyrgyz Republic' => 'kyrg', + 'Republic of Latvia' => 'latv', + 'Lebanese Republic' => 'leba', + 'Kingdom of Lesotho' => 'lest', + 'Republic of Liberia' => 'libe', + 'Principality of Liechtenstein' => 'liec', + 'Republic of Lithuania' => 'lith', + 'Grand Duchy of Luxembourg' => 'luxe', + 'Macao Special Administrative Region' => 'maca', + 'Republic of Macedonia' => 'mace', + 'Republic of Madagascar' => 'mada', + 'Republic of the Marshall Islands' => 'mais', + 'Republic of Mali' => 'mali', + 'Federation of Malaysia' => 'mals', + 'Republic of Malta' => 'malt', + 'Republic of Malawi' => 'malw', + 'Overseas Department of Martinique' => 'mart', + 'Islamic Republic of Mauritania' => 'maur', + 'Territorial Collectivity of Mayotte' => 'mayt', + 'United Mexican States' => 'mexc', + 'Federated States of Micronesia' => 'micr', + 'Midway Islands' => 'miis', + 'Republic of Moldova' => 'mold', + 'Principality of Monaco' => 'mona', + 'Republic of Mongolia' => 'mong', + 'British Overseas Territory of Montserrat' => 'mont', + 'Kingdom of Morocco' => 'morc', + 'Republic of Mozambique' => 'moza', + 'Republic of Mauritius' => 'mrts', + 'Union of Myanmar' => 'myan', + 'Republic of Namibia' => 'namb', + 'North Atlantic Treaty Organization' => 'nato', + 'Republic of Nauru' => 'naur', + 'Turkish Republic of Northern Cyprus' => 'ncyp', + 'Netherlands Antilles' => 'nean', + 'Kingdom of Nepal' => 'nepa', + 'Kingdom of the Netherlands' => 'neth', + 'Territory of Norfolk Island' => 'nfis', + 'Federal Republic of Nigeria' => 'ngra', + 'Republic of Nicaragua' => 'nica', + 'Republic of Niger' => 'nigr', + 'Niue' => 'niue', + 'Commonwealth of the Northern Mariana Islands' => 'nmar', + 'Province of Northern Ireland' => 'noir', + 'Nordic Council' => 'nord', + 'Kingdom of Norway' => 'norw', + 'Territory of New Caledonia and Dependencies' => 'nwca', + 'New Zealand' => 'nwze', + 'Organization of American States' => 'oast', + 'Organization of African Unity' => 'oaun', + 'International Olympic Committee' => 'olym', + 'Sultanate of Oman' => 'oman', + 'Islamic Republic of Pakistan' => 'paks', + 'Republic of Palau' => 'pala', + 'Independent State of Papua New Guinea' => 'pang', + 'Republic of Paraguay' => 'para', + 'Republic of Peru' => 'peru', + 'Republic of the Philippines' => 'phil', + 'British Overseas Territory of the Pitcairn Islands' => 'piis', + 'Republic of Poland' => 'pola', + 'Republic of Portugal' => 'port', + 'Commonwealth of Puerto Rico' => 'purc', + 'State of Qatar' => 'qata', + 'Russian Federation' => 'russ', + 'Romania' => 'rmna', + 'Republic of Rwanda' => 'rwan', + 'Kingdom of Saudi Arabia' => 'saar', + 'Republic of San Marino' => 'sama', + 'Nordic Sami Conference' => 'sami', + 'Sark' => 'sark', + 'Scotland' => 'scot', + 'Principality of Seborga' => 'sebo', + 'Republic of Serbia' => 'serb', + 'Republic of Sierra Leone' => 'sile', + 'Republic of Singapore' => 'sing', + 'Republic of Korea' => 'skor', + 'Republic of Slovenia' => 'slva', + 'Somali Republic' => 'smla', + 'Republic of Somaliland' => 'smld', + 'Republic of South Africa' => 'soaf', + 'Solomon Islands' => 'sois', + 'Kingdom of Spain' => 'span', + 'Secretariat of the Pacific Community' => 'spco', + 'Democratic Socialist Republic of Sri Lanka' => 'srla', + 'Saint Lucia' => 'stlu', + 'Republic of the Sudan' => 'suda', + 'Republic of Suriname' => 'surn', + 'Slovak Republic' => 'svka', + 'Kingdom of Sweden' => 'swdn', + 'Swiss Confederation' => 'swit', + 'Syrian Arab Republic' => 'syra', + 'Kingdom of Swaziland' => 'szld', + 'Republic of China' => 'taiw', + 'Taiwan' => 'taiw', + 'Republic of Tajikistan' => 'tajk', + 'United Republic of Tanzania' => 'tanz', + 'Kingdom of Thailand' => 'thal', + 'Autonomous Region of Tibet' => 'tibe', + 'Turkmenistan' => 'tkst', + 'Togolese Republic' => 'togo', + 'Tokelau' => 'toke', + 'Kingdom of Tonga' => 'tong', + 'Tristan da Cunha' => 'trdc', + 'Tromelin' => 'tris', + 'Republic of Tunisia' => 'tuns', + 'Republic of Turkey' => 'turk', + 'Tuvalu' => 'tuva', + 'United Arab Emirates' => 'uaem', + 'Republic of Uganda' => 'ugan', + 'Ukraine' => 'ukrn', + 'United Kingdom of Great Britain' => 'unkg', + 'United Nations' => 'unna', + 'United States of America' => 'unst', + 'Oriental Republic of Uruguay' => 'urgy', + 'Virgin Islands of the United States' => 'usvs', + 'Republic of Uzbekistan' => 'uzbk', + 'State of the Vatican City' => 'vacy', + 'Republic of Vanuatu' => 'vant', + 'Bolivarian Republic of Venezuela' => 'venz', + 'Republic of Yemen' => 'yemn', + 'Democratic Republic of Congo' => 'zare', + 'Republic of Zimbabwe' => 'zbwe' ) ; + + + private $iFlagCount = -1; + private $iFlagSetMap = array( + FLAGSIZE1 => 'flags_thumb35x35', + FLAGSIZE2 => 'flags_thumb60x60', + FLAGSIZE3 => 'flags_thumb100x100', + FLAGSIZE4 => 'flags' + ); + + private $iFlagData ; + private $iOrdIdx=array(); + + function FlagImages($aSize=FLAGSIZE1) { + switch($aSize) { + case FLAGSIZE1 : + case FLAGSIZE2 : + case FLAGSIZE3 : + case FLAGSIZE4 : + $file = dirname(__FILE__).'/'.$this->iFlagSetMap[$aSize].'.dat'; + $fp = fopen($file,'rb'); + $rawdata = fread($fp,filesize($file)); + $this->iFlagData = unserialize($rawdata); + break; + default: + JpGraphError::RaiseL(5001,$aSize); +//('Unknown flag size. ('.$aSize.')'); + } + $this->iFlagCount = count($this->iCountryNameMap); + } + + function GetNum() { + return $this->iFlagCount; + } + + function GetImgByName($aName,&$outFullName) { + $idx = $this->GetIdxByName($aName,$outFullName); + return $this->GetImgByIdx($idx); + } + + function GetImgByIdx($aIdx) { + if( array_key_exists($aIdx,$this->iFlagData) ) { + $d = $this->iFlagData[$aIdx][1]; + return Image::CreateFromString($d); + } + else { + JpGraphError::RaiseL(5002,$aIdx); +//("Flag index \"$aIdx\" does not exist."); + } + } + + function GetIdxByOrdinal($aOrd,&$outFullName) { + $aOrd--; + $n = count($this->iOrdIdx); + if( $n == 0 ) { + reset($this->iCountryNameMap); + $this->iOrdIdx=array(); + $i=0; + while( list($key,$val) = each($this->iCountryNameMap) ) { + $this->iOrdIdx[$i++] = array($val,$key); + } + $tmp=$this->iOrdIdx[$aOrd]; + $outFullName = $tmp[1]; + return $tmp[0]; + + } + elseif( $aOrd >= 0 && $aOrd < $n ) { + $tmp=$this->iOrdIdx[$aOrd]; + $outFullName = $tmp[1]; + return $tmp[0]; + } + else { + JpGraphError::RaiseL(5003,$aOrd); +//('Invalid ordinal number specified for flag index.'); + } + } + + function GetIdxByName($aName,&$outFullName) { + + if( is_integer($aName) ) { + $idx = $this->GetIdxByOrdinal($aName,$outFullName); + return $idx; + } + + $found=false; + $aName = strtolower($aName); + $nlen = strlen($aName); + reset($this->iCountryNameMap); + // Start by trying to match exact index name + while( list($key,$val) = each($this->iCountryNameMap) ) { + if( $nlen == strlen($val) && $val == $aName ) { + $found=true; + break; + } + } + if( !$found ) { + reset($this->iCountryNameMap); + // If the exact index doesn't work try a (partial) full name + while( list($key,$val) = each($this->iCountryNameMap) ) { + if( strpos(strtolower($key), $aName) !== false ) { + $found=true; + break; + } + } + } + if( $found ) { + $outFullName = $key; + return $val; + } + else { + JpGraphError::RaiseL(5004,$aName); +//("The (partial) country name \"$aName\" does not have a cooresponding flag image. The flag may still exist but under another name, e.g. insted of \"usa\" try \"united states\"."); + } + } +} + + + + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php new file mode 100644 index 0000000..65e416f --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gantt.php @@ -0,0 +1,3803 @@ +vgrid = new LineProperty(); + } + + function Hide($aF=true) { + $this->iShow=!$aF; + } + + function Show($aF=true) { + $this->iShow=$aF; + } + + // Specify font + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function SetStyle($aStyle) { + $this->iStyle = $aStyle; + } + + function SetColumnMargin($aLeft,$aRight) { + $this->iLeftColMargin = $aLeft; + $this->iRightColMargin = $aRight; + } + + function SetFontColor($aFontColor) { + $this->iFontColor = $aFontColor; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetBackgroundColor($aColor) { + $this->iBackgroundColor = $aColor; + } + + function SetColTitles($aTitles,$aWidth=null) { + $this->iTitles = $aTitles; + $this->iWidth = $aWidth; + } + + function SetMinColWidth($aWidths) { + $n = min(count($this->iTitles),count($aWidths)); + for($i=0; $i < $n; ++$i ) { + if( !empty($aWidths[$i]) ) { + if( empty($this->iWidth[$i]) ) { + $this->iWidth[$i] = $aWidths[$i]; + } + else { + $this->iWidth[$i] = max($this->iWidth[$i],$aWidths[$i]); + } + } + } + } + + function GetWidth($aImg) { + $txt = new TextProperty(); + $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $n = count($this->iTitles) ; + $rm=$this->iRightColMargin; + $w = 0; + for($h=0, $i=0; $i < $n; ++$i ) { + $w += $this->iLeftColMargin; + $txt->Set($this->iTitles[$i]); + if( !empty($this->iWidth[$i]) ) { + $w1 = max($txt->GetWidth($aImg)+$rm,$this->iWidth[$i]); + } + else { + $w1 = $txt->GetWidth($aImg)+$rm; + } + $this->iWidth[$i] = $w1; + $w += $w1; + $h = max($h,$txt->GetHeight($aImg)); + } + $this->iHeight = $h+$this->iTopHeaderMargin; + $txt=''; + return $w; + } + + function GetColStart($aImg,&$aStart,$aAddLeftMargin=false) { + $n = count($this->iTitles) ; + $adj = $aAddLeftMargin ? $this->iLeftColMargin : 0; + $aStart=array($aImg->left_margin+$adj); + for( $i=1; $i < $n; ++$i ) { + $aStart[$i] = $aStart[$i-1]+$this->iLeftColMargin+$this->iWidth[$i-1]; + } + } + + // Adjust headers left, right or centered + function SetHeaderAlign($aAlign) { + $this->iHeaderAlign=$aAlign; + } + + function Stroke($aImg,$aXLeft,$aYTop,$aXRight,$aYBottom,$aUseTextHeight=false) { + + if( !$this->iShow ) return; + + $txt = new TextProperty(); + $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $txt->SetColor($this->iFontColor); + $txt->SetAlign($this->iHeaderAlign,'top'); + $n=count($this->iTitles); + + if( $n == 0 ) + return; + + $x = $aXLeft; + $h = $this->iHeight; + $yTop = $aUseTextHeight ? $aYBottom-$h-$this->iTopColMargin-$this->iBottomColMargin : $aYTop ; + + if( $h < 0 ) { + JpGraphError::RaiseL(6001); +//('Internal error. Height for ActivityTitles is < 0'); + } + + $aImg->SetLineWeight(1); + // Set background color + $aImg->SetColor($this->iBackgroundColor); + $aImg->FilledRectangle($aXLeft,$yTop,$aXRight,$aYBottom-1); + + if( $this->iStyle == 1 ) { + // Make a 3D effect + $aImg->SetColor('white'); + $aImg->Line($aXLeft,$yTop+1, + $aXRight,$yTop+1); + } + + for($i=0; $i < $n; ++$i ) { + if( $this->iStyle == 1 ) { + // Make a 3D effect + $aImg->SetColor('white'); + $aImg->Line($x+1,$yTop,$x+1,$aYBottom); + } + $x += $this->iLeftColMargin; + $txt->Set($this->iTitles[$i]); + + // Adjust the text anchor position according to the choosen alignment + $xp = $x; + if( $this->iHeaderAlign == 'center' ) { + $xp = (($x-$this->iLeftColMargin)+($x+$this->iWidth[$i]))/2; + } + elseif( $this->iHeaderAlign == 'right' ) { + $xp = $x +$this->iWidth[$i]-$this->iRightColMargin; + } + + $txt->Stroke($aImg,$xp,$yTop+$this->iTopHeaderMargin); + $x += $this->iWidth[$i]; + if( $i < $n-1 ) { + $aImg->SetColor($this->iColor); + $aImg->Line($x,$yTop,$x,$aYBottom); + } + } + + $aImg->SetColor($this->iColor); + $aImg->Line($aXLeft,$yTop, $aXRight,$yTop); + + // Stroke vertical column dividers + $cols=array(); + $this->GetColStart($aImg,$cols); + $n=count($cols); + for( $i=1; $i < $n; ++$i ) { + $this->vgrid->Stroke($aImg,$cols[$i],$aYBottom,$cols[$i], + $aImg->height - $aImg->bottom_margin); + } + } +} + + +//=================================================== +// CLASS GanttGraph +// Description: Main class to handle gantt graphs +//=================================================== +class GanttGraph extends Graph { + public $scale; // Public accessible + public $hgrid=null; + private $iObj=array(); // Gantt objects + private $iLabelHMarginFactor=0.2; // 10% margin on each side of the labels + private $iLabelVMarginFactor=0.4; // 40% margin on top and bottom of label + private $iLayout=GANTT_FROMTOP; // Could also be GANTT_EVEN + private $iSimpleFont = FF_FONT1,$iSimpleFontSize=11; + private $iSimpleStyle=GANTT_RDIAG,$iSimpleColor='yellow',$iSimpleBkgColor='red'; + private $iSimpleProgressBkgColor='gray',$iSimpleProgressColor='darkgreen'; + private $iSimpleProgressStyle=GANTT_SOLID; +//--------------- +// CONSTRUCTOR + // Create a new gantt graph + function GanttGraph($aWidth=0,$aHeight=0,$aCachedName="",$aTimeOut=0,$aInline=true) { + + // Backward compatibility + if( $aWidth == -1 ) $aWidth=0; + if( $aHeight == -1 ) $aHeight=0; + + if( $aWidth< 0 || $aHeight < 0 ) { + JpgraphError::RaiseL(6002); +//("You can't specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension."); + } + Graph::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline); + $this->scale = new GanttScale($this->img); + + // Default margins + $this->img->SetMargin(15,17,25,15); + + $this->hgrid = new HorizontalGridLine(); + + $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY); + $this->SetBox(); + } + +//--------------- +// PUBLIC METHODS + + // + + function SetSimpleFont($aFont,$aSize) { + $this->iSimpleFont = $aFont; + $this->iSimpleFontSize = $aSize; + } + + function SetSimpleStyle($aBand,$aColor,$aBkgColor) { + $this->iSimpleStyle = $aBand; + $this->iSimpleColor = $aColor; + $this->iSimpleBkgColor = $aBkgColor; + } + + // A utility function to help create basic Gantt charts + function CreateSimple($data,$constrains=array(),$progress=array()) { + $num = count($data); + for( $i=0; $i < $num; ++$i) { + switch( $data[$i][1] ) { + case ACTYPE_GROUP: + // Create a slightly smaller height bar since the + // "wings" at the end will make it look taller + $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',8); + $a->title->SetFont($this->iSimpleFont,FS_BOLD,$this->iSimpleFontSize); + $a->rightMark->Show(); + $a->rightMark->SetType(MARK_RIGHTTRIANGLE); + $a->rightMark->SetWidth(8); + $a->rightMark->SetColor('black'); + $a->rightMark->SetFillColor('black'); + + $a->leftMark->Show(); + $a->leftMark->SetType(MARK_LEFTTRIANGLE); + $a->leftMark->SetWidth(8); + $a->leftMark->SetColor('black'); + $a->leftMark->SetFillColor('black'); + + $a->SetPattern(BAND_SOLID,'black'); + $csimpos = 6; + break; + + case ACTYPE_NORMAL: + $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',10); + $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $a->SetPattern($this->iSimpleStyle,$this->iSimpleColor); + $a->SetFillColor($this->iSimpleBkgColor); + // Check if this activity should have a constrain line + $n = count($constrains); + for( $j=0; $j < $n; ++$j ) { + if( empty($constrains[$j]) || (count($constrains[$j]) != 3) ) { + JpGraphError::RaiseL(6003,$j); +//("Invalid format for Constrain parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)"); + } + if( $constrains[$j][0]==$data[$i][0] ) { + $a->SetConstrain($constrains[$j][1],$constrains[$j][2],'black',ARROW_S2,ARROWT_SOLID); + } + } + + // Check if this activity have a progress bar + $n = count($progress); + for( $j=0; $j < $n; ++$j ) { + + if( empty($progress[$j]) || (count($progress[$j]) != 2) ) { + JpGraphError::RaiseL(6004,$j); +//("Invalid format for Progress parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)"); + } + if( $progress[$j][0]==$data[$i][0] ) { + $a->progress->Set($progress[$j][1]); + $a->progress->SetPattern($this->iSimpleProgressStyle, + $this->iSimpleProgressColor); + $a->progress->SetFillColor($this->iSimpleProgressBkgColor); + //$a->progress->SetPattern($progress[$j][2],$progress[$j][3]); + break; + } + } + $csimpos = 6; + break; + + case ACTYPE_MILESTONE: + $a = new MileStone($data[$i][0],$data[$i][2],$data[$i][3]); + $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $a->caption->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize); + $csimpos = 5; + break; + default: + die('Unknown activity type'); + break; + } + + // Setup caption + $a->caption->Set($data[$i][$csimpos-1]); + + // Check if this activity should have a CSIM target? + if( !empty($data[$i][$csimpos]) ) { + $a->SetCSIMTarget($data[$i][$csimpos]); + $a->SetCSIMAlt($data[$i][$csimpos+1]); + } + if( !empty($data[$i][$csimpos+2]) ) { + $a->title->SetCSIMTarget($data[$i][$csimpos+2]); + $a->title->SetCSIMAlt($data[$i][$csimpos+3]); + } + + $this->Add($a); + } + } + + + // Set what headers should be shown + function ShowHeaders($aFlg) { + $this->scale->ShowHeaders($aFlg); + } + + // Specify the fraction of the font height that should be added + // as vertical margin + function SetLabelVMarginFactor($aVal) { + $this->iLabelVMarginFactor = $aVal; + } + + // Synonym to the method above + function SetVMarginFactor($aVal) { + $this->iLabelVMarginFactor = $aVal; + } + + + // Add a new Gantt object + function Add($aObject) { + if( is_array($aObject) && count($aObject) > 0 ) { + $cl = $aObject[0]; + if( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) { + $this->AddIcon($aObject); + } + else { + $n = count($aObject); + for($i=0; $i < $n; ++$i) + $this->iObj[] = $aObject[$i]; + } + } + else { + if( class_exists('IconPlot',false) && ($aObject instanceof IconPlot) ) { + $this->AddIcon($aObject); + } + else { + $this->iObj[] = $aObject; + } + } + } + + // Override inherit method from Graph and give a warning message + function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { + JpGraphError::RaiseL(6005); +//("SetScale() is not meaningfull with Gantt charts."); + } + + // Specify the date range for Gantt graphs (if this is not set it will be + // automtically determined from the input data) + function SetDateRange($aStart,$aEnd) { + // Adjust the start and end so that the indicate the + // begining and end of respective start and end days + if( strpos($aStart,':') === false ) + $aStart = date('Y-m-d 00:00',strtotime($aStart)); + if( strpos($aEnd,':') === false ) + $aEnd = date('Y-m-d 23:59',strtotime($aEnd)); + $this->scale->SetRange($aStart,$aEnd); + } + + // Get the maximum width of the activity titles columns for the bars + // The name is lightly misleading since we from now on can have + // multiple columns in the label section. When this was first written + // it only supported a single label, hence the name. + function GetMaxLabelWidth() { + $m=10; + if( $this->iObj != null ) { + $marg = $this->scale->actinfo->iLeftColMargin+$this->scale->actinfo->iRightColMargin; + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + if( !empty($this->iObj[$i]->title) ) { + if( $this->iObj[$i]->title->HasTabs() ) { + list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true); + $m=max($m,$tot); + } + else + $m=max($m,$this->iObj[$i]->title->GetWidth($this->img)); + } + } + } + return $m; + } + + // Get the maximum height of the titles for the bars + function GetMaxLabelHeight() { + $m=10; + if( $this->iObj != null ) { + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + if( !empty($this->iObj[$i]->title) ) { + $m=max($m,$this->iObj[$i]->title->GetHeight($this->img)); + } + } + } + return $m; + } + + function GetMaxBarAbsHeight() { + $m=0; + if( $this->iObj != null ) { + $m = $this->iObj[0]->GetAbsHeight($this->img); + $n = count($this->iObj); + for($i=1; $i < $n; ++$i) { + $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img)); + } + } + return $m; + } + + // Get the maximum used line number (vertical position) for bars + function GetBarMaxLineNumber() { + $m=1; + if( $this->iObj != null ) { + $m = $this->iObj[0]->GetLineNbr(); + $n = count($this->iObj); + for($i=1; $i < $n; ++$i) { + $m=max($m,$this->iObj[$i]->GetLineNbr()); + } + } + return $m; + } + + // Get the minumum and maximum used dates for all bars + function GetBarMinMax() { + $start = 0 ; + $n = count($this->iObj); + while( $start < $n && $this->iObj[$start]->GetMaxDate() === false ) + ++$start; + if( $start >= $n ) { + JpgraphError::RaiseL(6006); +//('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]'); + } + + $max=$this->scale->NormalizeDate($this->iObj[$start]->GetMaxDate()); + $min=$this->scale->NormalizeDate($this->iObj[$start]->GetMinDate()); + + for($i=$start+1; $i < $n; ++$i) { + $rmax = $this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate()); + if( $rmax != false ) + $max=Max($max,$rmax); + $rmin = $this->scale->NormalizeDate($this->iObj[$i]->GetMinDate()); + if( $rmin != false ) + $min=Min($min,$rmin); + } + $minDate = date("Y-m-d",$min); + $min = strtotime($minDate); + $maxDate = date("Y-m-d 23:59",$max); + $max = strtotime($maxDate); + return array($min,$max); + } + + // Create a new auto sized canvas if the user hasn't specified a size + // The size is determined by what scale the user has choosen and hence + // the minimum width needed to display the headers. Some margins are + // also added to make it better looking. + function AutoSize() { + + if( $this->img->img == null ) { + // The predefined left, right, top, bottom margins. + // Note that the top margin might incease depending on + // the title. + $lm = $this->img->left_margin; + $rm = $this->img->right_margin; + $rm += 2 ; + $tm = $this->img->top_margin; + $bm = $this->img->bottom_margin; + $bm += 1; + if( BRAND_TIMING ) $bm += 10; + + // First find out the height + $n=$this->GetBarMaxLineNumber()+1; + $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); + $height=$n*((1+$this->iLabelVMarginFactor)*$m); + + // Add the height of the scale titles + $h=$this->scale->GetHeaderHeight(); + $height += $h; + + // Calculate the top margin needed for title and subtitle + if( $this->title->t != "" ) { + $tm += $this->title->GetFontHeight($this->img); + } + if( $this->subtitle->t != "" ) { + $tm += $this->subtitle->GetFontHeight($this->img); + } + + // ...and then take the bottom and top plot margins into account + $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin; + // Now find the minimum width for the chart required + + // If day scale or smaller is shown then we use the day font width + // as the base size unit. + // If only weeks or above is displayed we use a modified unit to + // get a smaller image. + if( $this->scale->IsDisplayHour() || $this->scale->IsDisplayMinute() ) { + // Add 2 pixel margin on each side + $fw=$this->scale->day->GetFontWidth($this->img)+4; + } + elseif( $this->scale->IsDisplayWeek() ) { + $fw = 8; + } + elseif( $this->scale->IsDisplayMonth() ) { + $fw = 4; + } + else { + $fw = 2; + } + + $nd=$this->scale->GetNumberOfDays(); + + if( $this->scale->IsDisplayDay() ) { + // If the days are displayed we also need to figure out + // how much space each day's title will require. + switch( $this->scale->day->iStyle ) { + case DAYSTYLE_LONG : + $txt = "Monday"; + break; + case DAYSTYLE_LONGDAYDATE1 : + $txt = "Monday 23 Jun"; + break; + case DAYSTYLE_LONGDAYDATE2 : + $txt = "Monday 23 Jun 2003"; + break; + case DAYSTYLE_SHORT : + $txt = "Mon"; + break; + case DAYSTYLE_SHORTDAYDATE1 : + $txt = "Mon 23/6"; + break; + case DAYSTYLE_SHORTDAYDATE2 : + $txt = "Mon 23 Jun"; + break; + case DAYSTYLE_SHORTDAYDATE3 : + $txt = "Mon 23"; + break; + case DAYSTYLE_SHORTDATE1 : + $txt = "23/6"; + break; + case DAYSTYLE_SHORTDATE2 : + $txt = "23 Jun"; + break; + case DAYSTYLE_SHORTDATE3 : + $txt = "Mon 23"; + break; + case DAYSTYLE_SHORTDATE4 : + $txt = "88"; + break; + case DAYSTYLE_CUSTOM : + $txt = date($this->scale->day->iLabelFormStr, + strtotime('2003-12-20 18:00')); + break; + case DAYSTYLE_ONELETTER : + default: + $txt = "M"; + break; + } + $fw = $this->scale->day->GetStrWidth($this->img,$txt)+6; + } + + // If we have hours enabled we must make sure that each day has enough + // space to fit the number of hours to be displayed. + if( $this->scale->IsDisplayHour() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->hour->iStyle ) { + case HOURSTYLE_HMAMPM: + $txt = '12:00pm'; + break; + case HOURSTYLE_H24: + // 13 + $txt = '24'; + break; + case HOURSTYLE_HAMPM: + $txt = '12pm'; + break; + case HOURSTYLE_CUSTOM: + $txt = date($this->scale->hour->iLabelFormStr,strtotime('2003-12-20 18:00')); + break; + case HOURSTYLE_HM24: + default: + $txt = '24:00'; + break; + } + + $hfw = $this->scale->hour->GetStrWidth($this->img,$txt)+6; + $mw = $hfw; + if( $this->scale->IsDisplayMinute() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->minute->iStyle ) { + case HOURSTYLE_CUSTOM: + $txt2 = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); + break; + case MINUTESTYLE_MM: + default: + $txt2 = '15'; + break; + } + + $mfw = $this->scale->minute->GetStrWidth($this->img,$txt2)+6; + $n2 = ceil(60 / $this->scale->minute->GetIntervall() ); + $mw = $n2 * $mfw; + } + $hfw = $hfw < $mw ? $mw : $hfw ; + $n = ceil(24*60 / $this->scale->TimeToMinutes($this->scale->hour->GetIntervall()) ); + $hw = $n * $hfw; + $fw = $fw < $hw ? $hw : $fw ; + } + + // We need to repeat this code block here as well. + // THIS iS NOT A MISTAKE ! + // We really need it since we need to adjust for minutes both in the case + // where hour scale is shown and when it is not shown. + + if( $this->scale->IsDisplayMinute() ) { + // Depending on what format the user has choose we need different amount + // of space. We therefore create a typical string for the choosen format + // and determine the length of that string. + switch( $this->scale->minute->iStyle ) { + case HOURSTYLE_CUSTOM: + $txt = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55')); + break; + case MINUTESTYLE_MM: + default: + $txt = '15'; + break; + } + + $mfw = $this->scale->minute->GetStrWidth($this->img,$txt)+6; + $n = ceil(60 / $this->scale->TimeToMinutes($this->scale->minute->GetIntervall()) ); + $mw = $n * $mfw; + $fw = $fw < $mw ? $mw : $fw ; + } + + // If we display week we must make sure that 7*$fw is enough + // to fit up to 10 characters of the week font (if the week is enabled) + if( $this->scale->IsDisplayWeek() ) { + // Depending on what format the user has choose we need different amount + // of space + $fsw = strlen($this->scale->week->iLabelFormStr); + if( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $fsw += 8; + } + elseif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) { + $fsw += 7; + } + else { + $fsw += 4; + } + + $ww = $fsw*$this->scale->week->GetFontWidth($this->img); + if( 7*$fw < $ww ) { + $fw = ceil($ww/7); + } + } + + if( !$this->scale->IsDisplayDay() && !$this->scale->IsDisplayHour() && + !( ($this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR) && $this->scale->IsDisplayWeek() ) ) { + // If we don't display the individual days we can shrink the + // scale a little bit. This is a little bit pragmatic at the + // moment and should be re-written to take into account + // a) What scales exactly are shown and + // b) what format do they use so we know how wide we need to + // make each scale text space at minimum. + $fw /= 2; + if( !$this->scale->IsDisplayWeek() ) { + $fw /= 1.8; + } + } + + $cw = $this->GetMaxActInfoColWidth() ; + $this->scale->actinfo->SetMinColWidth($cw); + if( $this->img->width <= 0 ) { + // Now determine the width for the activity titles column + + // Firdst find out the maximum width of each object column + $titlewidth = max(max($this->GetMaxLabelWidth(), + $this->scale->tableTitle->GetWidth($this->img)), + $this->scale->actinfo->GetWidth($this->img)); + + // Add the width of the vertivcal divider line + $titlewidth += $this->scale->divider->iWeight*2; + + + // Now get the total width taking + // titlewidth, left and rigt margin, dayfont size + // into account + $width = $titlewidth + $nd*$fw + $lm+$rm; + } + else { + $width = $this->img->width; + } + + $width = round($width); + $height = round($height); + // Make a sanity check on image size + if( $width > MAX_GANTTIMG_SIZE_W || $height > MAX_GANTTIMG_SIZE_H ) { + JpgraphError::RaiseL(6007,$width,$height); +//("Sanity check for automatic Gantt chart size failed. Either the width (=$width) or height (=$height) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities."); + } + $this->img->CreateImgCanvas($width,$height); + $this->img->SetMargin($lm,$rm,$tm,$bm); + } + } + + // Return an array width the maximum width for each activity + // column. This is used when we autosize the columns where we need + // to find out the maximum width of each column. In order to do that we + // must walk through all the objects, sigh... + function GetMaxActInfoColWidth() { + $n = count($this->iObj); + if( $n == 0 ) return; + $w = array(); + $m = $this->scale->actinfo->iLeftColMargin + $this->scale->actinfo->iRightColMargin; + + for( $i=0; $i < $n; ++$i ) { + $tmp = $this->iObj[$i]->title->GetColWidth($this->img,$m); + $nn = count($tmp); + for( $j=0; $j < $nn; ++$j ) { + if( empty($w[$j]) ) + $w[$j] = $tmp[$j]; + else + $w[$j] = max($w[$j],$tmp[$j]); + } + } + return $w; + } + + // Stroke the gantt chart + function Stroke($aStrokeFileName="") { + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // Should we autoscale dates? + + if( !$this->scale->IsRangeSet() ) { + list($min,$max) = $this->GetBarMinMax(); + $this->scale->SetRange($min,$max); + } + + $this->scale->AdjustStartEndDay(); + + // Check if we should autoscale the image + $this->AutoSize(); + + // Should we start from the top or just spread the bars out even over the + // available height + $this->scale->SetVertLayout($this->iLayout); + if( $this->iLayout == GANTT_FROMTOP ) { + $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); + $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor)); + } + // If it hasn't been set find out the maximum line number + if( $this->scale->iVertLines == -1 ) + $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; + + $maxwidth=max($this->scale->actinfo->GetWidth($this->img), + max($this->GetMaxLabelWidth(), + $this->scale->tableTitle->GetWidth($this->img))); + + $this->scale->SetLabelWidth($maxwidth+$this->scale->divider->iWeight);//*(1+$this->iLabelHMarginFactor)); + + if( !$_csim ) { + $this->StrokePlotArea(); + if( $this->iIconDepth == DEPTH_BACK ) { + $this->StrokeIcons(); + } + } + + $this->scale->Stroke(); + + if( !$_csim ) { + // Due to a minor off by 1 bug we need to temporarily adjust the margin + $this->img->right_margin--; + $this->StrokePlotBox(); + $this->img->right_margin++; + } + + // Stroke Grid line + $this->hgrid->Stroke($this->img,$this->scale); + + $n = count($this->iObj); + for($i=0; $i < $n; ++$i) { + //$this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2)); + $this->iObj[$i]->Stroke($this->img,$this->scale); + } + + $this->StrokeTitles(); + + if( !$_csim ) { + $this->StrokeConstrains(); + $this->footer->Stroke($this->img); + + + if( $this->iIconDepth == DEPTH_FRONT) { + $this->StrokeIcons(); + } + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, + $aStrokeFileName); + } + } + } + + function StrokeConstrains() { + $n = count($this->iObj); + + // Stroke all constrains + for($i=0; $i < $n; ++$i) { + + // Some gantt objects may not have constraints associated with them + // for example we can add IconPlots which doesn't have this property. + if( empty($this->iObj[$i]->constraints) ) continue; + + $numConstrains = count($this->iObj[$i]->constraints); + + for( $k = 0; $k < $numConstrains; $k++ ) { + $vpos = $this->iObj[$i]->constraints[$k]->iConstrainRow; + if( $vpos >= 0 ) { + $c1 = $this->iObj[$i]->iConstrainPos; + + // Find out which object is on the target row + $targetobj = -1; + for( $j=0; $j < $n && $targetobj == -1; ++$j ) { + if( $this->iObj[$j]->iVPos == $vpos ) { + $targetobj = $j; + } + } + if( $targetobj == -1 ) { + JpGraphError::RaiseL(6008,$this->iObj[$i]->iVPos,$vpos); +//('You have specifed a constrain from row='.$this->iObj[$i]->iVPos.' to row='.$vpos.' which does not have any activity.'); + } + $c2 = $this->iObj[$targetobj]->iConstrainPos; + if( count($c1) == 4 && count($c2 ) == 4) { + switch( $this->iObj[$i]->constraints[$k]->iConstrainType ) { + case CONSTRAIN_ENDSTART: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[2],$c1[3],$c2[0],$c2[1]); + } + else { + $link = new GanttLink($c1[2],$c1[1],$c2[0],$c2[3]); + } + $link->SetPath(3); + break; + case CONSTRAIN_STARTEND: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[0],$c1[3],$c2[2],$c2[1]); + } + else { + $link = new GanttLink($c1[0],$c1[1],$c2[2],$c2[3]); + } + $link->SetPath(0); + break; + case CONSTRAIN_ENDEND: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[2],$c1[3],$c2[2],$c2[1]); + } + else { + $link = new GanttLink($c1[2],$c1[1],$c2[2],$c2[3]); + } + $link->SetPath(1); + break; + case CONSTRAIN_STARTSTART: + if( $c1[1] < $c2[1] ) { + $link = new GanttLink($c1[0],$c1[3],$c2[0],$c2[1]); + } + else { + $link = new GanttLink($c1[0],$c1[1],$c2[0],$c2[3]); + } + $link->SetPath(3); + break; + default: + JpGraphError::RaiseL(6009,$this->iObj[$i]->iVPos,$vpos); +//('Unknown constrain type specified from row='.$this->iObj[$i]->iVPos.' to row='.$vpos); + break; + } + + $link->SetColor($this->iObj[$i]->constraints[$k]->iConstrainColor); + $link->SetArrow($this->iObj[$i]->constraints[$k]->iConstrainArrowSize, + $this->iObj[$i]->constraints[$k]->iConstrainArrowType); + + $link->Stroke($this->img); + } + } + } + } + } + + function GetCSIMAreas() { + if( !$this->iHasStroked ) + $this->Stroke(_CSIM_SPECIALFILE); + + $csim = $this->title->GetCSIMAreas(); + $csim .= $this->subtitle->GetCSIMAreas(); + $csim .= $this->subsubtitle->GetCSIMAreas(); + + $n = count($this->iObj); + for( $i=$n-1; $i >= 0; --$i ) + $csim .= $this->iObj[$i]->GetCSIMArea(); + return $csim; + } +} + +//=================================================== +// CLASS PredefIcons +// Description: Predefined icons for use with Gantt charts +//=================================================== +DEFINE('GICON_WARNINGRED',0); +DEFINE('GICON_TEXT',1); +DEFINE('GICON_ENDCONS',2); +DEFINE('GICON_MAIL',3); +DEFINE('GICON_STARTCONS',4); +DEFINE('GICON_CALC',5); +DEFINE('GICON_MAGNIFIER',6); +DEFINE('GICON_LOCK',7); +DEFINE('GICON_STOP',8); +DEFINE('GICON_WARNINGYELLOW',9); +DEFINE('GICON_FOLDEROPEN',10); +DEFINE('GICON_FOLDER',11); +DEFINE('GICON_TEXTIMPORTANT',12); + +class PredefIcons { + private $iBuiltinIcon = null, $iLen = -1 ; + + function GetLen() { + return $this->iLen ; + } + + function GetImg($aIdx) { + if( $aIdx < 0 || $aIdx >= $this->iLen ) { + JpGraphError::RaiseL(6010,$aIdx); +//('Illegal icon index for Gantt builtin icon ['.$aIdx.']'); + } + return Image::CreateFromString(base64_decode($this->iBuiltinIcon[$aIdx][1])); + } + + function PredefIcons() { + //========================================================== + // warning.png + //========================================================== + $this->iBuiltinIcon[0][0]= 1043 ; + $this->iBuiltinIcon[0][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'. + 'B3RJTUUH0wgKFSgilWPhUQAAA6BJREFUeNrtl91rHFUYh5/3zMx+Z5JNUoOamCZNaqTZ6IWIkqRiQWmi1IDetHfeiCiltgXBP8AL'. + '0SIUxf/AvfRSBS9EKILFFqyIH9CEmFZtPqrBJLs7c+b1YneT3WTTbNsUFPLCcAbmzPt73o9zzgzs2Z793231UOdv3w9k9Z2uzOdA'. + '5+2+79yNeL7Hl7hw7oeixRMZ6PJM26W18DNAm/Vh7lR8fqh97NmMF11es1iFpMATqdirwMNA/J4DpIzkr5YsAF1PO6gIMYHRdPwl'. + 'oO2elmB+qH3sm7XozbkgYvy8SzYnZPtcblyM6I+5z3jQ+0vJfgpEu56BfI9vUkbyi2HZd1QJoeWRiAjBd4SDCW8SSAOy6wBHMzF7'. + 'YdV2A+ROuvRPLfHoiSU0EMY/cDAIhxJeGngKaN1VgHyPL7NBxI1K9P4QxBzw3K1zJ/zkG8B9uwaQ7/HNsRZv9kohBGD0o7JqMYS/'. + '/ynPidQw/LrBiPBcS/yFCT95DvB2BWAy4575PaQbQKW+tPd3GCItu2odKI++YxiKu0d26oWmAD7paZU/rLz37VqIijD2YbnzNBBE'. + 'IBHf8K8qjL7vYhCGErEU8CTg3xXAeMp96GrJEqkyXkm9Bhui1xfsunjdGhcYLq+IzjsGmBt5YH/cmJkFq6gIqlon3u4LxdKGuCIo'. + 'Qu41g0E41po+2R33Xt5uz9kRIB2UTle7PnfKrROP1HD4sRjZlq0lzhwoZ6rDNeTi3nEg1si/7FT7kYQbXS6E5E65tA5uRF9tutq0'. + 'K/VwAF+/FbIYWt6+tjQM/AqUms7A4Wy6d7YSfSNxgMmzi0ycWWworio4QJvj4LpuL5BqugTnXzzqJsJwurrlNhJXFaavW67NRw3F'. + 'q+aJcCQVe9fzvJGmAY7/dPH0gi0f64OveGxa+usCuQMeZ0+kt8BVrX+qPO9Bzx0MgqBvs+a2PfDdYIf+WAjXU1ub4tqNaPPzRs8A'. + 'blrli+WVn79cXn0cWKl+tGx7HLc7pu3CSmnfitL+l1UihAhwjFkPQev4K/fSABjBM8JCaFuurJU+rgW41SroA8aNMVNAFtgHJCsn'. + 'XGy/58QVxAC9MccJtZ5kIzNlW440WrJ2ea4YPA9cAooA7i0A/gS+iqLoOpB1HOegqrYB3UBmJrAtQAJwpwPr1Ry92wVlgZsiYlW1'. + 'uX1gU36dymgqYxJIJJNJT1W9QqHgNwFQBGYqo94OwHZQUuPD7ACglSvc+5n5T9m/wfJJX4U9qzEAAAAASUVORK5CYII=' ; + + //========================================================== + // edit.png + //========================================================== + $this->iBuiltinIcon[1][0]= 959 ; + $this->iBuiltinIcon[1][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAFgAWABY9j+ZuwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDAwbIEXOA6AAAAM8SURBVHicpdRPaBxlHMbx76ZvsmOTmm1dsEqQSIIsEmGVBAQjivEQ'. + 'PAUJngpWsAWlBw8egpQepKwplN4ULEG9CjkEyUFKlSJrWTG0IU51pCsdYW2ncUPjdtp9Z+f3vuNhu8nKbmhaf5cZeGc+PO8zf1Lc'. + 'm0KhkACICCKCMeaBjiLC0tLSnjNvPmuOHRpH0TZTU1M8zBi9wakzn7OFTs5sw8YYACYmJrre7HkeuVyu69qPF77hlT1XmZ0eQ03O'. + 'wOLJTvhBx1rLz18VmJ0eY+jVd2FxDkKXnvYLHgb97OgLzE4ON9Hzc1B1QaQzsed5O0Lta3Ec89OnR5h5McfQ+Mw2qgQUnfBOPbZ3'. + 'bK3l+xOvMT0+3ERLp5FNF6UEjcL32+DdVmGt5WLhDYYPZrbRqreFumXwql0S3w9tnDvLWD5PZigPpdOwuYpSCo3C8wU3UHxQdHbf'. + 'cZIkNM6dxcnlUM4k1eUFMlUPpUADbpkttFarHe6oYqeOr6yt4RzMQHYUcUsQVtGicHDwKprViuLDkkOtVnsHCHZVRVy/zcj1i5Af'. + 'h8AjdIts+hUcGcYPK3iBtKM3gD/uAzf/AdY2mmmVgy6X8YNNKmGIvyloPcB8SUin07RQ4EZHFdsdG0wkJEnEaHAJxvKEpSLeaokV'. + 'r4zWmhUZYLlY4b1D03y5eIEWCtS7vsciAgiIxkQRabWOrlQor66y4pUphoJb1jiO4uO5o0S3q6RSqVbiOmC7VCEgAhLSaDQ48dH7'. + 'vD46REY0iysegSjKQciRt99ib7qXwX0O+pG4teM6YKHLB9JMq4mTmF9/+AKA4wvLZByH7OgYL7+UY2qvw/7Bfg5kHiXjJFyv3CGO'. + 'Y1rof+BW4t/XLiPG0DCGr79d4XzRxRnIMn98huXSTYyJ6et1UNYQhRvcinpJq86H3wGPPPM0iBDd+QffD1g4eZjLvuG7S1Wef26E'. + 'J7L7eSx7gAHVg7V3MSbi6m/r93baBd6qQjerAJg/9Ql/XrvG0ON1+vv7GH3qSfY5fahUnSTpwZgIEQesaVXRPbHRG/xyJSAxMYlp'. + 'EOm71HUINiY7mGb95l/8jZCyQmJjMDGJjUmsdCROtZ0n/P/Z8v4Fs2MTUUf7vYoAAAAASUVORK5CYII=' ; + + //========================================================== + // endconstrain.png + //========================================================== + $this->iBuiltinIcon[2][0]= 666 ; + $this->iBuiltinIcon[2][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ALEREILkh0+eQAAAIXSURBVHictZU9aFNRFMd/N81HX77aptJUWmp1LHRpIcWhg5sIDlUQ'. + 'LAXB4t7RRUpwEhy7iQ46CCIoSHcl0CFaoVARU2MFMYktadLXJNok7x2HtCExvuYFmnO4w/3gx+Gc/z1HKRTdMEdXqHbB/sgc/sic'. + 'nDoYAI8XwDa8o1RMLT+2hAsigtTvbIGVqhX46szUifBGswUeCPgAGB7QeLk0X4Ork+HOxo1VgSqGASjMqkn8W4r4vVtEgI/RRQEL'. + 'vaoGD85cl5V3nySR/S1mxWxab7f35PnntNyMJeRr9kCMqiHTy09EoeToLwggx6ymiMOD/VwcD7Oa/MHkcIiQx026WGYto5P/U+ZZ'. + '7gD0QwDuT5z9N3LrVPi0Xs543eQPKkRzaS54eviJIp4tMFQFMllAWN2qcRZHBnixNM8NYD162xq8u7ePSQ+GX2Pjwxc2dB2cLtB8'. + '7GgamCb0anBYBeChMtl8855CarclxU1gvViiUK4w2OMkNDnGeJ8bt9fH90yOnOkCwLFTwhzykhvtYzOWoBBbY//R3dbaNTYhf2RO'. + 'QpeuUMzv188MlwuHy0H13HnE48UzMcL0WAtUHX8OxZHoG1URiFw7rnLLCswuSPD1ulze/iWjT2PSf+dBXRFtVVGIvzqph0pQL7VE'. + 'avXYaXXxPwsnt0imdttCocMmZBdK7YU9D8wuNOW0nXc6QWzPsSa5naZ1beb9BbGB6dxGtMnXAAAAAElFTkSuQmCC' ; + + //========================================================== + // mail.png + //========================================================== + $this->iBuiltinIcon[3][0]= 1122 ; + $this->iBuiltinIcon[3][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AJHAMfFvL9OU8AAAPfSURBVHictZRdaBRXFMd/987H7tbNx8aYtGCrEexDsOBDaKHFxirb'. + 'h0qhsiY0ykppKq1osI99C4H2WSiFFMHWUhXBrjRi0uCmtSEUGgP1QWqhWjGkoW7M1kTX3WRn5p4+TJJNGolQ6IXDnDtz+N0z/3PP'. + 'UWBIpdpYa23b9g09PZ2kUrOrvmUyGVKp1Ao/mUyi56YnVgWfO/P1CihAd/dJMpmaNROIRq8BkM1m0bH6TasC3j6QXgFdXI+DR6PR'. + 'JX/Pno8B+KLnMKqlpUU8z8MYs2RBEDzWf9J+0RcRbMdxGBsbw/fmCXwPMUEYID4iAVp8wIRmDIHMo4yHSIBSASKC+CWE0C/PF9jU'. + '3B6Cp+4M07C5FUtKGNvGwQJctPgIsgD2wRhEIqAMGB+UQYkHJgYYZD7P1HwVlmWhHcfhyk83KeRGUW4t6CgoG5SNUS4KBWgQDUov'. + '7AGlwYASBVqH0Bk49dXpCviVV3dw/tI1Bvr7kMIIlh0NYUpjlF0BAYvcxSXmEVLKceHSCJm+PnbueBHbtkNwTXUNBzo6aGpq4sSZ'. + 'GwT5H7BsF6Wdf1GWHQAoM0upeI9PT1yioS7B7tdaSdSuw7KsUGMAy7HYsmUztTW1nMwM0txssX1rlHjjS5jy/Uq2YkK/eJuLl6/z'. + 'x+1xkslW6mrixGIODx8EFSlEBC0+tmXT0NhA2763iEUjnLv4C8XpUbSbAB1mKkGJ3J83Od77HW5EszvZSqK2iljMIeJaRGNuJePF'. + '6mspY7BJ1DXwQnCd2fxGRq5OUCz8xt72dyhMZcn++Cu3xu9SKhdp2b4ZHWnAtTSxmIWlhcIjlksR3lNBYzlxZsb7+f7ne+xtSzOd'. + 'u83szH1OnThOPp/n+a0beeP1l4mvq+PU2Qyd+5PY1RuwlAqLYFaBfbTbyPSdfgaH77A//QF4f1O/vpr6RJyq+C5Kc/M8FbFxXItY'. + 'xOHDrvfo/fxLDnbsJBp5BowBReVWYAzabeTh5ABDw7cWoNNL3YYYNtSv57lnn6Z+Qx01VeuIuBa2DV1HD3H63BAPZu4u1WGpeLHq'. + 'Rh7+NcjA0O+0p4+CNwXigwnbWlQQdpuEpli+n+PIkcOc//YKuckJJFh2K2anrjFw+QZt6S6kPImIF/b+cqAJD1LihWAxC61twBTo'. + 'fPcQF/oGsVW5ovHQlavs2/8+uYnRVSOUgHAmmAClBIOBwKC0gPjhIRgEIX2wg7NnwpZW3d3d4vs+vu8TBMGK51rvPM9b8hdteZxd'. + 'LBbVR8feJDs0Rlv6GFKeXJ21rNRXESxMPR+CBUl0nN7PjtO+dye7Up/8v1I88bf/ixT/AO1/hZsqW+C6AAAAAElFTkSuQmCC' ; + + //========================================================== + // startconstrain.png + //========================================================== + $this->iBuiltinIcon[4][0]= 725 ; + $this->iBuiltinIcon[4][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDgAACw4BQL7hQQAAAAd0SU1FB9ALEREICJp5fBkAAAJSSURBVHic3dS9a1NRGMfx77kxtS+xqS9FG6p1ER3qVJpBQUUc3CRU'. + 'BwURVLB1EAuKIP0THJQiiNRJBK3iJl18AyeltRZa0bbaJMbUNmlNSm5e7s25j0NqpSSmyag/OMM9POdzDuflwn8djz8gClVRrVEV'. + 'ur4Bl1FTNSzLrSS6vbml0jUUwSXj8Qfk3PkLtLW2AeBIybmrgz3+gFzpucjlE4f4btuFTuWuCF5XDr3a3UPf6cM8GQvxzbsRAJdh'. + 'ScfxSywml5j7mVypN0eGEJ0tebIre+zxB6Tv7jPReS2hREpOvpmUXU+H5eC913JnNCSRVE60pUVbWoZjprR39Yq70bdqj4pW7PEH'. + '5FpvL9e79jOTTHM7ssDL6CJZ08LbvAGnrpZg2mI2Z/MlZfN8IkxuSwu4V9+WIrj7zFlOHfXzKrLIi2SGh5ECKjnNVNxkQEc55vOw'. + 'rb6O8JLFdHyJ+ayFElUeHvjwkfteL/V7fKTSkFvIQE4DoLI2Mz/muTkTApcBKIwaN8pwIUrKw+ajWwDknAO0d/r4zFaMuRS63sWm'. + 'RoOdm+vRIriUYjKexrQV+t1o0YEVwfZSVJmD/dIABJuO0LG3lRFx0GOfiAELE9OgCrfU0XnIp5FwGLEy5WEAOxlR5uN+ARhP7GN3'. + '5w7Gv4bQI2+xpt4jjv2nWBmIlcExE2vDAHYioszBZXw6CPE4ADoWVHmd/tuwlZR9eXYyoszBfpiNQqaAOU5+TXRN+DeeenADPT9b'. + 'EVgKVsutKPl0TGWGhwofoquaoKK4apsq/tH/e/kFwBMXLgAEKK4AAAAASUVORK5CYII=' ; + + //========================================================== + // calc.png + //========================================================== + $this->iBuiltinIcon[5][0]= 589 ; + $this->iBuiltinIcon[5][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAA4AIwBbgMF12wAAAAlwSFlz'. + 'AAALEQAACxEBf2RfkQAAAAd0SU1FB9AHBxQeFsqn0wQAAAHKSURBVHicnZWff+RAGIef3U/gcOEgUAgUCgcLhYXCwsHBQeGgUDgs'. + 'FgMHB4VA/4Bg4XChWFgIFIqBwkJhsRAYeOGF+TQHmWSTTbKd9pU37/x45jvfTDITXEynAbdWKVQB0NazcVm0alcL4rJaRVzm+w/e'. + '3iwAkzbYRcnnYgI04GCvsxxSPabYaEdt2Ra6D0atcvvvDmyrMWBX1zPq2ircP/Tk98DiJtjV/fim6ziOCL6dDHZNhxQ3arIMsox4'. + 'vejleL2Ay9+jaw6A+4OSICG2cacGKhsGxg+CxeqAQS0Y7BYJvowq7iGMOhXHEfzpvpQkA9bLKgOgWKt+4Lo1mM9hs9m17QNsJ70P'. + 'Fjc/O52joogoX8MZKiBiAFxd9Z1vcj9wfSpUlDRNMcYQxzFpmnJ0FPH8nDe1MQaWSz9woQpWSZKEojDkeaWoKAyr1tlu+s48wfVx'. + 'u7n5i7jthmGIiEGcT+36PP+gFeJrxWLhb0UA/lb4ggGs1T0rZs0zwM/ZjNfilcIY5tutPxgOW3F6dUX464LrKILLiw+A7WErrl+2'. + 'rABG1EL/BilZP8DjU2uR4U+2E49P1Z8QJmNXUzl24A9GBT0IruCfi86d9x+D12RGzt+pNAAAAABJRU5ErkJggg==' ; + + //========================================================== + // mag.png + //========================================================== + $this->iBuiltinIcon[6][0]= 1415 ; + $this->iBuiltinIcon[6][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'. + 'AAALDAAACwwBP0AiyAAAAAd0SU1FB9ALDxEWDY6Ul+UAAAUESURBVHicdZVrbFRFGIafsyyF0nalV1R6WiggaAptlzsr1OgEogmC'. + '0IgoBAsBgkIrBAPEhBj/AP6xRTCUFEwRI4jcgsitXMrFCJptJWvBNpXYbbXtbtttt6e7e86ec/yxadlCfZPJZDIz73zzzjfvR2VL'. + 'F7U+hf0HD2JduIzTFy6SlJRkPtkcDgdCCE65OxFC8NPV6wghyM7OptankJ2dzbSC5QghEEIgCSHog9PpNAF27dlN6miZuPgElB4/'. + 'nmY3O7ZtByA1NVUCkGWZweD1eklJScESTbqxuIjrd+/x6uIl5M19hSy7nfGOeUxf+g7VjU1sKi7C4/GYsiyz7tAJAD4/cRaA1tZW'. + 'AHIPnECUVGD1+/3U19ebG4uLeHf1akamjsIwoVnVCOvQEdLoVILYYmMo3PIxSBJflpSaDX5FAmju1QAYv/8k/s8+wLVxOU0jR2LZ'. + '8sMFAApWrCApbRRDrRZirBYSLBKaoRPQw3SFernf2sav7T0Ubt4KwL4FMwF4Vu8FoHBCKgCzDhwHwLIhZ7y5a89u4m2JhA0wTdDC'. + 'OrphEjJMNElCHxKDEjaobmvlfo/Krj27CQQCJsCGJW8C0KXqAMxMiosQA8hZWcTFx9OsaniDKh1qmG7VoFsL0x0K06kbeAMhWpRe'. + '/KpG+gwHAKUnz7Dz3BUMw6DK18nuw99wt0Nh6VdHI8RJicmETQgFg7SFwjSrGv+oKp6ghldV6dZ0ugJBlF6FmCESQ2w2AIqXLsan'. + 'BrFYLJTnTCBrdBqveeopWZiPFaBHUegJhegMqGgxEkHDwB/UaQ9rdIV06v0+TD2EEQjQFtAY0dsNgNvt5sialQAIIXh7wQKuVf6J'. + 'gTsSccPDWlQstClBGjr9eHpVWvUQncEwdYEedF8noQ4vmYmpZMTH0nTvDn25vLbrNmu7bvfnsYEbAMnhcPDgwQPzUo2LJusw/mhp'. + 'QwlHNO0KBAnoIfxtrcQMT2De1Mm891wyUzNlUlJSpIyMDBobGzlzr5rFM/Koq6vrP8ASGxsLwPmKcvIShjPGZiPOakE3VFB8hHwd'. + 'vJAxhrk5L7Ly+RQuH/sWgPdXrwFg/6HDFBUsIj09nehfbAWwPWOT9n5RYhqGwarNWxkRM5TRCfF4U1PQsDDJFk9uYhwXvzvKjm3b'. + 'KSsro3DJInNW5RXp7u2bAKSlpeH1esnPz6eqqgqLpmmcr3Fht9ulfaV7mZk1Bs+lM6T1djM9fhg5egDPpTNMy5TZsW07kydPYdWM'. + 'aXx96ixOp9O8cfUa80srmDpjOgAulytiQqZpMnvObLbt/JTtHxXj9/tRVdU0DGOAufRpevPDTeac0hJyc3NxOOawfv161lVWS6eX'. + 'z+9/UOCxu1VWVvaTRGv16NFfjB2bNeAQp9NpTpmSM4DcbrdL0WsGDKLRR+52uwe1yP8jb2lpYfikyY9t80n03UCWZeaXVjw1f+zs'. + 'Oen+/d+pqanhzp2fKSsrw+l0mi6XiyPl5ZGITdN8fAVJwjRNJEmi1qfw1kw7siyTnJxMe3s71dXV3GpoZO64DG41NPJylvxU5D/e'. + 'qJKsfWQD9IkaZ2RmUvr9aV4aGYcQgjfO3aWoYBF5eXm4ewIsu/CbdPz1aWb0/p1bNoOrQxlUiuiaFo3c3FyEEOx9+C9CCD6paaTW'. + 'p/TXyYkTJ0Xe59jf7QOyAKDWp/QXxcFQ61P4pT3ShBBcvnUHIQTjxmX19/8BCeVg+/GPpskAAAAASUVORK5CYII=' ; + + //========================================================== + // lock.png + //========================================================== + $this->iBuiltinIcon[7][0]= 963 ; + $this->iBuiltinIcon[7][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALCwAACwsBbQSEtwAAAAd0SU1FB9AKAw0XDmwMOwIAAANASURBVHic7ZXfS1t3GMY/3+PprI7aisvo2YU6h6ATA8JW4rrlsF4U'. + 'qiAsF9mhl0N2cYTRy9G/wptAYWPD9iJtRy5asDe7cYFmyjaXOLaMImOrmkRrjL9yTmIS3120JybWQgfb3R74wuc8Lzw858vLOUpE'. + 'OK6pqSm2trbY39+nu7tbPHYch7m5OcLhMIA67kWj0aMQEWk6tm17rNm2LSIie3t7ksvlJJ1OSyqVkls3Z8SyLMnlcqTTaVKpFLdu'. + 'zmBZVj1HeY2VUti2TSQSQSml2bZdi0QirK2tMT09zerqKtlslqGhISYnJ4nHv2N+foFsNquOe9FotLlxOBwmk8lgWRbhcFgymYxY'. + 'liUi0mqaJoAuIi2macrdO7fFsizx3to0Te7euV1vrXtXEgqFmJmZYWVlhXK5LB4/U9kwDL784kYV0A3DYHd3m4sXRymXywKoRi8U'. + 'Ch01DgQCJBIJLMsiEAhIIpHw2uLz+eqtYrEYIqKZpimxWEyCwaCMjY01zYPBIJpXqVQqsby8TLVabWKA/v5+RkZGMAyDrq4ulFKH'. + 'HsfjcWZnZ+ns7KTRqwcnk0mKxSKFQqGJlVKtruuSTCYB6O3trW9UI/v9/iZPB/j8s2HOnX0FgHfeXpeffnzK+fWf+fijvhLs0PtG'. + 'D/n1OJ9+MsrlSwb3733DwMCAt1EyPj6uACYmJp56168NU6nUqFSE9nZdPE7+WqC/r4NKTagcCJVqDaUUB5VDAA4Pa9x7sMLlSwan'. + 'WjRmv13D7/erpaWlo604qOp88OF7LC48rPNosMq5Th+Dgxd4/XyA1rbzADi7j8jnf2P++wdcvSr8MJ/i8eomAKlUqn41OsDAQDeD'. + 'g++yuPCwzm/2vU8+n2a7sMFfj79mp7BBuVzioFSiXHJx3SKuW2Rzy0Up9dxnQVvODALQerqNRn4ZKe0Mvtc6TpzpmqbxalcY9Ato'. + '2v06t515C73YQftZB9GLnDrt4LoujuPgOA4Ui+C6yOpXJwZrJ7r/gv4P/u+D9W7fLxTz+1ScQxrZ3atRLaVxdjbY2d184R6/sLHe'. + 'opHP7/Do90Ua+WWUyezzZHObP/7cfX54/dowE1d66s8TV3oE+Mfn+L/zb4XmHPjRG9YjAAAAAElFTkSuQmCC' ; + + //========================================================== + // stop.png + //========================================================== + $this->iBuiltinIcon[8][0]= 889 ; + $this->iBuiltinIcon[8][1]= + 'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9AJDwEvNyD6M/0AAAL2SURBVHic1ZTLaxVnGIefb2bO5OScHJN4oWrFNqcUJYoUEgU3/Qf6'. + 'F7gwCkIrvdBLUtqqiLhSg9bgBduFSHZdiG5ctkJ3xRDbUFwUmghNzBDanPGMkzOX79LFJGPMOSd204U/+Bbzvd/78F4H/ieJdoad'. + 'pZKxRFszAI/DcP0HazXY22v+HB01kee1PA/v3zfnjx4xgGnHcNZe7OvuNj+cOEF1ZATv5nUA4jhBSgmADCVWo8Ge2Of9wb18P/G7'. + 'oUXmYi30zqlTVEdGWLh1g2D6MYlKkXGE0Vl8aa2GEB149+4xXSzyoOIw/mimiZV/DPb25pFOj13A9gOMEChhUEqhVYqWKUk9QAUp'. + 'sT/P4s8PmKlUmNhQaIJbkDVqBbpw6wZ2zUc4Nm+ePku5p4eOrgpueQOFUoVCVxcD4+N07dpF9+5tVJeWGPBjhvr7WF1zC8ASgtcP'. + 'H8a7eZ1odh4sh50nzwCw9ZNh3M4Stutiu0X2nB/LyjZ6lcIbVTpdQU/jWVPzLADM8+ZGBRdtC7wrF/O7bR99iu26VL86iU4SAH4b'. + 'Po5d6AQhstMSvGyI4wS5FJBKSRwnzF8byx/u+PjzzMF1mfryQ1K/jnCahqp1xEopjFLoNEFJSRJHzF799gWHqa+/QKcSUXBI609f'. + 'Al5W4teQSiHDOipNUKnMI13RvnOXAIEKQixvGWya98SC560MFwPiqEG86JM8q79Q06lvhnOndy5/B6GPCUOMUu3BQgg8z0M3GmBZ'. + 'iGJn3v2VmsqnfzNx7FDueODuj8ROCFpjtG5TCmOYv32bJ09msP0ISydMfnAUgF8/O45RAA6WTPjlvXcB+Gn7FuRf/zAnNX6x3ARe'. + 'PSdmqL+P/YHkwMGDOGWDZTlQcNBRhPEComgB/YeHfq2InF1kLlXUOkpMbio1bd7aATRD/X0M1lPeSlM2vt2X1XBZjZnpLG2tmZO6'. + 'LbQVOIcP+HG2UauH3xgwBqOz9Cc3l1tC24Fz+MvUDroeGNb5if9H/1dM/wLPCYMw9fryKgAAAABJRU5ErkJggg==' ; + + //========================================================== + // error.png + //========================================================== + $this->iBuiltinIcon[9][0]= 541 ; + $this->iBuiltinIcon[9][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaVBMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'. + 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpYiYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'. + 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTCAkUMSj9wWSOAAABLUlEQVR4'. + '2s2U3ZKCMAxGjfzJanFAXFkUle/9H9JUKA1gKTN7Yy6YMjl+kNPK5rlZVSuxf1ZRnlZxFYAm93NnIKvR+MEHUgqBXx93wZGIUrSe'. + 'h+ctEgbpiMo3iQ4kioHCGxir/ZYUbr7AgPXs9bX0BCYM8vN/cPe8oQYzom3tVsSBMVHEoOJ5dm5F1RsIe9CtqGgRacCAkUvRtevT'. + 'e2pd6vOWF+gCuc/brcuhyARakBU9FgK5bUBWdHEH8tHpDsZnRTZQGzdLVvQ3CzyYZiTAmSIODEwzFCAdJopuvbpeZDisJ4pKEcjD'. + 'ijWPJhU1MjCo9dkYfiUVjQNTDKY6CVbR6A0niUSZjRwFanR0l9i/TyvGnFdqwStq5axMfDbyBksld/FUumvxS/Bd9VyJvQDWiiMx'. + 'iOsCHgAAAABJRU5ErkJggg==' ; + + //========================================================== + // openfolder.png + //========================================================== + $this->iBuiltinIcon[10][0]= 2040 ; + $this->iBuiltinIcon[10][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEANAAtwClFht71AAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDQ4RIXMeaLcAAAd1SURBVHicxZd7jBXVHcc/58zcvTNzH8vusqw8FsTsKiCUUh5WBZXG'. + 'GkOptmqwNWsWLKXFGlEpzZI0AWNKSy0WhDS22gJKtWlTsSRqzYIuLGB2WVvDIwQMZQMsy2OFfdzde+/OnHP6x907vJaFpjb9JZM5'. + 'c85Mfp/f9/s7Jxn4P4e41gtSyp78WGvtfdEAcqDFYUOH9HS0NhGk9tPb/ilSyp789UUB2AMuqhQy3Uzm7HGkE6W3dTNZMRI3EcWO'. + 'jf9ClLmWBT3dzW8jUsevWHCG3UpWl+IkHSxnbDh/Mcz12NevBcuWXTmf6TjnXvJ88gDmVB3pw3+nt3UzHa1NqMzBS2zqPLGFjtMN'. + 'ZNr3XdW+qyqwZcFk76HX/tHWfuQvyO4W7qhaHwL8efkMRlRUpPv7rqD0RrJ+FgAjLy1a20OIxZJEEuNCRfIApj+om4bGM3u2/sYU'. + '9J41d8973f3Dhg1pISTV1dXXBRNJxPGFCzhou+DCQrScZOkktNaeDZjamgeZ9MgiYmVDccvHhjAzJw0NTh8/alyZMaVJicp0iTHj'. + 'JpgNv38tjWUhhGROdbUL9W5/MH5XCkjlcibi+KIop5LVHLKEu8A/f4r286doa9pGrGwYAAsfqbbH3b8MgO/Nqgy6WvdbbXHMkEFJ'. + '4xUOMVEvaTZu3BgmvF4Yk4hz9rO/Ulr5cE9owae/rcGxohSOuiWkC2IjcIqKyPZm+OmCH7GhoZEF077EEzVVweAbJ+riEeO0Ey8y'. + 'UubqOHn0AOgMwvf59txnBrSp9dgxKmf/+kIP1NY8SFk0jh5ajmNHAWg5b2E5EexojGHjbiVRMoRMNs0LC+Yz46vTuH3enN7BI8fr'. + 'qFdo0BoVZNC9aVSQ4fNjBzEmQJiARxb+/AqYPMAVB5FsPU5v37g9OxgLhe14ZM5/ju052E6MNZvf5pmHHuLmmWOkEysxUtpGAtme'. + 'dtHTflJkezqQto3jFRnLssyf1jydxiiM7zNnye/c3ZsqLu2BN5fcMfzrv/hby1tPzmRUoihcTJ87CwQI2yLtDcIqsIjYUf51qBlf'. + 'OnScOSrdQUOMURkiXsLUzJnvbGhoBGDHH5cGyZLhOpYoNl5hqYnYEXOu5fDl9eYAHntx98n8hFHZcPHUuTSxSASAeK/CGIOxJJ0f'. + 'bOGNPU280dgkq6Y2yu8vfjCIlwwzr+/ZQ/PHO0gOLuO5qsftDQ2NbN+4OCgqG6WTxWVaq6zpF+DiSHWnicdylp3r6aZTWthIOrNp'. + 'ktHcvBu0sHX1Sm6ozB3B42d90zZA9bQp7PvgPSzXZfnqX/HS4DKKK2+x69Y/HURs26iBAN5ccsfw7774UcumF37C6f07KSt2OHji'. + 'DEUJD0tISjyPrrSPlAKvN0JP/U4O1NfjuhG2rvklN1SOpfXwftpbTqAyKRrff5fb7rs9V1R7m4wlz2ihA3HpmXflUWyOH2umpLiY'. + 'ui3v8M+6bWzfsRNbSgqkxaCkiy0simMuEWEhpcRzIhQWOIAh6tiAwS4owInFiTou5dOnMnl2NR++ujBwXEc9terD6M43nrj6LgAB'. + 'QnDPA9/irtkP8JRS7Hr/3T6YekDQ1pEiEXOwpUVJzCVlZZFS4mZtkpEo9ChAkDp/jtLMBACy6S4RiQghLyv5cgBRPnKUOX6smUGF'. + 'hSil0MYw9d77mPy1e5mnFE3batm3czvb6nYgEJztSFGU9LCRlMRdUjIH0+lnEMIwPNXD3NumoVJnrMCJaiciMUZfvQnz4QcBSvV1'. + 'vjE5GK358t0zmXDnDB79saLpo20c+aSRD+t25JTp7GZQwsEWFiVxl6hlUf/WO9z32CxmL1rOe6u/I2KuwGhzLQCB7/sYY9Bah3el'. + 'FKbvrrVm4vS7GH/7ncx+chEHGz7myCeNbPtoO0JI2jq78WIRLGkzsqs7V5SfFV5EovXACoiqqsfNpk2vo5VCWtYFBfoU0VoTBAFa'. + 'a7TRaK2p+MoURk+cxMzq+Rzbv49DDbuo27UTW9h0dedssPxuK+kIfN8XxhgDYPVXf2Fh4XKtFIl4AiklAlBKAYRKKK36wHIweTCt'. + 'NfHiEkaOn8j0+7/BmDFjaT30GbHywSxcuZkpFfFg+m1jjZ/NmnVvNfRvwd69e8WBA/uNFAIh4JVXXmHsmDHE4vEQQgjQ2lxQIm9N'. + 'nz35q3BEOZOHzaG2thaA4mRU+L29It+IV21CpbRQfeMFC35gRB/M2rVrubnyZmLxWJhECBEmz/eHyo/7lMlH3LFFujsthNFCCGOu'. + '+WNyeUgpjSVzMKtWraKyshLPdcPEeYWCIEBdpIxSivr6eta8vI7d6+cGnhdV06pe1QP+F/QXWmuRL+jZZ58LlVmxYgUVFRV4rhtu'. + '4TzMxXAA6XRaRAtsYUkx8I/JtSJQOlSwpmZpCLN8+fPcdNNoHMfB9/0QJgRoP295TlR7UVv8xxZcHMuWIZ9/Hn35vG3JEGZpzVJG'. + 'jx5N1IlitKahsZE1L69j69qHgx+urFX/lQL9JYdLlfnZihUhzOLFi8N3Ml1dthOxVH/f/8/CtqSJ2JaJ2JZ59J7RPsC/AViJsQS/'. + 'dBntAAAAAElFTkSuQmCC' ; + + //========================================================== + // folder.png + //========================================================== + $this->iBuiltinIcon[11][0]= 1824 ; + $this->iBuiltinIcon[11][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALEAAACxABrSO9dQAAAAd0SU1FB9ECAQgFFyd9cRUAAAadSURBVHiczdhvbBP3Hcfx9/2xfefEOA5JoCNNnIT8AdtZmYBETJsI'. + '6+jQOlQihT1AYgytqzZpD1atfyYqlT1h0lRpT7aRJ4NQpRvZGELVuo5Ua9jEJDIETQsNQyPBsUJMWGPnj//e+e72wNg4xElMR6ed'. + 'ZNln3933dZ/f93f6yfB/sgmrHdDV1WXlPg8NDZUDScD8LFFFEZZlWYZhWMFg0Orq6sq/gDJAfFy1iiZy9OjrVnj4JzQ1rMWqfxm/'. + '309jYyNtbW0kEgnu3bvH4cOH88c/jqSKQl4/XGkd+eVtAN46up1LH92ktqYS++ZX8Pv9NDQ0sGnTJlKpFOFwmO7u7vy5IyMjeVRd'. + 'XV1+WEOh0IrY4pDnq6wXX/sTiCJaMkFZdRNqxefoe7VtCSqXVDqdZnZ2ltraWkzTpKqqijt3JpFlG7dvj7NzZ1f++qFQyA3EClHL'. + 'Ql743nFkhxPDtJAd5eTaYSVUfX09lZWVlJWVIUnSg7sVQMBCUcu4ceMGe/bsIRQK1QAzOcyykIM9P0KyudAyCWyqG8nhwqa4SkLt'. + '3r0bVVVxu924XC40TUOWZUQxe97CwgIdHR2LMHIxSCaVInVvFElxE0vMY1Pd2NUKJMWNTXHlUfF//4vETJCelwbpFm3MjP2dt37x'. + 'AlN+PzU1NViWRSwW4+7du3g8HjweD4qi5EFAJzAExIpCANbooxhplfB0FJvTg6xWIqsVRVF6MopkU3FXPcnkJxGU0VEAdF2noqKC'. + 'W3/8DpnqLjzep2lubsblcjE8PExHR8fboVDID9xYFpLBDpJF0jDQIncQpWlkm31FlFLtp9PfyuW/vYQj1kPSuRW/38+lj27S2Q7v'. + '/aWXUBVUffVNtm3blivVCEwsC5Eyc5iiApEpDEAXMqQdldhSiWVQHjJagud+8Fuexck/zv+K82dfoSbSCsDe75/km+4GVPd6+l5t'. + '4zJHcqVUYN2yEEtZQDCSJCueRAYsPY49HsFIZVG6p25JUumFafT4DKJN4amtT7Nz38sk5+5A70HMtEYyMkFiZhxzjQ/poXrLQrRU'. + 'DFGEeFpAlkQkm4pRiCpIKodKzk0T/2QMh+piPjxKZPwiSkUtu/b9mNnJEWS7E8nhAmvpM60oJDkXJxqNozxRRUxPIesispBBlsXV'. + 'UaKEFo8gzoaJhz8s2lOmrpUG+WBhJ9/60g+Z+fDXTAXfxllRjl1VkO0OFATsYhYliiK21ZKKhhHnFveUqSdKgwAEOp7F2v51vvw8'. + 'XH7/N1wd/BlTweuUV65BdtgfoLTSkipsdD3tRi0VYpommUwGwzDwdT5HYEc3giAwcvH3jLz3BlPB67jWeZBEKYsSBWwpHZtNKo4q'. + 'aHTDsJeeiGEYWJaFZVmYpommaRiGQdPnv0bb1m8gSRL/vPIOV979aR4lmAJ2p4qCgCxksNuKJ6VNpx4NYhgGpmkuQhmGQTqdxjAM'. + 'qr2d7HtxEEEQuH1tkKvvvkF44tqDnrIcKJKAPf1g+LAUElq8dIiu60sApmnm93Pfzc7OYhgGrie+wFe++ztcLhcT1wf54PzPCU9c'. + 'w7XWjWS3IdsdOAUBWZAxrRJnTQ6SG5bce2FCpmkughmGQSqVYm5uDtnj44sH38TtdhP6+Dwf//V4ttHXrkGURZJaic8RgHQ6jWma'. + 'SJKUL5RLKNfIOczDKF3XSSaTRCIRhLJWntp3nGfWrSMxc5OLf3iNP4+68T9Ub9nF76lTpxgfHycajZJKpdA0LZ9GbjYV7hcDWZaF'. + 'pmnMz88Ti8UYunSLmu1HFi2aVkxkaGjINTY2ttDb24vX6+XQoUNs3ryZ8vJyIDu1BUFYkkxhgxeiWlpaOHPmDE1NTdTX1xe98eWG'. + 'JnF/9dQZCoXUYDA4AOD1ejlw4ACtra2Ul5fniwmCkEcUJiUIAoFAgL6+Pnw+H21tbfT39z8SxCS7hHsfWH9/8dL4MKqnp4eWlhac'. + 'TmcekEvMNE2am5s5ceIEgUCA9vZ2Tp48ic/nY3j4UsmQHCYOjJHtpeBKqL1799Lc3IzT6UTXdRobGxkYGKC9vZ3W1tZ8Ko86NJ8a'. + 'tXHjRo4dO8bp06fZsmULGzZsoL+/n0AggNfr5ezZs/8VpGTU5OSkc//+/acBfD4f1dXV7Nq1i4aGBs6dO4fP5+Pq1SuPBbIiyjTN'. + 'RUnV1dUNXLhwAa/Xy44dO4jFYgBEo9FFF1r134BPuYlk16LrAYXsAlmtq6sbKDwoFAp9m+ykuP5ZQVZF3f8tCdwCov8LyHIoAANI'. + 'AXf/A1TI0XCDh7OWAAAAAElFTkSuQmCC' ; + + //========================================================== + // file_important.png + //========================================================== + $this->iBuiltinIcon[12][0]= 1785 ; + $this->iBuiltinIcon[12][1]= + 'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'. + 'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ECDAcjDeD3lKsAAAZ2SURBVHicrZhPaFzHHcc/897s7lutJCsr2VHsOHWMk0MPbsBUrcnF'. + 'OFRdSo6FNhdB6SGHlpDmYtJCDyoxyKe6EBxKQkt7KKL0T6ABo0NbciqigtC6PhWKI2NFqqxdSd7V2/dmftPDvPd212t55dCBYfbN'. + 'zpvfZ77z+/1mdhUjytWrV93Hf/24eD5z9gwiMlDjOKbb7dLtdhER2u02u7u73Lp1CxEZBw4AeZwdNQqkMd9wbziFGINJUt6rRbz5'. + '1ptUq1XK5TJBEAAUMHt7e+zu7gKwvLzMysoKwAng/uNg9CgQgFKlgg1DUJ67Vqtx6tQpZmdniaIIpRTOOZRSdDoddnZ2aLfbLC8v'. + 's7S0xJUrV7ZGwQSj1PhhfRodVdDlMrpc5vup5Z2fvMPdu3fZ29vDWjvwztjYGPV6nVqtRqVS4dKlSywtLQFsAdOH2XwsCEApg3jl'. + 'w98Rak2gvYjNZpNms0mSJDjnHgkDMDc3dySYQ0Ea8w139YUX0OUKulzyg7UmCEO+l1huvHuDra0t9vf3h1TJYSqVypFhHquIrlQI'. + 'S5qv/uIDAC7/4bcEQYAKvK+0Wq1DVQGIoog7d+4cCeaRII35hrt+8SsEOkRlUaEyR0UpFIrXHxyMVKVUKnHv3r0jwRwaNelBjBjL'. + 'Sz/7KYuLiwAsLi7y4z/9kY9e+TpkCuSqjI+Po7XuAWeKXLt2DWNMUZMkwRjDhQsXWFtbK6JpCCT3jfQgxomPtPX19YHWicM5x3c2'. + '73Pj3Ru8/aO3mZqaolKpoHVvyuvXr/Ppnf/Q7uzz380NPtu4y/qnG+ztd1hfX2dtbQ3gIvDnRyqSxl1UoPjyz98D4PTp0wPtq39Z'. + '4fdzLxegrVaLVqvF5OQkYRgWqpRKJZ77wvNsbW1RG5tgfKLOTH2G7Z1twqBQrgrMDvhInjfSOCY5iIv+hYWFgRZArEWsZWF941Bf'. + 'SdMUgMnJCWpjVU4cn+HUyePM1Gc4+fRUPkzBI5w1jbukcczLv/5l0XfmzJmBFuCba38r/CRXpT+CrDUoZ0jjB4RYonJAOYRobJKT'. + 'z5zgqfqxAbsFSH6mpHFM2qdGXh4VnoViD6mSJF2cTQeqDqBaKVHWmonJCWpZjhkC6anR5WsffTgwaHV1FaUUq6urA/2v3f5k4LnV'. + 'arG9tUn3oI2YBCcWHYAxMVYs1qZEZY2SFB2aYZDGfMN9d7uJiWPSeFiNo5Rclc3NTXZbO6RpF7EJVixYA9agwwDnUiqlEPdQ3imi'. + 'Jo27BGHIt/7x9yEjc3Nzh27Na7c/4TdffKl4bja3ae5MUIu0T/HOEIaOpJt4gwoSsVTK4SBIY77hFtY3ABBjBiZ90rKwvsH77/+K'. + 't37wOhO1iPpTk4SBw1mLsz6CnKQ4l3qV+kE+t9XHlNZOk+bUJLVIE1VCcIJWQmJ6qjj30NbcXLkZMt8YPig+Z3n1G5fZ39/j/vY2'. + '9ckqZT2Ochbn0p4qNkU/dDfUADdXbh4HXgRO4zNdEU0XL1784PLly5w9e7Z4SazFOfGrEotDcOKrcoJPmrYIXf/Zop3QNd1skuGt'. + 'cUAb2MgAxvHZTgFUq1Wmp6eZnZ0F8JlTjDduDThBnDeECEoJtbGIp6enqEblzCcEZ1PECU4yVRiOGgd0gc+AB0CZvkv1sWPHOHfu'. + 'HOfPn8da41cpkkltEBEPJhYnBkTQJcdYVKGkgRxCfBsq5xXNgAa2Bn+hjTOgHEKBP8pzRUxykIH4ifLJRTJAl+UMBJzPHQ6bfe/f'. + 'cWIzPxlUpD+zugzIZtVk1d8znBAqRxgoQuVQgSJQ3h9C5QhDRYgjUILCAzlnEdsHYTKfMTEBcP7F54YUGVmc2GLlIn6ve6v0ahSt'. + '8X25TzjJ+rIx1grKpQPWR4LkGVVsMgghvS0qjPdvm5OeceOTWA5Evo2mFzkjQfL7hZPUy5yvvF/uPFQL3+nbDmsLCEmT3sTmCTNr'. + 'rogT6yFsOix3ftw7OwQhkvSU6CuinhCk0+kAkFoBazEEICHaHHiPVmU0gnUp4EAc1mYrF0EBVpwPi34VrBkwPxKk3W5ju/e5/c+d'. + 'bGUHIAIuydTIE5zfc5Wr4lJcahHnHTP3CVGm78DrgY38N+DEibp7dmYKdAQmBh1hjEFjis+9CTWYGK21H6PxPyOI0DobYwzZF/z7'. + '7jadTvJtYG0kCD7lfwl49ijgT1gc0AH+dZSJA/xB+Mz/GSIvFoj/B7H1mAd8CO/zAAAAAElFTkSuQmCC' ; + + $this->iLen = count($this->iBuiltinIcon); + } +} + +//=================================================== +// Global cache for builtin images +//=================================================== +$_gPredefIcons = new PredefIcons(); + +//=================================================== +// CLASS IconImage +// Description: Holds properties for an icon image +//=================================================== +class IconImage { + private $iGDImage=null; + private $iWidth,$iHeight; + private $ixalign='left',$iyalign='center'; + private $iScale=1.0; + + function IconImage($aIcon,$aScale=1) { + GLOBAL $_gPredefIcons ; + if( is_string($aIcon) ) { + $this->iGDImage = Graph::LoadBkgImage('',$aIcon); + } + elseif( is_integer($aIcon) ) { + // Builtin image + $this->iGDImage = $_gPredefIcons->GetImg($aIcon); + } + else { + JpGraphError::RaiseL(6011); +//('Argument to IconImage must be string or integer'); + } + $this->iScale = $aScale; + $this->iWidth = Image::GetWidth($this->iGDImage); + $this->iHeight = Image::GetHeight($this->iGDImage); + } + + function GetWidth() { + return round($this->iScale*$this->iWidth); + } + + function GetHeight() { + return round($this->iScale*$this->iHeight); + } + + function SetAlign($aX='left',$aY='center') { + + $this->ixalign = $aX; + $this->iyalign = $aY; + + } + + function Stroke($aImg,$x,$y) { + + if( $this->ixalign == 'right' ) { + $x -= $this->iWidth; + } + elseif( $this->ixalign == 'center' ) { + $x -= round($this->iWidth/2*$this->iScale); + } + + if( $this->iyalign == 'bottom' ) { + $y -= $this->iHeight; + } + elseif( $this->iyalign == 'center' ) { + $y -= round($this->iHeight/2*$this->iScale); + } + + $aImg->Copy($this->iGDImage, + $x,$y,0,0, + round($this->iWidth*$this->iScale),round($this->iHeight*$this->iScale), + $this->iWidth,$this->iHeight); + } +} + + +//=================================================== +// CLASS TextProperty +// Description: Holds properties for a text +//=================================================== +class TextProperty { + public $iShow=true; + public $csimtarget='',$csimwintarget='',$csimalt=''; + private $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10; + private $iColor="black"; + private $iText=""; + private $iHAlign="left",$iVAlign="bottom"; + +//--------------- +// CONSTRUCTOR + function TextProperty($aTxt='') { + $this->iText = $aTxt; + } + +//--------------- +// PUBLIC METHODS + function Set($aTxt) { + $this->iText = $aTxt; + } + + function SetCSIMTarget($aTarget,$aAltText='',$aWinTarget='') { + if( is_string($aTarget) ) + $aTarget = array($aTarget); + $this->csimtarget=$aTarget; + + if( is_string($aWinTarget) ) + $aWinTarget = array($aWinTarget); + $this->csimwintarget=$aWinTarget; + + if( is_string($aAltText) ) + $aAltText = array($aAltText); + $this->csimalt=$aAltText; + + } + + function SetCSIMAlt($aAltText) { + if( is_string($aAltText) ) + $aAltText = array($aAltText); + $this->csimalt=$aAltText; + } + + // Set text color + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function HasTabs() { + if( is_string($this->iText) ) { + return substr_count($this->iText,"\t") > 0; + } + elseif( is_array($this->iText) ) { + return false; + } + } + + // Get number of tabs in string + function GetNbrTabs() { + if( is_string($this->iText) ) { + return substr_count($this->iText,"\t") ; + } + else{ + return 0; + } + } + + // Set alignment + function Align($aHAlign,$aVAlign="bottom") { + $this->iHAlign=$aHAlign; + $this->iVAlign=$aVAlign; + } + + // Synonym + function SetAlign($aHAlign,$aVAlign="bottom") { + $this->iHAlign=$aHAlign; + $this->iVAlign=$aVAlign; + } + + // Specify font + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function IsColumns() { + return is_array($this->iText) ; + } + + // Get width of text. If text contains several columns separated by + // tabs then return both the total width as well as an array with a + // width for each column. + function GetWidth($aImg,$aUseTabs=false,$aTabExtraMargin=1.1) { + $extra_margin=4; + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + if( is_string($this->iText) ) { + if( strlen($this->iText) == 0 ) return 0; + $tmp = split("\t",$this->iText); + if( count($tmp) <= 1 || !$aUseTabs ) { + $w = $aImg->GetTextWidth($this->iText); + return $w + 2*$extra_margin; + } + else { + $tot=0; + $n = count($tmp); + for($i=0; $i < $n; ++$i) { + $res[$i] = $aImg->GetTextWidth($tmp[$i]); + $tot += $res[$i]*$aTabExtraMargin; + } + return array(round($tot),$res); + } + } + elseif( is_object($this->iText) ) { + // A single icon + return $this->iText->GetWidth()+2*$extra_margin; + } + elseif( is_array($this->iText) ) { + // Must be an array of texts. In this case we return the sum of the + // length + a fixed margin of 4 pixels on each text string + $n = count($this->iText); + for( $i=0, $w=0; $i < $n; ++$i ) { + $tmp = $this->iText[$i]; + if( is_string($tmp) ) { + $w += $aImg->GetTextWidth($tmp)+$extra_margin; + } + else { + if( is_object($tmp) === false ) { + JpGraphError::RaiseL(6012); + } + $w += $tmp->GetWidth()+$extra_margin; + } + } + return $w; + } + else { + JpGraphError::RaiseL(6012); + } + } + + // for the case where we have multiple columns this function returns the width of each + // column individually. If there is no columns just return the width of the single + // column as an array of one + function GetColWidth($aImg,$aMargin=0) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + if( is_array($this->iText) ) { + $n = count($this->iText); + for( $i=0, $w=array(); $i < $n; ++$i ) { + $tmp = $this->iText[$i]; + if( is_string($tmp) ) { + $w[$i] = $aImg->GetTextWidth($this->iText[$i])+$aMargin; + } + else { + if( is_object($tmp) === false ) { + JpGraphError::RaiseL(6012); + } + $w[$i] = $tmp->GetWidth()+$aMargin; + } + } + return $w; + } + else { + return array($this->GetWidth($aImg)); + } + } + + // Get total height of text + function GetHeight($aImg) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetFontHeight(); + } + + // Unhide/hide the text + function Show($aShow=true) { + $this->iShow=$aShow; + } + + // Stroke text at (x,y) coordinates. If the text contains tabs then the + // x parameter should be an array of positions to be used for each successive + // tab mark. If no array is supplied then the tabs will be ignored. + function Stroke($aImg,$aX,$aY) { + if( $this->iShow ) { + $aImg->SetColor($this->iColor); + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + $aImg->SetTextAlign($this->iHAlign,$this->iVAlign); + if( $this->GetNbrTabs() <= 1 ) { + if( is_string($this->iText) ) { + // Get rid of any "\t" characters and stroke string + if( is_array($aX) ) $aX=$aX[0]; + if( is_array($aY) ) $aY=$aY[0]; + $aImg->StrokeText($aX,$aY,str_replace("\t"," ",$this->iText)); + } + elseif( is_array($this->iText) && ($n = count($this->iText)) > 0 ) { + $ax = is_array($aX) ; + $ay = is_array($aY) ; + if( $ax && $ay ) { + // Nothing; both are already arrays + } + elseif( $ax ) { + $aY = array_fill(0,$n,$aY); + } + elseif( $ay ) { + $aX = array_fill(0,$n,$aX); + } + else { + $aX = array_fill(0,$n,$aX); + $aY = array_fill(0,$n,$aY); + } + $n = min($n, count($aX) ) ; + $n = min($n, count($aY) ) ; + for($i=0; $i < $n; ++$i ) { + $tmp = $this->iText[$i]; + if( is_object($tmp) ) { + $tmp->Stroke($aImg,$aX[$i],$aY[$i]); + } + else + $aImg->StrokeText($aX[$i],$aY[$i],str_replace("\t"," ",$tmp)); + } + } + } + else { + $tmp = split("\t",$this->iText); + $n = min(count($tmp),count($aX)); + for($i=0; $i < $n; ++$i) { + $aImg->StrokeText($aX[$i],$aY,$tmp[$i]); + } + } + } + } +} + +//=================================================== +// CLASS HeaderProperty +// Description: Data encapsulating class to hold property +// for each type of the scale headers +//=================================================== +class HeaderProperty { + public $grid; + public $iShowLabels=true,$iShowGrid=true; + public $iTitleVertMargin=3,$iFFamily=FF_FONT0,$iFStyle=FS_NORMAL,$iFSize=8; + public $iStyle=0; + public $iFrameColor="black",$iFrameWeight=1; + public $iBackgroundColor="white"; + public $iWeekendBackgroundColor="lightgray",$iSundayTextColor="red"; // these are only used with day scale + public $iTextColor="black"; + public $iLabelFormStr="%d"; + public $iIntervall = 1; + +//--------------- +// CONSTRUCTOR + function HeaderProperty() { + $this->grid = new LineProperty(); + } + +//--------------- +// PUBLIC METHODS + function Show($aShow=true) { + $this->iShowLabels = $aShow; + } + + function SetIntervall($aInt) { + $this->iIntervall = $aInt; + } + + function GetIntervall() { + return $this->iIntervall ; + } + + function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { + $this->iFFamily = $aFFamily; + $this->iFStyle = $aFStyle; + $this->iFSize = $aFSize; + } + + function SetFontColor($aColor) { + $this->iTextColor = $aColor; + } + + function GetFontHeight($aImg) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetFontHeight(); + } + + function GetFontWidth($aImg) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetFontWidth(); + } + + function GetStrWidth($aImg,$aStr) { + $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); + return $aImg->GetTextWidth($aStr); + } + + function SetStyle($aStyle) { + $this->iStyle = $aStyle; + } + + function SetBackgroundColor($aColor) { + $this->iBackgroundColor=$aColor; + } + + function SetFrameWeight($aWeight) { + $this->iFrameWeight=$aWeight; + } + + function SetFrameColor($aColor) { + $this->iFrameColor=$aColor; + } + + // Only used by day scale + function SetWeekendColor($aColor) { + $this->iWeekendBackgroundColor=$aColor; + } + + // Only used by day scale + function SetSundayFontColor($aColor) { + $this->iSundayTextColor=$aColor; + } + + function SetTitleVertMargin($aMargin) { + $this->iTitleVertMargin=$aMargin; + } + + function SetLabelFormatString($aStr) { + $this->iLabelFormStr=$aStr; + } + + function SetFormatString($aStr) { + $this->SetLabelFormatString($aStr); + } + + +} + +//=================================================== +// CLASS GanttScale +// Description: Responsible for calculating and showing +// the scale in a gantt chart. This includes providing methods for +// converting dates to position in the chart as well as stroking the +// date headers (days, week, etc). +//=================================================== +class GanttScale { + public $minute,$hour,$day,$week,$month,$year; + public $divider,$dividerh,$tableTitle; + public $iStartDate=-1,$iEndDate=-1; + // Number of gantt bar position (n.b not necessariliy the same as the number of bars) + // we could have on bar in position 1, and one bar in position 5 then there are two + // bars but the number of bar positions is 5 + public $actinfo; + public $iTopPlotMargin=10,$iBottomPlotMargin=15; + public $iVertLines=-1; + public $iVertHeaderSize=-1; + // The width of the labels (defaults to the widest of all labels) + private $iLabelWidth; + // Out image to stroke the scale to + private $iImg; + private $iTableHeaderBackgroundColor="white",$iTableHeaderFrameColor="black"; + private $iTableHeaderFrameWeight=1; + private $iAvailableHeight=-1,$iVertSpacing=-1; + private $iDateLocale; + private $iVertLayout=GANTT_EVEN; + private $iUsePlotWeekendBackground=true; + private $iWeekStart = 1; // Default to have weekends start on Monday + +//--------------- +// CONSTRUCTOR + function GanttScale($aImg) { + $this->iImg = $aImg; + $this->iDateLocale = new DateLocale(); + + $this->minute = new HeaderProperty(); + $this->minute->SetIntervall(15); + $this->minute->SetLabelFormatString('i'); + $this->minute->SetFont(FF_FONT0); + $this->minute->grid->SetColor("gray"); + + $this->hour = new HeaderProperty(); + $this->hour->SetFont(FF_FONT0); + $this->hour->SetIntervall(6); + $this->hour->SetStyle(HOURSTYLE_HM24); + $this->hour->SetLabelFormatString('H:i'); + $this->hour->grid->SetColor("gray"); + + $this->day = new HeaderProperty(); + $this->day->grid->SetColor("gray"); + $this->day->SetLabelFormatString('l'); + + $this->week = new HeaderProperty(); + $this->week->SetLabelFormatString("w%d"); + $this->week->SetFont(FF_FONT1); + + $this->month = new HeaderProperty(); + $this->month->SetFont(FF_FONT1,FS_BOLD); + + $this->year = new HeaderProperty(); + $this->year->SetFont(FF_FONT1,FS_BOLD); + + $this->divider=new LineProperty(); + $this->dividerh=new LineProperty(); + $this->dividerh->SetWeight(2); + $this->divider->SetWeight(6); + $this->divider->SetColor('gray'); + $this->divider->SetStyle('fancy'); + + $this->tableTitle=new TextProperty(); + $this->tableTitle->Show(false); + $this->actinfo = new GanttActivityInfo(); + } + +//--------------- +// PUBLIC METHODS + // Specify what headers should be visible + function ShowHeaders($aFlg) { + $this->day->Show($aFlg & GANTT_HDAY); + $this->week->Show($aFlg & GANTT_HWEEK); + $this->month->Show($aFlg & GANTT_HMONTH); + $this->year->Show($aFlg & GANTT_HYEAR); + $this->hour->Show($aFlg & GANTT_HHOUR); + $this->minute->Show($aFlg & GANTT_HMIN); + + // Make some default settings of gridlines whihc makes sense + if( $aFlg & GANTT_HWEEK ) { + $this->month->grid->Show(false); + $this->year->grid->Show(false); + } + if( $aFlg & GANTT_HHOUR ) { + $this->day->grid->SetColor("black"); + } + } + + // Should the weekend background stretch all the way down in the plotarea + function UseWeekendBackground($aShow) { + $this->iUsePlotWeekendBackground = $aShow; + } + + // Have a range been specified? + function IsRangeSet() { + return $this->iStartDate!=-1 && $this->iEndDate!=-1; + } + + // Should the layout be from top or even? + function SetVertLayout($aLayout) { + $this->iVertLayout = $aLayout; + } + + // Which locale should be used? + function SetDateLocale($aLocale) { + $this->iDateLocale->Set($aLocale); + } + + // Number of days we are showing + function GetNumberOfDays() { + return round(($this->iEndDate-$this->iStartDate)/SECPERDAY); + } + + // The width of the actual plot area + function GetPlotWidth() { + $img=$this->iImg; + return $img->width - $img->left_margin - $img->right_margin; + } + + // Specify the width of the titles(labels) for the activities + // (This is by default set to the minimum width enought for the + // widest title) + function SetLabelWidth($aLabelWidth) { + $this->iLabelWidth=$aLabelWidth; + } + + // Which day should the week start? + // 0==Sun, 1==Monday, 2==Tuesday etc + function SetWeekStart($aStartDay) { + $this->iWeekStart = $aStartDay % 7; + + //Recalculate the startday since this will change the week start + $this->SetRange($this->iStartDate,$this->iEndDate); + } + + // Do we show min scale? + function IsDisplayMinute() { + return $this->minute->iShowLabels; + } + + // Do we show day scale? + function IsDisplayHour() { + return $this->hour->iShowLabels; + } + + + // Do we show day scale? + function IsDisplayDay() { + return $this->day->iShowLabels; + } + + // Do we show week scale? + function IsDisplayWeek() { + return $this->week->iShowLabels; + } + + // Do we show month scale? + function IsDisplayMonth() { + return $this->month->iShowLabels; + } + + // Do we show year scale? + function IsDisplayYear() { + return $this->year->iShowLabels; + } + + // Specify spacing (in percent of bar height) between activity bars + function SetVertSpacing($aSpacing) { + $this->iVertSpacing = $aSpacing; + } + + // Specify scale min and max date either as timestamp or as date strings + // Always round to the nearest week boundary + function SetRange($aMin,$aMax) { + $this->iStartDate = $this->NormalizeDate($aMin); + $this->iEndDate = $this->NormalizeDate($aMax); + } + + + // Adjust the start and end date so they fit to beginning/ending + // of the week taking the specified week start day into account. + function AdjustStartEndDay() { + + if( !($this->IsDisplayYear() ||$this->IsDisplayMonth() || $this->IsDisplayWeek()) ) { + // Don't adjust + return; + } + + // Get day in week for start and ending date (Sun==0) + $ds=strftime("%w",$this->iStartDate); + $de=strftime("%w",$this->iEndDate); + + // We want to start on iWeekStart day. But first we subtract a week + // if the startdate is "behind" the day the week start at. + // This way we ensure that the given start date is always included + // in the range. If we don't do this the nearest correct weekday in the week + // to start at might be later than the start date. + if( $ds < $this->iWeekStart ) + $d = strtotime('-7 day',$this->iStartDate); + else + $d = $this->iStartDate; + $adjdate = strtotime(($this->iWeekStart-$ds).' day',$d /*$this->iStartDate*/ ); + $this->iStartDate = $adjdate; + + // We want to end on the last day of the week + $preferredEndDay = ($this->iWeekStart+6)%7; + if( $preferredEndDay != $de ) { + // Solve equivalence eq: $de + x ~ $preferredDay (mod 7) + $adj = (7+($preferredEndDay - $de)) % 7; + $adjdate = strtotime("+$adj day",$this->iEndDate); + $this->iEndDate = $adjdate; + } + } + + // Specify background for the table title area (upper left corner of the table) + function SetTableTitleBackground($aColor) { + $this->iTableHeaderBackgroundColor = $aColor; + } + +/////////////////////////////////////// +// PRIVATE Methods + + // Determine the height of all the scale headers combined + function GetHeaderHeight() { + $img=$this->iImg; + $height=1; + if( $this->minute->iShowLabels ) { + $height += $this->minute->GetFontHeight($img); + $height += $this->minute->iTitleVertMargin; + } + if( $this->hour->iShowLabels ) { + $height += $this->hour->GetFontHeight($img); + $height += $this->hour->iTitleVertMargin; + } + if( $this->day->iShowLabels ) { + $height += $this->day->GetFontHeight($img); + $height += $this->day->iTitleVertMargin; + } + if( $this->week->iShowLabels ) { + $height += $this->week->GetFontHeight($img); + $height += $this->week->iTitleVertMargin; + } + if( $this->month->iShowLabels ) { + $height += $this->month->GetFontHeight($img); + $height += $this->month->iTitleVertMargin; + } + if( $this->year->iShowLabels ) { + $height += $this->year->GetFontHeight($img); + $height += $this->year->iTitleVertMargin; + } + return $height; + } + + // Get width (in pixels) for a single day + function GetDayWidth() { + return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays(); + } + + // Get width (in pixels) for a single hour + function GetHourWidth() { + return $this->GetDayWidth() / 24 ; + } + + function GetMinuteWidth() { + return $this->GetHourWidth() / 60 ; + } + + // Nuber of days in a year + function GetNumDaysInYear($aYear) { + if( $this->IsLeap($aYear) ) + return 366; + else + return 365; + } + + // Get week number + function GetWeekNbr($aDate,$aSunStart=true) { + // We can't use the internal strftime() since it gets the weeknumber + // wrong since it doesn't follow ISO on all systems since this is + // system linrary dependent. + // Even worse is that this works differently if we are on a Windows + // or UNIX box (it even differs between UNIX boxes how strftime() + // is natively implemented) + // + // Credit to Nicolas Hoizey for this elegant + // version of Week Nbr calculation. + + $day = $this->NormalizeDate($aDate); + if( $aSunStart ) + $day += 60*60*24; + + /*------------------------------------------------------------------------- + According to ISO-8601 : + "Week 01 of a year is per definition the first week that has the Thursday in this year, + which is equivalent to the week that contains the fourth day of January. + In other words, the first week of a new year is the week that has the majority of its + days in the new year." + + Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!! + + day of year = date("z", $day) + 1 + offset to thursday = 3 - (date("w", $day) + 6) % 7 + first thursday of year = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7 + week number = (thursday's day of year - first thursday's day of year) / 7 + 1 + ---------------------------------------------------------------------------*/ + + $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7); // take week's thursday + $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7; + + return $week; + } + + // Is year a leap year? + function IsLeap($aYear) { + // Is the year a leap year? + //$year = 0+date("Y",$aDate); + if( $aYear % 4 == 0) + if( !($aYear % 100 == 0) || ($aYear % 400 == 0) ) + return true; + return false; + } + + // Get current year + function GetYear($aDate) { + return 0+Date("Y",$aDate); + } + + // Return number of days in a year + function GetNumDaysInMonth($aMonth,$aYear) { + $days=array(31,28,31,30,31,30,31,31,30,31,30,31); + $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31); + if( $this->IsLeap($aYear)) + return $daysl[$aMonth]; + else + return $days[$aMonth]; + } + + // Get day in month + function GetMonthDayNbr($aDate) { + return 0+strftime("%d",$aDate); + } + + // Get day in year + function GetYearDayNbr($aDate) { + return 0+strftime("%j",$aDate); + } + + // Get month number + function GetMonthNbr($aDate) { + return 0+strftime("%m",$aDate); + } + + // Translate a date to screen coordinates (horizontal scale) + function TranslateDate($aDate) { + // + // In order to handle the problem with Daylight savings time + // the scale written with equal number of seconds per day beginning + // with the start date. This means that we "cement" the state of + // DST as it is in the start date. If later the scale includes the + // switchover date (depends on the locale) we need to adjust back + // if the date we try to translate has a different DST status since + // we would otherwise be off by one hour. + $aDate = $this->NormalizeDate($aDate); + $tmp = localtime($aDate); + $cloc = $tmp[8]; + $tmp = localtime($this->iStartDate); + $sloc = $tmp[8]; + $offset = 0; + if( $sloc != $cloc) { + if( $sloc ) + $offset = 3600; + else + $offset = -3600; + } + $img=$this->iImg; + return ($aDate-$this->iStartDate-$offset)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;; + } + + // Get screen coordinatesz for the vertical position for a bar + function TranslateVertPos($aPos) { + $img=$this->iImg; + $ph=$this->iAvailableHeight; + if( $aPos > $this->iVertLines ) + JpGraphError::RaiseL(6015,$aPos); +// 'Illegal vertical position %d' + if( $this->iVertLayout == GANTT_EVEN ) { + // Position the top bar at 1 vert spacing from the scale + return round($img->top_margin + $this->iVertHeaderSize + ($aPos+1)*$this->iVertSpacing); + } + else { + // position the top bar at 1/2 a vert spacing from the scale + return round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing); + } + } + + // What is the vertical spacing? + function GetVertSpacing() { + return $this->iVertSpacing; + } + + // Convert a date to timestamp + function NormalizeDate($aDate) { + if( $aDate === false ) return false; + if( is_string($aDate) ) { + $t = strtotime($aDate); + if( $t === FALSE || $t === -1 ) { + JpGraphError::RaiseL(6016,$aDate); +//("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30"); + } + return $t; + } + elseif( is_int($aDate) || is_float($aDate) ) + return $aDate; + else + JpGraphError::RaiseL(6017,$aDate); +//Unknown date format in GanttScale ($aDate)."); + } + + + // Convert a time string to minutes + + function TimeToMinutes($aTimeString) { + // Split in hours and minutes + $pos=strpos($aTimeString,':'); + $minint=60; + if( $pos === false ) { + $hourint = $aTimeString; + $minint = 0; + } + else { + $hourint = floor(substr($aTimeString,0,$pos)); + $minint = floor(substr($aTimeString,$pos+1)); + } + $minint += 60 * $hourint; + return $minint; + } + + // Stroke the day scale (including gridlines) + function StrokeMinutes($aYCoord,$getHeight=false) { + $img=$this->iImg; + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->minute->iShowLabels ) { + $img->SetFont($this->minute->iFFamily,$this->minute->iFStyle,$this->minute->iFSize); + $yb = $yt + $img->GetFontHeight() + + $this->minute->iTitleVertMargin + $this->minute->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb = $img->width-$img->right_margin+1; + $img->SetColor($this->minute->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $day = date('w',$this->iStartDate); + $minint = $this->minute->GetIntervall() ; + + if( 60 % $minint !== 0 ) { + JpGraphError::RaiseL(6018,$minint); +//'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.'); + } + + + $n = 60 / $minint; + $datestamp = $this->iStartDate; + $width = $this->GetHourWidth() / $n ; + if( $width < 8 ) { + // TO small width to draw minute scale + JpGraphError::RaiseL(6019,$width); +//('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.'); + } + + $nh = ceil(24*60 / $this->TimeToMinutes($this->hour->GetIntervall()) ); + $nd = $this->GetNumberOfDays(); + // Convert to intervall to seconds + $minint *= 60; + for($j=0; $j < $nd; ++$j, $day += 1, $day %= 7) { + for( $k=0; $k < $nh; ++$k ) { + for($i=0; $i < $n ;++$i, $x+=$width, $datestamp += $minint ) { + if( $day==6 || $day==0 ) { + + $img->PushColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground ) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); + $img->PopColor(); + + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + + switch( $this->minute->iStyle ) { + case MINUTESTYLE_CUSTOM: + $txt = date($this->minute->iLabelFormStr,$datestamp); + break; + case MINUTESTYLE_MM: + default: + // 15 + $txt = date('i',$datestamp); + break; + } + $img->StrokeText(round($x+$width/2),round($yb-$this->minute->iTitleVertMargin),$txt); + + // FIXME: The rounding problem needs to be solved properly ... + // + // Fix a rounding problem the wrong way .. + // If we also have hour scale then don't draw the firsta or last + // gridline since that will be overwritten by the hour scale gridline if such exists. + // However, due to the propagation of rounding of the 'x+=width' term in the loop + // this might sometimes be one pixel of so we fix this by not drawing it. + // The proper way to fix it would be to re-calculate the scale for each step and + // not using the additive term. + if( !(($i == $n || $i==0) && $this->hour->iShowLabels && $this->hour->grid->iShow) ) { + $img->SetColor($this->minute->grid->iColor); + $img->SetLineWeight($this->minute->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->minute->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + } + } + } + } + $img->SetColor($this->minute->iFrameColor); + $img->SetLineWeight($this->minute->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + // Stroke the day scale (including gridlines) + function StrokeHours($aYCoord,$getHeight=false) { + $img=$this->iImg; + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->hour->iShowLabels ) { + $img->SetFont($this->hour->iFFamily,$this->hour->iFStyle,$this->hour->iFSize); + $yb = $yt + $img->GetFontHeight() + + $this->hour->iTitleVertMargin + $this->hour->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb = $img->width-$img->right_margin+1; + $img->SetColor($this->hour->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $tmp = $this->hour->GetIntervall() ; + $minint = $this->TimeToMinutes($tmp); + if( 1440 % $minint !== 0 ) { + JpGraphError::RaiseL(6020,$tmp); +//('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp); + } + + $n = ceil(24*60 / $minint ); + $datestamp = $this->iStartDate; + $day = date('w',$this->iStartDate); + $doback = !$this->minute->iShowLabels; + $width = $this->GetDayWidth() / $n ; + for($j=0; $j < $this->GetNumberOfDays(); ++$j, $day += 1,$day %= 7) { + for($i=0; $i < $n ;++$i, $x+=$width) { + if( $day==6 || $day==0 ) { + + $img->PushColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground && $doback ) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight); + $img->PopColor(); + + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + + switch( $this->hour->iStyle ) { + case HOURSTYLE_HMAMPM: + // 1:35pm + $txt = date('g:ia',$datestamp); + break; + case HOURSTYLE_H24: + // 13 + $txt = date('H',$datestamp); + break; + case HOURSTYLE_HAMPM: + $txt = date('ga',$datestamp); + break; + case HOURSTYLE_CUSTOM: + $txt = date($this->hour->iLabelFormStr,$datestamp); + break; + case HOURSTYLE_HM24: + default: + $txt = date('H:i',$datestamp); + break; + } + $img->StrokeText(round($x+$width/2),round($yb-$this->hour->iTitleVertMargin),$txt); + $img->SetColor($this->hour->grid->iColor); + $img->SetLineWeight($this->hour->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->hour->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + //$datestamp += $minint*60 + $datestamp = mktime(date('H',$datestamp),date('i',$datestamp)+$minint,0, + date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); + + } + } + $img->SetColor($this->hour->iFrameColor); + $img->SetLineWeight($this->hour->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + + // Stroke the day scale (including gridlines) + function StrokeDays($aYCoord,$getHeight=false) { + $img=$this->iImg; + $daywidth=$this->GetDayWidth(); + $xt=$img->left_margin+$this->iLabelWidth; + $yt=$aYCoord+$img->top_margin; + if( $this->day->iShowLabels ) { + $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $xb=$img->width-$img->right_margin+1; + $img->SetColor($this->day->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $x = $xt; + $img->SetTextAlign("center"); + $day = date('w',$this->iStartDate); + $datestamp = $this->iStartDate; + + $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels); + + setlocale(LC_TIME,$this->iDateLocale->iLocale); + + for($i=0; $i < $this->GetNumberOfDays(); ++$i, $x+=$daywidth, $day += 1,$day %= 7) { + if( $day==6 || $day==0 ) { + $img->SetColor($this->day->iWeekendBackgroundColor); + if( $this->iUsePlotWeekendBackground && $doback) + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, + $x+$daywidth,$img->height-$img->bottom_margin); + else + $img->FilledRectangle($x,$yt+$this->day->iFrameWeight, + $x+$daywidth,$yb-$this->day->iFrameWeight); + } + + $mn = strftime('%m',$datestamp); + if( $mn[0]=='0' ) + $mn = $mn[1]; + + switch( $this->day->iStyle ) { + case DAYSTYLE_LONG: + // "Monday" + $txt = strftime('%A',$datestamp); + break; + case DAYSTYLE_SHORT: + // "Mon" + $txt = strftime('%a',$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE1: + // "Mon 23/6" + $txt = strftime('%a %d/'.$mn,$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE2: + // "Mon 23 Jun" + $txt = strftime('%a %d %b',$datestamp); + break; + case DAYSTYLE_SHORTDAYDATE3: + // "Mon 23 Jun 2003" + $txt = strftime('%a %d %b %Y',$datestamp); + break; + case DAYSTYLE_LONGDAYDATE1: + // "Monday 23 Jun" + $txt = strftime('%A %d %b',$datestamp); + break; + case DAYSTYLE_LONGDAYDATE2: + // "Monday 23 Jun 2003" + $txt = strftime('%A %d %b %Y',$datestamp); + break; + case DAYSTYLE_SHORTDATE1: + // "23/6" + $txt = strftime('%d/'.$mn,$datestamp); + break; + case DAYSTYLE_SHORTDATE2: + // "23 Jun" + $txt = strftime('%d %b',$datestamp); + break; + case DAYSTYLE_SHORTDATE3: + // "Mon 23" + $txt = strftime('%a %d',$datestamp); + break; + case DAYSTYLE_SHORTDATE4: + // "23" + $txt = strftime('%d',$datestamp); + break; + case DAYSTYLE_CUSTOM: + // Custom format + $txt = strftime($this->day->iLabelFormStr,$datestamp); + break; + case DAYSTYLE_ONELETTER: + default: + // "M" + $txt = strftime('%A',$datestamp); + $txt = strtoupper($txt[0]); + break; + } + + if( $day==0 ) + $img->SetColor($this->day->iSundayTextColor); + else + $img->SetColor($this->day->iTextColor); + $img->StrokeText(round($x+$daywidth/2+1), + round($yb-$this->day->iTitleVertMargin),$txt); + $img->SetColor($this->day->grid->iColor); + $img->SetLineWeight($this->day->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $datestamp = mktime(0,0,0,date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp)); + //$datestamp += SECPERDAY; + + } + $img->SetColor($this->day->iFrameColor); + $img->SetLineWeight($this->day->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb - $img->top_margin; + } + return $aYCoord; + } + + // Stroke week header and grid + function StrokeWeeks($aYCoord,$getHeight=false) { + if( $this->week->iShowLabels ) { + $img=$this->iImg; + $yt=$aYCoord+$img->top_margin; + $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight; + + if( $getHeight ) { + return $yb - $img->top_margin; + } + + $xt=$img->left_margin+$this->iLabelWidth; + $weekwidth=$this->GetDayWidth()*7; + $wdays=$this->iDateLocale->GetDayAbb(); + $xb=$img->width-$img->right_margin+1; + $week = $this->iStartDate; + $weeknbr=$this->GetWeekNbr($week); + $img->SetColor($this->week->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $img->SetColor($this->week->grid->iColor); + $x = $xt; + if( $this->week->iStyle==WEEKSTYLE_WNBR ) { + $img->SetTextAlign("center"); + $txtOffset = $weekwidth/2+1; + } + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || + $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $img->SetTextAlign("left"); + $txtOffset = 3; + } + else + JpGraphError::RaiseL(6021); +//("Unknown formatting style for week."); + + for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) { + $img->PushColor($this->week->iTextColor); + + if( $this->week->iStyle==WEEKSTYLE_WNBR ) + $txt = sprintf($this->week->iLabelFormStr,$weeknbr); + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || + $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) + $txt = date("j/n",$week); + elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $monthnbr = date("n",$week)-1; + $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr); + $txt = Date("j",$week)." ".$shortmonth; + } + + if( $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR || + $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) { + $w = sprintf($this->week->iLabelFormStr,$weeknbr); + $txt .= ' '.$w; + } + + $img->StrokeText(round($x+$txtOffset), + round($yb-$this->week->iTitleVertMargin),$txt); + + $week = strtotime('+7 day',$week); + $weeknbr = $this->GetWeekNbr($week); + $img->PopColor(); + $img->SetLineWeight($this->week->grid->iWeight); + $img->Line($x,$yt,$x,$yb); + $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + } + $img->SetColor($this->week->iFrameColor); + $img->SetLineWeight($this->week->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Format the mont scale header string + function GetMonthLabel($aMonthNbr,$year) { + $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr); + $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr); + switch($this->month->iStyle) { + case MONTHSTYLE_SHORTNAME: + $m=$sn; + break; + case MONTHSTYLE_LONGNAME: + $m=$ln; + break; + case MONTHSTYLE_SHORTNAMEYEAR2: + $m=$sn." '".substr("".$year,2); + break; + case MONTHSTYLE_SHORTNAMEYEAR4: + $m=$sn." ".$year; + break; + case MONTHSTYLE_LONGNAMEYEAR2: + $m=$ln." '".substr("".$year,2); + break; + case MONTHSTYLE_LONGNAMEYEAR4: + $m=$ln." ".$year; + break; + case MONTHSTYLE_FIRSTLETTER: + $m=$sn[0]; + break; + } + return $m; + } + + // Stroke month scale and gridlines + function StrokeMonths($aYCoord,$getHeight=false) { + if( $this->month->iShowLabels ) { + $img=$this->iImg; + $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize); + $yt=$aYCoord+$img->top_margin; + $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight; + if( $getHeight ) { + return $yb - $img->top_margin; + } + $monthnbr = $this->GetMonthNbr($this->iStartDate)-1; + $xt=$img->left_margin+$this->iLabelWidth; + $xb=$img->width-$img->right_margin+1; + + $img->SetColor($this->month->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + + $img->SetLineWeight($this->month->grid->iWeight); + $img->SetColor($this->month->iTextColor); + $year = 0+strftime("%Y",$this->iStartDate); + $img->SetTextAlign("center"); + if( $this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate) + && $this->GetYear($this->iStartDate)==$this->GetYear($this->iEndDate) ) { + $monthwidth=$this->GetDayWidth()*($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1); + } + else { + $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1); + } + // Is it enough space to stroke the first month? + $monthName = $this->GetMonthLabel($monthnbr,$year); + if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) { + $img->SetColor($this->month->iTextColor); + $img->StrokeText(round($xt+$monthwidth/2+1), + round($yb-$this->month->iTitleVertMargin), + $monthName); + } + $x = $xt + $monthwidth; + while( $x < $xb ) { + $img->SetColor($this->month->grid->iColor); + $img->Line($x,$yt,$x,$yb); + $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $monthnbr++; + if( $monthnbr==12 ) { + $monthnbr=0; + $year++; + } + $monthName = $this->GetMonthLabel($monthnbr,$year); + $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year); + if( $x + $monthwidth < $xb ) + $w = $monthwidth; + else + $w = $xb-$x; + if( $w >= 1.2*$img->GetTextWidth($monthName) ) { + $img->SetColor($this->month->iTextColor); + $img->StrokeText(round($x+$w/2+1), + round($yb-$this->month->iTitleVertMargin),$monthName); + } + $x += $monthwidth; + } + $img->SetColor($this->month->iFrameColor); + $img->SetLineWeight($this->month->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Stroke year scale and gridlines + function StrokeYears($aYCoord,$getHeight=false) { + if( $this->year->iShowLabels ) { + $img=$this->iImg; + $yt=$aYCoord+$img->top_margin; + $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize); + $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight; + + if( $getHeight ) { + return $yb - $img->top_margin; + } + + $xb=$img->width-$img->right_margin+1; + $xt=$img->left_margin+$this->iLabelWidth; + $year = $this->GetYear($this->iStartDate); + $img->SetColor($this->year->iBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $img->SetLineWeight($this->year->grid->iWeight); + $img->SetTextAlign("center"); + if( $year == $this->GetYear($this->iEndDate) ) + $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1); + else + $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1); + + // The space for a year must be at least 20% bigger than the actual text + // so we allow 10% margin on each side + if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) { + $img->SetColor($this->year->iTextColor); + $img->StrokeText(round($xt+$yearwidth/2+1), + round($yb-$this->year->iTitleVertMargin), + $year); + } + $x = $xt + $yearwidth; + while( $x < $xb ) { + $img->SetColor($this->year->grid->iColor); + $img->Line($x,$yt,$x,$yb); + $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); + $year += 1; + $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year); + if( $x + $yearwidth < $xb ) + $w = $yearwidth; + else + $w = $xb-$x; + if( $w >= 1.2*$img->GetTextWidth("".$year) ) { + $img->SetColor($this->year->iTextColor); + $img->StrokeText(round($x+$w/2+1), + round($yb-$this->year->iTitleVertMargin), + $year); + } + $x += $yearwidth; + } + $img->SetColor($this->year->iFrameColor); + $img->SetLineWeight($this->year->iFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + return $yb-$img->top_margin; + } + return $aYCoord; + } + + // Stroke table title (upper left corner) + function StrokeTableHeaders($aYBottom) { + $img=$this->iImg; + $xt=$img->left_margin; + $yt=$img->top_margin; + $xb=$xt+$this->iLabelWidth; + $yb=$aYBottom+$img->top_margin; + + if( $this->tableTitle->iShow ) { + $img->SetColor($this->iTableHeaderBackgroundColor); + $img->FilledRectangle($xt,$yt,$xb,$yb); + $this->tableTitle->Align("center","top"); + $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+2); + $img->SetColor($this->iTableHeaderFrameColor); + $img->SetLineWeight($this->iTableHeaderFrameWeight); + $img->Rectangle($xt,$yt,$xb,$yb); + } + + $this->actinfo->Stroke($img,$xt,$yt,$xb,$yb,$this->tableTitle->iShow); + + + // Draw the horizontal dividing line + $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb); + + // Draw the vertical dividing line + // We do the width "manually" since we want the line only to grow + // to the left + $fancy = $this->divider->iStyle == 'fancy' ; + if( $fancy ) { + $this->divider->iStyle = 'solid'; + } + + $tmp = $this->divider->iWeight; + $this->divider->iWeight=1; + $y = $img->height-$img->bottom_margin; + for($i=0; $i < $tmp; ++$i ) { + $this->divider->Stroke($img,$xb-$i,$yt,$xb-$i,$y); + } + + // Should we draw "fancy" divider + if( $fancy ) { + $img->SetLineWeight(1); + $img->SetColor($this->iTableHeaderFrameColor); + $img->Line($xb,$yt,$xb,$y); + $img->Line($xb-$tmp+1,$yt,$xb-$tmp+1,$y); + $img->SetColor('white'); + $img->Line($xb-$tmp+2,$yt,$xb-$tmp+2,$y); + } + } + + // Main entry point to stroke scale + function Stroke() { + if( !$this->IsRangeSet() ) + JpGraphError::RaiseL(6022); +//("Gantt scale has not been specified."); + $img=$this->iImg; + + // If minutes are displayed then hour interval must be 1 + if( $this->IsDisplayMinute() && $this->hour->GetIntervall() > 1 ) { + JpGraphError::RaiseL(6023); +//('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).'); + } + + // Stroke all headers. As argument we supply the offset from the + // top which depends on any previous headers + + // First find out the height of each header + $offy=$this->StrokeYears(0,true); + $offm=$this->StrokeMonths($offy,true); + $offw=$this->StrokeWeeks($offm,true); + $offd=$this->StrokeDays($offw,true); + $offh=$this->StrokeHours($offd,true); + $offmin=$this->StrokeMinutes($offh,true); + + + // ... then we can stroke them in the "backwards order to ensure that + // the larger scale gridlines is stroked over the smaller scale gridline + $this->StrokeMinutes($offh); + $this->StrokeHours($offd); + $this->StrokeDays($offw); + $this->StrokeWeeks($offm); + $this->StrokeMonths($offy); + $this->StrokeYears(0); + + // Now when we now the oaverall size of the scale headers + // we can stroke the overall table headers + $this->StrokeTableHeaders($offmin); + + // Now we can calculate the correct scaling factor for each vertical position + $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd; + $this->iVertHeaderSize = $offmin; + if( $this->iVertSpacing == -1 ) + $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines; + } +} + + +//=================================================== +// CLASS GanttConstraint +// Just a structure to store all the values for a constraint +//=================================================== +class GanttConstraint { + public $iConstrainRow; + public $iConstrainType; + public $iConstrainColor; + public $iConstrainArrowSize; + public $iConstrainArrowType; + +//--------------- +// CONSTRUCTOR + function GanttConstraint($aRow,$aType,$aColor,$aArrowSize,$aArrowType){ + $this->iConstrainType = $aType; + $this->iConstrainRow = $aRow; + $this->iConstrainColor=$aColor; + $this->iConstrainArrowSize=$aArrowSize; + $this->iConstrainArrowType=$aArrowType; + } +} + + +//=================================================== +// CLASS GanttPlotObject +// The common signature for a Gantt object +//=================================================== +class GanttPlotObject { + public $title,$caption; + public $csimarea='',$csimtarget='',$csimwintarget='',$csimalt=''; + public $constraints = array(); + public $iCaptionMargin=5; + public $iConstrainPos=array(); + protected $iStart=""; // Start date + public $iVPos=0; // Vertical position + protected $iLabelLeftMargin=2; // Title margin + + function GanttPlotObject() { + $this->title = new TextProperty(); + $this->title->Align("left","center"); + $this->caption = new TextProperty(); + } + + function GetCSIMArea() { + return $this->csimarea; + } + + function SetCSIMTarget($aTarget,$aAlt='',$aWinTarget='') { + if( !is_string($aTarget) ) { + $tv = substr(var_export($aTarget,true),0,40); + JpGraphError::RaiseL(6024,$tv); +//('CSIM Target must be specified as a string.'."\nStart of target is:\n$tv"); + } + if( !is_string($aAlt) ) { + $tv = substr(var_export($aAlt,true),0,40); + JpGraphError::RaiseL(6025,$tv); +//('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); + } + + $this->csimtarget=$aTarget; + $this->csimwintarget=$aWinTarget; + $this->csimalt=$aAlt; + } + + function SetCSIMAlt($aAlt) { + if( !is_string($aAlt) ) { + $tv = substr(var_export($aAlt,true),0,40); + JpGraphError::RaiseL(6025,$tv); +//('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv"); + } + $this->csimalt=$aAlt; + } + + function SetConstrain($aRow,$aType,$aColor='black',$aArrowSize=ARROW_S2,$aArrowType=ARROWT_SOLID) { + $this->constraints[] = new GanttConstraint($aRow, $aType, $aColor, $aArrowSize, $aArrowType); + } + + function SetConstrainPos($xt,$yt,$xb,$yb) { + $this->iConstrainPos = array($xt,$yt,$xb,$yb); + } + + /* + function GetConstrain() { + return array($this->iConstrainRow,$this->iConstrainType); + } + */ + + function GetMinDate() { + return $this->iStart; + } + + function GetMaxDate() { + return $this->iStart; + } + + function SetCaptionMargin($aMarg) { + $this->iCaptionMargin=$aMarg; + } + + function GetAbsHeight($aImg) { + return 0; + } + + function GetLineNbr() { + return $this->iVPos; + } + + function SetLabelLeftMargin($aOff) { + $this->iLabelLeftMargin=$aOff; + } + + function StrokeActInfo($aImg,$aScale,$aYPos) { + $cols=array(); + $aScale->actinfo->GetColStart($aImg,$cols,true); + $this->title->Stroke($aImg,$cols,$aYPos); + } +} + +//=================================================== +// CLASS Progress +// Holds parameters for the progress indicator +// displyed within a bar +//=================================================== +class Progress { + public $iProgress=-1; + public $iPattern=GANTT_SOLID; + public $iColor="black", $iFillColor='black'; + public $iDensity=98, $iHeight=0.65; + + function Set($aProg) { + if( $aProg < 0.0 || $aProg > 1.0 ) + JpGraphError::RaiseL(6027); +//("Progress value must in range [0, 1]"); + $this->iProgress = $aProg; + } + + function SetPattern($aPattern,$aColor="blue",$aDensity=98) { + $this->iPattern = $aPattern; + $this->iColor = $aColor; + $this->iDensity = $aDensity; + } + + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + function SetHeight($aHeight) { + $this->iHeight = $aHeight; + } +} + +DEFINE('GANTT_HGRID1',0); +DEFINE('GANTT_HGRID2',1); + +//=================================================== +// CLASS HorizontalGridLine +// Responsible for drawinf horizontal gridlines and filled alternatibg rows +//=================================================== +class HorizontalGridLine { + private $iGraph=NULL; + private $iRowColor1 = '', $iRowColor2 = ''; + private $iShow=false; + private $line=null; + private $iStart=0; // 0=from left margin, 1=just along header + + function HorizontalGridLine() { + $this->line = new LineProperty(); + $this->line->SetColor('gray@0.4'); + $this->line->SetStyle('dashed'); + } + + function Show($aShow=true) { + $this->iShow = $aShow; + } + + function SetRowFillColor($aColor1,$aColor2='') { + $this->iRowColor1 = $aColor1; + $this->iRowColor2 = $aColor2; + } + + function SetStart($aStart) { + $this->iStart = $aStart; + } + + function Stroke($aImg,$aScale) { + + if( ! $this->iShow ) return; + + // Get horizontal width of line + /* + $limst = $aScale->iStartDate; + $limen = $aScale->iEndDate; + $xt = round($aScale->TranslateDate($aScale->iStartDate)); + $xb = round($aScale->TranslateDate($limen)); + */ + + if( $this->iStart === 0 ) { + $xt = $aImg->left_margin-1; + } + else { + $xt = round($aScale->TranslateDate($aScale->iStartDate))+1; + } + + $xb = $aImg->width-$aImg->right_margin; + + $yt = round($aScale->TranslateVertPos(0)); + $yb = round($aScale->TranslateVertPos(1)); + $height = $yb - $yt; + + // Loop around for all lines in the chart + for($i=0; $i < $aScale->iVertLines; ++$i ) { + $yb = $yt - $height; + $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); + if( $this->iRowColor1 !== '' ) { + if( $i % 2 == 0 ) { + $aImg->PushColor($this->iRowColor1); + $aImg->FilledRectangle($xt,$yt,$xb,$yb); + $aImg->PopColor(); + } + elseif( $this->iRowColor2 !== '' ) { + $aImg->PushColor($this->iRowColor2); + $aImg->FilledRectangle($xt,$yt,$xb,$yb); + $aImg->PopColor(); + } + } + $yt = round($aScale->TranslateVertPos($i+1)); + } + $yb = $yt - $height; + $this->line->Stroke($aImg,$xt,$yb,$xb,$yb); + } +} + + +//=================================================== +// CLASS GanttBar +// Responsible for formatting individual gantt bars +//=================================================== +class GanttBar extends GanttPlotObject { + public $progress; + public $leftMark,$rightMark; + private $iEnd; + private $iHeightFactor=0.5; + private $iFillColor="white",$iFrameColor="black"; + private $iShadow=false,$iShadowColor="darkgray",$iShadowWidth=1,$iShadowFrame="black"; + private $iPattern=GANTT_RDIAG,$iPatternColor="blue",$iPatternDensity=95; +//--------------- +// CONSTRUCTOR + function GanttBar($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) { + parent::GanttPlotObject(); + $this->iStart = $aStart; + // Is the end date given as a date or as number of days added to start date? + if( is_string($aEnd) ) { + // If end date has been specified without a time we will asssume + // end date is at the end of that date + if( strpos($aEnd,':') === false ) + $this->iEnd = strtotime($aEnd)+SECPERDAY-1; + else + $this->iEnd = $aEnd; + } + elseif(is_int($aEnd) || is_float($aEnd) ) + $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY); + $this->iVPos = $aPos; + $this->iHeightFactor = $aHeightFactor; + $this->title->Set($aLabel); + $this->caption = new TextProperty($aCaption); + $this->caption->Align("left","center"); + $this->leftMark =new PlotMark(); + $this->leftMark->Hide(); + $this->rightMark=new PlotMark(); + $this->rightMark->Hide(); + $this->progress = new Progress(); + } + +//--------------- +// PUBLIC METHODS + function SetShadow($aShadow=true,$aColor="gray") { + $this->iShadow=$aShadow; + $this->iShadowColor=$aColor; + } + + function GetMaxDate() { + return $this->iEnd; + } + + function SetHeight($aHeight) { + $this->iHeightFactor = $aHeight; + } + + function SetColor($aColor) { + $this->iFrameColor = $aColor; + } + + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + function GetAbsHeight($aImg) { + if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) { + $m=-1; + if( is_int($this->iHeightFactor) ) + $m = $this->iHeightFactor; + if( $this->leftMark->show ) + $m = max($m,$this->leftMark->width*2); + if( $this->rightMark->show ) + $m = max($m,$this->rightMark->width*2); + return $m; + } + else + return -1; + } + + function SetPattern($aPattern,$aColor="blue",$aDensity=95) { + $this->iPattern = $aPattern; + $this->iPatternColor = $aColor; + $this->iPatternDensity = $aDensity; + } + + function Stroke($aImg,$aScale) { + $factory = new RectPatternFactory(); + $prect = $factory->Create($this->iPattern,$this->iPatternColor); + $prect->SetDensity($this->iPatternDensity); + + // If height factor is specified as a float between 0,1 then we take it as meaning + // percetage of the scale width between horizontal line. + // If it is an integer > 1 we take it to mean the absolute height in pixels + if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1) + $vs = $aScale->GetVertSpacing()*$this->iHeightFactor; + elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor < 200 ) + $vs = $this->iHeightFactor; + else + JpGraphError::RaiseL(6028,$this->iHeightFactor); +//("Specified height (".$this->iHeightFactor.") for gantt bar is out of range."); + + // Clip date to min max dates to show + $st = $aScale->NormalizeDate($this->iStart); + $en = $aScale->NormalizeDate($this->iEnd); + + + $limst = max($st,$aScale->iStartDate); + $limen = min($en,$aScale->iEndDate); + + $xt = round($aScale->TranslateDate($limst)); + $xb = round($aScale->TranslateDate($limen)); + $yt = round($aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2)); + $yb = round($aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2)); + $middle = round($yt+($yb-$yt)/2); + $this->StrokeActInfo($aImg,$aScale,$middle); + + // CSIM for title + if( ! empty($this->title->csimtarget) ) { + $colwidth = $this->title->GetColWidth($aImg); + $colstarts=array(); + $aScale->actinfo->GetColStart($aImg,$colstarts,true); + $n = min(count($colwidth),count($this->title->csimtarget)); + for( $i=0; $i < $n; ++$i ) { + $title_xt = $colstarts[$i]; + $title_xb = $title_xt + $colwidth[$i]; + $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; + + if( ! empty($this->title->csimtarget[$i]) ) { + $this->csimarea .= "title->csimtarget[$i]."\""; + + if( ! empty($this->title->csimwintarget[$i]) ) { + $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\" "; + } + + if( ! empty($this->title->csimalt[$i]) ) { + $tmp = $this->title->csimalt[$i]; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + } + } + + // Check if the bar is totally outside the current scale range + if( $en < $aScale->iStartDate || $st > $aScale->iEndDate ) + return; + + + // Remember the positions for the bar + $this->SetConstrainPos($xt,$yt,$xb,$yb); + + $prect->ShowFrame(false); + $prect->SetBackground($this->iFillColor); + if( $this->iShadow ) { + $aImg->SetColor($this->iFrameColor); + $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor); + $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2)); + $prect->Stroke($aImg); + } + else { + $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1)); + $prect->Stroke($aImg); + $aImg->SetColor($this->iFrameColor); + $aImg->Rectangle($xt,$yt,$xb,$yb); + } + + // CSIM for bar + if( ! empty($this->csimtarget) ) { + + $coords = "$xt,$yt,$xb,$yt,$xb,$yb,$xt,$yb"; + $this->csimarea .= "csimtarget."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimarea .= " target=\"".$this->csimwintarget."\" "; + } + + if( $this->csimalt != '' ) { + $tmp = $this->csimalt; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + + // Draw progress bar inside activity bar + if( $this->progress->iProgress > 0 ) { + + $xtp = $aScale->TranslateDate($st); + $xbp = $aScale->TranslateDate($en); + $len = ($xbp-$xtp)*$this->progress->iProgress; + + $endpos = $xtp+$len; + if( $endpos > $xt ) { + + // Take away the length of the progress that is not visible (before the start date) + $len -= ($xt-$xtp); + + // Is the the progress bar visible after the start date? + if( $xtp < $xt ) + $xtp = $xt; + + // Make sure that the progess bar doesn't extend over the end date + if( $xtp+$len-1 > $xb ) + $len = $xb - $xtp ; + + $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor); + $prog->SetDensity($this->progress->iDensity); + $prog->SetBackground($this->progress->iFillColor); + $barheight = ($yb-$yt+1); + if( $this->iShadow ) + $barheight -= $this->iShadowWidth; + $progressheight = floor($barheight*$this->progress->iHeight); + $marg = ceil(($barheight-$progressheight)/2); + $pos = new Rectangle($xtp,$yt + $marg, $len,$barheight-2*$marg); + $prog->SetPos($pos); + $prog->Stroke($aImg); + } + } + + // We don't plot the end mark if the bar has been capped + if( $limst == $st ) { + $y = $middle; + // We treat the RIGHT and LEFT triangle mark a little bi + // special so that these marks are placed right under the + // bar. + if( $this->leftMark->GetType() == MARK_LEFTTRIANGLE ) { + $y = $yb ; + } + $this->leftMark->Stroke($aImg,$xt,$y); + } + if( $limen == $en ) { + $y = $middle; + // We treat the RIGHT and LEFT triangle mark a little bi + // special so that these marks are placed right under the + // bar. + if( $this->rightMark->GetType() == MARK_RIGHTTRIANGLE ) { + $y = $yb ; + } + $this->rightMark->Stroke($aImg,$xb,$y); + + $margin = $this->iCaptionMargin; + if( $this->rightMark->show ) + $margin += $this->rightMark->GetWidth(); + $this->caption->Stroke($aImg,$xb+$margin,$middle); + } + } +} + +//=================================================== +// CLASS MileStone +// Responsible for formatting individual milestones +//=================================================== +class MileStone extends GanttPlotObject { + public $mark; + +//--------------- +// CONSTRUCTOR + function MileStone($aVPos,$aLabel,$aDate,$aCaption="") { + GanttPlotObject::GanttPlotObject(); + $this->caption->Set($aCaption); + $this->caption->Align("left","center"); + $this->caption->SetFont(FF_FONT1,FS_BOLD); + $this->title->Set($aLabel); + $this->title->SetColor("darkred"); + $this->mark = new PlotMark(); + $this->mark->SetWidth(10); + $this->mark->SetType(MARK_DIAMOND); + $this->mark->SetColor("darkred"); + $this->mark->SetFillColor("darkred"); + $this->iVPos = $aVPos; + $this->iStart = $aDate; + } + +//--------------- +// PUBLIC METHODS + + function GetAbsHeight($aImg) { + return max($this->title->GetHeight($aImg),$this->mark->GetWidth()); + } + + function Stroke($aImg,$aScale) { + // Put the mark in the middle at the middle of the day + $d = $aScale->NormalizeDate($this->iStart)+SECPERDAY/2; + $x = $aScale->TranslateDate($d); + $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2); + + $this->StrokeActInfo($aImg,$aScale,$y); + + // CSIM for title + if( ! empty($this->title->csimtarget) ) { + + $yt = round($y - $this->title->GetHeight($aImg)/2); + $yb = round($y + $this->title->GetHeight($aImg)/2); + + $colwidth = $this->title->GetColWidth($aImg); + $colstarts=array(); + $aScale->actinfo->GetColStart($aImg,$colstarts,true); + $n = min(count($colwidth),count($this->title->csimtarget)); + for( $i=0; $i < $n; ++$i ) { + $title_xt = $colstarts[$i]; + $title_xb = $title_xt + $colwidth[$i]; + $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb"; + + if( !empty($this->title->csimtarget[$i]) ) { + + $this->csimarea .= "title->csimtarget[$i]."\""; + + if( !empty($this->title->csimwintarget[$i]) ) { + $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\""; + } + + if( ! empty($this->title->csimalt[$i]) ) { + $tmp = $this->title->csimalt[$i]; + $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimarea .= " />\n"; + } + } + } + + if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) + return; + + // Remember the coordinates for any constrains linking to + // this milestone + $w = $this->mark->GetWidth()/2; + $this->SetConstrainPos($x,round($y-$w),$x,round($y+$w)); + + // Setup CSIM + if( $this->csimtarget != '' ) { + $this->mark->SetCSIMTarget( $this->csimtarget ); + $this->mark->SetCSIMAlt( $this->csimalt ); + } + + $this->mark->Stroke($aImg,$x,$y); + $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y); + + $this->csimarea .= $this->mark->GetCSIMAreas(); + } +} + + +//=================================================== +// CLASS GanttVLine +// Responsible for formatting individual milestones +//=================================================== + +class TextPropertyBelow extends TextProperty { + function TextPropertyBelow($aTxt='') { + parent::TextProperty($aTxt); + } + + function GetColWidth($aImg,$aMargin=0) { + // Since we are not stroking the title in the columns + // but rather under the graph we want this to return 0. + return array(0); + } +} + +class GanttVLine extends GanttPlotObject { + + private $iLine,$title_margin=3, $iDayOffset=1; + +//--------------- +// CONSTRUCTOR + function GanttVLine($aDate,$aTitle="",$aColor="black",$aWeight=3,$aStyle="dashed") { + GanttPlotObject::GanttPlotObject(); + $this->iLine = new LineProperty(); + $this->iLine->SetColor($aColor); + $this->iLine->SetWeight($aWeight); + $this->iLine->SetStyle($aStyle); + $this->iStart = $aDate; + $this->title = new TextPropertyBelow(); + $this->title->Set($aTitle); + } + +//--------------- +// PUBLIC METHODS + + function SetDayOffset($aOff=0.5) { + if( $aOff < 0.0 || $aOff > 1.0 ) + JpGraphError::RaiseL(6029); +//("Offset for vertical line must be in range [0,1]"); + $this->iDayOffset = $aOff; + } + + function SetTitleMargin($aMarg) { + $this->title_margin = $aMarg; + } + + function Stroke($aImg,$aScale) { + $d = $aScale->NormalizeDate($this->iStart); + if( $d < $aScale->iStartDate || $d > $aScale->iEndDate ) + return; + if($this->iDayOffset != 0.0) + $d += 24*60*60*$this->iDayOffset; + $x = $aScale->TranslateDate($d); + $y1 = $aScale->iVertHeaderSize+$aImg->top_margin; + $y2 = $aImg->height - $aImg->bottom_margin; + $this->iLine->Stroke($aImg,$x,$y1,$x,$y2); + $this->title->Align("center","top"); + $this->title->Stroke($aImg,$x,$y2+$this->title_margin); + } +} + +//=================================================== +// CLASS LinkArrow +// Handles the drawing of a an arrow +//=================================================== +class LinkArrow { + private $ix,$iy; + private $isizespec = array( + array(2,3),array(3,5),array(3,8),array(6,15),array(8,22)); + private $iDirection=ARROW_DOWN,$iType=ARROWT_SOLID,$iSize=ARROW_S2; + private $iColor='black'; + + function LinkArrow($x,$y,$aDirection,$aType=ARROWT_SOLID,$aSize=ARROW_S2) { + $this->iDirection = $aDirection; + $this->iType = $aType; + $this->iSize = $aSize; + $this->ix = $x; + $this->iy = $y; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetSize($aSize) { + $this->iSize = $aSize; + } + + function SetType($aType) { + $this->iType = $aType; + } + + function Stroke($aImg) { + list($dx,$dy) = $this->isizespec[$this->iSize]; + $x = $this->ix; + $y = $this->iy; + switch ( $this->iDirection ) { + case ARROW_DOWN: + $c = array($x,$y,$x-$dx,$y-$dy,$x+$dx,$y-$dy,$x,$y); + break; + case ARROW_UP: + $c = array($x,$y,$x-$dx,$y+$dy,$x+$dx,$y+$dy,$x,$y); + break; + case ARROW_LEFT: + $c = array($x,$y,$x+$dy,$y-$dx,$x+$dy,$y+$dx,$x,$y); + break; + case ARROW_RIGHT: + $c = array($x,$y,$x-$dy,$y-$dx,$x-$dy,$y+$dx,$x,$y); + break; + default: + JpGraphError::RaiseL(6030); +//('Unknown arrow direction for link.'); + die(); + break; + } + $aImg->SetColor($this->iColor); + switch( $this->iType ) { + case ARROWT_SOLID: + $aImg->FilledPolygon($c); + break; + case ARROWT_OPEN: + $aImg->Polygon($c); + break; + default: + JpGraphError::RaiseL(6031); +//('Unknown arrow type for link.'); + die(); + break; + } + } +} + +//=================================================== +// CLASS GanttLink +// Handles the drawing of a link line between 2 points +//=================================================== + +class GanttLink { + private $ix1,$ix2,$iy1,$iy2; + private $iPathType=2,$iPathExtend=15; + private $iColor='black',$iWeight=1; + private $iArrowSize=ARROW_S2,$iArrowType=ARROWT_SOLID; + + function GanttLink($x1=0,$y1=0,$x2=0,$y2=0) { + $this->ix1 = $x1; + $this->ix2 = $x2; + $this->iy1 = $y1; + $this->iy2 = $y2; + } + + function SetPos($x1,$y1,$x2,$y2) { + $this->ix1 = $x1; + $this->ix2 = $x2; + $this->iy1 = $y1; + $this->iy2 = $y2; + } + + function SetPath($aPath) { + $this->iPathType = $aPath; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function SetArrow($aSize,$aType=ARROWT_SOLID) { + $this->iArrowSize = $aSize; + $this->iArrowType = $aType; + } + + function SetWeight($aWeight) { + $this->iWeight = $aWeight; + } + + function Stroke($aImg) { + // The way the path for the arrow is constructed is partly based + // on some heuristics. This is not an exact science but draws the + // path in a way that, for me, makes esthetic sence. For example + // if the start and end activities are very close we make a small + // detour to endter the target horixontally. If there are more + // space between axctivities then no suh detour is made and the + // target is "hit" directly vertical. I have tried to keep this + // simple. no doubt this could become almost infinitive complex + // and have some real AI. Feel free to modify this. + // This will no-doubt be tweaked as times go by. One design aim + // is to avoid having the user choose what types of arrow + // he wants. + + // The arrow is drawn between (x1,y1) to (x2,y2) + $x1 = $this->ix1 ; + $x2 = $this->ix2 ; + $y1 = $this->iy1 ; + $y2 = $this->iy2 ; + + // Depending on if the target is below or above we have to + // handle thi different. + if( $y2 > $y1 ) { + $arrowtype = ARROW_DOWN; + $midy = round(($y2-$y1)/2+$y1); + if( $x2 > $x1 ) { + switch ( $this->iPathType ) { + case 0: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 1: + case 2: + case 3: + $c = array($x1,$y1,$x2,$y1,$x2,$y2); + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); +//('Internal error: Unknown path type (='.$this->iPathType .') specified for link.'); + exit(1); + break; + } + } + else { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 2: + // Always extend out horizontally a bit from the first point + // If we draw a link back in time (end to start) and the bars + // are very close we also change the path so it comes in from + // the left on the activity + $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, + $x1+$this->iPathExtend,$midy, + $x2,$midy,$x2,$y2); + break; + case 3: + if( $y2-$midy < 6 ) { + $c = array($x1,$y1,$x1,$midy, + $x2-$this->iPathExtend,$midy, + $x2-$this->iPathExtend,$y2, + $x2,$y2); + $arrowtype = ARROW_RIGHT; + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); +//('Internal error: Unknown path type specified for link.'); + exit(1); + break; + } + } + $arrow = new LinkArrow($x2,$y2,$arrowtype); + } + else { + // Y2 < Y1 + $arrowtype = ARROW_UP; + $midy = round(($y1-$y2)/2+$y2); + if( $x2 > $x1 ) { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 3: + if( $midy-$y2 < 8 ) { + $arrowtype = ARROW_RIGHT; + $c = array($x1,$y1,$x1,$y2,$x2,$y2); + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); +//('Internal error: Unknown path type specified for link.'); + break; + } + } + else { + switch ( $this->iPathType ) { + case 0: + case 1: + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + break; + case 2: + // Always extend out horizontally a bit from the first point + $c = array($x1,$y1,$x1+$this->iPathExtend,$y1, + $x1+$this->iPathExtend,$midy, + $x2,$midy,$x2,$y2); + break; + case 3: + if( $midy-$y2 < 16 ) { + $arrowtype = ARROW_RIGHT; + $c = array($x1,$y1,$x1,$midy,$x2-$this->iPathExtend,$midy, + $x2-$this->iPathExtend,$y2, + $x2,$y2); + } + else { + $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2); + } + break; + default: + JpGraphError::RaiseL(6032,$this->iPathType); +//('Internal error: Unknown path type specified for link.'); + break; + } + } + $arrow = new LinkArrow($x2,$y2,$arrowtype); + } + $aImg->SetColor($this->iColor); + $aImg->SetLineWeight($this->iWeight); + $aImg->Polygon($c); + $aImg->SetLineWeight(1); + $arrow->SetColor($this->iColor); + $arrow->SetSize($this->iArrowSize); + $arrow->SetType($this->iArrowType); + $arrow->Stroke($aImg); + } +} + +// +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gradient.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gradient.php new file mode 100644 index 0000000..bbe2241 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_gradient.php @@ -0,0 +1,423 @@ +img = $img; + } + + + function SetNumColors($aNum) { + $this->numcolors=$aNum; + } +//--------------- +// PUBLIC METHODS + // Produce a gradient filled rectangle with a smooth transition between + // two colors. + // ($xl,$yt) Top left corner + // ($xr,$yb) Bottom right + // $from_color Starting color in gradient + // $to_color End color in the gradient + // $style Which way is the gradient oriented? + function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) { + switch( $style ) { + case GRAD_VER: + $steps = ceil(abs($xr-$xl)); + $delta = $xr>=$xl ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + for( $i=0, $x=$xl; $i < $steps; ++$i ) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yt,$x,$yb); + $x += $delta; + } + break; + + case GRAD_HOR: + $steps = ceil(abs($yb-$yt)); + $delta = $yb>=$yt ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + for($i=0,$y=$yt; $i < $steps; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + break; + + case GRAD_MIDHOR: + $steps = ceil(abs($yb-$yt)/2); + $delta = $yb >= $yt ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + for($y=$yt, $i=0; $i < $steps; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + --$i; + if( abs($yb-$yt) % 2 == 1 ) --$steps; + for($j=0; $j < $steps; ++$j, --$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + $this->img->Line($xl,$y,$xr,$y); + break; + + case GRAD_MIDVER: + $steps = ceil(abs($xr-$xl)/2); + $delta = $xr>=$xl ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + for($x=$xl, $i=0; $i < $steps; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + --$i; + if( abs($xr-$xl) % 2 == 1 ) --$steps; + for($j=0; $j < $steps; ++$j, --$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + $this->img->Line($x,$yb,$x,$yt); + break; + + case GRAD_WIDE_MIDVER: + $diff = ceil(abs($xr-$xl)); + $steps = floor(abs($diff)/3); + $firststep = $diff - 2*$steps ; + $delta = $xr >= $xl ? 1 : -1; + $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors); + for($x=$xl, $i=0; $i < $firststep; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + --$i; + $this->img->current_color = $colors[$i]; + for($j=0; $j< $steps; ++$j) { + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + + for($j=0; $j < $steps; ++$j, --$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + break; + + case GRAD_WIDE_MIDHOR: + $diff = ceil(abs($yb-$yt)); + $steps = floor(abs($diff)/3); + $firststep = $diff - 2*$steps ; + $delta = $yb >= $yt? 1 : -1; + $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors); + for($y=$yt, $i=0; $i < $firststep; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + --$i; + $this->img->current_color = $colors[$i]; + for($j=0; $j < $steps; ++$j) { + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + for($j=0; $j < $steps; ++$j, --$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($xl,$y,$xr,$y); + $y += $delta; + } + break; + + case GRAD_LEFT_REFLECTION: + $steps1 = ceil(0.3*abs($xr-$xl)); + $delta = $xr>=$xl ? 1 : -1; + + $from_color = $this->img->rgb->Color($from_color); + $adj = 1.4; + $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2])))); + $from_color2 = array(min(255,$from_color[0]+$m), + min(255,$from_color[1]+$m), min(255,$from_color[2]+$m)); + + $this->GetColArray($from_color2,$to_color,$steps1,$colors,$this->numcolors); + $n = count($colors); + for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + $steps2 = max(1,ceil(0.08*abs($xr-$xl))); + $this->img->SetColor($to_color); + for($j=0; $j< $steps2; ++$j) { + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + $steps = abs($xr-$xl)-$steps1-$steps2; + $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors); + $n = count($colors); + for($i=0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + break; + + case GRAD_RIGHT_REFLECTION: + $steps1 = ceil(0.7*abs($xr-$xl)); + $delta = $xr>=$xl ? 1 : -1; + + $this->GetColArray($from_color,$to_color,$steps1,$colors,$this->numcolors); + $n = count($colors); + for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + $steps2 = max(1,ceil(0.08*abs($xr-$xl))); + $this->img->SetColor($to_color); + for($j=0; $j< $steps2; ++$j) { + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + + $from_color = $this->img->rgb->Color($from_color); + $adj = 1.4; + $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2])))); + $from_color = array(min(255,$from_color[0]+$m), + min(255,$from_color[1]+$m), min(255,$from_color[2]+$m)); + + $steps = abs($xr-$xl)-$steps1-$steps2; + $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors); + $n = count($colors); + for($i=0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + break; + + case GRAD_CENTER: + $steps = ceil(min(($yb-$yt)+1,($xr-$xl)+1)/2); + $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors); + $dx = ($xr-$xl)/2; + $dy = ($yb-$yt)/2; + $x=$xl;$y=$yt;$x2=$xr;$y2=$yb; + $n = count($colors); + for($x=$xl, $i=0; $x < $xl+$dx && $y < $yt+$dy && $i < $n; ++$x, ++$y, --$x2, --$y2, ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Rectangle($x,$y,$x2,$y2); + } + $this->img->Line($x,$y,$x2,$y2); + break; + + case GRAD_RAISED_PANEL: + // right to left + $steps1 = $xr-$xl; + $delta = $xr>=$xl ? 1 : -1; + $this->GetColArray($to_color,$from_color,$steps1,$colors,$this->numcolors); + $n = count($colors); + for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + + // left to right + $xr -= 3; + $xl += 3; + $yb -= 3; + $yt += 3; + $steps2 = $xr-$xl; + $delta = $xr>=$xl ? 1 : -1; + for($x=$xl, $j=$steps2; $j >= 0; --$j) { + $this->img->current_color = $colors[$j]; + $this->img->Line($x,$yb,$x,$yt); + $x += $delta; + } + break; + + case GRAD_DIAGONAL: + // use the longer dimension to determine the required number of steps. + // first loop draws from one corner to the mid-diagonal and the second + // loop draws from the mid-diagonal to the opposing corner. + if($xr-$xl > $yb - $yt) { + // width is greater than height -> use x-dimension for steps + $steps = $xr-$xl; + $delta = $xr>=$xl ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps*2,$colors,$this->numcolors); + $n = count($colors); + + for($x=$xl, $i=0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $y = $yt+($i/$steps)*($yb-$yt)*$delta; + $this->img->Line($x,$yt,$xl,$y); + $x += $delta; + } + + for($x=$xl, $i = 0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$steps+$i]; + $y = $yt+($i/$steps)*($yb-$yt)*$delta; + $this->img->Line($x,$yb,$xr,$y); + $x += $delta; + } + } else { + // height is greater than width -> use y-dimension for steps + $steps = $yb-$yt; + $delta = $yb>=$yt ? 1 : -1; + $this->GetColArray($from_color,$to_color,$steps*2,$colors,$this->numcolors); + $n = count($colors); + + for($y=$yt, $i=0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$i]; + $x = $xl+($i/$steps)*($xr-$xl)*$delta; + $this->img->Line($x,$yt,$xl,$y); + $y += $delta; + } + + for($y=$yt, $i = 0; $i < $steps && $i < $n; ++$i) { + $this->img->current_color = $colors[$steps+$i]; + $x = $xl+($i/$steps)*($xr-$xl)*$delta; + $this->img->Line($x,$yb,$xr,$y); + $x += $delta; + } + + } + break; + + default: + JpGraphError::RaiseL(7001,$style); +//("Unknown gradient style (=$style)."); + break; + } + } + + // Fill a special case of a polygon with a flat bottom + // with a gradient. Can be used for filled line plots. + // Please note that this is NOT a generic gradient polygon fill + // routine. It assumes that the bottom is flat (like a drawing + // of a mountain) + function FilledFlatPolygon($pts,$from_color,$to_color) { + if( count($pts) == 0 ) return; + + $maxy=$pts[1]; + $miny=$pts[1]; + $n = count($pts) ; + for( $i=0, $idx=0; $i < $n; $i += 2) { + $x = round($pts[$i]); + $y = round($pts[$i+1]); + $miny = min($miny,$y); + $maxy = max($maxy,$y); + } + + $colors = array(); + $this->GetColArray($from_color,$to_color,abs($maxy-$miny)+1,$colors,$this->numcolors); + for($i=$miny, $idx=0; $i <= $maxy; ++$i ) { + $colmap[$i] = $colors[$idx++]; + } + + $n = count($pts)/2 ; + $idx = 0 ; + while( $idx < $n-1 ) { + $p1 = array(round($pts[$idx*2]),round($pts[$idx*2+1])); + $p2 = array(round($pts[++$idx*2]),round($pts[$idx*2+1])); + + // Find the largest rectangle we can fill + $y = max($p1[1],$p2[1]) ; + for($yy=$maxy; $yy > $y; --$yy) { + $this->img->current_color = $colmap[$yy]; + $this->img->Line($p1[0],$yy,$p2[0]-1,$yy); + } + + if( $p1[1] == $p2[1] ) continue; + + // Fill the rest using lines (slow...) + $slope = ($p2[0]-$p1[0])/($p1[1]-$p2[1]); + $x1 = $p1[0]; + $x2 = $p2[0]-1; + $start = $y; + if( $p1[1] > $p2[1] ) { + while( $y >= $p2[1] ) { + $x1=$slope*($start-$y)+$p1[0]; + $this->img->current_color = $colmap[$y]; + $this->img->Line($x1,$y,$x2,$y); + --$y; + } + } + else { + while( $y >= $p1[1] ) { + $x2=$p2[0]+$slope*($start-$y); + $this->img->current_color = $colmap[$y]; + $this->img->Line($x1,$y,$x2,$y); + --$y; + } + } + } + } + +//--------------- +// PRIVATE METHODS + // Add to the image color map the necessary colors to do the transition + // between the two colors using $numcolors intermediate colors + function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) { + if( $arr_size==0 ) return; + // If color is given as text get it's corresponding r,g,b values + $from_color = $this->img->rgb->Color($from_color); + $to_color = $this->img->rgb->Color($to_color); + + $rdelta=($to_color[0]-$from_color[0])/$numcols; + $gdelta=($to_color[1]-$from_color[1])/$numcols; + $bdelta=($to_color[2]-$from_color[2])/$numcols; + $colorsperstep = $numcols/$arr_size; + $prevcolnum = -1; + $from_alpha = $from_color[3]; + $to_alpha = $to_color[3]; + $adelta = ( $to_alpha - $from_alpha ) / $numcols ; + for ($i=0; $i < $arr_size; ++$i) { + $colnum = floor($colorsperstep*$i); + if ( $colnum == $prevcolnum ) + $colors[$i] = $colidx; + else { + $r = floor($from_color[0] + $colnum*$rdelta); + $g = floor($from_color[1] + $colnum*$gdelta); + $b = floor($from_color[2] + $colnum*$bdelta); + $alpha = $from_alpha + $colnum*$adelta; + $colidx = $this->img->rgb->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b),$alpha); + $colors[$i] = $colidx; + } + $prevcolnum = $colnum; + } + } +} // Class + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_iconplot.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_iconplot.php new file mode 100644 index 0000000..f2a6d19 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_iconplot.php @@ -0,0 +1,190 @@ +iFile = $aFile; + $this->iX=$aX; + $this->iY=$aY; + $this->iScale= $aScale; + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001); //('Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix ; + } + + function SetCountryFlag($aFlag,$aX=0,$aY=0,$aScale=1.0,$aMix=100,$aStdSize=3) { + $this->iCountryFlag = $aFlag; + $this->iX=$aX; + $this->iY=$aY; + $this->iScale= $aScale; + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001);//'Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix; + $this->iCountryStdSize = $aStdSize; + } + + function SetPos($aX,$aY) { + $this->iX=$aX; + $this->iY=$aY; + } + + function CreateFromString($aStr) { + $this->iImgString = $aStr; + } + + function SetScalePos($aX,$aY) { + $this->iScalePosX = $aX; + $this->iScalePosY = $aY; + } + + function SetScale($aScale) { + $this->iScale = $aScale; + } + + function SetMix($aMix) { + if( $aMix < 0 || $aMix > 100 ) { + JpGraphError::RaiseL(8001);//('Mix value for icon must be between 0 and 100.'); + } + $this->iMix = $aMix ; + } + + function SetAnchor($aXAnchor='left',$aYAnchor='center') { + if( !in_array($aXAnchor,$this->iAnchors) || + !in_array($aYAnchor,$this->iAnchors) ) { + JpGraphError::RaiseL(8002);//("Anchor position for icons must be one of 'top', 'bottom', 'left', 'right' or 'center'"); + } + $this->iHorAnchor=$aXAnchor; + $this->iVertAnchor=$aYAnchor; + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do ... + } + + function DoLegend($aGraph) { + // Nothing to do ... + } + + function Max() { + return array(false,false); + } + + + // The next four function are framework function tht gets called + // from Gantt and is not menaiungfull in the context of Icons but + // they must be implemented to avoid errors. + function GetMaxDate() { return false; } + function GetMinDate() { return false; } + function GetLineNbr() { return 0; } + function GetAbsHeight() {return 0; } + + + function Min() { + return array(false,false); + } + + function StrokeMargin(&$aImg) { + return true; + } + + function Stroke($aImg,$axscale,$ayscale) { + $this->StrokeWithScale($aImg,$axscale,$ayscale); + } + + function StrokeWithScale($aImg,$axscale,$ayscale) { + if( $this->iScalePosX === null || + $this->iScalePosY === null ) { + $this->_Stroke($aImg); + } + else { + $this->_Stroke($aImg, + round($axscale->Translate($this->iScalePosX)), + round($ayscale->Translate($this->iScalePosY))); + } + } + + function GetWidthHeight() { + $dummy=0; + return $this->_Stroke($dummy,null,null,true); + } + + function _Stroke($aImg,$x=null,$y=null,$aReturnWidthHeight=false) { + if( $this->iFile != '' && $this->iCountryFlag != '' ) { + JpGraphError::RaiseL(8003);//('It is not possible to specify both an image file and a country flag for the same icon.'); + } + if( $this->iFile != '' ) { + $gdimg = Graph::LoadBkgImage('',$this->iFile); + } + elseif( $this->iImgString != '') { + $gdimg = Image::CreateFromString($this->iImgString); + } + + else { + if( ! class_exists('FlagImages',false) ) { + JpGraphError::RaiseL(8004);//('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.'); + } + $fobj = new FlagImages($this->iCountryStdSize); + $dummy=''; + $gdimg = $fobj->GetImgByName($this->iCountryFlag,$dummy); + } + + $iconw = imagesx($gdimg); + $iconh = imagesy($gdimg); + + if( $aReturnWidthHeight ) { + return array(round($iconw*$this->iScale),round($iconh*$this->iScale)); + } + + if( $x !== null && $y !== null ) { + $this->iX = $x; $this->iY = $y; + } + if( $this->iX >= 0 && $this->iX <= 1.0 ) { + $w = imagesx($aImg->img); + $this->iX = round($w*$this->iX); + } + if( $this->iY >= 0 && $this->iY <= 1.0 ) { + $h = imagesy($aImg->img); + $this->iY = round($h*$this->iY); + } + + if( $this->iHorAnchor == 'center' ) + $this->iX -= round($iconw*$this->iScale/2); + if( $this->iHorAnchor == 'right' ) + $this->iX -= round($iconw*$this->iScale); + if( $this->iVertAnchor == 'center' ) + $this->iY -= round($iconh*$this->iScale/2); + if( $this->iVertAnchor == 'bottom' ) + $this->iY -= round($iconh*$this->iScale); + + $aImg->CopyMerge($gdimg,$this->iX,$this->iY,0,0, + round($iconw*$this->iScale),round($iconh*$this->iScale), + $iconw,$iconh, + $this->iMix); + } +} + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_imgtrans.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_imgtrans.php new file mode 100644 index 0000000..2d1359e --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_imgtrans.php @@ -0,0 +1,223 @@ +gdImg = $aGdImg; + } + + // -------------------------------------------------------------------- + // _TransVert3D() and _TransHor3D() are helper methods to + // Skew3D(). + // -------------------------------------------------------------------- + function _TransVert3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_DOWN,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { + + + // Parameter check + if( $aHorizonPos < 0 || $aHorizonPos > 1.0 ) { + JpGraphError::RaiseL(9001); +//("Value for image transformation out of bounds.\nVanishing point on horizon must be specified as a value between 0 and 1."); + } + + $w = imagesx($aGdImg); + $h = imagesy($aGdImg); + + // Create new image + $ww = $w; + if( $aMinSize ) + $hh = ceil($h * $aHorizon / ($aSkewDist+$h)); + else + $hh = $h; + + $newgdh = imagecreatetruecolor($ww,$hh); + $crgb = new RGB( $newgdh ); + $fillColor = $crgb->Allocate($aFillColor); + imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); + + if( $aBorder ) { + $colidx = $crgb->Allocate($aBorder); + imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); + } + + $mid = round($w * $aHorizonPos); + + $last=$h; + for($y=0; $y < $h; ++$y) { + + $yp = $h-$y-1; + $yt = floor($yp * $aHorizon / ($aSkewDist + $yp)); + + if( !$aQuality ) { + if( $last <= $yt ) continue ; + $last = $yt; + } + + for($x=0; $x < $w; ++$x) { + $xt = ($x-$mid) * $aSkewDist / ($aSkewDist + $yp); + if( $aDir == SKEW3D_UP ) + $rgb = imagecolorat($aGdImg,$x,$h-$y-1); + else + $rgb = imagecolorat($aGdImg,$x,$y); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $colidx = imagecolorallocate($newgdh,$r,$g,$b); + $xt = round($xt+$mid); + if( $aDir == SKEW3D_UP ) { + $syt = $yt; + } + else { + $syt = $hh-$yt-1; + } + + if( !empty($set[$yt]) ) { + $nrgb = imagecolorat($newgdh,$xt,$syt); + $nr = ($nrgb >> 16) & 0xFF; + $ng = ($nrgb >> 8) & 0xFF; + $nb = $nrgb & 0xFF; + $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), + floor(($g+$ng)/2),floor(($b+$nb)/2)); + } + + imagesetpixel($newgdh,$xt,$syt,$colidx); + } + + $set[$yt] = true; + } + + return $newgdh; + } + + // -------------------------------------------------------------------- + // _TransVert3D() and _TransHor3D() are helper methods to + // Skew3D(). + // -------------------------------------------------------------------- + function _TransHor3D($aGdImg,$aHorizon=100,$aSkewDist=120,$aDir=SKEW3D_LEFT,$aMinSize=true,$aFillColor='#FFFFFF',$aQuality=false,$aBorder=false,$aHorizonPos=0.5) { + + $w = imagesx($aGdImg); + $h = imagesy($aGdImg); + + // Create new image + $hh = $h; + if( $aMinSize ) + $ww = ceil($w * $aHorizon / ($aSkewDist+$w)); + else + $ww = $w; + + $newgdh = imagecreatetruecolor($ww,$hh); + $crgb = new RGB( $newgdh ); + $fillColor = $crgb->Allocate($aFillColor); + imagefilledrectangle($newgdh,0,0,$ww-1,$hh-1,$fillColor); + + if( $aBorder ) { + $colidx = $crgb->Allocate($aBorder); + imagerectangle($newgdh,0,0,$ww-1,$hh-1,$colidx); + } + + $mid = round($h * $aHorizonPos); + + $last = -1; + for($x=0; $x < $w-1; ++$x) { + $xt = floor($x * $aHorizon / ($aSkewDist + $x)); + if( !$aQuality ) { + if( $last >= $xt ) continue ; + $last = $xt; + } + + for($y=0; $y < $h; ++$y) { + $yp = $h-$y-1; + $yt = ($yp-$mid) * $aSkewDist / ($aSkewDist + $x); + + if( $aDir == SKEW3D_RIGHT ) + $rgb = imagecolorat($aGdImg,$w-$x-1,$y); + else + $rgb = imagecolorat($aGdImg,$x,$y); + $r = ($rgb >> 16) & 0xFF; + $g = ($rgb >> 8) & 0xFF; + $b = $rgb & 0xFF; + $colidx = imagecolorallocate($newgdh,$r,$g,$b); + $yt = floor($hh-$yt-$mid-1); + if( $aDir == SKEW3D_RIGHT ) { + $sxt = $ww-$xt-1; + } + else + $sxt = $xt ; + + if( !empty($set[$xt]) ) { + $nrgb = imagecolorat($newgdh,$sxt,$yt); + $nr = ($nrgb >> 16) & 0xFF; + $ng = ($nrgb >> 8) & 0xFF; + $nb = $nrgb & 0xFF; + $colidx = imagecolorallocate($newgdh,floor(($r+$nr)/2), + floor(($g+$ng)/2),floor(($b+$nb)/2)); + } + imagesetpixel($newgdh,$sxt,$yt,$colidx); + } + + $set[$xt] = true; + } + + return $newgdh; + } + + // -------------------------------------------------------------------- + // Skew image for the apperance of a 3D effect + // This transforms an image into a 3D-skewed version + // of the image. The transformation is specified by giving the height + // of the artificial horizon and specifying a "skew" factor which + // is the distance on the horizon line between the point of + // convergence and perspective line. + // + // The function returns the GD handle of the transformed image + // leaving the original image untouched. + // + // Parameters: + // * $aGdImg, GD handle to the image to be transformed + // * $aHorizon, Distance to the horizon + // * $aSkewDist, Distance from the horizon point of convergence + // on the horizon line to the perspective points. A larger + // value will fore-shorten the image more + // * $aDir, parameter specifies type of convergence. This of this + // as the walls in a room you are looking at. This specifies if the + // image should be applied on the left,right,top or bottom walls. + // * $aMinSize, true=make the new image just as big as needed, + // false = keep the image the same size as the original image + // * $aFillColor, Background fill color in the image + // * $aHiQuality, true=performa some interpolation that improves + // the image quality but at the expense of performace. Enabling + // high quality will have a dramatic effect on the time it takes + // to transform an image. + // * $aBorder, if set to anything besides false this will draw a + // a border of the speciied color around the image + // -------------------------------------------------------------------- + function Skew3D($aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { + return $this->_Skew3D($this->gdImg,$aHorizon,$aSkewDist,$aDir,$aHiQuality, + $aMinSize,$aFillColor,$aBorder); + } + + function _Skew3D($aGdImg,$aHorizon=120,$aSkewDist=150,$aDir=SKEW3D_DOWN,$aHiQuality=false,$aMinSize=true,$aFillColor='#FFFFFF',$aBorder=false) { + if( $aDir == SKEW3D_DOWN || $aDir == SKEW3D_UP ) + return $this->_TransVert3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); + else + return $this->_TransHor3D($aGdImg,$aHorizon,$aSkewDist,$aDir,$aMinSize,$aFillColor,$aHiQuality,$aBorder); + + } + +} + + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_line.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_line.php new file mode 100644 index 0000000..144e978 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_line.php @@ -0,0 +1,624 @@ +Plot($datay,$datax); + $this->mark = new PlotMark() ; + } +//--------------- +// PUBLIC METHODS + + // Set style, filled or open + function SetFilled($aFlag=true) { + JpGraphError::RaiseL(10001);//('LinePlot::SetFilled() is deprecated. Use SetFillColor()'); + } + + function SetBarCenter($aFlag=true) { + $this->barcenter=$aFlag; + } + + function SetStyle($aStyle) { + $this->line_style=$aStyle; + } + + function SetStepStyle($aFlag=true) { + $this->step_style = $aFlag; + } + + function SetColor($aColor) { + parent::SetColor($aColor); + } + + function SetFillFromYMin($f=true) { + $this->fillFromMin = $f ; + } + + function SetFillColor($aColor,$aFilled=true) { + $this->fill_color=$aColor; + $this->filled=$aFilled; + } + + function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) { + $this->fillgrad_fromcolor = $aFromColor; + $this->fillgrad_tocolor = $aToColor; + $this->fillgrad_numcolors = $aNumColors; + $this->filled = $aFilled; + $this->fillgrad = true; + } + + function Legend($graph) { + if( $this->legend!="" ) { + if( $this->filled && !$this->fillgrad ) { + $graph->legend->Add($this->legend, + $this->fill_color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + elseif( $this->fillgrad ) { + $color=array($this->fillgrad_fromcolor,$this->fillgrad_tocolor); + // In order to differentiate between gradients and cooors specified as an RGB triple + $graph->legend->Add($this->legend,$color,"",-2 /* -GRAD_HOR */, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } else { + $graph->legend->Add($this->legend, + $this->color,$this->mark,$this->line_style, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } + } + + function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) { + if($aMin > $aMax) { + // swap + $tmp = $aMin; + $aMin = $aMax; + $aMax = $tmp; + } + $this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder); + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + + // If another plot type have already adjusted the + // offset we don't touch it. + // (We check for empty in case the scale is a log scale + // and hence doesn't contain any xlabel_offset) + if( empty($graph->xaxis->scale->ticks->xlabel_offset) || + $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { + if( $this->center ) { + ++$this->numpoints; + $a=0.5; $b=0.5; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); + } + } + + function SetFastStroke($aFlg=true) { + $this->iFastStroke = $aFlg; + } + + function FastStroke($img,$xscale,$yscale,$aStartPoint=0,$exist_x=true) { + // An optimized stroke for many data points with no extra + // features but 60% faster. You can't have values or line styles, or null + // values in plots. + $numpoints=count($this->coords[0]); + if( $this->barcenter ) + $textadj = 0.5-$xscale->text_scale_off; + else + $textadj = 0; + + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + $pnts=$aStartPoint; + while( $pnts < $numpoints ) { + if( $exist_x ) $x=$this->coords[1][$pnts]; + else $x=$pnts+$textadj; + $xt = $xscale->Translate($x); + $y=$this->coords[0][$pnts]; + $yt = $yscale->Translate($y); + if( is_numeric($y) ) { + $cord[] = $xt; + $cord[] = $yt; + } + elseif( $y == '-' && $pnts > 0 ) { + // Just ignore + } + else { + JpGraphError::RaiseL(10002);//('Plot too complicated for fast line Stroke. Use standard Stroke()'); + } + ++$pnts; + } // WHILE + + $img->Polygon($cord,false,true); + } + + function Stroke($img,$xscale,$yscale) { + $idx=0; + $numpoints=count($this->coords[0]); + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$numpoints ) + JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); +//("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); + else + $exist_x = true; + } + else + $exist_x = false; + + if( $this->barcenter ) + $textadj = 0.5-$xscale->text_scale_off; + else + $textadj = 0; + + // Find the first numeric data point + $startpoint=0; + while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) ) + ++$startpoint; + + // Bail out if no data points + if( $startpoint == $numpoints ) + return; + + if( $this->iFastStroke ) { + $this->FastStroke($img,$xscale,$yscale,$startpoint,$exist_x); + return; + } + + if( $exist_x ) + $xs=$this->coords[1][$startpoint]; + else + $xs= $textadj+$startpoint; + + $img->SetStartPoint($xscale->Translate($xs), + $yscale->Translate($this->coords[0][$startpoint])); + + + if( $this->filled ) { + $min = $yscale->GetMinVal(); + if( $min > 0 || $this->fillFromMin ) + $fillmin = $yscale->scale_abs[0];//Translate($min); + else + $fillmin = $yscale->Translate(0); + + $cord[$idx++] = $xscale->Translate($xs); + $cord[$idx++] = $fillmin; + } + $xt = $xscale->Translate($xs); + $yt = $yscale->Translate($this->coords[0][$startpoint]); + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + $yt_old = $yt; + $xt_old = $xt; + $y_old = $this->coords[0][$startpoint]; + + $this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt); + + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + $img->SetLineStyle($this->line_style); + $pnts=$startpoint+1; + $firstnonumeric = false; + while( $pnts < $numpoints ) { + + if( $exist_x ) $x=$this->coords[1][$pnts]; + else $x=$pnts+$textadj; + $xt = $xscale->Translate($x); + $yt = $yscale->Translate($this->coords[0][$pnts]); + + $y=$this->coords[0][$pnts]; + if( $this->step_style ) { + // To handle null values within step style we need to record the + // first non numeric value so we know from where to start if the + // non value is '-'. + if( is_numeric($y) ) { + $firstnonumeric = false; + if( is_numeric($y_old) ) { + $img->StyleLine($xt_old,$yt_old,$xt,$yt_old); + $img->StyleLine($xt,$yt_old,$xt,$yt); + } + elseif( $y_old == '-' ) { + $img->StyleLine($xt_first,$yt_first,$xt,$yt_first); + $img->StyleLine($xt,$yt_first,$xt,$yt); + } + else { + $yt_old = $yt; + $xt_old = $xt; + } + $cord[$idx++] = $xt; + $cord[$idx++] = $yt_old; + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + } + elseif( $firstnonumeric==false ) { + $firstnonumeric = true; + $yt_first = $yt_old; + $xt_first = $xt_old; + } + } + else { + $tmp1=$y; + $prev=$this->coords[0][$pnts-1]; + if( $tmp1==='' || $tmp1===NULL || $tmp1==='X' ) $tmp1 = 'x'; + if( $prev==='' || $prev===null || $prev==='X' ) $prev = 'x'; + + if( is_numeric($y) || (is_string($y) && $y != '-') ) { + if( is_numeric($y) && (is_numeric($prev) || $prev === '-' ) ) { + $img->StyleLineTo($xt,$yt); + } + else { + $img->SetStartPoint($xt,$yt); + } + } + if( $this->filled && $tmp1 !== '-' ) { + if( $tmp1 === 'x' ) { + $cord[$idx++] = $cord[$idx-3]; + $cord[$idx++] = $fillmin; + } + elseif( $prev === 'x' ) { + $cord[$idx++] = $xt; + $cord[$idx++] = $fillmin; + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + } + else { + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + } + } + else { + if( is_numeric($tmp1) && (is_numeric($prev) || $prev === '-' ) ) { + $cord[$idx++] = $xt; + $cord[$idx++] = $yt; + } + } + } + $yt_old = $yt; + $xt_old = $xt; + $y_old = $y; + + $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt); + + ++$pnts; + } + + if( $this->filled ) { + $cord[$idx++] = $xt; + if( $min > 0 || $this->fillFromMin ) + $cord[$idx++] = $yscale->Translate($min); + else + $cord[$idx++] = $yscale->Translate(0); + if( $this->fillgrad ) { + $img->SetLineWeight(1); + $grad = new Gradient($img); + $grad->SetNumColors($this->fillgrad_numcolors); + $grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor); + $img->SetLineWeight($this->weight); + } + else { + $img->SetColor($this->fill_color); + $img->FilledPolygon($cord); + } + if( $this->line_weight > 0 ) { + $img->SetColor($this->color); + $img->Polygon($cord); + } + } + + if(!empty($this->filledAreas)) { + + $minY = $yscale->Translate($yscale->GetMinVal()); + $factor = ($this->step_style ? 4 : 2); + + for($i = 0; $i < sizeof($this->filledAreas); ++$i) { + // go through all filled area elements ordered by insertion + // fill polygon array + $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor]; + $areaCoords[] = $minY; + + $areaCoords = + array_merge($areaCoords, + array_slice($cord, + $this->filledAreas[$i][0] * $factor, + ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1)) * $factor)); + $areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x + $areaCoords[] = $minY; // last y + + if($this->filledAreas[$i][3]) { + $img->SetColor($this->filledAreas[$i][2]); + $img->FilledPolygon($areaCoords); + $img->SetColor($this->color); + } + // Check if we should draw the frame. + // If not we still re-draw the line since it might have been + // partially overwritten by the filled area and it doesn't look + // very good. + // TODO: The behaviour is undefined if the line does not have + // any line at the position of the area. + if( $this->filledAreas[$i][4] ) + $img->Polygon($areaCoords); + else + $img->Polygon($cord); + + $areaCoords = array(); + } + } + + if( $this->mark->type == -1 || $this->mark->show == false ) + return; + + for( $pnts=0; $pnts<$numpoints; ++$pnts) { + + if( $exist_x ) $x=$this->coords[1][$pnts]; + else $x=$pnts+$textadj; + $xt = $xscale->Translate($x); + $yt = $yscale->Translate($this->coords[0][$pnts]); + + if( is_numeric($this->coords[0][$pnts]) ) { + if( !empty($this->csimtargets[$pnts]) ) { + if( !empty($this->csimwintargets[$pnts]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$pnts],$this->csimwintargets[$pnts]); + } + else { + $this->mark->SetCSIMTarget($this->csimtargets[$pnts]); + } + $this->mark->SetCSIMAlt($this->csimalts[$pnts]); + } + if( $exist_x ) + $x=$this->coords[1][$pnts]; + else + $x=$pnts; + $this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x); + $this->mark->Stroke($img,$xt,$yt); + $this->csimareas .= $this->mark->GetCSIMAreas(); + $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt); + } + } + } +} // Class + + +//=================================================== +// CLASS AccLinePlot +// Description: +//=================================================== +class AccLinePlot extends Plot { + protected $plots=null,$nbrplots=0; + private $iStartEndZero=true; +//--------------- +// CONSTRUCTOR + function AccLinePlot($plots) { + $this->plots = $plots; + $this->nbrplots = count($plots); + $this->numpoints = $plots[0]->numpoints; + + for($i=0; $i < $this->nbrplots; ++$i ) { + $this->LineInterpolate($this->plots[$i]->coords[0]); + } + } + +//--------------- +// PUBLIC METHODS + function Legend($graph) { + foreach( $this->plots as $p ) + $p->DoLegend($graph); + } + + function Max() { + list($xmax) = $this->plots[0]->Max(); + $nmax=0; + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + $nc = count($this->plots[$i]->coords[0]); + $nmax = max($nmax,$nc); + list($x) = $this->plots[$i]->Max(); + $xmax = Max($xmax,$x); + } + for( $i = 0; $i < $nmax; $i++ ) { + // Get y-value for line $i by adding the + // individual bars from all the plots added. + // It would be wrong to just add the + // individual plots max y-value since that + // would in most cases give to large y-value. + $y=$this->plots[0]->coords[0][$i]; + for( $j = 1; $j < $this->nbrplots; $j++ ) { + $y += $this->plots[ $j ]->coords[0][$i]; + } + $ymax[$i] = $y; + } + $ymax = max($ymax); + return array($xmax,$ymax); + } + + function Min() { + $nmax=0; + list($xmin,$ysetmin) = $this->plots[0]->Min(); + $n = count($this->plots); + for($i=0; $i < $n; ++$i) { + $nc = count($this->plots[$i]->coords[0]); + $nmax = max($nmax,$nc); + list($x,$y) = $this->plots[$i]->Min(); + $xmin = Min($xmin,$x); + $ysetmin = Min($y,$ysetmin); + } + for( $i = 0; $i < $nmax; $i++ ) { + // Get y-value for line $i by adding the + // individual bars from all the plots added. + // It would be wrong to just add the + // individual plots min y-value since that + // would in most cases give to small y-value. + $y=$this->plots[0]->coords[0][$i]; + for( $j = 1; $j < $this->nbrplots; $j++ ) { + $y += $this->plots[ $j ]->coords[0][$i]; + } + $ymin[$i] = $y; + } + $ymin = Min($ysetmin,Min($ymin)); + return array($xmin,$ymin); + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + + // If another plot type have already adjusted the + // offset we don't touch it. + // (We check for empty in case the scale is a log scale + // and hence doesn't contain any xlabel_offset) + + if( empty($graph->xaxis->scale->ticks->xlabel_offset) || + $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { + if( $this->center ) { + ++$this->numpoints; + $a=0.5; $b=0.5; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + $graph->xaxis->scale->ticks->SupressMinorTickMarks(); + } + + } + + function SetInterpolateMode($aIntMode) { + $this->iStartEndZero=$aIntMode; + } + + // Replace all '-' with an interpolated value. We use straightforward + // linear interpolation. If the data starts with one or several '-' they + // will be replaced by the the first valid data point + function LineInterpolate(&$aData) { + + $n=count($aData); + $i=0; + + // If first point is undefined we will set it to the same as the first + // valid data + if( $aData[$i]==='-' ) { + // Find the first valid data + while( $i < $n && $aData[$i]==='-' ) { + ++$i; + } + if( $i < $n ) { + for($j=0; $j < $i; ++$j ) { + if( $this->iStartEndZero ) + $aData[$i] = 0; + else + $aData[$j] = $aData[$i]; + } + } + else { + // All '-' => Error + return false; + } + } + + while($i < $n) { + while( $i < $n && $aData[$i] !== '-' ) { + ++$i; + } + if( $i < $n ) { + $pstart=$i-1; + + // Now see how long this segment of '-' are + while( $i < $n && $aData[$i] === '-' ) + ++$i; + if( $i < $n ) { + $pend=$i; + $size=$pend-$pstart; + $k=($aData[$pend]-$aData[$pstart])/$size; + // Replace the segment of '-' with a linear interpolated value. + for($j=1; $j < $size; ++$j ) { + $aData[$pstart+$j] = $aData[$pstart] + $j*$k ; + } + } + else { + // There are no valid end point. The '-' goes all the way to the end + // In that case we just set all the remaining values the the same as the + // last valid data point. + for( $j=$pstart+1; $j < $n; ++$j ) + if( $this->iStartEndZero ) + $aData[$j] = 0; + else + $aData[$j] = $aData[$pstart] ; + } + } + } + return true; + } + + + + // To avoid duplicate of line drawing code here we just + // change the y-values for each plot and then restore it + // after we have made the stroke. We must do this copy since + // it wouldn't be possible to create an acc line plot + // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl)); + // since this method would have a side effect. + function Stroke($img,$xscale,$yscale) { + $img->SetLineWeight($this->weight); + $this->numpoints = count($this->plots[0]->coords[0]); + // Allocate array + $coords[$this->nbrplots][$this->numpoints]=0; + for($i=0; $i<$this->numpoints; $i++) { + $coords[0][$i]=$this->plots[0]->coords[0][$i]; + $accy=$coords[0][$i]; + for($j=1; $j<$this->nbrplots; ++$j ) { + $coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy; + $accy = $coords[$j][$i]; + } + } + for($j=$this->nbrplots-1; $j>=0; --$j) { + $p=$this->plots[$j]; + for( $i=0; $i<$this->numpoints; ++$i) { + $tmp[$i]=$p->coords[0][$i]; + $p->coords[0][$i]=$coords[$j][$i]; + } + $p->Stroke($img,$xscale,$yscale); + for( $i=0; $i<$this->numpoints; ++$i) + $p->coords[0][$i]=$tmp[$i]; + $p->coords[0][]=$tmp; + } + } +} // Class + + +/* EOF */ +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_log.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_log.php new file mode 100644 index 0000000..0da887e --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_log.php @@ -0,0 +1,283 @@ +LinearScale($min,$max,$type); + $this->ticks = new LogTicks(); + $this->name = 'log'; + } + +//---------------- +// PUBLIC METHODS + + // Translate between world and screen + function Translate($a) { + if( !is_numeric($a) ) { + if( $a != '' && $a != '-' && $a != 'x' ) + JpGraphError::RaiseL(11001); +//('Your data contains non-numeric values.'); + return 1; + } + if( $a < 0 ) { + JpGraphError::RaiseL(11002); +//("Negative data values can not be used in a log scale."); + exit(1); + } + if( $a==0 ) $a=1; + $a=log10($a); + return ceil($this->off + ($a*1.0 - $this->scale[0]) * $this->scale_factor); + } + + // Relative translate (don't include offset) usefull when we just want + // to know the relative position (in pixels) on the axis + function RelTranslate($a) { + if( !is_numeric($a) ) { + if( $a != '' && $a != '-' && $a != 'x' ) + JpGraphError::RaiseL(11001); +//('Your data contains non-numeric values.'); + return 1; + } + if( $a==0 ) $a=1; + $a=log10($a); + return round(($a*1.0 - $this->scale[0]) * $this->scale_factor); + } + + // Use bcpow() for increased precision + function GetMinVal() { + if( function_exists("bcpow") ) + return round(bcpow(10,$this->scale[0],15),14); + else + return round(pow(10,$this->scale[0]),14); + } + + function GetMaxVal() { + if( function_exists("bcpow") ) + return round(bcpow(10,$this->scale[1],15),14); + else + return round(pow(10,$this->scale[1]),14); + } + + // Logarithmic autoscaling is much simplier since we just + // set the min and max to logs of the min and max values. + // Note that for log autoscale the "maxstep" the fourth argument + // isn't used. This is just included to give the method the same + // signature as the linear counterpart. + function AutoScale($img,$min,$max,$maxsteps,$majend=true) { + if( $min==0 ) $min=1; + + if( $max <= 0 ) { + JpGraphError::RaiseL(11004); +//('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.'); + } + if( is_numeric($this->autoscale_min) ) { + $smin = round($this->autoscale_min); + $smax = ceil(log10($max)); + if( $min >= $max ) { + JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); + } + } + else { + $smin = floor(log10($min)); + if( is_numeric($this->autoscale_max) ) { + $smax = round($this->autoscale_max); + if( $smin >= $smax ) { + JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); + } + } + else + $smax = ceil(log10($max)); + } + + $this->Update($img,$smin,$smax); + } +//--------------- +// PRIVATE METHODS +} // Class + +//=================================================== +// CLASS LogTicks +// Description: +//=================================================== +class LogTicks extends Ticks{ + private $label_logtype=LOGLABELS_MAGNITUDE; + private $ticklabels_pos = array(); +//--------------- +// CONSTRUCTOR + function LogTicks() { + } +//--------------- +// PUBLIC METHODS + function IsSpecified() { + return true; + } + + function SetLabelLogType($aType) { + $this->label_logtype = $aType; + } + + // For log scale it's meaningless to speak about a major step + // We just return -1 to make the framework happy (specifically + // StrokeLabels() ) + function GetMajor() { + return -1; + } + + function SetTextLabelStart($aStart) { + JpGraphError::RaiseL(11005); +//('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.'); + } + + function SetXLabelOffset($dummy) { + // For log scales we dont care about XLabel offset + } + + // Draw ticks on image "img" using scale "scale". The axis absolute + // position in the image is specified in pos, i.e. for an x-axis + // it specifies the absolute y-coord and for Y-ticks it specified the + // absolute x-position. + function Stroke($img,$scale,$pos) { + $start = $scale->GetMinVal(); + $limit = $scale->GetMaxVal(); + $nextMajor = 10*$start; + $step = $nextMajor / 10.0; + + + $img->SetLineWeight($this->weight); + + if( $scale->type == "y" ) { + // member direction specified if the ticks should be on + // left or right side. + $a=$pos + $this->direction*$this->GetMinTickAbsSize(); + $a2=$pos + $this->direction*$this->GetMajTickAbsSize(); + + $count=1; + $this->maj_ticks_pos[0]=$scale->Translate($start); + $this->maj_ticklabels_pos[0]=$scale->Translate($start); + if( $this->supress_first ) + $this->maj_ticks_label[0]=""; + else { + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[0]=call_user_func($f,$start); + } + elseif( $this->label_logtype == LOGLABELS_PLAIN ) + $this->maj_ticks_label[0]=$start; + else + $this->maj_ticks_label[0]='10^'.round(log10($start)); + } + $i=1; + for($y=$start; $y<=$limit; $y+=$step,++$count ) { + $ys=$scale->Translate($y); + $this->ticks_pos[]=$ys; + $this->ticklabels_pos[]=$ys; + if( $count % 10 == 0 ) { + if( !$this->supress_tickmarks ) { + if( $this->majcolor!="" ) { + $img->PushColor($this->majcolor); + $img->Line($pos,$ys,$a2,$ys); + $img->PopColor(); + } + else + $img->Line($pos,$ys,$a2,$ys); + } + + $this->maj_ticks_pos[$i]=$ys; + $this->maj_ticklabels_pos[$i]=$ys; + + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); + } + elseif( $this->label_logtype == 0 ) + $this->maj_ticks_label[$i]=$nextMajor; + else + $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); + ++$i; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else { + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + if( $this->mincolor!="" ) $img->PushColor($this->mincolor); + $img->Line($pos,$ys,$a,$ys); + if( $this->mincolor!="" ) $img->PopColor(); + } + } + } + } + else { + $a=$pos - $this->direction*$this->GetMinTickAbsSize(); + $a2=$pos - $this->direction*$this->GetMajTickAbsSize(); + $count=1; + $this->maj_ticks_pos[0]=$scale->Translate($start); + $this->maj_ticklabels_pos[0]=$scale->Translate($start); + if( $this->supress_first ) + $this->maj_ticks_label[0]=""; + else { + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[0]=call_user_func($f,$start); + } + elseif( $this->label_logtype == 0 ) + $this->maj_ticks_label[0]=$start; + else + $this->maj_ticks_label[0]='10^'.round(log10($start)); + } + $i=1; + for($x=$start; $x<=$limit; $x+=$step,++$count ) { + $xs=$scale->Translate($x); + $this->ticks_pos[]=$xs; + $this->ticklabels_pos[]=$xs; + if( $count % 10 == 0 ) { + if( !$this->supress_tickmarks ) { + $img->Line($xs,$pos,$xs,$a2); + } + $this->maj_ticks_pos[$i]=$xs; + $this->maj_ticklabels_pos[$i]=$xs; + + if( $this->label_formfunc != '' ) { + $f = $this->label_formfunc; + $this->maj_ticks_label[$i]=call_user_func($f,$nextMajor); + } + elseif( $this->label_logtype == 0 ) + $this->maj_ticks_label[$i]=$nextMajor; + else + $this->maj_ticks_label[$i]='10^'.round(log10($nextMajor)); + ++$i; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else { + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + $img->Line($xs,$pos,$xs,$a); + } + } + } + } + return true; + } +} // Class +/* EOF */ +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_mgraph.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_mgraph.php new file mode 100644 index 0000000..d701371 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_mgraph.php @@ -0,0 +1,387 @@ +iWidth = $aWidth; + $this->iHeight = $aHeight; + } + + // Specify background fill color for the combined graph + function SetFillColor($aColor) { + $this->iFillColor = $aColor; + } + + // Add a frame around the combined graph + function SetFrame($aFlg,$aColor='black',$aWeight=1) { + $this->iDoFrame = $aFlg; + $this->iFrameColor = $aColor; + $this->iFrameWeight = $aWeight; + } + + // Specify a background image blend + function SetBackgroundImageMix($aMix) { + $this->background_image_mix = $aMix ; + } + + // Specify a background image + function SetBackgroundImage($aFileName,$aCenter_aX=NULL,$aY=NULL) { + // Second argument can be either a boolean value or + // a numeric + $aCenter=TRUE; + $aX=NULL; + + if( $GLOBALS['gd2'] && !USE_TRUECOLOR ) { + JpGraphError::RaiseL(12001); +//("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x you must enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts."); + } + if( is_numeric($aCenter_aX) ) { + $aX=$aCenter_aX; + } + + // Get extension to determine image type + $e = explode('.',$aFileName); + if( !$e ) { + JpGraphError::RaiseL(12002,$aFileName); +//('Incorrect file name for MGraph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); + } + + $valid_formats = array('png', 'jpg', 'gif'); + $aImgFormat = strtolower($e[count($e)-1]); + if ($aImgFormat == 'jpeg') { + $aImgFormat = 'jpg'; + } + elseif (!in_array($aImgFormat, $valid_formats) ) { + JpGraphError::RaiseL(12003,$aImgFormat,$aFileName); +//('Unknown file extension ($aImgFormat) in MGraph::SetBackgroundImage() for filename: '.$aFileName); + } + + $this->background_image = $aFileName; + $this->background_image_center=$aCenter; + $this->background_image_format=$aImgFormat; + $this->background_image_x = $aX; + $this->background_image_y = $aY; + } + + + // Private helper function for backgound image + function _loadBkgImage($aFile='') { + if( $aFile == '' ) + $aFile = $this->background_image; + + // Remove case sensitivity and setup appropriate function to create image + // Get file extension. This should be the LAST '.' separated part of the filename + $e = explode('.',$aFile); + $ext = strtolower($e[count($e)-1]); + if ($ext == "jpeg") { + $ext = "jpg"; + } + + if( trim($ext) == '' ) + $ext = 'png'; // Assume PNG if no extension specified + + $supported = imagetypes(); + if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) || + ( $ext == 'gif' && !($supported & IMG_GIF) ) || + ( $ext == 'png' && !($supported & IMG_PNG) ) ) { + JpGraphError::RaiseL(12004,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. '); + } + + if( $ext == "jpg" || $ext == "jpeg") { + $f = "imagecreatefromjpeg"; + $ext = "jpg"; + } + else { + $f = "imagecreatefrom".$ext; + } + + $img = @$f($aFile); + if( !$img ) { + JpGraphError::RaiseL(12005,$aFile); +//(" Can't read background image: '".$aFile."'"); + } + return $img; + } + + function _strokeBackgroundImage() { + if( $this->background_image == '' ) + return; + + $bkgimg = $this->_loadBkgImage(); + // Background width & Heoght + $bw = imagesx($bkgimg); + $bh = imagesy($bkgimg); + // Canvas width and height + $cw = imagesx($this->img); + $ch = imagesy($this->img); + + if( $this->background_image_x === NULL || $this->background_image_y === NULL ) { + if( $this->background_image_center ) { + // Center original image in the plot area + $x = round($cw/2-$bw/2); $y = round($ch/2-$bh/2); + } + else { + // Just copy the image from left corner, no resizing + $x=0; $y=0; + } + } + else { + $x = $this->background_image_x; + $y = $this->background_image_y; + } + $this->_imageCp($bkgimg,$x,$y,0,0,$bw,$bh,$this->background_image_mix); + } + + function _imageCp($aSrcImg,$x,$y,$fx,$fy,$w,$h,$mix=100) { + imagecopymerge($this->img,$aSrcImg,$x,$y,$fx,$fy,$w,$h,$mix); + } + + function _imageCreate($aWidth,$aHeight) { + if( $aWidth <= 1 || $aHeight <= 1 ) { + JpGraphError::RaiseL(12006,$aWidth,$aHeight); +//("Illegal sizes specified for width or height when creating an image, (width=$aWidth, height=$aHeight)"); + } + if( @$GLOBALS['gd2']==true && USE_TRUECOLOR ) { + $this->img = @imagecreatetruecolor($aWidth, $aHeight); + if( $this->img < 1 ) { + JpGraphError::RaiseL(12011); +// die("JpGraph Error: Can't create truecolor image. Check that you really have GD2 library installed."); + } + ImageAlphaBlending($this->img,true); + } else { + $this->img = @imagecreate($aWidth, $aHeight); + if( $this->img < 1 ) { + JpGraphError::RaiseL(12012); +// die("JpGraph Error: Can't create image. Check that you really have the GD library installed."); + } + } + } + + function _polygon($p,$closed=FALSE) { + if( $this->iLineWeight==0 ) return; + $n=count($p); + $oldx = $p[0]; + $oldy = $p[1]; + for( $i=2; $i < $n; $i+=2 ) { + imageline($this->img,$oldx,$oldy,$p[$i],$p[$i+1],$this->iCurrentColor); + $oldx = $p[$i]; + $oldy = $p[$i+1]; + } + if( $closed ) { + imageline($this->img,$p[$n*2-2],$p[$n*2-1],$p[0],$p[1],$this->iCurrentColor); + } + } + + function _filledPolygon($pts) { + $n=count($pts); + for($i=0; $i < $n; ++$i) + $pts[$i] = round($pts[$i]); + imagefilledpolygon($this->img,$pts,count($pts)/2,$this->iCurrentColor); + } + + function _rectangle($xl,$yu,$xr,$yl) { + for($i=0; $i < $this->iLineWeight; ++$i ) + $this->_polygon(array($xl+$i,$yu+$i,$xr-$i,$yu+$i, + $xr-$i,$yl-$i,$xl+$i,$yl-$i, + $xl+$i,$yu+$i)); + } + + function _filledRectangle($xl,$yu,$xr,$yl) { + $this->_filledPolygon(array($xl,$yu,$xr,$yu,$xr,$yl,$xl,$yl)); + } + + function _setColor($aColor) { + $this->iCurrentColor = $this->iRGB->Allocate($aColor); + } + + function AddMix($aGraph,$x=0,$y=0,$mix=100,$fx=0,$fy=0,$w=0,$h=0) { + $this->_gdImgHandle($aGraph->Stroke( _IMG_HANDLER),$x,$y,$fx=0,$fy=0,$w,$h,$mix); + } + + function Add($aGraph,$x=0,$y=0,$fx=0,$fy=0,$w=0,$h=0) { + $this->_gdImgHandle($aGraph->Stroke( _IMG_HANDLER),$x,$y,$fx=0,$fy=0,$w,$h); + } + + function _gdImgHandle($agdCanvas,$x,$y,$fx=0,$fy=0,$w=0,$h=0,$mix=100) { + if( $w == 0 ) $w = @imagesx($agdCanvas); + if( $w === NULL ) { + JpGraphError::RaiseL(12007); +//('Argument to MGraph::Add() is not a valid GD image handle.'); + return; + } + if( $h == 0 ) $h = @imagesy($agdCanvas); + $this->iGraphs[$this->iCnt++] = array($agdCanvas,$x,$y,$fx,$fy,$w,$h,$mix); + } + + function SetMargin($lm,$rm,$tm,$bm) { + $this->lm = $lm; + $this->rm = $rm; + $this->tm = $tm; + $this->bm = $bm; + } + + function SetExpired($aFlg=true) { + $this->expired = $aFlg; + } + + // Generate image header + function Headers() { + + // In case we are running from the command line with the client version of + // PHP we can't send any headers. + $sapi = php_sapi_name(); + if( $sapi == 'cli' ) + return; + + if( headers_sent() ) { + + echo "
    JpGraph Error: +HTTP headers have already been sent.
    Explanation:
    HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it's image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).

    Most likely you have some text in your script before the call to Graph::Stroke(). If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser.

    For example it is a common mistake to leave a blank line before the opening \"<?php\".

    "; + + die(); + + } + + if ($this->expired) { + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); + header("Last-Modified: " . gmdate("D, d M Y H:i:s") . "GMT"); + header("Cache-Control: no-cache, must-revalidate"); + header("Pragma: no-cache"); + } + header("Content-type: image/$this->img_format"); + } + + function SetImgFormat($aFormat,$aQuality=75) { + $this->image_quality = $aQuality; + $aFormat = strtolower($aFormat); + $tst = true; + $supported = imagetypes(); + if( $aFormat=="auto" ) { + if( $supported & IMG_PNG ) + $this->img_format="png"; + elseif( $supported & IMG_JPG ) + $this->img_format="jpeg"; + elseif( $supported & IMG_GIF ) + $this->img_format="gif"; + else + JpGraphError::RaiseL(12008); +//(" Your PHP (and GD-lib) installation does not appear to support any known graphic formats.". + return true; + } + else { + if( $aFormat=="jpeg" || $aFormat=="png" || $aFormat=="gif" ) { + if( $aFormat=="jpeg" && !($supported & IMG_JPG) ) + $tst=false; + elseif( $aFormat=="png" && !($supported & IMG_PNG) ) + $tst=false; + elseif( $aFormat=="gif" && !($supported & IMG_GIF) ) + $tst=false; + else { + $this->img_format=$aFormat; + return true; + } + } + else + $tst=false; + if( !$tst ) + JpGraphError::RaiseL(12009,$aFormat); +//(" Your PHP installation does not support the chosen graphic format: $aFormat"); + } + } + + // Stream image to browser or to file + function Stream($aFile="") { + $func="image".$this->img_format; + if( $this->img_format=="jpeg" && $this->image_quality != null ) { + $res = @$func($this->img,$aFile,$this->image_quality); + } + else { + if( $aFile != "" ) { + $res = @$func($this->img,$aFile); + } + else + $res = @$func($this->img); + } + if( !$res ) + JpGraphError::RaiseL(12010,$aFile); +//("Can't create or stream image to file $aFile Check that PHP has enough permission to write a file to the current directory."); + } + + function Stroke($aFileName='') { + // Find out the necessary size for the container image + $w=0; $h=0; + for($i=0; $i < $this->iCnt; ++$i ) { + $maxw = $this->iGraphs[$i][1]+$this->iGraphs[$i][5]; + $maxh = $this->iGraphs[$i][2]+$this->iGraphs[$i][6]; + $w = max( $w, $maxw ); + $h = max( $h, $maxh ); + } + $w += $this->lm+$this->rm; + $h += $this->tm+$this->bm; + + // User specified width,height overrides + if( $this->iWidth !== NULL ) $w = $this->iWidth; + if( $this->iHeight!== NULL ) $h = $this->iHeight; + + $this->_imageCreate($w,$h); + $this->iRGB = new RGB($this->img); + + $this->_setcolor($this->iFillColor); + $this->_filledRectangle(0,0,$w-1,$h-1); + + $this->_strokeBackgroundImage(); + + if( $this->iDoFrame ) { + $this->_setColor($this->iFrameColor); + $this->iLineWeight=$this->iFrameWeight; + $this->_rectangle(0,0,$w-1,$h-1); + } + + // Copy all sub graphs to the container + for($i=0; $i < $this->iCnt; ++$i ) { + $this->_imageCp($this->iGraphs[$i][0], + $this->iGraphs[$i][1]+$this->lm,$this->iGraphs[$i][2]+$this->tm, + $this->iGraphs[$i][3],$this->iGraphs[$i][4], + $this->iGraphs[$i][5],$this->iGraphs[$i][6], + $this->iGraphs[$i][7]); + } + + // Output image + if( $aFileName == _IMG_HANDLER ) { + return $this->img; + } + else { + $this->Headers(); + $this->Stream($aFileName); + } + } +} + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie.php new file mode 100644 index 0000000..357a405 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie.php @@ -0,0 +1,1372 @@ + array(136,34,40,45,46,62,63,134,74,10,120,136,141,168,180,77,209,218,346,395,89,430), + "pastel" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38), + "water" => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388), + "sand" => array(27,168,34,170,19,50,65,72,131,209,46,393)); + protected $theme="earth"; + protected $setslicecolors=array(); + protected $labeltype=0; // Default to percentage + protected $pie_border=true,$pie_interior_border=true; + public $value; + protected $ishadowcolor='',$ishadowdrop=4; + protected $ilabelposadj=1; + protected $legendcsimtargets = array(),$legendcsimwintargets = array(); + protected $legendcsimalts = array(); + protected $adjusted_data = array(); + public $guideline = null; + protected $guidelinemargin=10,$iShowGuideLineForSingle = false; + protected $iGuideLineCurve = false,$iGuideVFactor=1.4,$iGuideLineRFactor=0.8; + protected $la = array(); // Holds the exact angle for each label + +//--------------- +// CONSTRUCTOR + function PiePlot($data) { + $this->data = array_reverse($data); + $this->title = new Text(""); + $this->title->SetFont(FF_FONT1,FS_BOLD); + $this->value = new DisplayValue(); + $this->value->Show(); + $this->value->SetFormat('%.1f%%'); + $this->guideline = new LineProperty(); + } + +//--------------- +// PUBLIC METHODS + function SetCenter($x,$y=0.5) { + $this->posx = $x; + $this->posy = $y; + } + + // Enable guideline and set drwaing policy + function SetGuideLines($aFlg=true,$aCurved=true,$aAlways=false) { + $this->guideline->Show($aFlg); + $this->iShowGuideLineForSingle = $aAlways; + $this->iGuideLineCurve = $aCurved; + } + + // Adjuste the distance between labels and labels and pie + function SetGuideLinesAdjust($aVFactor,$aRFactor=0.8) { + $this->iGuideVFactor=$aVFactor; + $this->iGuideLineRFactor=$aRFactor; + } + + function SetColor($aColor) { + $this->color = $aColor; + } + + function SetSliceColors($aColors) { + $this->setslicecolors = $aColors; + } + + function SetShadow($aColor='darkgray',$aDropWidth=4) { + $this->ishadowcolor = $aColor; + $this->ishadowdrop = $aDropWidth; + } + + function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { + $this->csimtargets=array_reverse($aTargets); + if( is_array($aWinTargets) ) + $this->csimwintargets=array_reverse($aWinTargets); + if( is_array($aAlts) ) + $this->csimalts=array_reverse($aAlts); + } + + function GetCSIMareas() { + return $this->csimareas; + } + + function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { + //Slice number, ellipse centre (x,y), height, width, start angle, end angle + while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI; + while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI; + + $sa = 2*M_PI - $sa; + $ea = 2*M_PI - $ea; + + // Special case when we have only one slice since then both start and end + // angle will be == 0 + if( abs($sa - $ea) < 0.0001 ) { + $sa=2*M_PI; $ea=0; + } + + //add coordinates of the centre to the map + $xc = floor($xc);$yc=floor($yc); + $coords = "$xc, $yc"; + + //add coordinates of the first point on the arc to the map + $xp = floor(($radius*cos($ea))+$xc); + $yp = floor($yc-$radius*sin($ea)); + $coords.= ", $xp, $yp"; + + //add coordinates every 0.2 radians + $a=$ea+0.2; + + // If we cross the 360-limit with a slice we need to handle + // the fact that end angle is smaller than start + if( $sa < $ea ) { + while ($a <= 2*M_PI) { + $xp = floor($radius*cos($a)+$xc); + $yp = floor($yc-$radius*sin($a)); + $coords.= ", $xp, $yp"; + $a += 0.2; + } + $a -= 2*M_PI; + } + + + while ($a < $sa) { + $xp = floor($radius*cos($a)+$xc); + $yp = floor($yc-$radius*sin($a)); + $coords.= ", $xp, $yp"; + $a += 0.2; + } + + //Add the last point on the arc + $xp = floor($radius*cos($sa)+$xc); + $yp = floor($yc-$radius*sin($sa)); + $coords.= ", $xp, $yp"; + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas .= "csimtargets[$i]."\""; + $tmp=""; + if( !empty($this->csimwintargets[$i]) ) { + $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; + } + if( !empty($this->csimalts[$i]) ) { + $tmp=sprintf($this->csimalts[$i],$this->data[$i]); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + } + + + function SetTheme($aTheme) { + if( in_array($aTheme,array_keys($this->themearr)) ) + $this->theme = $aTheme; + else + JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme"); + } + + function ExplodeSlice($e,$radius=20) { + if( ! is_integer($e) ) + JpGraphError::RaiseL(15002);//('Argument to PiePlot::ExplodeSlice() must be an integer'); + $this->explode_radius[$e]=$radius; + } + + function ExplodeAll($radius=20) { + $this->explode_all=true; + $this->explode_r = $radius; + } + + function Explode($aExplodeArr) { + if( !is_array($aExplodeArr) ) { + JpGraphError::RaiseL(15003); +//("Argument to PiePlot::Explode() must be an array with integer distances."); + } + $this->explode_radius = $aExplodeArr; + } + + function SetStartAngle($aStart) { + if( $aStart < 0 || $aStart > 360 ) { + JpGraphError::RaiseL(15004);//('Slice start angle must be between 0 and 360 degrees.'); + } + $this->startangle = 360-$aStart; + $this->startangle *= M_PI/180; + } + + function SetFont($family,$style=FS_NORMAL,$size=10) { + JpGraphError::RaiseL(15005);//('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.'); + } + + // Size in percentage + function SetSize($aSize) { + if( ($aSize>0 && $aSize<=0.5) || ($aSize>10 && $aSize<1000) ) + $this->radius = $aSize; + else + JpGraphError::RaiseL(15006); +//("PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]"); + } + + function SetFontColor($aColor) { + JpGraphError::RaiseL(15007); +//('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.'); + } + + // Set label arrays + function SetLegends($aLegend) { + $this->legends = $aLegend; + } + + // Set text labels for slices + function SetLabels($aLabels,$aLblPosAdj="auto") { + $this->labels = array_reverse($aLabels); + $this->ilabelposadj=$aLblPosAdj; + } + + function SetLabelPos($aLblPosAdj) { + $this->ilabelposadj=$aLblPosAdj; + } + + // Should we display actual value or percentage? + function SetLabelType($t) { + if( $t < 0 || $t > 2 ) + JpGraphError::RaiseL(15008,$t); +//("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t)."); + $this->labeltype=$t; + } + + // Deprecated. + function SetValueType($aType) { + $this->SetLabelType($aType); + } + + // Should the circle around a pie plot be displayed + function ShowBorder($exterior=true,$interior=true) { + $this->pie_border = $exterior; + $this->pie_interior_border = $interior; + } + + // Setup the legends + function Legend($graph) { + $colors = array_keys($graph->img->rgb->rgb_table); + sort($colors); + $ta=$this->themearr[$this->theme]; + $n = count($this->data); + + if( $this->setslicecolors==null ) { + $numcolors=count($ta); + if( class_exists('PiePlot3D',false) && ($this instanceof PiePlot3D) ) { + $ta = array_reverse(array_slice($ta,0,$n)); + } + } + else { + $this->setslicecolors = array_slice($this->setslicecolors,0,$n); + $numcolors=count($this->setslicecolors); + if( $graph->pieaa && !($this instanceof PiePlot3D) ) { + $this->setslicecolors = array_reverse($this->setslicecolors); + } + } + + $sum=0; + for($i=0; $i < $n; ++$i) + $sum += $this->data[$i]; + + // Bail out with error if the sum is 0 + if( $sum==0 ) + JpGraphError::RaiseL(15009);//("Illegal pie plot. Sum of all data is zero for Pie!"); + + // Make sure we don't plot more values than data points + // (in case the user added more legends than data points) + $n = min(count($this->legends),count($this->data)); + if( $this->legends != "" ) { + $this->legends = array_reverse(array_slice($this->legends,0,$n)); + } + for( $i=$n-1; $i >= 0; --$i ) { + $l = $this->legends[$i]; + // Replace possible format with actual values + if( count($this->csimalts) > $i ) { + $fmt = $this->csimalts[$i]; + } + else { + $fmt = "%d"; // Deafult Alt if no other has been specified + } + if( $this->labeltype==0 ) { + $l = sprintf($l,100*$this->data[$i]/$sum); + $alt = sprintf($fmt,$this->data[$i]); + + } + elseif( $this->labeltype == 1) { + $l = sprintf($l,$this->data[$i]); + $alt = sprintf($fmt,$this->data[$i]); + + } + else { + $l = sprintf($l,$this->adjusted_data[$i]); + $alt = sprintf($fmt,$this->adjusted_data[$i]); + } + + if( empty($this->csimwintargets[$i]) ) { + $wintarg = ''; + } + else { + $wintarg = $this->csimwintargets[$i]; + } + + if( $this->setslicecolors==null ) { + $graph->legend->Add($l,$colors[$ta[$i%$numcolors]],"",0,$this->csimtargets[$i],$alt,$wintarg); + } + else { + $graph->legend->Add($l,$this->setslicecolors[$i%$numcolors],"",0,$this->csimtargets[$i],$alt,$wintarg); + } + } + } + + // Adjust the rounded percetage value so that the sum of + // of the pie slices are always 100% + // Using the Hare/Niemeyer method + function AdjPercentage($aData,$aPrec=0) { + $mul=100; + if( $aPrec > 0 && $aPrec < 3 ) { + if( $aPrec == 1 ) + $mul=1000; + else + $mul=10000; + } + + $tmp = array(); + $result = array(); + $quote_sum=0; + $n = count($aData) ; + for( $i=0, $sum=0; $i < $n; ++$i ) + $sum+=$aData[$i]; + foreach($aData as $index => $value) { + $tmp_percentage=$value/$sum*$mul; + $result[$index]=floor($tmp_percentage); + $tmp[$index]=$tmp_percentage-$result[$index]; + $quote_sum+=$result[$index]; + } + if( $quote_sum == $mul) { + if( $mul > 100 ) { + $tmp = $mul / 100; + for( $i=0; $i < $n; ++$i ) { + $result[$i] /= $tmp ; + } + } + return $result; + } + arsort($tmp,SORT_NUMERIC); + reset($tmp); + for($i=0; $i < $mul-$quote_sum; $i++) + { + $result[key($tmp)]++; + next($tmp); + } + if( $mul > 100 ) { + $tmp = $mul / 100; + for( $i=0; $i < $n; ++$i ) { + $result[$i] /= $tmp ; + } + } + return $result; + } + + + function Stroke($img,$aaoption=0) { + // aaoption is used to handle antialias + // aaoption == 0 a normal pie + // aaoption == 1 just the body + // aaoption == 2 just the values + + // Explode scaling. If anti anti alias we scale the image + // twice and we also need to scale the exploding distance + $expscale = $aaoption === 1 ? 2 : 1; + + if( $this->labeltype == 2 ) { + // Adjust the data so that it will add up to 100% + $this->adjusted_data = $this->AdjPercentage($this->data); + } + + $colors = array_keys($img->rgb->rgb_table); + sort($colors); + $ta=$this->themearr[$this->theme]; + $n = count($this->data); + + if( $this->setslicecolors==null ) { + $numcolors=count($ta); + } + else { + // We need to create an array of colors as long as the data + // since we need to reverse it to get the colors in the right order + $numcolors=count($this->setslicecolors); + $i = 2*$numcolors; + while( $n > $i ) { + $this->setslicecolors = array_merge($this->setslicecolors,$this->setslicecolors); + $i += $n; + } + $tt = array_slice($this->setslicecolors,0,$n % $numcolors); + $this->setslicecolors = array_merge($this->setslicecolors,$tt); + $this->setslicecolors = array_reverse($this->setslicecolors); + } + + // Draw the slices + $sum=0; + for($i=0; $i < $n; ++$i) + $sum += $this->data[$i]; + + // Bail out with error if the sum is 0 + if( $sum==0 ) + JpGraphError::RaiseL(15009);//("Sum of all data is 0 for Pie."); + + // Set up the pie-circle + if( $this->radius <= 1 ) + $radius = floor($this->radius*min($img->width,$img->height)); + else { + $radius = $aaoption === 1 ? $this->radius*2 : $this->radius; + } + + if( $this->posx <= 1 && $this->posx > 0 ) + $xc = round($this->posx*$img->width); + else + $xc = $this->posx ; + + if( $this->posy <= 1 && $this->posy > 0 ) + $yc = round($this->posy*$img->height); + else + $yc = $this->posy ; + + $n = count($this->data); + + if( $this->explode_all ) + for($i=0; $i < $n; ++$i) + $this->explode_radius[$i]=$this->explode_r; + + if( $this->ishadowcolor != "" && $aaoption !== 2) { + $accsum=0; + $angle2 = $this->startangle; + $img->SetColor($this->ishadowcolor); + for($i=0; $sum > 0 && $i < $n; ++$i) { + $j = $n-$i-1; + $d = $this->data[$i]; + $angle1 = $angle2; + $accsum += $d; + $angle2 = $this->startangle+2*M_PI*$accsum/$sum; + if( empty($this->explode_radius[$j]) ) + $this->explode_radius[$j]=0; + + $la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1); + + $xcm = $xc + $this->explode_radius[$j]*cos($la)*$expscale; + $ycm = $yc - $this->explode_radius[$j]*sin($la)*$expscale; + + $xcm += $this->ishadowdrop*$expscale; + $ycm += $this->ishadowdrop*$expscale; + + $img->CakeSlice($xcm,$ycm,$radius,$radius, + $angle1*180/M_PI,$angle2*180/M_PI,$this->ishadowcolor); + + } + } + + $accsum=0; + $angle2 = $this->startangle; + $img->SetColor($this->color); + for($i=0; $sum>0 && $i < $n; ++$i) { + $j = $n-$i-1; + if( empty($this->explode_radius[$j]) ) + $this->explode_radius[$j]=0; + $d = $this->data[$i]; + $angle1 = $angle2; + $accsum += $d; + $angle2 = $this->startangle+2*M_PI*$accsum/$sum; + $this->la[$i] = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1); + + if( $d == 0 ) continue; + + if( $this->setslicecolors==null ) + $slicecolor=$colors[$ta[$i%$numcolors]]; + else + $slicecolor=$this->setslicecolors[$i%$numcolors]; + + if( $this->pie_interior_border && $aaoption===0 ) + $img->SetColor($this->color); + else + $img->SetColor($slicecolor); + + $arccolor = $this->pie_border && $aaoption===0 ? $this->color : ""; + + $xcm = $xc + $this->explode_radius[$j]*cos($this->la[$i])*$expscale; + $ycm = $yc - $this->explode_radius[$j]*sin($this->la[$i])*$expscale; + + if( $aaoption !== 2 ) { + $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1, + $angle1*180/M_PI,$angle2*180/M_PI,$slicecolor,$arccolor); + } + + if( $this->csimtargets && $aaoption !== 1 ) { + $this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2); + } + } + + // Format the titles for each slice + if( $aaoption !== 2 ) { + for( $i=0; $i < $n; ++$i) { + if( $this->labeltype==0 ) { + if( $sum != 0 ) + $l = 100.0*$this->data[$i]/$sum; + else + $l = 0.0; + } + elseif( $this->labeltype==1 ) { + $l = $this->data[$i]*1.0; + } + else { + $l = $this->adjusted_data[$i]; + } + if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) + $this->labels[$i]=sprintf($this->labels[$i],$l); + else + $this->labels[$i]=$l; + } + } + + if( $this->value->show && $aaoption !== 1 ) { + $this->StrokeAllLabels($img,$xc,$yc,$radius); + } + + // Adjust title position + if( $aaoption !== 1 ) { + $this->title->SetPos($xc, + $yc-$this->title->GetFontHeight($img)-$radius-$this->title->margin, + "center","bottom"); + $this->title->Stroke($img); + } + + } + +//--------------- +// PRIVATE METHODS + + function NormAngle($a) { + while( $a < 0 ) $a += 2*M_PI; + while( $a > 2*M_PI ) $a -= 2*M_PI; + return $a; + } + + function Quadrant($a) { + $a=$this->NormAngle($a); + if( $a > 0 && $a <= M_PI/2 ) + return 0; + if( $a > M_PI/2 && $a <= M_PI ) + return 1; + if( $a > M_PI && $a <= 1.5*M_PI ) + return 2; + if( $a > 1.5*M_PI ) + return 3; + } + + function StrokeGuideLabels($img,$xc,$yc,$radius) { + $n = count($this->labels); + + //----------------------------------------------------------------------- + // Step 1 of the algorithm is to construct a number of clusters + // a cluster is defined as all slices within the same quadrant (almost) + // that has an angualr distance less than the treshold + //----------------------------------------------------------------------- + $tresh_hold=25 * M_PI/180; // 25 degrees difference to be in a cluster + $incluster=false; // flag if we are currently in a cluster or not + $clusters = array(); // array of clusters + $cidx=-1; // running cluster index + + // Go through all the labels and construct a number of clusters + for($i=0; $i < $n-1; ++$i) { + // Calc the angle distance between two consecutive slices + $a1=$this->la[$i]; + $a2=$this->la[$i+1]; + $q1 = $this->Quadrant($a1); + $q2 = $this->Quadrant($a2); + $diff = abs($a1-$a2); + if( $diff < $tresh_hold ) { + if( $incluster ) { + $clusters[$cidx][1]++; + // Each cluster can only cover one quadrant + // Do we cross a quadrant ( and must break the cluster) + if( $q1 != $q2 ) { + // If we cross a quadrant boundary we normally start a + // new cluster. However we need to take the 12'a clock + // and 6'a clock positions into a special consideration. + // Case 1: WE go from q=1 to q=2 if the last slice on + // the cluster for q=1 is close to 12'a clock and the + // first slice in q=0 is small we extend the previous + // cluster + if( $q1 == 1 && $q2 == 0 && $a2 > (90-15)*M_PI/180 ) { + if( $i < $n-2 ) { + $a3 = $this->la[$i+2]; + // If there isn't a cluster coming up with the next-next slice + // we extend the previous cluster to cover this slice as well + if( abs($a3-$a2) >= $tresh_hold ) { + $clusters[$cidx][1]++; + $i++; + } + } + } + elseif( $q1 == 3 && $q2 == 2 && $a2 > (270-15)*M_PI/180 ) { + if( $i < $n-2 ) { + $a3 = $this->la[$i+2]; + // If there isn't a cluster coming up with the next-next slice + // we extend the previous cluster to cover this slice as well + if( abs($a3-$a2) >= $tresh_hold ) { + $clusters[$cidx][1]++; + $i++; + } + } + } + + if( $q1==2 && $q2==1 && $a2 > (180-15)*M_PI/180 ) { + $clusters[$cidx][1]++; + $i++; + } + + $incluster = false; + } + } + elseif( $q1 == $q2) { + $incluster = true; + // Now we have a special case for quadrant 0. If we previously + // have a cluster of one in quadrant 0 we just extend that + // cluster. If we don't do this then we risk that the label + // for the cluster of one will cross the guide-line + if( $q1 == 0 && $cidx > -1 && + $clusters[$cidx][1] == 1 && + $this->Quadrant($this->la[$clusters[$cidx][0]]) == 0 ) { + $clusters[$cidx][1]++; + } + else { + $cidx++; + $clusters[$cidx][0] = $i; + $clusters[$cidx][1] = 1; + } + } + else { + // Create a "cluster" of one since we are just crossing + // a quadrant + $cidx++; + $clusters[$cidx][0] = $i; + $clusters[$cidx][1] = 1; + } + } + else { + if( $incluster ) { + // Add the last slice + $clusters[$cidx][1]++; + $incluster = false; + } + else { // Create a "cluster" of one + $cidx++; + $clusters[$cidx][0] = $i; + $clusters[$cidx][1] = 1; + } + } + } + // Handle the very last slice + if( $incluster ) { + $clusters[$cidx][1]++; + } + else { // Create a "cluster" of one + $cidx++; + $clusters[$cidx][0] = $i; + $clusters[$cidx][1] = 1; + } + + /* + if( true ) { + // Debug printout in labels + for( $i=0; $i <= $cidx; ++$i ) { + for( $j=0; $j < $clusters[$i][1]; ++$j ) { + $a = $this->la[$clusters[$i][0]+$j]; + $aa = round($a*180/M_PI); + $q = $this->Quadrant($a); + $this->labels[$clusters[$i][0]+$j]="[$q:$aa] $i:$j"; + } + } + } + */ + + //----------------------------------------------------------------------- + // Step 2 of the algorithm is use the clusters and draw the labels + // and guidelines + //----------------------------------------------------------------------- + + // We use the font height as the base factor for how far we need to + // spread the labels in the Y-direction. + $this->value->ApplyFont($img); + $fh = $img->GetFontHeight(); + $origvstep=$fh*$this->iGuideVFactor; + $this->value->SetMargin(0); + + // Number of clusters found + $nc = count($clusters); + + // Walk through all the clusters + for($i=0; $i < $nc; ++$i) { + + // Start angle and number of slices in this cluster + $csize = $clusters[$i][1]; + $a = $this->la[$clusters[$i][0]]; + $q = $this->Quadrant($a); + + // Now set up the start and end conditions to make sure that + // in each cluster we walk through the all the slices starting with the slice + // closest to the equator. Since all slices are numbered clockwise from "3'a clock" + // we have different conditions depending on in which quadrant the slice lies within. + if( $q == 0 ) { + $start = $csize-1; $idx = $start; $step = -1; $vstep = -$origvstep; + } + elseif( $q == 1 ) { + $start = 0; $idx = $start; $step = 1; $vstep = -$origvstep; + } + elseif( $q == 2 ) { + $start = $csize-1; $idx = $start; $step = -1; $vstep = $origvstep; + } + elseif( $q == 3 ) { + $start = 0; $idx = $start; $step = 1; $vstep = $origvstep; + } + + // Walk through all slices within this cluster + for($j=0; $j < $csize; ++$j) { + // Now adjust the position of the labels in each cluster starting + // with the slice that is closest to the equator of the pie + $a = $this->la[$clusters[$i][0]+$idx]; + + // Guide line start in the center of the arc of the slice + $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)]; + $x = round($r*cos($a)+$xc); + $y = round($yc-$r*sin($a)); + + // The distance from the arc depends on chosen font and the "R-Factor" + $r += $fh*$this->iGuideLineRFactor; + + // Should the labels be placed curved along the pie or in straight columns + // outside the pie? + if( $this->iGuideLineCurve ) + $xt=round($r*cos($a)+$xc); + + // If this is the first slice in the cluster we need some first time + // proessing + if( $idx == $start ) { + if( ! $this->iGuideLineCurve ) + $xt=round($r*cos($a)+$xc); + $yt=round($yc-$r*sin($a)); + + // Some special consideration in case this cluster starts + // in quadrant 1 or 3 very close to the "equator" (< 20 degrees) + // and the previous clusters last slice is within the tolerance. + // In that case we add a font height to this labels Y-position + // so it doesn't collide with + // the slice in the previous cluster + $prevcluster = ($i + ($nc-1) ) % $nc; + $previdx=$clusters[$prevcluster][0]+$clusters[$prevcluster][1]-1; + if( $q == 1 && $a > 160*M_PI/180 ) { + // Get the angle for the previous clusters last slice + $diff = abs($a-$this->la[$previdx]); + if( $diff < $tresh_hold ) { + $yt -= $fh; + } + } + elseif( $q == 3 && $a > 340*M_PI/180 ) { + // We need to subtract 360 to compare angle distance between + // q=0 and q=3 + $diff = abs($a-$this->la[$previdx]-360*M_PI/180); + if( $diff < $tresh_hold ) { + $yt += $fh; + } + } + + } + else { + // The step is at minimum $vstep but if the slices are relatively large + // we make sure that we add at least a step that corresponds to the vertical + // distance between the centers at the arc on the slice + $prev_a = $this->la[$clusters[$i][0]+($idx-$step)]; + $dy = abs($radius*(sin($a)-sin($prev_a))*1.2); + if( $vstep > 0 ) + $yt += max($vstep,$dy); + else + $yt += min($vstep,-$dy); + } + + $label = $this->labels[$clusters[$i][0]+$idx]; + + if( $csize == 1 ) { + // A "meta" cluster with only one slice + $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)]; + $rr = $r+$img->GetFontHeight()/2; + $xt=round($rr*cos($a)+$xc); + $yt=round($yc-$rr*sin($a)); + $this->StrokeLabel($label,$img,$xc,$yc,$a,$r); + if( $this->iShowGuideLineForSingle ) + $this->guideline->Stroke($img,$x,$y,$xt,$yt); + } + else { + $this->guideline->Stroke($img,$x,$y,$xt,$yt); + if( $q==1 || $q==2 ) { + // Left side of Pie + $this->guideline->Stroke($img,$xt,$yt,$xt-$this->guidelinemargin,$yt); + $lbladj = -$this->guidelinemargin-5; + $this->value->halign = "right"; + $this->value->valign = "center"; + } + else { + // Right side of pie + $this->guideline->Stroke($img,$xt,$yt,$xt+$this->guidelinemargin,$yt); + $lbladj = $this->guidelinemargin+5; + $this->value->halign = "left"; + $this->value->valign = "center"; + } + $this->value->Stroke($img,$label,$xt+$lbladj,$yt); + } + + // Udate idx to point to next slice in the cluster to process + $idx += $step; + } + } + } + + function StrokeAllLabels($img,$xc,$yc,$radius) { + // First normalize all angles for labels + $n = count($this->la); + for($i=0; $i < $n; ++$i) { + $this->la[$i] = $this->NormAngle($this->la[$i]); + } + if( $this->guideline->iShow ) { + $this->StrokeGuideLabels($img,$xc,$yc,$radius); + } + else { + $n = count($this->labels); + for($i=0; $i < $n; ++$i) { + $this->StrokeLabel($this->labels[$i],$img,$xc,$yc, + $this->la[$i], + $radius + $this->explode_radius[$n-1-$i]); + } + } + } + + // Position the labels of each slice + function StrokeLabel($label,$img,$xc,$yc,$a,$r) { + + // Default value + if( $this->ilabelposadj === 'auto' ) + $this->ilabelposadj = 0.65; + + // We position the values diferently depending on if they are inside + // or outside the pie + if( $this->ilabelposadj < 1.0 ) { + + $this->value->SetAlign('center','center'); + $this->value->margin = 0; + + $xt=round($this->ilabelposadj*$r*cos($a)+$xc); + $yt=round($yc-$this->ilabelposadj*$r*sin($a)); + + $this->value->Stroke($img,$label,$xt,$yt); + } + else { + + $this->value->halign = "left"; + $this->value->valign = "top"; + $this->value->margin = 0; + + // Position the axis title. + // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text + // that intersects with the extension of the corresponding axis. The code looks a little + // bit messy but this is really the only way of having a reasonable position of the + // axis titles. + $this->value->ApplyFont($img); + $h=$img->GetTextHeight($label); + // For numeric values the format of the display value + // must be taken into account + if( is_numeric($label) ) { + if( $label > 0 ) + $w=$img->GetTextWidth(sprintf($this->value->format,$label)); + else + $w=$img->GetTextWidth(sprintf($this->value->negformat,$label)); + } + else + $w=$img->GetTextWidth($label); + + if( $this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) { + $r *= $this->ilabelposadj; + } + + $r += $img->GetFontHeight()/1.5; + + $xt=round($r*cos($a)+$xc); + $yt=round($yc-$r*sin($a)); + + // Normalize angle + while( $a < 0 ) $a += 2*M_PI; + while( $a > 2*M_PI ) $a -= 2*M_PI; + + if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); + + if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; + if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; + + $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h); + } + } +} // Class + + +//=================================================== +// CLASS PiePlotC +// Description: Same as a normal pie plot but with a +// filled circle in the center +//=================================================== +class PiePlotC extends PiePlot { + private $imidsize=0.5; // Fraction of total width + private $imidcolor='white'; + public $midtitle=''; + private $middlecsimtarget='',$middlecsimwintarget='',$middlecsimalt=''; + + function PiePlotC($data,$aCenterTitle='') { + parent::PiePlot($data); + $this->midtitle = new Text(); + $this->midtitle->ParagraphAlign('center'); + } + + function SetMid($aTitle,$aColor='white',$aSize=0.5) { + $this->midtitle->Set($aTitle); + + $this->imidsize = $aSize ; + $this->imidcolor = $aColor ; + } + + function SetMidTitle($aTitle) { + $this->midtitle->Set($aTitle); + } + + function SetMidSize($aSize) { + $this->imidsize = $aSize ; + } + + function SetMidColor($aColor) { + $this->imidcolor = $aColor ; + } + + function SetMidCSIM($aTarget,$aAlt='',$aWinTarget='') { + $this->middlecsimtarget = $aTarget; + $this->middlecsimwintarget = $aWinTarget; + $this->middlecsimalt = $aAlt; + } + + function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { + //Slice number, ellipse centre (x,y), radius, start angle, end angle + while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI; + while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI; + + $sa = 2*M_PI - $sa; + $ea = 2*M_PI - $ea; + + // Special case when we have only one slice since then both start and end + // angle will be == 0 + if( abs($sa - $ea) < 0.0001 ) { + $sa=2*M_PI; $ea=0; + } + + // Add inner circle first point + $xp = floor(($this->imidsize*$radius*cos($ea))+$xc); + $yp = floor($yc-($this->imidsize*$radius*sin($ea))); + $coords = "$xp, $yp"; + + //add coordinates every 0.25 radians + $a=$ea+0.25; + + // If we cross the 360-limit with a slice we need to handle + // the fact that end angle is smaller than start + if( $sa < $ea ) { + while ($a <= 2*M_PI) { + $xp = floor($radius*cos($a)+$xc); + $yp = floor($yc-$radius*sin($a)); + $coords.= ", $xp, $yp"; + $a += 0.25; + } + $a -= 2*M_PI; + } + + while ($a < $sa) { + $xp = floor(($this->imidsize*$radius*cos($a)+$xc)); + $yp = floor($yc-($this->imidsize*$radius*sin($a))); + $coords.= ", $xp, $yp"; + $a += 0.25; + } + + // Make sure we end at the last point + $xp = floor(($this->imidsize*$radius*cos($sa)+$xc)); + $yp = floor($yc-($this->imidsize*$radius*sin($sa))); + $coords.= ", $xp, $yp"; + + // Straight line to outer circle + $xp = floor($radius*cos($sa)+$xc); + $yp = floor($yc-$radius*sin($sa)); + $coords.= ", $xp, $yp"; + + //add coordinates every 0.25 radians + $a=$sa - 0.25; + while ($a > $ea) { + $xp = floor($radius*cos($a)+$xc); + $yp = floor($yc-$radius*sin($a)); + $coords.= ", $xp, $yp"; + $a -= 0.25; + } + + //Add the last point on the arc + $xp = floor($radius*cos($ea)+$xc); + $yp = floor($yc-$radius*sin($ea)); + $coords.= ", $xp, $yp"; + + // Close the arc + $xp = floor(($this->imidsize*$radius*cos($ea))+$xc); + $yp = floor($yc-($this->imidsize*$radius*sin($ea))); + $coords .= ", $xp, $yp"; + + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas .= "csimtargets[$i]."\""; + if( !empty($this->csimwintargets[$i]) ) { + $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; + } + if( !empty($this->csimalts[$i]) ) { + $tmp=sprintf($this->csimalts[$i],$this->data[$i]); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + } + + + function Stroke($img,$aaoption=0) { + + // Stroke the pie but don't stroke values + $tmp = $this->value->show; + $this->value->show = false; + parent::Stroke($img,$aaoption); + $this->value->show = $tmp; + + $xc = round($this->posx*$img->width); + $yc = round($this->posy*$img->height); + + $radius = floor($this->radius * min($img->width,$img->height)) ; + + + if( $this->imidsize > 0 && $aaoption !== 2 ) { + + if( $this->ishadowcolor != "" ) { + $img->SetColor($this->ishadowcolor); + $img->FilledCircle($xc+$this->ishadowdrop,$yc+$this->ishadowdrop, + round($radius*$this->imidsize)); + } + + $img->SetColor($this->imidcolor); + $img->FilledCircle($xc,$yc,round($radius*$this->imidsize)); + + if( $this->pie_border && $aaoption === 0 ) { + $img->SetColor($this->color); + $img->Circle($xc,$yc,round($radius*$this->imidsize)); + } + + if( !empty($this->middlecsimtarget) ) + $this->AddMiddleCSIM($xc,$yc,round($radius*$this->imidsize)); + + } + + if( $this->value->show && $aaoption !== 1) { + $this->StrokeAllLabels($img,$xc,$yc,$radius); + $this->midtitle->SetPos($xc,$yc,'center','center'); + $this->midtitle->Stroke($img); + } + + } + + function AddMiddleCSIM($xc,$yc,$r) { + $xc=round($xc);$yc=round($yc);$r=round($r); + $this->csimareas .= "middlecsimtarget."\""; + if( !empty($this->middlecsimwintarget) ) { + $this->csimareas .= " target=\"".$this->middlecsimwintarget."\""; + } + if( !empty($this->middlecsimalt) ) { + $tmp = $this->middlecsimalt; + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + + function StrokeLabel($label,$img,$xc,$yc,$a,$r) { + + if( $this->ilabelposadj === 'auto' ) + $this->ilabelposadj = (1-$this->imidsize)/2+$this->imidsize; + + parent::StrokeLabel($label,$img,$xc,$yc,$a,$r); + + } + +} + + +//=================================================== +// CLASS PieGraph +// Description: +//=================================================== +class PieGraph extends Graph { + private $posx, $posy, $radius; + private $legends=array(); + public $plots=array(); + public $pieaa = false ; +//--------------- +// CONSTRUCTOR + function PieGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { + $this->Graph($width,$height,$cachedName,$timeout,$inline); + $this->posx=$width/2; + $this->posy=$height/2; + $this->SetColor(array(255,255,255)); + } + +//--------------- +// PUBLIC METHODS + function Add($aObj) { + + if( is_array($aObj) && count($aObj) > 0 ) + $cl = $aObj[0]; + else + $cl = $aObj; + + if( $cl instanceof Text ) + $this->AddText($aObj); + elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) + $this->AddIcon($aObj); + else { + if( is_array($aObj) ) { + $n = count($aObj); + for($i=0; $i < $n; ++$i ) { + $this->plots[] = $aObj[$i]; + } + } + else { + $this->plots[] = $aObj; + } + } + } + + function SetAntiAliasing($aFlg=true) { + $this->pieaa = $aFlg; + } + + function SetColor($c) { + $this->SetMarginColor($c); + } + + + function DisplayCSIMAreas() { + $csim=""; + foreach($this->plots as $p ) { + $csim .= $p->GetCSIMareas(); + } + //$csim.= $this->legend->GetCSIMareas(); + if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { + $this->img->SetColor($this->csimcolor); + $n = count($coords[0]); + for ($i=0; $i < $n; $i++) { + if ($coords[1][$i]=="poly") { + preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); + $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); + $m = count($pts[0]); + for ($j=0; $j < $m; $j++) { + $this->img->LineTo($pts[1][$j],$pts[2][$j]); + } + } else if ($coords[1][$i]=="rect") { + $pts = preg_split('/,/', $coords[2][$i]); + $this->img->SetStartPoint($pts[0],$pts[1]); + $this->img->LineTo($pts[2],$pts[1]); + $this->img->LineTo($pts[2],$pts[3]); + $this->img->LineTo($pts[0],$pts[3]); + $this->img->LineTo($pts[0],$pts[1]); + + } + } + } + } + + // Method description + function Stroke($aStrokeFileName="") { + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + $n = count($this->plots); + + if( $this->pieaa ) { + + if( !$_csim ) { + if( $this->background_image != "" ) { + $this->StrokeFrameBackground(); + } + else { + $this->StrokeFrame(); + $this->StrokeBackgroundGrad(); + } + } + + + $w = $this->img->width; + $h = $this->img->height; + $oldimg = $this->img->img; + + $this->img->CreateImgCanvas(2*$w,2*$h); + + $this->img->SetColor( $this->margin_color ); + $this->img->FilledRectangle(0,0,2*$w-1,2*$h-1); + + // Make all icons *2 i size since we will be scaling down the + // imahe to do the anti aliasing + $ni = count($this->iIcons); + for($i=0; $i < $ni; ++$i) { + $this->iIcons[$i]->iScale *= 2 ; + if( $this->iIcons[$i]->iX > 1 ) + $this->iIcons[$i]->iX *= 2 ; + if( $this->iIcons[$i]->iY > 1 ) + $this->iIcons[$i]->iY *= 2 ; + } + + $this->StrokeIcons(); + + for($i=0; $i < $n; ++$i) { + if( $this->plots[$i]->posx > 1 ) + $this->plots[$i]->posx *= 2 ; + if( $this->plots[$i]->posy > 1 ) + $this->plots[$i]->posy *= 2 ; + + $this->plots[$i]->Stroke($this->img,1); + + if( $this->plots[$i]->posx > 1 ) + $this->plots[$i]->posx /= 2 ; + if( $this->plots[$i]->posy > 1 ) + $this->plots[$i]->posy /= 2 ; + } + + $indent = $this->doframe ? ($this->frame_weight + ($this->doshadow ? $this->shadow_width : 0 )) : 0 ; + $indent += $this->framebevel ? $this->framebeveldepth + 1 : 0 ; + $this->img->CopyCanvasH($oldimg,$this->img->img,$indent,$indent,$indent,$indent, + $w-2*$indent,$h-2*$indent,2*($w-$indent),2*($h-$indent)); + + $this->img->img = $oldimg ; + $this->img->width = $w ; + $this->img->height = $h ; + + for($i=0; $i < $n; ++$i) { + $this->plots[$i]->Stroke($this->img,2); // Stroke labels + $this->plots[$i]->Legend($this); + } + + } + else { + + if( !$_csim ) { + if( $this->background_image != "" ) { + $this->StrokeFrameBackground(); + } + else { + $this->StrokeFrame(); + } + } + + $this->StrokeIcons(); + + for($i=0; $i < $n; ++$i) { + $this->plots[$i]->Stroke($this->img); + $this->plots[$i]->Legend($this); + } + } + + $this->legend->Stroke($this->img); + $this->footer->Stroke($this->img); + $this->StrokeTitles(); + + if( !$_csim ) { + + // Stroke texts + if( $this->texts != null ) { + $n = count($this->texts); + for($i=0; $i < $n; ++$i ) { + $this->texts[$i]->Stroke($this->img); + } + } + + if( _JPG_DEBUG ) { + $this->DisplayCSIMAreas(); + } + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, + $aStrokeFileName); + } + } + } +} // Class + +/* EOF */ +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie3d.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie3d.php new file mode 100644 index 0000000..9b2012c --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_pie3d.php @@ -0,0 +1,923 @@ +radius = 0.5; + $this->data = $data; + $this->title = new Text(""); + $this->title->SetFont(FF_FONT1,FS_BOLD); + $this->value = new DisplayValue(); + $this->value->Show(); + $this->value->SetFormat('%.0f%%'); + } + +//--------------- +// PUBLIC METHODS + + // Set label arrays + function SetLegends($aLegend) { + $this->legends = array_reverse(array_slice($aLegend,0,count($this->data))); + } + + function SetSliceColors($aColors) { + $this->setslicecolors = $aColors; + } + + function Legend($aGraph) { + parent::Legend($aGraph); + $aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol); + } + + function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { + $this->csimtargets = $aTargets; + $this->csimwintargets = $aWinTargets; + $this->csimalts = $aAlts; + } + + // Should the slices be separated by a line? If color is specified as "" no line + // will be used to separate pie slices. + function SetEdge($aColor='black',$aWeight=1) { + $this->edgecolor = $aColor; + $this->edgeweight = $aWeight; + } + + // Dummy function to make Pie3D behave in a similair way to 2D + function ShowBorder($exterior=true,$interior=true) { + JpGraphError::RaiseL(14001); +//('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.'); + } + + // Specify projection angle for 3D in degrees + // Must be between 20 and 70 degrees + function SetAngle($a) { + if( $a<5 || $a>90 ) + JpGraphError::RaiseL(14002); +//("PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees."); + else + $this->angle = $a; + } + + function Add3DSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle + + $sa *= M_PI/180; + $ea *= M_PI/180; + + //add coordinates of the centre to the map + $coords = "$xc, $yc"; + + //add coordinates of the first point on the arc to the map + $xp = floor($width*cos($sa)/2+$xc); + $yp = floor($yc-$height*sin($sa)/2); + $coords.= ", $xp, $yp"; + + //If on the front half, add the thickness offset + if ($sa >= M_PI && $sa <= 2*M_PI*1.01) { + $yp = floor($yp+$thick); + $coords.= ", $xp, $yp"; + } + + //add coordinates every 0.2 radians + $a=$sa+0.2; + while ($a<$ea) { + $xp = floor($width*cos($a)/2+$xc); + if ($a >= M_PI && $a <= 2*M_PI*1.01) { + $yp = floor($yc-($height*sin($a)/2)+$thick); + } else { + $yp = floor($yc-$height*sin($a)/2); + } + $coords.= ", $xp, $yp"; + $a += 0.2; + } + + //Add the last point on the arc + $xp = floor($width*cos($ea)/2+$xc); + $yp = floor($yc-$height*sin($ea)/2); + + + if ($ea >= M_PI && $ea <= 2*M_PI*1.01) { + $coords.= ", $xp, ".floor($yp+$thick); + } + $coords.= ", $xp, $yp"; + $alt=''; + + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas .= "csimtargets[$i]."\""; + + if( !empty($this->csimwintargets[$i]) ) { + $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" "; + } + + if( !empty($this->csimalts[$i]) ) { + $tmp=sprintf($this->csimalts[$i],$this->data[$i]); + $this->csimareas .= "alt=\"$tmp\" title=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + + } + + function SetLabels($aLabels,$aLblPosAdj="auto") { + $this->labels = $aLabels; + $this->ilabelposadj=$aLblPosAdj; + } + + + // Distance from the pie to the labels + function SetLabelMargin($m) { + $this->value->SetMargin($m); + } + + // Show a thin line from the pie to the label for a specific slice + function ShowLabelHint($f=true) { + $this->showlabelhint=$f; + } + + // Set color of hint line to label for each slice + function SetLabelHintColor($c) { + $this->labelhintcolor=$c; + } + + function SetHeight($aHeight) { + $this->iThickness = $aHeight; + } + + +// Normalize Angle between 0-360 + function NormAngle($a) { + // Normalize anle to 0 to 2M_PI + // + if( $a > 0 ) { + while($a > 360) $a -= 360; + } + else { + while($a < 0) $a += 360; + } + if( $a < 0 ) + $a = 360 + $a; + + if( $a == 360 ) $a=0; + return $a; + } + + + +// Draw one 3D pie slice at position ($xc,$yc) with height $z + function Pie3DSlice($img,$xc,$yc,$w,$h,$sa,$ea,$z,$fillcolor,$shadow=0.65) { + + // Due to the way the 3D Pie algorithm works we are + // guaranteed that any slice we get into this method + // belongs to either the left or right side of the + // pie ellipse. Hence, no slice will cross 90 or 270 + // point. + if( ($sa < 90 && $ea > 90) || ( ($sa > 90 && $sa < 270) && $ea > 270) ) { + JpGraphError::RaiseL(14003);//('Internal assertion failed. Pie3D::Pie3DSlice'); + exit(1); + } + + $p[] = array(); + + // Setup pre-calculated values + $rsa = $sa/180*M_PI; // to Rad + $rea = $ea/180*M_PI; // to Rad + $sinsa = sin($rsa); + $cossa = cos($rsa); + $sinea = sin($rea); + $cosea = cos($rea); + + // p[] is the points for the overall slice and + // pt[] is the points for the top pie + + // Angular step when approximating the arc with a polygon train. + $step = 0.05; + + if( $sa >= 270 ) { + if( $ea > 360 || ($ea > 0 && $ea <= 90) ) { + if( $ea > 0 && $ea <= 90 ) { + // Adjust angle to simplify conditions in loops + $rea += 2*M_PI; + } + + $p = array($xc,$yc,$xc,$yc+$z, + $xc+$w*$cossa,$z+$yc-$h*$sinsa); + $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); + + for( $a=$rsa; $a < 2*M_PI; $a += $step ) { + $tca = cos($a); + $tsa = sin($a); + $p[] = $xc+$w*$tca; + $p[] = $z+$yc-$h*$tsa; + $pt[] = $xc+$w*$tca; + $pt[] = $yc-$h*$tsa; + } + + $pt[] = $xc+$w; + $pt[] = $yc; + + $p[] = $xc+$w; + $p[] = $z+$yc; + $p[] = $xc+$w; + $p[] = $yc; + $p[] = $xc; + $p[] = $yc; + + for( $a=2*M_PI+$step; $a < $rea; $a += $step ) { + $pt[] = $xc + $w*cos($a); + $pt[] = $yc - $h*sin($a); + } + + $pt[] = $xc+$w*$cosea; + $pt[] = $yc-$h*$sinea; + $pt[] = $xc; + $pt[] = $yc; + + } + else { + $p = array($xc,$yc,$xc,$yc+$z, + $xc+$w*$cossa,$z+$yc-$h*$sinsa); + $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); + + $rea = $rea == 0.0 ? 2*M_PI : $rea; + for( $a=$rsa; $a < $rea; $a += $step ) { + $tca = cos($a); + $tsa = sin($a); + $p[] = $xc+$w*$tca; + $p[] = $z+$yc-$h*$tsa; + $pt[] = $xc+$w*$tca; + $pt[] = $yc-$h*$tsa; + } + + $pt[] = $xc+$w*$cosea; + $pt[] = $yc-$h*$sinea; + $pt[] = $xc; + $pt[] = $yc; + + $p[] = $xc+$w*$cosea; + $p[] = $z+$yc-$h*$sinea; + $p[] = $xc+$w*$cosea; + $p[] = $yc-$h*$sinea; + $p[] = $xc; + $p[] = $yc; + } + } + elseif( $sa >= 180 ) { + $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea); + $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); + + for( $a=$rea; $a>$rsa; $a -= $step ) { + $tca = cos($a); + $tsa = sin($a); + $p[] = $xc+$w*$tca; + $p[] = $z+$yc-$h*$tsa; + $pt[] = $xc+$w*$tca; + $pt[] = $yc-$h*$tsa; + } + + $pt[] = $xc+$w*$cossa; + $pt[] = $yc-$h*$sinsa; + $pt[] = $xc; + $pt[] = $yc; + + $p[] = $xc+$w*$cossa; + $p[] = $z+$yc-$h*$sinsa; + $p[] = $xc+$w*$cossa; + $p[] = $yc-$h*$sinsa; + $p[] = $xc; + $p[] = $yc; + + } + elseif( $sa >= 90 ) { + if( $ea > 180 ) { + $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea); + $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); + + for( $a=$rea; $a > M_PI; $a -= $step ) { + $tca = cos($a); + $tsa = sin($a); + $p[] = $xc+$w*$tca; + $p[] = $z + $yc - $h*$tsa; + $pt[] = $xc+$w*$tca; + $pt[] = $yc-$h*$tsa; + } + + $p[] = $xc-$w; + $p[] = $z+$yc; + $p[] = $xc-$w; + $p[] = $yc; + $p[] = $xc; + $p[] = $yc; + + $pt[] = $xc-$w; + $pt[] = $z+$yc; + $pt[] = $xc-$w; + $pt[] = $yc; + + for( $a=M_PI-$step; $a > $rsa; $a -= $step ) { + $pt[] = $xc + $w*cos($a); + $pt[] = $yc - $h*sin($a); + } + + $pt[] = $xc+$w*$cossa; + $pt[] = $yc-$h*$sinsa; + $pt[] = $xc; + $pt[] = $yc; + + } + else { // $sa >= 90 && $ea <= 180 + $p = array($xc,$yc,$xc,$yc+$z, + $xc+$w*$cosea,$z+$yc-$h*$sinea, + $xc+$w*$cosea,$yc-$h*$sinea, + $xc,$yc); + + $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea); + + for( $a=$rea; $a>$rsa; $a -= $step ) { + $pt[] = $xc + $w*cos($a); + $pt[] = $yc - $h*sin($a); + } + + $pt[] = $xc+$w*$cossa; + $pt[] = $yc-$h*$sinsa; + $pt[] = $xc; + $pt[] = $yc; + + } + } + else { // sa > 0 && ea < 90 + + $p = array($xc,$yc,$xc,$yc+$z, + $xc+$w*$cossa,$z+$yc-$h*$sinsa, + $xc+$w*$cossa,$yc-$h*$sinsa, + $xc,$yc); + + $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa); + + for( $a=$rsa; $a < $rea; $a += $step ) { + $pt[] = $xc + $w*cos($a); + $pt[] = $yc - $h*sin($a); + } + + $pt[] = $xc+$w*$cosea; + $pt[] = $yc-$h*$sinea; + $pt[] = $xc; + $pt[] = $yc; + } + + $img->PushColor($fillcolor.":".$shadow); + $img->FilledPolygon($p); + $img->PopColor(); + + $img->PushColor($fillcolor); + $img->FilledPolygon($pt); + $img->PopColor(); + } + + function SetStartAngle($aStart) { + if( $aStart < 0 || $aStart > 360 ) { + JpGraphError::RaiseL(14004);//('Slice start angle must be between 0 and 360 degrees.'); + } + $this->startangle = $aStart; + } + +// Draw a 3D Pie + function Pie3D($aaoption,$img,$data,$colors,$xc,$yc,$d,$angle,$z, + $shadow=0.65,$startangle=0,$edgecolor="",$edgeweight=1) { + + //--------------------------------------------------------------------------- + // As usual the algorithm get more complicated than I originally + // envisioned. I believe that this is as simple as it is possible + // to do it with the features I want. It's a good exercise to start + // thinking on how to do this to convince your self that all this + // is really needed for the general case. + // + // The algorithm two draw 3D pies without "real 3D" is done in + // two steps. + // First imagine the pie cut in half through a thought line between + // 12'a clock and 6'a clock. It now easy to imagine that we can plot + // the individual slices for each half by starting with the topmost + // pie slice and continue down to 6'a clock. + // + // In the algortithm this is done in three principal steps + // Step 1. Do the knife cut to ensure by splitting slices that extends + // over the cut line. This is done by splitting the original slices into + // upto 3 subslices. + // Step 2. Find the top slice for each half + // Step 3. Draw the slices from top to bottom + // + // The thing that slightly complicates this scheme with all the + // angle comparisons below is that we can have an arbitrary start + // angle so we must take into account the different equivalence classes. + // For the same reason we must walk through the angle array in a + // modulo fashion. + // + // Limitations of algorithm: + // * A small exploded slice which crosses the 270 degree point + // will get slightly nagged close to the center due to the fact that + // we print the slices in Z-order and that the slice left part + // get printed first and might get slightly nagged by a larger + // slice on the right side just before the right part of the small + // slice. Not a major problem though. + //--------------------------------------------------------------------------- + + + // Determine the height of the ellippse which gives an + // indication of the inclination angle + $h = ($angle/90.0)*$d; + $sum = 0; + for($i=0; $ilabeltype == 2 ) { + $this->adjusted_data = $this->AdjPercentage($data); + } + + // Setup the start + $accsum = 0; + $a = $startangle; + $a = $this->NormAngle($a); + + // + // Step 1 . Split all slices that crosses 90 or 270 + // + $idx=0; + $adjexplode=array(); + $numcolors = count($colors); + for($i=0; $iexplode_radius[$i]) ) + $this->explode_radius[$i]=0; + + $expscale=1; + if( $aaoption == 1 ) + $expscale=2; + + $la = $a + $da/2; + $explode = array( $xc + $this->explode_radius[$i]*cos($la*M_PI/180)*$expscale, + $yc - $this->explode_radius[$i]*sin($la*M_PI/180) * ($h/$d) *$expscale ); + $adjexplode[$idx] = $explode; + $labeldata[$i] = array($la,$explode[0],$explode[1]); + $originalangles[$i] = array($a,$a+$da); + + $ne = $this->NormAngle($a+$da); + if( $da <= 180 ) { + // If the slice size is <= 90 it can at maximum cut across + // one boundary (either 90 or 270) where it needs to be split + $split=-1; // no split + if( ($da<=90 && ($a <= 90 && $ne > 90)) || + (($da <= 180 && $da >90) && (($a < 90 || $a >= 270) && $ne > 90)) ) { + $split = 90; + } + elseif( ($da<=90 && ($a <= 270 && $ne > 270)) || + (($da<=180 && $da>90) && ($a >= 90 && $a < 270 && ($a+$da) > 270 )) ) { + $split = 270; + } + if( $split > 0 ) { // split in two + $angles[$idx] = array($a,$split); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + $angles[++$idx] = array($split,$ne); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + } + else { // no split + $angles[$idx] = array($a,$ne); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + } + } + else { + // da>180 + // Slice may, depending on position, cross one or two + // bonudaries + + if( $a < 90 ) + $split = 90; + elseif( $a <= 270 ) + $split = 270; + else + $split = 90; + + $angles[$idx] = array($a,$split); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + //if( $a+$da > 360-$split ) { + // For slices larger than 270 degrees we might cross + // another boundary as well. This means that we must + // split the slice further. The comparison gets a little + // bit complicated since we must take into accound that + // a pie might have a startangle >0 and hence a slice might + // wrap around the 0 angle. + // Three cases: + // a) Slice starts before 90 and hence gets a split=90, but + // we must also check if we need to split at 270 + // b) Slice starts after 90 but before 270 and slices + // crosses 90 (after a wrap around of 0) + // c) If start is > 270 (hence the firstr split is at 90) + // and the slice is so large that it goes all the way + // around 270. + if( ($a < 90 && ($a+$da > 270)) || + ($a > 90 && $a<=270 && ($a+$da>360+90) ) || + ($a > 270 && $this->NormAngle($a+$da)>270) ) { + $angles[++$idx] = array($split,360-$split); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + $angles[++$idx] = array(360-$split,$ne); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + } + else { + // Just a simple split to the previous decided + // angle. + $angles[++$idx] = array($split,$ne); + $adjcolors[$idx] = $colors[$i % $numcolors]; + $adjexplode[$idx] = $explode; + } + } + $a += $da; + $a = $this->NormAngle($a); + } + + // Total number of slices + $n = count($angles); + + for($i=0; $i<$n; ++$i) { + list($dbgs,$dbge) = $angles[$i]; + } + + // + // Step 2. Find start index (first pie that starts in upper left quadrant) + // + $minval = $angles[0][0]; + $min = 0; + for( $i=0; $i<$n; ++$i ) { + if( $angles[$i][0] < $minval ) { + $minval = $angles[$i][0]; + $min = $i; + } + } + $j = $min; + $cnt = 0; + while( $angles[$j][1] <= 90 ) { + $j++; + if( $j>=$n) { + $j=0; + } + if( $cnt > $n ) { + JpGraphError::RaiseL(14005); +//("Pie3D Internal error (#1). Trying to wrap twice when looking for start index"); + } + ++$cnt; + } + $start = $j; + + // + // Step 3. Print slices in z-order + // + $cnt = 0; + + // First stroke all the slices between 90 and 270 (left half circle) + // counterclockwise + + while( $angles[$j][0] < 270 && $aaoption !== 2 ) { + + list($x,$y) = $adjexplode[$j]; + + $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1], + $z,$adjcolors[$j],$shadow); + + $last = array($x,$y,$j); + + $j++; + if( $j >= $n ) $j=0; + if( $cnt > $n ) { + JpGraphError::RaiseL(14006); +//("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); + } + ++$cnt; + } + + $slice_left = $n-$cnt; + $j=$start-1; + if($j<0) $j=$n-1; + $cnt = 0; + + // The stroke all slices from 90 to -90 (right half circle) + // clockwise + while( $cnt < $slice_left && $aaoption !== 2 ) { + + list($x,$y) = $adjexplode[$j]; + + $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1], + $z,$adjcolors[$j],$shadow); + $j--; + if( $cnt > $n ) { + JpGraphError::RaiseL(14006); +//("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking."); + } + if($j<0) $j=$n-1; + $cnt++; + } + + // Now do a special thing. Stroke the last slice on the left + // halfcircle one more time. This is needed in the case where + // the slice close to 270 have been exploded. In that case the + // part of the slice close to the center of the pie might be + // slightly nagged. + if( $aaoption !== 2 ) + $this->Pie3DSlice($img,$last[0],$last[1],$d,$h,$angles[$last[2]][0], + $angles[$last[2]][1],$z,$adjcolors[$last[2]],$shadow); + + + if( $aaoption !== 1 ) { + // Now print possible labels and add csim + $this->value->ApplyFont($img); + $margin = $img->GetFontHeight()/2 + $this->value->margin ; + for($i=0; $i < count($data); ++$i ) { + $la = $labeldata[$i][0]; + $x = $labeldata[$i][1] + cos($la*M_PI/180)*($d+$margin)*$this->ilabelposadj; + $y = $labeldata[$i][2] - sin($la*M_PI/180)*($h+$margin)*$this->ilabelposadj; + if( $this->ilabelposadj >= 1.0 ) { + if( $la > 180 && $la < 360 ) $y += $z; + } + if( $this->labeltype == 0 ) { + if( $sum > 0 ) + $l = 100*$data[$i]/$sum; + else + $l = 0; + } + elseif( $this->labeltype == 1 ) { + $l = $data[$i]; + } + else { + $l = $this->adjusted_data[$i]; + } + if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) + $l=sprintf($this->labels[$i],$l); + + $this->StrokeLabels($l,$img,$labeldata[$i][0]*M_PI/180,$x,$y,$z); + + $this->Add3DSliceToCSIM($i,$labeldata[$i][1],$labeldata[$i][2],$h*2,$d*2,$z, + $originalangles[$i][0],$originalangles[$i][1]); + } + } + + // + // Finally add potential lines in pie + // + + if( $edgecolor=="" || $aaoption !== 0 ) return; + + $accsum = 0; + $a = $startangle; + $a = $this->NormAngle($a); + + $a *= M_PI/180.0; + + $idx=0; + $img->PushColor($edgecolor); + $img->SetLineWeight($edgeweight); + + $fulledge = true; + for($i=0; $i < count($data) && $fulledge; ++$i ) { + if( empty($this->explode_radius[$i]) ) + $this->explode_radius[$i]=0; + if( $this->explode_radius[$i] > 0 ) { + $fulledge = false; + } + } + + + for($i=0; $i < count($data); ++$i, ++$idx ) { + + $da = $data[$i]/$sum * 2*M_PI; + $this->StrokeFullSliceFrame($img,$xc,$yc,$a,$a+$da,$d,$h,$z,$edgecolor, + $this->explode_radius[$i],$fulledge); + $a += $da; + } + $img->PopColor(); + } + + function StrokeFullSliceFrame($img,$xc,$yc,$sa,$ea,$w,$h,$z,$edgecolor,$exploderadius,$fulledge) { + $step = 0.02; + + if( $exploderadius > 0 ) { + $la = ($sa+$ea)/2; + $xc += $exploderadius*cos($la); + $yc -= $exploderadius*sin($la) * ($h/$w) ; + + } + + $p = array($xc,$yc,$xc+$w*cos($sa),$yc-$h*sin($sa)); + + for($a=$sa; $a < $ea; $a += $step ) { + $p[] = $xc + $w*cos($a); + $p[] = $yc - $h*sin($a); + } + + $p[] = $xc+$w*cos($ea); + $p[] = $yc-$h*sin($ea); + $p[] = $xc; + $p[] = $yc; + + $img->SetColor($edgecolor); + $img->Polygon($p); + + // Unfortunately we can't really draw the full edge around the whole of + // of the slice if any of the slices are exploded. The reason is that + // this algorithm is to simply. There are cases where the edges will + // "overwrite" other slices when they have been exploded. + // Doing the full, proper 3D hidden lines stiff is actually quite + // tricky. So for exploded pies we only draw the top edge. Not perfect + // but the "real" solution is much more complicated. + if( $fulledge && !( $sa > 0 && $sa < M_PI && $ea < M_PI) ) { + + if($sa < M_PI && $ea > M_PI) + $sa = M_PI; + + if($sa < 2*M_PI && (($ea >= 2*M_PI) || ($ea > 0 && $ea < $sa ) ) ) + $ea = 2*M_PI; + + if( $sa >= M_PI && $ea <= 2*M_PI ) { + $p = array($xc + $w*cos($sa),$yc - $h*sin($sa), + $xc + $w*cos($sa),$z + $yc - $h*sin($sa)); + + for($a=$sa+$step; $a < $ea; $a += $step ) { + $p[] = $xc + $w*cos($a); + $p[] = $z + $yc - $h*sin($a); + } + $p[] = $xc + $w*cos($ea); + $p[] = $z + $yc - $h*sin($ea); + $p[] = $xc + $w*cos($ea); + $p[] = $yc - $h*sin($ea); + $img->SetColor($edgecolor); + $img->Polygon($p); + } + } + } + + function Stroke($img,$aaoption=0) { + $n = count($this->data); + + // If user hasn't set the colors use the theme array + if( $this->setslicecolors==null ) { + $colors = array_keys($img->rgb->rgb_table); + sort($colors); + $idx_a=$this->themearr[$this->theme]; + $ca = array(); + $m = count($idx_a); + for($i=0; $i < $m; ++$i) + $ca[$i] = $colors[$idx_a[$i]]; + $ca = array_reverse(array_slice($ca,0,$n)); + } + else { + $ca = $this->setslicecolors; + } + + + if( $this->posx <= 1 && $this->posx > 0 ) + $xc = round($this->posx*$img->width); + else + $xc = $this->posx ; + + if( $this->posy <= 1 && $this->posy > 0 ) + $yc = round($this->posy*$img->height); + else + $yc = $this->posy ; + + if( $this->radius <= 1 ) { + $width = floor($this->radius*min($img->width,$img->height)); + // Make sure that the pie doesn't overflow the image border + // The 0.9 factor is simply an extra margin to leave some space + // between the pie an the border of the image. + $width = min($width,min($xc*0.9,($yc*90/$this->angle-$width/4)*0.9)); + } + else { + $width = $this->radius * ($aaoption === 1 ? 2 : 1 ) ; + } + + // Add a sanity check for width + if( $width < 1 ) { + JpGraphError::RaiseL(14007);//("Width for 3D Pie is 0. Specify a size > 0"); + } + + // Establish a thickness. By default the thickness is a fifth of the + // pie slice width (=pie radius) but since the perspective depends + // on the inclination angle we use some heuristics to make the edge + // slightly thicker the less the angle. + + // Has user specified an absolute thickness? In that case use + // that instead + + if( $this->iThickness ) { + $thick = $this->iThickness; + $thick *= ($aaoption === 1 ? 2 : 1 ); + } + else + $thick = $width/12; + $a = $this->angle; + if( $a <= 30 ) $thick *= 1.6; + elseif( $a <= 40 ) $thick *= 1.4; + elseif( $a <= 50 ) $thick *= 1.2; + elseif( $a <= 60 ) $thick *= 1.0; + elseif( $a <= 70 ) $thick *= 0.8; + elseif( $a <= 80 ) $thick *= 0.7; + else $thick *= 0.6; + + $thick = floor($thick); + + if( $this->explode_all ) + for($i=0; $i < $n; ++$i) + $this->explode_radius[$i]=$this->explode_r; + + $this->Pie3D($aaoption,$img,$this->data, $ca, $xc, $yc, $width, $this->angle, + $thick, 0.65, $this->startangle, $this->edgecolor, $this->edgeweight); + + // Adjust title position + if( $aaoption != 1 ) { + $this->title->SetPos($xc,$yc-$this->title->GetFontHeight($img)-$width/2-$this->title->margin, "center","bottom"); + $this->title->Stroke($img); + } + } + +//--------------- +// PRIVATE METHODS + + // Position the labels of each slice + function StrokeLabels($label,$img,$a,$xp,$yp,$z) { + $this->value->halign="left"; + $this->value->valign="top"; + + // Position the axis title. + // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text + // that intersects with the extension of the corresponding axis. The code looks a little + // bit messy but this is really the only way of having a reasonable position of the + // axis titles. + $this->value->ApplyFont($img); + $h=$img->GetTextHeight($label); + // For numeric values the format of the display value + // must be taken into account + if( is_numeric($label) ) { + if( $label >= 0 ) + $w=$img->GetTextWidth(sprintf($this->value->format,$label)); + else + $w=$img->GetTextWidth(sprintf($this->value->negformat,$label)); + } + else + $w=$img->GetTextWidth($label); + while( $a > 2*M_PI ) $a -= 2*M_PI; + if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); + + if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; + if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); + if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; + if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); + if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; + + $x = round($xp-$dx*$w); + $y = round($yp-$dy*$h); + + + // Mark anchor point for debugging + /* + $img->SetColor('red'); + $img->Line($xp-10,$yp,$xp+10,$yp); + $img->Line($xp,$yp-10,$xp,$yp+10); + */ + $oldmargin = $this->value->margin; + $this->value->margin=0; + $this->value->Stroke($img,$label,$x,$y); + $this->value->margin=$oldmargin; + + } +} // Class + +/* EOF */ +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php new file mode 100644 index 0000000..c20be33 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotband.php @@ -0,0 +1,635 @@ +x=$aX; + $this->y=$aY; + $this->w=$aWidth; + $this->h=$aHeight; + $this->xe=$aX+$aWidth-1; + $this->ye=$aY+$aHeight-1; + } +} + +//===================================================================== +// Class RectPattern +// Base class for pattern hierarchi that is used to display patterned +// bands on the graph. Any subclass that doesn't override Stroke() +// must at least implement method DoPattern($aImg) which is responsible +// for drawing the pattern onto the graph. +//===================================================================== +class RectPattern { + protected $color; + protected $weight; + protected $rect=null; + protected $doframe=true; + protected $linespacing; // Line spacing in pixels + protected $iBackgroundColor=-1; // Default is no background fill + + function RectPattern($aColor,$aWeight=1) { + $this->color = $aColor; + $this->weight = $aWeight; + } + + function SetBackground($aBackgroundColor) { + $this->iBackgroundColor=$aBackgroundColor; + } + + function SetPos($aRect) { + $this->rect = $aRect; + } + + function ShowFrame($aShow=true) { + $this->doframe=$aShow; + } + + function SetDensity($aDens) { + if( $aDens < 1 || $aDens > 100 ) + JpGraphError::RaiseL(16001,$aDens); +//(" Desity for pattern must be between 1 and 100. (You tried $aDens)"); + // 1% corresponds to linespacing=50 + // 100 % corresponds to linespacing 1 + $this->linespacing = floor(((100-$aDens)/100.0)*50)+1; + + } + + function Stroke($aImg) { + if( $this->rect == null ) + JpGraphError::RaiseL(16002); +//(" No positions specified for pattern."); + + if( !(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1) ) { + $aImg->SetColor($this->iBackgroundColor); + $aImg->FilledRectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); + } + + $aImg->SetColor($this->color); + $aImg->SetLineWeight($this->weight); + + // Virtual function implemented by subclass + $this->DoPattern($aImg); + + // Frame around the pattern area + if( $this->doframe ) + $aImg->Rectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye); + } + +} + + +//===================================================================== +// Class RectPatternSolid +// Implements a solid band +//===================================================================== +class RectPatternSolid extends RectPattern { + + function RectPatternSolid($aColor="black",$aWeight=1) { + parent::RectPattern($aColor,$aWeight); + } + + function DoPattern($aImg) { + $aImg->SetColor($this->color); + $aImg->FilledRectangle($this->rect->x,$this->rect->y, + $this->rect->xe,$this->rect->ye); + } +} + +//===================================================================== +// Class RectPatternHor +// Implements horizontal line pattern +//===================================================================== +class RectPatternHor extends RectPattern { + + function RectPatternHor($aColor="black",$aWeight=1,$aLineSpacing=7) { + parent::RectPattern($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + function DoPattern($aImg) { + $x0 = $this->rect->x; + $x1 = $this->rect->xe; + $y = $this->rect->y; + while( $y < $this->rect->ye ) { + $aImg->Line($x0,$y,$x1,$y); + $y += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPatternVert +// Implements vertical line pattern +//===================================================================== +class RectPatternVert extends RectPattern { + + function RectPatternVert($aColor="black",$aWeight=1,$aLineSpacing=7) { + parent::RectPattern($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + //-------------------- + // Private methods + // + function DoPattern($aImg) { + $x = $this->rect->x; + $y0 = $this->rect->y; + $y1 = $this->rect->ye; + while( $x < $this->rect->xe ) { + $aImg->Line($x,$y0,$x,$y1); + $x += $this->linespacing; + } + } +} + + +//===================================================================== +// Class RectPatternRDiag +// Implements right diagonal pattern +//===================================================================== +class RectPatternRDiag extends RectPattern { + + function RectPatternRDiag($aColor="black",$aWeight=1,$aLineSpacing=12) { + parent::RectPattern($aColor,$aWeight); + $this->linespacing = $aLineSpacing; + } + + function DoPattern($aImg) { + // -------------------- + // | / / / / /| + // |/ / / / / | + // | / / / / | + // -------------------- + $xe = $this->rect->xe; + $ye = $this->rect->ye; + $x0 = $this->rect->x + round($this->linespacing/2); + $y0 = $this->rect->y; + $x1 = $this->rect->x; + $y1 = $this->rect->y + round($this->linespacing/2); + + while($x0<=$xe && $y1<=$ye) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $y1 += $this->linespacing; + } + + if( $xe-$x1 > $ye-$y0 ) { + // Width larger than height + $x1 = $this->rect->x + ($y1-$ye); + $y1 = $ye; + $y0 = $this->rect->y; + while( $x0 <= $xe ) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $x1 += $this->linespacing; + } + + $y0=$this->rect->y + ($x0-$xe); + $x0=$xe; + } + else { + // Height larger than width + $diff = $x0-$xe; + $y0 = $diff+$this->rect->y; + $x0 = $xe; + $x1 = $this->rect->x; + while( $y1 <= $ye ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y1 += $this->linespacing; + $y0 += $this->linespacing; + } + + $diff = $y1-$ye; + $y1 = $ye; + $x1 = $diff + $this->rect->x; + } + + while( $y0 <= $ye ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 += $this->linespacing; + $x1 += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPatternLDiag +// Implements left diagonal pattern +//===================================================================== +class RectPatternLDiag extends RectPattern { + + function RectPatternLDiag($aColor="black",$aWeight=1,$aLineSpacing=12) { + $this->linespacing = $aLineSpacing; + parent::RectPattern($aColor,$aWeight); + } + + function DoPattern($aImg) { + // -------------------- + // |\ \ \ \ \ | + // | \ \ \ \ \| + // | \ \ \ \ | + // |------------------| + $xe = $this->rect->xe; + $ye = $this->rect->ye; + $x0 = $this->rect->x + round($this->linespacing/2); + $y0 = $this->rect->ye; + $x1 = $this->rect->x; + $y1 = $this->rect->ye - round($this->linespacing/2); + + while($x0<=$xe && $y1>=$this->rect->y) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $y1 -= $this->linespacing; + } + if( $xe-$x1 > $ye-$this->rect->y ) { + // Width larger than height + $x1 = $this->rect->x + ($this->rect->y-$y1); + $y0=$ye; $y1=$this->rect->y; + while( $x0 <= $xe ) { + $aImg->Line($x0,$y0,$x1,$y1); + $x0 += $this->linespacing; + $x1 += $this->linespacing; + } + + $y0=$this->rect->ye - ($x0-$xe); + $x0=$xe; + } + else { + // Height larger than width + $diff = $x0-$xe; + $y0 = $ye-$diff; + $x0 = $xe; + while( $y1 >= $this->rect->y ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 -= $this->linespacing; + $y1 -= $this->linespacing; + } + $diff = $this->rect->y - $y1; + $x1 = $this->rect->x + $diff; + $y1 = $this->rect->y; + } + while( $y0 >= $this->rect->y ) { + $aImg->Line($x0,$y0,$x1,$y1); + $y0 -= $this->linespacing; + $x1 += $this->linespacing; + } + } +} + +//===================================================================== +// Class RectPattern3DPlane +// Implements "3D" plane pattern +//===================================================================== +class RectPattern3DPlane extends RectPattern { + private $alpha=50; // Parameter that specifies the distance + // to "simulated" horizon in pixel from the + // top of the band. Specifies how fast the lines + // converge. + + function RectPattern3DPlane($aColor="black",$aWeight=1) { + parent::RectPattern($aColor,$aWeight); + $this->SetDensity(10); // Slightly larger default + } + + function SetHorizon($aHorizon) { + $this->alpha=$aHorizon; + } + + function DoPattern($aImg) { + // "Fake" a nice 3D grid-effect. + $x0 = $this->rect->x + $this->rect->w/2; + $y0 = $this->rect->y; + $x1 = $x0; + $y1 = $this->rect->ye; + $x0_right = $x0; + $x1_right = $x1; + + // BTW "apa" means monkey in Swedish but is really a shortform for + // "alpha+a" which was the labels I used on paper when I derived the + // geometric to get the 3D perspective right. + // $apa is the height of the bounding rectangle plus the distance to the + // artifical horizon (alpha) + $apa = $this->rect->h + $this->alpha; + + // Three cases and three loops + // 1) The endpoint of the line ends on the bottom line + // 2) The endpoint ends on the side + // 3) Horizontal lines + + // Endpoint falls on bottom line + $middle=$this->rect->x + $this->rect->w/2; + $dist=$this->linespacing; + $factor=$this->alpha /($apa); + while($x1>$this->rect->x) { + $aImg->Line($x0,$y0,$x1,$y1); + $aImg->Line($x0_right,$y0,$x1_right,$y1); + $x1 = $middle - $dist; + $x0 = $middle - $dist * $factor; + $x1_right = $middle + $dist; + $x0_right = $middle + $dist * $factor; + $dist += $this->linespacing; + } + + // Endpoint falls on sides + $dist -= $this->linespacing; + $d=$this->rect->w/2; + $c = $apa - $d*$apa/$dist; + while( $x0>$this->rect->x ) { + $aImg->Line($x0,$y0,$this->rect->x,$this->rect->ye-$c); + $aImg->Line($x0_right,$y0,$this->rect->xe,$this->rect->ye-$c); + $dist += $this->linespacing; + $x0 = $middle - $dist * $factor; + $x1 = $middle - $dist; + $x0_right = $middle + $dist * $factor; + $c = $apa - $d*$apa/$dist; + } + + // Horizontal lines + // They need some serious consideration since they are a function + // of perspective depth (alpha) and density (linespacing) + $x0=$this->rect->x; + $x1=$this->rect->xe; + $y=$this->rect->ye; + + // The first line is drawn directly. Makes the loop below slightly + // more readable. + $aImg->Line($x0,$y,$x1,$y); + $hls = $this->linespacing; + + // A correction factor for vertical "brick" line spacing to account for + // a) the difference in number of pixels hor vs vert + // b) visual apperance to make the first layer of "bricks" look more + // square. + $vls = $this->linespacing*0.6; + + $ds = $hls*($apa-$vls)/$apa; + // Get the slope for the "perspective line" going from bottom right + // corner to top left corner of the "first" brick. + + // Uncomment the following lines if you want to get a visual understanding + // of what this helpline does. BTW this mimics the way you would get the + // perspective right when drawing on paper. + /* + $x0 = $middle; + $y0 = $this->rect->ye; + $len=floor(($this->rect->ye-$this->rect->y)/$vls); + $x1 = $middle+round($len*$ds); + $y1 = $this->rect->ye-$len*$vls; + $aImg->PushColor("red"); + $aImg->Line($x0,$y0,$x1,$y1); + $aImg->PopColor(); + */ + + $y -= $vls; + $k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds)); + $dist = $hls; + while( $y>$this->rect->y ) { + $aImg->Line($this->rect->x,$y,$this->rect->xe,$y); + $adj = $k*$dist/(1+$dist*$k/$apa); + if( $adj < 2 ) $adj=1; + $y = $this->rect->ye - round($adj); + $dist += $hls; + } + } +} + +//===================================================================== +// Class RectPatternCross +// Vert/Hor crosses +//===================================================================== +class RectPatternCross extends RectPattern { + private $vert=null; + private $hor=null; + function RectPatternCross($aColor="black",$aWeight=1) { + parent::RectPattern($aColor,$aWeight); + $this->vert = new RectPatternVert($aColor,$aWeight); + $this->hor = new RectPatternHor($aColor,$aWeight); + } + + function SetOrder($aDepth) { + $this->vert->SetOrder($aDepth); + $this->hor->SetOrder($aDepth); + } + + function SetPos($aRect) { + parent::SetPos($aRect); + $this->vert->SetPos($aRect); + $this->hor->SetPos($aRect); + } + + function SetDensity($aDens) { + $this->vert->SetDensity($aDens); + $this->hor->SetDensity($aDens); + } + + function DoPattern($aImg) { + $this->vert->DoPattern($aImg); + $this->hor->DoPattern($aImg); + } +} + +//===================================================================== +// Class RectPatternDiagCross +// Vert/Hor crosses +//===================================================================== + +class RectPatternDiagCross extends RectPattern { + private $left=null; + private $right=null; + function RectPatternDiagCross($aColor="black",$aWeight=1) { + parent::RectPattern($aColor,$aWeight); + $this->right = new RectPatternRDiag($aColor,$aWeight); + $this->left = new RectPatternLDiag($aColor,$aWeight); + } + + function SetOrder($aDepth) { + $this->left->SetOrder($aDepth); + $this->right->SetOrder($aDepth); + } + + function SetPos($aRect) { + parent::SetPos($aRect); + $this->left->SetPos($aRect); + $this->right->SetPos($aRect); + } + + function SetDensity($aDens) { + $this->left->SetDensity($aDens); + $this->right->SetDensity($aDens); + } + + function DoPattern($aImg) { + $this->left->DoPattern($aImg); + $this->right->DoPattern($aImg); + } + +} + +//===================================================================== +// Class RectPatternFactory +// Factory class for rectangular pattern +//===================================================================== +class RectPatternFactory { + function RectPatternFactory() { + // Empty + } + function Create($aPattern,$aColor,$aWeight=1) { + switch($aPattern) { + case BAND_RDIAG: + $obj = new RectPatternRDiag($aColor,$aWeight); + break; + case BAND_LDIAG: + $obj = new RectPatternLDiag($aColor,$aWeight); + break; + case BAND_SOLID: + $obj = new RectPatternSolid($aColor,$aWeight); + break; + case BAND_VLINE: + $obj = new RectPatternVert($aColor,$aWeight); + break; + case BAND_HLINE: + $obj = new RectPatternHor($aColor,$aWeight); + break; + case BAND_3DPLANE: + $obj = new RectPattern3DPlane($aColor,$aWeight); + break; + case BAND_HVCROSS: + $obj = new RectPatternCross($aColor,$aWeight); + break; + case BAND_DIAGCROSS: + $obj = new RectPatternDiagCross($aColor,$aWeight); + break; + default: + JpGraphError::RaiseL(16003,$aPattern); +//(" Unknown pattern specification ($aPattern)"); + } + return $obj; + } +} + + +//===================================================================== +// Class PlotBand +// Factory class which is used by the client. +// It is responsible for factoring the corresponding pattern +// concrete class. +//===================================================================== +class PlotBand { + public $depth; // Determine if band should be over or under the plots + private $prect=null; + private $dir, $min, $max; + + function PlotBand($aDir,$aPattern,$aMin,$aMax,$aColor="black",$aWeight=1,$aDepth=DEPTH_BACK) { + $f = new RectPatternFactory(); + $this->prect = $f->Create($aPattern,$aColor,$aWeight); + if( is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax) ) + JpGraphError::RaiseL(16004); +//('Min value for plotband is larger than specified max value. Please correct.'); + $this->dir = $aDir; + $this->min = $aMin; + $this->max = $aMax; + $this->depth=$aDepth; + } + + // Set position. aRect contains absolute image coordinates + function SetPos($aRect) { + assert( $this->prect != null ) ; + $this->prect->SetPos($aRect); + } + + function ShowFrame($aFlag=true) { + $this->prect->ShowFrame($aFlag); + } + + // Set z-order. In front of pplot or in the back + function SetOrder($aDepth) { + $this->depth=$aDepth; + } + + function SetDensity($aDens) { + $this->prect->SetDensity($aDens); + } + + function GetDir() { + return $this->dir; + } + + function GetMin() { + return $this->min; + } + + function GetMax() { + return $this->max; + } + + function PreStrokeAdjust($aGraph) { + // Nothing to do + } + + // Display band + function Stroke($aImg,$aXScale,$aYScale) { + assert( $this->prect != null ) ; + if( $this->dir == HORIZONTAL ) { + if( $this->min === 'min' ) $this->min = $aYScale->GetMinVal(); + if( $this->max === 'max' ) $this->max = $aYScale->GetMaxVal(); + + // Only draw the bar if it actually appears in the range + if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) { + + // Trucate to limit of axis + $this->min = max($this->min, $aYScale->GetMinVal()); + $this->max = min($this->max, $aYScale->GetMaxVal()); + + $x=$aXScale->scale_abs[0]; + $y=$aYScale->Translate($this->max); + $width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1; + $height=abs($y-$aYScale->Translate($this->min))+1; + $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); + $this->prect->Stroke($aImg); + } + } + else { // VERTICAL + if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal(); + if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal(); + + // Only draw the bar if it actually appears in the range + if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) { + + // Trucate to limit of axis + $this->min = max($this->min, $aXScale->GetMinVal()); + $this->max = min($this->max, $aXScale->GetMaxVal()); + + $y=$aYScale->scale_abs[1]; + $x=$aXScale->Translate($this->min); + $height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]); + $width=abs($x-$aXScale->Translate($this->max)); + $this->prect->SetPos(new Rectangle($x,$y,$width,$height)); + $this->prect->Stroke($aImg); + } + } + } +} + + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotmark.inc.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotmark.inc.php new file mode 100644 index 0000000..8efa3d0 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_plotmark.inc.php @@ -0,0 +1,497 @@ +title = new Text(); + $this->title->Hide(); + $this->csimareas = ''; + $this->type=-1; + } +//--------------- +// PUBLIC METHODS + function SetType($aType,$aFileName='',$aScale=1.0) { + $this->type = $aType; + if( $aType == MARK_IMG && $aFileName=='' ) { + JpGraphError::RaiseL(23003);//('A filename must be specified if you set the mark type to MARK_IMG.'); + } + $this->iFileName = $aFileName; + $this->iScale = $aScale; + } + + function SetCallback($aFunc) { + $this->iFormatCallback = $aFunc; + } + + function SetCallbackYX($aFunc) { + $this->iFormatCallback2 = $aFunc; + } + + function GetType() { + return $this->type; + } + + function SetColor($aColor) { + $this->color=$aColor; + } + + function SetFillColor($aFillColor) { + $this->fill_color = $aFillColor; + } + + function SetWeight($aWeight) { + $this->weight = $aWeight; + } + + // Synonym for SetWidth() + function SetSize($aWidth) { + $this->width=$aWidth; + } + + function SetWidth($aWidth) { + $this->width=$aWidth; + } + + function SetDefaultWidth() { + switch( $this->type ) { + case MARK_CIRCLE: + case MARK_FILLEDCIRCLE: + $this->width=4; + break; + default: + $this->width=7; + } + } + + function GetWidth() { + return $this->width; + } + + function Hide($aHide=true) { + $this->show = !$aHide; + } + + function Show($aShow=true) { + $this->show = $aShow; + } + + function SetCSIMAltVal($aY,$aX='') { + $this->yvalue=$aY; + $this->xvalue=$aX; + } + + function SetCSIMTarget($aTarget,$aWinTarget='') { + $this->csimtarget=$aTarget; + $this->csimwintarget=$aWinTarget; + } + + function SetCSIMAlt($aAlt) { + $this->csimalt=$aAlt; + } + + function GetCSIMAreas(){ + return $this->csimareas; + } + + function AddCSIMPoly($aPts) { + $coords = round($aPts[0]).", ".round($aPts[1]); + $n = count($aPts)/2; + for( $i=1; $i < $n; ++$i){ + $coords .= ", ".round($aPts[2*$i]).", ".round($aPts[2*$i+1]); + } + $this->csimareas=""; + if( !empty($this->csimtarget) ) { + $this->csimareas .= "csimtarget)."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimareas .= " target=\"".$this->csimwintarget."\" "; + } + + if( !empty($this->csimalt) ) { + $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\""; + } + $this->csimareas .= " />\n"; + } + } + + function AddCSIMCircle($x,$y,$r) { + $x = round($x); $y=round($y); $r=round($r); + $this->csimareas=""; + if( !empty($this->csimtarget) ) { + $this->csimareas .= "csimtarget)."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimareas .= " target=\"".$this->csimwintarget."\" "; + } + + if( !empty($this->csimalt) ) { + $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + } + + function Stroke($img,$x,$y) { + if( !$this->show ) return; + + if( $this->iFormatCallback != '' || $this->iFormatCallback2 != '' ) { + + if( $this->iFormatCallback != '' ) { + $f = $this->iFormatCallback; + list($width,$color,$fcolor) = call_user_func($f,$this->yvalue); + $filename = $this->iFileName; + $imgscale = $this->iScale; + } + else { + $f = $this->iFormatCallback2; + list($width,$color,$fcolor,$filename,$imgscale) = call_user_func($f,$this->yvalue,$this->xvalue); + if( $filename=="" ) $filename = $this->iFileName; + if( $imgscale=="" ) $imgscale = $this->iScale; + } + + if( $width=="" ) $width = $this->width; + if( $color=="" ) $color = $this->color; + if( $fcolor=="" ) $fcolor = $this->fill_color; + + } + else { + $fcolor = $this->fill_color; + $color = $this->color; + $width = $this->width; + $filename = $this->iFileName; + $imgscale = $this->iScale; + } + + if( $this->type == MARK_IMG || + ($this->type >= MARK_FLAG1 && $this->type <= MARK_FLAG4 ) || + $this->type >= MARK_IMG_PUSHPIN ) { + + // Note: For the builtin images we use the "filename" parameter + // to denote the color + $anchor_x = 0.5; + $anchor_y = 0.5; + switch( $this->type ) { + case MARK_FLAG1: + case MARK_FLAG2: + case MARK_FLAG3: + case MARK_FLAG4: + $this->markimg = FlagCache::GetFlagImgByName($this->type-MARK_FLAG1+1,$filename); + break; + + case MARK_IMG : + // Load an image and use that as a marker + // Small optimization, if we have already read an image don't + // waste time reading it again. + if( $this->markimg == '' || !($this->oldfilename === $filename) ) { + $this->markimg = Graph::LoadBkgImage('',$filename); + $this->oldfilename = $filename ; + } + break; + + case MARK_IMG_PUSHPIN: + case MARK_IMG_SPUSHPIN: + case MARK_IMG_LPUSHPIN: + if( $this->imgdata_pushpins == null ) { + require_once 'imgdata_pushpins.inc.php'; + $this->imgdata_pushpins = new ImgData_PushPins(); + } + $this->markimg = $this->imgdata_pushpins->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_pushpins->GetAnchor(); + break; + + case MARK_IMG_SQUARE: + if( $this->imgdata_squares == null ) { + require_once 'imgdata_squares.inc.php'; + $this->imgdata_squares = new ImgData_Squares(); + } + $this->markimg = $this->imgdata_squares->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_squares->GetAnchor(); + break; + + case MARK_IMG_STAR: + if( $this->imgdata_stars == null ) { + require_once 'imgdata_stars.inc.php'; + $this->imgdata_stars = new ImgData_Stars(); + } + $this->markimg = $this->imgdata_stars->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_stars->GetAnchor(); + break; + + case MARK_IMG_BEVEL: + if( $this->imgdata_bevels == null ) { + require_once 'imgdata_bevels.inc.php'; + $this->imgdata_bevels = new ImgData_Bevels(); + } + $this->markimg = $this->imgdata_bevels->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_bevels->GetAnchor(); + break; + + case MARK_IMG_DIAMOND: + if( $this->imgdata_diamonds == null ) { + require_once 'imgdata_diamonds.inc.php'; + $this->imgdata_diamonds = new ImgData_Diamonds(); + } + $this->markimg = $this->imgdata_diamonds->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_diamonds->GetAnchor(); + break; + + case MARK_IMG_BALL: + case MARK_IMG_SBALL: + case MARK_IMG_MBALL: + case MARK_IMG_LBALL: + if( $this->imgdata_balls == null ) { + require_once 'imgdata_balls.inc.php'; + $this->imgdata_balls = new ImgData_Balls(); + } + $this->markimg = $this->imgdata_balls->GetImg($this->type,$filename); + list($anchor_x,$anchor_y) = $this->imgdata_balls->GetAnchor(); + break; + } + + $w = $img->GetWidth($this->markimg); + $h = $img->GetHeight($this->markimg); + + $dw = round($imgscale * $w ); + $dh = round($imgscale * $h ); + + // Do potential rotation + list($x,$y) = $img->Rotate($x,$y); + + $dx = round($x-$dw*$anchor_x); + $dy = round($y-$dh*$anchor_y); + + $this->width = max($dx,$dy); + + $img->Copy($this->markimg,$dx,$dy,0,0,$dw,$dh,$w,$h); + if( !empty($this->csimtarget) ) { + $this->csimareas = "csimtarget)."\""; + + if( !empty($this->csimwintarget) ) { + $this->csimareas .= " target=\"".$this->csimwintarget."\" "; + } + + if( !empty($this->csimalt) ) { + $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue); + $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" "; + } + $this->csimareas .= " />\n"; + } + + // Stroke title + $this->title->Align("center","top"); + $this->title->Stroke($img,$x,$y+round($dh/2)); + return; + } + + $weight = $this->weight; + $dx=round($width/2,0); + $dy=round($width/2,0); + $pts=0; + + switch( $this->type ) { + case MARK_SQUARE: + $c[]=$x-$dx;$c[]=$y-$dy; + $c[]=$x+$dx;$c[]=$y-$dy; + $c[]=$x+$dx;$c[]=$y+$dy; + $c[]=$x-$dx;$c[]=$y+$dy; + $c[]=$x-$dx;$c[]=$y-$dy; + $pts=5; + break; + case MARK_UTRIANGLE: + ++$dx;++$dy; + $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx + $c[]=$x;$c[]=$y-0.87*$dy; + $c[]=$x+$dx;$c[]=$y+0.87*$dy; + $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx + $pts=4; + break; + case MARK_DTRIANGLE: + ++$dx;++$dy; + $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx + $c[]=$x-$dx;$c[]=$y-0.87*$dy; + $c[]=$x+$dx;$c[]=$y-0.87*$dy; + $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx + $pts=4; + break; + case MARK_DIAMOND: + $c[]=$x;$c[]=$y+$dy; + $c[]=$x-$dx;$c[]=$y; + $c[]=$x;$c[]=$y-$dy; + $c[]=$x+$dx;$c[]=$y; + $c[]=$x;$c[]=$y+$dy; + $pts=5; + break; + case MARK_LEFTTRIANGLE: + $c[]=$x;$c[]=$y; + $c[]=$x;$c[]=$y+2*$dy; + $c[]=$x+$dx*2;$c[]=$y; + $c[]=$x;$c[]=$y; + $pts=4; + break; + case MARK_RIGHTTRIANGLE: + $c[]=$x-$dx*2;$c[]=$y; + $c[]=$x;$c[]=$y+2*$dy; + $c[]=$x;$c[]=$y; + $c[]=$x-$dx*2;$c[]=$y; + $pts=4; + break; + case MARK_FLASH: + $dy *= 2; + $c[]=$x+$dx/2; $c[]=$y-$dy; + $c[]=$x-$dx+$dx/2; $c[]=$y+$dy*0.7-$dy; + $c[]=$x+$dx/2; $c[]=$y+$dy*1.3-$dy; + $c[]=$x-$dx+$dx/2; $c[]=$y+2*$dy-$dy; + $img->SetLineWeight($weight); + $img->SetColor($color); + $img->Polygon($c); + $img->SetLineWeight(1); + $this->AddCSIMPoly($c); + break; + } + + if( $pts>0 ) { + $this->AddCSIMPoly($c); + $img->SetLineWeight($weight); + $img->SetColor($fcolor); + $img->FilledPolygon($c); + $img->SetColor($color); + $img->Polygon($c); + $img->SetLineWeight(1); + } + elseif( $this->type==MARK_CIRCLE ) { + $img->SetColor($color); + $img->Circle($x,$y,$width); + $this->AddCSIMCircle($x,$y,$width); + } + elseif( $this->type==MARK_FILLEDCIRCLE ) { + $img->SetColor($fcolor); + $img->FilledCircle($x,$y,$width); + $img->SetColor($color); + $img->Circle($x,$y,$width); + $this->AddCSIMCircle($x,$y,$width); + } + elseif( $this->type==MARK_CROSS ) { + // Oversize by a pixel to match the X + $img->SetColor($color); + $img->SetLineWeight($weight); + $img->Line($x,$y+$dy+1,$x,$y-$dy-1); + $img->Line($x-$dx-1,$y,$x+$dx+1,$y); + $this->AddCSIMCircle($x,$y,$dx); + } + elseif( $this->type==MARK_X ) { + $img->SetColor($color); + $img->SetLineWeight($weight); + $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); + $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); + $this->AddCSIMCircle($x,$y,$dx+$dy); + } + elseif( $this->type==MARK_STAR ) { + $img->SetColor($color); + $img->SetLineWeight($weight); + $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy); + $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy); + // Oversize by a pixel to match the X + $img->Line($x,$y+$dy+1,$x,$y-$dy-1); + $img->Line($x-$dx-1,$y,$x+$dx+1,$y); + $this->AddCSIMCircle($x,$y,$dx+$dy); + } + + // Stroke title + $this->title->Align("center","center"); + $this->title->Stroke($img,$x,$y); + } +} // Class + + + +//======================================================================== +// CLASS ImgData +// Description: Base class for all image data classes that contains the +// real image data. +//======================================================================== +class ImgData { + protected $name = ''; // Each subclass gives a name + protected $an = array(); // Data array names + protected $colors = array(); // Available colors + protected $index = array(); // Index for colors + protected $maxidx = 0 ; // Max color index + protected $anchor_x=0.5, $anchor_y=0.5 ; // Where is the center of the image + // Create a GD image from the data and return a GD handle + function GetImg($aMark,$aIdx) { + $n = $this->an[$aMark]; + if( is_string($aIdx) ) { + if( !in_array($aIdx,$this->colors) ) { + JpGraphError::RaiseL(23001,$this->name,$aIdx);//('This marker "'.($this->name).'" does not exist in color: '.$aIdx); + } + $idx = $this->index[$aIdx]; + } + elseif( !is_integer($aIdx) || + (is_integer($aIdx) && $aIdx > $this->maxidx ) ) { + JpGraphError::RaiseL(23002,$this->name);//('Mark color index too large for marker "'.($this->name).'"'); + } + else + $idx = $aIdx ; + return Image::CreateFromString(base64_decode($this->{$n}[$idx][1])); + } + function GetAnchor() { + return array($this->anchor_x,$this->anchor_y); + } +} + + +// Keep a global flag cache to reduce memory usage +$_gFlagCache=array( + 1 => null, + 2 => null, + 3 => null, + 4 => null, +); +// Only supposed to b called as statics +class FlagCache { + static function GetFlagImgByName($aSize,$aName) { + global $_gFlagCache; + require_once('jpgraph_flags.php'); + if( $_gFlagCache[$aSize] === null ) { + $_gFlagCache[$aSize] = new FlagImages($aSize); + } + $f = $_gFlagCache[$aSize]; + $idx = $f->GetIdxByName($aName,$aFullName); + return $f->GetImgByIdx($idx); + } +} + +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php new file mode 100644 index 0000000..671139e --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_polar.php @@ -0,0 +1,841 @@ +numpoints = $n/2; + $this->coord = $aData; + $this->mark = new PlotMark(); + } + + function SetWeight($aWeight) { + $this->iLineWeight = $aWeight; + } + + function SetColor($aColor){ + $this->iColor = $aColor; + } + + function SetFillColor($aColor){ + $this->iFillColor = $aColor; + } + + function Max() { + $m = $this->coord[1]; + $i=1; + while( $i < $this->numpoints ) { + $m = max($m,$this->coord[2*$i+1]); + ++$i; + } + return $m; + } + // Set href targets for CSIM + function SetCSIMTargets($aTargets,$aAlts=null) { + $this->csimtargets=$aTargets; + $this->csimalts=$aAlts; + } + + // Get all created areas + function GetCSIMareas() { + return $this->csimareas; + } + + function SetLegend($aLegend,$aCSIM="",$aCSIMAlt="") { + $this->legend = $aLegend; + $this->legendcsimtarget = $aCSIM; + $this->legendcsimalt = $aCSIMAlt; + } + + // Private methods + + function Legend($aGraph) { + $color = $this->iColor ; + if( $this->legend != "" ) { + if( $this->iFillColor!='' ) { + $color = $this->iFillColor; + $aGraph->legend->Add($this->legend,$color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt); + } + else { + $aGraph->legend->Add($this->legend,$color,$this->mark,$this->line_style, + $this->legendcsimtarget,$this->legendcsimalt); + } + } + } + + function Stroke($img,$scale) { + + $i=0; + $p=array(); + $this->csimareas=''; + while($i < $this->numpoints) { + list($x1,$y1) = $scale->PTranslate($this->coord[2*$i],$this->coord[2*$i+1]); + $p[2*$i] = $x1; + $p[2*$i+1] = $y1; + + if( isset($this->csimtargets[$i]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$i]); + $this->mark->SetCSIMAlt($this->csimalts[$i]); + $this->mark->SetCSIMAltVal($this->coord[2*$i], $this->coord[2*$i+1]); + $this->mark->Stroke($img,$x1,$y1); + $this->csimareas .= $this->mark->GetCSIMAreas(); + } + else + $this->mark->Stroke($img,$x1,$y1); + + ++$i; + } + + if( $this->iFillColor != '' ) { + $img->SetColor($this->iFillColor); + $img->FilledPolygon($p); + } + $img->SetLineWeight($this->iLineWeight); + $img->SetColor($this->iColor); + $img->Polygon($p,$this->iFillColor!=''); + } +} + +//-------------------------------------------------------------------------- +// class PolarAxis +//-------------------------------------------------------------------------- +class PolarAxis extends Axis { + private $angle_step=15,$angle_color='lightgray',$angle_label_color='black'; + private $angle_fontfam=FF_FONT1,$angle_fontstyle=FS_NORMAL,$angle_fontsize=10; + private $angle_fontcolor = 'navy'; + private $gridminor_color='lightgray',$gridmajor_color='lightgray'; + private $show_minor_grid = false, $show_major_grid = true ; + private $show_angle_mark=true, $show_angle_grid=true, $show_angle_label=true; + private $angle_tick_len=3, $angle_tick_len2=3, $angle_tick_color='black'; + private $show_angle_tick=true; + private $radius_tick_color='black'; + + function PolarAxis($img,$aScale) { + parent::Axis($img,$aScale); + } + + function ShowAngleDegreeMark($aFlg=true) { + $this->show_angle_mark = $aFlg; + } + + function SetAngleStep($aStep) { + $this->angle_step=$aStep; + } + + function HideTicks($aFlg=true,$aAngleFlg=true) { + parent::HideTicks($aFlg,$aFlg); + $this->show_angle_tick = !$aAngleFlg; + } + + function ShowAngleLabel($aFlg=true) { + $this->show_angle_label = $aFlg; + } + + function ShowGrid($aMajor=true,$aMinor=false,$aAngle=true) { + $this->show_minor_grid = $aMinor; + $this->show_major_grid = $aMajor; + $this->show_angle_grid = $aAngle ; + } + + function SetAngleFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=10) { + $this->angle_fontfam = $aFontFam; + $this->angle_fontstyle = $aFontStyle; + $this->angle_fontsize = $aFontSize; + } + + function SetColor($aColor,$aRadColor='',$aAngleColor='') { + if( $aAngleColor == '' ) + $aAngleColor=$aColor; + parent::SetColor($aColor,$aRadColor); + $this->angle_fontcolor = $aAngleColor; + } + + function SetGridColor($aMajorColor,$aMinorColor='',$aAngleColor='') { + if( $aMinorColor == '' ) + $aMinorColor = $aMajorColor; + if( $aAngleColor == '' ) + $aAngleColor = $aMajorColor; + + $this->gridminor_color = $aMinorColor; + $this->gridmajor_color = $aMajorColor; + $this->angle_color = $aAngleColor; + } + + function SetTickColors($aRadColor,$aAngleColor='') { + $this->radius_tick_color = $aRadColor; + $this->angle_tick_color = $aAngleColor; + } + + // Private methods + function StrokeGrid($pos) { + $x = round($this->img->left_margin + $this->img->plotwidth/2); + $this->scale->ticks->Stroke($this->img,$this->scale,$pos); + + // Stroke the minor arcs + $pmin = array(); + $p = $this->scale->ticks->ticks_pos; + $n = count($p); + $i = 0; + $this->img->SetColor($this->gridminor_color); + while( $i < $n ) { + $r = $p[$i]-$x+1; + $pmin[]=$r; + if( $this->show_minor_grid ) { + $this->img->Circle($x,$pos,$r); + } + $i++; + } + + $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; + while( $r < $limit ) { + $off = $r; + $i=1; + $r = $off + round($p[$i]-$x+1); + while( $r < $limit && $i < $n ) { + $r = $off+$p[$i]-$x; + $pmin[]=$r; + if( $this->show_minor_grid ) { + $this->img->Circle($x,$pos,$r); + } + $i++; + } + } + + // Stroke the major arcs + if( $this->show_major_grid ) { + // First determine how many minor step on + // every major step. We have recorded the minor radius + // in pmin and use these values. This is done in order + // to avoid rounding errors if we were to recalculate the + // different major radius. + $pmaj = $this->scale->ticks->maj_ticks_pos; + $p = $this->scale->ticks->ticks_pos; + if( $this->scale->name == 'lin' ) { + $step=round(($pmaj[1] - $pmaj[0])/($p[1] - $p[0])); + } + else { + $step=9; + } + $n = round(count($pmin)/$step); + $i = 0; + $this->img->SetColor($this->gridmajor_color); + $limit = max($this->img->plotwidth,$this->img->plotheight)*1.4 ; + $off = $r; + $i=0; + $r = $pmin[$i*$step]; + while( $r < $limit && $i < $n ) { + $r = $pmin[$i*$step]; + $this->img->Circle($x,$pos,$r); + $i++; + } + } + + // Draw angles + if( $this->show_angle_grid ) { + $this->img->SetColor($this->angle_color); + $d = max($this->img->plotheight,$this->img->plotwidth)*1.4 ; + $a = 0; + $p = $this->scale->ticks->ticks_pos; + $start_radius = $p[1]-$x; + while( $a < 360 ) { + if( $a == 90 || $a == 270 ) { + // Make sure there are no rounding problem with + // exactly vertical lines + $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, + $pos-$start_radius*sin($a/180*M_PI), + $x+$start_radius*cos($a/180*M_PI)+1, + $pos-$d*sin($a/180*M_PI)); + + } + else { + $this->img->Line($x+$start_radius*cos($a/180*M_PI)+1, + $pos-$start_radius*sin($a/180*M_PI), + $x+$d*cos($a/180*M_PI), + $pos-$d*sin($a/180*M_PI)); + } + $a += $this->angle_step; + } + } + } + + function StrokeAngleLabels($pos,$type) { + + if( !$this->show_angle_label ) + return; + + $x0 = round($this->img->left_margin+$this->img->plotwidth/2)+1; + + $d = max($this->img->plotwidth,$this->img->plotheight)*1.42; + $a = $this->angle_step; + $t = new Text(); + $t->SetColor($this->angle_fontcolor); + $t->SetFont($this->angle_fontfam,$this->angle_fontstyle,$this->angle_fontsize); + $xright = $this->img->width - $this->img->right_margin; + $ytop = $this->img->top_margin; + $xleft = $this->img->left_margin; + $ybottom = $this->img->height - $this->img->bottom_margin; + $ha = 'left'; + $va = 'center'; + $w = $this->img->plotwidth/2; + $h = $this->img->plotheight/2; + $xt = $x0; $yt = $pos; + $margin=5; + + $tl = $this->angle_tick_len ; // Outer len + $tl2 = $this->angle_tick_len2 ; // Interior len + + $this->img->SetColor($this->angle_tick_color); + $rot90 = $this->img->a == 90 ; + + if( $type == POLAR_360 ) { + $ca1 = atan($h/$w)/M_PI*180; + $ca2 = 180-$ca1; + $ca3 = $ca1+180; + $ca4 = 360-$ca1; + $end = 360; + while( $a < $end ) { + $ca = cos($a/180*M_PI); + $sa = sin($a/180*M_PI); + $x = $d*$ca; + $y = $d*$sa; + $xt=1000;$yt=1000; + if( $a <= $ca1 || $a >= $ca4 ) { + $yt = $pos - $w * $y/$x; + $xt = $xright + $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'top'; + } + else { + $ha = 'left'; + $va = 'center'; + } + $x1=$xright-$tl2; $x2=$xright+$tl; + $y1=$y2=$yt; + } + elseif( $a > $ca1 && $a < $ca2 ) { + $xt = $x0 + $h * $x/$y; + $yt = $ytop - $margin; + if( $rot90 ) { + $ha = 'left'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'bottom'; + } + $y1=$ytop+$tl2;$y2=$ytop-$tl; + $x1=$x2=$xt; + } + elseif( $a >= $ca2 && $a <= $ca3 ) { + $yt = $pos + $w * $y/$x; + $xt = $xleft - $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'bottom'; + } + else { + $ha = 'right'; + $va = 'center'; + } + $x1=$xleft+$tl2;$x2=$xleft-$tl; + $y1=$y2=$yt; + } + else { + $xt = $x0 - $h * $x/$y; + $yt = $ybottom + $margin; + if( $rot90 ) { + $ha = 'right'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'top'; + } + $y1=$ybottom-$tl2;$y2=$ybottom+$tl; + $x1=$x2=$xt; + } + if( $a != 0 && $a != 180 ) { + $t->Align($ha,$va); + if( $this->show_angle_mark ) + $a .= ''; + $t->Set($a); + $t->Stroke($this->img,$xt,$yt); + if( $this->show_angle_tick ) + $this->img->Line($x1,$y1,$x2,$y2); + } + $a += $this->angle_step; + } + } + else { + // POLAR_HALF + $ca1 = atan($h/$w*2)/M_PI*180; + $ca2 = 180-$ca1; + $end = 180; + while( $a < $end ) { + $ca = cos($a/180*M_PI); + $sa = sin($a/180*M_PI); + $x = $d*$ca; + $y = $d*$sa; + if( $a <= $ca1 ) { + $yt = $pos - $w * $y/$x; + $xt = $xright + $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'top'; + } + else { + $ha = 'left'; + $va = 'center'; + } + $x1=$xright-$tl2; $x2=$xright+$tl; + $y1=$y2=$yt; + } + elseif( $a > $ca1 && $a < $ca2 ) { + $xt = $x0 + 2*$h * $x/$y; + $yt = $ytop - $margin; + if( $rot90 ) { + $ha = 'left'; + $va = 'center'; + } + else { + $ha = 'center'; + $va = 'bottom'; + } + $y1=$ytop+$tl2;$y2=$ytop-$tl; + $x1=$x2=$xt; + } + elseif( $a >= $ca2 ) { + $yt = $pos + $w * $y/$x; + $xt = $xleft - $margin; + if( $rot90 ) { + $ha = 'center'; + $va = 'bottom'; + } + else { + $ha = 'right'; + $va = 'center'; + } + $x1=$xleft+$tl2;$x2=$xleft-$tl; + $y1=$y2=$yt; + } + $t->Align($ha,$va); + if( $this->show_angle_mark ) + $a .= ''; + $t->Set($a); + $t->Stroke($this->img,$xt,$yt); + if( $this->show_angle_tick ) + $this->img->Line($x1,$y1,$x2,$y2); + $a += $this->angle_step; + } + } + } + + function Stroke($pos,$dummy=true) { + + $this->img->SetLineWeight($this->weight); + $this->img->SetColor($this->color); + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + if( !$this->hide_line ) + $this->img->FilledRectangle($this->img->left_margin,$pos, + $this->img->width-$this->img->right_margin,$pos+$this->weight-1); + $y=$pos+$this->img->GetFontHeight()+$this->title_margin+$this->title->margin; + if( $this->title_adjust=="high" ) + $this->title->SetPos($this->img->width-$this->img->right_margin,$y,"right","top"); + elseif( $this->title_adjust=="middle" || $this->title_adjust=="center" ) + $this->title->SetPos(($this->img->width-$this->img->left_margin- + $this->img->right_margin)/2+$this->img->left_margin, + $y,"center","top"); + elseif($this->title_adjust=="low") + $this->title->SetPos($this->img->left_margin,$y,"left","top"); + else { + JpGraphError::RaiseL(17002,$this->title_adjust); +//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); + } + + + if (!$this->hide_labels) { + $this->StrokeLabels($pos,false); + } + $this->img->SetColor($this->radius_tick_color); + $this->scale->ticks->Stroke($this->img,$this->scale,$pos); + + // + // Mirror the positions for the left side of the scale + // + $mid = 2*($this->img->left_margin+$this->img->plotwidth/2); + $n = count($this->scale->ticks->ticks_pos); + $i=0; + while( $i < $n ) { + $this->scale->ticks->ticks_pos[$i] = + $mid-$this->scale->ticks->ticks_pos[$i] ; + ++$i; + } + + $n = count($this->scale->ticks->maj_ticks_pos); + $i=0; + while( $i < $n ) { + $this->scale->ticks->maj_ticks_pos[$i] = + $mid-$this->scale->ticks->maj_ticks_pos[$i] ; + ++$i; + } + + $n = count($this->scale->ticks->maj_ticklabels_pos); + $i=1; + while( $i < $n ) { + $this->scale->ticks->maj_ticklabels_pos[$i] = + $mid-$this->scale->ticks->maj_ticklabels_pos[$i] ; + ++$i; + } + + // Draw the left side of the scale + $n = count($this->scale->ticks->ticks_pos); + $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMinTickAbsSize(); + + + // Minor ticks + if( ! $this->scale->ticks->supress_minor_tickmarks ) { + $i=1; + while( $i < $n/2 ) { + $x = round($this->scale->ticks->ticks_pos[$i]) ; + $this->img->Line($x,$pos,$x,$yu); + ++$i; + } + } + + $n = count($this->scale->ticks->maj_ticks_pos); + $yu = $pos - $this->scale->ticks->direction*$this->scale->ticks->GetMajTickAbsSize(); + + + // Major ticks + if( ! $this->scale->ticks->supress_tickmarks ) { + $i=1; + while( $i < $n/2 ) { + $x = round($this->scale->ticks->maj_ticks_pos[$i]) ; + $this->img->Line($x,$pos,$x,$yu); + ++$i; + } + } + if (!$this->hide_labels) { + $this->StrokeLabels($pos,false); + } + $this->title->Stroke($this->img); + } +} + +class PolarScale extends LinearScale { + private $graph; + + function PolarScale($aMax=0,$graph) { + parent::LinearScale(0,$aMax,'x'); + $this->graph = $graph; + } + + function _Translate($v) { + return parent::Translate($v); + } + + function PTranslate($aAngle,$aRad) { + + $m = $this->scale[1]; + $w = $this->graph->img->plotwidth/2; + $aRad = $aRad/$m*$w; + + $x = cos( $aAngle/180 * M_PI ) * $aRad; + $y = sin( $aAngle/180 * M_PI ) * $aRad; + + $x += $this->_Translate(0); + + if( $this->graph->iType == POLAR_360 ) { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; + } + else { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; + } + return array($x,$y); + } +} + +class PolarLogScale extends LogScale { + private $graph; + function PolarLogScale($aMax=1,$graph) { + parent::LogScale(0,$aMax,'x'); + $this->graph = $graph; + $this->ticks->SetLabelLogType(LOGLABELS_MAGNITUDE); + + } + + function PTranslate($aAngle,$aRad) { + + if( $aRad == 0 ) + $aRad = 1; + $aRad = log10($aRad); + $m = $this->scale[1]; + $w = $this->graph->img->plotwidth/2; + $aRad = $aRad/$m*$w; + + $x = cos( $aAngle/180 * M_PI ) * $aRad; + $y = sin( $aAngle/180 * M_PI ) * $aRad; + + $x += $w+$this->graph->img->left_margin;//$this->_Translate(0); + if( $this->graph->iType == POLAR_360 ) { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight/2) - $y; + } + else { + $y = ($this->graph->img->top_margin + $this->graph->img->plotheight) - $y; + } + return array($x,$y); + } +} + +class PolarGraph extends Graph { + public $scale; + public $axis; + public $iType=POLAR_360; + + function PolarGraph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { + parent::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline) ; + $this->SetDensity(TICKD_DENSE); + $this->SetBox(); + $this->SetMarginColor('white'); + } + + function SetDensity($aDense) { + $this->SetTickDensity(TICKD_NORMAL,$aDense); + } + + function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { + $adj = ($this->img->height - $this->img->width)/2; + $this->SetAngle(90); + $this->img->SetMargin($lm-$adj,$rm-$adj,$tm+$adj,$bm+$adj); + $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2)); + $this->axis->SetLabelAlign('right','center'); + //JpGraphError::Raise('Set90AndMargin() is not supported for polar graphs.'); + } + + function SetScale($aScale,$rmax=0,$dummy1=1,$dummy2=1,$dummy3=1) { + if( $aScale == 'lin' ) + $this->scale = new PolarScale($rmax,$this); + elseif( $aScale == 'log' ) { + $this->scale = new PolarLogScale($rmax,$this); + } + else { + JpGraphError::RaiseL(17004);//('Unknown scale type for polar graph. Must be "lin" or "log"'); + } + + $this->axis = new PolarAxis($this->img,$this->scale); + $this->SetMargin(40,40,50,40); + } + + function SetType($aType) { + $this->iType = $aType; + } + + function SetPlotSize($w,$h) { + $this->SetMargin(($this->img->width-$w)/2,($this->img->width-$w)/2, + ($this->img->height-$h)/2,($this->img->height-$h)/2); + } + + // Private methods + function GetPlotsMax() { + $n = count($this->plots); + $m = $this->plots[0]->Max(); + $i=1; + while($i < $n) { + $m = max($this->plots[$i]->Max(),$m); + ++$i; + } + return $m; + } + + function Stroke($aStrokeFileName="") { + + // Start by adjusting the margin so that potential titles will fit. + $this->AdjustMarginsForTitles(); + + // If the filename is the predefined value = '_csim_special_' + // we assume that the call to stroke only needs to do enough + // to correctly generate the CSIM maps. + // We use this variable to skip things we don't strictly need + // to do to generate the image map to improve performance + // a best we can. Therefor you will see a lot of tests !$_csim in the + // code below. + $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); + + // We need to know if we have stroked the plot in the + // GetCSIMareas. Otherwise the CSIM hasn't been generated + // and in the case of GetCSIM called before stroke to generate + // CSIM without storing an image to disk GetCSIM must call Stroke. + $this->iHasStroked = true; + + //Check if we should autoscale axis + if( !$this->scale->IsSpecified() && count($this->plots)>0 ) { + $max = $this->GetPlotsMax(); + $t1 = $this->img->plotwidth; + $this->img->plotwidth /= 2; + $t2 = $this->img->left_margin; + $this->img->left_margin += $this->img->plotwidth+1; + $this->scale->AutoScale($this->img,0,$max, + $this->img->plotwidth/$this->xtick_factor/2); + $this->img->plotwidth = $t1; + $this->img->left_margin = $t2; + } + else { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + //$min = 0; + $max = $this->scale->scale[1]; + $t1 = $this->img->plotwidth; + $this->img->plotwidth /= 2; + $t2 = $this->img->left_margin; + $this->img->left_margin += $this->img->plotwidth+1; + $this->scale->AutoScale($this->img,0,$max, + $this->img->plotwidth/$this->xtick_factor/2); + $this->img->plotwidth = $t1; + $this->img->left_margin = $t2; + } + + if( $this->iType == POLAR_180 ) + $pos = $this->img->height - $this->img->bottom_margin; + else + $pos = $this->img->plotheight/2 + $this->img->top_margin; + + + if( !$_csim ) { + $this->StrokePlotArea(); + } + + $this->iDoClipping = true; + + if( $this->iDoClipping ) { + $oldimage = $this->img->CloneCanvasH(); + } + + if( !$_csim ) { + $this->axis->StrokeGrid($pos); + } + + // Stroke all plots for Y1 axis + for($i=0; $i < count($this->plots); ++$i) { + $this->plots[$i]->Stroke($this->img,$this->scale); + } + + + if( $this->iDoClipping ) { + // Clipping only supports graphs at 0 and 90 degrees + if( $this->img->a == 0 ) { + $this->img->CopyCanvasH($oldimage,$this->img->img, + $this->img->left_margin,$this->img->top_margin, + $this->img->left_margin,$this->img->top_margin, + $this->img->plotwidth+1,$this->img->plotheight+1); + } + elseif( $this->img->a == 90 ) { + $adj = round(($this->img->height - $this->img->width)/2); + $this->img->CopyCanvasH($oldimage,$this->img->img, + $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, + $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, + $this->img->plotheight,$this->img->plotwidth); + } + $this->img->Destroy(); + $this->img->SetCanvasH($oldimage); + } + + if( !$_csim ) { + $this->axis->Stroke($pos); + $this->axis->StrokeAngleLabels($pos,$this->iType); + } + + if( !$_csim ) { + $this->StrokePlotBox(); + $this->footer->Stroke($this->img); + + // The titles and legends never gets rotated so make sure + // that the angle is 0 before stroking them + $aa = $this->img->SetAngle(0); + $this->StrokeTitles(); + } + + for($i=0; $i < count($this->plots) ; ++$i ) { + $this->plots[$i]->Legend($this); + } + + $this->legend->Stroke($this->img); + + if( !$_csim ) { + + $this->StrokeTexts(); + $this->img->SetAngle($aa); + + // Draw an outline around the image map + if(_JPG_DEBUG) + $this->DisplayClientSideaImageMapAreas(); + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, + $aStrokeFileName); + } + } + } +} + + + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php new file mode 100644 index 0000000..1ba1be9 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_radar.php @@ -0,0 +1,732 @@ +GetMinVal(); + $limit = $aScale->GetMaxVal(); + $nextMajor = 10*$start; + $step = $nextMajor / 10.0; + $count=1; + + $ticklen_maj=5; + $dx_maj=round(sin($aAxisAngle)*$ticklen_maj); + $dy_maj=round(cos($aAxisAngle)*$ticklen_maj); + $ticklen_min=3; + $dx_min=round(sin($aAxisAngle)*$ticklen_min); + $dy_min=round(cos($aAxisAngle)*$ticklen_min); + + $aMajPos=array(); + $aMajLabel=array(); + + if( $this->supress_first ) + $aMajLabel[]=""; + else + $aMajLabel[]=$start; + $yr=$aScale->RelTranslate($start); + $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($yr*sin($aAxisAngle)); + $aMajPos[]=$xt+2*$dx_maj; + $aMajPos[]=$yt-$aImg->GetFontheight()/2; + $grid[]=$xt; + $grid[]=$yt; + + $aImg->SetLineWeight($this->weight); + + for($y=$start; $y<=$limit; $y+=$step,++$count ) { + $yr=$aScale->RelTranslate($y); + $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($yr*sin($aAxisAngle)); + if( $count % 10 == 0 ) { + $grid[]=$xt; + $grid[]=$yt; + $aMajPos[]=$xt+2*$dx_maj; + $aMajPos[]=$yt-$aImg->GetFontheight()/2; + if( !$this->supress_tickmarks ) { + if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); + $aImg->Line($xt+$dx_maj,$yt+$dy_maj,$xt-$dx_maj,$yt-$dy_maj); + if( $this->majcolor!="" ) $aImg->PopColor(); + } + if( $this->label_formfunc != "" ) { + $f=$this->label_formfunc; + $l = call_user_func($f,$nextMajor); + } + else + $l = $nextMajor; + + $aMajLabel[]=$l; + $nextMajor *= 10; + $step *= 10; + $count=1; + } + else + if( !$this->supress_minor_tickmarks ) { + if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); + $aImg->Line($xt+$dx_min,$yt+$dy_min,$xt-$dx_min,$yt-$dy_min); + if( $this->mincolor!="" ) $aImg->PopColor(); + } + } + } +} + +class RadarLinearTicks extends Ticks { + + private $minor_step=1, $major_step=2; + private $xlabel_offset=0,$xtick_offset=0; + +//--------------- +// CONSTRUCTOR + function RadarLinearTicks() { + // Empty + } + +//--------------- +// PUBLIC METHODS + + + // Return major step size in world coordinates + function GetMajor() { + return $this->major_step; + } + + // Return minor step size in world coordinates + function GetMinor() { + return $this->minor_step; + } + + // Set Minor and Major ticks (in world coordinates) + function Set($aMajStep,$aMinStep=false) { + if( $aMinStep==false ) + $aMinStep=$aMajStep; + + if( $aMajStep <= 0 || $aMinStep <= 0 ) { + JpGraphError::Raise(" Minor or major step size is 0. Check that you haven't + got an accidental SetTextTicks(0) in your code.

    + If this is not the case you might have stumbled upon a bug in JpGraph. + Please report this and if possible include the data that caused the + problem."); + } + + $this->major_step=$aMajStep; + $this->minor_step=$aMinStep; + $this->is_set = true; + } + + function Stroke($aImg,&$grid,$aPos,$aAxisAngle,$aScale,&$aMajPos,&$aMajLabel) { + // Prepare to draw linear ticks + $maj_step_abs = abs($aScale->scale_factor*$this->major_step); + $min_step_abs = abs($aScale->scale_factor*$this->minor_step); + $nbrmaj = floor(($aScale->world_abs_size)/$maj_step_abs); + $nbrmin = floor(($aScale->world_abs_size)/$min_step_abs); + $skip = round($nbrmin/$nbrmaj); // Don't draw minor ontop of major + + // Draw major ticks + $ticklen2=$this->major_abs_size; + $dx=round(sin($aAxisAngle)*$ticklen2); + $dy=round(cos($aAxisAngle)*$ticklen2); + $label=$aScale->scale[0]+$this->major_step; + + $aImg->SetLineWeight($this->weight); + // NEW + $aMajPos = array(); + $aMajLabel = array(); + for($i=1; $i<=$nbrmaj; ++$i) { + $xt=round($i*$maj_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($i*$maj_step_abs*sin($aAxisAngle)); + + if( $this->label_formfunc != "" ) { + $f=$this->label_formfunc; + $l = call_user_func($f,$label); + } + else + $l = $label; + + $aMajLabel[]=$l; + $label += $this->major_step; + $grid[]=$xt; + $grid[]=$yt; + $aMajPos[($i-1)*2]=$xt+2*$dx; + $aMajPos[($i-1)*2+1]=$yt-$aImg->GetFontheight()/2; + if( !$this->supress_tickmarks ) { + if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); + $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); + if( $this->majcolor!="" ) $aImg->PopColor(); + } + } + + // Draw minor ticks + $ticklen2=$this->minor_abs_size; + $dx=round(sin($aAxisAngle)*$ticklen2); + $dy=round(cos($aAxisAngle)*$ticklen2); + if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { + if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); + for($i=1; $i<=$nbrmin; ++$i) { + if( ($i % $skip) == 0 ) continue; + $xt=round($i*$min_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0]; + $yt=$aPos-round($i*$min_step_abs*sin($aAxisAngle)); + $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy); + } + if( $this->mincolor!="" ) $aImg->PopColor(); + } + } +} + + + +//=================================================== +// CLASS RadarAxis +// Description: Implements axis for the radar graph +//=================================================== +class RadarAxis extends AxisPrototype { + public $title=null; + private $title_color="navy"; + private $len=0; +//--------------- +// CONSTRUCTOR + function RadarAxis($img,$aScale,$color=array(0,0,0)) { + parent::Axis($img,$aScale,$color); + $this->len=$img->plotheight; + $this->title = new Text(); + $this->title->SetFont(FF_FONT1,FS_BOLD); + $this->color = array(0,0,0); + } +//--------------- +// PUBLIC METHODS + function SetTickLabels($aLabelArray,$aLabelColorArray=null) { + $this->ticks_label = $aLabelArray; + $this->ticks_label_colors = $aLabelColorArray; + } + + + // Stroke the axis + // $pos = Vertical position of axis + // $aAxisAngle = Axis angle + // $grid = Returns an array with positions used to draw the grid + // $lf = Label flag, TRUE if the axis should have labels + function Stroke($pos,$aAxisAngle,&$grid,$title,$lf) { + $this->img->SetColor($this->color); + + // Determine end points for the axis + $x=round($this->scale->world_abs_size*cos($aAxisAngle)+$this->scale->scale_abs[0]); + $y=round($pos-$this->scale->world_abs_size*sin($aAxisAngle)); + + // Draw axis + $this->img->SetColor($this->color); + $this->img->SetLineWeight($this->weight); + if( !$this->hide ) + $this->img->Line($this->scale->scale_abs[0],$pos,$x,$y); + + $this->scale->ticks->Stroke($this->img,$grid,$pos,$aAxisAngle,$this->scale,$majpos,$majlabel); + $ncolor=0; + if( isset($this->ticks_label_colors) ) + $ncolor=count($this->ticks_label_colors); + + // Draw labels + if( $lf && !$this->hide ) { + $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); + $this->img->SetTextAlign("left","top"); + $this->img->SetColor($this->label_color); + + // majpos contains (x,y) coordinates for labels + if( ! $this->hide_labels ) { + $n = floor(count($majpos)/2); + for($i=0; $i < $n; ++$i) { + // Set specific label color if specified + if( $ncolor > 0 ) + $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); + + if( $this->ticks_label != null && isset($this->ticks_label[$i]) ) + $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$this->ticks_label[$i]); + else + $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$majlabel[$i]); + } + } + } + $this->_StrokeAxisTitle($pos,$aAxisAngle,$title); + } +//--------------- +// PRIVATE METHODS + + function _StrokeAxisTitle($pos,$aAxisAngle,$title) { + $this->title->Set($title); + $marg=6+$this->title->margin; + $xt=round(($this->scale->world_abs_size+$marg)*cos($aAxisAngle)+$this->scale->scale_abs[0]); + $yt=round($pos-($this->scale->world_abs_size+$marg)*sin($aAxisAngle)); + + // Position the axis title. + // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text + // that intersects with the extension of the corresponding axis. The code looks a little + // bit messy but this is really the only way of having a reasonable position of the + // axis titles. + if( $this->title->iWordwrap > 0 ) { + $title = wordwrap($title,$this->title->iWordwrap,"\n"); + } + + $h=$this->img->GetTextHeight($title)*1.2; + $w=$this->img->GetTextWidth($title)*1.2; + + while( $aAxisAngle > 2*M_PI ) $aAxisAngle -= 2*M_PI; + + // Around 3 a'clock + if( $aAxisAngle>=7*M_PI/4 || $aAxisAngle <= M_PI/4 ) $dx=-0.15; // Small trimming to make the dist to the axis more even + // Around 12 a'clock + if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dx=($aAxisAngle-M_PI/4)*2/M_PI; + // Around 9 a'clock + if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dx=1; + // Around 6 a'clock + if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dx=(1-($aAxisAngle-M_PI*5/4)*2/M_PI); + + if( $aAxisAngle>=7*M_PI/4 ) $dy=(($aAxisAngle-M_PI)-3*M_PI/4)*2/M_PI; + if( $aAxisAngle<=M_PI/12 ) $dy=(0.5-$aAxisAngle*2/M_PI); + if( $aAxisAngle<=M_PI/4 && $aAxisAngle > M_PI/12) $dy=(1-$aAxisAngle*2/M_PI); + if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dy=1; + if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dy=(1-($aAxisAngle-3*M_PI/4)*2/M_PI); + if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dy=0; + + if( !$this->hide ) { + $this->title->Stroke($this->img,$xt-$dx*$w,$yt-$dy*$h,$title); + } + } + + +} // Class + + +//=================================================== +// CLASS RadarGrid +// Description: Draws grid for the radar graph +//=================================================== +class RadarGrid { //extends Grid { + private $type='solid'; + private $grid_color='#DDDDDD'; + private $show=false, $weight=1; + +//------------ +// CONSTRUCTOR + function RadarGrid() { + } + +// PUBLIC METHODS + function SetColor($aMajColor) { + $this->grid_color = $aMajColor; + } + + function SetWeight($aWeight) { + $this->weight=$aWeight; + } + + // Specify if grid should be dashed, dotted or solid + function SetLineStyle($aType) { + $this->type = $aType; + } + + // Decide if both major and minor grid should be displayed + function Show($aShowMajor=true) { + $this->show=$aShowMajor; + } + +//---------------- +// PRIVATE METHODS + function Stroke($img,$grid) { + if( !$this->show ) return; + $nbrticks = count($grid[0])/2; + $nbrpnts = count($grid); + $img->SetColor($this->grid_color); + $img->SetLineWeight($this->weight); + for($i=0; $i<$nbrticks; ++$i) { + for($j=0; $j<$nbrpnts; ++$j) { + $pnts[$j*2]=$grid[$j][$i*2]; + $pnts[$j*2+1]=$grid[$j][$i*2+1]; + } + for($k=0; $k<$nbrpnts; ++$k ){ + $l=($k+1)%$nbrpnts; + if( $this->type == "solid" ) + $img->Line($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1]); + elseif( $this->type == "dotted" ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],1,6); + elseif( $this->type == "dashed" ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],2,4); + elseif( $this->type == "longdashed" ) + $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],8,6); + } + $pnts=array(); + } + } +} // Class + + +//=================================================== +// CLASS RadarPlot +// Description: Plot a radarplot +//=================================================== +class RadarPlot { + public $mark=null; + public $legend=""; + private $data=array(); + private $fill=false, $fill_color=array(200,170,180); + private $color=array(0,0,0); + private $weight=1; + private $linestyle='solid'; +//--------------- +// CONSTRUCTOR + function RadarPlot($data) { + $this->data = $data; + $this->mark = new PlotMark(); + } + +//--------------- +// PUBLIC METHODS + function Min() { + return Min($this->data); + } + + function Max() { + return Max($this->data); + } + + function SetLegend($legend) { + $this->legend=$legend; + } + + function SetLineStyle($aStyle) { + $this->linestyle=$aStyle; + } + + function SetLineWeight($w) { + $this->weight=$w; + } + + function SetFillColor($aColor) { + $this->fill_color = $aColor; + $this->fill = true; + } + + function SetFill($f=true) { + $this->fill = $f; + } + + function SetColor($aColor,$aFillColor=false) { + $this->color = $aColor; + if( $aFillColor ) { + $this->SetFillColor($aFillColor); + $this->fill = true; + } + } + + function GetCSIMareas() { + JpGraphError::RaiseL(18001); +//("Client side image maps not supported for RadarPlots."); + } + + function Stroke($img, $pos, $scale, $startangle) { + $nbrpnts = count($this->data); + $astep=2*M_PI/$nbrpnts; + $a=$startangle; + + // Rotate each point to the correct axis-angle + // TODO: Update for LogScale + for($i=0; $i<$nbrpnts; ++$i) { + //$c=$this->data[$i]; + $cs=$scale->RelTranslate($this->data[$i]); + $x=round($cs*cos($a)+$scale->scale_abs[0]); + $y=round($pos-$cs*sin($a)); + /* + $c=log10($c); + $x=round(($c-$scale->scale[0])*$scale->scale_factor*cos($a)+$scale->scale_abs[0]); + $y=round($pos-($c-$scale->scale[0])*$scale->scale_factor*sin($a)); + */ + $pnts[$i*2]=$x; + $pnts[$i*2+1]=$y; + $a += $astep; + } + if( $this->fill ) { + $img->SetColor($this->fill_color); + $img->FilledPolygon($pnts); + } + $img->SetLineWeight($this->weight); + $img->SetColor($this->color); + $img->SetLineStyle($this->linestyle); + $pnts[]=$pnts[0]; + $pnts[]=$pnts[1]; + $img->Polygon($pnts); + $img->SetLineStyle('solid'); // Reset line style to default + // Add plotmarks on top + if( $this->mark->show ) { + for($i=0; $i < $nbrpnts; ++$i) { + $this->mark->Stroke($img,$pnts[$i*2],$pnts[$i*2+1]); + } + } + + } + +//--------------- +// PRIVATE METHODS + function GetCount() { + return count($this->data); + } + + function Legend($graph) { + if( $this->legend=="" ) return; + if( $this->fill ) + $graph->legend->Add($this->legend,$this->fill_color,$this->mark); + else + $graph->legend->Add($this->legend,$this->color,$this->mark); + } + +} // Class + +//=================================================== +// CLASS RadarGraph +// Description: Main container for a radar graph +//=================================================== +class RadarGraph extends Graph { + public $grid,$axis=null; + private $posx,$posy; + private $len; + private $axis_title=null; +//--------------- +// CONSTRUCTOR + function RadarGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) { + $this->Graph($width,$height,$cachedName,$timeout,$inline); + $this->posx=$width/2; + $this->posy=$height/2; + $this->len=min($width,$height)*0.35; + $this->SetColor(array(255,255,255)); + $this->SetTickDensity(TICKD_NORMAL); + $this->SetScale("lin"); + $this->SetGridDepth(DEPTH_FRONT); + + } + +//--------------- +// PUBLIC METHODS + function SupressTickMarks($f=true) { + if( ERR_DEPRECATED ) + JpGraphError::RaiseL(18002); +//('RadarGraph::SupressTickMarks() is deprecated. Use HideTickMarks() instead.'); + $this->axis->scale->ticks->SupressTickMarks($f); + } + + function HideTickMarks($aFlag=true) { + $this->axis->scale->ticks->SupressTickMarks($aFlag); + } + + function ShowMinorTickmarks($aFlag=true) { + $this->yscale->ticks->SupressMinorTickMarks(!$aFlag); + } + + function SetScale($axtype,$ymin=1,$ymax=1,$dummy1=null,$dumy2=null) { + if( $axtype != "lin" && $axtype != "log" ) { + JpGraphError::RaiseL(18003,$axtype); +//("Illegal scale for radarplot ($axtype). Must be \"lin\" or \"log\""); + } + if( $axtype=="lin" ) { + $this->yscale = new LinearScale($ymin,$ymax); + $this->yscale->ticks = new RadarLinearTicks(); + $this->yscale->ticks->SupressMinorTickMarks(); + } + elseif( $axtype=="log" ) { + $this->yscale = new LogScale($ymin,$ymax); + $this->yscale->ticks = new RadarLogTicks(); + } + + $this->axis = new RadarAxis($this->img,$this->yscale); + $this->grid = new RadarGrid(); + } + + function SetSize($aSize) { + if( $aSize < 0.1 || $aSize>1 ) + JpGraphError::RaiseL(18004,$aSize); +//("Radar Plot size must be between 0.1 and 1. (Your value=$s)"); + $this->len=min($this->img->width,$this->img->height)*$aSize/2; + } + + function SetPlotSize($aSize) { + $this->SetSize($aSize); + } + + function SetTickDensity($densy=TICKD_NORMAL,$dummy1=null) { + $this->ytick_factor=25; + switch( $densy ) { + case TICKD_DENSE: + $this->ytick_factor=12; + break; + case TICKD_NORMAL: + $this->ytick_factor=25; + break; + case TICKD_SPARSE: + $this->ytick_factor=40; + break; + case TICKD_VERYSPARSE: + $this->ytick_factor=70; + break; + default: + JpGraphError::RaiseL(18005,$densy); +//("RadarPlot Unsupported Tick density: $densy"); + } + } + + function SetPos($px,$py=0.5) { + $this->SetCenter($px,$py); + } + + function SetCenter($px,$py=0.5) { + assert($px > 0 && $py > 0 ); + $this->posx=$this->img->width*$px; + $this->posy=$this->img->height*$py; + } + + function SetColor($c) { + $this->SetMarginColor($c); + } + + function SetTitles($title) { + $this->axis_title = $title; + } + + function Add($splot) { + $this->plots[]=$splot; + } + + function GetPlotsYMinMax($aPlots) { + $min=$aPlots[0]->Min(); + $max=$aPlots[0]->Max(); + foreach( $this->plots as $p ) { + $max=max($max,$p->Max()); + $min=min($min,$p->Min()); + } + if( $min < 0 ) + JpGraphError::RaiseL(18006,$min); +//("Minimum data $min (Radar plots should only be used when all data points > 0)"); + return array($min,$max); + } + + // Stroke the Radar graph + function Stroke($aStrokeFileName="") { + $n = count($this->plots); + // Set Y-scale + if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { + list($min,$max) = $this->GetPlotsYMinMax($this->plots); + $this->yscale->AutoScale($this->img,0,$max,$this->len/$this->ytick_factor); + } + elseif( $this->yscale->IsSpecified() && + ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { + // The tick calculation will use the user suplied min/max values to determine + // the ticks. If auto_ticks is false the exact user specifed min and max + // values will be used for the scale. + // If auto_ticks is true then the scale might be slightly adjusted + // so that the min and max values falls on an even major step. + $min = $this->yscale->scale[0]; + $max = $this->yscale->scale[1]; + $this->yscale->AutoScale($this->img,$min,$max, + $this->len/$this->ytick_factor, + $this->yscale->auto_ticks); + } + + // Set start position end length of scale (in absolute pixels) + $this->yscale->SetConstants($this->posx,$this->len); + + // We need as many axis as there are data points + $nbrpnts=$this->plots[0]->GetCount(); + + // If we have no titles just number the axis 1,2,3,... + if( $this->axis_title==null ) { + for($i=0; $i < $nbrpnts; ++$i ) + $this->axis_title[$i] = $i+1; + } + elseif(count($this->axis_title)<$nbrpnts) + JpGraphError::RaiseL(18007); +//("Number of titles does not match number of points in plot."); + for($i=0; $i < $n; ++$i ) + if( $nbrpnts != $this->plots[$i]->GetCount() ) + JpGraphError::RaiseL(18008); +//("Each radar plot must have the same number of data points."); + + if( $this->background_image != "" ) { + $this->StrokeFrameBackground(); + } + else { + $this->StrokeFrame(); + } + $astep=2*M_PI/$nbrpnts; + + // Prepare legends + for($i=0; $i < $n; ++$i) + $this->plots[$i]->Legend($this); + $this->legend->Stroke($this->img); + $this->footer->Stroke($this->img); + + if( $this->grid_depth == DEPTH_BACK ) { + // Draw axis and grid + for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { + $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); + } + } + + // Plot points + $a=M_PI/2; + for($i=0; $i < $n; ++$i ) + $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a); + + if( $this->grid_depth != DEPTH_BACK ) { + // Draw axis and grid + for( $i=0,$a=M_PI/2; $i < $nbrpnts; ++$i, $a += $astep ) { + $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0); + } + } + $this->grid->Stroke($this->img,$grid); + $this->StrokeTitles(); + + // Stroke texts + if( $this->texts != null ) { + foreach( $this->texts as $t) + $t->Stroke($this->img); + } + + // Should we do any final image transformation + if( $this->iImgTrans ) { + if( !class_exists('ImgTrans',false) ) { + require_once('jpgraph_imgtrans.php'); + } + + $tform = new ImgTrans($this->img->img); + $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, + $this->iImgTransDirection,$this->iImgTransHighQ, + $this->iImgTransMinSize,$this->iImgTransFillColor, + $this->iImgTransBorder); + } + + // If the filename is given as the special "__handle" + // then the image handler is returned and the image is NOT + // streamed back + if( $aStrokeFileName == _IMG_HANDLER ) { + return $this->img->img; + } + else { + // Finally stream the generated picture + $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline, + $aStrokeFileName); + } + } +} // Class + +/* EOF */ +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_regstat.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_regstat.php new file mode 100644 index 0000000..4620975 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_regstat.php @@ -0,0 +1,202 @@ +y2 = array(); + $this->xdata = $xdata; + $this->ydata = $ydata; + + $n = count($ydata); + $this->n = $n; + if( $this->n !== count($xdata) ) { + JpGraphError::RaiseL(19001); +//('Spline: Number of X and Y coordinates must be the same'); + } + + // Natural spline 2:derivate == 0 at endpoints + $this->y2[0] = 0.0; + $this->y2[$n-1] = 0.0; + $delta[0] = 0.0; + + // Calculate 2:nd derivate + for($i=1; $i < $n-1; ++$i) { + $d = ($xdata[$i+1]-$xdata[$i-1]); + if( $d == 0 ) { + JpGraphError::RaiseL(19002); +//('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); + } + $s = ($xdata[$i]-$xdata[$i-1])/$d; + $p = $s*$this->y2[$i-1]+2.0; + $this->y2[$i] = ($s-1.0)/$p; + $delta[$i] = ($ydata[$i+1]-$ydata[$i])/($xdata[$i+1]-$xdata[$i]) - + ($ydata[$i]-$ydata[$i-1])/($xdata[$i]-$xdata[$i-1]); + $delta[$i] = (6.0*$delta[$i]/($xdata[$i+1]-$xdata[$i-1])-$s*$delta[$i-1])/$p; + } + + // Backward substitution + for( $j=$n-2; $j >= 0; --$j ) { + $this->y2[$j] = $this->y2[$j]*$this->y2[$j+1] + $delta[$j]; + } + } + + // Return the two new data vectors + function Get($num=50) { + $n = $this->n ; + $step = ($this->xdata[$n-1]-$this->xdata[0]) / ($num-1); + $xnew=array(); + $ynew=array(); + $xnew[0] = $this->xdata[0]; + $ynew[0] = $this->ydata[0]; + for( $j=1; $j < $num; ++$j ) { + $xnew[$j] = $xnew[0]+$j*$step; + $ynew[$j] = $this->Interpolate($xnew[$j]); + } + return array($xnew,$ynew); + } + + // Return a single interpolated Y-value from an x value + function Interpolate($xpoint) { + + $max = $this->n-1; + $min = 0; + + // Binary search to find interval + while( $max-$min > 1 ) { + $k = ($max+$min) / 2; + if( $this->xdata[$k] > $xpoint ) + $max=$k; + else + $min=$k; + } + + // Each interval is interpolated by a 3:degree polynom function + $h = $this->xdata[$max]-$this->xdata[$min]; + + if( $h == 0 ) { + JpGraphError::RaiseL(19002); +//('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.'); + } + + + $a = ($this->xdata[$max]-$xpoint)/$h; + $b = ($xpoint-$this->xdata[$min])/$h; + return $a*$this->ydata[$min]+$b*$this->ydata[$max]+ + (($a*$a*$a-$a)*$this->y2[$min]+($b*$b*$b-$b)*$this->y2[$max])*($h*$h)/6.0; + } +} + +//------------------------------------------------------------------------ +// CLASS Bezier +// Create a new data array from a number of control points +//------------------------------------------------------------------------ +class Bezier { +/** + * @author Thomas Despoix, openXtrem company + * @license released under QPL + * @abstract Bezier interoplated point generation, + * computed from control points data sets, based on Paul Bourke algorithm : + * http://astronomy.swin.edu.au/~pbourke/curves/bezier/ + */ + private $datax = array(); + private $datay = array(); + private $n=0; + + function Bezier($datax, $datay, $attraction_factor = 1) { + // Adding control point multiple time will raise their attraction power over the curve + $this->n = count($datax); + if( $this->n !== count($datay) ) { + JpGraphError::RaiseL(19003); +//('Bezier: Number of X and Y coordinates must be the same'); + } + $idx=0; + foreach($datax as $datumx) { + for ($i = 0; $i < $attraction_factor; $i++) { + $this->datax[$idx++] = $datumx; + } + } + $idx=0; + foreach($datay as $datumy) { + for ($i = 0; $i < $attraction_factor; $i++) { + $this->datay[$idx++] = $datumy; + } + } + $this->n *= $attraction_factor; + } + + function Get($steps) { + $datax = array(); + $datay = array(); + for ($i = 0; $i < $steps; $i++) { + list($datumx, $datumy) = $this->GetPoint((double) $i / (double) $steps); + $datax[] = $datumx; + $datay[] = $datumy; + } + + $datax[] = end($this->datax); + $datay[] = end($this->datay); + + return array($datax, $datay); + } + + function GetPoint($mu) { + $n = $this->n - 1; + $k = 0; + $kn = 0; + $nn = 0; + $nkn = 0; + $blend = 0.0; + $newx = 0.0; + $newy = 0.0; + + $muk = 1.0; + $munk = (double) pow(1-$mu,(double) $n); + + for ($k = 0; $k <= $n; $k++) { + $nn = $n; + $kn = $k; + $nkn = $n - $k; + $blend = $muk * $munk; + $muk *= $mu; + $munk /= (1-$mu); + while ($nn >= 1) { + $blend *= $nn; + $nn--; + if ($kn > 1) { + $blend /= (double) $kn; + $kn--; + } + if ($nkn > 1) { + $blend /= (double) $nkn; + $nkn--; + } + } + $newx += $this->datax[$k] * $blend; + $newy += $this->datay[$k] * $blend; + } + + return array($newx, $newy); + } +} + +// EOF +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_scatter.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_scatter.php new file mode 100644 index 0000000..1e3908d --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_scatter.php @@ -0,0 +1,231 @@ +iSize = $aSize; + $this->iArrowSize = $aArrowSize; + } + + function SetColor($aColor) { + $this->iColor = $aColor; + } + + function Stroke($aImg,$x,$y,$a) { + // First rotate the center coordinates + list($x,$y) = $aImg->Rotate($x,$y); + + $old_origin = $aImg->SetCenter($x,$y); + $old_a = $aImg->a; + $aImg->SetAngle(-$a+$old_a); + + $dx = round($this->iSize/2); + $c = array($x-$dx,$y,$x+$dx,$y); + $x += $dx; + + list($dx,$dy) = $this->isizespec[$this->iArrowSize]; + $ca = array($x,$y,$x-$dx,$y-$dy,$x-$dx,$y+$dy,$x,$y); + + $aImg->SetColor($this->iColor); + $aImg->Polygon($c); + $aImg->FilledPolygon($ca); + + $aImg->SetCenter($old_origin[0],$old_origin[1]); + $aImg->SetAngle($old_a); + } +} + +//=================================================== +// CLASS FieldPlot +// Description: Render a field plot +//=================================================== +class FieldPlot extends Plot { + public $arrow = ''; + private $iAngles = array(); + private $iCallback = ''; + + function FieldPlot($datay,$datax,$angles) { + if( (count($datax) != count($datay)) ) + JpGraphError::RaiseL(20001);//("Fieldplots must have equal number of X and Y points."); + if( (count($datax) != count($angles)) ) + JpGraphError::RaiseL(20002);//("Fieldplots must have an angle specified for each X and Y points."); + + $this->iAngles = $angles; + + $this->Plot($datay,$datax); + $this->value->SetAlign('center','center'); + $this->value->SetMargin(15); + + $this->arrow = new FieldArrow(); + } + + function SetCallback($aFunc) { + $this->iCallback = $aFunc; + } + + function Stroke($img,$xscale,$yscale) { + + // Remeber base color and size + $bc = $this->arrow->iColor; + $bs = $this->arrow->iSize; + $bas = $this->arrow->iArrowSize; + + for( $i=0; $i<$this->numpoints; ++$i ) { + // Skip null values + if( $this->coords[0][$i]==="" ) + continue; + + $f = $this->iCallback; + if( $f != "" ) { + list($cc,$cs,$cas) = call_user_func($f,$this->coords[1][$i],$this->coords[0][$i],$this->iAngles[$i]); + // Fall back on global data if the callback isn't set + if( $cc == "" ) $cc = $bc; + if( $cs == "" ) $cs = $bs; + if( $cas == "" ) $cas = $bas; + $this->arrow->SetColor($cc); + $this->arrow->SetSize($cs,$cas); + } + + $xt = $xscale->Translate($this->coords[1][$i]); + $yt = $yscale->Translate($this->coords[0][$i]); + + $this->arrow->Stroke($img,$xt,$yt,$this->iAngles[$i]); + $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); + } + } + + // Framework function + function Legend($aGraph) { + if( $this->legend != "" ) { + $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } +} + +//=================================================== +// CLASS ScatterPlot +// Description: Render X and Y plots +//=================================================== +class ScatterPlot extends Plot { + public $mark = ''; + private $impuls = false; + private $linkpoints = false, $linkpointweight=1, $linkpointcolor="black"; +//--------------- +// CONSTRUCTOR + function ScatterPlot($datay,$datax=false) { + if( (count($datax) != count($datay)) && is_array($datax)) + JpGraphError::RaiseL(20003);//("Scatterplot must have equal number of X and Y points."); + $this->Plot($datay,$datax); + $this->mark = new PlotMark(); + $this->mark->SetType(MARK_SQUARE); + $this->mark->SetColor($this->color); + $this->value->SetAlign('center','center'); + $this->value->SetMargin(0); + } + +//--------------- +// PUBLIC METHODS + function SetImpuls($f=true) { + $this->impuls = $f; + } + + // Combine the scatter plot points with a line + function SetLinkPoints($aFlag=true,$aColor="black",$aWeight=1) { + $this->linkpoints=$aFlag; + $this->linkpointcolor=$aColor; + $this->linkpointweight=$aWeight; + } + + function Stroke($img,$xscale,$yscale) { + + $ymin=$yscale->scale_abs[0]; + if( $yscale->scale[0] < 0 ) + $yzero=$yscale->Translate(0); + else + $yzero=$yscale->scale_abs[0]; + + $this->csimareas = ''; + for( $i=0; $i<$this->numpoints; ++$i ) { + + // Skip null values + if( $this->coords[0][$i]==='' || $this->coords[0][$i]==='-' || $this->coords[0][$i]==='x') + continue; + + if( isset($this->coords[1]) ) + $xt = $xscale->Translate($this->coords[1][$i]); + else + $xt = $xscale->Translate($i); + $yt = $yscale->Translate($this->coords[0][$i]); + + + if( $this->linkpoints && isset($yt_old) ) { + $img->SetColor($this->linkpointcolor); + $img->SetLineWeight($this->linkpointweight); + $img->Line($xt_old,$yt_old,$xt,$yt); + } + + if( $this->impuls ) { + $img->SetColor($this->color); + $img->SetLineWeight($this->weight); + $img->Line($xt,$yzero,$xt,$yt); + } + + if( !empty($this->csimtargets[$i]) ) { + if( !empty($this->csimwintargets[$i]) ) { + $this->mark->SetCSIMTarget($this->csimtargets[$i],$this->csimwintargets[$i]); + } + else { + $this->mark->SetCSIMTarget($this->csimtargets[$i]); + } + $this->mark->SetCSIMAlt($this->csimalts[$i]); + } + + if( isset($this->coords[1]) ) { + $this->mark->SetCSIMAltVal($this->coords[0][$i],$this->coords[1][$i]); + } + else { + $this->mark->SetCSIMAltVal($this->coords[0][$i],$i); + } + + $this->mark->Stroke($img,$xt,$yt); + + $this->csimareas .= $this->mark->GetCSIMAreas(); + $this->value->Stroke($img,$this->coords[0][$i],$xt,$yt); + + $xt_old = $xt; + $yt_old = $yt; + } + } + + // Framework function + function Legend($aGraph) { + if( $this->legend != "" ) { + $aGraph->legend->Add($this->legend,$this->mark->fill_color,$this->mark,0, + $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); + } + } +} // Class +/* EOF */ +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_stock.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_stock.php new file mode 100644 index 0000000..d702b77 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_stock.php @@ -0,0 +1,183 @@ +iTupleSize ) { + JpGraphError::RaiseL(21001,$this->iTupleSize); +//('Data values for Stock charts must contain an even multiple of '.$this->iTupleSize.' data points.'); + } + $this->Plot($datay,$datax); + $this->numpoints /= $this->iTupleSize; + } +//--------------- +// PUBLIC METHODS + + function SetColor($aColor,$aColor1='white',$aColor2='darkred',$aColor3='darkred') { + $this->color = $aColor; + $this->iStockColor1 = $aColor1; + $this->iStockColor2 = $aColor2; + $this->iStockColor3 = $aColor3; + } + + function SetWidth($aWidth) { + // Make sure it's odd + $this->iWidth = 2*floor($aWidth/2)+1; + } + + function HideEndLines($aHide=true) { + $this->iEndLines = !$aHide; + } + + // Gets called before any axis are stroked + function PreStrokeAdjust($graph) { + if( $this->center ) { + $a=0.5; $b=0.5; + $this->numpoints++; + } else { + $a=0; $b=0; + } + $graph->xaxis->scale->ticks->SetXLabelOffset($a); + $graph->SetTextScaleOff($b); + } + + // Method description + function Stroke($img,$xscale,$yscale) { + $n=$this->numpoints; + if( $this->center ) $n--; + if( isset($this->coords[1]) ) { + if( count($this->coords[1])!=$n ) + JpGraphError::RaiseL(2003,count($this->coords[1]),$n); +//("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); + else + $exist_x = true; + } + else + $exist_x = false; + + if( $exist_x ) + $xs=$this->coords[1][0]; + else + $xs=0; + + $ts = $this->iTupleSize; + $this->csimareas = ''; + for( $i=0; $i<$n; ++$i) { + + //If value is NULL, then don't draw a bar at all + if ($this->coords[0][$i] === null) continue; + + if( $exist_x ) $x=$this->coords[1][$i]; + else $x=$i; + $xt = $xscale->Translate($x); + + $neg = $this->coords[0][$i*$ts] > $this->coords[0][$i*$ts+1] ; + $yopen = $yscale->Translate($this->coords[0][$i*$ts]); + $yclose = $yscale->Translate($this->coords[0][$i*$ts+1]); + $ymin = $yscale->Translate($this->coords[0][$i*$ts+2]); + $ymax = $yscale->Translate($this->coords[0][$i*$ts+3]); + + $dx = floor($this->iWidth/2); + $xl = $xt - $dx; + $xr = $xt + $dx; + + if( $neg ) + $img->SetColor($this->iStockColor3); + else + $img->SetColor($this->iStockColor1); + $img->FilledRectangle($xl,$yopen,$xr,$yclose); + $img->SetLineWeight($this->weight); + if( $neg ) + $img->SetColor($this->iStockColor2); + else + $img->SetColor($this->color); + + $img->Rectangle($xl,$yopen,$xr,$yclose); + + if( $yopen < $yclose ) { + $ytop = $yopen ; + $ybottom = $yclose ; + } + else { + $ytop = $yclose ; + $ybottom = $yopen ; + } + $img->SetColor($this->color); + $img->Line($xt,$ytop,$xt,$ymax); + $img->Line($xt,$ybottom,$xt,$ymin); + + if( $this->iEndLines ) { + $img->Line($xl,$ymax,$xr,$ymax); + $img->Line($xl,$ymin,$xr,$ymin); + } + + // A chance for subclasses to add things to the bar + // for data point i + $this->ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg); + + // Setup image maps + if( !empty($this->csimtargets[$i]) ) { + $this->csimareas.= 'csimareas .= ' href="'.$this->csimtargets[$i].'"'; + if( !empty($this->csimalts[$i]) ) { + $sval=$this->csimalts[$i]; + $this->csimareas .= " title=\"$sval\" alt=\"$sval\" "; + } + $this->csimareas.= " />\n"; + } + } + return true; + } + + // A hook for subclasses to modify the plot + function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) {} + +} // Class + +//=================================================== +// CLASS BoxPlot +//=================================================== +class BoxPlot extends StockPlot { + private $iPColor='black',$iNColor='white'; + function BoxPlot($datay,$datax=false) { + $this->iTupleSize=5; + parent::StockPlot($datay,$datax); + } + + function SetMedianColor($aPos,$aNeg) { + $this->iPColor = $aPos; + $this->iNColor = $aNeg; + } + + function ModBox($img,$xscale,$yscale,$i,$xl,$xr,$neg) { + if( $neg ) + $img->SetColor($this->iNColor); + else + $img->SetColor($this->iPColor); + + $y = $yscale->Translate($this->coords[0][$i*5+4]); + $img->Line($xl,$y,$xr,$y); + } +} + +/* EOF */ +?> \ No newline at end of file diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_ttf.inc.php b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_ttf.inc.php new file mode 100644 index 0000000..5fc184a --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/jpgraph_ttf.inc.php @@ -0,0 +1,346 @@ +g2312 == null ) { + include_once 'jpgraph_gb2312.php' ; + $this->g2312 = new GB2312toUTF8(); + } + return $this->g2312->gb2utf8($aTxt); + } + elseif( $aFF === FF_CHINESE ) { + if( !function_exists('iconv') ) { + JpGraphError::RaiseL(25006); +//('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).'); + } + return iconv('BIG5','UTF-8',$aTxt); + } + elseif( ASSUME_EUCJP_ENCODING && + ($aFF == FF_MINCHO || $aFF == FF_GOTHIC || $aFF == FF_PMINCHO || $aFF == FF_PGOTHIC) ) { + if( !function_exists('mb_convert_encoding') ) { + JpGraphError::RaiseL(25127); + } + return mb_convert_encoding($aTxt, 'UTF-8','EUC-JP'); + } + elseif( $aFF == FF_DAVID || $aFF == FF_MIRIAM || $aFF == FF_AHRON ) { + return $this->heb_iso2uni($aTxt); + } + else + return $aTxt; + } + + // Translate iso encoding to unicode + function iso2uni ($isoline){ + $uniline=''; + for ($i=0; $i < strlen($isoline); $i++){ + $thischar = substr($isoline,$i,1); + $charcode = ord($thischar); + $uniline .= ($charcode>175) ? "&#" . (1040+($charcode-176)). ";" : $thischar; + } + return $uniline; + } + + // Translate greek iso encoding to unicode + function gr_iso2uni ($isoline) { + $uniline=''; + for ($i=0; $i < strlen($isoline); $i++) { + $thischar=substr($isoline,$i,1); + $charcode=ord($thischar); + $uniline.=($charcode>179 && $charcode!=183 && $charcode!=187 && $charcode!=189) ? "&#" . (900+($charcode-180)). ";" : $thischar; + } + return $uniline; + } + + // Translate greek win encoding to unicode + function gr_win2uni ($winline) { + $uniline=''; + $n = strlen($winline); + for ($i=0; $i < $n; $i++) { + $thischar=substr($winline,$i,1); + $charcode=ord($thischar); + if ($charcode==161 || $charcode==162) { + $uniline.="&#" . (740+$charcode). ";"; + } + else { + $uniline.=(($charcode>183 && $charcode!=187 && $charcode!=189) || $charcode==180) ? "&#" . (900+($charcode-180)). ";" : $thischar; + } + } + return $uniline; + } + + function heb_iso2uni($isoline) { + $isoline = hebrev($isoline); + $o = ''; + + $n = strlen($isoline); + for($i=0; $i < $n; $i++) { + $c=ord( substr($isoline,$i,1) ); + $o .= ($c > 223) && ($c < 251) ? '&#'.(1264+$c).';' : chr($c); + } + return utf8_encode($o); + } +} + +//================================================================= +// CLASS TTF +// Description: Handle TTF font names and loading of font files +//================================================================= +class TTF { + var $font_files,$style_names; + +//--------------- +// CONSTRUCTOR + function TTF() { + + // String names for font styles to be used in error messages + $this->style_names=array(FS_NORMAL =>'normal', + FS_BOLD =>'bold', + FS_ITALIC =>'italic', + FS_BOLDITALIC =>'bolditalic'); + + // File names for available fonts + $this->font_files=array( + FF_COURIER => array(FS_NORMAL =>'cour.ttf', + FS_BOLD =>'courbd.ttf', + FS_ITALIC =>'couri.ttf', + FS_BOLDITALIC =>'courbi.ttf' ), + FF_GEORGIA => array(FS_NORMAL =>'georgia.ttf', + FS_BOLD =>'georgiab.ttf', + FS_ITALIC =>'georgiai.ttf', + FS_BOLDITALIC =>'' ), + FF_TREBUCHE =>array(FS_NORMAL =>'trebuc.ttf', + FS_BOLD =>'trebucbd.ttf', + FS_ITALIC =>'trebucit.ttf', + FS_BOLDITALIC =>'trebucbi.ttf' ), + FF_VERDANA => array(FS_NORMAL =>'verdana.ttf', + FS_BOLD =>'verdanab.ttf', + FS_ITALIC =>'verdanai.ttf', + FS_BOLDITALIC =>'' ), + FF_TIMES => array(FS_NORMAL =>'times.ttf', + FS_BOLD =>'timesbd.ttf', + FS_ITALIC =>'timesi.ttf', + FS_BOLDITALIC =>'timesbi.ttf' ), + FF_COMIC => array(FS_NORMAL =>'comic.ttf', + FS_BOLD =>'comicbd.ttf', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_ARIAL => array(FS_NORMAL =>'arial.ttf', + FS_BOLD =>'arialbd.ttf', + FS_ITALIC =>'ariali.ttf', + FS_BOLDITALIC =>'arialbi.ttf' ) , + FF_VERA => array(FS_NORMAL =>'Vera.ttf', + FS_BOLD =>'VeraBd.ttf', + FS_ITALIC =>'VeraIt.ttf', + FS_BOLDITALIC =>'VeraBI.ttf' ), + FF_VERAMONO => array(FS_NORMAL =>'VeraMono.ttf', + FS_BOLD =>'VeraMoBd.ttf', + FS_ITALIC =>'VeraMoIt.ttf', + FS_BOLDITALIC =>'VeraMoBI.ttf' ), + FF_VERASERIF=> array(FS_NORMAL =>'VeraSe.ttf', + FS_BOLD =>'VeraSeBd.ttf', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ) , + + /* Chinese fonts */ + FF_SIMSUN => array(FS_NORMAL =>'simsun.ttc', + FS_BOLD =>'simhei.ttf', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_CHINESE => array(FS_NORMAL =>CHINESE_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + /* Japanese fonts */ + FF_MINCHO => array(FS_NORMAL =>MINCHO_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_PMINCHO => array(FS_NORMAL =>PMINCHO_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_GOTHIC => array(FS_NORMAL =>GOTHIC_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_PGOTHIC => array(FS_NORMAL =>PGOTHIC_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_MINCHO => array(FS_NORMAL =>PMINCHO_TTF_FONT, + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + /* Hebrew fonts */ + FF_DAVID => array(FS_NORMAL =>'DAVIDNEW.TTF', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_MIRIAM => array(FS_NORMAL =>'MRIAMY.TTF', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + FF_AHRON => array(FS_NORMAL =>'ahronbd.ttf', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + + /* Misc fonts */ + FF_DIGITAL => array(FS_NORMAL =>'DIGIRU__.TTF', + FS_BOLD =>'Digirtu_.ttf', + FS_ITALIC =>'Digir___.ttf', + FS_BOLDITALIC =>'DIGIRT__.TTF' ), + FF_SPEEDO => array(FS_NORMAL =>'Speedo.ttf', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_COMPUTER => array(FS_NORMAL =>'COMPUTER.TTF', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + FF_CALCULATOR =>array(FS_NORMAL =>'Triad_xs.ttf', + FS_BOLD =>'', + FS_ITALIC =>'', + FS_BOLDITALIC =>'' ), + ); + } + +//--------------- +// PUBLIC METHODS + // Create the TTF file from the font specification + function File($family,$style=FS_NORMAL) { + + if( $family == FF_HANDWRT || $family==FF_BOOK ) { + JpGraphError::RaiseL(25045);//('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph. Please download fonts from http://corefonts.sourceforge.net/'); + } + + $fam = @$this->font_files[$family]; + if( !$fam ) { + JpGraphError::RaiseL(25046,$family);//("Specified TTF font family (id=$family) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/"); + } + $f = @$fam[$style]; + + if( $f==='' ) + JpGraphError::RaiseL(25047,$this->style_names[$style],$this->font_files[$family][FS_NORMAL]);//('Style "'.$this->style_names[$style].'" is not available for font family '.$this->font_files[$family][FS_NORMAL].'.'); + if( !$f ) { + JpGraphError::RaiseL(25048,$fam);//("Unknown font style specification [$fam]."); + } + + if ($family >= FF_MINCHO && $family <= FF_PGOTHIC) { + $f = MBTTF_DIR.$f; + } else { + $f = TTF_DIR.$f; + } + + if( file_exists($f) === false || is_readable($f) === false ) { + JpGraphError::RaiseL(25049,$f);//("Font file \"$f\" is not readable or does not exist."); + } + return $f; + } +} // Class + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/lang/de.inc.php b/plugins/dwJpgraphPlugin/lib/jpgraph/lang/de.inc.php new file mode 100644 index 0000000..32f4ad4 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/lang/de.inc.php @@ -0,0 +1,500 @@ +,) +$_jpg_messages = array( + +/* +** Headers wurden bereits gesendet - Fehler. Dies wird als HTML formatiert, weil es direkt als text zurueckgesendet wird +*/ +10 => array('
    JpGraph Fehler: +HTTP header wurden bereits gesendet.
    Fehler in der Datei %s in der Zeile %d.
    Erklrung:
    HTTP header wurden bereits zum Browser gesendet, wobei die Daten als Text gekennzeichnet wurden, bevor die Bibliothek die Chance hatte, seinen Bild-HTTP-Header zum Browser zu schicken. Dies verhindert, dass die Bibliothek Bilddaten zum Browser schicken kann (weil sie vom Browser als Text interpretiert wrden und daher nur Mist dargestellt wrde).

    Wahrscheinlich steht Text im Skript bevor Graph::Stroke() aufgerufen wird. Wenn dieser Text zum Browser gesendet wird, nimmt dieser an, dass die gesamten Daten aus Text bestehen. Such nach irgendwelchem Text, auch nach Leerzeichen und Zeilenumbrchen, die eventuell bereits zum Browser gesendet wurden.

    Zum Beispiel ist ein oft auftretender Fehler, eine Leerzeile am Anfang der Datei oder vor Graph::Stroke() zu lassen."<?php".

    ',2), + +/* +** Setup Fehler +*/ +11 => array('Es wurde kein Pfad fr CACHE_DIR angegeben. Bitte gib einen Pfad CACHE_DIR in der Datei jpg-config.inc an.',0), +12 => array('Es wurde kein Pfad fr TTF_DIR angegeben und der Pfad kann nicht automatisch ermittelt werden. Bitte gib den Pfad in der Datei jpg-config.inc an.',0), +13 => array('The installed PHP version (%s) is not compatible with this release of the library. The library requires at least PHP version %s',2), + +/* +** jpgraph_bar +*/ + +2001 => array('Die Anzahl der Farben ist nicht gleich der Anzahl der Vorlagen in BarPlot::SetPattern().',0), +2002 => array('Unbekannte Vorlage im Aufruf von BarPlot::SetPattern().',0), +2003 => array('Anzahl der X- und Y-Koordinaten sind nicht identisch. Anzahl der X-Koordinaten: %d; Anzahl der Y-Koordinaten: %d.',2), +2004 => array('Alle Werte fr ein Balkendiagramm (barplot) mssen numerisch sein. Du hast den Wert nr [%d] == %s angegeben.',2), +2005 => array('Du hast einen leeren Vektor fr die Schattierungsfarben im Balkendiagramm (barplot) angegeben.',0), +2006 => array('Unbekannte Position fr die Werte der Balken: %s.',1), +2007 => array('Kann GroupBarPlot nicht aus einem leeren Vektor erzeugen.',0), +2008 => array('GroupBarPlot Element nbr %d wurde nicht definiert oder ist leer.',0), +2009 => array('Eins der Objekte, das an GroupBar weitergegeben wurde ist kein Balkendiagramm (BarPlot). Versichere Dich, dass Du den GroupBarPlot aus einem Vektor von Balkendiagrammen (barplot) oder AccBarPlot-Objekten erzeugst. (Class = %s)',1), +2010 => array('Kann AccBarPlot nicht aus einem leeren Vektor erzeugen.',0), +2011 => array('AccBarPlot-Element nbr %d wurde nicht definiert oder ist leer.',1), +2012 => array('Eins der Objekte, das an AccBar weitergegeben wurde ist kein Balkendiagramm (barplot). Versichere Dich, dass Du den AccBar-Plot aus einem Vektor von Balkendiagrammen (barplot) erzeugst. (Class=%s)',1), +2013 => array('Du hast einen leeren Vektor fr die Schattierungsfarben im Balkendiagramm (barplot) angegeben.',0), +2014 => array('Die Anzahl der Datenpunkte jeder Datenreihe in AccBarPlot muss gleich sein.',0), + + +/* +** jpgraph_date +*/ + +3001 => array('Es ist nur mglich, entweder SetDateAlign() oder SetTimeAlign() zu benutzen, nicht beides!',0), + +/* +** jpgraph_error +*/ + +4002 => array('Fehler bei den Eingabedaten von LineErrorPlot. Die Anzahl der Datenpunkte mus ein Mehrfaches von drei sein!',0), + +/* +** jpgraph_flags +*/ + +5001 => array('Unbekannte Flaggen-Gre (%d).',1), +5002 => array('Der Flaggen-Index %s existiert nicht.',1), +5003 => array('Es wurde eine ungltige Ordnungszahl (%d) fr den Flaggen-Index angegeben.',1), +5004 => array('Der Landesname %s hat kein korrespondierendes Flaggenbild. Die Flagge mag existieren, abr eventuell unter einem anderen Namen, z.B. versuche "united states" statt "usa".',1), + + +/* +** jpgraph_gantt +*/ + +6001 => array('Interner Fehler. Die Hhe fr ActivityTitles ist < 0.',0), +6002 => array('Es drfen keine negativen Werte fr die Gantt-Diagramm-Dimensionen angegeben werden. Verwende 0, wenn die Dimensionen automatisch ermittelt werden sollen.',0), +6003 => array('Ungltiges Format fr den Bedingungs-Parameter bei Index=%d in CreateSimple(). Der Parameter muss bei index 0 starten und Vektoren in der Form (Row,Constrain-To,Constrain-Type) enthalten.',1), +6004 => array('Ungltiges Format fr den Fortschritts-Parameter bei Index=%d in CreateSimple(). Der Parameter muss bei Index 0 starten und Vektoren in der Form (Row,Progress) enthalten.',1), +6005 => array('SetScale() ist nicht sinnvoll bei Gantt-Diagrammen.',0), +6006 => array('Das Gantt-Diagramm kann nicht automatisch skaliert werden. Es existieren keine Aktivitten mit Termin. [GetBarMinMax() start >= n]',0), +6007 => array('Plausibilttsprfung fr die automatische Gantt-Diagramm-Gre schlug fehl. Entweder die Breite (=%d) oder die Hhe (=%d) ist grer als MAX_GANTTIMG_SIZE. Dies kann mglicherweise durch einen falschen Wert bei einer Aktivitt hervorgerufen worden sein.',2), +6008 => array('Du hast eine Bedingung angegeben von Reihe=%d bis Reihe=%d, die keine Aktivitt hat.',2), +6009 => array('Unbekannter Bedingungstyp von Reihe=%d bis Reihe=%d',2), +6010 => array('Ungltiger Icon-Index fr das eingebaute Gantt-Icon [%d]',1), +6011 => array('Argument fr IconImage muss entweder ein String oder ein Integer sein.',0), +6012 => array('Unbekannter Typ bei der Gantt-Objekt-Title-Definition.',0), +6015 => array('Ungltige vertikale Position %d',1), +6016 => array('Der eingegebene Datums-String (%s) fr eine Gantt-Aktivitt kann nicht interpretiert werden. Versichere Dich, dass es ein gltiger Datumsstring ist, z.B. 2005-04-23 13:30',1), +6017 => array('Unbekannter Datumstyp in GanttScale (%s).',1), +6018 => array('Intervall fr Minuten muss ein gerader Teiler einer Stunde sein, z.B. 1,5,10,12,15,20,30, etc. Du hast ein Intervall von %d Minuten angegeben.',1), +6019 => array('Die vorhandene Breite (%d) fr die Minuten ist zu klein, um angezeigt zu werden. Bitte benutze die automatische Grenermittlung oder vergrere die Breite des Diagramms.',1), +6020 => array('Das Intervall fr die Stunden muss ein gerader Teiler eines Tages sein, z.B. 0:30, 1:00, 1:30, 4:00, etc. Du hast ein Intervall von %d eingegeben.',1), +6021 => array('Unbekanntes Format fr die Woche.',0), +6022 => array('Die Gantt-Skala wurde nicht eingegeben.',0), +6023 => array('Wenn Du sowohl Stunden als auch Minuten anzeigen lassen willst, muss das Stunden-Interval gleich 1 sein (anderenfalls ist es nicht sinnvoll, Minuten anzeigen zu lassen).',0), +6024 => array('Das CSIM-Ziel muss als String angegeben werden. Der Start des Ziels ist: %d',1), +6025 => array('Der CSIM-Alt-Text muss als String angegeben werden. Der Beginn des Alt-Textes ist: %d',1), +6027 => array('Der Fortschrittswert muss im Bereich [0, 1] liegen.',0), +6028 => array('Die eingegebene Hhe (%d) fr GanttBar ist nicht im zulssigen Bereich.',1), +6029 => array('Der Offset fr die vertikale Linie muss im Bereich [0,1] sein.',0), +6030 => array('Unbekannte Pfeilrichtung fr eine Verbindung.',0), +6031 => array('Unbekannter Pfeiltyp fr eine Verbindung.',0), +6032 => array('Interner Fehler: Unbekannter Pfadtyp (=%d) fr eine Verbindung.',1), + +/* +** jpgraph_gradient +*/ + +7001 => array('Unbekannter Gradiententyp (=%d).',1), + +/* +** jpgraph_iconplot +*/ + +8001 => array('Der Mix-Wert fr das Icon muss zwischen 0 und 100 sein.',0), +8002 => array('Die Ankerposition fr Icons muss entweder "top", "bottom", "left", "right" oder "center" sein.',0), +8003 => array('Es ist nicht mglich, gleichzeitig ein Bild und eine Landesflagge fr dasselbe Icon zu definieren',0), +8004 => array('Wenn Du Landesflaggen benutzen willst, musst Du die Datei "jpgraph_flags.php" hinzufgen (per include).',0), + +/* +** jpgraph_imgtrans +*/ + +9001 => array('Der Wert fr die Bildtransformation ist auerhalb des zulssigen Bereichs. Der verschwindende Punkt am Horizont muss als Wert zwischen 0 und 1 angegeben werden.',0), + +/* +** jpgraph_lineplot +*/ + +10001 => array('Die Methode LinePlot::SetFilled() sollte nicht mehr benutzt werden. Benutze lieber SetFillColor()',0), +10002 => array('Der Plot ist zu kompliziert fr FastLineStroke. Benutze lieber den StandardStroke()',0), + +/* +** jpgraph_log +*/ + +11001 => array('Deine Daten enthalten nicht-numerische Werte.',0), +11002 => array('Negative Werte knnen nicht fr logarithmische Achsen verwendet werden.',0), +11003 => array('Deine Daten enthalten nicht-numerische Werte.',0), +11004 => array('Skalierungsfehler fr die logarithmische Achse. Es gibt ein Problem mit den Daten der Achse. Der grte Wert muss grer sein als Null. Es ist mathematisch nicht mglich, einen Wert gleich Null in der Skala zu haben.',0), +11005 => array('Das Tick-Intervall fr die logarithmische Achse ist nicht definiert. Lsche jeden Aufruf von SetTextLabelStart() oder SetTextTickInterval() bei der logarithmischen Achse.',0), + +/* +** jpgraph_mgraph +*/ + +12001 => array("Du benutzt GD 2.x und versuchst ein Nicht-Truecolor-Bild als Hintergrundbild zu benutzen. Um Hintergrundbilder mit GD 2.x zu benutzen, ist es notwendig Truecolor zu aktivieren, indem die USE_TRUECOLOR-Konstante auf TRUE gesetzt wird. Wegen eines Bugs in GD 2.0.1 ist die Qualitt der Truetype-Schriften sehr schlecht, wenn man Truetype-Schriften mit Truecolor-Bildern verwendet.",0), +12002 => array('Ungltiger Dateiname fr MGraph::SetBackgroundImage() : %s. Die Datei muss eine gltige Dateierweiterung haben (jpg,gif,png), wenn die automatische Typerkennung verwendet wird.',1), +12003 => array('Unbekannte Dateierweiterung (%s) in MGraph::SetBackgroundImage() fr Dateiname: %s',2), +12004 => array('Das Bildformat des Hintergrundbildes (%s) wird von Deiner System-Konfiguration nicht untersttzt. ',1), +12005 => array('Das Hintergrundbild kann nicht gelesen werden: %s',1), +12006 => array('Es wurden ungltige Gren fr Breite oder Hhe beim Erstellen des Bildes angegeben, (Breite=%d, Hhe=%d)',2), +12007 => array('Das Argument fr MGraph::Add() ist nicht gltig fr GD.',0), +12008 => array('Deine PHP- (und GD-lib-) Installation scheint keine bekannten Bildformate zu untersttzen.',0), +12009 => array('Deine PHP-Installation untersttzt das gewhlte Bildformat nicht: %s',1), +12010 => array('Es konnte kein Bild als Datei %s erzeugt werden. berprfe, ob Du die entsprechenden Schreibrechte im aktuellen Verzeichnis hast.',1), +12011 => array('Es konnte kein Truecolor-Bild erzeugt werden. berprfe, ob Du wirklich die GD2-Bibliothek installiert hast.',0), +12012 => array('Es konnte kein Bild erzeugt werden. berprfe, ob Du wirklich die GD2-Bibliothek installiert hast.',0), + +/* +** jpgraph_pie3d +*/ + +14001 => array('Pie3D::ShowBorder(). Missbilligte Funktion. Benutze Pie3D::SetEdge(), um die Ecken der Tortenstcke zu kontrollieren.',0), +14002 => array('PiePlot3D::SetAngle() 3D-Torten-Projektionswinkel muss zwischen 5 und 85 Grad sein.',0), +14003 => array('Interne Festlegung schlug fehl. Pie3D::Pie3DSlice',0), +14004 => array('Tortenstck-Startwinkel muss zwischen 0 und 360 Grad sein.',0), +14005 => array('Pie3D Interner Fehler: Versuch, zweimal zu umhllen bei der Suche nach dem Startindex.',0,), +14006 => array('Pie3D Interner Fehler: Z-Sortier-Algorithmus fr 3D-Tortendiagramme funktioniert nicht einwandfrei (2). Versuch, zweimal zu umhllen beim Erstellen des Bildes.',0), +14007 => array('Die Breite fr das 3D-Tortendiagramm ist 0. Gib eine Breite > 0 an.',0), + +/* +** jpgraph_pie +*/ + +15001 => array('PiePLot::SetTheme() Unbekannter Stil: %s',1), +15002 => array('Argument fr PiePlot::ExplodeSlice() muss ein Integer-Wert sein',0), +15003 => array('Argument fr PiePlot::Explode() muss ein Vektor mit Integer-Werten sein.',0), +15004 => array('Tortenstck-Startwinkel muss zwischen 0 und 360 Grad sein.',0), +15005 => array('PiePlot::SetFont() sollte nicht mehr verwendet werden. Benutze stattdessen PiePlot->value->SetFont().',0), +15006 => array('PiePlot::SetSize() Radius fr Tortendiagramm muss entweder als Bruch [0, 0.5] der Bildgre oder als Absoluwert in Pixel im Bereich [10, 1000] angegeben werden.',0), +15007 => array('PiePlot::SetFontColor() sollte nicht mehr verwendet werden. Benutze stattdessen PiePlot->value->SetColor()..',0), +15008 => array('PiePlot::SetLabelType() der Typ fr Tortendiagramme muss entweder 0 or 1 sein (nicht %d).',1), +15009 => array('Ungltiges Tortendiagramm. Die Summe aller Daten ist Null.',0), +15010 => array('Die Summe aller Daten ist Null.',0), +15011 => array('Um Bildtransformationen benutzen zu knnen, muss die Datei jpgraph_imgtrans.php eingefgt werden (per include).',0), + +/* +** jpgraph_plotband +*/ + +16001 => array('Die Dichte fr das Pattern muss zwischen 1 und 100 sein. (Du hast %f eingegeben)',1), +16002 => array('Es wurde keine Position fr das Pattern angegeben.',0), +16003 => array('Unbekannte Pattern-Definition (%d)',0), +16004 => array('Der Mindeswert fr das PlotBand ist grer als der Maximalwert. Bitte korrigiere dies!',0), + + +/* +** jpgraph_polar +*/ + +17001 => array('PolarPlots mssen eine gerade Anzahl von Datenpunkten haben. Jeder Datenpunkt ist ein Tupel (Winkel, Radius).',0), +17002 => array('Unbekannte Ausrichtung fr X-Achsen-Titel. (%s)',1), +//17003 => array('Set90AndMargin() wird fr PolarGraph nicht untersttzt.',0), +17004 => array('Unbekannter Achsentyp fr PolarGraph. Er muss entweder \'lin\' oder \'log\' sein.',0), + +/* +** jpgraph_radar +*/ + +18001 => array('ClientSideImageMaps werden fr RadarPlots nicht untersttzt.',0), +18002 => array('RadarGraph::SupressTickMarks() sollte nicht mehr verwendet werden. Benutze stattdessen HideTickMarks().',0), +18003 => array('Ungltiger Achsentyp fr RadarPlot (%s). Er muss entweder \'lin\' oder \'log\' sein.',1), +18004 => array('Die RadarPlot-Gre muss zwischen 0.1 und 1 sein. (Dein Wert=%f)',1), +18005 => array('RadarPlot: nicht untersttzte Tick-Dichte: %d',1), +18006 => array('Minimum Daten %f (RadarPlots sollten nur verwendet werden, wenn alle Datenpunkte einen Wert > 0 haben).',1), +18007 => array('Die Anzahl der Titel entspricht nicht der Anzahl der Datenpunkte.',0), +18008 => array('Jeder RadarPlot muss die gleiche Anzahl von Datenpunkten haben.',0), + +/* +** jpgraph_regstat +*/ + +19001 => array('Spline: Anzahl der X- und Y-Koordinaten muss gleich sein.',0), +19002 => array('Ungltige Dateneingabe fr Spline. Zwei oder mehr aufeinanderfolgende X-Werte sind identisch. Jeder eigegebene X-Wert muss unterschiedlich sein, weil vom mathematischen Standpunkt ein Eins-zu-Eins-Mapping vorliegen muss, d.h. jeder X-Wert korrespondiert mit exakt einem Y-Wert.',0), +19003 => array('Bezier: Anzahl der X- und Y-Koordinaten muss gleich sein.',0), + +/* +** jpgraph_scatter +*/ + +20001 => array('Fieldplots mssen die gleiche Anzahl von X und Y Datenpunkten haben.',0), +20002 => array('Bei Fieldplots muss ein Winkel fr jeden X und Y Datenpunkt angegeben werden.',0), +20003 => array('Scatterplots mssen die gleiche Anzahl von X- und Y-Datenpunkten haben.',0), + +/* +** jpgraph_stock +*/ + +21001 => array('Die Anzahl der Datenwerte fr Stock-Charts mssen ein Mehrfaches von %d Datenpunkten sein.',1), + +/* +** jpgraph_plotmark +*/ + +23001 => array('Der Marker "%s" existiert nicht in der Farbe: %d',2), +23002 => array('Der Farb-Index ist zu hoch fr den Marker "%s"',1), +23003 => array('Ein Dateiname muss angegeben werden, wenn Du den Marker-Typ auf MARK_IMG setzt.',0), + +/* +** jpgraph_utils +*/ + +24001 => array('FuncGenerator : Keine Funktion definiert. ',0), +24002 => array('FuncGenerator : Syntax-Fehler in der Funktionsdefinition ',0), +24003 => array('DateScaleUtils: Unknown tick type specified in call to GetTicks()',0), + +/* +** jpgraph +*/ + +25001 => array('Diese PHP-Installation ist nicht mit der GD-Bibliothek kompiliert. Bitte kompiliere PHP mit GD-Untersttzung neu, damit JpGraph funktioniert. (Weder die Funktion imagetypes() noch imagecreatefromstring() existiert!)',0), +25002 => array('Diese PHP-Installation scheint nicht die bentigte GD-Bibliothek zu untersttzen. Bitte schau in der PHP-Dokumentation nach, wie man die GD-Bibliothek installiert und aktiviert.',0), +25003 => array('Genereller PHP Fehler : Bei %s:%d : %s',3), +25004 => array('Genereller PHP Fehler : %s ',1), +25005 => array('PHP_SELF, die PHP-Global-Variable kann nicht ermittelt werden. PHP kann nicht von der Kommandozeile gestartet werden, wenn der Cache oder die Bilddateien automatisch benannt werden sollen.',0), +25006 => array('Die Benutzung der FF_CHINESE (FF_BIG5) Schriftfamilie bentigt die iconv() Funktion in Deiner PHP-Konfiguration. Dies wird nicht defaultmig in PHP kompiliert (bentigt "--width-iconv" bei der Konfiguration).',0), +25007 => array('Du versuchst das lokale (%s) zu verwenden, was von Deiner PHP-Installation nicht untersttzt wird. Hinweis: Benutze \'\', um das defaultmige Lokale fr diese geographische Region festzulegen.',1), +25008 => array('Die Bild-Breite und Hhe in Graph::Graph() mssen numerisch sein',0), +25009 => array('Die Skalierung der Achsen muss angegeben werden mit Graph::SetScale()',0), + +25010 => array('Graph::Add() Du hast versucht, einen leeren Plot zum Graph hinzuzufgen.',0), +25011 => array('Graph::AddY2() Du hast versucht, einen leeren Plot zum Graph hinzuzufgen.',0), +25012 => array('Graph::AddYN() Du hast versucht, einen leeren Plot zum Graph hinzuzufgen.',0), +25013 => array('Es knnen nur Standard-Plots zu multiplen Y-Achsen hinzugefgt werden',0), +25014 => array('Graph::AddText() Du hast versucht, einen leeren Text zum Graph hinzuzufgen.',0), +25015 => array('Graph::AddLine() Du hast versucht, eine leere Linie zum Graph hinzuzufgen.',0), +25016 => array('Graph::AddBand() Du hast versucht, ein leeres Band zum Graph hinzuzufgen.',0), +25017 => array('Du benutzt GD 2.x und versuchst, ein Hintergrundbild in einem Truecolor-Bild zu verwenden. Um Hintergrundbilder mit GD 2.x zu verwenden, ist es notwendig, Truecolor zu aktivieren, indem die USE_TRUECOLOR-Konstante auf TRUE gesetzt wird. Wegen eines Bugs in GD 2.0.1 ist die Qualitt der Schrift sehr schlecht, wenn Truetype-Schrift in Truecolor-Bildern verwendet werden.',0), +25018 => array('Falscher Dateiname fr Graph::SetBackgroundImage() : "%s" muss eine gltige Dateinamenerweiterung (jpg,gif,png) haben, wenn die automatische Dateityperkennung verwenndet werden soll.',1), +25019 => array('Unbekannte Dateinamenerweiterung (%s) in Graph::SetBackgroundImage() fr Dateiname: "%s"',2), + +25020 => array('Graph::SetScale(): Dar Maximalwert muss grer sein als der Mindestwert.',0), +25021 => array('Unbekannte Achsendefinition fr die Y-Achse. (%s)',1), +25022 => array('Unbekannte Achsendefinition fr die X-Achse. (%s)',1), +25023 => array('Nicht untersttzter Y2-Achsentyp: "%s" muss einer von (lin,log,int) sein.',1), +25024 => array('Nicht untersttzter X-Achsentyp: "%s" muss einer von (lin,log,int) sein.',1), +25025 => array('Nicht untersttzte Tick-Dichte: %d',1), +25026 => array('Nicht untersttzter Typ der nicht angegebenen Y-Achse. Du hast entweder: 1. einen Y-Achsentyp fr automatisches Skalieren definiert, aber keine Plots angegeben. 2. eine Achse direkt definiert, aber vergessen, die Tick-Dichte zu festzulegen.',0), +25027 => array('Kann cached CSIM "%s" zum Lesen nicht ffnen.',1), +25028 => array('Apache/PHP hat keine Schreibrechte, in das CSIM-Cache-Verzeichnis (%s) zu schreiben. berprfe die Rechte.',1), +25029 => array('Kann nicht in das CSIM "%s" schreiben. berprfe die Schreibrechte und den freien Speicherplatz.',1), + +25030 => array('Fehlender Skriptname fr StrokeCSIM(). Der Name des aktuellen Skriptes muss als erster Parameter von StrokeCSIM() angegeben werden.',0), +25031 => array('Der Achsentyp muss mittels Graph::SetScale() angegeben werden.',0), +25032 => array('Es existieren keine Plots fr die Y-Achse nbr:%d',1), +25033 => array('',0), +25034 => array('Undefinierte X-Achse kann nicht gezeichnet werden. Es wurden keine Plots definiert.',0), +25035 => array('Du hast Clipping aktiviert. Clipping wird nur fr Diagramme mit 0 oder 90 Grad Rotation untersttzt. Bitte verndere Deinen Rotationswinkel (=%d Grad) dementsprechend oder deaktiviere Clipping.',1), +25036 => array('Unbekannter Achsentyp AxisStyle() : %s',1), +25037 => array('Das Bildformat Deines Hintergrundbildes (%s) wird von Deiner System-Konfiguration nicht untersttzt. ',1), +25038 => array('Das Hintergrundbild scheint von einem anderen Typ (unterschiedliche Dateierweiterung) zu sein als der angegebene Typ. Angegebenen: %s; Datei: %s',2), +25039 => array('Hintergrundbild kann nicht gelesen werden: "%s"',1), + +25040 => array('Es ist nicht mglich, sowohl ein Hintergrundbild als auch eine Hintergrund-Landesflagge anzugeben.',0), +25041 => array('Um Landesflaggen als Hintergrund benutzen zu knnen, muss die Datei "jpgraph_flags.php" eingefgt werden (per include).',0), +25042 => array('Unbekanntes Hintergrundbild-Layout',0), +25043 => array('Unbekannter Titelhintergrund-Stil.',0), +25044 => array('Automatisches Skalieren kann nicht verwendet werden, weil es unmglich ist, einen gltigen min/max Wert fr die Y-Achse zu ermitteln (nur Null-Werte).',0), +25045 => array('Die Schriftfamilien FF_HANDWRT und FF_BOOK sind wegen Copyright-Problemen nicht mehr verfgbar. Diese Schriften knnen nicht mehr mit JpGraph verteilt werden. Bitte lade Dir Schriften von http://corefonts.sourceforge.net/ herunter.',0), +25046 => array('Angegebene TTF-Schriftfamilie (id=%d) ist unbekannt oder existiert nicht. Bitte merke Dir, dass TTF-Schriften wegen Copyright-Problemen nicht mit JpGraph mitgeliefert werden. Du findest MS-TTF-Internetschriften (arial, courier, etc.) zum Herunterladen unter http://corefonts.sourceforge.net/',1), +25047 => array('Stil %s ist nicht verfgbar fr Schriftfamilie %s',2), +25048 => array('Unbekannte Schriftstildefinition [%s].',1), +25049 => array('Schriftdatei "%s" ist nicht lesbar oder existiert nicht.',1), + +25050 => array('Erstes Argument fr Text::Text() muss ein String sein.',0), +25051 => array('Ungltige Richtung angegeben fr Text.',0), +25052 => array('PANIK: Interner Fehler in SuperScript::Stroke(). Unbekannte vertikale Ausrichtung fr Text.',0), +25053 => array('PANIK: Interner Fehler in SuperScript::Stroke(). Unbekannte horizontale Ausrichtung fr Text.',0), +25054 => array('Interner Fehler: Unbekannte Grid-Achse %s',1), +25055 => array('Axis::SetTickDirection() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetTickSide().',0), +25056 => array('SetTickLabelMargin() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetLabelMargin().',0), +25057 => array('SetTextTicks() sollte nicht mehr verwendet werden. Benutze stattdessen SetTextTickInterval().',0), +25058 => array('TextLabelIntevall >= 1 muss angegeben werden.',0), +25059 => array('SetLabelPos() sollte nicht mehr verwendet werden. Benutze stattdessen Axis::SetLabelSide().',0), + +25060 => array('Unbekannte Ausrichtung angegeben fr X-Achsentitel (%s).',1), +25061 => array('Unbekannte Ausrichtung angegeben fr Y-Achsentitel (%s).',1), +25062 => array('Label unter einem Winkel werden fr die Y-Achse nicht untersttzt.',0), +25063 => array('Ticks::SetPrecision() sollte nicht mehr verwendet werden. Benutze stattdessen Ticks::SetLabelFormat() (oder Ticks::SetFormatCallback()).',0), +25064 => array('Kleinere oder grere Schrittgre ist 0. berprfe, ob Du flschlicherweise SetTextTicks(0) in Deinem Skript hast. Wenn dies nicht der Fall ist, bist Du eventuell ber einen Bug in JpGraph gestolpert. Bitte sende einen Report und fge den Code an, der den Fehler verursacht hat.',0), +25065 => array('Tick-Positionen mssen als array() angegeben werden',0), +25066 => array('Wenn die Tick-Positionen und -Label von Hand eingegeben werden, muss die Anzahl der Ticks und der Label gleich sein.',0), +25067 => array('Deine von Hand eingegebene Achse und Ticks sind nicht korrekt. Die Skala scheint zu klein zu sein fr den Tickabstand.',0), +25068 => array('Ein Plot hat eine ungltige Achse. Dies kann beispielsweise der Fall sein, wenn Du automatisches Text-Skalieren verwendest, um ein Liniendiagramm zu zeichnen mit nur einem Datenpunkt, oder wenn die Bildflche zu klein ist. Es kann auch der Fall sein, dass kein Datenpunkt einen numerischen Wert hat (vielleicht nur \'-\' oder \'x\').',0), +25069 => array('Grace muss grer sein als 0',0), + +25070 => array('Deine Daten enthalten nicht-numerische Werte.',0), +25071 => array('Du hast mit SetAutoMin() einen Mindestwert angegeben, der grer ist als der Maximalwert fr die Achse. Dies ist nicht mglich.',0), +25072 => array('Du hast mit SetAutoMax() einen Maximalwert angegeben, der kleiner ist als der Minimalwert der Achse. Dies ist nicht mglich.',0), +25073 => array('Interner Fehler. Der Integer-Skalierungs-Algorithmus-Vergleich ist auerhalb der Grenzen (r=%f).',1), +25074 => array('Interner Fehler. Der Skalierungsbereich ist negativ (%f) [fr %s Achse]. Dieses Problem knnte verursacht werden durch den Versuch, \'ungltige\' Werte in die Daten-Vektoren einzugeben (z.B. nur String- oder NULL-Werte), was beim automatischen Skalieren einen Fehler erzeugt.',2), +25075 => array('Die automatischen Ticks knnen nicht gesetzt werden, weil min==max.',0), +25077 => array('Einstellfaktor fr die Farbe muss grer sein als 0',0), +25078 => array('Unbekannte Farbe: %s',1), +25079 => array('Unbekannte Farbdefinition: %s, Gre=%d',2), + +25080 => array('Der Alpha-Parameter fr Farben muss zwischen 0.0 und 1.0 liegen.',0), +25081 => array('Das ausgewhlte Grafikformat wird entweder nicht untersttzt oder ist unbekannt [%s]',1), +25082 => array('Es wurden ungltige Gren fr Breite und Hhe beim Erstellen des Bildes definiert (Breite=%d, Hhe=%d).',2), +25083 => array('Es wurde eine ungltige Gre beim Kopieren des Bildes angegeben. Die Gre fr das kopierte Bild wurde auf 1 Pixel oder weniger gesetzt.',0), +25084 => array('Fehler beim Erstellen eines temporren GD-Canvas. Mglicherweise liegt ein Arbeitsspeicherproblem vor.',0), +25085 => array('Ein Bild kann nicht aus dem angegebenen String erzeugt werden. Er ist entweder in einem nicht untersttzen Format oder er represntiert ein kaputtes Bild.',0), +25086 => array('Du scheinst nur GD 1.x installiert zu haben. Um Alphablending zu aktivieren, ist GD 2.x oder hher notwendig. Bitte installiere GD 2.x oder versichere Dich, dass die Konstante USE_GD2 richtig gesetzt ist. Standardmig wird die installierte GD-Version automatisch erkannt. Ganz selten wird GD2 erkannt, obwohl nur GD1 installiert ist. Die Konstante USE_GD2 muss dann zu "false" gesetzt werden.',0), +25087 => array('Diese PHP-Version wurde ohne TTF-Untersttzung konfiguriert. PHP muss mit TTF-Untersttzung neu kompiliert und installiert werden.',0), +25088 => array('Die GD-Schriftuntersttzung wurde falsch konfiguriert. Der Aufruf von imagefontwidth() ist fehlerhaft.',0), +25089 => array('Die GD-Schriftuntersttzung wurde falsch konfiguriert. Der Aufruf von imagefontheight() ist fehlerhaft.',0), + +25090 => array('Unbekannte Richtung angegeben im Aufruf von StrokeBoxedText() [%s].',1), +25091 => array('Die interne Schrift untesttzt das Schreiben von Text in einem beliebigen Winkel nicht. Benutze stattdessen TTF-Schriften.',0), +25092 => array('Es liegt entweder ein Konfigurationsproblem mit TrueType oder ein Problem beim Lesen der Schriftdatei "%s" vor. Versichere Dich, dass die Datei existiert und Leserechte und -pfad vergeben sind. (wenn \'basedir\' restriction in PHP aktiviert ist, muss die Schriftdatei im Dokumentwurzelverzeichnis abgelegt werden). Mglicherweise ist die FreeType-Bibliothek falsch installiert. Versuche, mindestens zur FreeType-Version 2.1.13 zu aktualisieren und kompiliere GD mit einem korrekten Setup neu, damit die FreeType-Bibliothek gefunden werden kann.',1), +25093 => array('Die Schriftdatei "%s" kann nicht gelesen werden beim Aufruf von Image::GetBBoxTTF. Bitte versichere Dich, dass die Schrift gesetzt wurde, bevor diese Methode aufgerufen wird, und dass die Schrift im TTF-Verzeichnis installiert ist.',1), +25094 => array('Die Textrichtung muss in einem Winkel zwischen 0 und 90 engegeben werden.',0), +25095 => array('Unbekannte Schriftfamilien-Definition. ',0), +25096 => array('Der Farbpalette knnen keine weiteren Farben zugewiesen werden. Dem Bild wurde bereits die grtmgliche Anzahl von Farben (%d) zugewiesen und die Palette ist voll. Verwende stattdessen ein TrueColor-Bild',0), +25097 => array('Eine Farbe wurde als leerer String im Aufruf von PushColor() angegegeben.',0), +25098 => array('Negativer Farbindex. Unpassender Aufruf von PopColor().',0), +25099 => array('Die Parameter fr Helligkeit und Kontrast sind auerhalb des zulssigen Bereichs [-1,1]',0), + +25100 => array('Es liegt ein Problem mit der Farbpalette und dem GD-Setup vor. Bitte deaktiviere anti-aliasing oder verwende GD2 mit TrueColor. Wenn die GD2-Bibliothek installiert ist, versichere Dich, dass die Konstante USE_GD2 auf "true" gesetzt und TrueColor aktiviert ist.',0), +25101 => array('Ungltiges numerisches Argument fr SetLineStyle(): (%d)',1), +25102 => array('Ungltiges String-Argument fr SetLineStyle(): %s',1), +25103 => array('Ungltiges Argument fr SetLineStyle %s',1), +25104 => array('Unbekannter Linientyp: %s',1), +25105 => array('Es wurden NULL-Daten fr ein geflltes Polygon angegeben. Sorge dafr, dass keine NULL-Daten angegeben werden.',0), +25106 => array('Image::FillToBorder : es knnen keine weiteren Farben zugewiesen werden.',0), +25107 => array('In Datei "%s" kann nicht geschrieben werden. berprfe die aktuellen Schreibrechte.',1), +25108 => array('Das Bild kann nicht gestreamt werden. Mglicherweise liegt ein Fehler im PHP/GD-Setup vor. Kompiliere PHP neu und verwende die eingebaute GD-Bibliothek, die mit PHP angeboten wird.',0), +25109 => array('Deine PHP- (und GD-lib-) Installation scheint keine bekannten Grafikformate zu untersttzen. Sorge zunchst dafr, dass GD als PHP-Modul kompiliert ist. Wenn Du auerdem JPEG-Bilder verwenden willst, musst Du die JPEG-Bibliothek installieren. Weitere Details sind in der PHP-Dokumentation zu finden.',0), + +25110 => array('Dein PHP-Installation untersttzt das gewhlte Grafikformat nicht: %s',1), +25111 => array('Das gecachete Bild %s kann nicht gelscht werden. Problem mit den Rechten?',1), +25112 => array('Das Datum der gecacheten Datei (%s) liegt in der Zukunft.',1), +25113 => array('Das gecachete Bild %s kann nicht gelscht werden. Problem mit den Rechten?',1), +25114 => array('PHP hat nicht die erforderlichen Rechte, um in die Cache-Datei %s zu schreiben. Bitte versichere Dich, dass der Benutzer, der PHP anwendet, die entsprechenden Schreibrechte fr die Datei hat, wenn Du das Cache-System in JPGraph verwenden willst.',1), +25115 => array('Berechtigung fr gecachetes Bild %s kann nicht gesetzt werden. Problem mit den Rechten?',1), +25116 => array('Datei kann nicht aus dem Cache %s geffnet werden',1), +25117 => array('Gecachetes Bild %s kann nicht zum Lesen geffnet werden.',1), +25118 => array('Verzeichnis %s kann nicht angelegt werden. Versichere Dich, dass PHP die Schreibrechte in diesem Verzeichnis hat.',1), +25119 => array('Rechte fr Datei %s knnen nicht gesetzt werden. Problem mit den Rechten?',1), + +25120 => array('Die Position fr die Legende muss als Prozentwert im Bereich 0-1 angegeben werden.',0), +25121 => array('Eine leerer Datenvektor wurde fr den Plot eingegeben. Es muss wenigstens ein Datenpunkt vorliegen.',0), +25122 => array('Stroke() muss als Subklasse der Klasse Plot definiert sein.',0), +25123 => array('Du kannst keine Text-X-Achse mit X-Koordinaten verwenden. Benutze stattdessen eine "int" oder "lin" Achse.',0), +25124 => array('Der Eingabedatenvektor mus aufeinanderfolgende Werte von 0 aufwrts beinhalten. Der angegebene Y-Vektor beginnt mit leeren Werten (NULL).',0), +25125 => array('Ungltige Richtung fr statische Linie.',0), +25126 => array('Es kann kein TrueColor-Bild erzeugt werden. berprfe, ob die GD2-Bibliothek und PHP korrekt aufgesetzt wurden.',0), +25127 => array('The library has been configured for automatic encoding conversion of Japanese fonts. This requires that PHP has the mb_convert_encoding() function. Your PHP installation lacks this function (PHP needs the "--enable-mbstring" when compiled).',0), +25128 => array('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.',0), + +/* +**--------------------------------------------------------------------------------------------- +** Pro-version strings +**--------------------------------------------------------------------------------------------- +*/ + +/* +** jpgraph_table +*/ + +27001 => array('GTextTable: Ungltiges Argument fr Set(). Das Array-Argument muss 2-- dimensional sein.',0), +27002 => array('GTextTable: Ungltiges Argument fr Set()',0), +27003 => array('GTextTable: Falsche Anzahl von Argumenten fr GTextTable::SetColor()',0), +27004 => array('GTextTable: Angegebener Zellenbereich, der verschmolzen werden soll, ist ungltig.',0), +27005 => array('GTextTable: Bereits verschmolzene Zellen im Bereich (%d,%d) bis (%d,%d) knnen nicht ein weiteres Mal verschmolzen werden.',4), +27006 => array('GTextTable: Spalten-Argument = %d liegt auerhalb der festgelegten Tabellengre.',1), +27007 => array('GTextTable: Zeilen-Argument = %d liegt auerhalb der festgelegten Tabellengre.',1), +27008 => array('GTextTable: Spalten- und Zeilengre mssen zu den Dimensionen der Tabelle passen.',0), +27009 => array('GTextTable: Die Anzahl der Tabellenspalten oder -zeilen ist 0. Versichere Dich, dass die Methoden Init() oder Set() aufgerufen werden.',0), +27010 => array('GTextTable: Es wurde keine Ausrichtung beim Aufruf von SetAlign() angegeben.',0), +27011 => array('GTextTable: Es wurde eine unbekannte Ausrichtung beim Aufruf von SetAlign() abgegeben. Horizontal=%s, Vertikal=%s',2), +27012 => array('GTextTable: Interner Fehler. Es wurde ein ungltiges Argument festgeleget %s',1), +27013 => array('GTextTable: Das Argument fr FormatNumber() muss ein String sein.',0), +27014 => array('GTextTable: Die Tabelle wurde weder mit einem Aufruf von Set() noch von Init() initialisiert.',0), +27015 => array('GTextTable: Der Zellenbildbedingungstyp muss entweder TIMG_WIDTH oder TIMG_HEIGHT sein.',0), + +/* +** jpgraph_windrose +*/ + +22001 => array('Die Gesamtsumme der prozentualen Anteile aller Windrosenarme darf 100%% nicht berschreiten!\n(Aktuell max: %d)',1), +22002 => array('Das Bild ist zu klein fr eine Skala. Bitte vergrere das Bild.',0), +22004 => array('Die Etikettendefinition fr Windrosenrichtungen mssen 16 Werte haben (eine fr jede Kompassrichtung).',0), +22005 => array('Der Linientyp fr radiale Linien muss einer von ("solid","dotted","dashed","longdashed") sein.',0), +22006 => array('Es wurde ein ungltiger Windrosentyp angegeben.',0), +22007 => array('Es wurden zu wenig Werte fr die Bereichslegende angegeben.',0), +22008 => array('Interner Fehler: Versuch, eine freie Windrose zu plotten, obwohl der Typ keine freie Windrose ist.',0), +22009 => array('Du hast die gleiche Richtung zweimal angegeben, einmal mit einem Winkel und einmal mit einer Kompassrichtung (%f Grad).',0), +22010 => array('Die Richtung muss entweder ein numerischer Wert sein oder eine der 16 Kompassrichtungen',0), +22011 => array('Der Windrosenindex muss ein numerischer oder Richtungswert sein. Du hast angegeben Index=%d',1), +22012 => array('Die radiale Achsendefinition fr die Windrose enthlt eine nicht aktivierte Richtung.',0), +22013 => array('Du hast dasselbe Look&Feel fr die gleiche Kompassrichtung zweimal engegeben, einmal mit Text und einmal mit einem Index (Index=%d)',1), +22014 => array('Der Index fr eine Kompassrichtung muss zwischen 0 und 15 sein.',0), +22015 => array('Du hast einen unbekannten Windrosenplottyp angegeben.',0), +22016 => array('Der Windrosenarmindex muss ein numerischer oder ein Richtungswert sein.',0), +22017 => array('Die Windrosendaten enthalten eine Richtung, die nicht aktiviert ist. Bitte berichtige, welche Label angezeigt werden sollen.',0), +22018 => array('Du hast fr dieselbe Kompassrichtung zweimal Daten angegeben, einmal mit Text und einmal mit einem Index (Index=%d)',1), +22019 => array('Der Index fr eine Richtung muss zwischen 0 und 15 sein. Winkel drfen nicht fr einen regelmigen Windplot angegeben werden, sondern entweder ein Index oder eine Kompassrichtung.',0), +22020 => array('Der Windrosenplot ist zu gro fr die angegebene Bildgre. Benutze entweder WindrosePlot::SetSize(), um den Plot kleiner zu machen oder vergrere das Bild im ursprnglichen Aufruf von WindroseGraph().',0), +22021 => array('It is only possible to add Text, IconPlot or WindrosePlot to a Windrose Graph',0), + +/* +** jpgraph_odometer +*/ + +13001 => array('Unbekannter Nadeltypstil (%d).',1), +13002 => array('Ein Wert fr das Odometer (%f) ist auerhalb des angegebenen Bereichs [%f,%f]',3), + +/* +** jpgraph_barcode +*/ + +1001 => array('Unbekannte Kodier-Specifikation: %s',1), +1002 => array('datenvalidierung schlug fehl. [%s] kann nicht mittels der Kodierung "%s" kodiert werden',2), +1003 => array('Interner Kodierfehler. Kodieren von %s ist nicht mglich in Code 128',1), +1004 => array('Interner barcode Fehler. Unbekannter UPC-E Kodiertyp: %s',1), +1005 => array('Interner Fehler. Das Textzeichen-Tupel (%s, %s) kann nicht im Code-128 Zeichensatz C kodiert werden.',2), +1006 => array('Interner Kodierfehler fr CODE 128. Es wurde versucht, CTRL in CHARSET != A zu kodieren.',0), +1007 => array('Interner Kodierfehler fr CODE 128. Es wurde versucht, DEL in CHARSET != B zu kodieren.',0), +1008 => array('Interner Kodierfehler fr CODE 128. Es wurde versucht, kleine Buchstaben in CHARSET != B zu kodieren.',0), +1009 => array('Kodieren mittels CODE 93 wird noch nicht untersttzt.',0), +1010 => array('Kodieren mittels POSTNET wird noch nicht untersttzt.',0), +1011 => array('Nicht untrsttztes Barcode-Backend fr den Typ %s',1), + +/* +** PDF417 +*/ + +26001 => array('PDF417: Die Anzahl der Spalten muss zwischen 1 und 30 sein.',0), +26002 => array('PDF417: Der Fehler-Level muss zwischen 0 und 8 sein.',0), +26003 => array('PDF417: Ungltiges Format fr Eingabedaten, um sie mit PDF417 zu kodieren.',0), +26004 => array('PDF417: die eigebenen Daten knnen nicht mit Fehler-Level %d und %d spalten kodiert werden, weil daraus zu viele Symbole oder mehr als 90 Zeilen resultieren.',2), +26005 => array('PDF417: Die Datei "%s" kann nicht zum Schreiben geffnet werden.',1), +26006 => array('PDF417: Interner Fehler. Die Eingabedatendatei fr PDF417-Cluster %d ist fehlerhaft.',1), +26007 => array('PDF417: Interner Fehler. GetPattern: Ungltiger Code-Wert %d (Zeile %d)',2), +26008 => array('PDF417: Interner Fehler. Modus wurde nicht in der Modusliste!! Modus %d',1), +26009 => array('PDF417: Kodierfehler: Ungltiges Zeichen. Zeichen kann nicht mit ASCII-Code %d kodiert werden.',1), +26010 => array('PDF417: Interner Fehler: Keine Eingabedaten beim Dekodieren.',0), +26011 => array('PDF417: Kodierfehler. Numerisches Kodieren bei nicht-numerischen Daten nicht mglich.',0), +26012 => array('PDF417: Interner Fehler. Es wurden fr den Binary-Kompressor keine Daten zum Dekodieren eingegeben.',0), +26013 => array('PDF417: Interner Fehler. Checksum Fehler. Koeffiziententabellen sind fehlerhaft.',0), +26014 => array('PDF417: Interner Fehler. Es wurden keine Daten zum Berechnen von Kodewrtern eingegeben.',0), +26015 => array('PDF417: Interner Fehler. Ein Eintrag 0 in die Statusbertragungstabellen ist nicht NULL. Eintrag 1 = (%s)',1), +26016 => array('PDF417: Interner Fehler: Nichtregistrierter Statusbertragungsmodus beim Dekodieren.',0), + + +); + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/lang/en.inc.php b/plugins/dwJpgraphPlugin/lib/jpgraph/lang/en.inc.php new file mode 100644 index 0000000..ea65986 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/lang/en.inc.php @@ -0,0 +1,497 @@ +,) +$_jpg_messages = array( + +/* +** Headers already sent error. This is formatted as HTML different since this will be sent back directly as text +*/ +10 => array('
    JpGraph Error: +HTTP headers have already been sent.
    Caused by output from file %s at line %d.
    Explanation:
    HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it\'s image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).

    Most likely you have some text in your script before the call to Graph::Stroke(). If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser.

    For example it is a common mistake to leave a blank line before the opening "<?php".

    ',2), + +/* +** Setup errors +*/ +11 => array('No path specified for CACHE_DIR. Please specify CACHE_DIR manually in jpg-config.inc',0), +12 => array('No path specified for TTF_DIR and path can not be determined automatically. Please specify TTF_DIR manually (in jpg-config.inc).',0), +13 => array('The installed PHP version (%s) is not compatible with this release of the library. The library requires at least PHP version %s',2), + + +/* +** jpgraph_bar +*/ + +2001 => array('Number of colors is not the same as the number of patterns in BarPlot::SetPattern()',0), +2002 => array('Unknown pattern specified in call to BarPlot::SetPattern()',0), +2003 => array('Number of X and Y points are not equal. Number of X-points: %d Number of Y-points: %d',2), +2004 => array('All values for a barplot must be numeric. You have specified value nr [%d] == %s',2), +2005 => array('You have specified an empty array for shadow colors in the bar plot.',0), +2006 => array('Unknown position for values on bars : %s',1), +2007 => array('Cannot create GroupBarPlot from empty plot array.',0), +2008 => array('Group bar plot element nbr %d is undefined or empty.',0), +2009 => array('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the GroupBar plot from an array of BarPlot or AccBarPlot objects. (Class = %s)',1), +2010 => array('Cannot create AccBarPlot from empty plot array.',0), +2011 => array('Acc bar plot element nbr %d is undefined or empty.',1), +2012 => array('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects. (Class=%s)',1), +2013 => array('You have specified an empty array for shadow colors in the bar plot.',0), +2014 => array('Number of datapoints for each data set in accbarplot must be the same',0), + + +/* +** jpgraph_date +*/ + +3001 => array('It is only possible to use either SetDateAlign() or SetTimeAlign() but not both',0), + +/* +** jpgraph_error +*/ + +4002 => array('Error in input data to LineErrorPlot. Number of data points must be a multiple of 3',0), + +/* +** jpgraph_flags +*/ + +5001 => array('Unknown flag size (%d).',1), +5002 => array('Flag index %s does not exist.',1), +5003 => array('Invalid ordinal number (%d) specified for flag index.',1), +5004 => array('The (partial) country name %s does not have a corresponding flag image. The flag may still exist but under another name, e.g. instead of "usa" try "united states".',1), + + +/* +** jpgraph_gantt +*/ + +6001 => array('Internal error. Height for ActivityTitles is < 0',0), +6002 => array('You can\'t specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension.',0), +6003 => array('Invalid format for Constrain parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)',1), +6004 => array('Invalid format for Progress parameter at index=%d in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)',1), +6005 => array('SetScale() is not meaningful with Gantt charts.',0), +6006 => array('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]',0), +6007 => array('Sanity check for automatic Gantt chart size failed. Either the width (=%d) or height (=%d) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities.',2), +6008 => array('You have specified a constrain from row=%d to row=%d which does not have any activity',2), +6009 => array('Unknown constrain type specified from row=%d to row=%d',2), +6010 => array('Illegal icon index for Gantt builtin icon [%d]',1), +6011 => array('Argument to IconImage must be string or integer',0), +6012 => array('Unknown type in Gantt object title specification',0), +6015 => array('Illegal vertical position %d',1), +6016 => array('Date string (%s) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30',1), +6017 => array('Unknown date format in GanttScale (%s).',1), +6018 => array('Interval for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an interval of %d minutes.',1), +6019 => array('The available width (%d) for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.',1), +6020 => array('Interval for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an interval of %d',1), +6021 => array('Unknown formatting style for week.',0), +6022 => array('Gantt scale has not been specified.',0), +6023 => array('If you display both hour and minutes the hour interval must be 1 (Otherwise it doesn\'t make sense to display minutes).',0), +6024 => array('CSIM Target must be specified as a string. Start of target is: %d',1), +6025 => array('CSIM Alt text must be specified as a string. Start of alt text is: %d',1), +6027 => array('Progress value must in range [0, 1]',0), +6028 => array('Specified height (%d) for gantt bar is out of range.',1), +6029 => array('Offset for vertical line must be in range [0,1]',0), +6030 => array('Unknown arrow direction for link.',0), +6031 => array('Unknown arrow type for link.',0), +6032 => array('Internal error: Unknown path type (=%d) specified for link.',1), + +/* +** jpgraph_gradient +*/ + +7001 => array('Unknown gradient style (=%d).',1), + +/* +** jpgraph_iconplot +*/ + +8001 => array('Mix value for icon must be between 0 and 100.',0), +8002 => array('Anchor position for icons must be one of "top", "bottom", "left", "right" or "center"',0), +8003 => array('It is not possible to specify both an image file and a country flag for the same icon.',0), +8004 => array('In order to use Country flags as icons you must include the "jpgraph_flags.php" file.',0), + +/* +** jpgraph_imgtrans +*/ + +9001 => array('Value for image transformation out of bounds. Vanishing point on horizon must be specified as a value between 0 and 1.',0), + +/* +** jpgraph_lineplot +*/ + +10001 => array('LinePlot::SetFilled() is deprecated. Use SetFillColor()',0), +10002 => array('Plot too complicated for fast line Stroke. Use standard Stroke()',0), + +/* +** jpgraph_log +*/ + +11001 => array('Your data contains non-numeric values.',0), +11002 => array('Negative data values can not be used in a log scale.',0), +11003 => array('Your data contains non-numeric values.',0), +11004 => array('Scale error for logarithmic scale. You have a problem with your data values. The max value must be greater than 0. It is mathematically impossible to have 0 in a logarithmic scale.',0), +11005 => array('Specifying tick interval for a logarithmic scale is undefined. Remove any calls to SetTextLabelStart() or SetTextTickInterval() on the logarithmic scale.',0), + +/* +** jpgraph_mgraph +*/ + +12001 => array("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.",0), +12002 => array('Incorrect file name for MGraph::SetBackgroundImage() : %s Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1), +12003 => array('Unknown file extension (%s) in MGraph::SetBackgroundImage() for filename: %s',2), +12004 => array('The image format of your background image (%s) is not supported in your system configuration. ',1), +12005 => array('Can\'t read background image: %s',1), +12006 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2), +12007 => array('Argument to MGraph::Add() is not a valid GD image handle.',0), +12008 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats.',0), +12009 => array('Your PHP installation does not support the chosen graphic format: %s',1), +12010 => array('Can\'t create or stream image to file %s Check that PHP has enough permission to write a file to the current directory.',1), +12011 => array('Can\'t create truecolor image. Check that you really have GD2 library installed.',0), +12012 => array('Can\'t create image. Check that you really have GD2 library installed.',0), + +/* +** jpgraph_pie3d +*/ + +14001 => array('Pie3D::ShowBorder() . Deprecated function. Use Pie3D::SetEdge() to control the edges around slices.',0), +14002 => array('PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.',0), +14003 => array('Internal assertion failed. Pie3D::Pie3DSlice',0), +14004 => array('Slice start angle must be between 0 and 360 degrees.',0), +14005 => array('Pie3D Internal error: Trying to wrap twice when looking for start index',0,), +14006 => array('Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.',0), +14007 => array('Width for 3D Pie is 0. Specify a size > 0',0), + +/* +** jpgraph_pie +*/ + +15001 => array('PiePLot::SetTheme() Unknown theme: %s',1), +15002 => array('Argument to PiePlot::ExplodeSlice() must be an integer',0), +15003 => array('Argument to PiePlot::Explode() must be an array with integer distances.',0), +15004 => array('Slice start angle must be between 0 and 360 degrees.',0), +15005 => array('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.',0), +15006 => array('PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]',0), +15007 => array('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.',0), +15008 => array('PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not %d).',1), +15009 => array('Illegal pie plot. Sum of all data is zero for Pie Plot',0), +15010 => array('Sum of all data is 0 for Pie.',0), +15011 => array('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.',0), + +/* +** jpgraph_plotband +*/ + +16001 => array('Density for pattern must be between 1 and 100. (You tried %f)',1), +16002 => array('No positions specified for pattern.',0), +16003 => array('Unknown pattern specification (%d)',0), +16004 => array('Min value for plotband is larger than specified max value. Please correct.',0), + + +/* +** jpgraph_polar +*/ + +17001 => array('Polar plots must have an even number of data point. Each data point is a tuple (angle,radius).',0), +17002 => array('Unknown alignment specified for X-axis title. (%s)',1), +//17003 => array('Set90AndMargin() is not supported for polar graphs.',0), +17004 => array('Unknown scale type for polar graph. Must be "lin" or "log"',0), + +/* +** jpgraph_radar +*/ + +18001 => array('Client side image maps not supported for RadarPlots.',0), +18002 => array('RadarGraph::SupressTickMarks() is deprecated. Use HideTickMarks() instead.',0), +18003 => array('Illegal scale for radarplot (%s). Must be \'lin\' or \'log\'',1), +18004 => array('Radar Plot size must be between 0.1 and 1. (Your value=%f)',1), +18005 => array('RadarPlot Unsupported Tick density: %d',1), +18006 => array('Minimum data %f (Radar plots should only be used when all data points > 0)',1), +18007 => array('Number of titles does not match number of points in plot.',0), +18008 => array('Each radar plot must have the same number of data points.',0), + +/* +** jpgraph_regstat +*/ + +19001 => array('Spline: Number of X and Y coordinates must be the same',0), +19002 => array('Invalid input data for spline. Two or more consecutive input X-values are equal. Each input X-value must differ since from a mathematical point of view it must be a one-to-one mapping, i.e. each X-value must correspond to exactly one Y-value.',0), +19003 => array('Bezier: Number of X and Y coordinates must be the same',0), + +/* +** jpgraph_scatter +*/ + +20001 => array('Fieldplots must have equal number of X and Y points.',0), +20002 => array('Fieldplots must have an angle specified for each X and Y points.',0), +20003 => array('Scatterplot must have equal number of X and Y points.',0), + +/* +** jpgraph_stock +*/ + +21001 => array('Data values for Stock charts must contain an even multiple of %d data points.',1), + +/* +** jpgraph_plotmark +*/ + +23001 => array('This marker "%s" does not exist in color with index: %d',2), +23002 => array('Mark color index too large for marker "%s"',1), +23003 => array('A filename must be specified if you set the mark type to MARK_IMG.',0), + +/* +** jpgraph_utils +*/ + +24001 => array('FuncGenerator : No function specified. ',0), +24002 => array('FuncGenerator : Syntax error in function specification ',0), +24003 => array('DateScaleUtils: Unknown tick type specified in call to GetTicks()',0), +/* +** jpgraph +*/ + +25001 => array('This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)',0), +25002 => array('Your PHP installation does not seem to have the required GD library. Please see the PHP documentation on how to install and enable the GD library.',0), +25003 => array('General PHP error : At %s:%d : %s',3), +25004 => array('General PHP error : %s ',1), +25005 => array('Can\'t access PHP_SELF, PHP global variable. You can\'t run PHP from command line if you want to use the \'auto\' naming of cache or image files.',0), +25006 => array('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).',0), +25007 => array('You are trying to use the locale (%s) which your PHP installation does not support. Hint: Use \'\' to indicate the default locale for this geographic region.',1), +25008 => array('Image width/height argument in Graph::Graph() must be numeric',0), +25009 => array('You must specify what scale to use with a call to Graph::SetScale()',0), + +25010 => array('Graph::Add() You tried to add a null plot to the graph.',0), +25011 => array('Graph::AddY2() You tried to add a null plot to the graph.',0), +25012 => array('Graph::AddYN() You tried to add a null plot to the graph.',0), +25013 => array('You can only add standard plots to multiple Y-axis',0), +25014 => array('Graph::AddText() You tried to add a null text to the graph.',0), +25015 => array('Graph::AddLine() You tried to add a null line to the graph.',0), +25016 => array('Graph::AddBand() You tried to add a null band to the graph.',0), +25017 => array('You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x it is necessary to enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.',0), +25018 => array('Incorrect file name for Graph::SetBackgroundImage() : "%s" Must have a valid image extension (jpg,gif,png) when using auto detection of image type',1), +25019 => array('Unknown file extension (%s) in Graph::SetBackgroundImage() for filename: "%s"',2), + +25020 => array('Graph::SetScale(): Specified Max value must be larger than the specified Min value.',0), +25021 => array('Unknown scale specification for Y-scale. (%s)',1), +25022 => array('Unknown scale specification for X-scale. (%s)',1), +25023 => array('Unsupported Y2 axis type: "%s" Must be one of (lin,log,int)',1), +25024 => array('Unsupported Y axis type: "%s" Must be one of (lin,log,int)',1), +25025 => array('Unsupported Tick density: %d',1), +25026 => array('Can\'t draw unspecified Y-scale. You have either: 1. Specified an Y axis for auto scaling but have not supplied any plots. 2. Specified a scale manually but have forgot to specify the tick steps',0), +25027 => array('Can\'t open cached CSIM "%s" for reading.',1), +25028 => array('Apache/PHP does not have permission to write to the CSIM cache directory (%s). Check permissions.',1), +25029 => array('Can\'t write CSIM "%s" for writing. Check free space and permissions.',1), + +25030 => array('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().',0), +25031 => array('You must specify what scale to use with a call to Graph::SetScale().',0), +25032 => array('No plots for Y-axis nbr:%d',1), +25033 => array('',0), +25034 => array('Can\'t draw unspecified X-scale. No plots specified.',0), +25035 => array('You have enabled clipping. Clipping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (=%d degrees) or disable clipping.',1), +25036 => array('Unknown AxisStyle() : %s',1), +25037 => array('The image format of your background image (%s) is not supported in your system configuration. ',1), +25038 => array('Background image seems to be of different type (has different file extension) than specified imagetype. Specified: %s File: %s',2), +25039 => array('Can\'t read background image: "%s"',1), + +25040 => array('It is not possible to specify both a background image and a background country flag.',0), +25041 => array('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.',0), +25042 => array('Unknown background image layout',0), +25043 => array('Unknown title background style.',0), +25044 => array('Cannot use auto scaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).',0), +25045 => array('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph. Please download fonts from http://corefonts.sourceforge.net/',0), +25046 => array('Specified TTF font family (id=%d) is unknown or does not exist. Please note that TTF fonts are not distributed with JpGraph for copyright reasons. You can find the MS TTF WEB-fonts (arial, courier etc) for download at http://corefonts.sourceforge.net/',1), +25047 => array('Style %s is not available for font family %s',2), +25048 => array('Unknown font style specification [%s].',1), +25049 => array('Font file "%s" is not readable or does not exist.',1), + +25050 => array('First argument to Text::Text() must be a string.',0), +25051 => array('Invalid direction specified for text.',0), +25052 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text',0), +25053 => array('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text',0), +25054 => array('Internal error: Unknown grid axis %s',1), +25055 => array('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead',0), +25056 => array('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.',0), +25057 => array('SetTextTicks() is deprecated. Use SetTextTickInterval() instead.',0), +25058 => array('Text label interval must be specified >= 1.',0), +25059 => array('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.',0), + +25060 => array('Unknown alignment specified for X-axis title. (%s)',1), +25061 => array('Unknown alignment specified for Y-axis title. (%s)',1), +25062 => array('Labels at an angle are not supported on Y-axis',0), +25063 => array('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead',0), +25064 => array('Minor or major step size is 0. Check that you haven\'t got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem',0), +25065 => array('Tick positions must be specified as an array()',0), +25066 => array('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.',0), +25067 => array('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tick marks.',0), +25068 => array('A plot has an illegal scale. This could for example be that you are trying to use text auto scaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only \'-\' or \'x\')',0), +25069 => array('Grace must be larger then 0',0), +25070 => array('Either X or Y data arrays contains non-numeric values. Check that the data is really specified as numeric data and not as strings. It is an error to specify data for example as \'-2345.2\' (using quotes).',0), +25071 => array('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.',0), +25072 => array('You have specified a max value with SetAutoMax() which is smaller than the minimum value used for the scale. This is not possible.',0), +25073 => array('Internal error. Integer scale algorithm comparison out of bound (r=%f)',1), +25074 => array('Internal error. The scale range is negative (%f) [for %s scale] This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the auto scaling to fail.',2), +25075 => array('Can\'t automatically determine ticks since min==max.',0), +25077 => array('Adjustment factor for color must be > 0',0), +25078 => array('Unknown color: %s',1), +25079 => array('Unknown color specification: %s, size=%d',2), + +25080 => array('Alpha parameter for color must be between 0.0 and 1.0',0), +25081 => array('Selected graphic format is either not supported or unknown [%s]',1), +25082 => array('Illegal sizes specified for width or height when creating an image, (width=%d, height=%d)',2), +25083 => array('Illegal image size when copying image. Size for copied to image is 1 pixel or less.',0), +25084 => array('Failed to create temporary GD canvas. Possible Out of memory problem.',0), +25085 => array('An image can not be created from the supplied string. It is either in a format not supported or the string is representing an corrupt image.',0), +25086 => array('You only seem to have GD 1.x installed. To enable Alphablending requires GD 2.x or higher. Please install GD or make sure the constant USE_GD2 is specified correctly to reflect your installation. By default it tries to auto detect what version of GD you have installed. On some very rare occasions it may falsely detect GD2 where only GD1 is installed. You must then set USE_GD2 to false.',0), +25087 => array('This PHP build has not been configured with TTF support. You need to recompile your PHP installation with FreeType support.',0), +25088 => array('You have a misconfigured GD font support. The call to imagefontwidth() fails.',0), +25089 => array('You have a misconfigured GD font support. The call to imagefontheight() fails.',0), + +25090 => array('Unknown direction specified in call to StrokeBoxedText() [%s]',1), +25091 => array('Internal font does not support drawing text at arbitrary angle. Use TTF fonts instead.',0), +25092 => array('There is either a configuration problem with TrueType or a problem reading font file "%s" Make sure file exists and is in a readable place for the HTTP process. (If \'basedir\' restriction is enabled in PHP then the font file must be located in the document root.). It might also be a wrongly installed FreeType library. Try upgrading to at least FreeType 2.1.13 and recompile GD with the correct setup so it can find the new FT library.',1), +25093 => array('Can not read font file "%s" in call to Image::GetBBoxTTF. Please make sure that you have set a font before calling this method and that the font is installed in the TTF directory.',1), +25094 => array('Direction for text most be given as an angle between 0 and 90.',0), +25095 => array('Unknown font font family specification. ',0), +25096 => array('Can\'t allocate any more colors in palette image. Image has already allocated maximum of %d colors and the palette is now full. Change to a truecolor image instead',0), +25097 => array('Color specified as empty string in PushColor().',0), +25098 => array('Negative Color stack index. Unmatched call to PopColor()',0), +25099 => array('Parameters for brightness and Contrast out of range [-1,1]',0), + +25100 => array('Problem with color palette and your GD setup. Please disable anti-aliasing or use GD2 with true-color. If you have GD2 library installed please make sure that you have set the USE_GD2 constant to true and truecolor is enabled.',0), +25101 => array('Illegal numeric argument to SetLineStyle(): (%d)',1), +25102 => array('Illegal string argument to SetLineStyle(): %s',1), +25103 => array('Illegal argument to SetLineStyle %s',1), +25104 => array('Unknown line style: %s',1), +25105 => array('NULL data specified for a filled polygon. Check that your data is not NULL.',0), +25106 => array('Image::FillToBorder : Can not allocate more colors',0), +25107 => array('Can\'t write to file "%s". Check that the process running PHP has enough permission.',1), +25108 => array('Can\'t stream image. This is most likely due to a faulty PHP/GD setup. Try to recompile PHP and use the built-in GD library that comes with PHP.',0), +25109 => array('Your PHP (and GD-lib) installation does not appear to support any known graphic formats. You need to first make sure GD is compiled as a module to PHP. If you also want to use JPEG images you must get the JPEG library. Please see the PHP docs for details.',0), + +25110 => array('Your PHP installation does not support the chosen graphic format: %s',1), +25111 => array('Can\'t delete cached image %s. Permission problem?',1), +25112 => array('Cached imagefile (%s) has file date in the future.',1), +25113 => array('Can\'t delete cached image "%s". Permission problem?',1), +25114 => array('PHP has not enough permissions to write to the cache file "%s". Please make sure that the user running PHP has write permission for this file if you wan to use the cache system with JpGraph.',1), +25115 => array('Can\'t set permission for cached image "%s". Permission problem?',1), +25116 => array('Cant open file from cache "%s"',1), +25117 => array('Can\'t open cached image "%s" for reading.',1), +25118 => array('Can\'t create directory "%s". Make sure PHP has write permission to this directory.',1), +25119 => array('Can\'t set permissions for "%s". Permission problems?',1), + +25120 => array('Position for legend must be given as percentage in range 0-1',0), +25121 => array('Empty input data array specified for plot. Must have at least one data point.',0), +25122 => array('Stroke() must be implemented by concrete subclass to class Plot',0), +25123 => array('You can\'t use a text X-scale with specified X-coords. Use a "int" or "lin" scale instead.',0), +25124 => array('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)',0), +25125 => array('Illegal direction for static line',0), +25126 => array('Can\'t create truecolor image. Check that the GD2 library is properly setup with PHP.',0), +25127 => array('The library has been configured for automatic encoding conversion of Japanese fonts. This requires that PHP has the mb_convert_encoding() function. Your PHP installation lacks this function (PHP needs the "--enable-mbstring" when compiled).',0), +25128 => array('The function imageantialias() is not available in your PHP installation. Use the GD version that comes with PHP and not the standalone version.',0), + +/* +**--------------------------------------------------------------------------------------------- +** Pro-version strings +**--------------------------------------------------------------------------------------------- +*/ + +/* +** jpgraph_table +*/ + +27001 => array('GTextTable: Invalid argument to Set(). Array argument must be 2 dimensional',0), +27002 => array('GTextTable: Invalid argument to Set()',0), +27003 => array('GTextTable: Wrong number of arguments to GTextTable::SetColor()',0), +27004 => array('GTextTable: Specified cell range to be merged is not valid.',0), +27005 => array('GTextTable: Cannot merge already merged cells in the range: (%d,%d) to (%d,%d)',4), +27006 => array('GTextTable: Column argument = %d is outside specified table size.',1), +27007 => array('GTextTable: Row argument = %d is outside specified table size.',1), +27008 => array('GTextTable: Column and row size arrays must match the dimensions of the table',0), +27009 => array('GTextTable: Number of table columns or rows are 0. Make sure Init() or Set() is called.',0), +27010 => array('GTextTable: No alignment specified in call to SetAlign()',0), +27011 => array('GTextTable: Unknown alignment specified in SetAlign(). Horizontal=%s, Vertical=%s',2), +27012 => array('GTextTable: Internal error. Invalid alignment specified =%s',1), +27013 => array('GTextTable: Argument to FormatNumber() must be a string.',0), +27014 => array('GTextTable: Table is not initilaized with either a call to Set() or Init()',0), +27015 => array('GTextTable: Cell image constrain type must be TIMG_WIDTH or TIMG_HEIGHT',0), + +/* +** jpgraph_windrose +*/ + +22001 => array('Total percentage for all windrose legs in a windrose plot can not exceed 100%% !\n(Current max is: %d)',1), +22002 => array('Graph is too small to have a scale. Please make the graph larger.',0), +22004 => array('Label specification for windrose directions must have 16 values (one for each compass direction).',0), +22005 => array('Line style for radial lines must be on of ("solid","dotted","dashed","longdashed") ',0), +22006 => array('Illegal windrose type specified.',0), +22007 => array('To few values for the range legend.',0), +22008 => array('Internal error: Trying to plot free Windrose even though type is not a free windrose',0), +22009 => array('You have specified the same direction twice, once with an angle and once with a compass direction (%f degrees)',0), +22010 => array('Direction must either be a numeric value or one of the 16 compass directions',0), +22011 => array('Windrose index must be numeric or direction label. You have specified index=%d',1), +22012 => array('Windrose radial axis specification contains a direction which is not enabled.',0), +22013 => array('You have specified the look&feel for the same compass direction twice, once with text and once with index (Index=%d)',1), +22014 => array('Index for compass direction must be between 0 and 15.',0), +22015 => array('You have specified an undefined Windrose plot type.',0), +22016 => array('Windrose leg index must be numeric or direction label.',0), +22017 => array('Windrose data contains a direction which is not enabled. Please adjust what labels are displayed.',0), +22018 => array('You have specified data for the same compass direction twice, once with text and once with index (Index=%d)',1), +22019 => array('Index for direction must be between 0 and 15. You can\'t specify angles for a Regular Windplot, only index and compass directions.',0), +22020 => array('Windrose plot is too large to fit the specified Graph size. Please use WindrosePlot::SetSize() to make the plot smaller or increase the size of the Graph in the initial WindroseGraph() call.',0), +22021 => array('It is only possible to add Text, IconPlot or WindrosePlot to a Windrose Graph',0), +/* +** jpgraph_odometer +*/ + +13001 => array('Unknown needle style (%d).',1), +13002 => array('Value for odometer (%f) is outside specified scale [%f,%f]',3), + +/* +** jpgraph_barcode +*/ + +1001 => array('Unknown encoder specification: %s',1), +1002 => array('Data validation failed. Can\'t encode [%s] using encoding "%s"',2), +1003 => array('Internal encoding error. Trying to encode %s is not possible in Code 128',1), +1004 => array('Internal barcode error. Unknown UPC-E encoding type: %s',1), +1005 => array('Internal error. Can\'t encode character tuple (%s, %s) in Code-128 charset C',2), +1006 => array('Internal encoding error for CODE 128. Trying to encode control character in CHARSET != A',0), +1007 => array('Internal encoding error for CODE 128. Trying to encode DEL in CHARSET != B',0), +1008 => array('Internal encoding error for CODE 128. Trying to encode small letters in CHARSET != B',0), +1009 => array('Encoding using CODE 93 is not yet supported.',0), +1010 => array('Encoding using POSTNET is not yet supported.',0), +1011 => array('Non supported barcode backend for type %s',1), + +/* +** PDF417 +*/ + +26001 => array('PDF417: Number of Columns must be >= 1 and <= 30',0), +26002 => array('PDF417: Error level must be between 0 and 8',0), +26003 => array('PDF417: Invalid format for input data to encode with PDF417',0), +26004 => array('PDF417: Can\'t encode given data with error level %d and %d columns since it results in too many symbols or more than 90 rows.',2), +26005 => array('PDF417: Can\'t open file "%s" for writing',1), +26006 => array('PDF417: Internal error. Data files for PDF417 cluster %d is corrupted.',1), +26007 => array('PDF417: Internal error. GetPattern: Illegal Code Value = %d (row=%d)',2), +26008 => array('PDF417: Internal error. Mode not found in mode list!! mode=%d',1), +26009 => array('PDF417: Encode error: Illegal character. Can\'t encode character with ASCII code=%d',1), +26010 => array('PDF417: Internal error: No input data in decode.',0), +26011 => array('PDF417: Encoding error. Can\'t use numeric encoding on non-numeric data.',0), +26012 => array('PDF417: Internal error. No input data to decode for Binary compressor.',0), +26013 => array('PDF417: Internal error. Checksum error. Coefficient tables corrupted.',0), +26014 => array('PDF417: Internal error. No data to calculate codewords on.',0), +26015 => array('PDF417: Internal error. State transition table entry 0 is NULL. Entry 1 = (%s)',1), +26016 => array('PDF417: Internal error: Unrecognized state transition mode in decode.',0), + + +); + +?> diff --git a/plugins/dwJpgraphPlugin/lib/jpgraph/lang/prod.inc.php b/plugins/dwJpgraphPlugin/lib/jpgraph/lang/prod.inc.php new file mode 100644 index 0000000..7b246f9 --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/jpgraph/lang/prod.inc.php @@ -0,0 +1,354 @@ +,) +$_jpg_messages = array( + +/* +** Headers already sent error. This is formatted as HTML different since this will be sent back directly as text +*/ +10 => array('
    JpGraph Error: +HTTP headers have already been sent.
    Caused by output from file %s at line %d.
    Explanation:
    HTTP headers have already been sent back to the browser indicating the data as text before the library got a chance to send it\'s image HTTP header to this browser. This makes it impossible for the library to send back image data to the browser (since that would be interpretated as text by the browser and show up as junk text).

    Most likely you have some text in your script before the call to Graph::Stroke(). If this texts gets sent back to the browser the browser will assume that all data is plain text. Look for any text, even spaces and newlines, that might have been sent back to the browser.

    For example it is a common mistake to leave a blank line before the opening "<?php".

    ',2), + + +11 => array(DEFAULT_ERROR_MESSAGE.'11',0), +12 => array(DEFAULT_ERROR_MESSAGE.'12',0), +13 => array(DEFAULT_ERROR_MESSAGE.'13',0), +2001 => array(DEFAULT_ERROR_MESSAGE.'2001',0), +2002 => array(DEFAULT_ERROR_MESSAGE.'2002',0), +2003 => array(DEFAULT_ERROR_MESSAGE.'2003',0), +2004 => array(DEFAULT_ERROR_MESSAGE.'2004',0), +2005 => array(DEFAULT_ERROR_MESSAGE.'2005',0), +2006 => array(DEFAULT_ERROR_MESSAGE.'2006',0), +2007 => array(DEFAULT_ERROR_MESSAGE.'2007',0), +2008 => array(DEFAULT_ERROR_MESSAGE.'2008',0), +2009 => array(DEFAULT_ERROR_MESSAGE.'2009',0), +2010 => array(DEFAULT_ERROR_MESSAGE.'2010',0), +2011 => array(DEFAULT_ERROR_MESSAGE.'2011',0), +2012 => array(DEFAULT_ERROR_MESSAGE.'2012',0), +2013 => array(DEFAULT_ERROR_MESSAGE.'2013',0), +2014 => array(DEFAULT_ERROR_MESSAGE.'2014',0), +3001 => array(DEFAULT_ERROR_MESSAGE.'3001',0), +4002 => array(DEFAULT_ERROR_MESSAGE.'4002',0), +5001 => array(DEFAULT_ERROR_MESSAGE.'5001',0), +5002 => array(DEFAULT_ERROR_MESSAGE.'5002',0), +5003 => array(DEFAULT_ERROR_MESSAGE.'5003',0), +5004 => array(DEFAULT_ERROR_MESSAGE.'5004',0), +6001 => array(DEFAULT_ERROR_MESSAGE.'6001',0), +6002 => array(DEFAULT_ERROR_MESSAGE.'6002',0), +6003 => array(DEFAULT_ERROR_MESSAGE.'6003',0), +6004 => array(DEFAULT_ERROR_MESSAGE.'6004',0), +6005 => array(DEFAULT_ERROR_MESSAGE.'6005',0), +6006 => array(DEFAULT_ERROR_MESSAGE.'6006',0), +6007 => array(DEFAULT_ERROR_MESSAGE.'6007',0), +6008 => array(DEFAULT_ERROR_MESSAGE.'6008',0), +6009 => array(DEFAULT_ERROR_MESSAGE.'6009',0), +6010 => array(DEFAULT_ERROR_MESSAGE.'6010',0), +6011 => array(DEFAULT_ERROR_MESSAGE.'6011',0), +6012 => array(DEFAULT_ERROR_MESSAGE.'6012',0), +6015 => array(DEFAULT_ERROR_MESSAGE.'6015',0), +6016 => array(DEFAULT_ERROR_MESSAGE.'6016',0), +6017 => array(DEFAULT_ERROR_MESSAGE.'6017',0), +6018 => array(DEFAULT_ERROR_MESSAGE.'6018',0), +6019 => array(DEFAULT_ERROR_MESSAGE.'6019',0), +6020 => array(DEFAULT_ERROR_MESSAGE.'6020',0), +6021 => array(DEFAULT_ERROR_MESSAGE.'6021',0), +6022 => array(DEFAULT_ERROR_MESSAGE.'6022',0), +6023 => array(DEFAULT_ERROR_MESSAGE.'6023',0), +6024 => array(DEFAULT_ERROR_MESSAGE.'6024',0), +6025 => array(DEFAULT_ERROR_MESSAGE.'6025',0), +6027 => array(DEFAULT_ERROR_MESSAGE.'6027',0), +6028 => array(DEFAULT_ERROR_MESSAGE.'6028',0), +6029 => array(DEFAULT_ERROR_MESSAGE.'6029',0), +6030 => array(DEFAULT_ERROR_MESSAGE.'6030',0), +6031 => array(DEFAULT_ERROR_MESSAGE.'6031',0), +6032 => array(DEFAULT_ERROR_MESSAGE.'6032',0), +7001 => array(DEFAULT_ERROR_MESSAGE.'7001',0), +8001 => array(DEFAULT_ERROR_MESSAGE.'8001',0), +8002 => array(DEFAULT_ERROR_MESSAGE.'8002',0), +8003 => array(DEFAULT_ERROR_MESSAGE.'8003',0), +8004 => array(DEFAULT_ERROR_MESSAGE.'8004',0), +9001 => array(DEFAULT_ERROR_MESSAGE.'9001',0), +10001 => array(DEFAULT_ERROR_MESSAGE.'10001',0), +10002 => array(DEFAULT_ERROR_MESSAGE.'10002',0), +11001 => array(DEFAULT_ERROR_MESSAGE.'11001',0), +11002 => array(DEFAULT_ERROR_MESSAGE.'11002',0), +11003 => array(DEFAULT_ERROR_MESSAGE.'11003',0), +11004 => array(DEFAULT_ERROR_MESSAGE.'11004',0), +11005 => array(DEFAULT_ERROR_MESSAGE.'11005',0), +12001 => array(DEFAULT_ERROR_MESSAGE.'12001',0), +12002 => array(DEFAULT_ERROR_MESSAGE.'12002',0), +12003 => array(DEFAULT_ERROR_MESSAGE.'12003',0), +12004 => array(DEFAULT_ERROR_MESSAGE.'12004',0), +12005 => array(DEFAULT_ERROR_MESSAGE.'12005',0), +12006 => array(DEFAULT_ERROR_MESSAGE.'12006',0), +12007 => array(DEFAULT_ERROR_MESSAGE.'12007',0), +12008 => array(DEFAULT_ERROR_MESSAGE.'12008',0), +12009 => array(DEFAULT_ERROR_MESSAGE.'12009',0), +12010 => array(DEFAULT_ERROR_MESSAGE.'12010',0), +12011 => array(DEFAULT_ERROR_MESSAGE.'12011',0), +12012 => array(DEFAULT_ERROR_MESSAGE.'12012',0), +14001 => array(DEFAULT_ERROR_MESSAGE.'14001',0), +14002 => array(DEFAULT_ERROR_MESSAGE.'14002',0), +14003 => array(DEFAULT_ERROR_MESSAGE.'14003',0), +14004 => array(DEFAULT_ERROR_MESSAGE.'14004',0), +14005 => array(DEFAULT_ERROR_MESSAGE.'14005',0), +14006 => array(DEFAULT_ERROR_MESSAGE.'14006',0), +14007 => array(DEFAULT_ERROR_MESSAGE.'14007',0), +15001 => array(DEFAULT_ERROR_MESSAGE.'15001',0), +15002 => array(DEFAULT_ERROR_MESSAGE.'15002',0), +15003 => array(DEFAULT_ERROR_MESSAGE.'15003',0), +15004 => array(DEFAULT_ERROR_MESSAGE.'15004',0), +15005 => array(DEFAULT_ERROR_MESSAGE.'15005',0), +15006 => array(DEFAULT_ERROR_MESSAGE.'15006',0), +15007 => array(DEFAULT_ERROR_MESSAGE.'15007',0), +15008 => array(DEFAULT_ERROR_MESSAGE.'15008',0), +15009 => array(DEFAULT_ERROR_MESSAGE.'15009',0), +15010 => array(DEFAULT_ERROR_MESSAGE.'15010',0), +15011 => array(DEFAULT_ERROR_MESSAGE.'15011',0), +16001 => array(DEFAULT_ERROR_MESSAGE.'16001',0), +16002 => array(DEFAULT_ERROR_MESSAGE.'16002',0), +16003 => array(DEFAULT_ERROR_MESSAGE.'16003',0), +16004 => array(DEFAULT_ERROR_MESSAGE.'16004',0), +17001 => array(DEFAULT_ERROR_MESSAGE.'17001',0), +17002 => array(DEFAULT_ERROR_MESSAGE.'17002',0), +17004 => array(DEFAULT_ERROR_MESSAGE.'17004',0), +18001 => array(DEFAULT_ERROR_MESSAGE.'18001',0), +18002 => array(DEFAULT_ERROR_MESSAGE.'18002',0), +18003 => array(DEFAULT_ERROR_MESSAGE.'18003',0), +18004 => array(DEFAULT_ERROR_MESSAGE.'18004',0), +18005 => array(DEFAULT_ERROR_MESSAGE.'18005',0), +18006 => array(DEFAULT_ERROR_MESSAGE.'18006',0), +18007 => array(DEFAULT_ERROR_MESSAGE.'18007',0), +18008 => array(DEFAULT_ERROR_MESSAGE.'18008',0), +19001 => array(DEFAULT_ERROR_MESSAGE.'19001',0), +19002 => array(DEFAULT_ERROR_MESSAGE.'19002',0), +19003 => array(DEFAULT_ERROR_MESSAGE.'19003',0), +20001 => array(DEFAULT_ERROR_MESSAGE.'20001',0), +20002 => array(DEFAULT_ERROR_MESSAGE.'20002',0), +20003 => array(DEFAULT_ERROR_MESSAGE.'20003',0), +21001 => array(DEFAULT_ERROR_MESSAGE.'21001',0), +23001 => array(DEFAULT_ERROR_MESSAGE.'23001',0), +23002 => array(DEFAULT_ERROR_MESSAGE.'23002',0), +23003 => array(DEFAULT_ERROR_MESSAGE.'23003',0), +24001 => array(DEFAULT_ERROR_MESSAGE.'24001',0), +24002 => array(DEFAULT_ERROR_MESSAGE.'24002',0), +24003 => array(DEFAULT_ERROR_MESSAGE.'24003',0), +25001 => array(DEFAULT_ERROR_MESSAGE.'25001',0), +25002 => array(DEFAULT_ERROR_MESSAGE.'25002',0), +25003 => array(DEFAULT_ERROR_MESSAGE.'25003',0), +25004 => array(DEFAULT_ERROR_MESSAGE.'25004',0), +25005 => array(DEFAULT_ERROR_MESSAGE.'25005',0), +25006 => array(DEFAULT_ERROR_MESSAGE.'25006',0), +25007 => array(DEFAULT_ERROR_MESSAGE.'25007',0), +25008 => array(DEFAULT_ERROR_MESSAGE.'25008',0), +25009 => array(DEFAULT_ERROR_MESSAGE.'25009',0), +25010 => array(DEFAULT_ERROR_MESSAGE.'25010',0), +25011 => array(DEFAULT_ERROR_MESSAGE.'25011',0), +25012 => array(DEFAULT_ERROR_MESSAGE.'25012',0), +25013 => array(DEFAULT_ERROR_MESSAGE.'25013',0), +25014 => array(DEFAULT_ERROR_MESSAGE.'25014',0), +25015 => array(DEFAULT_ERROR_MESSAGE.'25015',0), +25016 => array(DEFAULT_ERROR_MESSAGE.'25016',0), +25017 => array(DEFAULT_ERROR_MESSAGE.'25017',0), +25018 => array(DEFAULT_ERROR_MESSAGE.'25018',0), +25019 => array(DEFAULT_ERROR_MESSAGE.'25019',0), +25020 => array(DEFAULT_ERROR_MESSAGE.'25020',0), +25021 => array(DEFAULT_ERROR_MESSAGE.'25021',0), +25022 => array(DEFAULT_ERROR_MESSAGE.'25022',0), +25023 => array(DEFAULT_ERROR_MESSAGE.'25023',0), +25024 => array(DEFAULT_ERROR_MESSAGE.'25024',0), +25025 => array(DEFAULT_ERROR_MESSAGE.'25025',0), +25026 => array(DEFAULT_ERROR_MESSAGE.'25026',0), +25027 => array(DEFAULT_ERROR_MESSAGE.'25027',0), +25028 => array(DEFAULT_ERROR_MESSAGE.'25028',0), +25029 => array(DEFAULT_ERROR_MESSAGE.'25029',0), +25030 => array(DEFAULT_ERROR_MESSAGE.'25030',0), +25031 => array(DEFAULT_ERROR_MESSAGE.'25031',0), +25032 => array(DEFAULT_ERROR_MESSAGE.'25032',0), +25033 => array(DEFAULT_ERROR_MESSAGE.'25033',0), +25034 => array(DEFAULT_ERROR_MESSAGE.'25034',0), +25035 => array(DEFAULT_ERROR_MESSAGE.'25035',0), +25036 => array(DEFAULT_ERROR_MESSAGE.'25036',0), +25037 => array(DEFAULT_ERROR_MESSAGE.'25037',0), +25038 => array(DEFAULT_ERROR_MESSAGE.'25038',0), +25039 => array(DEFAULT_ERROR_MESSAGE.'25039',0), +25040 => array(DEFAULT_ERROR_MESSAGE.'25040',0), +25041 => array(DEFAULT_ERROR_MESSAGE.'25041',0), +25042 => array(DEFAULT_ERROR_MESSAGE.'25042',0), +25043 => array(DEFAULT_ERROR_MESSAGE.'25043',0), +25044 => array(DEFAULT_ERROR_MESSAGE.'25044',0), +25045 => array(DEFAULT_ERROR_MESSAGE.'25045',0), +25046 => array(DEFAULT_ERROR_MESSAGE.'25046',0), +25047 => array(DEFAULT_ERROR_MESSAGE.'25047',0), +25048 => array(DEFAULT_ERROR_MESSAGE.'25048',0), +25049 => array(DEFAULT_ERROR_MESSAGE.'25049',0), +25050 => array(DEFAULT_ERROR_MESSAGE.'25050',0), +25051 => array(DEFAULT_ERROR_MESSAGE.'25051',0), +25052 => array(DEFAULT_ERROR_MESSAGE.'25052',0), +25053 => array(DEFAULT_ERROR_MESSAGE.'25053',0), +25054 => array(DEFAULT_ERROR_MESSAGE.'25054',0), +25055 => array(DEFAULT_ERROR_MESSAGE.'25055',0), +25056 => array(DEFAULT_ERROR_MESSAGE.'25056',0), +25057 => array(DEFAULT_ERROR_MESSAGE.'25057',0), +25058 => array(DEFAULT_ERROR_MESSAGE.'25058',0), +25059 => array(DEFAULT_ERROR_MESSAGE.'25059',0), +25060 => array(DEFAULT_ERROR_MESSAGE.'25060',0), +25061 => array(DEFAULT_ERROR_MESSAGE.'25061',0), +25062 => array(DEFAULT_ERROR_MESSAGE.'25062',0), +25063 => array(DEFAULT_ERROR_MESSAGE.'25063',0), +25064 => array(DEFAULT_ERROR_MESSAGE.'25064',0), +25065 => array(DEFAULT_ERROR_MESSAGE.'25065',0), +25066 => array(DEFAULT_ERROR_MESSAGE.'25066',0), +25067 => array(DEFAULT_ERROR_MESSAGE.'25067',0), +25068 => array(DEFAULT_ERROR_MESSAGE.'25068',0), +25069 => array(DEFAULT_ERROR_MESSAGE.'25069',0), +25070 => array(DEFAULT_ERROR_MESSAGE.'25070',0), +25071 => array(DEFAULT_ERROR_MESSAGE.'25071',0), +25072 => array(DEFAULT_ERROR_MESSAGE.'25072',0), +25073 => array(DEFAULT_ERROR_MESSAGE.'25073',0), +25074 => array(DEFAULT_ERROR_MESSAGE.'25074',0), +25075 => array(DEFAULT_ERROR_MESSAGE.'25075',0), +25077 => array(DEFAULT_ERROR_MESSAGE.'25077',0), +25078 => array(DEFAULT_ERROR_MESSAGE.'25078',0), +25079 => array(DEFAULT_ERROR_MESSAGE.'25079',0), +25080 => array(DEFAULT_ERROR_MESSAGE.'25080',0), +25081 => array(DEFAULT_ERROR_MESSAGE.'25081',0), +25082 => array(DEFAULT_ERROR_MESSAGE.'25082',0), +25083 => array(DEFAULT_ERROR_MESSAGE.'25083',0), +25084 => array(DEFAULT_ERROR_MESSAGE.'25084',0), +25085 => array(DEFAULT_ERROR_MESSAGE.'25085',0), +25086 => array(DEFAULT_ERROR_MESSAGE.'25086',0), +25087 => array(DEFAULT_ERROR_MESSAGE.'25087',0), +25088 => array(DEFAULT_ERROR_MESSAGE.'25088',0), +25089 => array(DEFAULT_ERROR_MESSAGE.'25089',0), +25090 => array(DEFAULT_ERROR_MESSAGE.'25090',0), +25091 => array(DEFAULT_ERROR_MESSAGE.'25091',0), +25092 => array(DEFAULT_ERROR_MESSAGE.'25092',0), +25093 => array(DEFAULT_ERROR_MESSAGE.'25093',0), +25094 => array(DEFAULT_ERROR_MESSAGE.'25094',0), +25095 => array(DEFAULT_ERROR_MESSAGE.'25095',0), +25096 => array(DEFAULT_ERROR_MESSAGE.'25096',0), +25097 => array(DEFAULT_ERROR_MESSAGE.'25097',0), +25098 => array(DEFAULT_ERROR_MESSAGE.'25098',0), +25099 => array(DEFAULT_ERROR_MESSAGE.'25099',0), +25100 => array(DEFAULT_ERROR_MESSAGE.'25100',0), +25101 => array(DEFAULT_ERROR_MESSAGE.'25101',0), +25102 => array(DEFAULT_ERROR_MESSAGE.'25102',0), +25103 => array(DEFAULT_ERROR_MESSAGE.'25103',0), +25104 => array(DEFAULT_ERROR_MESSAGE.'25104',0), +25105 => array(DEFAULT_ERROR_MESSAGE.'25105',0), +25106 => array(DEFAULT_ERROR_MESSAGE.'25106',0), +25107 => array(DEFAULT_ERROR_MESSAGE.'25107',0), +25108 => array(DEFAULT_ERROR_MESSAGE.'25108',0), +25109 => array(DEFAULT_ERROR_MESSAGE.'25109',0), +25110 => array(DEFAULT_ERROR_MESSAGE.'25110',0), +25111 => array(DEFAULT_ERROR_MESSAGE.'25111',0), +25112 => array(DEFAULT_ERROR_MESSAGE.'25112',0), +25113 => array(DEFAULT_ERROR_MESSAGE.'25113',0), +25114 => array(DEFAULT_ERROR_MESSAGE.'25114',0), +25115 => array(DEFAULT_ERROR_MESSAGE.'25115',0), +25116 => array(DEFAULT_ERROR_MESSAGE.'25116',0), +25117 => array(DEFAULT_ERROR_MESSAGE.'25117',0), +25118 => array(DEFAULT_ERROR_MESSAGE.'25118',0), +25119 => array(DEFAULT_ERROR_MESSAGE.'25119',0), +25120 => array(DEFAULT_ERROR_MESSAGE.'25120',0), +25121 => array(DEFAULT_ERROR_MESSAGE.'25121',0), +25122 => array(DEFAULT_ERROR_MESSAGE.'25122',0), +25123 => array(DEFAULT_ERROR_MESSAGE.'25123',0), +25124 => array(DEFAULT_ERROR_MESSAGE.'25124',0), +25125 => array(DEFAULT_ERROR_MESSAGE.'25125',0), +25126 => array(DEFAULT_ERROR_MESSAGE.'25126',0), +25127 => array(DEFAULT_ERROR_MESSAGE.'25126',0), +24003 => array(DEFAULT_ERROR_MESSAGE.'24003',0), +24004 => array(DEFAULT_ERROR_MESSAGE.'24004',0), +24005 => array(DEFAULT_ERROR_MESSAGE.'24005',0), +24006 => array(DEFAULT_ERROR_MESSAGE.'24006',0), +24007 => array(DEFAULT_ERROR_MESSAGE.'24007',0), +24008 => array(DEFAULT_ERROR_MESSAGE.'24008',0), +24009 => array(DEFAULT_ERROR_MESSAGE.'24009',0), +24010 => array(DEFAULT_ERROR_MESSAGE.'24010',0), +24011 => array(DEFAULT_ERROR_MESSAGE.'24011',0), +24012 => array(DEFAULT_ERROR_MESSAGE.'24012',0), +24013 => array(DEFAULT_ERROR_MESSAGE.'24013',0), +24014 => array(DEFAULT_ERROR_MESSAGE.'24014',0), +24015 => array(DEFAULT_ERROR_MESSAGE.'24015',0), +22001 => array(DEFAULT_ERROR_MESSAGE.'22001',0), +22002 => array(DEFAULT_ERROR_MESSAGE.'22002',0), +22004 => array(DEFAULT_ERROR_MESSAGE.'22004',0), +22005 => array(DEFAULT_ERROR_MESSAGE.'22005',0), +22006 => array(DEFAULT_ERROR_MESSAGE.'22006',0), +22007 => array(DEFAULT_ERROR_MESSAGE.'22007',0), +22008 => array(DEFAULT_ERROR_MESSAGE.'22008',0), +22009 => array(DEFAULT_ERROR_MESSAGE.'22009',0), +22010 => array(DEFAULT_ERROR_MESSAGE.'22010',0), +22011 => array(DEFAULT_ERROR_MESSAGE.'22011',0), +22012 => array(DEFAULT_ERROR_MESSAGE.'22012',0), +22013 => array(DEFAULT_ERROR_MESSAGE.'22013',0), +22014 => array(DEFAULT_ERROR_MESSAGE.'22014',0), +22015 => array(DEFAULT_ERROR_MESSAGE.'22015',0), +22016 => array(DEFAULT_ERROR_MESSAGE.'22016',0), +22017 => array(DEFAULT_ERROR_MESSAGE.'22017',0), +22018 => array(DEFAULT_ERROR_MESSAGE.'22018',0), +22019 => array(DEFAULT_ERROR_MESSAGE.'22019',0), +22020 => array(DEFAULT_ERROR_MESSAGE.'22020',0), +13001 => array(DEFAULT_ERROR_MESSAGE.'13001',0), +13002 => array(DEFAULT_ERROR_MESSAGE.'13002',0), +1001 => array(DEFAULT_ERROR_MESSAGE.'1001',0), +1002 => array(DEFAULT_ERROR_MESSAGE.'1002',0), +1003 => array(DEFAULT_ERROR_MESSAGE.'1003',0), +1004 => array(DEFAULT_ERROR_MESSAGE.'1004',0), +1005 => array(DEFAULT_ERROR_MESSAGE.'1005',0), +1006 => array(DEFAULT_ERROR_MESSAGE.'1006',0), +1007 => array(DEFAULT_ERROR_MESSAGE.'1007',0), +1008 => array(DEFAULT_ERROR_MESSAGE.'1008',0), +1009 => array(DEFAULT_ERROR_MESSAGE.'1009',0), +1010 => array(DEFAULT_ERROR_MESSAGE.'1010',0), +1011 => array(DEFAULT_ERROR_MESSAGE.'1011',0), +26001 => array(DEFAULT_ERROR_MESSAGE.'26001',0), +26002 => array(DEFAULT_ERROR_MESSAGE.'26002',0), +26003 => array(DEFAULT_ERROR_MESSAGE.'26003',0), +26004 => array(DEFAULT_ERROR_MESSAGE.'26004',0), +26005 => array(DEFAULT_ERROR_MESSAGE.'26005',0), +26006 => array(DEFAULT_ERROR_MESSAGE.'26006',0), +26007 => array(DEFAULT_ERROR_MESSAGE.'26007',0), +26008 => array(DEFAULT_ERROR_MESSAGE.'26008',0), +26009 => array(DEFAULT_ERROR_MESSAGE.'26009',0), +26010 => array(DEFAULT_ERROR_MESSAGE.'26010',0), +26011 => array(DEFAULT_ERROR_MESSAGE.'26011',0), +26012 => array(DEFAULT_ERROR_MESSAGE.'26012',0), +26013 => array(DEFAULT_ERROR_MESSAGE.'26013',0), +26014 => array(DEFAULT_ERROR_MESSAGE.'26014',0), +26015 => array(DEFAULT_ERROR_MESSAGE.'26015',0), +26016 => array(DEFAULT_ERROR_MESSAGE.'26016',0), + +27001 => array(DEFAULT_ERROR_MESSAGE.'27001',0), +27002 => array(DEFAULT_ERROR_MESSAGE.'27002',0), +27003 => array(DEFAULT_ERROR_MESSAGE.'27003',0), +27004 => array(DEFAULT_ERROR_MESSAGE.'27004',0), +27005 => array(DEFAULT_ERROR_MESSAGE.'27005',0), +27006 => array(DEFAULT_ERROR_MESSAGE.'27006',0), +27007 => array(DEFAULT_ERROR_MESSAGE.'27007',0), +27008 => array(DEFAULT_ERROR_MESSAGE.'27008',0), +27009 => array(DEFAULT_ERROR_MESSAGE.'27009',0), +27010 => array(DEFAULT_ERROR_MESSAGE.'27010',0), +27011 => array(DEFAULT_ERROR_MESSAGE.'27011',0), +27012 => array(DEFAULT_ERROR_MESSAGE.'27012',0), +27013 => array(DEFAULT_ERROR_MESSAGE.'27013',0), +27014 => array(DEFAULT_ERROR_MESSAGE.'27014',0), +27015 => array(DEFAULT_ERROR_MESSAGE.'27015',0), +); + +?> diff --git a/plugins/dwJpgraphPlugin/lib/sfJpGraph.class.php b/plugins/dwJpgraphPlugin/lib/sfJpGraph.class.php new file mode 100644 index 0000000..8c61d9a --- /dev/null +++ b/plugins/dwJpgraphPlugin/lib/sfJpGraph.class.php @@ -0,0 +1,198 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * sfJpGraph class. + * + * This class provides an abstraction layer to the PHP FPDF library Provides + * creation/modification of pdf files. + * + * @package symfony + * @subpackage dwJgraphPlugin + * @author Dustin Whittle + * @author Jordi Backx + * @version SVN: $Id: sfJpGraph.class.php 6910 2008-01-03 07:03:55Z dwhittle $ + * @todo autoload libraries + more graphs + docs + */ + +require_once('jpgraph/jpgraph.php'); + +class sfJpGraph +{ + + /** + * The actual jpgraph object. Is returned by getJpGraphObject() to be used in a + * symfony action method + */ + private $JpGraph; + + /** + * Contsructor + * + * @param string graph type. Can be combination of comma separated types + * @param int width of the graph canvas + * @param int height of the graph canvas + * @param string cached name of the graph (see JpGraph docs) + * @param int timeout (see JpGraph docs) + * @param bool inline (or not, see JpGrpah docs) + */ + public function __construct($type = 'bar', $width = 300, $height = 200, $cached_name = '', $time_out = 0, $inline = true, $barcode_type = null) + { + + /* + * Some types used their own class, default is Graph, however + */ + switch ($type) + { + + case 'pie3D': + + require_once('jpgraph/jpgraph_pie.php'); + require_once('jpgraph/jpgraph_pie3d.php'); + + $this->JpGraph = new PieGraph($width, $height, $cached_name, $time_out, $inline); + + break; + + case 'pie': + + require_once('jpgraph/jpgraph_pie.php'); + $this->JpGraph = new PieGraph($width, $height, $cached_name, $time_out, $inline); + + break; + + case 'polar': + + require_once('jpgraph/jpgraph_polar.php'); + $this->JpGraph = new PolarGraph($width, $height, $cached_name, $time_out, $inline); + + break; + + case 'radar': + + require_once('jpgraph/jpgraph_radar.php'); + $this->JpGraph = new RadarGraph($width, $height, $cached_name, $time_out, $inline); + + break; + + case 'canvas': + + require_once('jpgraph/jpgraph_canvas.php'); + $this->JpGraph = new CanvasGraph($width, $height, $cached_name, $time_out, $inline); + + break; + + case 'gantt': + + require_once('jpgraph/jpgraph_gantt.php'); + $this->JpGraph = new GanttGraph($width, $height, $cached_name, $time_out, $inline); + + break; + + case 'mgraph': + + require_once('jpgraph/jpgraph_mgraph.php'); + $this->JpGraph = new MGraph($width, $height, $cached_name, $time_out, $inline); + + break; + + case 'barcode': + + require_once('jpgraph_canvas.php'); + require_once('jpgraph_barcode.php'); + + switch ($barcode_type) + { + case 'EAN-8' : + $symbology = BarcodeFactory::Create(ENCODING_EAN8); + break; + case 'EAN-13' : + $symbology = BarcodeFactory::Create(ENCODING_EAN13); + break; + + case 'EAN-128' : + $symbology = BarcodeFactory::Create(ENCODING_EAN128); + break; + + case 'UPC-A' : + $symbology = BarcodeFactory::Create(ENCODING_UPCA); + break; + + case 'UPC-E' : + $symbology = BarcodeFactory::Create(ENCODING_UPCE); + break; + + case 'CODE-11' : + $symbology = BarcodeFactory::Create(ENCODING_CODE11); + break; + + case 'CODE-25' : + $symbology = BarcodeFactory::Create(ENCODING_CODE25); + break; + + case 'CODE-39' : + $symbology = BarcodeFactory::Create(ENCODING_CODE39); + break; + + case 'CODE-93' : + $symbology = BarcodeFactory::Create(ENCODING_CODE93); + break; + + case 'CODE-128' : + $symbology = BarcodeFactory::Create(ENCODING_CODE128); + break; + + case 'POSTNET' : + $symbology = BarcodeFactory::Create(ENCODING_POSTNET); + break; + + case 'CODEI25' : + $symbology = BarcodeFactory::Create(ENCODING_CODEI25); + break; + + case 'CODABAR' : + $symbology = BarcodeFactory::Create(ENCODING_CODABAR); + break; + + case 'BOOKLAND' : + $symbology = BarcodeFactory::Create(ENCODING_BOOKLAND); + break; + } + + $this->JpGraph = BackendFactory::Create(BACKEND_IMAGE, $symbology); + $this->JpGraph->setHeight($height); + $this->JpGraph->AddChecksum(); + + break; + + default: + + $this->JpGraph = new Graph($width, $height, $cached_name, $time_out, $inline); + $this->JpGraph->SetScale('textlin'); + + break; + } + + } + + /** + * Return the JpGraph object for manipulation in action + * + * @return object JpGraph object + */ + public function getJpGraph() + { + return $this->JpGraph; + } + +} + +?> diff --git a/plugins/dwJpgraphPlugin/modules/dwJpgraphPlugin/actions/actions.class.php b/plugins/dwJpgraphPlugin/modules/dwJpgraphPlugin/actions/actions.class.php new file mode 100644 index 0000000..77588fa --- /dev/null +++ b/plugins/dwJpgraphPlugin/modules/dwJpgraphPlugin/actions/actions.class.php @@ -0,0 +1,121 @@ + + * @author Jordi Backx + * @version SVN: $Id$ + */ +class dwJpgraphPluginActions extends sfActions +{ + + /** + * Executes index action + * + */ + public function executeIndex() + { + $this->forward('dwJpgraphPlugin', 'test'); + } + + /** + * Executes test action + * + */ + public function executeTest() + { + + /* + In order to use fonts, you must define the location to your fonts: + define('TTF_DIR', '/usr/X11R6/share/fonts/ttf/'); + */ + + //------------------------------------------------------------------ + // Create some random data for the plot. We use the current time for the + // first X-position + //------------------------------------------------------------------ + $datay = array(); + $datax = array(); + $ts = time(); + $n=70; // Number of data points + for($i=0; $i < $n; ++$i ) { + $datax[$i] = $ts+$i*150000; + $datay[$i] = rand(5,60); + $datay2[$i] = rand(1,8); + } + + // Now get labels at the start of each month + $date = new DateScaleUtils(); + list($tickPositions,$minTickPositions) = $date->getTicks($datax,DSUTILS_MONTH1); + + // Now create the real graph + // Combine a line and a bar graph + + // We add some grace to the end of the X-axis scale so that the first and last + // data point isn't exactly at the very end or beginning of the scale + $grace = 400000; + $xmin = $datax[0]-$grace; + $xmax = $datax[$n-1]+$grace;; + + // Overall width of graphs + $w = 450; + // Left and right margin for each graph + $lm=25; $rm=15; + + //---------------------- + // Setup the line graph + //---------------------- + $graph = new sfJpGraph('line',$w,250); + $graph = $graph->getJpGraph(); + + $graph->SetScale('linlin',0,0,$xmin,$xmax); + $graph->SetMargin($lm,$rm,10,30); + $graph->SetMarginColor('white'); + $graph->SetFrame(false); + $graph->SetBox(true); + $graph->xaxis->SetTickPositions($tickPositions,$minTickPositions); + $graph->xaxis->SetLabelFormatString('My',true); + $graph->xgrid->Show(); + $p1 = new LinePlot($datay,$datax); + $graph->Add($p1); + + //---------------------- + // Setup the bar graph + //---------------------- + $graph2 = new sfJpGraph('bar',$w,110); + $graph2 = $graph2->getJpGraph(); + + $graph2->SetScale('linlin',0,0,$xmin,$xmax); + $graph2->SetMargin($lm,$rm,5,10); + $graph2->SetMarginColor('white'); + $graph2->SetFrame(false); + $graph2->SetBox(true); + $graph2->xgrid->Show(); + $graph2->xaxis->SetTickPositions($tickPositions,$minTickPositions); + $graph2->xaxis->SetLabelFormatString('My',true); + $graph2->xaxis->SetPos('max'); + $graph2->xaxis->HideLabels(); + $graph2->xaxis->SetTickSide(SIDE_DOWN); + $b1 = new BarPlot($datay2,$datax); + $b1->SetFillColor('teal'); + $b1->SetColor('teal:1.2'); + $graph2->Add($b1); + + //----------------------- + // Create a multigraph + //---------------------- + $mgraph = new sfJpGraph('mgraph',$w,110); + $mgraph = $mgraph->getJpGraph(); + $mgraph->SetImgFormat('jpeg',60); + $mgraph->SetMargin(2,2,2,2); + $mgraph->SetFrame(true); + $mgraph->AddMix($graph,0,0,85); + $mgraph->AddMix($graph2,0,250,85); + $mgraph->Stroke(); + + return sfView::NONE; + } +} diff --git a/plugins/dwJpgraphPlugin/test/sfJpGraphTest.php b/plugins/dwJpgraphPlugin/test/sfJpGraphTest.php new file mode 100644 index 0000000..96b12ad --- /dev/null +++ b/plugins/dwJpgraphPlugin/test/sfJpGraphTest.php @@ -0,0 +1,17 @@ + + * @author Jordi Backx + * @version SVN: $Id: sfJpGraphTest.php 6910 2008-01-03 07:03:55Z dwhittle $ + */ + +require_once(dirname(__FILE__).'/../../../test/bootstrap/unit.php'); +require_once(dirname(__FILE__).'/../lib/sfJpGraph.class.php'); + +$t = new lime_test(2, new lime_output_color()); +$sfJpGraph = new sfJpGraph(); + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/LICENSE b/plugins/getId3Plugin/LICENSE new file mode 100644 index 0000000..339b705 --- /dev/null +++ b/plugins/getId3Plugin/LICENSE @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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) + + 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 + + +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) year 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. diff --git a/plugins/getId3Plugin/README b/plugins/getId3Plugin/README new file mode 100644 index 0000000..210aefe --- /dev/null +++ b/plugins/getId3Plugin/README @@ -0,0 +1,23 @@ += getId3 plugin = + +== Overview == + +This plugin is a package of the getId3 project available from sourceforge + +== Installation == + +To install getId3Plugin: + +{{{ +symfony plugin-install local|global symfony/getId3Plugin +}}} + +== Usage == + +This plugin gives you access to the getId3 libraries, +see http://getid3.sourceforge.net/ for details and docs + +== License == + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. diff --git a/plugins/getId3Plugin/helperapps/cygwin1.dll b/plugins/getId3Plugin/helperapps/cygwin1.dll new file mode 100644 index 0000000..4f2596c Binary files /dev/null and b/plugins/getId3Plugin/helperapps/cygwin1.dll differ diff --git a/plugins/getId3Plugin/helperapps/head.exe b/plugins/getId3Plugin/helperapps/head.exe new file mode 100644 index 0000000..7f5ef87 Binary files /dev/null and b/plugins/getId3Plugin/helperapps/head.exe differ diff --git a/plugins/getId3Plugin/helperapps/md5sum.exe b/plugins/getId3Plugin/helperapps/md5sum.exe new file mode 100644 index 0000000..0313120 Binary files /dev/null and b/plugins/getId3Plugin/helperapps/md5sum.exe differ diff --git a/plugins/getId3Plugin/helperapps/metaflac.exe b/plugins/getId3Plugin/helperapps/metaflac.exe new file mode 100644 index 0000000..cdf41c5 Binary files /dev/null and b/plugins/getId3Plugin/helperapps/metaflac.exe differ diff --git a/plugins/getId3Plugin/helperapps/readme.txt b/plugins/getId3Plugin/helperapps/readme.txt new file mode 100644 index 0000000..aea9002 --- /dev/null +++ b/plugins/getId3Plugin/helperapps/readme.txt @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////// +/// getID3() by James Heinrich // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// // +// /helperapps/readme.txt - part of getID3() // +// List of binary files required under Windows for some // +// features and/or file formats // +// See /readme.txt for more details // +// /// +///////////////////////////////////////////////////////////////// + +This directory should contain binaries of various helper applications +that getID3() depends on to handle some file formats under Windows. + +The location of this directory is configurable in /getid3/getid3.php +as GETID3_HELPERAPPSDIR + +If this directory is empty, or you are missing any files, please +download the latest version of the "getID3()-WindowsSupport" package +from the usual download location (http://getid3.sourceforge.net) + + + +Included files: +===================================================== + +Taken from http://www.cygwin.com/ +* cygwin1.dll + +Taken from http://unxutils.sourceforge.net/ +* head.exe +* md5sum.exe +* tail.exe + +Taken from http://ebible.org/mpj/software.htm +* sha1sum.exe + +Taken from http://www.vorbis.com/download.psp +* vorbiscomment.exe + +Taken from http://flac.sourceforge.net/download.html +* metaflac.exe + +Taken from http://www.etree.org/shncom.html +* shorten.exe diff --git a/plugins/getId3Plugin/helperapps/sha1sum.exe b/plugins/getId3Plugin/helperapps/sha1sum.exe new file mode 100644 index 0000000..f1a5216 Binary files /dev/null and b/plugins/getId3Plugin/helperapps/sha1sum.exe differ diff --git a/plugins/getId3Plugin/helperapps/shorten.exe b/plugins/getId3Plugin/helperapps/shorten.exe new file mode 100644 index 0000000..b82d6c3 Binary files /dev/null and b/plugins/getId3Plugin/helperapps/shorten.exe differ diff --git a/plugins/getId3Plugin/helperapps/tail.exe b/plugins/getId3Plugin/helperapps/tail.exe new file mode 100644 index 0000000..36c2abc Binary files /dev/null and b/plugins/getId3Plugin/helperapps/tail.exe differ diff --git a/plugins/getId3Plugin/helperapps/vorbiscomment.exe b/plugins/getId3Plugin/helperapps/vorbiscomment.exe new file mode 100644 index 0000000..9e4e4b9 Binary files /dev/null and b/plugins/getId3Plugin/helperapps/vorbiscomment.exe differ diff --git a/plugins/getId3Plugin/lib/extension.cache.dbm.php b/plugins/getId3Plugin/lib/extension.cache.dbm.php new file mode 100644 index 0000000..f8d56b8 --- /dev/null +++ b/plugins/getId3Plugin/lib/extension.cache.dbm.php @@ -0,0 +1,217 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | extension.cache.mysql.php | +// | MySQL Cache Extension. | +// | dependencies: getid3. | +// +----------------------------------------------------------------------+ +// +// $Id: extension.cache.dbm.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + +/** +* This is a caching extension for getID3(). It works the exact same +* way as the getID3 class, but return cached information very fast +* +* Example: (see also demo.cache.dbm.php in /demo/) +* +* Normal getID3 usage (example): +* +* require_once 'getid3/getid3.php'; +* $getid3 = new getid3; +* $getid3->encoding = 'UTF-8'; +* try { +* $info1 = $getid3->Analyse('file1.flac'); +* $info2 = $getid3->Analyse('file2.wv'); +* .... +* +* getID3_cached usage: +* +* require_once 'getid3/getid3.php'; +* require_once 'getid3/getid3/extension.cache.mysql.php'; +* $getid3 = new getid3_cached_mysql('localhost', 'database', 'username', 'password'); +* $getid3->encoding = 'UTF-8'; +* try { +* $info1 = $getid3->analyse('file1.flac'); +* $info2 = $getid3->analyse('file2.wv'); +* ... +* +* +* Supported Cache Types +* +* SQL Databases: (use extension.cache.mysql) +* +* cache_type cache_options +* ------------------------------------------------------------------- +* mysql host, database, username, password +* +* +* DBM-Style Databases: (this extension) +* +* cache_type cache_options +* ------------------------------------------------------------------- +* gdbm dbm_filename, lock_filename +* ndbm dbm_filename, lock_filename +* db2 dbm_filename, lock_filename +* db3 dbm_filename, lock_filename +* db4 dbm_filename, lock_filename (PHP5 required) +* +* PHP must have write access to both dbm_filename and lock_filename. +* +* +* Recommended Cache Types +* +* Infrequent updates, many reads any DBM +* Frequent updates mysql +*/ + + +class getid3_cached_dbm extends getid3 +{ + + public function __construct($cache_type, $dbm_filename, $lock_filename) { + + // Check for dba extension + if (!extension_loaded('dba')) { + throw new getid3_exception('PHP is not compiled with dba support, required to use DBM style cache.'); + } + + if (!in_array($cache_type, dba_handlers())) { + throw new getid3_exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.'); + } + + // Create lock file if needed + if (!file_exists($lock_filename)) { + if (!touch($lock_filename)) { + die('failed to create lock file: ' . $lock_filename); + } + } + + // Open lock file for writing + if (!is_writeable($lock_filename)) { + die('lock file: ' . $lock_filename . ' is not writable'); + } + $this->lock = fopen($lock_filename, 'w'); + + // Acquire exclusive write lock to lock file + flock($this->lock, LOCK_EX); + + // Create dbm-file if needed + if (!file_exists($dbm_filename)) { + if (!touch($dbm_filename)) { + die('failed to create dbm file: ' . $dbm_filename); + } + } + + // Try to open dbm file for writing + $this->dba = @dba_open($dbm_filename, 'w', $cache_type); + if (!$this->dba) { + + // Failed - create new dbm file + $this->dba = dba_open($dbm_filename, 'n', $cache_type); + + if (!$this->dba) { + die('failed to create dbm file: ' . $dbm_filename); + } + + // Insert getID3 version number + dba_insert(getid3::VERSION, getid3::VERSION, $this->dba); + } + + // Init misc values + $this->cache_type = $cache_type; + $this->dbm_filename = $dbm_filename; + + // Register destructor + register_shutdown_function(array($this, '__destruct')); + + // Check version number and clear cache if changed + if (dba_fetch(getid3::VERSION, $this->dba) != getid3::VERSION) { + $this->clear_cache(); + } + + parent::__construct(); + } + + + + public function __destruct() { + + // Close dbm file + @dba_close($this->dba); + + // Release exclusive lock + @flock($this->lock, LOCK_UN); + + // Close lock file + @fclose($this->lock); + } + + + + public function clear_cache() { + + // Close dbm file + dba_close($this->dba); + + // Create new dbm file + $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type); + + if (!$this->dba) { + die('failed to clear cache/recreate dbm file: ' . $this->dbm_filename); + } + + // Insert getID3 version number + dba_insert(getid3::VERSION, getid3::VERSION, $this->dba); + + // Reregister shutdown function + register_shutdown_function(array($this, '__destruct')); + } + + + + // public: analyze file + public function Analyze($filename) { + + if (file_exists($filename)) { + + // Calc key filename::mod_time::size - should be unique + $key = $filename . '::' . filemtime($filename) . '::' . filesize($filename); + + // Loopup key + $result = dba_fetch($key, $this->dba); + + // Hit + if ($result !== false) { + return unserialize($result); + } + } + + // Miss + $result = parent::Analyze($filename); + + // Save result + if (file_exists($filename)) { + dba_insert($key, serialize($result), $this->dba); + } + + return $result; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/extension.cache.mysql.php b/plugins/getId3Plugin/lib/extension.cache.mysql.php new file mode 100644 index 0000000..53c56b7 --- /dev/null +++ b/plugins/getId3Plugin/lib/extension.cache.mysql.php @@ -0,0 +1,177 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | extension.cache.mysql.php | +// | MySQL Cache Extension. | +// | dependencies: getid3. | +// +----------------------------------------------------------------------+ +// +// $Id: extension.cache.mysql.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + +/** +* This is a caching extension for getID3(). It works the exact same +* way as the getID3 class, but return cached information very fast +* +* Example: (see also demo.cache.mysql.php in /demo/) +* +* Normal getID3 usage (example): +* +* require_once 'getid3/getid3.php'; +* $getid3 = new getid3; +* $getid3->encoding = 'UTF-8'; +* try { +* $info1 = $getid3->Analyse('file1.flac'); +* $info2 = $getid3->Analyse('file2.wv'); +* .... +* +* getID3_cached usage: +* +* require_once 'getid3/getid3.php'; +* require_once 'getid3/getid3/extension.cache.mysql.php'; +* $getid3 = new getid3_cached_mysql('localhost', 'database', 'username', 'password'); +* $getid3->encoding = 'UTF-8'; +* try { +* $info1 = $getid3->analyse('file1.flac'); +* $info2 = $getid3->analyse('file2.wv'); +* ... +* +* +* Supported Cache Types (this extension) +* +* SQL Databases: +* +* cache_type cache_options +* ------------------------------------------------------------------- +* mysql host, database, username, password +* +* +* DBM-Style Databases: (use extension.cache.dbm) +* +* cache_type cache_options +* ------------------------------------------------------------------- +* gdbm dbm_filename, lock_filename +* ndbm dbm_filename, lock_filename +* db2 dbm_filename, lock_filename +* db3 dbm_filename, lock_filename +* db4 dbm_filename, lock_filename (PHP5 required) +* +* PHP must have write access to both dbm_filename and lock_filename. +* +* +* Recommended Cache Types +* +* Infrequent updates, many reads any DBM +* Frequent updates mysql +*/ + + +class getid3_cached_mysql extends getID3 +{ + + private $cursor; + private $connection; + + + public function __construct($host, $database, $username, $password) { + + // Check for mysql support + if (!function_exists('mysql_pconnect')) { + throw new getid3_exception('PHP not compiled with mysql support.'); + } + + // Connect to database + $this->connection = @mysql_pconnect($host, $username, $password); + if (!$this->connection) { + throw new getid3_exception('mysql_pconnect() failed - check permissions and spelling.'); + } + + // Select database + if (!@mysql_select_db($database, $this->connection)) { + throw new getid3_exception('Cannot use database '.$database); + } + + // Create cache table if not exists + $this->create_table(); + + // Check version number and clear cache if changed + $this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename` = '".getid3::VERSION."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection); + list($version) = @mysql_fetch_array($this->cursor); + if ($version != getid3::VERSION) { + $this->clear_cache(); + } + + parent::__construct(); + } + + + + public function clear_cache() { + + $this->cursor = mysql_query("DELETE FROM `getid3_cache`", $this->connection); + $this->cursor = mysql_query("INSERT INTO `getid3_cache` VALUES ('".getid3::VERSION."', -1, -1, -1, '".getid3::VERSION."')", $this->connection); + } + + + + public function Analyze($filename) { + + if (file_exists($filename)) { + + // Short-hands + $filetime = filemtime($filename); + $filesize = filesize($filename); + $filenam2 = mysql_escape_string($filename); + + // Loopup file + $this->cursor = mysql_query("SELECT `value` FROM `getid3_cache` WHERE (`filename`='".$filenam2."') AND (`filesize`='".$filesize."') AND (`filetime`='".$filetime."')", $this->connection); + list($result) = @mysql_fetch_array($this->cursor); + + // Hit + if ($result) { + return unserialize($result); + } + } + + // Miss + $result = parent::Analyze($filename); + + // Save result + if (file_exists($filename)) { + $res2 = mysql_escape_string(serialize($result)); + $this->cursor = mysql_query("INSERT INTO `getid3_cache` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".$filenam2."', '".$filesize."', '".$filetime."', '".time()."', '".$res2."')", $this->connection); + } + return $result; + } + + + + // (re)create sql table + private function create_table($drop = false) { + + $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `getid3_cache` ( + `filename` VARCHAR(255) NOT NULL DEFAULT '', + `filesize` INT(11) NOT NULL DEFAULT '0', + `filetime` INT(11) NOT NULL DEFAULT '0', + `analyzetime` INT(11) NOT NULL DEFAULT '0', + `value` TEXT NOT NULL, + PRIMARY KEY (`filename`,`filesize`,`filetime`)) TYPE=MyISAM", $this->connection); + echo mysql_error($this->connection); + } +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/getid3.lib.php b/plugins/getId3Plugin/lib/getid3.lib.php new file mode 100644 index 0000000..b5146b7 --- /dev/null +++ b/plugins/getId3Plugin/lib/getid3.lib.php @@ -0,0 +1,1323 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// // +// getid3.lib.php - part of getID3() // +// See readme.txt for more details // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_lib +{ + + function PrintHexBytes($string, $hex=true, $spaces=true, $htmlsafe=true) { + $returnstring = ''; + for ($i = 0; $i < strlen($string); $i++) { + if ($hex) { + $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT); + } else { + $returnstring .= ' '.(ereg("[\x20-\x7E]", $string{$i}) ? $string{$i} : ''); + } + if ($spaces) { + $returnstring .= ' '; + } + } + if ($htmlsafe) { + $returnstring = htmlentities($returnstring); + } + return $returnstring; + } + + function SafeStripSlashes($text) { + if (get_magic_quotes_gpc()) { + return stripslashes($text); + } + return $text; + } + + + function trunc($floatnumber) { + // truncates a floating-point number at the decimal point + // returns int (if possible, otherwise float) + if ($floatnumber >= 1) { + $truncatednumber = floor($floatnumber); + } elseif ($floatnumber <= -1) { + $truncatednumber = ceil($floatnumber); + } else { + $truncatednumber = 0; + } + if ($truncatednumber <= 1073741824) { // 2^30 + $truncatednumber = (int) $truncatednumber; + } + return $truncatednumber; + } + + + function CastAsInt($floatnum) { + // convert to float if not already + $floatnum = (float) $floatnum; + + // convert a float to type int, only if possible + if (getid3_lib::trunc($floatnum) == $floatnum) { + // it's not floating point + if ($floatnum <= 1073741824) { // 2^30 + // it's within int range + $floatnum = (int) $floatnum; + } + } + return $floatnum; + } + + + function DecimalBinary2Float($binarynumerator) { + $numerator = getid3_lib::Bin2Dec($binarynumerator); + $denominator = getid3_lib::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator))); + return ($numerator / $denominator); + } + + + function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) { + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html + if (strpos($binarypointnumber, '.') === false) { + $binarypointnumber = '0.'.$binarypointnumber; + } elseif ($binarypointnumber{0} == '.') { + $binarypointnumber = '0'.$binarypointnumber; + } + $exponent = 0; + while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) { + if (substr($binarypointnumber, 1, 1) == '.') { + $exponent--; + $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3); + } else { + $pointpos = strpos($binarypointnumber, '.'); + $exponent += ($pointpos - 1); + $binarypointnumber = str_replace('.', '', $binarypointnumber); + $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1); + } + } + $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT); + return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent); + } + + + function Float2BinaryDecimal($floatvalue) { + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html + $maxbits = 128; // to how many bits of precision should the calculations be taken? + $intpart = getid3_lib::trunc($floatvalue); + $floatpart = abs($floatvalue - $intpart); + $pointbitstring = ''; + while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) { + $floatpart *= 2; + $pointbitstring .= (string) getid3_lib::trunc($floatpart); + $floatpart -= getid3_lib::trunc($floatpart); + } + $binarypointnumber = decbin($intpart).'.'.$pointbitstring; + return $binarypointnumber; + } + + + function Float2String($floatvalue, $bits) { + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html + switch ($bits) { + case 32: + $exponentbits = 8; + $fractionbits = 23; + break; + + case 64: + $exponentbits = 11; + $fractionbits = 52; + break; + + default: + return false; + break; + } + if ($floatvalue >= 0) { + $signbit = '0'; + } else { + $signbit = '1'; + } + $normalizedbinary = getid3_lib::NormalizeBinaryPoint(getid3_lib::Float2BinaryDecimal($floatvalue), $fractionbits); + $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent + $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT); + $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT); + + return getid3_lib::BigEndian2String(getid3_lib::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false); + } + + + function LittleEndian2Float($byteword) { + return getid3_lib::BigEndian2Float(strrev($byteword)); + } + + + function BigEndian2Float($byteword) { + // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic + // http://www.psc.edu/general/software/packages/ieee/ieee.html + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html + + $bitword = getid3_lib::BigEndian2Bin($byteword); + $signbit = $bitword{0}; + + switch (strlen($byteword) * 8) { + case 32: + $exponentbits = 8; + $fractionbits = 23; + break; + + case 64: + $exponentbits = 11; + $fractionbits = 52; + break; + + case 80: + // 80-bit Apple SANE format + // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ + $exponentstring = substr($bitword, 1, 15); + $isnormalized = intval($bitword{16}); + $fractionstring = substr($bitword, 17, 63); + $exponent = pow(2, getid3_lib::Bin2Dec($exponentstring) - 16383); + $fraction = $isnormalized + getid3_lib::DecimalBinary2Float($fractionstring); + $floatvalue = $exponent * $fraction; + if ($signbit == '1') { + $floatvalue *= -1; + } + return $floatvalue; + break; + + default: + return false; + break; + } + $exponentstring = substr($bitword, 1, $exponentbits); + $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits); + $exponent = getid3_lib::Bin2Dec($exponentstring); + $fraction = getid3_lib::Bin2Dec($fractionstring); + + if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) { + // Not a Number + $floatvalue = false; + } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) { + if ($signbit == '1') { + $floatvalue = '-infinity'; + } else { + $floatvalue = '+infinity'; + } + } elseif (($exponent == 0) && ($fraction == 0)) { + if ($signbit == '1') { + $floatvalue = -0; + } else { + $floatvalue = 0; + } + $floatvalue = ($signbit ? 0 : -0); + } elseif (($exponent == 0) && ($fraction != 0)) { + // These are 'unnormalized' values + $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * getid3_lib::DecimalBinary2Float($fractionstring); + if ($signbit == '1') { + $floatvalue *= -1; + } + } elseif ($exponent != 0) { + $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + getid3_lib::DecimalBinary2Float($fractionstring)); + if ($signbit == '1') { + $floatvalue *= -1; + } + } + return (float) $floatvalue; + } + + + function BigEndian2Int($byteword, $synchsafe=false, $signed=false) { + $intvalue = 0; + $bytewordlen = strlen($byteword); + for ($i = 0; $i < $bytewordlen; $i++) { + if ($synchsafe) { // disregard MSB, effectively 7-bit bytes + $intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); + } else { + $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i)); + } + } + if ($signed && !$synchsafe) { + // synchsafe ints are not allowed to be signed + switch ($bytewordlen) { + case 1: + case 2: + case 3: + case 4: + $signmaskbit = 0x80 << (8 * ($bytewordlen - 1)); + if ($intvalue & $signmaskbit) { + $intvalue = 0 - ($intvalue & ($signmaskbit - 1)); + } + break; + + default: + die('ERROR: Cannot have signed integers larger than 32-bits in getid3_lib::BigEndian2Int()'); + break; + } + } + return getid3_lib::CastAsInt($intvalue); + } + + + function LittleEndian2Int($byteword, $signed=false) { + return getid3_lib::BigEndian2Int(strrev($byteword), false, $signed); + } + + + function BigEndian2Bin($byteword) { + $binvalue = ''; + $bytewordlen = strlen($byteword); + for ($i = 0; $i < $bytewordlen; $i++) { + $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT); + } + return $binvalue; + } + + + function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) { + if ($number < 0) { + return false; + } + $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF); + $intstring = ''; + if ($signed) { + if ($minbytes > 4) { + die('ERROR: Cannot have signed integers larger than 32-bits in getid3_lib::BigEndian2String()'); + } + $number = $number & (0x80 << (8 * ($minbytes - 1))); + } + while ($number != 0) { + $quotient = ($number / ($maskbyte + 1)); + $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring; + $number = floor($quotient); + } + return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT); + } + + + function Dec2Bin($number) { + while ($number >= 256) { + $bytes[] = (($number / 256) - (floor($number / 256))) * 256; + $number = floor($number / 256); + } + $bytes[] = $number; + $binstring = ''; + for ($i = 0; $i < count($bytes); $i++) { + $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring; + } + return $binstring; + } + + + function Bin2Dec($binstring, $signed=false) { + $signmult = 1; + if ($signed) { + if ($binstring{0} == '1') { + $signmult = -1; + } + $binstring = substr($binstring, 1); + } + $decvalue = 0; + for ($i = 0; $i < strlen($binstring); $i++) { + $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i); + } + return getid3_lib::CastAsInt($decvalue * $signmult); + } + + + function Bin2String($binstring) { + // return 'hi' for input of '0110100001101001' + $string = ''; + $binstringreversed = strrev($binstring); + for ($i = 0; $i < strlen($binstringreversed); $i += 8) { + $string = chr(getid3_lib::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string; + } + return $string; + } + + + function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { + $intstring = ''; + while ($number > 0) { + if ($synchsafe) { + $intstring = $intstring.chr($number & 127); + $number >>= 7; + } else { + $intstring = $intstring.chr($number & 255); + $number >>= 8; + } + } + return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); + } + + + function array_merge_clobber($array1, $array2) { + // written by kchireability*com + // taken from http://www.php.net/manual/en/function.array-merge-recursive.php + if (!is_array($array1) || !is_array($array2)) { + return false; + } + $newarray = $array1; + foreach ($array2 as $key => $val) { + if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { + $newarray[$key] = getid3_lib::array_merge_clobber($newarray[$key], $val); + } else { + $newarray[$key] = $val; + } + } + return $newarray; + } + + + function array_merge_noclobber($array1, $array2) { + if (!is_array($array1) || !is_array($array2)) { + return false; + } + $newarray = $array1; + foreach ($array2 as $key => $val) { + if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { + $newarray[$key] = getid3_lib::array_merge_noclobber($newarray[$key], $val); + } elseif (!isset($newarray[$key])) { + $newarray[$key] = $val; + } + } + return $newarray; + } + + + function fileextension($filename, $numextensions=1) { + if (strstr($filename, '.')) { + $reversedfilename = strrev($filename); + $offset = 0; + for ($i = 0; $i < $numextensions; $i++) { + $offset = strpos($reversedfilename, '.', $offset + 1); + if ($offset === false) { + return ''; + } + } + return strrev(substr($reversedfilename, 0, $offset)); + } + return ''; + } + + + function PlaytimeString($playtimeseconds) { + $contentseconds = round((($playtimeseconds / 60) - floor($playtimeseconds / 60)) * 60); + $contentminutes = floor($playtimeseconds / 60); + if ($contentseconds >= 60) { + $contentseconds -= 60; + $contentminutes++; + } + return intval($contentminutes).':'.str_pad($contentseconds, 2, 0, STR_PAD_LEFT); + } + + + function image_type_to_mime_type($imagetypeid) { + // only available in PHP v4.3.0+ + static $image_type_to_mime_type = array(); + if (empty($image_type_to_mime_type)) { + $image_type_to_mime_type[1] = 'image/gif'; // GIF + $image_type_to_mime_type[2] = 'image/jpeg'; // JPEG + $image_type_to_mime_type[3] = 'image/png'; // PNG + $image_type_to_mime_type[4] = 'application/x-shockwave-flash'; // Flash + $image_type_to_mime_type[5] = 'image/psd'; // PSD + $image_type_to_mime_type[6] = 'image/bmp'; // BMP + $image_type_to_mime_type[7] = 'image/tiff'; // TIFF: little-endian (Intel) + $image_type_to_mime_type[8] = 'image/tiff'; // TIFF: big-endian (Motorola) + //$image_type_to_mime_type[9] = 'image/jpc'; // JPC + //$image_type_to_mime_type[10] = 'image/jp2'; // JPC + //$image_type_to_mime_type[11] = 'image/jpx'; // JPC + //$image_type_to_mime_type[12] = 'image/jb2'; // JPC + $image_type_to_mime_type[13] = 'application/x-shockwave-flash'; // Shockwave + $image_type_to_mime_type[14] = 'image/iff'; // IFF + } + return (isset($image_type_to_mime_type[$imagetypeid]) ? $image_type_to_mime_type[$imagetypeid] : 'application/octet-stream'); + } + + + function DateMac2Unix($macdate) { + // Macintosh timestamp: seconds since 00:00h January 1, 1904 + // UNIX timestamp: seconds since 00:00h January 1, 1970 + return getid3_lib::CastAsInt($macdate - 2082844800); + } + + + function FixedPoint8_8($rawdata) { + return getid3_lib::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (getid3_lib::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8)); + } + + + function FixedPoint16_16($rawdata) { + return getid3_lib::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (getid3_lib::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16)); + } + + + function FixedPoint2_30($rawdata) { + $binarystring = getid3_lib::BigEndian2Bin($rawdata); + return getid3_lib::Bin2Dec(substr($binarystring, 0, 2)) + (float) (getid3_lib::Bin2Dec(substr($binarystring, 2, 30)) / 1073741824); + } + + + function CreateDeepArray($ArrayPath, $Separator, $Value) { + // assigns $Value to a nested array path: + // $foo = getid3_lib::CreateDeepArray('/path/to/my', '/', 'file.txt') + // is the same as: + // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt')))); + // or + // $foo['path']['to']['my'] = 'file.txt'; + while ($ArrayPath && ($ArrayPath{0} == $Separator)) { + $ArrayPath = substr($ArrayPath, 1); + } + if (($pos = strpos($ArrayPath, $Separator)) !== false) { + $ReturnedArray[substr($ArrayPath, 0, $pos)] = getid3_lib::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value); + } else { + $ReturnedArray[$ArrayPath] = $Value; + } + return $ReturnedArray; + } + + function array_max($arraydata, $returnkey=false) { + $maxvalue = false; + $maxkey = false; + foreach ($arraydata as $key => $value) { + if (!is_array($value)) { + if ($value > $maxvalue) { + $maxvalue = $value; + $maxkey = $key; + } + } + } + return ($returnkey ? $maxkey : $maxvalue); + } + + function array_min($arraydata, $returnkey=false) { + $minvalue = false; + $minkey = false; + foreach ($arraydata as $key => $value) { + if (!is_array($value)) { + if ($value > $minvalue) { + $minvalue = $value; + $minkey = $key; + } + } + } + return ($returnkey ? $minkey : $minvalue); + } + + + function md5_file($file) { + + // md5_file() exists in PHP 4.2.0+. + if (function_exists('md5_file')) { + return md5_file($file); + } + + if (GETID3_OS_ISWINDOWS) { + + $RequiredFiles = array('cygwin1.dll', 'md5sum.exe'); + foreach ($RequiredFiles as $required_file) { + if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { + die(implode(' and ', $RequiredFiles).' are required in '.GETID3_HELPERAPPSDIR.' for getid3_lib::md5_file() to function under Windows in PHP < v4.2.0'); + } + } + $commandline = GETID3_HELPERAPPSDIR.'md5sum.exe "'.str_replace('/', DIRECTORY_SEPARATOR, $file).'"'; + if (ereg("^[\\]?([0-9a-f]{32})", strtolower(`$commandline`), $r)) { + return $r[1]; + } + + } else { + + // The following works under UNIX only + $file = str_replace('`', '\\`', $file); + if (ereg("^([0-9a-f]{32})[ \t\n\r]", `md5sum "$file"`, $r)) { + return $r[1]; + } + + } + return false; + } + + + function sha1_file($file) { + + // sha1_file() exists in PHP 4.3.0+. + if (function_exists('sha1_file')) { + return sha1_file($file); + } + + $file = str_replace('`', '\\`', $file); + + if (GETID3_OS_ISWINDOWS) { + + $RequiredFiles = array('cygwin1.dll', 'sha1sum.exe'); + foreach ($RequiredFiles as $required_file) { + if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { + die(implode(' and ', $RequiredFiles).' are required in '.GETID3_HELPERAPPSDIR.' for getid3_lib::sha1_file() to function under Windows in PHP < v4.3.0'); + } + } + $commandline = GETID3_HELPERAPPSDIR.'sha1sum.exe "'.str_replace('/', DIRECTORY_SEPARATOR, $file).'"'; + if (ereg("^sha1=([0-9a-f]{40})", strtolower(`$commandline`), $r)) { + return $r[1]; + } + + } else { + + $commandline = 'sha1sum '.escapeshellarg($file).''; + if (ereg("^([0-9a-f]{40})[ \t\n\r]", strtolower(`$commandline`), $r)) { + return $r[1]; + } + + } + + return false; + } + + + // Allan Hansen + // getid3_lib::md5_data() - returns md5sum for a file from startuing position to absolute end position + function hash_data($file, $offset, $end, $algorithm) { + + switch ($algorithm) { + case 'md5': + $hash_function = 'md5_file'; + $unix_call = 'md5sum'; + $windows_call = 'md5sum.exe'; + $hash_length = 32; + break; + + case 'sha1': + $hash_function = 'sha1_file'; + $unix_call = 'sha1sum'; + $windows_call = 'sha1sum.exe'; + $hash_length = 40; + break; + + default: + die('Invalid algorithm ('.$algorithm.') in getid3_lib::hash_data()'); + break; + } + $size = $end - $offset; + while (true) { + if (GETID3_OS_ISWINDOWS) { + + // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data + // Fall back to create-temp-file method: + if ($algorithm == 'sha1') { + break; + } + + $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call); + foreach ($RequiredFiles as $required_file) { + if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { + // helper apps not available - fall back to old method + break; + } + } + $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' "'.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).'" | '; + $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | '; + $commandline .= GETID3_HELPERAPPSDIR.$windows_call; + + } else { + + $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | '; + $commandline .= 'tail -c'.$size.' | '; + $commandline .= $unix_call; + + } + if ((bool) ini_get('safe_mode')) { + $ThisFileInfo['warning'][] = 'PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm'; + break; + } + return substr(`$commandline`, 0, $hash_length); + } + + // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir + if (($data_filename = tempnam('*', 'getID3')) === false) { + // can't find anywhere to create a temp file, just die + return false; + } + + // Init + $result = false; + + // copy parts of file + if ($fp = @fopen($file, 'rb')) { + + if ($fp_data = @fopen($data_filename, 'wb')) { + + fseek($fp, $offset, SEEK_SET); + $byteslefttowrite = $end - $offset; + while (($byteslefttowrite > 0) && ($buffer = fread($fp, GETID3_FREAD_BUFFER_SIZE))) { + $byteswritten = fwrite($fp_data, $buffer, $byteslefttowrite); + $byteslefttowrite -= $byteswritten; + } + fclose($fp_data); + $result = getid3_lib::$hash_function($data_filename); + + } + fclose($fp); + } + unlink($data_filename); + return $result; + } + + + function iconv_fallback_int_utf8($charval) { + if ($charval < 128) { + // 0bbbbbbb + $newcharstring = chr($charval); + } elseif ($charval < 2048) { + // 110bbbbb 10bbbbbb + $newcharstring = chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } elseif ($charval < 65536) { + // 1110bbbb 10bbbbbb 10bbbbbb + $newcharstring = chr(($charval >> 12) | 0xE0); + $newcharstring .= chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } else { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $newcharstring = chr(($charval >> 18) | 0xF0); + $newcharstring .= chr(($charval >> 12) | 0xC0); + $newcharstring .= chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } + return $newcharstring; + } + + // ISO-8859-1 => UTF-8 + function iconv_fallback_iso88591_utf8($string, $bom=false) { + if (function_exists('utf8_encode')) { + return utf8_encode($string); + } + // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xEF\xBB\xBF"; + } + for ($i = 0; $i < strlen($string); $i++) { + $charval = ord($string{$i}); + $newcharstring .= getid3_lib::iconv_fallback_int_utf8($charval); + } + return $newcharstring; + } + + // ISO-8859-1 => UTF-16BE + function iconv_fallback_iso88591_utf16be($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFE\xFF"; + } + for ($i = 0; $i < strlen($string); $i++) { + $newcharstring .= "\x00".$string{$i}; + } + return $newcharstring; + } + + // ISO-8859-1 => UTF-16LE + function iconv_fallback_iso88591_utf16le($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFF\xFE"; + } + for ($i = 0; $i < strlen($string); $i++) { + $newcharstring .= $string{$i}."\x00"; + } + return $newcharstring; + } + + // ISO-8859-1 => UTF-16LE (BOM) + function iconv_fallback_iso88591_utf16($string) { + return getid3_lib::iconv_fallback_iso88591_utf16le($string, true); + } + + // UTF-8 => ISO-8859-1 + function iconv_fallback_utf8_iso88591($string) { + if (function_exists('utf8_decode')) { + return utf8_decode($string); + } + // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) + $newcharstring = ''; + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? throw some kind of warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + } + return $newcharstring; + } + + // UTF-8 => UTF-16BE + function iconv_fallback_utf8_utf16be($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFE\xFF"; + } + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? throw some kind of warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 65536) ? getid3_lib::BigEndian2String($charval, 2) : "\x00".'?'); + } + } + return $newcharstring; + } + + // UTF-8 => UTF-16LE + function iconv_fallback_utf8_utf16le($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFF\xFE"; + } + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? maybe throw some warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 65536) ? getid3_lib::LittleEndian2String($charval, 2) : '?'."\x00"); + } + } + return $newcharstring; + } + + // UTF-8 => UTF-16LE (BOM) + function iconv_fallback_utf8_utf16($string) { + return getid3_lib::iconv_fallback_utf8_utf16le($string, true); + } + + // UTF-16BE => UTF-8 + function iconv_fallback_utf16be_utf8($string) { + if (substr($string, 0, 2) == "\xFE\xFF") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::BigEndian2Int(substr($string, $i, 2)); + $newcharstring .= getid3_lib::iconv_fallback_int_utf8($charval); + } + return $newcharstring; + } + + // UTF-16LE => UTF-8 + function iconv_fallback_utf16le_utf8($string) { + if (substr($string, 0, 2) == "\xFF\xFE") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::LittleEndian2Int(substr($string, $i, 2)); + $newcharstring .= getid3_lib::iconv_fallback_int_utf8($charval); + } + return $newcharstring; + } + + // UTF-16BE => ISO-8859-1 + function iconv_fallback_utf16be_iso88591($string) { + if (substr($string, 0, 2) == "\xFE\xFF") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::BigEndian2Int(substr($string, $i, 2)); + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + return $newcharstring; + } + + // UTF-16LE => ISO-8859-1 + function iconv_fallback_utf16le_iso88591($string) { + if (substr($string, 0, 2) == "\xFF\xFE") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::LittleEndian2Int(substr($string, $i, 2)); + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + return $newcharstring; + } + + // UTF-16 (BOM) => ISO-8859-1 + function iconv_fallback_utf16_iso88591($string) { + $bom = substr($string, 0, 2); + if ($bom == "\xFE\xFF") { + return getid3_lib::iconv_fallback_utf16be_iso88591(substr($string, 2)); + } elseif ($bom == "\xFF\xFE") { + return getid3_lib::iconv_fallback_utf16le_iso88591(substr($string, 2)); + } + return $string; + } + + // UTF-16 (BOM) => UTF-8 + function iconv_fallback_utf16_utf8($string) { + $bom = substr($string, 0, 2); + if ($bom == "\xFE\xFF") { + return getid3_lib::iconv_fallback_utf16be_utf8(substr($string, 2)); + } elseif ($bom == "\xFF\xFE") { + return getid3_lib::iconv_fallback_utf16le_utf8(substr($string, 2)); + } + return $string; + } + + function iconv_fallback($in_charset, $out_charset, $string) { + + if ($in_charset == $out_charset) { + return $string; + } + + static $iconv_broken_or_unavailable = array(); + if (is_null(@$iconv_broken_or_unavailable[$in_charset.'_'.$out_charset])) { + $GETID3_ICONV_TEST_STRING = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ '; + + // Check iconv() + if (function_exists('iconv')) { + if (@iconv($in_charset, 'ISO-8859-1', @iconv('ISO-8859-1', $in_charset, $GETID3_ICONV_TEST_STRING)) == $GETID3_ICONV_TEST_STRING) { + if (@iconv($out_charset, 'ISO-8859-1', @iconv('ISO-8859-1', $out_charset, $GETID3_ICONV_TEST_STRING)) == $GETID3_ICONV_TEST_STRING) { + // everything works, use iconv() + $iconv_broken_or_unavailable[$in_charset.'_'.$out_charset] = false; + } else { + // iconv() available, but broken. Use getID3()'s iconv_fallback() conversions instead + // known issue in PHP v4.1.x + $iconv_broken_or_unavailable[$in_charset.'_'.$out_charset] = true; + } + } else { + // iconv() available, but broken. Use getID3()'s iconv_fallback() conversions instead + // known issue in PHP v4.1.x + $iconv_broken_or_unavailable[$in_charset.'_'.$out_charset] = true; + } + } else { + // iconv() unavailable, use getID3()'s iconv_fallback() conversions + $iconv_broken_or_unavailable[$in_charset.'_'.$out_charset] = true; + } + } + + if ($iconv_broken_or_unavailable[$in_charset.'_'.$out_charset]) { + static $ConversionFunctionList = array(); + if (empty($ConversionFunctionList)) { + $ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8'; + $ConversionFunctionList['ISO-8859-1']['UTF-16'] = 'iconv_fallback_iso88591_utf16'; + $ConversionFunctionList['ISO-8859-1']['UTF-16BE'] = 'iconv_fallback_iso88591_utf16be'; + $ConversionFunctionList['ISO-8859-1']['UTF-16LE'] = 'iconv_fallback_iso88591_utf16le'; + $ConversionFunctionList['UTF-8']['ISO-8859-1'] = 'iconv_fallback_utf8_iso88591'; + $ConversionFunctionList['UTF-8']['UTF-16'] = 'iconv_fallback_utf8_utf16'; + $ConversionFunctionList['UTF-8']['UTF-16BE'] = 'iconv_fallback_utf8_utf16be'; + $ConversionFunctionList['UTF-8']['UTF-16LE'] = 'iconv_fallback_utf8_utf16le'; + $ConversionFunctionList['UTF-16']['ISO-8859-1'] = 'iconv_fallback_utf16_iso88591'; + $ConversionFunctionList['UTF-16']['UTF-8'] = 'iconv_fallback_utf16_utf8'; + $ConversionFunctionList['UTF-16LE']['ISO-8859-1'] = 'iconv_fallback_utf16le_iso88591'; + $ConversionFunctionList['UTF-16LE']['UTF-8'] = 'iconv_fallback_utf16le_utf8'; + $ConversionFunctionList['UTF-16BE']['ISO-8859-1'] = 'iconv_fallback_utf16be_iso88591'; + $ConversionFunctionList['UTF-16BE']['UTF-8'] = 'iconv_fallback_utf16be_utf8'; + } + if (isset($ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)])) { + $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)]; + return getid3_lib::$ConversionFunction($string); + } + die('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset); + } + + if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { + switch ($out_charset) { + case 'ISO-8859-1': + $converted_string = rtrim($converted_string, "\x00"); + break; + } + return $converted_string; + } + + // iconv() may sometimes fail with "illegal character in input string" error message + // and return an empty string, but returning the unconverted string is more useful + return $string; + } + + + function MultiByteCharString2HTML($string, $charset='ISO-8859-1') { + $HTMLstring = ''; + + switch ($charset) { + case 'ISO-8859-1': + case 'ISO8859-1': + case 'ISO-8859-15': + case 'ISO8859-15': + case 'cp866': + case 'ibm866': + case '866': + case 'cp1251': + case 'Windows-1251': + case 'win-1251': + case '1251': + case 'cp1252': + case 'Windows-1252': + case '1252': + case 'KOI8-R': + case 'koi8-ru': + case 'koi8r': + case 'BIG5': + case '950': + case 'GB2312': + case '936': + case 'BIG5-HKSCS': + case 'Shift_JIS': + case 'SJIS': + case '932': + case 'EUC-JP': + case 'EUCJP': + $HTMLstring = htmlentities($string, ENT_COMPAT, $charset); + break; + + case 'UTF-8': + $strlen = strlen($string); + for ($i = 0; $i < $strlen; $i++) { + $char_ord_val = ord($string{$i}); + $charval = 0; + if ($char_ord_val < 0x80) { + $charval = $char_ord_val; + } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F) { + $charval = (($char_ord_val & 0x07) << 18); + $charval += ((ord($string{++$i}) & 0x3F) << 12); + $charval += ((ord($string{++$i}) & 0x3F) << 6); + $charval += (ord($string{++$i}) & 0x3F); + } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07) { + $charval = (($char_ord_val & 0x0F) << 12); + $charval += ((ord($string{++$i}) & 0x3F) << 6); + $charval += (ord($string{++$i}) & 0x3F); + } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03) { + $charval = (($char_ord_val & 0x1F) << 6); + $charval += (ord($string{++$i}) & 0x3F); + } + if (($charval >= 32) && ($charval <= 127)) { + $HTMLstring .= chr($charval); + } else { + $HTMLstring .= '&#'.$charval.';'; + } + } + break; + + case 'UTF-16LE': + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::LittleEndian2Int(substr($string, $i, 2)); + if (($charval >= 32) && ($charval <= 127)) { + $HTMLstring .= chr($charval); + } else { + $HTMLstring .= '&#'.$charval.';'; + } + } + break; + + case 'UTF-16BE': + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::BigEndian2Int(substr($string, $i, 2)); + if (($charval >= 32) && ($charval <= 127)) { + $HTMLstring .= chr($charval); + } else { + $HTMLstring .= '&#'.$charval.';'; + } + } + break; + + default: + $HTMLstring = 'ERROR: Character set "'.$charset.'" not supported in MultiByteCharString2HTML()'; + break; + } + return $HTMLstring; + } + + + + function RGADnameLookup($namecode) { + static $RGADname = array(); + if (empty($RGADname)) { + $RGADname[0] = 'not set'; + $RGADname[1] = 'Track Gain Adjustment'; + $RGADname[2] = 'Album Gain Adjustment'; + } + + return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : ''); + } + + + function RGADoriginatorLookup($originatorcode) { + static $RGADoriginator = array(); + if (empty($RGADoriginator)) { + $RGADoriginator[0] = 'unspecified'; + $RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer'; + $RGADoriginator[2] = 'set by user'; + $RGADoriginator[3] = 'determined automatically'; + } + + return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : ''); + } + + + function RGADadjustmentLookup($rawadjustment, $signbit) { + $adjustment = $rawadjustment / 10; + if ($signbit == 1) { + $adjustment *= -1; + } + return (float) $adjustment; + } + + + function RGADgainString($namecode, $originatorcode, $replaygain) { + if ($replaygain < 0) { + $signbit = '1'; + } else { + $signbit = '0'; + } + $storedreplaygain = intval(round($replaygain * 10)); + $gainstring = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT); + $gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT); + $gainstring .= $signbit; + $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT); + + return $gainstring; + } + + function RGADamplitude2dB($amplitude) { + return 20 * log10($amplitude); + } + + + function GetDataImageSize($imgData) { + $GetDataImageSize = false; + if ($tempfilename = tempnam('*', 'getID3')) { + if ($tmp = @fopen($tempfilename, 'wb')) { + fwrite($tmp, $imgData); + fclose($tmp); + $GetDataImageSize = @GetImageSize($tempfilename); + } + unlink($tempfilename); + } + return $GetDataImageSize; + } + + function ImageTypesLookup($imagetypeid) { + static $ImageTypesLookup = array(); + if (empty($ImageTypesLookup)) { + $ImageTypesLookup[1] = 'gif'; + $ImageTypesLookup[2] = 'jpeg'; + $ImageTypesLookup[3] = 'png'; + $ImageTypesLookup[4] = 'swf'; + $ImageTypesLookup[5] = 'psd'; + $ImageTypesLookup[6] = 'bmp'; + $ImageTypesLookup[7] = 'tiff (little-endian)'; + $ImageTypesLookup[8] = 'tiff (big-endian)'; + $ImageTypesLookup[9] = 'jpc'; + $ImageTypesLookup[10] = 'jp2'; + $ImageTypesLookup[11] = 'jpx'; + $ImageTypesLookup[12] = 'jb2'; + $ImageTypesLookup[13] = 'swc'; + $ImageTypesLookup[14] = 'iff'; + } + return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : ''); + } + + function CopyTagsToComments(&$ThisFileInfo) { + + // Copy all entries from ['tags'] into common ['comments'] + if (!empty($ThisFileInfo['tags'])) { + foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) { + foreach ($tagarray as $tagname => $tagdata) { + foreach ($tagdata as $key => $value) { + if (!empty($value)) { + if (empty($ThisFileInfo['comments'][$tagname])) { + + // fall through and append value + + } elseif ($tagtype == 'id3v1') { + + $newvaluelength = strlen(trim($value)); + foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { + $oldvaluelength = strlen(trim($existingvalue)); + if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) { + // new value is identical but shorter-than (or equal-length to) one already in comments - skip + break 2; + } + } + + } else { + + $newvaluelength = strlen(trim($value)); + foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { + $oldvaluelength = strlen(trim($existingvalue)); + if (($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) { + $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); + break 2; + } + } + + } + if (empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) { + $ThisFileInfo['comments'][$tagname][] = trim($value); + } + } + } + } + } + + // Copy to ['comments_html'] + foreach ($ThisFileInfo['comments'] as $field => $values) { + foreach ($values as $index => $value) { + $ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', getid3_lib::MultiByteCharString2HTML($value, $ThisFileInfo['encoding'])); + } + } + } + } + + + function EmbeddedLookup($key, $begin, $end, $file, $name) { + + // Cached + static $cache; + if (isset($cache[$file][$name])) { + return @$cache[$file][$name][$key]; + } + + // Init + $keylength = strlen($key); + $line_count = $end - $begin - 7; + + // Open php file + $fp = fopen($file, 'r'); + + // Discard $begin lines + for ($i = 0; $i < ($begin + 3); $i++) { + fgets($fp, 1024); + } + + // Loop thru line + while (0 < $line_count--) { + + // Read line + $line = ltrim(fgets($fp, 1024), "\t "); + + // METHOD A: only cache the matching key - less memory but slower on next lookup of not-previously-looked-up key + //$keycheck = substr($line, 0, $keylength); + //if ($key == $keycheck) { + // $cache[$file][$name][$keycheck] = substr($line, $keylength + 1); + // break; + //} + + // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key + //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1)); + @list($ThisKey, $ThisValue) = explode("\t", $line, 2); + $cache[$file][$name][$ThisKey] = trim($ThisValue); + } + + // Close and return + fclose($fp); + return @$cache[$file][$name][$key]; + } + + function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) { + global $GETID3_ERRORARRAY; + + if (file_exists($filename)) { + if (@include_once($filename)) { + return true; + } else { + $diemessage = basename($sourcefile).' depends on '.$filename.', which has errors'; + } + } else { + $diemessage = basename($sourcefile).' depends on '.$filename.', which is missing'; + } + if ($DieOnFailure) { + die($diemessage); + } else { + $GETID3_ERRORARRAY[] = $diemessage; + } + return false; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/getid3.php b/plugins/getId3Plugin/lib/getid3.php new file mode 100644 index 0000000..f05c82b --- /dev/null +++ b/plugins/getId3Plugin/lib/getid3.php @@ -0,0 +1,1527 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | getid3.php | +// | Main getID3() file. | +// | dependencies: modules. | +// +----------------------------------------------------------------------+ +// +// $Id: getid3.php,v 1.5 2006/06/24 22:58:30 ah Exp $ + + +class getid3 +{ + //// Settings Section - do NOT modify this file - change setting after newing getid3! + + // Encoding + public $encoding = 'ISO-8859-1'; // CASE SENSITIVE! - i.e. (must be supported by iconv() - see http://www.gnu.org/software/libiconv/). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE. + public $encoding_id3v1 = 'ISO-8859-1'; // Override SPECIFICATION encoding for broken ID3v1 tags caused by bad tag programs. Examples: 'EUC-CN' for "Chinese MP3s" and 'CP1251' for "Cyrillic". + public $encoding_id3v2 = 'ISO-8859-1'; // Override ISO-8859-1 encoding for broken ID3v2 tags caused by BRAINDEAD tag programs that writes system codepage as 'ISO-8859-1' instead of UTF-8. + + // Tags - disable for speed + public $option_tag_id3v1 = true; // Read and process ID3v1 tags. + public $option_tag_id3v2 = true; // Read and process ID3v2 tags. + public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags. + public $option_tag_apetag = true; // Read and process APE tags. + + // Misc calucations - disable for speed + public $option_analyze = true; // Analyze file - disable if you only need to detect file format. + public $option_accurate_results = true; // Disable to greatly speed up parsing of some file formats at the cost of accuracy. + public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding. + public $option_tags_html = false; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities. + public $option_tags_images = false; // Scan tags for binary image data - ID3v2 and vorbiscomments only. + public $option_extra_info = true; // Calculate/return additional info such as bitrate, channelmode etc. + public $option_max_2gb_check = false; // Check whether file is larger than 2 Gb and thus not supported by PHP. + + // Misc data hashes - slow - require hash module + public $option_md5_data = false; // Get MD5 sum of data part - slow. + public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC, MAC, OptimFROG and Wavpack4. + public $option_sha1_data = false; // Get SHA1 sum of data part - slow. + + // Needed for windows only - no spaces allowed + public $option_helperapps_dir; + + + // Public variables + public $windowed; // Bool - Running under MS Windows. + public $filename; // Filename of file being analysed. + public $fp; // Filepointer to file being analysed. + public $info; // Result array. + + // Private and protected variables + private $include_path; // getid3 include path. + private $warnings = array (); + private $iconv_present; + + // Class constants + const VERSION = '2.0.0b3'; + const FREAD_BUFFER_SIZE = 16384; // Read buffer size in bytes. + const ICONV_TEST_STRING = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ '; + + + + // Constructor - check PHP enviroment and load library. + public function __construct() { + + // Static varibles - no need to recalc every time we new getid3. + static $windowed; + static $include_path; + static $iconv_present; + + + static $initialized; + if ($initialized) { + + // Import static variables + $this->windowed = $windowed; + $this->include_path = $include_path; + $this->iconv_present = $iconv_present; + + // Run init checks only on first instance. + return; + } + + + // Running under Windows? + $this->windowed = $windowed = strtoupper(substr(PHP_OS, 0, 3)) == 'WIN'; + + // Get include_path + $this->include_path = $include_path = dirname(__FILE__) . '/'; + + // Check for presence of iconv() and make sure it works (simpel test only). + if (function_exists('iconv') && @iconv('UTF-16LE', 'ISO-8859-1', @iconv('ISO-8859-1', 'UTF-16LE', getid3::ICONV_TEST_STRING)) == getid3::ICONV_TEST_STRING) { + $this->iconv_present = $iconv_present = true; + } + + // iconv() not present - load replacement module. + else { + $this->include_module('lib.iconv_replacement'); + $this->iconv_present = $iconv_present = false; + } + + + // Require magic_quotes_runtime off + if (get_magic_quotes_runtime()) { + throw new getid3_exception('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'); + } + + + // Check memory limit. + $memory_limit = ini_get('memory_limit'); + if (eregi('([0-9]+)M', $memory_limit, $matches)) { + // could be stored as "16M" rather than 16777216 for example + $memory_limit = $matches[1] * 1048576; + } + if ($memory_limit <= 0) { + // Should not happen. + } elseif ($memory_limit <= 4194304) { + $this->warning('[SERIOUS] PHP has less than 4 Mb available memory and will very likely run out. Increase memory_limit in php.ini.'); + } elseif ($memory_limit <= 12582912) { + $this->warning('PHP has less than 12 Mb available memory and might run out if all modules are loaded. Increase memory_limit in php.ini if needed.'); + } + + + // Check safe_mode off + if ((bool)ini_get('safe_mode')) { + $this->warning('Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbis/flac tag writing disabled.'); + } + + + // Windows only: - ignore if safe mode on + // Define locations of helper applications for shorten, sVorbisComment, MetaFLAC as well as other helper functions such as head, tail, md5sum, etc + // IMPORTANT: This path cannot have spaces in it. If neccesary, use the 8dot3 equivalent ie for "C:/Program Files/Apache/" put "C:/PROGRA~1/APACHE/" + elseif ($this->windowed) { + + $this->option_helperapps_dir = realpath($this->option_helperapps_dir); + + if (!$this->option_helperapps_dir) { + $this->warning('Running windows and option_helperapps_dir not set to valid directory. Shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbis/flac tag writing disabled.'); + } + + elseif (strstr(realpath($this->option_helperapps_dir), ' ')) { + $this->warning('option_helperapps_dir contains spaces - not allowed. Shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbis/flac tag writing disabled.'); + } + } + + $initialized = true; + } + + + + // Analyze file by name + public function Analyze($filename) { + + // Init and save values + $this->filename = $filename; + $this->warnings = array (); + + // Init result array and set parameters + $this->info = array (); + $this->info['GETID3_VERSION'] = getid3::VERSION; + + // Remote files not supported + if (preg_match('/^(ht|f)tp:\/\//', $filename)) { + throw new getid3_exception('Remote files are not supported - please copy the file locally first.'); + } + + // Open local file + if (!$this->fp = @fopen($filename, 'rb')) { + throw new getid3_exception('Could not open file "'.$filename.'"'); + } + + // Set filesize related parameters + $this->info['filesize'] = filesize($filename); + $this->info['avdataoffset'] = 0; + $this->info['avdataend'] = $this->info['filesize']; + + // Option_max_2gb_check + if ($this->option_max_2gb_check) { + // PHP doesn't support integers larger than 31-bit (~2GB) + // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize + // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer + fseek($this->fp, 0, SEEK_END); + if ((($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) || + ($this->info['filesize'] < 0) || + (ftell($this->fp) < 0)) { + unset($this->info['filesize']); + fclose($this->fp); + throw new getid3_exception('File is most likely larger than 2GB and is not supported by PHP.'); + } + } + + + // ID3v2 detection (NOT parsing) done to make fileformat easier. + if (!$this->option_tag_id3v2) { + + fseek($this->fp, 0, SEEK_SET); + $header = fread($this->fp, 10); + if (substr($header, 0, 3) == 'ID3') { + $this->info['id3v2']['header'] = true; + $this->info['id3v2']['majorversion'] = ord($header{3}); + $this->info['id3v2']['minorversion'] = ord($header{4}); + $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length + } + } + + + // Handle tags + foreach (array ("id3v2", "id3v1", "apetag", "lyrics3") as $tag_name) { + + $option_tag = 'option_tag_' . $tag_name; + if ($this->$option_tag) { + $this->include_module('tag.'.$tag_name); + try { + $tag_class = 'getid3_' . $tag_name; + $tag = new $tag_class($this); + $tag->Analyze(); + } + catch (getid3_exception $e) { + throw $e; + } + } + } + + + + //// Determine file format by magic bytes in file header. + + // Read 32 kb file data + fseek($this->fp, $this->info['avdataoffset'], SEEK_SET); + $filedata = fread($this->fp, 32774); + + // Get huge FileFormatArray + $file_format_array = getid3::GetFileFormatArray(); + + // Identify file format - loop through $format_info and detect with reg expr + foreach ($file_format_array as $name => $info) { + + if (preg_match('/'.$info['pattern'].'/s', $filedata)) { // The /s switch on preg_match() forces preg_match() NOT to treat newline (0x0A) characters as special chars but do a binary match + + // Format detected but not supported + if (!@$info['module'] || !@$info['group']) { + fclose($this->fp); + $this->info['fileformat'] = $name; + $this->info['mime_type'] = $info['mime_type']; + $this->warning('Format only detected. Parsing not available yet.'); + $this->info['warning'] = $this->warnings; + return $this->info; + } + + $determined_format = $info; // copy $info deleted by foreach() + continue; + } + } + + // Unable to determine file format + if (!@$determined_format) { + + // Too many mp3 encoders on the market put gabage in front of mpeg files + // use assume format on these if format detection failed + if (preg_match('/\.mp[123a]$/i', $filename)) { + $determined_format = $file_format_array['mp3']; + } + + else { + fclose($this->fp); + throw new getid3_exception('Unable to determine file format'); + } + } + + // Free memory + unset($file_format_array); + + // Check for illegal ID3 tags + if (@$determined_format['fail_id3'] && (@$this->info['id3v1'] || @$this->info['id3v2'])) { + if ($determined_format['fail_id3'] === 'ERROR') { + fclose($this->fp); + throw new getid3_exception('ID3 tags not allowed on this file type.'); + } + elseif ($determined_format['fail_id3'] === 'WARNING') { + @$this->info['id3v1'] and $this->warning('ID3v1 tags not allowed on this file type.'); + @$this->info['id3v2'] and $this->warning('ID3v2 tags not allowed on this file type.'); + } + } + + // Check for illegal APE tags + if (@$determined_format['fail_ape'] && @$this->info['tags']['ape']) { + if ($determined_format['fail_ape'] === 'ERROR') { + fclose($this->fp); + throw new getid3_exception('APE tags not allowed on this file type.'); + } elseif ($determined_format['fail_ape'] === 'WARNING') { + $this->warning('APE tags not allowed on this file type.'); + } + } + + + // Set mime type + $this->info['mime_type'] = $determined_format['mime_type']; + + // Calc module file name + $determined_format['include'] = 'module.'.$determined_format['group'].'.'.$determined_format['module'].'.php'; + + // Supported format signature pattern detected, but module deleted. + if (!file_exists($this->include_path.$determined_format['include'])) { + fclose($this->fp); + throw new getid3_exception('Format not supported, module, '.$determined_format['include'].', was removed.'); + } + + // Include module + $this->include_module($determined_format['group'].'.'.$determined_format['module']); + + // Instantiate module class and analyze + $class_name = 'getid3_'.$determined_format['module']; + if (!class_exists($class_name)) { + throw new getid3_exception('Format not supported, module, '.$determined_format['include'].', is corrupt.'); + } + $class = new $class_name($this); + + try { + $this->option_analyze and $class->Analyze(); + } + catch (getid3_exception $e) { + throw $e; + } + catch (Exception $e) { + throw new getid3_exception('Corrupt file.'); + } + + // Close file + fclose($this->fp); + + // Optional - Process all tags - copy to 'tags' and convert charsets + if ($this->option_tags_process) { + $this->HandleAllTags(); + } + + + //// Optional - perform more calculations + if ($this->option_extra_info) { + + // Set channelmode on audio + if (@$this->info['audio']['channels'] == '1') { + $this->info['audio']['channelmode'] = 'mono'; + } elseif (@$this->info['audio']['channels'] == '2') { + $this->info['audio']['channelmode'] = 'stereo'; + } + + // Calculate combined bitrate - audio + video + $combined_bitrate = 0; + $combined_bitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0); + $combined_bitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); + if (($combined_bitrate > 0) && empty($this->info['bitrate'])) { + $this->info['bitrate'] = $combined_bitrate; + } + if (!isset($this->info['playtime_seconds']) && !empty($this->info['bitrate'])) { + $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate']; + } + + // Set playtime string + if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) { + $this->info['playtime_string'] = floor(round($this->info['playtime_seconds']) / 60) . ':' . str_pad(floor(round($this->info['playtime_seconds']) % 60), 2, 0, STR_PAD_LEFT);; + } + + + // CalculateCompressionRatioVideo() { + if (@$this->info['video'] && @$this->info['video']['resolution_x'] && @$this->info['video']['resolution_y'] && @$this->info['video']['bits_per_sample']) { + + // From static image formats + if (in_array($this->info['video']['dataformat'], array ('bmp', 'gif', 'jpeg', 'jpg', 'png', 'tiff'))) { + $frame_rate = 1; + $bitrate_compressed = $this->info['filesize'] * 8; + } + + // From video formats + else { + $frame_rate = @$this->info['video']['frame_rate']; + $bitrate_compressed = @$this->info['video']['bitrate']; + } + + if ($frame_rate && $bitrate_compressed) { + $this->info['video']['compression_ratio'] = $bitrate_compressed / ($this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $frame_rate); + } + } + + + // CalculateCompressionRatioAudio() { + if (@$this->info['audio']['bitrate'] && @$this->info['audio']['channels'] && @$this->info['audio']['sample_rate']) { + $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (@$this->info['audio']['bits_per_sample'] ? $this->info['audio']['bits_per_sample'] : 16)); + } + + if (@$this->info['audio']['streams']) { + foreach ($this->info['audio']['streams'] as $stream_number => $stream_data) { + if (@$stream_data['bitrate'] && @$stream_data['channels'] && @$stream_data['sample_rate']) { + $this->info['audio']['streams'][$stream_number]['compression_ratio'] = $stream_data['bitrate'] / ($stream_data['channels'] * $stream_data['sample_rate'] * (@$stream_data['bits_per_sample'] ? $stream_data['bits_per_sample'] : 16)); + } + } + } + + + // CalculateReplayGain() { + if (@$this->info['replay_gain']) { + $this->info['replay_gain']['reference_volume'] = 89; + if (isset($this->info['replay_gain']['track']['adjustment'])) { + $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; + } + if (isset($this->info['replay_gain']['album']['adjustment'])) { + $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment']; + } + + if (isset($this->info['replay_gain']['track']['peak'])) { + $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - 20 * log10($this->info['replay_gain']['track']['peak']); + } + if (isset($this->info['replay_gain']['album']['peak'])) { + $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - 20 * log10($this->info['replay_gain']['album']['peak']); + } + } + + + // ProcessAudioStreams() { + if (@!$this->info['audio']['streams'] && (@$this->info['audio']['bitrate'] || @$this->info['audio']['channels'] || @$this->info['audio']['sample_rate'])) { + foreach ($this->info['audio'] as $key => $value) { + if ($key != 'streams') { + $this->info['audio']['streams'][0][$key] = $value; + } + } + } + } + + + // Get the md5/sha1sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags. + if ($this->option_md5_data || $this->option_sha1_data) { + + // Load data-hash library if needed + $this->include_module('lib.data_hash'); + + if ($this->option_sha1_data) { + new getid3_lib_data_hash($this, 'sha1'); + } + + if ($this->option_md5_data) { + + // do not call md5_data if md5_data_source is present - set by FLAC, MAC, OptimFROG, Wavpack4 - future MPC/SV8 too... + if (!$this->option_md5_data_source || !@$this->info['md5_data_source']) { + new getid3_lib_data_hash($this, 'md5'); + } + } + } + + // Set warnings + if ($this->warnings) { + $this->info['warning'] = $this->warnings; + } + + // Return result + return $this->info; + } + + + + // Return array of warnings + public function warnings() { + + return $this->warnings; + } + + + + // Add warning(s) to $this->warnings[] + public function warning($message) { + + if (is_array($message)) { + $this->warnings = array_merge($this->warnings, $message); + } + else { + $this->warnings[] = $message; + } + } + + + + // Clear all warnings when cloning + public function __clone() { + + $this->warnings = array (); + + // Copy info array, otherwise it will be a reference. + $temp = $this->info; + unset($this->info); + $this->info = $temp; + } + + + + // Convert string between charsets -- iconv() wrapper + public function iconv($in_charset, $out_charset, $string, $drop01 = false) { + + if ($drop01 && ($string === "\x00" || $string === "\x01")) { + return ''; + } + + + if (!$this->iconv_present) { + return getid3_iconv_replacement::iconv($in_charset, $out_charset, $string); + } + + + // iconv() present + if ($result = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { + + if ($out_charset == 'ISO-8859-1') { + return rtrim($result, "\x00"); + } + return $result; + } + + $this->warning('iconv() was unable to convert the string: "' . $string . '" from ' . $in_charset . ' to ' . $out_charset); + return $string; + } + + + + public function include_module($name) { + + if (!file_exists($this->include_path.'module.'.$name.'.php')) { + throw new getid3_exception('Required module.'.$name.'.php is missing.'); + } + + include_once($this->include_path.'module.'.$name.'.php'); + } + + + + public function include_module_optional($name) { + + if (!file_exists($this->include_path.'module.'.$name.'.php')) { + return; + } + + include_once($this->include_path.'module.'.$name.'.php'); + return true; + } + + + // Return array containing information about all supported formats + public static function GetFileFormatArray() { + + static $format_info = array ( + + // Audio formats + + // AC-3 - audio - Dolby AC-3 / Dolby Digital + 'ac3' => array ( + 'pattern' => '^\x0B\x77', + 'group' => 'audio', + 'module' => 'ac3', + 'mime_type' => 'audio/ac3', + ), + + // AAC - audio - Advanced Audio Coding (AAC) - ADIF format + 'adif' => array ( + 'pattern' => '^ADIF', + 'group' => 'audio', + 'module' => 'aac_adif', + 'mime_type' => 'application/octet-stream', + 'fail_ape' => 'WARNING', + ), + + + // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3) + 'adts' => array ( + 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]', + 'group' => 'audio', + 'module' => 'aac_adts', + 'mime_type' => 'application/octet-stream', + 'fail_ape' => 'WARNING', + ), + + + // AU - audio - NeXT/Sun AUdio (AU) + 'au' => array ( + 'pattern' => '^\.snd', + 'group' => 'audio', + 'module' => 'au', + 'mime_type' => 'audio/basic', + ), + + // AVR - audio - Audio Visual Research + 'avr' => array ( + 'pattern' => '^2BIT', + 'group' => 'audio', + 'module' => 'avr', + 'mime_type' => 'application/octet-stream', + ), + + // BONK - audio - Bonk v0.9+ + 'bonk' => array ( + 'pattern' => '^\x00(BONK|INFO|META| ID3)', + 'group' => 'audio', + 'module' => 'bonk', + 'mime_type' => 'audio/xmms-bonk', + ), + + // FLAC - audio - Free Lossless Audio Codec + 'flac' => array ( + 'pattern' => '^fLaC', + 'group' => 'audio', + 'module' => 'xiph', + 'mime_type' => 'audio/x-flac', + ), + + // LA - audio - Lossless Audio (LA) + 'la' => array ( + 'pattern' => '^LA0[2-4]', + 'group' => 'audio', + 'module' => 'la', + 'mime_type' => 'application/octet-stream', + ), + + // LPAC - audio - Lossless Predictive Audio Compression (LPAC) + 'lpac' => array ( + 'pattern' => '^LPAC', + 'group' => 'audio', + 'module' => 'lpac', + 'mime_type' => 'application/octet-stream', + ), + + // MIDI - audio - MIDI (Musical Instrument Digital Interface) + 'midi' => array ( + 'pattern' => '^MThd', + 'group' => 'audio', + 'module' => 'midi', + 'mime_type' => 'audio/midi', + ), + + // MAC - audio - Monkey's Audio Compressor + 'mac' => array ( + 'pattern' => '^MAC ', + 'group' => 'audio', + 'module' => 'monkey', + 'mime_type' => 'application/octet-stream', + ), + + // MOD - audio - MODule (assorted sub-formats) + 'mod' => array ( + 'pattern' => '^.{1080}(M.K.|[5-9]CHN|[1-3][0-9]CH)', + 'mime_type' => 'audio/mod', + ), + + // MOD - audio - MODule (Impulse Tracker) + 'it' => array ( + 'pattern' => '^IMPM', + 'mime_type' => 'audio/it', + ), + + // MOD - audio - MODule (eXtended Module, various sub-formats) + 'xm' => array ( + 'pattern' => '^Extended Module', + 'mime_type' => 'audio/xm', + ), + + // MOD - audio - MODule (ScreamTracker) + 's3m' => array ( + 'pattern' => '^.{44}SCRM', + 'mime_type' => 'audio/s3m', + ), + + // MPC - audio - Musepack / MPEGplus SV7+ + 'mpc' => array ( + 'pattern' => '^(MP\+)', + 'group' => 'audio', + 'module' => 'mpc', + 'mime_type' => 'application/octet-stream', + ), + + // MPC - audio - Musepack / MPEGplus SV4-6 + 'mpc_old' => array ( + 'pattern' => '^([\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])', + 'group' => 'audio', + 'module' => 'mpc_old', + 'mime_type' => 'application/octet-stream', + ), + + + // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS) + 'mp3' => array ( + 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]', + 'group' => 'audio', + 'module' => 'mp3', + 'mime_type' => 'audio/mpeg', + ), + + // OFR - audio - OptimFROG + 'ofr' => array ( + 'pattern' => '^(\*RIFF|OFR)', + 'group' => 'audio', + 'module' => 'optimfrog', + 'mime_type' => 'application/octet-stream', + ), + + // RKAU - audio - RKive AUdio compressor + 'rkau' => array ( + 'pattern' => '^RKA', + 'group' => 'audio', + 'module' => 'rkau', + 'mime_type' => 'application/octet-stream', + ), + + // SHN - audio - Shorten + 'shn' => array ( + 'pattern' => '^ajkg', + 'group' => 'audio', + 'module' => 'shorten', + 'mime_type' => 'audio/xmms-shn', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) + 'tta' => array ( + 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)' + 'group' => 'audio', + 'module' => 'tta', + 'mime_type' => 'application/octet-stream', + ), + + // VOC - audio - Creative Voice (VOC) + 'voc' => array ( + 'pattern' => '^Creative Voice File', + 'group' => 'audio', + 'module' => 'voc', + 'mime_type' => 'audio/voc', + ), + + // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF) + 'vqf' => array ( + 'pattern' => '^TWIN', + 'group' => 'audio', + 'module' => 'vqf', + 'mime_type' => 'application/octet-stream', + ), + + // WV - audio - WavPack (v4.0+) + 'vw' => array( + 'pattern' => '^wvpk', + 'group' => 'audio', + 'module' => 'wavpack', + 'mime_type' => 'application/octet-stream', + ), + + + // Audio-Video formats + + // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio + 'asf' => array ( + 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', + 'group' => 'audio-video', + 'module' => 'asf', + 'mime_type' => 'video/x-ms-asf', + ), + + // BINK - audio/video - Bink / Smacker + 'bink' => array( + 'pattern' => '^(BIK|SMK)', + 'mime_type' => 'application/octet-stream', + ), + + // FLV - audio/video - FLash Video + 'flv' => array( + 'pattern' => '^FLV\x01', + 'group' => 'audio-video', + 'module' => 'flv', + 'mime_type' => 'video/x-flv', + ), + + // MKAV - audio/video - Mastroka + 'matroska' => array ( + 'pattern' => '^\x1A\x45\xDF\xA3', + 'mime_type' => 'application/octet-stream', + ), + + // MPEG - audio/video - MPEG (Moving Pictures Experts Group) + 'mpeg' => array ( + 'pattern' => '^\x00\x00\x01(\xBA|\xB3)', + 'group' => 'audio-video', + 'module' => 'mpeg', + 'mime_type' => 'video/mpeg', + ), + + // NSV - audio/video - Nullsoft Streaming Video (NSV) + 'nsv' => array ( + 'pattern' => '^NSV[sf]', + 'group' => 'audio-video', + 'module' => 'nsv', + 'mime_type' => 'application/octet-stream', + ), + + // Ogg - audio/video - Ogg (Ogg Vorbis, OggFLAC, Speex, Ogg Theora(*), Ogg Tarkin(*)) + 'ogg' => array ( + 'pattern' => '^OggS', + 'group' => 'audio', + 'module' => 'xiph', + 'mime_type' => 'application/ogg', + 'fail_id3' => 'WARNING', + 'fail_ape' => 'WARNING', + ), + + // QT - audio/video - Quicktime + 'quicktime' => array ( + 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', + 'group' => 'audio-video', + 'module' => 'quicktime', + 'mime_type' => 'video/quicktime', + ), + + // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF) + 'riff' => array ( + 'pattern' => '^(RIFF|SDSS|FORM)', + 'group' => 'audio-video', + 'module' => 'riff', + 'mime_type' => 'audio/x-wave', + 'fail_ape' => 'WARNING', + ), + + // Real - audio/video - RealAudio, RealVideo + 'real' => array ( + 'pattern' => '^(\.RMF|.ra)', + 'group' => 'audio-video', + 'module' => 'real', + 'mime_type' => 'audio/x-realaudio', + ), + + // SWF - audio/video - ShockWave Flash + 'swf' => array ( + 'pattern' => '^(F|C)WS', + 'group' => 'audio-video', + 'module' => 'swf', + 'mime_type' => 'application/x-shockwave-flash', + ), + + + // Still-Image formats + + // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4) + 'bmp' => array ( + 'pattern' => '^BM', + 'group' => 'graphic', + 'module' => 'bmp', + 'mime_type' => 'image/bmp', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // GIF - still image - Graphics Interchange Format + 'gif' => array ( + 'pattern' => '^GIF', + 'group' => 'graphic', + 'module' => 'gif', + 'mime_type' => 'image/gif', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // JPEG - still image - Joint Photographic Experts Group (JPEG) + 'jpeg' => array ( + 'pattern' => '^\xFF\xD8\xFF', + 'group' => 'graphic', + 'module' => 'jpeg', + 'mime_type' => 'image/jpeg', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // PCD - still image - Kodak Photo CD + 'pcd' => array ( + 'pattern' => '^.{2048}PCD_IPI\x00', + 'group' => 'graphic', + 'module' => 'pcd', + 'mime_type' => 'image/x-photo-cd', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // PNG - still image - Portable Network Graphics (PNG) + 'png' => array ( + 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', + 'group' => 'graphic', + 'module' => 'png', + 'mime_type' => 'image/png', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // TIFF - still image - Tagged Information File Format (TIFF) + 'tiff' => array ( + 'pattern' => '^(II\x2A\x00|MM\x00\x2A)', + 'group' => 'graphic', + 'module' => 'tiff', + 'mime_type' => 'image/tiff', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // Data formats + + 'exe' => array( + 'pattern' => '^MZ', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // ISO - data - International Standards Organization (ISO) CD-ROM Image + 'iso' => array ( + 'pattern' => '^.{32769}CD001', + 'group' => 'misc', + 'module' => 'iso', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // RAR - data - RAR compressed data + 'rar' => array( + 'pattern' => '^Rar\!', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // SZIP - audio - SZIP compressed data + 'szip' => array ( + 'pattern' => '^SZ\x0A\x04', + 'group' => 'archive', + 'module' => 'szip', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // TAR - data - TAR compressed data + 'tar' => array( + 'pattern' => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}', + 'group' => 'archive', + 'module' => 'tar', + 'mime_type' => 'application/x-tar', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // GZIP - data - GZIP compressed data + 'gz' => array( + 'pattern' => '^\x1F\x8B\x08', + 'group' => 'archive', + 'module' => 'gzip', + 'mime_type' => 'application/x-gzip', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // ZIP - data - ZIP compressed data + 'zip' => array ( + 'pattern' => '^PK\x03\x04', + 'group' => 'archive', + 'module' => 'zip', + 'mime_type' => 'application/zip', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // PDF - data - Portable Document Format? + 'pdf' => array( + 'pattern' => '^\x25PDF', + 'mime_type' => 'application/pdf', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // DOC - data - Microsoft Word + 'msoffice' => array( + 'pattern' => '^\xD0\xCF\x11\xE0', // D0CF11E == DOCFILE == Microsoft Office Document + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + ); + + return $format_info; + } + + + + // Recursive over array - converts array to $encoding charset from $this->encoding + function CharConvert(&$array, $encoding) { + + // Identical encoding - end here + if ($encoding == $this->encoding) { + return; + } + + // Loop thru array + foreach ($array as $key => $value) { + + // Go recursive + if (is_array($value)) { + $this->CharConvert($array[$key], $encoding); + } + + // Convert string + elseif (is_string($value)) { + $array[$key] = $this->iconv($encoding, $this->encoding, $value); + } + } + } + + + + // Convert and copy tags + protected function HandleAllTags() { + + // Key name => array (tag name, character encoding) + static $tags = array ( + 'asf' => array ('asf', 'UTF-16LE'), + 'midi' => array ('midi', 'ISO-8859-1'), + 'nsv' => array ('nsv', 'ISO-8859-1'), + 'ogg' => array ('vorbiscomment', 'UTF-8'), + 'png' => array ('png', 'UTF-8'), + 'tiff' => array ('tiff', 'ISO-8859-1'), + 'quicktime' => array ('quicktime', 'ISO-8859-1'), + 'real' => array ('real', 'ISO-8859-1'), + 'vqf' => array ('vqf', 'ISO-8859-1'), + 'zip' => array ('zip', 'ISO-8859-1'), + 'riff' => array ('riff', 'ISO-8859-1'), + 'lyrics3' => array ('lyrics3', 'ISO-8859-1'), + 'id3v1' => array ('id3v1', ''), // change below - cannot assign variable to static array + 'id3v2' => array ('id3v2', 'UTF-8'), // module converts all frames to UTF-8 + 'ape' => array ('ape', 'UTF-8') + ); + $tags['id3v1'][1] = $this->encoding_id3v1; + + // Loop thru tags array + foreach ($tags as $comment_name => $tag_name_encoding_array) { + list($tag_name, $encoding) = $tag_name_encoding_array; + + // Fill in default encoding type if not already present + @$this->info[$comment_name] and $this->info[$comment_name]['encoding'] = $encoding; + + // Copy comments if key name set + if (@$this->info[$comment_name]['comments']) { + + foreach ($this->info[$comment_name]['comments'] as $tag_key => $value_array) { + foreach ($value_array as $key => $value) { + if (strlen(trim($value)) > 0) { + $this->info['tags'][$tag_name][trim($tag_key)][] = $value; // do not trim!! Unicode characters will get mangled if trailing nulls are removed! + } + } + + } + + if (!@$this->info['tags'][$tag_name]) { + // comments are set but contain nothing but empty strings, so skip + continue; + } + + if ($this->option_tags_html) { + foreach ($this->info['tags'][$tag_name] as $tag_key => $value_array) { + foreach ($value_array as $key => $value) { + if (is_string($value)) { + + switch ($encoding) { + case 'ISO-8859-1': + case 'ISO-8859-15': + case 'cp866': + case 'ibm866': + case '866': + case 'cp1251': + case 'Windows-1251': + case 'win-1251': + case '1251': + case 'cp1252': + case 'Windows-1252': + case '1252': + case 'KOI8-R': + case 'koi8-ru': + case 'koi8r': + case 'BIG5': + case '950': + case 'GB2312': + case '936': + case 'BIG5-HKSCS': + case 'Shift_JIS': + case 'SJIS': + case '932': + case 'EUC-JP': + case 'EUCJP': + $html = htmlentities($value, ENT_NOQUOTES, $encoding); + break; + + case 'UTF-8': + case 'UTF-16LE': + case 'UTF-16BE': + case 'UTF-16': + $html = htmlentities($this->iconv($encoding, 'ISO-8859-1', $value), ENT_NOQUOTES); + break; + + default: + throw new getid3_exception('Character set "'.$charset.'" not supported by htmlentities().'); + } + + $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('�', '', $html); + unset($html); + + } else { + $this->info['tags_html'][$tag_name][$tag_key][$key] = $value; + } + } + } + } + + $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! + } + } + return true; + } +} + + + + +abstract class getid3_handler +{ + + protected $getid3; // pointer + + protected $data_string_flag = false; // analyzing filepointer or string + protected $data_string; // string to analyze + protected $data_string_position = 0; // seek position in string + + + public function __construct(getID3 $getid3) { + + $this->getid3 = $getid3; + } + + + // Analyze from file pointer + abstract public function Analyze(); + + + + // Analyze from string instead + public function AnalyzeString(&$string) { + + // Enter string mode + $this->data_string_flag = true; + $this->data_string = $string; + + // Save info + $saved_avdataoffset = $this->getid3->info['avdataoffset']; + $saved_avdataend = $this->getid3->info['avdataend']; + $saved_filesize = $this->getid3->info['filesize']; + + // Reset some info + $this->getid3->info['avdataoffset'] = 0; + $this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = strlen($string); + + // Analyze + $this->Analyze(); + + // Restore some info + $this->getid3->info['avdataoffset'] = $saved_avdataoffset; + $this->getid3->info['avdataend'] = $saved_avdataend; + $this->getid3->info['filesize'] = $saved_filesize; + + // Exit string mode + $this->data_string_flag = false; + } + + + protected function ftell() { + + if ($this->data_string_flag) { + return $this->data_string_position; + } + return ftell($this->getid3->fp); + } + + + protected function fread($bytes) { + + if ($this->data_string_flag) { + $this->data_string_position += $bytes; + return substr($this->data_string, $this->data_string_position - $bytes, $bytes); + } + return fread($this->getid3->fp, $bytes); + } + + + protected function fseek($bytes, $whence = SEEK_SET) { + + if ($this->data_string_flag) { + switch ($whence) { + case SEEK_SET: + $this->data_string_position = $bytes; + return; + + case SEEK_CUR: + $this->data_string_position += $bytes; + return; + + case SEEK_END: + $this->data_string_position = strlen($this->data_string) + $bytes; + return; + } + } + return fseek($this->getid3->fp, $bytes, $whence); + } + +} + + + + +class getid3_exception extends Exception +{ + public $message; +} + + + + +class getid3_lib +{ + + // Convert Little Endian byte string to int - max 32 bits + public static function LittleEndian2Int($byte_word, $signed = false) { + + return getid3_lib::BigEndian2Int(strrev($byte_word), $signed); + } + + + + // Convert number to Little Endian byte string + public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { + $intstring = ''; + while ($number > 0) { + if ($synchsafe) { + $intstring = $intstring.chr($number & 127); + $number >>= 7; + } else { + $intstring = $intstring.chr($number & 255); + $number >>= 8; + } + } + return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); + } + + + + // Convert Big Endian byte string to int - max 32 bits + public static function BigEndian2Int($byte_word, $signed = false) { + + $int_value = 0; + $byte_wordlen = strlen($byte_word); + + for ($i = 0; $i < $byte_wordlen; $i++) { + $int_value += ord($byte_word{$i}) * pow(256, ($byte_wordlen - 1 - $i)); + } + + if ($signed) { + $sign_mask_bit = 0x80 << (8 * ($byte_wordlen - 1)); + if ($int_value & $sign_mask_bit) { + $int_value = 0 - ($int_value & ($sign_mask_bit - 1)); + } + } + + return $int_value; + } + + + + // Convert Big Endian byte sybc safe string to int - max 32 bits + public static function BigEndianSyncSafe2Int($byte_word) { + + $int_value = 0; + $byte_wordlen = strlen($byte_word); + + // disregard MSB, effectively 7-bit bytes + for ($i = 0; $i < $byte_wordlen; $i++) { + $int_value = $int_value | (ord($byte_word{$i}) & 0x7F) << (($byte_wordlen - 1 - $i) * 7); + } + return $int_value; + } + + + + // Convert Big Endian byte string to bit string + public static function BigEndian2Bin($byte_word) { + + $bin_value = ''; + $byte_wordlen = strlen($byte_word); + for ($i = 0; $i < $byte_wordlen; $i++) { + $bin_value .= str_pad(decbin(ord($byte_word{$i})), 8, '0', STR_PAD_LEFT); + } + return $bin_value; + } + + + + public static function BigEndian2Float($byte_word) { + + // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic + // http://www.psc.edu/general/software/packages/ieee/ieee.html + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html + + $bit_word = getid3_lib::BigEndian2Bin($byte_word); + $sign_bit = $bit_word{0}; + + switch (strlen($byte_word) * 8) { + case 32: + $exponent_bits = 8; + $fraction_bits = 23; + break; + + case 64: + $exponent_bits = 11; + $fraction_bits = 52; + break; + + case 80: + // 80-bit Apple SANE format + // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ + $exponent_string = substr($bit_word, 1, 15); + $is_normalized = intval($bit_word{16}); + $fraction_string = substr($bit_word, 17, 63); + $exponent = pow(2, getid3_lib::Bin2Dec($exponent_string) - 16383); + $fraction = $is_normalized + getid3_lib::DecimalBinary2Float($fraction_string); + $float_value = $exponent * $fraction; + if ($sign_bit == '1') { + $float_value *= -1; + } + return $float_value; + break; + + default: + return false; + break; + } + $exponent_string = substr($bit_word, 1, $exponent_bits); + $fraction_string = substr($bit_word, $exponent_bits + 1, $fraction_bits); + $exponent = bindec($exponent_string); + $fraction = bindec($fraction_string); + + if (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction != 0)) { + // Not a Number + $float_value = false; + } elseif (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction == 0)) { + if ($sign_bit == '1') { + $float_value = '-infinity'; + } else { + $float_value = '+infinity'; + } + } elseif (($exponent == 0) && ($fraction == 0)) { + if ($sign_bit == '1') { + $float_value = -0; + } else { + $float_value = 0; + } + $float_value = ($sign_bit ? 0 : -0); + } elseif (($exponent == 0) && ($fraction != 0)) { + // These are 'unnormalized' values + $float_value = pow(2, (-1 * (pow(2, $exponent_bits - 1) - 2))) * getid3_lib::DecimalBinary2Float($fraction_string); + if ($sign_bit == '1') { + $float_value *= -1; + } + } elseif ($exponent != 0) { + $float_value = pow(2, ($exponent - (pow(2, $exponent_bits - 1) - 1))) * (1 + getid3_lib::DecimalBinary2Float($fraction_string)); + if ($sign_bit == '1') { + $float_value *= -1; + } + } + return (float) $float_value; + } + + + + public static function LittleEndian2Float($byte_word) { + + return getid3_lib::BigEndian2Float(strrev($byte_word)); + } + + + + public static function DecimalBinary2Float($binary_numerator) { + $numerator = bindec($binary_numerator); + $denominator = bindec('1'.str_repeat('0', strlen($binary_numerator))); + return ($numerator / $denominator); + } + + + public static function PrintHexBytes($string, $hex=true, $spaces=true, $html_safe=true) { + + $return_string = ''; + for ($i = 0; $i < strlen($string); $i++) { + if ($hex) { + $return_string .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT); + } else { + $return_string .= ' '.(ereg("[\x20-\x7E]", $string{$i}) ? $string{$i} : ''); + } + if ($spaces) { + $return_string .= ' '; + } + } + if ($html_safe) { + $return_string = htmlentities($return_string); + } + return $return_string; + } + + + + // Process header data string - read several values with algorithm and add to target + // algorithm is one one the getid3_lib::Something2Something() function names + // parts_array is index => length - $target[index] = algorithm(substring(data)) + // - OR just substring(data) if length is negative! + // indexes == 'IGNORE**' are ignored + + public static function ReadSequence($algorithm, &$target, &$data, $offset, $parts_array) { + + // Loop thru $parts_array + foreach ($parts_array as $target_string => $length) { + + // Add to target + if (!strstr($target_string, 'IGNORE')) { + + // substr(....length) + if ($length < 0) { + $target[$target_string] = substr($data, $offset, -$length); + } + + // algorithm(substr(...length)) + else { + $target[$target_string] = getid3_lib::$algorithm(substr($data, $offset, $length)); + } + } + + // Move pointer + $offset += abs($length); + } + } + +} + + + +class getid3_lib_replaygain +{ + + public static function NameLookup($name_code) { + + static $lookup = array ( + 0 => 'not set', + 1 => 'Track Gain Adjustment', + 2 => 'Album Gain Adjustment' + ); + + return @$lookup[$name_code]; + } + + + + public static function OriginatorLookup($originator_code) { + + static $lookup = array ( + 0 => 'unspecified', + 1 => 'pre-set by artist/producer/mastering engineer', + 2 => 'set by user', + 3 => 'determined automatically' + ); + + return @$lookup[$originator_code]; + } + + + + public static function AdjustmentLookup($raw_adjustment, $sign_bit) { + + return (float)$raw_adjustment / 10 * ($sign_bit == 1 ? -1 : 1); + } + + + + public static function GainString($name_code, $originator_code, $replaygain) { + + $sign_bit = $replaygain < 0 ? 1 : 0; + + $stored_replaygain = intval(round($replaygain * 10)); + $gain_string = str_pad(decbin($name_code), 3, '0', STR_PAD_LEFT); + $gain_string .= str_pad(decbin($originator_code), 3, '0', STR_PAD_LEFT); + $gain_string .= $sign_bit; + $gain_string .= str_pad(decbin($stored_replaygain), 9, '0', STR_PAD_LEFT); + + return $gain_string; + } + +} + + + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.archive.gzip.php b/plugins/getId3Plugin/lib/module.archive.gzip.php new file mode 100644 index 0000000..93c1d84 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.archive.gzip.php @@ -0,0 +1,296 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.archive.gzip.php | +// | module for analyzing GZIP files | +// | dependencies: PHP compiled with zlib support (optional) | +// +----------------------------------------------------------------------+ +// | Module written by Mike Mozolin | +// +----------------------------------------------------------------------+ +// +// $Id: module.archive.gzip.php,v 1.1 2006/06/13 08:44:50 ah Exp $ + + + +class getid3_gzip extends getid3_handler +{ + + // public: Optional file list - disable for speed. + public $option_gzip_parse_contents = true; // decode gzipped files, if possible, and parse recursively (.tar.gz for example) + + + // Reads the gzip-file + function Analyze() { + + $info = &$this->getid3->info; + + $info['fileformat'] = 'gzip'; + + $start_length = 10; + $unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os'; + + //+---+---+---+---+---+---+---+---+---+---+ + //|ID1|ID2|CM |FLG| MTIME |XFL|OS | + //+---+---+---+---+---+---+---+---+---+---+ + + @fseek($this->getid3->fp, 0); + $buffer = @fread($this->getid3->fp, $info['filesize']); + + $arr_members = explode("\x1F\x8B\x08", $buffer); + + while (true) { + $is_wrong_members = false; + $num_members = intval(count($arr_members)); + for ($i = 0; $i < $num_members; $i++) { + if (strlen($arr_members[$i]) == 0) { + continue; + } + $buf = "\x1F\x8B\x08".$arr_members[$i]; + + $attr = unpack($unpack_header, substr($buf, 0, $start_length)); + if (!$this->get_os_type(ord($attr['os']))) { + + // Merge member with previous if wrong OS type + $arr_members[$i - 1] .= $buf; + $arr_members[$i] = ''; + $is_wrong_members = true; + continue; + } + } + if (!$is_wrong_members) { + break; + } + } + + $fpointer = 0; + $idx = 0; + for ($i = 0; $i < $num_members; $i++) { + if (strlen($arr_members[$i]) == 0) { + continue; + } + $info_gzip_member_header_idx = &$info['gzip']['member_header'][++$idx]; + + $buff = "\x1F\x8B\x08".$arr_members[$i]; + + $attr = unpack($unpack_header, substr($buff, 0, $start_length)); + $info_gzip_member_header_idx['filemtime'] = getid3_lib::LittleEndian2Int($attr['mtime']); + $info_gzip_member_header_idx['raw']['id1'] = ord($attr['cmethod']); + $info_gzip_member_header_idx['raw']['id2'] = ord($attr['cmethod']); + $info_gzip_member_header_idx['raw']['cmethod'] = ord($attr['cmethod']); + $info_gzip_member_header_idx['raw']['os'] = ord($attr['os']); + $info_gzip_member_header_idx['raw']['xflags'] = ord($attr['xflags']); + $info_gzip_member_header_idx['raw']['flags'] = ord($attr['flags']); + + $info_gzip_member_header_idx['flags']['crc16'] = (bool) ($info_gzip_member_header_idx['raw']['flags'] & 0x02); + $info_gzip_member_header_idx['flags']['extra'] = (bool) ($info_gzip_member_header_idx['raw']['flags'] & 0x04); + $info_gzip_member_header_idx['flags']['filename'] = (bool) ($info_gzip_member_header_idx['raw']['flags'] & 0x08); + $info_gzip_member_header_idx['flags']['comment'] = (bool) ($info_gzip_member_header_idx['raw']['flags'] & 0x10); + + $info_gzip_member_header_idx['compression'] = $this->get_xflag_type($info_gzip_member_header_idx['raw']['xflags']); + + $info_gzip_member_header_idx['os'] = $this->get_os_type($info_gzip_member_header_idx['raw']['os']); + if (!$info_gzip_member_header_idx['os']) { + $info['error'][] = 'Read error on gzip file'; + return false; + } + + $fpointer = 10; + $arr_xsubfield = array (); + + // bit 2 - FLG.FEXTRA + //+---+---+=================================+ + //| XLEN |...XLEN bytes of "extra field"...| + //+---+---+=================================+ + + if ($info_gzip_member_header_idx['flags']['extra']) { + $w_xlen = substr($buff, $fpointer, 2); + $xlen = getid3_lib::LittleEndian2Int($w_xlen); + $fpointer += 2; + + $info_gzip_member_header_idx['raw']['xfield'] = substr($buff, $fpointer, $xlen); + + // Extra SubFields + //+---+---+---+---+==================================+ + //|SI1|SI2| LEN |... LEN bytes of subfield data ...| + //+---+---+---+---+==================================+ + + $idx = 0; + while (true) { + if ($idx >= $xlen) { + break; + } + $si1 = ord(substr($buff, $fpointer + $idx++, 1)); + $si2 = ord(substr($buff, $fpointer + $idx++, 1)); + if (($si1 == 0x41) && ($si2 == 0x70)) { + $w_xsublen = substr($buff, $fpointer+$idx, 2); + $xsublen = getid3_lib::LittleEndian2Int($w_xsublen); + $idx += 2; + $arr_xsubfield[] = substr($buff, $fpointer+$idx, $xsublen); + $idx += $xsublen; + } else { + break; + } + } + $fpointer += $xlen; + } + + // bit 3 - FLG.FNAME + //+=========================================+ + //|...original file name, zero-terminated...| + //+=========================================+ + // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz + + $info_gzip_member_header_idx['filename'] = eregi_replace('.gz$', '', @$info['filename']); + if ($info_gzip_member_header_idx['flags']['filename']) { + while (true) { + if (ord($buff[$fpointer]) == 0) { + $fpointer++; + break; + } + $info_gzip_member_header_idx['filename'] .= $buff[$fpointer]; + $fpointer++; + } + } + + // bit 4 - FLG.FCOMMENT + //+===================================+ + //|...file comment, zero-terminated...| + //+===================================+ + + if ($info_gzip_member_header_idx['flags']['comment']) { + while (true) { + if (ord($buff[$fpointer]) == 0) { + $fpointer++; + break; + } + $info_gzip_member_header_idx['comment'] .= $buff[$fpointer]; + $fpointer++; + } + } + + // bit 1 - FLG.FHCRC + //+---+---+ + //| CRC16 | + //+---+---+ + + if ($info_gzip_member_header_idx['flags']['crc16']) { + $w_crc = substr($buff, $fpointer, 2); + $info_gzip_member_header_idx['crc16'] = getid3_lib::LittleEndian2Int($w_crc); + $fpointer += 2; + } + + // bit 0 - FLG.FTEXT + //if ($info_gzip_member_header_idx['raw']['flags'] & 0x01) { + // Ignored... + //} + // bits 5, 6, 7 - reserved + + $info_gzip_member_header_idx['crc32'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4)); + $info_gzip_member_header_idx['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4)); + + if ($this->option_gzip_parse_contents) { + + // Try to inflate GZip + + if (!function_exists('gzinflate')) { + $this->getid3->warning('PHP does not have zlib support - contents not parsed.'); + return true; + } + + $csize = 0; + $inflated = ''; + $chkcrc32 = ''; + + $cdata = substr($buff, $fpointer); + $cdata = substr($cdata, 0, strlen($cdata) - 8); + $csize = strlen($cdata); + $inflated = gzinflate($cdata); + + // Calculate CRC32 for inflated content + $info_gzip_member_header_idx['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $info_gzip_member_header_idx['crc32']); + + + //// Analyse contents + + // write content to temp file + if (($temp_file_name = tempnam('*', 'getID3')) === false) { + throw new getid3_exception('Unable to create temporary file.'); + } + + if ($tmp = fopen($temp_file_name, 'wb')) { + fwrite($tmp, $inflated); + fclose($tmp); + + // clone getid3 - we want same settings + $clone = clone $this->getid3; + unset($clone->info); + try { + $clone->Analyze($temp_file_name); + $info_gzip_member_header_idx['parsed_content'] = $clone->info; + } + catch (getid3_exception $e) { + // unable to parse contents + } + + unlink($temp_file_name); + } + + // Unknown/unhandled format + else { + + } + } + } + return true; + } + + + // Converts the OS type + public static function get_os_type($key) { + static $os_type = array ( + '0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)', + '1' => 'Amiga', + '2' => 'VMS (or OpenVMS)', + '3' => 'Unix', + '4' => 'VM/CMS', + '5' => 'Atari TOS', + '6' => 'HPFS filesystem (OS/2, NT)', + '7' => 'Macintosh', + '8' => 'Z-System', + '9' => 'CP/M', + '10' => 'TOPS-20', + '11' => 'NTFS filesystem (NT)', + '12' => 'QDOS', + '13' => 'Acorn RISCOS', + '255' => 'unknown' + ); + return @$os_type[$key]; + } + + + // Converts the eXtra FLags + public static function get_xflag_type($key) { + static $xflag_type = array ( + '0' => 'unknown', + '2' => 'maximum compression', + '4' => 'fastest algorithm' + ); + return @$xflag_type[$key]; + } + +} + +?> diff --git a/plugins/getId3Plugin/lib/module.archive.rar.php b/plugins/getId3Plugin/lib/module.archive.rar.php new file mode 100644 index 0000000..f006ce4 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.archive.rar.php @@ -0,0 +1,32 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.rar.php // +// module for analyzing RAR files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_rar +{ + + function getid3_rar(&$fd, &$ThisFileInfo) { + + $ThisFileInfo['fileformat'] = 'rar'; + + $ThisFileInfo['error'][] = 'RAR parsing not enabled in this version of getID3()'; + return false; + + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.archive.szip.php b/plugins/getId3Plugin/lib/module.archive.szip.php new file mode 100644 index 0000000..1d96f1c --- /dev/null +++ b/plugins/getId3Plugin/lib/module.archive.szip.php @@ -0,0 +1,105 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.archive.szip.php | +// | module for analyzing SZIP compressed files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.archive.szip.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_szip extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $szip_rkau = fread($getid3->fp, 6); + + // Magic bytes: 'SZ'."\x0A\x04" + + $getid3->info['fileformat'] = 'szip'; + + $getid3->info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($szip_rkau, 4, 1)); + $getid3->info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($szip_rkau, 5, 1)); + + while (!feof($getid3->fp)) { + $next_block_id = fread($getid3->fp, 2); + switch ($next_block_id) { + case 'SZ': + // Note that szip files can be concatenated, this has the same effect as + // concatenating the files. this also means that global header blocks + // might be present between directory/data blocks. + fseek($getid3->fp, 4, SEEK_CUR); + break; + + case 'BH': + $bh_header_bytes = getid3_lib::BigEndian2Int(fread($getid3->fp, 3)); + $bh_header_data = fread($getid3->fp, $bh_header_bytes); + $bh_header_offset = 0; + while (strpos($bh_header_data, "\x00", $bh_header_offset) > 0) { + //filename as \0 terminated string (empty string indicates end) + //owner as \0 terminated string (empty is same as last file) + //group as \0 terminated string (empty is same as last file) + //3 byte filelength in this block + //2 byte access flags + //4 byte creation time (like in unix) + //4 byte modification time (like in unix) + //4 byte access time (like in unix) + + $bh_data_array['filename'] = substr($bh_header_data, $bh_header_offset, strcspn($bh_header_data, "\x00")); + $bh_header_offset += (strlen($bh_data_array['filename']) + 1); + + $bh_data_array['owner'] = substr($bh_header_data, $bh_header_offset, strcspn($bh_header_data, "\x00")); + $bh_header_offset += (strlen($bh_data_array['owner']) + 1); + + $bh_data_array['group'] = substr($bh_header_data, $bh_header_offset, strcspn($bh_header_data, "\x00")); + $bh_header_offset += (strlen($bh_data_array['group']) + 1); + + $bh_data_array['filelength'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 3)); + $bh_header_offset += 3; + + $bh_data_array['access_flags'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 2)); + $bh_header_offset += 2; + + $bh_data_array['creation_time'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 4)); + $bh_header_offset += 4; + + $bh_data_array['modification_time'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 4)); + $bh_header_offset += 4; + + $bh_data_array['access_time'] = getid3_lib::BigEndian2Int(substr($bh_header_data, $bh_header_offset, 4)); + $bh_header_offset += 4; + + $getid3->info['szip']['BH'][] = $bh_data_array; + } + break; + + default: + break 2; + } + } + + return true; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.archive.tar.php b/plugins/getId3Plugin/lib/module.archive.tar.php new file mode 100644 index 0000000..219830d --- /dev/null +++ b/plugins/getId3Plugin/lib/module.archive.tar.php @@ -0,0 +1,231 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.archive.tar.php | +// | module for analyzing TAR files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// | Module originally written by Mike Mozolin | +// +----------------------------------------------------------------------+ +// +// $Id: module.archive.tar.php,v 1.1 2006/06/13 08:44:50 ah Exp $ + + + +class getid3_tar extends getid3_handler +{ + + function Analyze() { + + $info = &$this->getid3->info; + + $info['fileformat'] = 'tar'; + + $fp = $this->getid3->fp; + + fseek($fp, 0); + + $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155/prefix'; + + $null_512k = str_repeat("\0", 512); // end-of-file marker + + $already_warned = false; + + while (!feof($fp)) { + + $buffer = fread($fp, 512); + + // check the block + $checksum = 0; + for ($i = 0; $i < 148; $i++) { + $checksum += ord(substr($buffer, $i, 1)); + } + for ($i = 148; $i < 156; $i++) { + $checksum += ord(' '); + } + for ($i = 156; $i < 512; $i++) { + $checksum += ord(substr($buffer, $i, 1)); + } + $attr = unpack($unpack_header, $buffer); + $name = trim(@$attr['fname']); + $mode = octdec(trim(@$attr['mode'])); + $uid = octdec(trim(@$attr['uid'])); + $gid = octdec(trim(@$attr['gid'])); + $size = octdec(trim(@$attr['size'])); + $mtime = octdec(trim(@$attr['mtime'])); + $chksum = octdec(trim(@$attr['chksum'])); + $typflag = trim(@$attr['typflag']); + $lnkname = trim(@$attr['lnkname']); + $magic = trim(@$attr['magic']); + $ver = trim(@$attr['ver']); + $uname = trim(@$attr['uname']); + $gname = trim(@$attr['gname']); + $devmaj = octdec(trim(@$attr['devmaj'])); + $devmin = octdec(trim(@$attr['devmin'])); + $prefix = trim(@$attr['prefix']); + + // EOF Found + if (($checksum == 256) && ($chksum == 0)) { + break; + } + + // Check if filename if 7bit as spec requires + if (!$already_warned) { + for ($i = 0; $i < strlen($name); $i++) { + if ($name{$i} < chr(32) || $name{$i} > chr(127)) { + $this->getid3->warning('Some filenames contains extended characters, which breaks the tar specifation. This is not uncommon, but you will have to handle the character encoding for filenames yourself.'); + $already_warned = true; + break; + } + } + } + + if ($prefix) { + $name = $prefix.'/'.$name; + } + if ((preg_match('#/$#', $name)) && !$name) { + $typeflag = 5; + } + + // If it's the end of the tar-file... + if ($buffer == $null_512k) { + break; + } + + // Protect against tar-files with garbage at the end + if ($name == '') { + break; + } + + $info['tar']['file_details'][$name] = array ( + 'name' => $name, + 'mode_raw' => $mode, + 'mode' => getid3_tar::display_perms($mode), + 'uid' => $uid, + 'gid' => $gid, + 'size' => $size, + 'mtime' => $mtime, + 'chksum' => $chksum, + 'typeflag' => getid3_tar::get_flag_type($typflag), + 'linkname' => $lnkname, + 'magic' => $magic, + 'version' => $ver, + 'uname' => $uname, + 'gname' => $gname, + 'devmajor' => $devmaj, + 'devminor' => $devmin + ); + + // Skip the next chunk + fseek($fp, $size, SEEK_CUR); + + // Throw away padding + if ($size % 512) { + fseek($fp, 512 - $diff, SEEK_CUR); + } + + } + return true; + } + + + // Parses the file mode to file permissions + public static function display_perms($mode) { + + // Determine Type + if ($mode & 0x1000) { + $type='p'; // FIFO pipe + } + elseif ($mode & 0x2000) { + $type='c'; // Character special + } + elseif ($mode & 0x4000) { + $type='d'; // Directory + } + elseif ($mode & 0x6000) { + $type='b'; // Block special + } + elseif ($mode & 0x8000) { + $type='-'; // Regular + } + elseif ($mode & 0xA000) { + $type='l'; // Symbolic Link + } + elseif ($mode & 0xC000) { + $type='s'; // Socket + } + else { + $type='u'; // UNKNOWN + } + + // Determine permissions + $owner['read'] = (($mode & 00400) ? 'r' : '-'); + $owner['write'] = (($mode & 00200) ? 'w' : '-'); + $owner['execute'] = (($mode & 00100) ? 'x' : '-'); + $group['read'] = (($mode & 00040) ? 'r' : '-'); + $group['write'] = (($mode & 00020) ? 'w' : '-'); + $group['execute'] = (($mode & 00010) ? 'x' : '-'); + $world['read'] = (($mode & 00004) ? 'r' : '-'); + $world['write'] = (($mode & 00002) ? 'w' : '-'); + $world['execute'] = (($mode & 00001) ? 'x' : '-'); + + // Adjust for SUID, SGID and sticky bit + if ($mode & 0x800) { + $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S'; + } + if ($mode & 0x400) { + $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S'; + } + if ($mode & 0x200) { + $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T'; + } + + $s = sprintf('%1s', $type); + $s .= sprintf('%1s%1s%1s', $owner['read'], $owner['write'], $owner['execute']); + $s .= sprintf('%1s%1s%1s', $group['read'], $group['write'], $group['execute']); + $s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']); + + return $s; + } + + + // Converts the file type + public static function get_flag_type($typflag) { + + static $flag_types = array ( + '0' => 'LF_NORMAL', + '1' => 'LF_LINK', + '2' => 'LF_SYNLINK', + '3' => 'LF_CHR', + '4' => 'LF_BLK', + '5' => 'LF_DIR', + '6' => 'LF_FIFO', + '7' => 'LF_CONFIG', + 'D' => 'LF_DUMPDIR', + 'K' => 'LF_LONGLINK', + 'L' => 'LF_LONGNAME', + 'M' => 'LF_MULTIVOL', + 'N' => 'LF_NAMES', + 'S' => 'LF_SPARSE', + 'V' => 'LF_VOLHDR' + ); + + return @$flag_types[$typflag]; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.archive.zip.php b/plugins/getId3Plugin/lib/module.archive.zip.php new file mode 100644 index 0000000..61c061c --- /dev/null +++ b/plugins/getId3Plugin/lib/module.archive.zip.php @@ -0,0 +1,510 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.archive.zip.php | +// | Module for analyzing pkZip files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.archive.zip.php,v 1.3 2006/06/24 22:58:30 ah Exp $ + + + +class getid3_zip extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['zip'] = array (); + $info_zip = &$getid3->info['zip']; + + $getid3->info['fileformat'] = 'zip'; + + $info_zip['encoding'] = 'ISO-8859-1'; + $info_zip['files'] = array (); + $info_zip['compressed_size'] = $info_zip['uncompressed_size'] = $info_zip['entries_count'] = 0; + + $eocd_search_data = ''; + $eocd_search_counter = 0; + while ($eocd_search_counter++ < 512) { + + fseek($getid3->fp, -128 * $eocd_search_counter, SEEK_END); + $eocd_search_data = fread($getid3->fp, 128).$eocd_search_data; + + if (strstr($eocd_search_data, 'PK'."\x05\x06")) { + + $eocd_position = strpos($eocd_search_data, 'PK'."\x05\x06"); + fseek($getid3->fp, (-128 * $eocd_search_counter) + $eocd_position, SEEK_END); + $info_zip['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory(); + + fseek($getid3->fp, $info_zip['end_central_directory']['directory_offset'], SEEK_SET); + $info_zip['entries_count'] = 0; + while ($central_directoryentry = $this->ZIPparseCentralDirectory($getid3->fp)) { + $info_zip['central_directory'][] = $central_directoryentry; + $info_zip['entries_count']++; + $info_zip['compressed_size'] += $central_directoryentry['compressed_size']; + $info_zip['uncompressed_size'] += $central_directoryentry['uncompressed_size']; + + if ($central_directoryentry['uncompressed_size'] > 0) { + $info_zip['files'] = getid3_zip::array_merge_clobber($info_zip['files'], getid3_zip::CreateDeepArray($central_directoryentry['filename'], '/', $central_directoryentry['uncompressed_size'])); + } + } + + if ($info_zip['entries_count'] == 0) { + throw new getid3_exception('No Central Directory entries found (truncated file?)'); + } + + if (!empty($info_zip['end_central_directory']['comment'])) { + $info_zip['comments']['comment'][] = $info_zip['end_central_directory']['comment']; + } + + if (isset($info_zip['central_directory'][0]['compression_method'])) { + $info_zip['compression_method'] = $info_zip['central_directory'][0]['compression_method']; + } + if (isset($info_zip['central_directory'][0]['flags']['compression_speed'])) { + $info_zip['compression_speed'] = $info_zip['central_directory'][0]['flags']['compression_speed']; + } + if (isset($info_zip['compression_method']) && ($info_zip['compression_method'] == 'store') && !isset($info_zip['compression_speed'])) { + $info_zip['compression_speed'] = 'store'; + } + + return true; + } + } + + if ($this->getZIPentriesFilepointer()) { + + // central directory couldn't be found and/or parsed + // scan through actual file data entries, recover as much as possible from probable trucated file + if (@$info_zip['compressed_size'] > ($getid3->info['filesize'] - 46 - 22)) { + throw new getid3_exception('Warning: Truncated file! - Total compressed file sizes ('.$info_zip['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($getid3->info['filesize'] - 46 - 22).' bytes)'); + } + throw new getid3_exception('Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete'); + } + + //throw new getid3_exception('Cannot find End Of Central Directory (truncated file?)'); + } + + + + private function getZIPHeaderFilepointerTopDown() { + + // shortcut + $getid3 = $this->getid3; + + $getid3->info['fileformat'] = 'zip'; + + $getid3->info['zip'] = array (); + $info_zip['compressed_size'] = $info_zip['uncompressed_size'] = $info_zip['entries_count'] = 0; + + rewind($getid3->fp); + while ($fileentry = $this->ZIPparseLocalFileHeader()) { + $info_zip['entries'][] = $fileentry; + $info_zip['entries_count']++; + } + if ($info_zip['entries_count'] == 0) { + throw new getid3_exception('No Local File Header entries found'); + } + + $info_zip['entries_count'] = 0; + while ($central_directoryentry = $this->ZIPparseCentralDirectory($getid3->fp)) { + $info_zip['central_directory'][] = $central_directoryentry; + $info_zip['entries_count']++; + $info_zip['compressed_size'] += $central_directoryentry['compressed_size']; + $info_zip['uncompressed_size'] += $central_directoryentry['uncompressed_size']; + } + if ($info_zip['entries_count'] == 0) { + throw new getid3_exception('No Central Directory entries found (truncated file?)'); + } + + if ($eocd = $this->ZIPparseEndOfCentralDirectory()) { + $info_zip['end_central_directory'] = $eocd; + } else { + throw new getid3_exception('No End Of Central Directory entry found (truncated file?)'); + } + + if (!@$info_zip['end_central_directory']['comment']) { + $info_zip['comments']['comment'][] = $info_zip['end_central_directory']['comment']; + } + + return true; + } + + + + private function getZIPentriesFilepointer() { + + // shortcut + $getid3 = $this->getid3; + + $getid3->info['zip'] = array (); + $info_zip['compressed_size'] = $info_zip['uncompressed_size'] = $info_zip['entries_count'] = 0; + + rewind($getid3->fp); + while ($fileentry = $this->ZIPparseLocalFileHeader($getid3->fp)) { + $info_zip['entries'][] = $fileentry; + $info_zip['entries_count']++; + $info_zip['compressed_size'] += $fileentry['compressed_size']; + $info_zip['uncompressed_size'] += $fileentry['uncompressed_size']; + } + if ($info_zip['entries_count'] == 0) { + throw new getid3_exception('No Local File Header entries found'); + } + + return true; + } + + + + private function ZIPparseLocalFileHeader() { + + // shortcut + $getid3 = $this->getid3; + + $local_file_header['offset'] = ftell($getid3->fp); + + $zip_local_file_header = fread($getid3->fp, 30); + + $local_file_header['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($zip_local_file_header, 0, 4)); + + // Invalid Local File Header Signature + if ($local_file_header['raw']['signature'] != 0x04034B50) { + fseek($getid3->fp, $local_file_header['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly + return false; + } + + getid3_lib::ReadSequence('LittleEndian2Int', $local_file_header['raw'], $zip_local_file_header, 4, + array ( + 'extract_version' => 2, + 'general_flags' => 2, + 'compression_method' => 2, + 'last_mod_file_time' => 2, + 'last_mod_file_date' => 2, + 'crc_32' => 2, + 'compressed_size' => 2, + 'uncompressed_size' => 2, + 'filename_length' => 2, + 'extra_field_length' => 2 + ) + ); + + $local_file_header['extract_version'] = sprintf('%1.1f', $local_file_header['raw']['extract_version'] / 10); + $local_file_header['host_os'] = $this->ZIPversionOSLookup(($local_file_header['raw']['extract_version'] & 0xFF00) >> 8); + $local_file_header['compression_method'] = $this->ZIPcompressionMethodLookup($local_file_header['raw']['compression_method']); + $local_file_header['compressed_size'] = $local_file_header['raw']['compressed_size']; + $local_file_header['uncompressed_size'] = $local_file_header['raw']['uncompressed_size']; + $local_file_header['flags'] = $this->ZIPparseGeneralPurposeFlags($local_file_header['raw']['general_flags'], $local_file_header['raw']['compression_method']); + $local_file_header['last_modified_timestamp'] = $this->DOStime2UNIXtime($local_file_header['raw']['last_mod_file_date'], $local_file_header['raw']['last_mod_file_time']); + + $filename_extra_field_length = $local_file_header['raw']['filename_length'] + $local_file_header['raw']['extra_field_length']; + if ($filename_extra_field_length > 0) { + $zip_local_file_header .= fread($getid3->fp, $filename_extra_field_length); + + if ($local_file_header['raw']['filename_length'] > 0) { + $local_file_header['filename'] = substr($zip_local_file_header, 30, $local_file_header['raw']['filename_length']); + } + if ($local_file_header['raw']['extra_field_length'] > 0) { + $local_file_header['raw']['extra_field_data'] = substr($zip_local_file_header, 30 + $local_file_header['raw']['filename_length'], $local_file_header['raw']['extra_field_length']); + } + } + + $local_file_header['data_offset'] = ftell($getid3->fp); + fseek($getid3->fp, $local_file_header['raw']['compressed_size'], SEEK_CUR); + + if ($local_file_header['flags']['data_descriptor_used']) { + $data_descriptor = fread($getid3->fp, 12); + + getid3_lib::ReadSequence('LittleEndian2Int', $local_file_header['data_descriptor'], $data_descriptor, 0, + array ( + 'crc_32' => 4, + 'compressed_size' => 4, + 'uncompressed_size' => 4 + ) + ); + } + + return $local_file_header; + } + + + + private function ZIPparseCentralDirectory() { + + // shortcut + $getid3 = $this->getid3; + + $central_directory['offset'] = ftell($getid3->fp); + + $zip_central_directory = fread($getid3->fp, 46); + + $central_directory['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($zip_central_directory, 0, 4)); + + // invalid Central Directory Signature + if ($central_directory['raw']['signature'] != 0x02014B50) { + fseek($getid3->fp, $central_directory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly + return false; + } + + getid3_lib::ReadSequence('LittleEndian2Int', $central_directory['raw'], $zip_central_directory, 4, + array ( + 'create_version' => 2, + 'extract_version' => 2, + 'general_flags' => 2, + 'compression_method' => 2, + 'last_mod_file_time' => 2, + 'last_mod_file_date' => 2, + 'crc_32' => 4, + 'compressed_size' => 4, + 'uncompressed_size' => 4, + 'filename_length' => 2, + 'extra_field_length' => 2, + 'file_comment_length' => 2, + 'disk_number_start' => 2, + 'internal_file_attrib' => 2, + 'external_file_attrib' => 4, + 'local_header_offset' => 4 + ) + ); + + $central_directory['entry_offset'] = $central_directory['raw']['local_header_offset']; + $central_directory['create_version'] = sprintf('%1.1f', $central_directory['raw']['create_version'] / 10); + $central_directory['extract_version'] = sprintf('%1.1f', $central_directory['raw']['extract_version'] / 10); + $central_directory['host_os'] = $this->ZIPversionOSLookup(($central_directory['raw']['extract_version'] & 0xFF00) >> 8); + $central_directory['compression_method'] = $this->ZIPcompressionMethodLookup($central_directory['raw']['compression_method']); + $central_directory['compressed_size'] = $central_directory['raw']['compressed_size']; + $central_directory['uncompressed_size'] = $central_directory['raw']['uncompressed_size']; + $central_directory['flags'] = $this->ZIPparseGeneralPurposeFlags($central_directory['raw']['general_flags'], $central_directory['raw']['compression_method']); + $central_directory['last_modified_timestamp'] = $this->DOStime2UNIXtime($central_directory['raw']['last_mod_file_date'], $central_directory['raw']['last_mod_file_time']); + + $filename_extra_field_comment_length = $central_directory['raw']['filename_length'] + $central_directory['raw']['extra_field_length'] + $central_directory['raw']['file_comment_length']; + if ($filename_extra_field_comment_length > 0) { + $filename_extra_field_comment = fread($getid3->fp, $filename_extra_field_comment_length); + + if ($central_directory['raw']['filename_length'] > 0) { + $central_directory['filename']= substr($filename_extra_field_comment, 0, $central_directory['raw']['filename_length']); + } + if ($central_directory['raw']['extra_field_length'] > 0) { + $central_directory['raw']['extra_field_data'] = substr($filename_extra_field_comment, $central_directory['raw']['filename_length'], $central_directory['raw']['extra_field_length']); + } + if ($central_directory['raw']['file_comment_length'] > 0) { + $central_directory['file_comment'] = substr($filename_extra_field_comment, $central_directory['raw']['filename_length'] + $central_directory['raw']['extra_field_length'], $central_directory['raw']['file_comment_length']); + } + } + + return $central_directory; + } + + + + private function ZIPparseEndOfCentralDirectory() { + + // shortcut + $getid3 = $this->getid3; + + $end_of_central_directory['offset'] = ftell($getid3->fp); + + $zip_end_of_central_directory = fread($getid3->fp, 22); + + $end_of_central_directory['signature'] = getid3_lib::LittleEndian2Int(substr($zip_end_of_central_directory, 0, 4)); + + // invalid End Of Central Directory Signature + if ($end_of_central_directory['signature'] != 0x06054B50) { + fseek($getid3->fp, $end_of_central_directory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly + return false; + } + + getid3_lib::ReadSequence('LittleEndian2Int', $end_of_central_directory, $zip_end_of_central_directory, 4, + array ( + 'disk_number_current' => 2, + 'disk_number_start_directory' => 2, + 'directory_entries_this_disk' => 2, + 'directory_entries_total' => 2, + 'directory_size' => 4, + 'directory_offset' => 4, + 'comment_length' => 2 + ) + ); + + if ($end_of_central_directory['comment_length'] > 0) { + $end_of_central_directory['comment'] = fread($getid3->fp, $end_of_central_directory['comment_length']); + } + + return $end_of_central_directory; + } + + + + public static function ZIPparseGeneralPurposeFlags($flag_bytes, $compression_method) { + + $parsed_flags['encrypted'] = (bool)($flag_bytes & 0x0001); + + switch ($compression_method) { + case 6: + $parsed_flags['dictionary_size'] = (($flag_bytes & 0x0002) ? 8192 : 4096); + $parsed_flags['shannon_fano_trees'] = (($flag_bytes & 0x0004) ? 3 : 2); + break; + + case 8: + case 9: + switch (($flag_bytes & 0x0006) >> 1) { + case 0: + $parsed_flags['compression_speed'] = 'normal'; + break; + case 1: + $parsed_flags['compression_speed'] = 'maximum'; + break; + case 2: + $parsed_flags['compression_speed'] = 'fast'; + break; + case 3: + $parsed_flags['compression_speed'] = 'superfast'; + break; + } + break; + } + $parsed_flags['data_descriptor_used'] = (bool)($flag_bytes & 0x0008); + + return $parsed_flags; + } + + + + public static function ZIPversionOSLookup($index) { + + static $lookup = array ( + 0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)', + 1 => 'Amiga', + 2 => 'OpenVMS', + 3 => 'Unix', + 4 => 'VM/CMS', + 5 => 'Atari ST', + 6 => 'OS/2 H.P.F.S.', + 7 => 'Macintosh', + 8 => 'Z-System', + 9 => 'CP/M', + 10 => 'Windows NTFS', + 11 => 'MVS', + 12 => 'VSE', + 13 => 'Acorn Risc', + 14 => 'VFAT', + 15 => 'Alternate MVS', + 16 => 'BeOS', + 17 => 'Tandem' + ); + return (isset($lookup[$index]) ? $lookup[$index] : '[unknown]'); + } + + + + public static function ZIPcompressionMethodLookup($index) { + + static $lookup = array ( + 0 => 'store', + 1 => 'shrink', + 2 => 'reduce-1', + 3 => 'reduce-2', + 4 => 'reduce-3', + 5 => 'reduce-4', + 6 => 'implode', + 7 => 'tokenize', + 8 => 'deflate', + 9 => 'deflate64', + 10 => 'PKWARE Date Compression Library Imploding' + ); + return (isset($lookup[$index]) ? $lookup[$index] : '[unknown]'); + } + + + + public static function DOStime2UNIXtime($DOSdate, $DOStime) { + + /* + // wFatDate + // Specifies the MS-DOS date. The date is a packed 16-bit value with the following format: + // Bits Contents + // 0-4 Day of the month (1-31) + // 5-8 Month (1 = January, 2 = February, and so on) + // 9-15 Year offset from 1980 (add 1980 to get actual year) + + $UNIXday = ($DOSdate & 0x001F); + $UNIXmonth = (($DOSdate & 0x01E0) >> 5); + $UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980; + + // wFatTime + // Specifies the MS-DOS time. The time is a packed 16-bit value with the following format: + // Bits Contents + // 0-4 Second divided by 2 + // 5-10 Minute (0-59) + // 11-15 Hour (0-23 on a 24-hour clock) + + $UNIXsecond = ($DOStime & 0x001F) * 2; + $UNIXminute = (($DOStime & 0x07E0) >> 5); + $UNIXhour = (($DOStime & 0xF800) >> 11); + + return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); + */ + return gmmktime(($DOStime & 0xF800) >> 11, ($DOStime & 0x07E0) >> 5, ($DOStime & 0x001F) * 2, ($DOSdate & 0x01E0) >> 5, $DOSdate & 0x001F, (($DOSdate & 0xFE00) >> 9) + 1980); + } + + + + public static function array_merge_clobber($array1, $array2) { + + // written by kchireability*com + // taken from http://www.php.net/manual/en/function.array-merge-recursive.php + + if (!is_array($array1) || !is_array($array2)) { + return false; + } + + $newarray = $array1; + foreach ($array2 as $key => $val) { + if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { + $newarray[$key] = getid3_zip::array_merge_clobber($newarray[$key], $val); + } else { + $newarray[$key] = $val; + } + } + return $newarray; + } + + + + public static function CreateDeepArray($array_path, $separator, $value) { + + // assigns $value to a nested array path: + // $foo = getid3_lib::CreateDeepArray('/path/to/my', '/', 'file.txt') + // is the same as: + // $foo = array ('path'=>array('to'=>'array('my'=>array('file.txt')))); + // or + // $foo['path']['to']['my'] = 'file.txt'; + + while ($array_path{0} == $separator) { + $array_path = substr($array_path, 1); + } + if (($pos = strpos($array_path, $separator)) !== false) { + return array (substr($array_path, 0, $pos) => getid3_zip::CreateDeepArray(substr($array_path, $pos + 1), $separator, $value)); + } + + return array ($array_path => $value); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.asf.php b/plugins/getId3Plugin/lib/module.audio-video.asf.php new file mode 100644 index 0000000..fb67d1b --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.asf.php @@ -0,0 +1,1839 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio-video.php | +// | Module for analyzing Microsoft ASF, WMA and WMV files. | +// | dependencies: module.audio-video.riff.php | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio-video.asf.php,v 1.4 2006/06/13 08:44:50 ah Exp $ + + + +class getid3_asf extends getid3_handler +{ + + const Extended_Stream_Properties_Object = '14E6A5CB-C672-4332-8399-A96952065B5A'; + const Padding_Object = '1806D474-CADF-4509-A4BA-9AABCB96AAE8'; + const Payload_Ext_Syst_Pixel_Aspect_Ratio = '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8'; + const Script_Command_Object = '1EFB1A30-0B62-11D0-A39B-00A0C90348F6'; + const No_Error_Correction = '20FB5700-5B55-11CF-A8FD-00805F5C442B'; + const Content_Branding_Object = '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E'; + const Content_Encryption_Object = '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E'; + const Digital_Signature_Object = '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E'; + const Extended_Content_Encryption_Object = '298AE614-2622-4C17-B935-DAE07EE9289C'; + const Simple_Index_Object = '33000890-E5B1-11CF-89F4-00A0C90349CB'; + const Degradable_JPEG_Media = '35907DE0-E415-11CF-A917-00805F5C442B'; + const Payload_Extension_System_Timecode = '399595EC-8667-4E2D-8FDB-98814CE76C1E'; + const Binary_Media = '3AFB65E2-47EF-40F2-AC2C-70A90D71D343'; + const Timecode_Index_Object = '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C'; + const Metadata_Library_Object = '44231C94-9498-49D1-A141-1D134E457054'; + const Reserved_3 = '4B1ACBE3-100B-11D0-A39B-00A0C90348F6'; + const Reserved_4 = '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB'; + const Command_Media = '59DACFC0-59E6-11D0-A3AC-00A0C90348F6'; + const Header_Extension_Object = '5FBF03B5-A92E-11CF-8EE3-00C00C205365'; + const Media_Object_Index_Parameters_Obj = '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7'; + const Header_Object = '75B22630-668E-11CF-A6D9-00AA0062CE6C'; + const Content_Description_Object = '75B22633-668E-11CF-A6D9-00AA0062CE6C'; + const Error_Correction_Object = '75B22635-668E-11CF-A6D9-00AA0062CE6C'; + const Data_Object = '75B22636-668E-11CF-A6D9-00AA0062CE6C'; + const Web_Stream_Media_Subtype = '776257D4-C627-41CB-8F81-7AC7FF1C40CC'; + const Stream_Bitrate_Properties_Object = '7BF875CE-468D-11D1-8D82-006097C9A2B2'; + const Language_List_Object = '7C4346A9-EFE0-4BFC-B229-393EDE415C85'; + const Codec_List_Object = '86D15240-311D-11D0-A3A4-00A0C90348F6'; + const Reserved_2 = '86D15241-311D-11D0-A3A4-00A0C90348F6'; + const File_Properties_Object = '8CABDCA1-A947-11CF-8EE4-00C00C205365'; + const File_Transfer_Media = '91BD222C-F21C-497A-8B6D-5AA86BFC0185'; + const Old_RTP_Extension_Data = '96800C63-4C94-11D1-837B-0080C7A37F95'; + const Advanced_Mutual_Exclusion_Object = 'A08649CF-4775-4670-8A16-6E35357566CD'; + const Bandwidth_Sharing_Object = 'A69609E6-517B-11D2-B6AF-00C04FD908E9'; + const Reserved_1 = 'ABD3D211-A9BA-11CF-8EE6-00C00C205365'; + const Bandwidth_Sharing_Exclusive = 'AF6060AA-5197-11D2-B6AF-00C04FD908E9'; + const Bandwidth_Sharing_Partial = 'AF6060AB-5197-11D2-B6AF-00C04FD908E9'; + const JFIF_Media = 'B61BE100-5B4E-11CF-A8FD-00805F5C442B'; + const Stream_Properties_Object = 'B7DC0791-A9B7-11CF-8EE6-00C00C205365'; + const Video_Media = 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B'; + const Audio_Spread = 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220'; + const Metadata_Object = 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA'; + const Payload_Ext_Syst_Sample_Duration = 'C6BD9450-867F-4907-83A3-C77921B733AD'; + const Group_Mutual_Exclusion_Object = 'D1465A40-5A79-4338-B71B-E36B8FD6C249'; + const Extended_Content_Description_Object = 'D2D0A440-E307-11D2-97F0-00A0C95EA850'; + const Stream_Prioritization_Object = 'D4FED15B-88D3-454F-81F0-ED5C45999E24'; + const Payload_Ext_System_Content_Type = 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC'; + const Old_File_Properties_Object = 'D6E229D0-35DA-11D1-9034-00A0C90349BE'; + const Old_ASF_Header_Object = 'D6E229D1-35DA-11D1-9034-00A0C90349BE'; + const Old_ASF_Data_Object = 'D6E229D2-35DA-11D1-9034-00A0C90349BE'; + const Index_Object = 'D6E229D3-35DA-11D1-9034-00A0C90349BE'; + const Old_Stream_Properties_Object = 'D6E229D4-35DA-11D1-9034-00A0C90349BE'; + const Old_Content_Description_Object = 'D6E229D5-35DA-11D1-9034-00A0C90349BE'; + const Old_Script_Command_Object = 'D6E229D6-35DA-11D1-9034-00A0C90349BE'; + const Old_Marker_Object = 'D6E229D7-35DA-11D1-9034-00A0C90349BE'; + const Old_Component_Download_Object = 'D6E229D8-35DA-11D1-9034-00A0C90349BE'; + const Old_Stream_Group_Object = 'D6E229D9-35DA-11D1-9034-00A0C90349BE'; + const Old_Scalable_Object = 'D6E229DA-35DA-11D1-9034-00A0C90349BE'; + const Old_Prioritization_Object = 'D6E229DB-35DA-11D1-9034-00A0C90349BE'; + const Bitrate_Mutual_Exclusion_Object = 'D6E229DC-35DA-11D1-9034-00A0C90349BE'; + const Old_Inter_Media_Dependency_Object = 'D6E229DD-35DA-11D1-9034-00A0C90349BE'; + const Old_Rating_Object = 'D6E229DE-35DA-11D1-9034-00A0C90349BE'; + const Index_Parameters_Object = 'D6E229DF-35DA-11D1-9034-00A0C90349BE'; + const Old_Color_Table_Object = 'D6E229E0-35DA-11D1-9034-00A0C90349BE'; + const Old_Language_List_Object = 'D6E229E1-35DA-11D1-9034-00A0C90349BE'; + const Old_Audio_Media = 'D6E229E2-35DA-11D1-9034-00A0C90349BE'; + const Old_Video_Media = 'D6E229E3-35DA-11D1-9034-00A0C90349BE'; + const Old_Image_Media = 'D6E229E4-35DA-11D1-9034-00A0C90349BE'; + const Old_Timecode_Media = 'D6E229E5-35DA-11D1-9034-00A0C90349BE'; + const Old_Text_Media = 'D6E229E6-35DA-11D1-9034-00A0C90349BE'; + const Old_MIDI_Media = 'D6E229E7-35DA-11D1-9034-00A0C90349BE'; + const Old_Command_Media = 'D6E229E8-35DA-11D1-9034-00A0C90349BE'; + const Old_No_Error_Concealment = 'D6E229EA-35DA-11D1-9034-00A0C90349BE'; + const Old_Scrambled_Audio = 'D6E229EB-35DA-11D1-9034-00A0C90349BE'; + const Old_No_Color_Table = 'D6E229EC-35DA-11D1-9034-00A0C90349BE'; + const Old_SMPTE_Time = 'D6E229ED-35DA-11D1-9034-00A0C90349BE'; + const Old_ASCII_Text = 'D6E229EE-35DA-11D1-9034-00A0C90349BE'; + const Old_Unicode_Text = 'D6E229EF-35DA-11D1-9034-00A0C90349BE'; + const Old_HTML_Text = 'D6E229F0-35DA-11D1-9034-00A0C90349BE'; + const Old_URL_Command = 'D6E229F1-35DA-11D1-9034-00A0C90349BE'; + const Old_Filename_Command = 'D6E229F2-35DA-11D1-9034-00A0C90349BE'; + const Old_ACM_Codec = 'D6E229F3-35DA-11D1-9034-00A0C90349BE'; + const Old_VCM_Codec = 'D6E229F4-35DA-11D1-9034-00A0C90349BE'; + const Old_QuickTime_Codec = 'D6E229F5-35DA-11D1-9034-00A0C90349BE'; + const Old_DirectShow_Transform_Filter = 'D6E229F6-35DA-11D1-9034-00A0C90349BE'; + const Old_DirectShow_Rendering_Filter = 'D6E229F7-35DA-11D1-9034-00A0C90349BE'; + const Old_No_Enhancement = 'D6E229F8-35DA-11D1-9034-00A0C90349BE'; + const Old_Unknown_Enhancement_Type = 'D6E229F9-35DA-11D1-9034-00A0C90349BE'; + const Old_Temporal_Enhancement = 'D6E229FA-35DA-11D1-9034-00A0C90349BE'; + const Old_Spatial_Enhancement = 'D6E229FB-35DA-11D1-9034-00A0C90349BE'; + const Old_Quality_Enhancement = 'D6E229FC-35DA-11D1-9034-00A0C90349BE'; + const Old_Number_of_Channels_Enhancement = 'D6E229FD-35DA-11D1-9034-00A0C90349BE'; + const Old_Frequency_Response_Enhancement = 'D6E229FE-35DA-11D1-9034-00A0C90349BE'; + const Old_Media_Object = 'D6E229FF-35DA-11D1-9034-00A0C90349BE'; + const Mutex_Language = 'D6E22A00-35DA-11D1-9034-00A0C90349BE'; + const Mutex_Bitrate = 'D6E22A01-35DA-11D1-9034-00A0C90349BE'; + const Mutex_Unknown = 'D6E22A02-35DA-11D1-9034-00A0C90349BE'; + const Old_ASF_Placeholder_Object = 'D6E22A0E-35DA-11D1-9034-00A0C90349BE'; + const Old_Data_Unit_Extension_Object = 'D6E22A0F-35DA-11D1-9034-00A0C90349BE'; + const Web_Stream_Format = 'DA1E6B13-8359-4050-B398-388E965BF00C'; + const Payload_Ext_System_File_Name = 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B'; + const Marker_Object = 'F487CD01-A951-11CF-8EE6-00C00C205365'; + const Timecode_Index_Parameters_Object = 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24'; + const Audio_Media = 'F8699E40-5B4D-11CF-A8FD-00805F5C442B'; + const Media_Object_Index_Object = 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C'; + const Alt_Extended_Content_Encryption_Obj = 'FF889EF1-ADEE-40DA-9E71-98704BB928CE'; + + + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->include_module('audio-video.riff'); + + !isset($getid3->info['audio']) and $getid3->info['audio'] = array (); + !isset($getid3->info['video']) and $getid3->info['video'] = array (); + $getid3->info['asf']['comments'] = $getid3->info['asf']['header_object'] = array (); + + $info_audio = &$getid3->info['audio']; + $info_video = &$getid3->info['video']; + $info_asf = &$getid3->info['asf']; + $info_asf_comments = &$info_asf['comments']; + $info_asf_header_object = &$info_asf['header_object']; + + // ASF structure: + // * Header Object [required] + // * File Properties Object [required] (global file attributes) + // * Stream Properties Object [required] (defines media stream & characteristics) + // * Header Extension Object [required] (additional functionality) + // * Content Description Object (bibliographic information) + // * Script Command Object (commands for during playback) + // * Marker Object (named jumped points within the file) + // * Data Object [required] + // * Data Packets + // * Index Object + + // Header Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for header object - getid3_asf::Header_Object + // Object Size QWORD 64 // size of header object, including 30 bytes of Header Object header + // Number of Header Objects DWORD 32 // number of objects in header object + // Reserved1 BYTE 8 // hardcoded: 0x01 + // Reserved2 BYTE 8 // hardcoded: 0x02 + + $getid3->info['fileformat'] = 'asf'; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $header_object_data = fread($getid3->fp, 30); + + $info_asf_header_object['objectid_guid'] = getid3_asf::BytestringToGUID(substr($header_object_data, 0, 16)); + + if ($info_asf_header_object['objectid_guid'] != getid3_asf::Header_Object) { + throw new getid3_exception('ASF header GUID {'.$info_asf_header_object['objectid_guid'].'} does not match expected "getid3_asf::Header_Object" GUID {'.getid3_asf::Header_Object.'}'); + } + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_header_object, $header_object_data, 16, + array ( + 'objectsize' => 8, + 'headerobjects' => 4, + 'reserved1' => 1, + 'reserved2' => 1 + ) + ); + + $asf_header_data = fread($getid3->fp, $info_asf_header_object['objectsize'] - 30); + $offset = 0; + + for ($header_objects_counter = 0; $header_objects_counter < $info_asf_header_object['headerobjects']; $header_objects_counter++) { + + $next_object_guid = substr($asf_header_data, $offset, 16); + $offset += 16; + + $next_object_size = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 8)); + $offset += 8; + + $next_object_guidtext = getid3_asf::BytestringToGUID($next_object_guid); + + switch ($next_object_guidtext) { + + case getid3_asf::File_Properties_Object: + + // File Properties Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for file properties object - getid3_asf::File_Properties_Object + // Object Size QWORD 64 // size of file properties object, including 104 bytes of File Properties Object header + // File ID GUID 128 // unique ID - identical to File ID in Data Object + // File Size QWORD 64 // entire file in bytes. Invalid if Broadcast Flag == 1 + // Creation Date QWORD 64 // date & time of file creation. Maybe invalid if Broadcast Flag == 1 + // Data Packets Count QWORD 64 // number of data packets in Data Object. Invalid if Broadcast Flag == 1 + // Play Duration QWORD 64 // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1 + // Send Duration QWORD 64 // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1 + // Preroll QWORD 64 // time to buffer data before starting to play file, in 1-millisecond units. If <> 0, PlayDuration and PresentationTime have been offset by this amount + // Flags DWORD 32 // + // * Broadcast Flag bits 1 (0x01) // file is currently being written, some header values are invalid + // * Seekable Flag bits 1 (0x02) // is file seekable + // * Reserved bits 30 (0xFFFFFFFC) // reserved - set to zero + // Minimum Data Packet Size DWORD 32 // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1 + // Maximum Data Packet Size DWORD 32 // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1 + // Maximum Bitrate DWORD 32 // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead + + $info_asf['file_properties_object'] = array (); + $info_asf_file_properties_object = &$info_asf['file_properties_object']; + + $info_asf_file_properties_object['objectid_guid'] = $next_object_guidtext; + $info_asf_file_properties_object['objectsize'] = $next_object_size; + + $info_asf_file_properties_object['fileid_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16)); + $offset += 16; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_file_properties_object, $asf_header_data, $offset, + array ( + 'filesize' => 8, + 'creation_date' => 8, + 'data_packets' => 8, + 'play_duration' => 8, + 'send_duration' => 8, + 'preroll' => 8, + 'flags_raw' => 4, + 'min_packet_size' => 4, + 'max_packet_size' => 4, + 'max_bitrate' => 4 + ) + ); + + $offset += 64 ; + + $info_asf_file_properties_object['creation_date_unix'] = getid3_asf::FiletimeToUNIXtime($info_asf_file_properties_object['creation_date']); + $info_asf_file_properties_object['flags']['broadcast'] = (bool)($info_asf_file_properties_object['flags_raw'] & 0x0001); + $info_asf_file_properties_object['flags']['seekable'] = (bool)($info_asf_file_properties_object['flags_raw'] & 0x0002); + + $getid3->info['playtime_seconds'] = ($info_asf_file_properties_object['play_duration'] / 10000000) - ($info_asf_file_properties_object['preroll'] / 1000); + $getid3->info['bitrate'] = ($info_asf_file_properties_object['filesize'] * 8) / $getid3->info['playtime_seconds']; + break; + + + case getid3_asf::Stream_Properties_Object: + + // Stream Properties Object: (mandatory, one per media stream) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for stream properties object - getid3_asf::Stream_Properties_Object + // Object Size QWORD 64 // size of stream properties object, including 78 bytes of Stream Properties Object header + // Stream Type GUID 128 // getid3_asf::Audio_Media, getid3_asf::Video_Media or getid3_asf::Command_Media + // Error Correction Type GUID 128 // getid3_asf::Audio_Spread for audio-only streams, getid3_asf::No_Error_Correction for other stream types + // Time Offset QWORD 64 // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream + // Type-Specific Data Length DWORD 32 // number of bytes for Type-Specific Data field + // Error Correction Data Length DWORD 32 // number of bytes for Error Correction Data field + // Flags WORD 16 // + // * Stream Number bits 7 (0x007F) // number of this stream. 1 <= valid <= 127 + // * Reserved bits 8 (0x7F80) // reserved - set to zero + // * Encrypted Content Flag bits 1 (0x8000) // stream contents encrypted if set + // Reserved DWORD 32 // reserved - set to zero + // Type-Specific Data BYTESTREAM variable // type-specific format data, depending on value of Stream Type + // Error Correction Data BYTESTREAM variable // error-correction-specific format data, depending on value of Error Correct Type + + // There is one getid3_asf::Stream_Properties_Object for each stream (audio, video) but the + // stream number isn't known until halfway through decoding the structure, hence it + // it is decoded to a temporary variable and then stuck in the appropriate index later + + $stream_properties_object_data['objectid_guid'] = $next_object_guidtext; + $stream_properties_object_data['objectsize'] = $next_object_size; + + getid3_lib::ReadSequence('LittleEndian2Int', $stream_properties_object_data, $asf_header_data, $offset, + array ( + 'stream_type' => -16, + 'error_correct_type' => -16, + 'time_offset' => 8, + 'type_data_length' => 4, + 'error_data_length' => 4, + 'flags_raw' => 2 + ) + ); + + $stream_properties_stream_number = $stream_properties_object_data['flags_raw'] & 0x007F; + $stream_properties_object_data['flags']['encrypted'] = (bool)($stream_properties_object_data['flags_raw'] & 0x8000); + + $stream_properties_object_data['stream_type_guid'] = getid3_asf::BytestringToGUID($stream_properties_object_data['stream_type']); + $stream_properties_object_data['error_correct_guid'] = getid3_asf::BytestringToGUID($stream_properties_object_data['error_correct_type']); + + $offset += 54; // 50 bytes + 4 bytes reserved - DWORD + + $stream_properties_object_data['type_specific_data'] = substr($asf_header_data, $offset, $stream_properties_object_data['type_data_length']); + $offset += $stream_properties_object_data['type_data_length']; + + $stream_properties_object_data['error_correct_data'] = substr($asf_header_data, $offset, $stream_properties_object_data['error_data_length']); + $offset += $stream_properties_object_data['error_data_length']; + + switch ($stream_properties_object_data['stream_type_guid']) { + + case getid3_asf::Audio_Media: + + $info_audio['dataformat'] = (@$info_audio['dataformat'] ? $info_audio['dataformat'] : 'asf'); + $info_audio['bitrate_mode'] = (@$info_audio['bitrate_mode'] ? $info_audio['bitrate_mode'] : 'cbr'); + + $audiodata = getid3_riff::RIFFparseWAVEFORMATex(substr($stream_properties_object_data['type_specific_data'], 0, 16)); + unset($audiodata['raw']); + $info_audio = getid3_riff::array_merge_noclobber($audiodata, $info_audio); + break; + + + case getid3_asf::Video_Media: + + $info_video['dataformat'] = (@$info_video['dataformat'] ? $info_video['dataformat'] : 'asf'); + $info_video['bitrate_mode'] = (@$info_video['bitrate_mode'] ? $info_video['bitrate_mode'] : 'cbr'); + break; + + + /* does nothing but eat memory + case getid3_asf::Command_Media: + default: + // do nothing + break; + */ + } + + $info_asf['stream_properties_object'][$stream_properties_stream_number] = $stream_properties_object_data; + unset($stream_properties_object_data); // clear for next stream, if any + break; + + + case getid3_asf::Header_Extension_Object: + + // Header Extension Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Header Extension object - getid3_asf::Header_Extension_Object + // Object Size QWORD 64 // size of Header Extension object, including 46 bytes of Header Extension Object header + // Reserved Field 1 GUID 128 // hardcoded: getid3_asf::Reserved_1 + // Reserved Field 2 WORD 16 // hardcoded: 0x00000006 + // Header Extension Data Size DWORD 32 // in bytes. valid: 0, or > 24. equals object size minus 46 + // Header Extension Data BYTESTREAM variable // array of zero or more extended header objects + + $info_asf['header_extension_object'] = array (); + $info_asf_header_extension_object = &$info_asf['header_extension_object']; + + $info_asf_header_extension_object['objectid_guid'] = $next_object_guidtext; + $info_asf_header_extension_object['objectsize'] = $next_object_size; + $info_asf_header_extension_object['reserved_1_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16)); + $offset += 16; + + if ($info_asf_header_extension_object['reserved_1_guid'] != getid3_asf::Reserved_1) { + $getid3->warning('header_extension_object.reserved_1 GUID ('.$info_asf_header_extension_object['reserved_1_guid'].') does not match expected "getid3_asf::Reserved_1" GUID ('.getid3_asf::Reserved_1.')'); + break; + } + + $info_asf_header_extension_object['reserved_2'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + if ($info_asf_header_extension_object['reserved_2'] != 6) { + $getid3->warning('header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($info_asf_header_extension_object['reserved_2']).') does not match expected value of "6"'); + break; + } + + $info_asf_header_extension_object['extension_data_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4)); + $offset += 4; + + $info_asf_header_extension_object['extension_data'] = substr($asf_header_data, $offset, $info_asf_header_extension_object['extension_data_size']); + $offset += $info_asf_header_extension_object['extension_data_size']; + break; + + + case getid3_asf::Codec_List_Object: + + // Codec List Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Codec List object - getid3_asf::Codec_List_Object + // Object Size QWORD 64 // size of Codec List object, including 44 bytes of Codec List Object header + // Reserved GUID 128 // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6 + // Codec Entries Count DWORD 32 // number of entries in Codec Entries array + // Codec Entries array of: variable // + // * Type WORD 16 // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec + // * Codec Name Length WORD 16 // number of Unicode characters stored in the Codec Name field + // * Codec Name WCHAR variable // array of Unicode characters - name of codec used to create the content + // * Codec Description Length WORD 16 // number of Unicode characters stored in the Codec Description field + // * Codec Description WCHAR variable // array of Unicode characters - description of format used to create the content + // * Codec Information Length WORD 16 // number of Unicode characters stored in the Codec Information field + // * Codec Information BYTESTREAM variable // opaque array of information bytes about the codec used to create the content + + $info_asf['codec_list_object'] = array (); + $info_asf_codec_list_object = &$info_asf['codec_list_object']; + + $info_asf_codec_list_object['objectid_guid'] = $next_object_guidtext; + $info_asf_codec_list_object['objectsize'] = $next_object_size; + + $info_asf_codec_list_object['reserved_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16)); + $offset += 16; + + if ($info_asf_codec_list_object['reserved_guid'] != '86D15241-311D-11D0-A3A4-00A0C90348F6') { + $getid3->warning('codec_list_object.reserved GUID {'.$info_asf_codec_list_object['reserved_guid'].'} does not match expected "getid3_asf::Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}'); + break; + } + + $info_asf_codec_list_object['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4)); + $offset += 4; + + for ($codec_entry_counter = 0; $codec_entry_counter < $info_asf_codec_list_object['codec_entries_count']; $codec_entry_counter++) { + + $info_asf_codec_list_object['codec_entries'][$codec_entry_counter] = array (); + $info_asf_codec_list_object_codecentries_current = &$info_asf_codec_list_object['codec_entries'][$codec_entry_counter]; + + $info_asf_codec_list_object_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $info_asf_codec_list_object_codecentries_current['type'] = getid3_asf::ASFCodecListObjectTypeLookup($info_asf_codec_list_object_codecentries_current['type_raw']); + + $codec_name_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + + $info_asf_codec_list_object_codecentries_current['name'] = substr($asf_header_data, $offset, $codec_name_length); + $offset += $codec_name_length; + + $codec_description_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + + $info_asf_codec_list_object_codecentries_current['description'] = substr($asf_header_data, $offset, $codec_description_length); + $offset += $codec_description_length; + + $codec_information_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $info_asf_codec_list_object_codecentries_current['information'] = substr($asf_header_data, $offset, $codec_information_length); + $offset += $codec_information_length; + + if ($info_asf_codec_list_object_codecentries_current['type_raw'] == 2) { + + // audio codec + if (strpos($info_asf_codec_list_object_codecentries_current['description'], ',') === false) { + throw new getid3_exception('[asf][codec_list_object][codec_entries]['.$codec_entry_counter.'][description] expected to contain comma-seperated list of parameters: "'.$info_asf_codec_list_object_codecentries_current['description'].'"'); + } + list($audio_codec_bitrate, $audio_codec_frequency, $audio_codec_channels) = explode(',', $this->TrimConvert($info_asf_codec_list_object_codecentries_current['description'])); + $info_audio['codec'] = $this->TrimConvert($info_asf_codec_list_object_codecentries_current['name']); + + if (!isset($info_audio['bitrate']) && strstr($audio_codec_bitrate, 'kbps')) { + $info_audio['bitrate'] = (int)(trim(str_replace('kbps', '', $audio_codec_bitrate)) * 1000); + } + + if (!isset($info_video['bitrate']) && isset($info_audio['bitrate']) && isset($info_asf['file_properties_object']['max_bitrate']) && ($info_asf_codec_list_object['codec_entries_count'] > 1)) { + $info_video['bitrate'] = $info_asf['file_properties_object']['max_bitrate'] - $info_audio['bitrate']; + } + + if (!@$info_video['bitrate'] && @$info_audio['bitrate'] && @$getid3->info['bitrate']) { + $info_video['bitrate'] = $getid3->info['bitrate'] - $info_audio['bitrate']; + } + + $audio_codec_frequency = (int)trim(str_replace('kHz', '', $audio_codec_frequency)); + + static $sample_rate_lookup = array ( + 8 => 8000, 8000 => 8000, + 11 => 11025, 11025 => 11025, + 12 => 12000, 12000 => 12000, + 16 => 16000, 16000 => 16000, + 22 => 22050, 22050 => 22050, + 24 => 24000, 24000 => 24000, + 32 => 32000, 32000 => 32000, + 44 => 44100, 44100 => 44100, + 48 => 48000, 48000 => 48000, + ); + + $info_audio['sample_rate'] = @$sample_rate_lookup[$audio_codec_frequency]; + + if (!$info_audio['sample_rate']) { + $getid3->warning('unknown frequency: "'.$audio_codec_frequency.'" ('.$this->TrimConvert($info_asf_codec_list_object_codecentries_current['description']).')'); + break; + } + + if (!isset($info_audio['channels'])) { + if (strstr($audio_codec_channels, 'stereo')) { + $info_audio['channels'] = 2; + } elseif (strstr($audio_codec_channels, 'mono')) { + $info_audio['channels'] = 1; + } + } + } + } + break; + + + case getid3_asf::Script_Command_Object: + + // Script Command Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Script Command object - getid3_asf::Script_Command_Object + // Object Size QWORD 64 // size of Script Command object, including 44 bytes of Script Command Object header + // Reserved GUID 128 // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6 + // Commands Count WORD 16 // number of Commands structures in the Script Commands Objects + // Command Types Count WORD 16 // number of Command Types structures in the Script Commands Objects + // Command Types array of: variable // + // * Command Type Name Length WORD 16 // number of Unicode characters for Command Type Name + // * Command Type Name WCHAR variable // array of Unicode characters - name of a type of command + // Commands array of: variable // + // * Presentation Time DWORD 32 // presentation time of that command, in milliseconds + // * Type Index WORD 16 // type of this command, as a zero-based index into the array of Command Types of this object + // * Command Name Length WORD 16 // number of Unicode characters for Command Name + // * Command Name WCHAR variable // array of Unicode characters - name of this command + + // shortcut + $info_asf['script_command_object'] = array (); + $info_asf_script_command_object = &$info_asf['script_command_object']; + + $info_asf_script_command_object['objectid_guid'] = $next_object_guidtext; + $info_asf_script_command_object['objectsize'] = $next_object_size; + $info_asf_script_command_object['reserved_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16)); + $offset += 16; + + if ($info_asf_script_command_object['reserved_guid'] != '4B1ACBE3-100B-11D0-A39B-00A0C90348F6') { + $getid3->warning('script_command_object.reserved GUID {'.$info_asf_script_command_object['reserved_guid'].'} does not match expected GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}'); + break; + } + + $info_asf_script_command_object['commands_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $info_asf_script_command_object['command_types_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + for ($command_types_counter = 0; $command_types_counter < $info_asf_script_command_object['command_types_count']; $command_types_counter++) { + + $command_type_name_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + + $info_asf_script_command_object['command_types'][$command_types_counter]['name'] = substr($asf_header_data, $offset, $command_type_name_length); + $offset += $command_type_name_length; + } + + for ($commands_counter = 0; $commands_counter < $info_asf_script_command_object['commands_count']; $commands_counter++) { + + $info_asf_script_command_object['commands'][$commands_counter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4)); + $offset += 4; + + $info_asf_script_command_object['commands'][$commands_counter]['type_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $command_type_name_length = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + + $info_asf_script_command_object['commands'][$commands_counter]['name'] = substr($asf_header_data, $offset, $command_type_name_length); + $offset += $command_type_name_length; + } + break; + + + case getid3_asf::Marker_Object: + + // Marker Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Marker object - getid3_asf::Marker_Object + // Object Size QWORD 64 // size of Marker object, including 48 bytes of Marker Object header + // Reserved GUID 128 // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB + // Markers Count DWORD 32 // number of Marker structures in Marker Object + // Reserved WORD 16 // hardcoded: 0x0000 + // Name Length WORD 16 // number of bytes in the Name field + // Name WCHAR variable // name of the Marker Object + // Markers array of: variable // + // * Offset QWORD 64 // byte offset into Data Object + // * Presentation Time QWORD 64 // in 100-nanosecond units + // * Entry Length WORD 16 // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding) + // * Send Time DWORD 32 // in milliseconds + // * Flags DWORD 32 // hardcoded: 0x00000000 + // * Marker Description Length DWORD 32 // number of bytes in Marker Description field + // * Marker Description WCHAR variable // array of Unicode characters - description of marker entry + // * Padding BYTESTREAM variable // optional padding bytes + + $info_asf['marker_object'] = array (); + $info_asf_marker_object = &$info_asf['marker_object']; + + $info_asf_marker_object['objectid_guid'] = $next_object_guidtext; + $info_asf_marker_object['objectsize'] = $next_object_size; + $info_asf_marker_object['reserved_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16)); + $offset += 16; + + if ($info_asf_marker_object['reserved_guid'] != '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB') { + $getid3->warning('marker_object.reserved GUID {'.$info_asf_marker_object['reserved_guid'].'} does not match expected GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}'); + break; + } + + $info_asf_marker_object['markers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4)); + $offset += 4; + + $info_asf_marker_object['reserved_2'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + if ($info_asf_marker_object['reserved_2'] != 0) { + $getid3->warning('marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($info_asf_marker_object['reserved_2']).') does not match expected value of "0"'); + break; + } + + $info_asf_marker_object['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $info_asf_marker_object['name'] = substr($asf_header_data, $offset, $info_asf_marker_object['name_length']); + $offset += $info_asf_marker_object['name_length']; + + for ($markers_counter = 0; $markers_counter < $info_asf_marker_object['markers_count']; $markers_counter++) { + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_marker_object['markers'][$markers_counter], $asf_header_data, $offset, + array ( + 'offset' => 8, + 'presentation_time' => 8, + 'entry_length' => 2, + 'send_time' => 4, + 'flags' => 4, + 'marker_description_length' => 4 + ) + ); + $offset += 30; + + $info_asf_marker_object['markers'][$markers_counter]['marker_description'] = substr($asf_header_data, $offset, $info_asf_marker_object['markers'][$markers_counter]['marker_description_length']); + $offset += $info_asf_marker_object['markers'][$markers_counter]['marker_description_length']; + + $padding_length = $info_asf_marker_object['markers'][$markers_counter]['entry_length'] - 4 - 4 - 4 - $info_asf_marker_object['markers'][$markers_counter]['marker_description_length']; + if ($padding_length > 0) { + $info_asf_marker_object['markers'][$markers_counter]['padding'] = substr($asf_header_data, $offset, $padding_length); + $offset += $padding_length; + } + } + break; + + + case getid3_asf::Bitrate_Mutual_Exclusion_Object: + + // Bitrate Mutual Exclusion Object: (optional) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Bitrate Mutual Exclusion object - getid3_asf::Bitrate_Mutual_Exclusion_Object + // Object Size QWORD 64 // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header + // Exlusion Type GUID 128 // nature of mutual exclusion relationship. one of: (getid3_asf::Mutex_Bitrate, getid3_asf::Mutex_Unknown) + // Stream Numbers Count WORD 16 // number of video streams + // Stream Numbers WORD variable // array of mutually exclusive video stream numbers. 1 <= valid <= 127 + + // shortcut + $info_asf['bitrate_mutual_exclusion_object'] = array (); + $info_asf_bitrate_mutual_exclusion_object = &$info_asf['bitrate_mutual_exclusion_object']; + + $info_asf_bitrate_mutual_exclusion_object['objectid_guid'] = $next_object_guidtext; + $info_asf_bitrate_mutual_exclusion_object['objectsize'] = $next_object_size; + $info_asf_bitrate_mutual_exclusion_object['reserved_guid'] = getid3_asf::BytestringToGUID(substr($asf_header_data, $offset, 16)); + $offset += 16; + + if ($info_asf_bitrate_mutual_exclusion_object['reserved_guid'] != getid3_asf::Mutex_Bitrate && $info_asf_bitrate_mutual_exclusion_object['reserved_guid'] != getid3_asf::Mutex_Unknown) { + $getid3->warning('bitrate_mutual_exclusion_object.reserved GUID {'.$info_asf_bitrate_mutual_exclusion_object['reserved_guid'].'} does not match expected "getid3_asf::Mutex_Bitrate" GUID {'.getid3_asf::Mutex_Bitrate.'} or "getid3_asf::Mutex_Unknown" GUID {'.getid3_asf::Mutex_Unknown.'}'); + break; + } + + $info_asf_bitrate_mutual_exclusion_object['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + for ($stream_number_counter = 0; $stream_number_counter < $info_asf_bitrate_mutual_exclusion_object['stream_numbers_count']; $stream_number_counter++) { + $info_asf_bitrate_mutual_exclusion_object['stream_numbers'][$stream_number_counter] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + } + break; + + + case getid3_asf::Error_Correction_Object: + + // Error Correction Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Error Correction object - getid3_asf::Error_Correction_Object + // Object Size QWORD 64 // size of Error Correction object, including 44 bytes of Error Correction Object header + // Error Correction Type GUID 128 // type of error correction. one of: (getid3_asf::No_Error_Correction, getid3_asf::Audio_Spread) + // Error Correction Data Length DWORD 32 // number of bytes in Error Correction Data field + // Error Correction Data BYTESTREAM variable // structure depends on value of Error Correction Type field + + $info_asf['error_correction_object'] = array (); + $info_asf_error_correction_object = &$info_asf['error_correction_object']; + + $info_asf_error_correction_object['objectid_guid'] = $next_object_guidtext; + $info_asf_error_correction_object['objectsize'] = $next_object_size; + $info_asf_error_correction_object['error_correction_type'] = substr($asf_header_data, $offset, 16); + $offset += 16; + + $info_asf_error_correction_object['error_correction_guid'] = getid3_asf::BytestringToGUID($info_asf_error_correction_object['error_correction_type']); + $info_asf_error_correction_object['error_correction_data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4)); + $offset += 4; + + switch ($info_asf_error_correction_object['error_correction_type_guid']) { + + case getid3_asf::No_Error_Correction: + + // should be no data, but just in case there is, skip to the end of the field + $offset += $info_asf_error_correction_object['error_correction_data_length']; + break; + + + case getid3_asf::Audio_Spread: + + // Field Name Field Type Size (bits) + // Span BYTE 8 // number of packets over which audio will be spread. + // Virtual Packet Length WORD 16 // size of largest audio payload found in audio stream + // Virtual Chunk Length WORD 16 // size of largest audio payload found in audio stream + // Silence Data Length WORD 16 // number of bytes in Silence Data field + // Silence Data BYTESTREAM variable // hardcoded: 0x00 * (Silence Data Length) bytes + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_error_correction_object, $asf_header_data, $offset, + array ( + 'span' => 1, + 'virtual_packet_length' => 2, + 'virtual_chunk_length' => 2, + 'silence_data_length' => 2 + ) + ); + $offset += 7; + + $info_asf_error_correction_object['silence_data'] = substr($asf_header_data, $offset, $info_asf_error_correction_object['silence_data_length']); + $offset += $info_asf_error_correction_object['silence_data_length']; + break; + + default: + $getid3->warning('error_correction_object.error_correction_type GUID {'.$info_asf_error_correction_object['reserved_guid'].'} does not match expected "getid3_asf::No_Error_Correction" GUID {'.getid3_asf::No_Error_Correction.'} or "getid3_asf::Audio_Spread" GUID {'.getid3_asf::Audio_Spread.'}'); + break; + } + + break; + + + case getid3_asf::Content_Description_Object: + + // Content Description Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Content Description object - getid3_asf::Content_Description_Object + // Object Size QWORD 64 // size of Content Description object, including 34 bytes of Content Description Object header + // Title Length WORD 16 // number of bytes in Title field + // Author Length WORD 16 // number of bytes in Author field + // Copyright Length WORD 16 // number of bytes in Copyright field + // Description Length WORD 16 // number of bytes in Description field + // Rating Length WORD 16 // number of bytes in Rating field + // Title WCHAR 16 // array of Unicode characters - Title + // Author WCHAR 16 // array of Unicode characters - Author + // Copyright WCHAR 16 // array of Unicode characters - Copyright + // Description WCHAR 16 // array of Unicode characters - Description + // Rating WCHAR 16 // array of Unicode characters - Rating + + $info_asf['content_description_object'] = array (); + $info_asf_content_description_object = &$info_asf['content_description_object']; + + $info_asf_content_description_object['objectid_guid'] = $next_object_guidtext; + $info_asf_content_description_object['objectsize'] = $next_object_size; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_content_description_object, $asf_header_data, $offset, + array ( + 'title_length' => 2, + 'author_length' => 2, + 'copyright_length' => 2, + 'description_length' => 2, + 'rating_length' => 2 + ) + ); + $offset += 10; + + $info_asf_content_description_object['title'] = substr($asf_header_data, $offset, $info_asf_content_description_object['title_length']); + $offset += $info_asf_content_description_object['title_length']; + + $info_asf_content_description_object['author'] = substr($asf_header_data, $offset, $info_asf_content_description_object['author_length']); + $offset += $info_asf_content_description_object['author_length']; + + $info_asf_content_description_object['copyright'] = substr($asf_header_data, $offset, $info_asf_content_description_object['copyright_length']); + $offset += $info_asf_content_description_object['copyright_length']; + + $info_asf_content_description_object['description'] = substr($asf_header_data, $offset, $info_asf_content_description_object['description_length']); + $offset += $info_asf_content_description_object['description_length']; + + $info_asf_content_description_object['rating'] = substr($asf_header_data, $offset, $info_asf_content_description_object['rating_length']); + $offset += $info_asf_content_description_object['rating_length']; + + foreach (array ('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating') as $key_to_copy_from => $key_to_copy_to) { + if (!empty($info_asf_content_description_object[$key_to_copy_from])) { + $info_asf_comments[$key_to_copy_to][] = getid3_asf::TrimTerm($info_asf_content_description_object[$key_to_copy_from]); + } + } + break; + + + case getid3_asf::Extended_Content_Description_Object: + + // Extended Content Description Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Extended Content Description object - getid3_asf::Extended_Content_Description_Object + // Object Size QWORD 64 // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header + // Content Descriptors Count WORD 16 // number of entries in Content Descriptors list + // Content Descriptors array of: variable // + // * Descriptor Name Length WORD 16 // size in bytes of Descriptor Name field + // * Descriptor Name WCHAR variable // array of Unicode characters - Descriptor Name + // * Descriptor Value Data Type WORD 16 // Lookup array: + // 0x0000 = Unicode String (variable length) + // 0x0001 = BYTE array (variable length) + // 0x0002 = BOOL (DWORD, 32 bits) + // 0x0003 = DWORD (DWORD, 32 bits) + // 0x0004 = QWORD (QWORD, 64 bits) + // 0x0005 = WORD (WORD, 16 bits) + // * Descriptor Value Length WORD 16 // number of bytes stored in Descriptor Value field + // * Descriptor Value variable variable // value for Content Descriptor + + $info_asf['extended_content_description_object'] = array (); + $info_asf_extended_content_description_object = &$info_asf['extended_content_description_object']; + + $info_asf_extended_content_description_object['objectid_guid'] = $next_object_guidtext; + $info_asf_extended_content_description_object['objectsize'] = $next_object_size; + $info_asf_extended_content_description_object['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + for ($extended_content_descriptors_counter = 0; $extended_content_descriptors_counter < $info_asf_extended_content_description_object['content_descriptors_count']; $extended_content_descriptors_counter++) { + + $info_asf_extended_content_description_object['content_descriptors'][$extended_content_descriptors_counter] = array (); + $info_asf_extended_content_description_object_content_descriptor_current = &$info_asf_extended_content_description_object['content_descriptors'][$extended_content_descriptors_counter]; + + $info_asf_extended_content_description_object_content_descriptor_current['base_offset'] = $offset + 30; + $info_asf_extended_content_description_object_content_descriptor_current['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $info_asf_extended_content_description_object_content_descriptor_current['name'] = substr($asf_header_data, $offset, $info_asf_extended_content_description_object_content_descriptor_current['name_length']); + $offset += $info_asf_extended_content_description_object_content_descriptor_current['name_length']; + + $info_asf_extended_content_description_object_content_descriptor_current['value_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $info_asf_extended_content_description_object_content_descriptor_current['value_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $info_asf_extended_content_description_object_content_descriptor_current['value'] = substr($asf_header_data, $offset, $info_asf_extended_content_description_object_content_descriptor_current['value_length']); + $offset += $info_asf_extended_content_description_object_content_descriptor_current['value_length']; + + switch ($info_asf_extended_content_description_object_content_descriptor_current['value_type']) { + + case 0x0000: // Unicode string + break; + + case 0x0001: // BYTE array + // do nothing + break; + + case 0x0002: // BOOL + $info_asf_extended_content_description_object_content_descriptor_current['value'] = (bool)getid3_lib::LittleEndian2Int($info_asf_extended_content_description_object_content_descriptor_current['value']); + break; + + case 0x0003: // DWORD + case 0x0004: // QWORD + case 0x0005: // WORD + $info_asf_extended_content_description_object_content_descriptor_current['value'] = getid3_lib::LittleEndian2Int($info_asf_extended_content_description_object_content_descriptor_current['value']); + break; + + default: + $getid3->warning('extended_content_description.content_descriptors.'.$extended_content_descriptors_counter.'.value_type is invalid ('.$info_asf_extended_content_description_object_content_descriptor_current['value_type'].')'); + break; + } + + switch ($this->TrimConvert(strtolower($info_asf_extended_content_description_object_content_descriptor_current['name']))) { + + case 'wm/albumartist': + case 'artist': + $info_asf_comments['artist'] = array (getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value'])); + break; + + + case 'wm/albumtitle': + case 'album': + $info_asf_comments['album'] = array (getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value'])); + break; + + + case 'wm/genre': + case 'genre': + $genre = getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value']); + $info_asf_comments['genre'] = array ($genre); + break; + + + case 'wm/tracknumber': + case 'tracknumber': + $info_asf_comments['track'] = array (intval(getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value']))); + break; + + + case 'wm/track': + if (empty($info_asf_comments['track'])) { + $info_asf_comments['track'] = array (1 + $this->TrimConvert($info_asf_extended_content_description_object_content_descriptor_current['value'])); + } + break; + + + case 'wm/year': + case 'year': + case 'date': + $info_asf_comments['year'] = array ( getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value'])); + break; + + + case 'wm/lyrics': + case 'lyrics': + $info_asf_comments['lyrics'] = array ( getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value'])); + break; + + + case 'isvbr': + if ($info_asf_extended_content_description_object_content_descriptor_current['value']) { + $info_audio['bitrate_mode'] = 'vbr'; + $info_video['bitrate_mode'] = 'vbr'; + } + break; + + + case 'id3': + + // id3v2 parsing might not be enabled + if (class_exists('getid3_id3v2')) { + + // Clone getid3 + $clone = clone $getid3; + + // Analyse clone by string + $id3v2 = new getid3_id3v2($clone); + $id3v2->AnalyzeString($info_asf_extended_content_description_object_content_descriptor_current['value']); + + // Import from clone and destroy + $getid3->info['id3v2'] = $clone->info['id3v2']; + $getid3->warnings($clone->warnings()); + unset($clone); + } + break; + + + case 'wm/encodingtime': + $info_asf_extended_content_description_object_content_descriptor_current['encoding_time_unix'] = getid3_asf::FiletimeToUNIXtime($info_asf_extended_content_description_object_content_descriptor_current['value']); + $info_asf_comments['encoding_time_unix'] = array ($info_asf_extended_content_description_object_content_descriptor_current['encoding_time_unix']); + break; + + + case 'wm/picture': + + //typedef struct _WMPicture{ + // LPWSTR pwszMIMEType; + // BYTE bPictureType; + // LPWSTR pwszDescription; + // DWORD dwDataLen; + // BYTE* pbData; + //} WM_PICTURE; + + $info_asf_extended_content_description_object_content_descriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int($info_asf_extended_content_description_object_content_descriptor_current['value']{0}); + $info_asf_extended_content_description_object_content_descriptor_current['image_type'] = getid3_asf::WMpictureTypeLookup($info_asf_extended_content_description_object_content_descriptor_current['image_type_id']); + $info_asf_extended_content_description_object_content_descriptor_current['image_size'] = getid3_lib::LittleEndian2Int(substr($info_asf_extended_content_description_object_content_descriptor_current['value'], 1, 4)); + $info_asf_extended_content_description_object_content_descriptor_current['image_mime'] = ''; + + $wm_picture_offset = 5; + + do { + $next_byte_pair = substr($info_asf_extended_content_description_object_content_descriptor_current['value'], $wm_picture_offset, 2); + $wm_picture_offset += 2; + $info_asf_extended_content_description_object_content_descriptor_current['image_mime'] .= $next_byte_pair; + } while ($next_byte_pair !== "\x00\x00"); + + $info_asf_extended_content_description_object_content_descriptor_current['image_description'] = ''; + + do { + $next_byte_pair = substr($info_asf_extended_content_description_object_content_descriptor_current['value'], $wm_picture_offset, 2); + $wm_picture_offset += 2; + $info_asf_extended_content_description_object_content_descriptor_current['image_description'] .= $next_byte_pair; + } while ($next_byte_pair !== "\x00\x00"); + + $info_asf_extended_content_description_object_content_descriptor_current['dataoffset'] = $wm_picture_offset; + $info_asf_extended_content_description_object_content_descriptor_current['data'] = substr($info_asf_extended_content_description_object_content_descriptor_current['value'], $wm_picture_offset); + unset($info_asf_extended_content_description_object_content_descriptor_current['value']); + break; + + default: + switch ($info_asf_extended_content_description_object_content_descriptor_current['value_type']) { + case 0: // Unicode string + if (substr($this->TrimConvert($info_asf_extended_content_description_object_content_descriptor_current['name']), 0, 3) == 'WM/') { + $info_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($info_asf_extended_content_description_object_content_descriptor_current['name'])))] = array (getid3_asf::TrimTerm($info_asf_extended_content_description_object_content_descriptor_current['value'])); + } + break; + + case 1: + break; + } + break; + } + + } + break; + + + case getid3_asf::Stream_Bitrate_Properties_Object: + + // Stream Bitrate Properties Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Stream Bitrate Properties object - getid3_asf::Stream_Bitrate_Properties_Object + // Object Size QWORD 64 // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header + // Bitrate Records Count WORD 16 // number of records in Bitrate Records + // Bitrate Records array of: variable // + // * Flags WORD 16 // + // * * Stream Number bits 7 (0x007F) // number of this stream + // * * Reserved bits 9 (0xFF80) // hardcoded: 0 + // * Average Bitrate DWORD 32 // in bits per second + + // shortcut + $info_asf['stream_bitrate_properties_object'] = array (); + $info_asf_stream_bitrate_properties_object = &$info_asf['stream_bitrate_properties_object']; + + $info_asf_stream_bitrate_properties_object['objectid_guid'] = $next_object_guidtext; + $info_asf_stream_bitrate_properties_object['objectsize'] = $next_object_size; + $info_asf_stream_bitrate_properties_object['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + for ($bitrate_records_counter = 0; $bitrate_records_counter < $info_asf_stream_bitrate_properties_object['bitrate_records_count']; $bitrate_records_counter++) { + + $info_asf_stream_bitrate_properties_object['bitrate_records'][$bitrate_records_counter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 2)); + $offset += 2; + + $info_asf_stream_bitrate_properties_object['bitrate_records'][$bitrate_records_counter]['flags']['stream_number'] = $info_asf_stream_bitrate_properties_object['bitrate_records'][$bitrate_records_counter]['flags_raw'] & 0x007F; + + $info_asf_stream_bitrate_properties_object['bitrate_records'][$bitrate_records_counter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_data, $offset, 4)); + $offset += 4; + } + break; + + + case getid3_asf::Padding_Object: + + // Padding Object: (optional) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Padding object - getid3_asf::Padding_Object + // Object Size QWORD 64 // size of Padding object, including 24 bytes of ASF Padding Object header + // Padding Data BYTESTREAM variable // ignore + + // shortcut + $info_asf['padding_object'] = array (); + $info_asf_paddingobject = &$info_asf['padding_object']; + + $info_asf_paddingobject['objectid_guid'] = $next_object_guidtext; + $info_asf_paddingobject['objectsize'] = $next_object_size; + $info_asf_paddingobject['padding_length'] = $info_asf_paddingobject['objectsize'] - 16 - 8; + $info_asf_paddingobject['padding'] = substr($asf_header_data, $offset, $info_asf_paddingobject['padding_length']); + break; + + + case getid3_asf::Extended_Content_Encryption_Object: + case getid3_asf::Content_Encryption_Object: + + // WMA DRM - just ignore + $offset += ($next_object_size - 16 - 8); + break; + + + default: + + // Implementations shall ignore any standard or non-standard object that they do not know how to handle. + if (getid3_asf::GUIDname($next_object_guidtext)) { + $getid3->warning('unhandled GUID "'.getid3_asf::GUIDname($next_object_guidtext).'" {'.$next_object_guidtext.'} in ASF header at offset '.($offset - 16 - 8)); + } else { + $getid3->warning('unknown GUID {'.$next_object_guidtext.'} in ASF header at offset '.($offset - 16 - 8)); + } + $offset += ($next_object_size - 16 - 8); + break; + } + } + + if (isset($info_asf_stream_bitrate_properties['bitrate_records_count'])) { + $asf_bitrate_audio = 0; + $asf_bitrate_video = 0; + + for ($bitrate_records_counter = 0; $bitrate_records_counter < $info_asf_stream_bitrate_properties['bitrate_records_count']; $bitrate_records_counter++) { + if (isset($info_asf_codec_list_object['codec_entries'][$bitrate_records_counter])) { + switch ($info_asf_codec_list_object['codec_entries'][$bitrate_records_counter]['type_raw']) { + + case 1: + $asf_bitrate_video += $info_asf_stream_bitrate_properties['bitrate_records'][$bitrate_records_counter]['bitrate']; + break; + + case 2: + $asf_bitrate_audio += $info_asf_stream_bitrate_properties['bitrate_records'][$bitrate_records_counter]['bitrate']; + break; + } + } + } + if ($asf_bitrate_audio > 0) { + $info_audio['bitrate'] = $asf_bitrate_audio; + } + if ($asf_bitrate_video > 0) { + $info_video['bitrate'] = $asf_bitrate_video; + } + } + + if (isset($info_asf['stream_properties_object']) && is_array($info_asf['stream_properties_object'])) { + + $info_audio['bitrate'] = 0; + $info_video['bitrate'] = 0; + + foreach ($info_asf['stream_properties_object'] as $stream_number => $stream_data) { + + switch ($stream_data['stream_type_guid']) { + + case getid3_asf::Audio_Media: + + // Field Name Field Type Size (bits) + // Codec ID / Format Tag WORD 16 // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure + // Number of Channels WORD 16 // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure + // Samples Per Second DWORD 32 // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure + // Average number of Bytes/sec DWORD 32 // bytes/sec of audio stream - defined as nAvgBytesPerSec field of WAVEFORMATEX structure + // Block Alignment WORD 16 // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure + // Bits per sample WORD 16 // bits per sample of mono data. set to zero for variable bitrate codecs. defined as wBitsPerSample field of WAVEFORMATEX structure + // Codec Specific Data Size WORD 16 // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure + // Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes + + // shortcut + $info_asf['audio_media'][$stream_number] = array (); + $info_asf_audio_media_current_stream = &$info_asf['audio_media'][$stream_number]; + + $audio_media_offset = 0; + + $info_asf_audio_media_current_stream = getid3_riff::RIFFparseWAVEFORMATex(substr($stream_data['type_specific_data'], $audio_media_offset, 16)); + + $audio_media_offset += 16; + + $info_audio['lossless'] = false; + switch ($info_asf_audio_media_current_stream['raw']['wFormatTag']) { + case 0x0001: // PCM + case 0x0163: // WMA9 Lossless + $info_audio['lossless'] = true; + break; + } + + if (!empty($info_asf['stream_bitrate_properties_object']['bitrate_records'])) { + foreach ($info_asf['stream_bitrate_properties_object']['bitrate_records'] as $data_array) { + if (@$data_array['flags']['stream_number'] == $stream_number) { + $info_asf_audio_media_current_stream['bitrate'] = $data_array['bitrate']; + $info_audio['bitrate'] += $data_array['bitrate']; + break; + } + } + } else { + if (@$info_asf_audio_media_current_stream['bytes_sec']) { + $info_audio['bitrate'] += $info_asf_audio_media_current_stream['bytes_sec'] * 8; + } elseif (@$info_asf_audio_media_current_stream['bitrate']) { + $info_audio['bitrate'] += $info_asf_audio_media_current_stream['bitrate']; + } + } + + $info_audio['streams'][$stream_number] = $info_asf_audio_media_current_stream; + $info_audio['streams'][$stream_number]['wformattag'] = $info_asf_audio_media_current_stream['raw']['wFormatTag']; + $info_audio['streams'][$stream_number]['lossless'] = $info_audio['lossless']; + $info_audio['streams'][$stream_number]['bitrate'] = $info_audio['bitrate']; + unset($info_audio['streams'][$stream_number]['raw']); + + $info_asf_audio_media_current_stream['codec_data_size'] = getid3_lib::LittleEndian2Int(substr($stream_data['type_specific_data'], $audio_media_offset, 2)); + $audio_media_offset += 2; + + $info_asf_audio_media_current_stream['codec_data'] = substr($stream_data['type_specific_data'], $audio_media_offset, $info_asf_audio_media_current_stream['codec_data_size']); + $audio_media_offset += $info_asf_audio_media_current_stream['codec_data_size']; + break; + + + case getid3_asf::Video_Media: + + // Field Name Field Type Size (bits) + // Encoded Image Width DWORD 32 // width of image in pixels + // Encoded Image Height DWORD 32 // height of image in pixels + // Reserved Flags BYTE 8 // hardcoded: 0x02 + // Format Data Size WORD 16 // size of Format Data field in bytes + // Format Data array of: variable // + // * Format Data Size DWORD 32 // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure + // * Image Width LONG 32 // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure + // * Image Height LONG 32 // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure + // * Reserved WORD 16 // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure + // * Bits Per Pixel Count WORD 16 // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure + // * Compression ID FOURCC 32 // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure + // * Image Size DWORD 32 // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure + // * Horizontal Pixels / Meter DWORD 32 // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure + // * Vertical Pixels / Meter DWORD 32 // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure + // * Colors Used Count DWORD 32 // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure + // * Important Colors Count DWORD 32 // number of color index required for displaying bitmap. if zero, all colors are required. defined as biClrImportant field of BITMAPINFOHEADER structure + // * Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes + + $info_asf['video_media'][$stream_number] = array (); + $info_asf_video_media_current_stream = &$info_asf['video_media'][$stream_number]; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_video_media_current_stream, $stream_data['type_specific_data'], 0, + array ( + 'image_width' => 4, + 'image_height' => 4, + 'flags' => 1, + 'format_data_size'=> 2 + ) + ); + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_video_media_current_stream['format_data'], $stream_data['type_specific_data'], 11, + array ( + 'format_data_size' => 4, + 'image_width' => 4, + 'image_height' => 4, + 'reserved' => 2, + 'bits_per_pixel' => 2, + 'codec_fourcc' => -4, + 'image_size' => 4, + 'horizontal_pels' => 4, + 'vertical_pels' => 4, + 'colors_used' => 4, + 'colors_important' => 4 + ) + ); + + $info_asf_video_media_current_stream['format_data']['codec_data'] = substr($stream_data['type_specific_data'], 51); + + if (!empty($info_asf['stream_bitrate_properties_object']['bitrate_records'])) { + foreach ($info_asf['stream_bitrate_properties_object']['bitrate_records'] as $data_array) { + if (@$data_array['flags']['stream_number'] == $stream_number) { + $info_asf_video_media_current_stream['bitrate'] = $data_array['bitrate']; + $info_video['streams'][$stream_number]['bitrate'] = $data_array['bitrate']; + $info_video['bitrate'] += $data_array['bitrate']; + + break; + } + } + } + + $info_asf_video_media_current_stream['format_data']['codec'] = getid3_riff::RIFFfourccLookup($info_asf_video_media_current_stream['format_data']['codec_fourcc']); + + $info_video['streams'][$stream_number]['fourcc'] = $info_asf_video_media_current_stream['format_data']['codec_fourcc']; + $info_video['streams'][$stream_number]['codec'] = $info_asf_video_media_current_stream['format_data']['codec']; + $info_video['streams'][$stream_number]['resolution_x'] = $info_asf_video_media_current_stream['image_width']; + $info_video['streams'][$stream_number]['resolution_y'] = $info_asf_video_media_current_stream['image_height']; + $info_video['streams'][$stream_number]['bits_per_sample'] = $info_asf_video_media_current_stream['format_data']['bits_per_pixel']; + break; + + default: + break; + } + } + } + + while (ftell($getid3->fp) < $getid3->info['avdataend']) { + + $next_object_data_header = fread($getid3->fp, 24); + $offset = 0; + + $next_object_guid = substr($next_object_data_header, 0, 16); + $offset += 16; + + $next_object_guidtext = getid3_asf::BytestringToGUID($next_object_guid); + $next_object_size = getid3_lib::LittleEndian2Int(substr($next_object_data_header, $offset, 8)); + $offset += 8; + + switch ($next_object_guidtext) { + + case getid3_asf::Data_Object: + + // Data Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Data object - getid3_asf::Data_Object + // Object Size QWORD 64 // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1 + // File ID GUID 128 // unique identifier. identical to File ID field in Header Object + // Total Data Packets QWORD 64 // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1 + // Reserved WORD 16 // hardcoded: 0x0101 + + // shortcut + $info_asf['data_object'] = array (); + $info_asf_data_object = &$info_asf['data_object']; + + $data_object_data = $next_object_data_header.fread($getid3->fp, 50 - 24); + $offset = 24; + + $info_asf_data_object['objectid_guid'] = $next_object_guidtext; + $info_asf_data_object['objectsize'] = $next_object_size; + + $info_asf_data_object['fileid_guid'] = getid3_asf::BytestringToGUID(substr($data_object_data, $offset, 16)); + $offset += 16; + + $info_asf_data_object['total_data_packets'] = getid3_lib::LittleEndian2Int(substr($data_object_data, $offset, 8)); + $offset += 8; + + $info_asf_data_object['reserved'] = getid3_lib::LittleEndian2Int(substr($data_object_data, $offset, 2)); + $offset += 2; + + if ($info_asf_data_object['reserved'] != 0x0101) { + $getid3->warning('data_object.reserved ('.getid3_lib::PrintHexBytes($info_asf_data_object['reserved']).') does not match expected value of "0x0101"'); + break; + } + + // Data Packets array of: variable // + // * Error Correction Flags BYTE 8 // + // * * Error Correction Data Length bits 4 // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000 + // * * Opaque Data Present bits 1 // + // * * Error Correction Length Type bits 2 // number of bits for size of the error correction data. hardcoded: 00 + // * * Error Correction Present bits 1 // If set, use Opaque Data Packet structure, else use Payload structure + // * Error Correction Data + + $getid3->info['avdataoffset'] = ftell($getid3->fp); + fseek($getid3->fp, ($info_asf_data_object['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data + $getid3->info['avdataend'] = ftell($getid3->fp); + break; + + + case getid3_asf::Simple_Index_Object: + + // Simple Index Object: (optional, recommended, one per video stream) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Simple Index object - getid3_asf::Data_Object + // Object Size QWORD 64 // size of Simple Index object, including 56 bytes of Simple Index Object header + // File ID GUID 128 // unique identifier. may be zero or identical to File ID field in Data Object and Header Object + // Index Entry Time Interval QWORD 64 // interval between index entries in 100-nanosecond units + // Maximum Packet Count DWORD 32 // maximum packet count for all index entries + // Index Entries Count DWORD 32 // number of Index Entries structures + // Index Entries array of: variable // + // * Packet Number DWORD 32 // number of the Data Packet associated with this index entry + // * Packet Count WORD 16 // number of Data Packets to sent at this index entry + + // shortcut + $info_asf['simple_index_object'] = array (); + $info_asf_simple_index_object = &$info_asf['simple_index_object']; + + $info_asf_simple_index_object['objectid_guid'] = $next_object_guidtext; + $info_asf_simple_index_object['objectsize'] = $next_object_size; + + $simple_index_object_data = $next_object_data_header.fread($getid3->fp, 56 - 24); + + $info_asf_simple_index_object['fileid_guid'] = getid3_asf::BytestringToGUID(substr($simple_index_object_data, 24, 16)); + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_simple_index_object, $simple_index_object_data, 40, + array ( + 'index_entry_time_interval' => 8, + 'maximum_packet_count' => 4, + 'index_entries_count' => 4 + ) + ); + + $offset = 56; + + $index_entries_data = $simple_index_object_data.fread($getid3->fp, 6 * $info_asf_simple_index_object['index_entries_count']); + for ($index_entries_counter = 0; $index_entries_counter < $info_asf_simple_index_object['index_entries_count']; $index_entries_counter++) { + + $info_asf_simple_index_object['index_entries'][$index_entries_counter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($index_entries_data, $offset, 4)); + $offset += 4; + + $info_asf_simple_index_object['index_entries'][$index_entries_counter]['packet_count'] = getid3_lib::LittleEndian2Int(substr($index_entries_data, $offset, 4)); + $offset += 2; + } + break; + + + case getid3_asf::Index_Object: + + // 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for the Index Object - getid3_asf::Index_Object + // Object Size QWORD 64 // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header + // Index Entry Time Interval DWORD 32 // Specifies the time interval between each index entry in ms. + // Index Specifiers Count WORD 16 // Specifies the number of Index Specifiers structures in this Index Object. + // Index Blocks Count DWORD 32 // Specifies the number of Index Blocks structures in this Index Object. + + // Index Entry Time Interval DWORD 32 // Specifies the time interval between index entries in milliseconds. This value cannot be 0. + // Index Specifiers Count WORD 16 // Specifies the number of entries in the Index Specifiers list. Valid values are 1 and greater. + // Index Specifiers array of: varies // + // * Stream Number WORD 16 // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127. + // * Index Type WORD 16 // Specifies Index Type values as follows: + // 1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time. + // 2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object. + // 3 = Nearest Past Cleanpoint. - indexes point to the closest data packet containing an entire object (or first fragment of an object) that has the Cleanpoint Flag set. + // Nearest Past Cleanpoint is the most common type of index. + // Index Entry Count DWORD 32 // Specifies the number of Index Entries in the block. + // * Block Positions QWORD varies // Specifies a list of byte offsets of the beginnings of the blocks relative to the beginning of the first Data Packet (i.e., the beginning of the Data Object + 50 bytes). The number of entries in this list is specified by the value of the Index Specifiers Count field. The order of those byte offsets is tied to the order in which Index Specifiers are listed. + // * Index Entries array of: varies // + // * * Offsets DWORD varies // An offset value of 0xffffffff indicates an invalid offset value + + // shortcut + $info_asf['asf_index_object'] = array (); + $info_asf_asf_index_object = &$info_asf['asf_index_object']; + + $asf_index_object_data = $next_object_data_header.fread($getid3->fp, 34 - 24); + + $info_asf_asf_index_object['objectid_guid'] = $next_object_guidtext; + $info_asf_asf_index_object['objectsize'] = $next_object_size; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_asf_asf_index_object, $asf_index_object_data, 24, + array ( + 'entry_time_interval' =>4, + 'index_specifiers_count' =>2, + 'index_blocks_count' =>4 + ) + ); + + $offset = 34; + + $asf_index_object_data .= fread($getid3->fp, 4 * $info_asf_asf_index_object['index_specifiers_count']); + + for ($index_specifiers_counter = 0; $index_specifiers_counter < $info_asf_asf_index_object['index_specifiers_count']; $index_specifiers_counter++) { + + $index_specifier_stream_number = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 2)); + $offset += 2; + + $info_asf_asf_index_object['index_specifiers'][$index_specifiers_counter]['stream_number'] = $index_specifier_stream_number; + + $info_asf_asf_index_object['index_specifiers'][$index_specifiers_counter]['index_type'] = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 2)); + $offset += 2; + + $info_asf_asf_index_object['index_specifiers'][$index_specifiers_counter]['index_type_text'] = getid3_asf::ASFIndexObjectIndexTypeLookup($info_asf_asf_index_object['index_specifiers'][$index_specifiers_counter]['index_type']); + } + + $asf_index_object_data .= fread($getid3->fp, 4); + $info_asf_asf_index_object['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 4)); + $offset += 4; + + $asf_index_object_data .= fread($getid3->fp, 8 * $info_asf_asf_index_object['index_specifiers_count']); + + for ($index_specifiers_counter = 0; $index_specifiers_counter < $info_asf_asf_index_object['index_specifiers_count']; $index_specifiers_counter++) { + $info_asf_asf_index_object['block_positions'][$index_specifiers_counter] = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 8)); + $offset += 8; + } + + $asf_index_object_data .= fread($getid3->fp, 4 * $info_asf_asf_index_object['index_specifiers_count'] * $info_asf_asf_index_object['index_entry_count']); + + for ($index_entry_counter = 0; $index_entry_counter < $info_asf_asf_index_object['index_entry_count']; $index_entry_counter++) { + for ($index_specifiers_counter = 0; $index_specifiers_counter < $info_asf_asf_index_object['index_specifiers_count']; $index_specifiers_counter++) { + $info_asf_asf_index_object['offsets'][$index_specifiers_counter][$index_entry_counter] = getid3_lib::LittleEndian2Int(substr($asf_index_object_data, $offset, 4)); + $offset += 4; + } + } + break; + + + default: + + // Implementations shall ignore any standard or non-standard object that they do not know how to handle. + if (getid3_asf::GUIDname($next_object_guidtext)) { + $getid3->warning('unhandled GUID "'.getid3_asf::GUIDname($next_object_guidtext).'" {'.$next_object_guidtext.'} in ASF body at offset '.($offset - 16 - 8)); + } else { + $getid3->warning('unknown GUID {'.$next_object_guidtext.'} in ASF body at offset '.(ftell($getid3->fp) - 16 - 8)); + } + fseek($getid3->fp, ($next_object_size - 16 - 8), SEEK_CUR); + break; + } + } + + if (isset($info_asf_codec_list_object['codec_entries']) && is_array($info_asf_codec_list_object['codec_entries'])) { + foreach ($info_asf_codec_list_object['codec_entries'] as $stream_number => $stream_data) { + switch ($stream_data['information']) { + case 'WMV1': + case 'WMV2': + case 'WMV3': + $info_video['dataformat'] = 'wmv'; + $getid3->info['mime_type'] = 'video/x-ms-wmv'; + break; + + case 'MP42': + case 'MP43': + case 'MP4S': + case 'mp4s': + $info_video['dataformat'] = 'asf'; + $getid3->info['mime_type'] = 'video/x-ms-asf'; + break; + + default: + switch ($stream_data['type_raw']) { + case 1: + if (strstr($this->TrimConvert($stream_data['name']), 'Windows Media')) { + $info_video['dataformat'] = 'wmv'; + if ($getid3->info['mime_type'] == 'video/x-ms-asf') { + $getid3->info['mime_type'] = 'video/x-ms-wmv'; + } + } + break; + + case 2: + if (strstr($this->TrimConvert($stream_data['name']), 'Windows Media')) { + $info_audio['dataformat'] = 'wma'; + if ($getid3->info['mime_type'] == 'video/x-ms-asf') { + $getid3->info['mime_type'] = 'audio/x-ms-wma'; + } + } + break; + + } + break; + } + } + } + + switch (@$info_audio['codec']) { + case 'MPEG Layer-3': + $info_audio['dataformat'] = 'mp3'; + break; + + default: + break; + } + + if (isset($info_asf_codec_list_object['codec_entries'])) { + foreach ($info_asf_codec_list_object['codec_entries'] as $stream_number => $stream_data) { + switch ($stream_data['type_raw']) { + + case 1: // video + $info_video['encoder'] = $this->TrimConvert($info_asf_codec_list_object['codec_entries'][$stream_number]['name']); + break; + + case 2: // audio + $info_audio['encoder'] = $this->TrimConvert($info_asf_codec_list_object['codec_entries'][$stream_number]['name']); + $info_audio['encoder_options'] = $this->TrimConvert($info_asf_codec_list_object['codec_entries'][0]['description']); + $info_audio['codec'] = $info_audio['encoder']; + break; + + default: + $getid3->warning('Unknown streamtype: [codec_list_object][codec_entries]['.$stream_number.'][type_raw] == '.$stream_data['type_raw']); + break; + + } + } + } + + if (isset($getid3->info['audio'])) { + $info_audio['lossless'] = (isset($info_audio['lossless']) ? $info_audio['lossless'] : false); + $info_audio['dataformat'] = (!empty($info_audio['dataformat']) ? $info_audio['dataformat'] : 'asf'); + } + + if (!empty($info_video['dataformat'])) { + $info_video['lossless'] = (isset($info_audio['lossless']) ? $info_audio['lossless'] : false); + $info_video['pixel_aspect_ratio'] = (isset($info_audio['pixel_aspect_ratio']) ? $info_audio['pixel_aspect_ratio'] : (float)1); + $info_video['dataformat'] = (!empty($info_video['dataformat']) ? $info_video['dataformat'] : 'asf'); + } + + $getid3->info['bitrate'] = @$info_audio['bitrate'] + @$info_video['bitrate']; + + if (empty($info_audio)) { + unset($getid3->info['audio']); + } + + if (empty($info_video)) { + unset($getid3->info['video']); + } + + return true; + } + + + + // Remove terminator 00 00 and convert UNICODE to Latin-1 + private function TrimConvert($string) { + + // remove terminator, only if present (it should be, but...) + if (substr($string, strlen($string) - 2, 2) == "\x00\x00") { + $string = substr($string, 0, strlen($string) - 2); + } + + // convert + return trim($this->getid3->iconv('UTF-16LE', 'ISO-8859-1', $string), ' '); + } + + + + private function WMpictureTypeLookup($wm_picture_type) { + + static $lookup = array ( + 0x03 => 'Front Cover', + 0x04 => 'Back Cover', + 0x00 => 'User Defined', + 0x05 => 'Leaflet Page', + 0x06 => 'Media Label', + 0x07 => 'Lead Artist', + 0x08 => 'Artist', + 0x09 => 'Conductor', + 0x0A => 'Band', + 0x0B => 'Composer', + 0x0C => 'Lyricist', + 0x0D => 'Recording Location', + 0x0E => 'During Recording', + 0x0F => 'During Performance', + 0x10 => 'Video Screen Capture', + 0x12 => 'Illustration', + 0x13 => 'Band Logotype', + 0x14 => 'Publisher Logotype' + ); + + return isset($lookup[$wm_picture_type]) ? $this->getid3->iconv('ISO-8859-1', 'UTF-16LE', $lookup[$wm_picture_type]) : ''; + } + + + + public static function ASFCodecListObjectTypeLookup($codec_list_type) { + + static $lookup = array ( + 0x0001 => 'Video Codec', + 0x0002 => 'Audio Codec', + 0xFFFF => 'Unknown Codec' + ); + + return (isset($lookup[$codec_list_type]) ? $lookup[$codec_list_type] : 'Invalid Codec Type'); + } + + + + public static function GUIDname($guid_string) { + + static $lookup = array ( + getid3_asf::Extended_Stream_Properties_Object => 'Extended_Stream_Properties_Object', + getid3_asf::Padding_Object => 'Padding_Object', + getid3_asf::Payload_Ext_Syst_Pixel_Aspect_Ratio => 'Payload_Ext_Syst_Pixel_Aspect_Ratio', + getid3_asf::Script_Command_Object => 'Script_Command_Object', + getid3_asf::No_Error_Correction => 'No_Error_Correction', + getid3_asf::Content_Branding_Object => 'Content_Branding_Object', + getid3_asf::Content_Encryption_Object => 'Content_Encryption_Object', + getid3_asf::Digital_Signature_Object => 'Digital_Signature_Object', + getid3_asf::Extended_Content_Encryption_Object => 'Extended_Content_Encryption_Object', + getid3_asf::Simple_Index_Object => 'Simple_Index_Object', + getid3_asf::Degradable_JPEG_Media => 'Degradable_JPEG_Media', + getid3_asf::Payload_Extension_System_Timecode => 'Payload_Extension_System_Timecode', + getid3_asf::Binary_Media => 'Binary_Media', + getid3_asf::Timecode_Index_Object => 'Timecode_Index_Object', + getid3_asf::Metadata_Library_Object => 'Metadata_Library_Object', + getid3_asf::Reserved_3 => 'Reserved_3', + getid3_asf::Reserved_4 => 'Reserved_4', + getid3_asf::Command_Media => 'Command_Media', + getid3_asf::Header_Extension_Object => 'Header_Extension_Object', + getid3_asf::Media_Object_Index_Parameters_Obj => 'Media_Object_Index_Parameters_Obj', + getid3_asf::Header_Object => 'Header_Object', + getid3_asf::Content_Description_Object => 'Content_Description_Object', + getid3_asf::Error_Correction_Object => 'Error_Correction_Object', + getid3_asf::Data_Object => 'Data_Object', + getid3_asf::Web_Stream_Media_Subtype => 'Web_Stream_Media_Subtype', + getid3_asf::Stream_Bitrate_Properties_Object => 'Stream_Bitrate_Properties_Object', + getid3_asf::Language_List_Object => 'Language_List_Object', + getid3_asf::Codec_List_Object => 'Codec_List_Object', + getid3_asf::Reserved_2 => 'Reserved_2', + getid3_asf::File_Properties_Object => 'File_Properties_Object', + getid3_asf::File_Transfer_Media => 'File_Transfer_Media', + getid3_asf::Old_RTP_Extension_Data => 'Old_RTP_Extension_Data', + getid3_asf::Advanced_Mutual_Exclusion_Object => 'Advanced_Mutual_Exclusion_Object', + getid3_asf::Bandwidth_Sharing_Object => 'Bandwidth_Sharing_Object', + getid3_asf::Reserved_1 => 'Reserved_1', + getid3_asf::Bandwidth_Sharing_Exclusive => 'Bandwidth_Sharing_Exclusive', + getid3_asf::Bandwidth_Sharing_Partial => 'Bandwidth_Sharing_Partial', + getid3_asf::JFIF_Media => 'JFIF_Media', + getid3_asf::Stream_Properties_Object => 'Stream_Properties_Object', + getid3_asf::Video_Media => 'Video_Media', + getid3_asf::Audio_Spread => 'Audio_Spread', + getid3_asf::Metadata_Object => 'Metadata_Object', + getid3_asf::Payload_Ext_Syst_Sample_Duration => 'Payload_Ext_Syst_Sample_Duration', + getid3_asf::Group_Mutual_Exclusion_Object => 'Group_Mutual_Exclusion_Object', + getid3_asf::Extended_Content_Description_Object => 'Extended_Content_Description_Object', + getid3_asf::Stream_Prioritization_Object => 'Stream_Prioritization_Object', + getid3_asf::Payload_Ext_System_Content_Type => 'Payload_Ext_System_Content_Type', + getid3_asf::Old_File_Properties_Object => 'Old_File_Properties_Object', + getid3_asf::Old_ASF_Header_Object => 'Old_ASF_Header_Object', + getid3_asf::Old_ASF_Data_Object => 'Old_ASF_Data_Object', + getid3_asf::Index_Object => 'Index_Object', + getid3_asf::Old_Stream_Properties_Object => 'Old_Stream_Properties_Object', + getid3_asf::Old_Content_Description_Object => 'Old_Content_Description_Object', + getid3_asf::Old_Script_Command_Object => 'Old_Script_Command_Object', + getid3_asf::Old_Marker_Object => 'Old_Marker_Object', + getid3_asf::Old_Component_Download_Object => 'Old_Component_Download_Object', + getid3_asf::Old_Stream_Group_Object => 'Old_Stream_Group_Object', + getid3_asf::Old_Scalable_Object => 'Old_Scalable_Object', + getid3_asf::Old_Prioritization_Object => 'Old_Prioritization_Object', + getid3_asf::Bitrate_Mutual_Exclusion_Object => 'Bitrate_Mutual_Exclusion_Object', + getid3_asf::Old_Inter_Media_Dependency_Object => 'Old_Inter_Media_Dependency_Object', + getid3_asf::Old_Rating_Object => 'Old_Rating_Object', + getid3_asf::Index_Parameters_Object => 'Index_Parameters_Object', + getid3_asf::Old_Color_Table_Object => 'Old_Color_Table_Object', + getid3_asf::Old_Language_List_Object => 'Old_Language_List_Object', + getid3_asf::Old_Audio_Media => 'Old_Audio_Media', + getid3_asf::Old_Video_Media => 'Old_Video_Media', + getid3_asf::Old_Image_Media => 'Old_Image_Media', + getid3_asf::Old_Timecode_Media => 'Old_Timecode_Media', + getid3_asf::Old_Text_Media => 'Old_Text_Media', + getid3_asf::Old_MIDI_Media => 'Old_MIDI_Media', + getid3_asf::Old_Command_Media => 'Old_Command_Media', + getid3_asf::Old_No_Error_Concealment => 'Old_No_Error_Concealment', + getid3_asf::Old_Scrambled_Audio => 'Old_Scrambled_Audio', + getid3_asf::Old_No_Color_Table => 'Old_No_Color_Table', + getid3_asf::Old_SMPTE_Time => 'Old_SMPTE_Time', + getid3_asf::Old_ASCII_Text => 'Old_ASCII_Text', + getid3_asf::Old_Unicode_Text => 'Old_Unicode_Text', + getid3_asf::Old_HTML_Text => 'Old_HTML_Text', + getid3_asf::Old_URL_Command => 'Old_URL_Command', + getid3_asf::Old_Filename_Command => 'Old_Filename_Command', + getid3_asf::Old_ACM_Codec => 'Old_ACM_Codec', + getid3_asf::Old_VCM_Codec => 'Old_VCM_Codec', + getid3_asf::Old_QuickTime_Codec => 'Old_QuickTime_Codec', + getid3_asf::Old_DirectShow_Transform_Filter => 'Old_DirectShow_Transform_Filter', + getid3_asf::Old_DirectShow_Rendering_Filter => 'Old_DirectShow_Rendering_Filter', + getid3_asf::Old_No_Enhancement => 'Old_No_Enhancement', + getid3_asf::Old_Unknown_Enhancement_Type => 'Old_Unknown_Enhancement_Type', + getid3_asf::Old_Temporal_Enhancement => 'Old_Temporal_Enhancement', + getid3_asf::Old_Spatial_Enhancement => 'Old_Spatial_Enhancement', + getid3_asf::Old_Quality_Enhancement => 'Old_Quality_Enhancement', + getid3_asf::Old_Number_of_Channels_Enhancement => 'Old_Number_of_Channels_Enhancement', + getid3_asf::Old_Frequency_Response_Enhancement => 'Old_Frequency_Response_Enhancement', + getid3_asf::Old_Media_Object => 'Old_Media_Object', + getid3_asf::Mutex_Language => 'Mutex_Language', + getid3_asf::Mutex_Bitrate => 'Mutex_Bitrate', + getid3_asf::Mutex_Unknown => 'Mutex_Unknown', + getid3_asf::Old_ASF_Placeholder_Object => 'Old_ASF_Placeholder_Object', + getid3_asf::Old_Data_Unit_Extension_Object => 'Old_Data_Unit_Extension_Object', + getid3_asf::Web_Stream_Format => 'Web_Stream_Format', + getid3_asf::Payload_Ext_System_File_Name => 'Payload_Ext_System_File_Name', + getid3_asf::Marker_Object => 'Marker_Object', + getid3_asf::Timecode_Index_Parameters_Object => 'Timecode_Index_Parameters_Object', + getid3_asf::Audio_Media => 'Audio_Media', + getid3_asf::Media_Object_Index_Object => 'Media_Object_Index_Object', + getid3_asf::Alt_Extended_Content_Encryption_Obj => 'Alt_Extended_Content_Encryption_Obj' + ); + + return @$lookup[$guid_string]; + } + + + + public static function ASFIndexObjectIndexTypeLookup($id) { + + static $lookup = array ( + 1 => 'Nearest Past Data Packet', + 2 => 'Nearest Past Media Object', + 3 => 'Nearest Past Cleanpoint' + ); + + return (isset($lookup[$id]) ? $lookup[$id] : 'invalid'); + } + + + + public static function GUIDtoBytestring($guid_string) { + + // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way: + // first 4 bytes are in little-endian order + // next 2 bytes are appended in little-endian order + // next 2 bytes are appended in little-endian order + // next 2 bytes are appended in big-endian order + // next 6 bytes are appended in big-endian order + + // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string: + // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp + + $hex_byte_char_string = chr(hexdec(substr($guid_string, 6, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 4, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 2, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 0, 2))); + + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 11, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 9, 2))); + + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 16, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 14, 2))); + + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 19, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 21, 2))); + + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 24, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 26, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 28, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 30, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 32, 2))); + $hex_byte_char_string .= chr(hexdec(substr($guid_string, 34, 2))); + + return $hex_byte_char_string; + } + + + + public static function BytestringToGUID($byte_string) { + + $guid_string = str_pad(dechex(ord($byte_string{3})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{2})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{1})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{0})), 2, '0', STR_PAD_LEFT); + $guid_string .= '-'; + $guid_string .= str_pad(dechex(ord($byte_string{5})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{4})), 2, '0', STR_PAD_LEFT); + $guid_string .= '-'; + $guid_string .= str_pad(dechex(ord($byte_string{7})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{6})), 2, '0', STR_PAD_LEFT); + $guid_string .= '-'; + $guid_string .= str_pad(dechex(ord($byte_string{8})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{9})), 2, '0', STR_PAD_LEFT); + $guid_string .= '-'; + $guid_string .= str_pad(dechex(ord($byte_string{10})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{11})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{12})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{13})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{14})), 2, '0', STR_PAD_LEFT); + $guid_string .= str_pad(dechex(ord($byte_string{15})), 2, '0', STR_PAD_LEFT); + + return strtoupper($guid_string); + } + + + + public static function FiletimeToUNIXtime($file_time, $round=true) { + + // FILETIME is a 64-bit unsigned integer representing + // the number of 100-nanosecond intervals since January 1, 1601 + // UNIX timestamp is number of seconds since January 1, 1970 + // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days + + $time = ($file_time - 116444736000000000) / 10000000; + + if ($round) { + return intval(round($time)); + } + + return $time; + } + + + + public static function TrimTerm($string) { + + // remove terminator, only if present (it should be, but...) + if (substr($string, -2) == "\x00\x00") { + $string = substr($string, 0, -2); + } + return $string; + } + + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.bink.php b/plugins/getId3Plugin/lib/module.audio-video.bink.php new file mode 100644 index 0000000..2ebc6fe --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.bink.php @@ -0,0 +1,70 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.bink.php // +// module for analyzing Bink or Smacker audio-video files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_bink +{ + + function getid3_bink(&$fd, &$ThisFileInfo) { + +$ThisFileInfo['error'][] = 'Bink / Smacker files not properly processed by this version of getID3()'; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $fileTypeID = fread($fd, 3); + switch ($fileTypeID) { + case 'BIK': + return $this->ParseBink($fd, $ThisFileInfo); + break; + + case 'SMK': + return $this->ParseSmacker($fd, $ThisFileInfo); + break; + + default: + $ThisFileInfo['error'][] = 'Expecting "BIK" or "SMK" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$fileTypeID.'"'; + return false; + break; + } + + return true; + + } + + function ParseBink(&$fd, &$ThisFileInfo) { + $ThisFileInfo['fileformat'] = 'bink'; + $ThisFileInfo['video']['dataformat'] = 'bink'; + + $fileData = 'BIK'.fread($fd, 13); + + $ThisFileInfo['bink']['data_size'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4)); + $ThisFileInfo['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2)); + + if (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) != ($ThisFileInfo['bink']['data_size'] + 8)) { + $ThisFileInfo['error'][] = 'Probably truncated file: expecting '.$ThisFileInfo['bink']['data_size'].' bytes, found '.($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']); + } + + return true; + } + + function ParseSmacker(&$fd, &$ThisFileInfo) { + $ThisFileInfo['fileformat'] = 'smacker'; + $ThisFileInfo['video']['dataformat'] = 'smacker'; + + return false; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.flv.php b/plugins/getId3Plugin/lib/module.audio-video.flv.php new file mode 100644 index 0000000..e40e4b4 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.flv.php @@ -0,0 +1,573 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.archive.gzip.php | +// | module for analyzing GZIP files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// | FLV module by Seth Kaufman | +// | | +// | * version 0.1 (26 June 2005) | +// | | +// | minor modifications by James Heinrich | +// | * version 0.1.1 (15 July 2005) | +// | | +// | Support for On2 VP6 codec and meta information by | +// | Steve Webster | +// | * version 0.2 (22 February 2006) | +// | | +// | Modified to not read entire file into memory | +// | by James Heinrich | +// | * version 0.3 (15 June 2006) | +// | | +// | Modifications by Allan Hansen 8 July 2006 | +// | Adapted module for PHP5 and getID3 2.0.0. | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio-video.flv.php,v 1.2 2006/06/24 22:58:30 ah Exp $ + + + +class getid3_flv extends getid3_handler +{ + + const TAG_AUDIO = 8; + const TAG_VIDEO = 9; + const TAG_META = 18; + + const VIDEO_H263 = 2; + const VIDEO_SCREEN = 3; + const VIDEO_VP6 = 4; + + + public function Analyze() + { + $info = &$this->getid3->info; + + $info['flv'] = array (); + $info_flv = &$info['flv']; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + $flv_data_length = $info['avdataend'] - $info['avdataoffset']; + $flv_header = fread($this->getid3->fp, 5); + + $info['fileformat'] = 'flv'; + $info_flv['header']['signature'] = substr($flv_header, 0, 3); + $info_flv['header']['version'] = getid3_lib::BigEndian2Int(substr($flv_header, 3, 1)); + $type_flags = getid3_lib::BigEndian2Int(substr($flv_header, 4, 1)); + + $info_flv['header']['hasAudio'] = (bool) ($type_flags & 0x04); + $info_flv['header']['hasVideo'] = (bool) ($type_flags & 0x01); + + $frame_size_data_length = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4)); + $flv_header_frame_length = 9; + if ($frame_size_data_length > $flv_header_frame_length) { + fseek($this->getid3->fp, $frame_size_data_length - $flv_header_frame_length, SEEK_CUR); + } + + $duration = 0; + while ((ftell($this->getid3->fp) + 1) < $info['avdataend']) { + + $this_tag_header = fread($this->getid3->fp, 16); + + $previous_tag_length = getid3_lib::BigEndian2Int(substr($this_tag_header, 0, 4)); + $tag_type = getid3_lib::BigEndian2Int(substr($this_tag_header, 4, 1)); + $data_length = getid3_lib::BigEndian2Int(substr($this_tag_header, 5, 3)); + $timestamp = getid3_lib::BigEndian2Int(substr($this_tag_header, 8, 3)); + $last_header_byte = getid3_lib::BigEndian2Int(substr($this_tag_header, 15, 1)); + $next_offset = ftell($this->getid3->fp) - 1 + $data_length; + + switch ($tag_type) { + + case getid3_flv::TAG_AUDIO: + if (!isset($info_flv['audio']['audioFormat'])) { + $info_flv['audio']['audioFormat'] = $last_header_byte & 0x07; + $info_flv['audio']['audioRate'] = ($last_header_byte & 0x30) / 0x10; + $info_flv['audio']['audioSampleSize'] = ($last_header_byte & 0x40) / 0x40; + $info_flv['audio']['audioType'] = ($last_header_byte & 0x80) / 0x80; + } + break; + + + case getid3_flv::TAG_VIDEO: + if (!isset($info_flv['video']['videoCodec'])) { + $info_flv['video']['videoCodec'] = $last_header_byte & 0x07; + + $flv_video_header = fread($this->getid3->fp, 11); + + if ($info_flv['video']['videoCodec'] != getid3_flv::VIDEO_VP6) { + + $picture_size_type = (getid3_lib::BigEndian2Int(substr($flv_video_header, 3, 2))) >> 7; + $picture_size_type = $picture_size_type & 0x0007; + $info_flv['header']['videoSizeType'] = $picture_size_type; + + switch ($picture_size_type) { + case 0: + $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 5, 2)); + $picture_size_enc <<= 1; + $info['video']['resolution_x'] = ($picture_size_enc & 0xFF00) >> 8; + $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 6, 2)); + $picture_size_enc <<= 1; + $info['video']['resolution_y'] = ($picture_size_enc & 0xFF00) >> 8; + break; + + case 1: + $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 5, 4)); + $picture_size_enc <<= 1; + $info['video']['resolution_x'] = ($picture_size_enc & 0xFFFF0000) >> 16; + + $picture_size_enc = getid3_lib::BigEndian2Int(substr($flv_video_header, 7, 4)); + $picture_size_enc <<= 1; + $info['video']['resolution_y'] = ($picture_size_enc & 0xFFFF0000) >> 16; + break; + + case 2: + $info['video']['resolution_x'] = 352; + $info['video']['resolution_y'] = 288; + break; + + case 3: + $info['video']['resolution_x'] = 176; + $info['video']['resolution_y'] = 144; + break; + + case 4: + $info['video']['resolution_x'] = 128; + $info['video']['resolution_y'] = 96; + break; + + case 5: + $info['video']['resolution_x'] = 320; + $info['video']['resolution_y'] = 240; + break; + + case 6: + $info['video']['resolution_x'] = 160; + $info['video']['resolution_y'] = 120; + break; + + default: + $info['video']['resolution_x'] = 0; + $info['video']['resolution_y'] = 0; + break; + } + } + } + break; + + + // Meta tag + case getid3_flv::TAG_META: + + fseek($this->getid3->fp, -1, SEEK_CUR); + $reader = new AMFReader(new AMFStream(fread($this->getid3->fp, $data_length))); + $eventName = $reader->readData(); + $info['meta'][$eventName] = $reader->readData(); + unset($reader); + + $info['video']['frame_rate'] = $info['meta']['onMetaData']['framerate']; + $info['video']['resolution_x'] = $info['meta']['onMetaData']['width']; + $info['video']['resolution_y'] = $info['meta']['onMetaData']['height']; + break; + + default: + // noop + break; + } + + if ($timestamp > $duration) { + $duration = $timestamp; + } + + fseek($this->getid3->fp, $next_offset, SEEK_SET); + } + + $info['playtime_seconds'] = $duration / 1000; + $info['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']; + + if ($info_flv['header']['hasAudio']) { + $info['audio']['codec'] = $this->FLVaudioFormat($info_flv['audio']['audioFormat']); + $info['audio']['sample_rate'] = $this->FLVaudioRate($info_flv['audio']['audioRate']); + $info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info_flv['audio']['audioSampleSize']); + + $info['audio']['channels'] = $info_flv['audio']['audioType'] + 1; // 0=mono,1=stereo + $info['audio']['lossless'] = ($info_flv['audio']['audioFormat'] ? false : true); // 0=uncompressed + $info['audio']['dataformat'] = 'flv'; + } + if (@$info_flv['header']['hasVideo']) { + $info['video']['codec'] = $this->FLVvideoCodec($info_flv['video']['videoCodec']); + $info['video']['dataformat'] = 'flv'; + $info['video']['lossless'] = false; + } + + return true; + } + + + public static function FLVaudioFormat($id) { + + static $lookup = array( + 0 => 'uncompressed', + 1 => 'ADPCM', + 2 => 'mp3', + 5 => 'Nellymoser 8kHz mono', + 6 => 'Nellymoser', + ); + return (@$lookup[$id] ? @$lookup[$id] : false); + } + + + public static function FLVaudioRate($id) { + + static $lookup = array( + 0 => 5500, + 1 => 11025, + 2 => 22050, + 3 => 44100, + ); + return (@$lookup[$id] ? @$lookup[$id] : false); + } + + + public static function FLVaudioBitDepth($id) { + + static $lookup = array( + 0 => 8, + 1 => 16, + ); + return (@$lookup[$id] ? @$lookup[$id] : false); + } + + + public static function FLVvideoCodec($id) { + + static $lookup = array( + getid3_flv::VIDEO_H263 => 'Sorenson H.263', + getid3_flv::VIDEO_SCREEN => 'Screen video', + getid3_flv::VIDEO_VP6 => 'On2 VP6', + ); + return (@$lookup[$id] ? @$lookup[$id] : false); + } +} + + + +class AMFStream +{ + public $bytes; + public $pos; + + + public function AMFStream($bytes) { + + $this->bytes = $bytes; + $this->pos = 0; + } + + + public function readByte() { + + return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1)); + } + + + public function readInt() { + + return ($this->readByte() << 8) + $this->readByte(); + } + + + public function readLong() { + + return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte(); + } + + + public function readDouble() { + + return getid3_lib::BigEndian2Float($this->read(8)); + } + + + public function readUTF() { + + $length = $this->readInt(); + return $this->read($length); + } + + + public function readLongUTF() { + + $length = $this->readLong(); + return $this->read($length); + } + + + public function read($length) { + + $val = substr($this->bytes, $this->pos, $length); + $this->pos += $length; + return $val; + } + + + public function peekByte() { + + $pos = $this->pos; + $val = $this->readByte(); + $this->pos = $pos; + return $val; + } + + + public function peekInt() { + + $pos = $this->pos; + $val = $this->readInt(); + $this->pos = $pos; + return $val; + } + + + public function peekLong() { + + $pos = $this->pos; + $val = $this->readLong(); + $this->pos = $pos; + return $val; + } + + + public function peekDouble() { + + $pos = $this->pos; + $val = $this->readDouble(); + $this->pos = $pos; + return $val; + } + + + public function peekUTF() { + + $pos = $this->pos; + $val = $this->readUTF(); + $this->pos = $pos; + return $val; + } + + + public function peekLongUTF() { + + $pos = $this->pos; + $val = $this->readLongUTF(); + $this->pos = $pos; + return $val; + } +} + + + +class AMFReader +{ + public $stream; + + public function __construct($stream) { + + $this->stream = $stream; + } + + + public function readData() { + + $value = null; + + $type = $this->stream->readByte(); + + switch($type) { + // Double + case 0: + $value = $this->readDouble(); + break; + + // Boolean + case 1: + $value = $this->readBoolean(); + break; + + // String + case 2: + $value = $this->readString(); + break; + + // Object + case 3: + $value = $this->readObject(); + break; + + // null + case 6: + return null; + break; + + // Mixed array + case 8: + $value = $this->readMixedArray(); + break; + + // Array + case 10: + $value = $this->readArray(); + break; + + // Date + case 11: + $value = $this->readDate(); + break; + + // Long string + case 13: + $value = $this->readLongString(); + break; + + // XML (handled as string) + case 15: + $value = $this->readXML(); + break; + + // Typed object (handled as object) + case 16: + $value = $this->readTypedObject(); + break; + + // Long string + default: + $value = '(unknown or unsupported data type)'; + break; + } + + return $value; + } + + + public function readDouble() { + + return $this->stream->readDouble(); + } + + + public function readBoolean() { + + return $this->stream->readByte() == 1; + } + + + public function readString() { + + return $this->stream->readUTF(); + } + + + public function readObject() { + + // Get highest numerical index - ignored + $highestIndex = $this->stream->readLong(); + + $data = array(); + + while ($key = $this->stream->readUTF()) { + // Mixed array record ends with empty string (0x00 0x00) and 0x09 + if (($key == '') && ($this->stream->peekByte() == 0x09)) { + // Consume byte + $this->stream->readByte(); + break; + } + + $data[$key] = $this->readData(); + } + + return $data; + } + + + public function readMixedArray() { + + // Get highest numerical index - ignored + $highestIndex = $this->stream->readLong(); + + $data = array(); + + while ($key = $this->stream->readUTF()) { + // Mixed array record ends with empty string (0x00 0x00) and 0x09 + if (($key == '') && ($this->stream->peekByte() == 0x09)) { + // Consume byte + $this->stream->readByte(); + break; + } + + if (is_numeric($key)) { + $key = (float) $key; + } + + $data[$key] = $this->readData(); + } + + return $data; + } + + + public function readArray() { + + $length = $this->stream->readLong(); + + $data = array(); + + for ($i = 0; $i < count($length); $i++) { + $data[] = $this->readData(); + } + + return $data; + } + + + public function readDate() { + + $timestamp = $this->stream->readDouble(); + $timezone = $this->stream->readInt(); + return $timestamp; + } + + + public function readLongString() { + + return $this->stream->readLongUTF(); + } + + + public function readXML() { + + return $this->stream->readLongUTF(); + } + + + public function readTypedObject() { + + $className = $this->stream->readUTF(); + return $this->readObject(); + } +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.matroska.php b/plugins/getId3Plugin/lib/module.audio-video.matroska.php new file mode 100644 index 0000000..11ac929 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.matroska.php @@ -0,0 +1,78 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.matriska.php // +// module for analyzing Matroska containers // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_matroska +{ + + function getid3_matroska(&$fd, &$ThisFileInfo) { + + $ThisFileInfo['fileformat'] = 'matroska'; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + + //$ThisFileInfo['matroska']['raw']['a'] = $this->EBML2Int(fread($fd, 4)); + + $ThisFileInfo['error'][] = 'Mastroka parsing not enabled in this version of getID3()'; + return false; + + } + + + function EBML2Int($EBMLstring) { + // http://matroska.org/specs/ + + // Element ID coded with an UTF-8 like system: + // 1xxx xxxx - Class A IDs (2^7 -2 possible values) (base 0x8X) + // 01xx xxxx xxxx xxxx - Class B IDs (2^14-2 possible values) (base 0x4X 0xXX) + // 001x xxxx xxxx xxxx xxxx xxxx - Class C IDs (2^21-2 possible values) (base 0x2X 0xXX 0xXX) + // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - Class D IDs (2^28-2 possible values) (base 0x1X 0xXX 0xXX 0xXX) + // Values with all x at 0 and 1 are reserved (hence the -2). + + // Data size, in octets, is also coded with an UTF-8 like system : + // 1xxx xxxx - value 0 to 2^7-2 + // 01xx xxxx xxxx xxxx - value 0 to 2^14-2 + // 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2 + // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2 + // 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2 + // 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2 + // 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2 + // 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2 + + if (0x80 & ord($EBMLstring{0})) { + $EBMLstring{0} = chr(ord($EBMLstring{0}) & 0x7F); + } elseif (0x40 & ord($EBMLstring{0})) { + $EBMLstring{0} = chr(ord($EBMLstring{0}) & 0x3F); + } elseif (0x20 & ord($EBMLstring{0})) { + $EBMLstring{0} = chr(ord($EBMLstring{0}) & 0x1F); + } elseif (0x10 & ord($EBMLstring{0})) { + $EBMLstring{0} = chr(ord($EBMLstring{0}) & 0x0F); + } elseif (0x08 & ord($EBMLstring{0})) { + $EBMLstring{0} = chr(ord($EBMLstring{0}) & 0x07); + } elseif (0x04 & ord($EBMLstring{0})) { + $EBMLstring{0} = chr(ord($EBMLstring{0}) & 0x03); + } elseif (0x02 & ord($EBMLstring{0})) { + $EBMLstring{0} = chr(ord($EBMLstring{0}) & 0x01); + } elseif (0x01 & ord($EBMLstring{0})) { + $EBMLstring{0} = chr(ord($EBMLstring{0}) & 0x00); + } else { + return false; + } + return getid3_lib::BigEndian2Int($EBMLstring); + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.mpeg.php b/plugins/getId3Plugin/lib/module.audio-video.mpeg.php new file mode 100644 index 0000000..612478f --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.mpeg.php @@ -0,0 +1,324 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio-video.mpeg.php | +// | Module for analyzing MPEG files | +// | dependencies: module.audio.mp3.php | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio-video.mpeg.php,v 1.2 2006/06/24 22:58:30 ah Exp $ + + + +class getid3_mpeg extends getid3_handler +{ + + const VIDEO_PICTURE_START = "\x00\x00\x01\x00"; + const VIDEO_USER_DATA_START = "\x00\x00\x01\xB2"; + const VIDEO_SEQUENCE_HEADER = "\x00\x00\x01\xB3"; + const VIDEO_SEQUENCE_ERROR = "\x00\x00\x01\xB4"; + const VIDEO_EXTENSION_START = "\x00\x00\x01\xB5"; + const VIDEO_SEQUENCE_END = "\x00\x00\x01\xB7"; + const VIDEO_GROUP_START = "\x00\x00\x01\xB8"; + const AUDIO_START = "\x00\x00\x01\xC0"; + + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['mpeg']['video']['raw'] = array (); + $info_mpeg_video = &$getid3->info['mpeg']['video']; + $info_mpeg_video_raw = &$info_mpeg_video['raw']; + + $getid3->info['video'] = array (); + $info_video = &$getid3->info['video']; + + $getid3->include_module('audio.mp3'); + + if ($getid3->info['avdataend'] <= $getid3->info['avdataoffset']) { + throw new getid3_exception('"avdataend" ('.$getid3->info['avdataend'].') is unexpectedly less-than-or-equal-to "avdataoffset" ('.$getid3->info['avdataoffset'].')'); + } + + $getid3->info['fileformat'] = 'mpeg'; + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $mpeg_stream_data = fread($getid3->fp, min(100000, $getid3->info['avdataend'] - $getid3->info['avdataoffset'])); + $mpeg_stream_data_length = strlen($mpeg_stream_data); + + $video_chunk_offset = 0; + while (substr($mpeg_stream_data, $video_chunk_offset++, 4) !== getid3_mpeg::VIDEO_SEQUENCE_HEADER) { + if ($video_chunk_offset >= $mpeg_stream_data_length) { + throw new getid3_exception('Could not find start of video block in the first 100,000 bytes (or before end of file) - this might not be an MPEG-video file?'); + } + } + + // Start code 32 bits + // horizontal frame size 12 bits + // vertical frame size 12 bits + // pixel aspect ratio 4 bits + // frame rate 4 bits + // bitrate 18 bits + // marker bit 1 bit + // VBV buffer size 10 bits + // constrained parameter flag 1 bit + // intra quant. matrix flag 1 bit + // intra quant. matrix values 512 bits (present if matrix flag == 1) + // non-intra quant. matrix flag 1 bit + // non-intra quant. matrix values 512 bits (present if matrix flag == 1) + + $info_video['dataformat'] = 'mpeg'; + + $video_chunk_offset += (strlen(getid3_mpeg::VIDEO_SEQUENCE_HEADER) - 1); + + $frame_size_dword = getid3_lib::BigEndian2Int(substr($mpeg_stream_data, $video_chunk_offset, 3)); + $video_chunk_offset += 3; + + $aspect_ratio_frame_rate_dword = getid3_lib::BigEndian2Int(substr($mpeg_stream_data, $video_chunk_offset, 1)); + $video_chunk_offset += 1; + + $assorted_information = getid3_lib::BigEndian2Bin(substr($mpeg_stream_data, $video_chunk_offset, 4)); + $video_chunk_offset += 4; + + $info_mpeg_video_raw['framesize_horizontal'] = ($frame_size_dword & 0xFFF000) >> 12; // 12 bits for horizontal frame size + $info_mpeg_video_raw['framesize_vertical'] = ($frame_size_dword & 0x000FFF); // 12 bits for vertical frame size + $info_mpeg_video_raw['pixel_aspect_ratio'] = ($aspect_ratio_frame_rate_dword & 0xF0) >> 4; + $info_mpeg_video_raw['frame_rate'] = ($aspect_ratio_frame_rate_dword & 0x0F); + + $info_mpeg_video['framesize_horizontal'] = $info_mpeg_video_raw['framesize_horizontal']; + $info_mpeg_video['framesize_vertical'] = $info_mpeg_video_raw['framesize_vertical']; + + $info_mpeg_video['pixel_aspect_ratio'] = $this->MPEGvideoAspectRatioLookup($info_mpeg_video_raw['pixel_aspect_ratio']); + $info_mpeg_video['pixel_aspect_ratio_text'] = $this->MPEGvideoAspectRatioTextLookup($info_mpeg_video_raw['pixel_aspect_ratio']); + $info_mpeg_video['frame_rate'] = $this->MPEGvideoFramerateLookup($info_mpeg_video_raw['frame_rate']); + + $info_mpeg_video_raw['bitrate'] = bindec(substr($assorted_information, 0, 18)); + $info_mpeg_video_raw['marker_bit'] = (bool)bindec($assorted_information{18}); + $info_mpeg_video_raw['vbv_buffer_size'] = bindec(substr($assorted_information, 19, 10)); + $info_mpeg_video_raw['constrained_param_flag'] = (bool)bindec($assorted_information{29}); + $info_mpeg_video_raw['intra_quant_flag'] = (bool)bindec($assorted_information{30}); + + if ($info_mpeg_video_raw['intra_quant_flag']) { + + // read 512 bits + $info_mpeg_video_raw['intra_quant'] = getid3_lib::BigEndian2Bin(substr($mpeg_stream_data, $video_chunk_offset, 64)); + $video_chunk_offset += 64; + + $info_mpeg_video_raw['non_intra_quant_flag'] = (bool)bindec($info_mpeg_video_raw['intra_quant']{511}); + $info_mpeg_video_raw['intra_quant'] = bindec($assorted_information{31}).substr(getid3_lib::BigEndian2Bin(substr($mpeg_stream_data, $video_chunk_offset, 64)), 0, 511); + + if ($info_mpeg_video_raw['non_intra_quant_flag']) { + $info_mpeg_video_raw['non_intra_quant'] = substr($mpeg_stream_data, $video_chunk_offset, 64); + $video_chunk_offset += 64; + } + + } else { + + $info_mpeg_video_raw['non_intra_quant_flag'] = (bool)bindec($assorted_information{31}); + if ($info_mpeg_video_raw['non_intra_quant_flag']) { + $info_mpeg_video_raw['non_intra_quant'] = substr($mpeg_stream_data, $video_chunk_offset, 64); + $video_chunk_offset += 64; + } + } + + if ($info_mpeg_video_raw['bitrate'] == 0x3FFFF) { // 18 set bits + + $getid3->warning('This version of getID3() cannot determine average bitrate of VBR MPEG video files'); + $info_mpeg_video['bitrate_mode'] = 'vbr'; + + } else { + + $info_mpeg_video['bitrate'] = $info_mpeg_video_raw['bitrate'] * 400; + $info_mpeg_video['bitrate_mode'] = 'cbr'; + $info_video['bitrate'] = $info_mpeg_video['bitrate']; + } + + $info_video['resolution_x'] = $info_mpeg_video['framesize_horizontal']; + $info_video['resolution_y'] = $info_mpeg_video['framesize_vertical']; + $info_video['frame_rate'] = $info_mpeg_video['frame_rate']; + $info_video['bitrate_mode'] = $info_mpeg_video['bitrate_mode']; + $info_video['pixel_aspect_ratio'] = $info_mpeg_video['pixel_aspect_ratio']; + $info_video['lossless'] = false; + $info_video['bits_per_sample'] = 24; + + + //0x000001B3 begins the sequence_header of every MPEG video stream. + //But in MPEG-2, this header must immediately be followed by an + //extension_start_code (0x000001B5) with a sequence_extension ID (1). + //(This extension contains all the additional MPEG-2 stuff.) + //MPEG-1 doesn't have this extension, so that's a sure way to tell the + //difference between MPEG-1 and MPEG-2 video streams. + + $info_video['codec'] = substr($mpeg_stream_data, $video_chunk_offset, 4) == getid3_mpeg::VIDEO_EXTENSION_START ? 'MPEG-2' : 'MPEG-1'; + + $audio_chunk_offset = 0; + while (true) { + while (substr($mpeg_stream_data, $audio_chunk_offset++, 4) !== getid3_mpeg::AUDIO_START) { + if ($audio_chunk_offset >= $mpeg_stream_data_length) { + break 2; + } + } + + for ($i = 0; $i <= 7; $i++) { + // some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it up to 13 bytes (or more?) after + // I have no idea why or what the difference is, so this is a stupid hack. + // If anybody has any better idea of what's going on, please let me know - info@getid3.org + + // make copy of info + $dummy = $getid3->info; + + // clone getid3 - better safe than sorry + $clone = clone $this->getid3; + + // check + $mp3 = new getid3_mp3($clone); + if ($mp3->decodeMPEGaudioHeader($getid3->fp, ($audio_chunk_offset + 3) + 8 + $i, $dummy, false)) { + + $getid3->info = $dummy; + $getid3->info['audio']['bitrate_mode'] = 'cbr'; + $getid3->info['audio']['lossless'] = false; + break 2; + } + + // destroy copy + unset($dummy); + } + } + + // Temporary hack to account for interleaving overhead: + if (!empty($info_video['bitrate']) && !empty($getid3->info['audio']['bitrate'])) { + $getid3->info['playtime_seconds'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / ($info_video['bitrate'] + $getid3->info['audio']['bitrate']); + + // Interleaved MPEG audio/video files have a certain amount of overhead that varies + // by both video and audio bitrates, and not in any sensible, linear/logarithmic patter + // Use interpolated lookup tables to approximately guess how much is overhead, because + // playtime is calculated as filesize / total-bitrate + $getid3->info['playtime_seconds'] *= $this->MPEGsystemNonOverheadPercentage($info_video['bitrate'], $getid3->info['audio']['bitrate']); + + //switch ($info_video['bitrate']) { + // case('5000000'): + // $multiplier = 0.93292642112380355828048824319889; + // break; + // case('5500000'): + // $multiplier = 0.93582895375200989965359777343219; + // break; + // case('6000000'): + // $multiplier = 0.93796247714820932532911373859139; + // break; + // case('7000000'): + // $multiplier = 0.9413264083635103463010117778776; + // break; + // default: + // $multiplier = 1; + // break; + //} + //$getid3->info['playtime_seconds'] *= $multiplier; + //$getid3->warning('Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.'); + + if ($info_video['bitrate'] < 50000) { + $getid3->warning('Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.'); + } + } + + return true; + } + + + + public static function MPEGsystemNonOverheadPercentage($video_bitrate, $audio_bitrate) { + + $overhead_percentage = 0; + + $audio_bitrate = max(min($audio_bitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?) + $video_bitrate = max(min($video_bitrate / 1000, 10000), 10); // limit to range of 10kbps - 10Mbps (beyond that curves flatten anyways, no big loss) + + //OMBB[audiobitrate] = array ( video-10kbps, video-100kbps, video-1000kbps, video-10000kbps) + static $overhead_multiplier_by_bitrate = array ( + 32 => array (0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940), + 48 => array (0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960), + 56 => array (0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340), + 64 => array (0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470), + 96 => array (0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690), + 128 => array (0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050), + 160 => array (0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570), + 192 => array (0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620), + 224 => array (0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480), + 256 => array (0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790), + 320 => array (0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190), + 384 => array (0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890) + ); + + $bitrate_to_use_min = $bitrate_to_use_max = $previous_bitrate = 32; + + foreach ($overhead_multiplier_by_bitrate as $key => $value) { + + if ($audio_bitrate >= $previous_bitrate) { + $bitrate_to_use_min = $previous_bitrate; + } + if ($audio_bitrate < $key) { + $bitrate_to_use_max = $key; + break; + } + $previous_bitrate = $key; + } + + $factor_a = ($bitrate_to_use_max - $audio_bitrate) / ($bitrate_to_use_max - $bitrate_to_use_min); + + $video_bitrate_log10 = log10($video_bitrate); + $video_factor_min1 = $overhead_multiplier_by_bitrate[$bitrate_to_use_min][floor($video_bitrate_log10)]; + $video_factor_min2 = $overhead_multiplier_by_bitrate[$bitrate_to_use_max][floor($video_bitrate_log10)]; + $video_factor_max1 = $overhead_multiplier_by_bitrate[$bitrate_to_use_min][ceil($video_bitrate_log10)]; + $video_factor_max2 = $overhead_multiplier_by_bitrate[$bitrate_to_use_max][ceil($video_bitrate_log10)]; + $factor_v = $video_bitrate_log10 - floor($video_bitrate_log10); + + $overhead_percentage = $video_factor_min1 * $factor_a * $factor_v; + $overhead_percentage += $video_factor_min2 * (1 - $factor_a) * $factor_v; + $overhead_percentage += $video_factor_max1 * $factor_a * (1 - $factor_v); + $overhead_percentage += $video_factor_max2 * (1 - $factor_a) * (1 - $factor_v); + + return $overhead_percentage; + } + + + + public static function MPEGvideoFramerateLookup($raw_frame_rate) { + + $lookup = array (0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60); + + return (float)(isset($lookup[$raw_frame_rate]) ? $lookup[$raw_frame_rate] : 0); + } + + + + public static function MPEGvideoAspectRatioLookup($raw_aspect_ratio) { + + $lookup = array (0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0); + + return (float)(isset($lookup[$raw_aspect_ratio]) ? $lookup[$raw_aspect_ratio] : 0); + } + + + + public static function MPEGvideoAspectRatioTextLookup($raw_aspect_ratio) { + + $lookup = array ('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved'); + + return (isset($lookup[$raw_aspect_ratio]) ? $lookup[$raw_aspect_ratio] : ''); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.nsv.php b/plugins/getId3Plugin/lib/module.audio-video.nsv.php new file mode 100644 index 0000000..a134d98 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.nsv.php @@ -0,0 +1,210 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio-video.nsv.php | +// | module for analyzing Nullsoft NSV files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio-video.nsv.php,v 1.2 2004/11/01 03:11:16 ah Exp $ + + + +class getid3_nsv extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['fileformat'] = 'nsv'; + $getid3->info['audio']['dataformat'] = 'nsv'; + $getid3->info['video']['dataformat'] = 'nsv'; + $getid3->info['audio']['lossless'] = false; + $getid3->info['video']['lossless'] = false; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $nsv_header = fread($getid3->fp, 4); + + switch ($nsv_header) { + + case 'NSVs': + $this->getNSVsHeader(); + break; + + case 'NSVf': + if ($this->getNSVfHeader()) { + $this->getNSVsHeader($getid3->info['nsv']['NSVf']['header_length']); + } + break; + + default: + throw new getid3_exception('Expecting "NSVs" or "NSVf" at offset '.$getid3->info['avdataoffset'].', found "'.$nsv_header.'"'); + break; + } + + if (!isset($getid3->info['nsv']['NSVf'])) { + $getid3->warning('NSVf header not present - cannot calculate playtime or bitrate'); + } + + return true; + } + + + + private function getNSVsHeader($file_offset = 0) { + + $getid3 = $this->getid3; + + fseek($getid3->fp, $file_offset, SEEK_SET); + $nsvs_header = fread($getid3->fp, 28); + + $getid3->info['nsv']['NSVs'] = array (); + $info_nsv_NSVs = &$getid3->info['nsv']['NSVs']; + + $info_nsv_NSVs['identifier'] = substr($nsvs_header, 0, 4); + if ($info_nsv_NSVs['identifier'] != 'NSVs') { + throw new getid3_exception('expected "NSVs" at offset ('.$file_offset.'), found "'.$info_nsv_NSVs['identifier'].'" instead'); + } + + $info_nsv_NSVs['offset'] = $file_offset; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_nsv_NSVs, $nsvs_header, 4, + array ( + 'video_codec' => -4, // string + 'audio_codec' => -4, // string + 'resolution_x' => 2, + 'resolution_y' => 2, + 'framerate_index' => 1, + ) + ); + + if ($info_nsv_NSVs['audio_codec'] == 'PCM ') { + + getid3_lib::ReadSequence('LittleEndian2Int', $info_nsv_NSVs, $nsvs_header, 24, + array ( + 'bits_channel' => 1, + 'channels' => 1, + 'sample_rate' => 2 + ) + ); + $getid3->info['audio']['sample_rate'] = $info_nsv_NSVs['sample_rate']; + + } + + $getid3->info['video']['resolution_x'] = $info_nsv_NSVs['resolution_x']; + $getid3->info['video']['resolution_y'] = $info_nsv_NSVs['resolution_y']; + $info_nsv_NSVs['frame_rate'] = getid3_nsv::NSVframerateLookup($info_nsv_NSVs['framerate_index']); + $getid3->info['video']['frame_rate'] = $info_nsv_NSVs['frame_rate']; + $getid3->info['video']['bits_per_sample'] = 24; + $getid3->info['video']['pixel_aspect_ratio'] = (float)1; + + return true; + } + + + + private function getNSVfHeader($file_offset = 0, $get_toc_offsets=false) { + + $getid3 = $this->getid3; + + fseek($getid3->fp, $file_offset, SEEK_SET); + $nsvf_header = fread($getid3->fp, 28); + + $getid3->info['nsv']['NSVf'] = array (); + $info_nsv_NSVf = &$getid3->info['nsv']['NSVf']; + + $info_nsv_NSVf['identifier'] = substr($nsvf_header, 0, 4); + if ($info_nsv_NSVf['identifier'] != 'NSVf') { + throw new getid3_exception('expected "NSVf" at offset ('.$file_offset.'), found "'.$info_nsv_NSVf['identifier'].'" instead'); + } + + $getid3->info['nsv']['NSVs']['offset'] = $file_offset; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_nsv_NSVf, $nsvf_header, 4, + array ( + 'header_length' => 4, + 'file_size' => 4, + 'playtime_ms' => 4, + 'meta_size' => 4, + 'TOC_entries_1' => 4, + 'TOC_entries_2' => 4 + ) + ); + + if ($info_nsv_NSVf['playtime_ms'] == 0) { + throw new getid3_exception('Corrupt NSV file: NSVf.playtime_ms == zero'); + } + + if ($info_nsv_NSVf['file_size'] > $getid3->info['avdataend']) { + $getid3->warning('truncated file - NSVf header indicates '.$info_nsv_NSVf['file_size'].' bytes, file actually '.$getid3->info['avdataend'].' bytes'); + } + + $nsvf_header .= fread($getid3->fp, $info_nsv_NSVf['meta_size'] + (4 * $info_nsv_NSVf['TOC_entries_1']) + (4 * $info_nsv_NSVf['TOC_entries_2'])); + $nsvf_headerlength = strlen($nsvf_header); + $info_nsv_NSVf['metadata'] = substr($nsvf_header, 28, $info_nsv_NSVf['meta_size']); + + $offset = 28 + $info_nsv_NSVf['meta_size']; + if ($get_toc_offsets) { + $toc_counter = 0; + while ($toc_counter < $info_nsv_NSVf['TOC_entries_1']) { + if ($toc_counter < $info_nsv_NSVf['TOC_entries_1']) { + $info_nsv_NSVf['TOC_1'][$toc_counter] = getid3_lib::LittleEndian2Int(substr($nsvf_header, $offset, 4)); + $offset += 4; + $toc_counter++; + } + } + } + + if (trim($info_nsv_NSVf['metadata']) != '') { + $info_nsv_NSVf['metadata'] = str_replace('`', "\x01", $info_nsv_NSVf['metadata']); + $comment_pair_array = explode("\x01".' ', $info_nsv_NSVf['metadata']); + foreach ($comment_pair_array as $comment_pair) { + if (strstr($comment_pair, '='."\x01")) { + list($key, $value) = explode('='."\x01", $comment_pair, 2); + $getid3->info['nsv']['comments'][strtolower($key)][] = trim(str_replace("\x01", '', $value)); + } + } + } + + $getid3->info['playtime_seconds'] = $info_nsv_NSVf['playtime_ms'] / 1000; + $getid3->info['bitrate'] = ($info_nsv_NSVf['file_size'] * 8) / $getid3->info['playtime_seconds']; + + return true; + } + + + + public static function NSVframerateLookup($frame_rate_index) { + + if ($frame_rate_index <= 127) { + return (float)$frame_rate_index; + } + + static $lookup = array ( + 129 => 29.970, + 131 => 23.976, + 133 => 14.985, + 197 => 59.940, + 199 => 47.952 + ); + return (isset($lookup[$frame_rate_index]) ? $lookup[$frame_rate_index] : false); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.quicktime.php b/plugins/getId3Plugin/lib/module.audio-video.quicktime.php new file mode 100644 index 0000000..53d1f4b --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.quicktime.php @@ -0,0 +1,1528 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio-video.quicktime.php | +// | Module for analyzing Quicktime, MP3-in-MP4 and Apple Lossless files. | +// | dependencies: module.audio.mp3.php | +// | zlib support in PHP (optional) | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio-video.quicktime.php,v 1.4 2006/06/13 08:44:50 ah Exp $ + + + +class getid3_quicktime extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $info = &$getid3->info; + + $getid3->include_module('audio.mp3'); + + $info['quicktime'] = array (); + $info_quicktime = &$info['quicktime']; + + $info['fileformat'] = 'quicktime'; + $info_quicktime['hinting'] = false; + + fseek($getid3->fp, $info['avdataoffset'], SEEK_SET); + + $offset = $atom_counter = 0; + + while ($offset < $info['avdataend']) { + + fseek($getid3->fp, $offset, SEEK_SET); + $atom_header = fread($getid3->fp, 8); + + $atom_size = getid3_lib::BigEndian2Int(substr($atom_header, 0, 4)); + $atom_name = substr($atom_header, 4, 4); + + $info_quicktime[$atom_name]['name'] = $atom_name; + $info_quicktime[$atom_name]['size'] = $atom_size; + $info_quicktime[$atom_name]['offset'] = $offset; + + if (($offset + $atom_size) > $info['avdataend']) { + throw new getid3_exception('Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atom_size.' bytes)'); + } + + if ($atom_size == 0) { + // Furthermore, for historical reasons the list of atoms is optionally + // terminated by a 32-bit integer set to 0. If you are writing a program + // to read user data atoms, you should allow for the terminating 0. + break; + } + + switch ($atom_name) { + + case 'mdat': // Media DATa atom + // 'mdat' contains the actual data for the audio/video + if (($atom_size > 8) && (!isset($info['avdataend_tmp']) || ($info_quicktime[$atom_name]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) { + + $info['avdataoffset'] = $info_quicktime[$atom_name]['offset'] + 8; + $old_av_data_end = $info['avdataend']; + $info['avdataend'] = $info_quicktime[$atom_name]['offset'] + $info_quicktime[$atom_name]['size']; + + + //// MP3 + + if (!$getid3->include_module_optional('audio.mp3')) { + $getid3->warning('MP3 skipped because mpeg module is missing.'); + } + + else { + + // Clone getid3 - messing with offsets - better safe than sorry + $clone = clone $getid3; + + if (getid3_mp3::MPEGaudioHeaderValid(getid3_mp3::MPEGaudioHeaderDecode(fread($clone->fp, 4)))) { + + $mp3 = new getid3_mp3($clone); + $mp3->AnalyzeMPEGaudioInfo(); + + // Import from clone and destroy + if (isset($clone->info['mpeg']['audio'])) { + + $info['mpeg']['audio'] = $clone->info['mpeg']['audio']; + + $info['audio']['dataformat'] = 'mp3'; + $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3'))); + $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; + $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); + $info['bitrate'] = $info['audio']['bitrate']; + + $getid3->warning($clone->warnings()); + unset($clone); + } + } + } + + $info['avdataend'] = $old_av_data_end; + unset($old_av_data_end); + + } + break; + + + case 'free': // FREE space atom + case 'skip': // SKIP atom + case 'wide': // 64-bit expansion placeholder atom + // 'free', 'skip' and 'wide' are just padding, contains no useful data at all + break; + + + default: + $atom_hierarchy = array (); + $info_quicktime[$atom_name] = $this->QuicktimeParseAtom($atom_name, $atom_size, fread($getid3->fp, $atom_size), $offset, $atom_hierarchy); + break; + } + + $offset += $atom_size; + $atom_counter++; + } + + if (!empty($info['avdataend_tmp'])) { + // this value is assigned to a temp value and then erased because + // otherwise any atoms beyond the 'mdat' atom would not get parsed + $info['avdataend'] = $info['avdataend_tmp']; + unset($info['avdataend_tmp']); + } + + if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) { + $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + } + + if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info_quicktime['video'])) { + $info['audio']['bitrate'] = $info['bitrate']; + } + + if ((@$info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) { + $info['fileformat'] = 'mp4'; + $info['mime_type'] = 'audio/mp4'; + unset($info['video']['dataformat']); + } + + if (!$getid3->option_extra_info) { + unset($info_quicktime['moov']); + } + + if (empty($info['audio']['dataformat']) && !empty($info_quicktime['audio'])) { + $info['audio']['dataformat'] = 'quicktime'; + } + + if (empty($info['video']['dataformat']) && !empty($info_quicktime['video'])) { + $info['video']['dataformat'] = 'quicktime'; + } + + return true; + } + + + + private function QuicktimeParseAtom($atom_name, $atom_size, $atom_data, $base_offset, &$atom_hierarchy) { + + // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm + + $getid3 = $this->getid3; + + $info = &$getid3->info; + $info_quicktime = &$info['quicktime']; + + array_push($atom_hierarchy, $atom_name); + $atom_structure['hierarchy'] = implode(' ', $atom_hierarchy); + $atom_structure['name'] = $atom_name; + $atom_structure['size'] = $atom_size; + $atom_structure['offset'] = $base_offset; + + switch ($atom_name) { + case 'moov': // MOVie container atom + case 'trak': // TRAcK container atom + case 'clip': // CLIPping container atom + case 'matt': // track MATTe container atom + case 'edts': // EDiTS container atom + case 'tref': // Track REFerence container atom + case 'mdia': // MeDIA container atom + case 'minf': // Media INFormation container atom + case 'dinf': // Data INFormation container atom + case 'udta': // User DaTA container atom + case 'stbl': // Sample TaBLe container atom + case 'cmov': // Compressed MOVie container atom + case 'rmra': // Reference Movie Record Atom + case 'rmda': // Reference Movie Descriptor Atom + case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR) + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $base_offset + 8, $atom_hierarchy); + break; + + + case 'cpy': + case 'day': + case 'dir': + case 'ed1': + case 'ed2': + case 'ed3': + case 'ed4': + case 'ed5': + case 'ed6': + case 'ed7': + case 'ed8': + case 'ed9': + case 'fmt': + case 'inf': + case 'prd': + case 'prf': + case 'req': + case 'src': + case 'wrt': + case 'nam': + case 'cmt': + case 'wrn': + case 'hst': + case 'mak': + case 'mod': + case 'PRD': + case 'swr': + case 'aut': + case 'ART': + case 'trk': + case 'alb': + case 'com': + case 'gen': + case 'ope': + case 'url': + case 'enc': + $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); + $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); + $atom_structure['data'] = substr($atom_data, 4); + + $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); + if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { + $info['comments']['language'][] = $atom_structure['language']; + } + $this->CopyToAppropriateCommentsSection($atom_name, $atom_structure['data']); + break; + + + case 'play': // auto-PLAY atom + $atom_structure['autoplay'] = (bool)getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + + $info_quicktime['autoplay'] = $atom_structure['autoplay']; + break; + + + case 'WLOC': // Window LOCation atom + $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); + $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); + break; + + + case 'LOOP': // LOOPing atom + case 'SelO': // play SELection Only atom + case 'AllF': // play ALL Frames atom + $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data); + break; + + + case 'name': // + case 'MCPS': // Media Cleaner PRo + case '@PRM': // adobe PReMiere version + case '@PRQ': // adobe PRemiere Quicktime version + $atom_structure['data'] = $atom_data; + break; + + + case 'cmvd': // Compressed MooV Data atom + // Code by ubergeekubergeek*tv based on information from + // http://developer.apple.com/quicktime/icefloe/dispatch012.html + $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); + + $compressed_file_data = substr($atom_data, 4); + if (!function_exists('gzuncompress')) { + $getid3->warning('PHP does not have zlib support - cannot decompress MOV atom at offset '.$atom_structure['offset']); + } + elseif ($uncompressed_header = @gzuncompress($compressed_file_data)) { + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($uncompressed_header, 0, $atom_hierarchy); + } else { + $getid3->warning('Error decompressing compressed MOV atom at offset '.$atom_structure['offset']); + } + break; + + + case 'dcom': // Data COMpression atom + $atom_structure['compression_id'] = $atom_data; + $atom_structure['compression_text'] = getid3_quicktime::QuicktimeDCOMLookup($atom_data); + break; + + + case 'rdrf': // Reference movie Data ReFerence atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, + 'reference_type_name' => -4, + 'reference_length' => 4, + ) + ); + + $atom_structure['flags']['internal_data'] = (bool)($atom_structure['flags_raw'] & 0x000001); + + switch ($atom_structure['reference_type_name']) { + case 'url ': + $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12)); + break; + + case 'alis': + $atom_structure['file_alias'] = substr($atom_data, 12); + break; + + case 'rsrc': + $atom_structure['resource_alias'] = substr($atom_data, 12); + break; + + default: + $atom_structure['data'] = substr($atom_data, 12); + break; + } + break; + + + case 'rmqu': // Reference Movie QUality atom + $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data); + break; + + + case 'rmcs': // Reference Movie Cpu Speed atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'cpu_speed_rating' => 2 + ) + ); + break; + + + case 'rmvc': // Reference Movie Version Check atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'gestalt_selector' => -4, + 'gestalt_value_mask' => 4, + 'gestalt_value' => 4, + 'gestalt_check_type' => 2 + ) + ); + break; + + + case 'rmcd': // Reference Movie Component check atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'component_type' => -4, + 'component_subtype' => -4, + 'component_manufacturer' => -4, + 'component_flags_raw' => 4, + 'component_flags_mask' => 4, + 'component_min_version' => 4 + ) + ); + break; + + + case 'rmdr': // Reference Movie Data Rate atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'data_rate' => 4 + ) + ); + + $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10; + break; + + + case 'rmla': // Reference Movie Language Atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'language_id' => 2 + ) + ); + + $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); + if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { + $info['comments']['language'][] = $atom_structure['language']; + } + break; + + + case 'rmla': // Reference Movie Language Atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'track_id' => 2 + ) + ); + break; + + + case 'ptv ': // Print To Video - defines a movie's full screen mode + // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'display_size_raw' => 2, + 'reserved_1' => 2, // hardcoded: 0x0000 + 'reserved_2' => 2, // hardcoded: 0x0000 + 'slide_show_flag' => 1, + 'play_on_open_flag' => 1 + ) + ); + + $atom_structure['flags']['play_on_open'] = (bool)$atom_structure['play_on_open_flag']; + $atom_structure['flags']['slide_show'] = (bool)$atom_structure['slide_show_flag']; + + $ptv_lookup[0] = 'normal'; + $ptv_lookup[1] = 'double'; + $ptv_lookup[2] = 'half'; + $ptv_lookup[3] = 'full'; + $ptv_lookup[4] = 'current'; + if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { + $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; + } else { + $getid3->warning('unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')'); + } + break; + + + case 'stsd': // Sample Table Sample Description atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'number_entries' => 4 + ) + ); + $stsd_entries_data_offset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_data, $stsd_entries_data_offset, + array ( + 'size' => 4, + 'data_format' => -4, + 'reserved' => 6, + 'reference_index' => 2 + ) + ); + + $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, 16+$stsd_entries_data_offset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); + $stsd_entries_data_offset += 16 + ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); + + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_structure['sample_description_table'][$i]['data'], 0, + array ( + 'encoder_version' => 2, + 'encoder_revision' => 2, + 'encoder_vendor' => -4 + ) + ); + + switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) { + + case "\x00\x00\x00\x00": + // audio atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_structure['sample_description_table'][$i]['data'], 8, + array ( + 'audio_channels' => 2, + 'audio_bit_depth' => 2, + 'audio_compression_id' => 2, + 'audio_packet_size' => 2 + ) + ); + + $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_quicktime::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4)); + + switch ($atom_structure['sample_description_table'][$i]['data_format']) { + + case 'mp4v': + $info['fileformat'] = 'mp4'; + throw new getid3_exception('This version of getID3() does not fully support MPEG-4 audio/video streams'); + + case 'qtvr': + $info['video']['dataformat'] = 'quicktimevr'; + break; + + case 'mp4a': + default: + $info_quicktime['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); + $info_quicktime['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; + $info_quicktime['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; + $info_quicktime['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth']; + $info['audio']['codec'] = $info_quicktime['audio']['codec']; + $info['audio']['sample_rate'] = $info_quicktime['audio']['sample_rate']; + $info['audio']['channels'] = $info_quicktime['audio']['channels']; + $info['audio']['bits_per_sample'] = $info_quicktime['audio']['bit_depth']; + switch ($atom_structure['sample_description_table'][$i]['data_format']) { + case 'raw ': // PCM + case 'alac': // Apple Lossless Audio Codec + $info['audio']['lossless'] = true; + break; + default: + $info['audio']['lossless'] = false; + break; + } + break; + } + break; + + default: + switch ($atom_structure['sample_description_table'][$i]['data_format']) { + case 'mp4s': + $info['fileformat'] = 'mp4'; + break; + + default: + // video atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_structure['sample_description_table'][$i]['data'], 8, + array ( + 'video_temporal_quality' => 4, + 'video_spatial_quality' => 4, + 'video_frame_width' => 2, + 'video_frame_height' => 2 + ) + ); + $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_quicktime::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4)); + $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_quicktime::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['sample_description_table'][$i], $atom_structure['sample_description_table'][$i]['data'], 28, + array ( + 'video_data_size' => 4, + 'video_frame_count' => 2, + 'video_encoder_name_len' => 1 + ) + ); + $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']); + $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2)); + $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); + + $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); + $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); + + if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') { + $info_quicktime['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; + $info_quicktime['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); + $info_quicktime['video']['codec'] = $atom_structure['sample_description_table'][$i]['video_encoder_name']; + $info_quicktime['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; + $info_quicktime['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; + + $info['video']['codec'] = $info_quicktime['video']['codec']; + $info['video']['bits_per_sample'] = $info_quicktime['video']['color_depth']; + } + $info['video']['lossless'] = false; + $info['video']['pixel_aspect_ratio'] = (float)1; + break; + } + break; + } + switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) { + case 'mp4a': + $info['audio']['dataformat'] = $info_quicktime['audio']['codec'] = 'mp4'; + break; + + case '3ivx': + case '3iv1': + case '3iv2': + $info['video']['dataformat'] = '3ivx'; + break; + + case 'xvid': + $info['video']['dataformat'] = 'xvid'; + break; + + case 'mp4v': + $info['video']['dataformat'] = 'mpeg4'; + break; + + case 'divx': + case 'div1': + case 'div2': + case 'div3': + case 'div4': + case 'div5': + case 'div6': + //$TDIVXileInfo['video']['dataformat'] = 'divx'; + break; + + default: + // do nothing + break; + } + unset($atom_structure['sample_description_table'][$i]['data']); + } + break; + + + case 'stts': // Sample Table Time-to-Sample atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'number_entries' => 4 + ) + ); + + $stts_entries_data_offset = 8; + $frame_rate_calculator_array = array (); + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + + $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $stts_entries_data_offset, 4)); + $stts_entries_data_offset += 4; + + $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $stts_entries_data_offset, 4)); + $stts_entries_data_offset += 4; + + if (!empty($info_quicktime['time_scale']) && (@$atoms_tructure['time_to_sample_table'][$i]['sample_duration'] > 0)) { + + $stts_new_framerate = $info_quicktime['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration']; + if ($stts_new_framerate <= 60) { + // some atoms have durations of "1" giving a very large framerate, which probably is not right + $info['video']['frame_rate'] = max(@$info['video']['frame_rate'], $stts_new_framerate); + } + } + //@$frame_rate_calculator_array[($info_quicktime['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count']; + } + /* + $stts_frames_total = 0; + $stts_seconds_total = 0; + foreach ($frame_rate_calculator_array as $frames_per_second => $frame_count) { + if (($frames_per_second > 60) || ($frames_per_second < 1)) { + // not video FPS information, probably audio information + $stts_frames_total = 0; + $stts_seconds_total = 0; + break; + } + $stts_frames_total += $frame_count; + $stts_seconds_total += $frame_count / $frames_per_second; + } + if (($stts_frames_total > 0) && ($stts_seconds_total > 0)) { + if (($stts_frames_total / $stts_seconds_total) > @$info['video']['frame_rate']) { + $info['video']['frame_rate'] = $stts_frames_total / $stts_seconds_total; + } + } + */ + break; + + + case 'stss': // Sample Table Sync Sample (key frames) atom + /* + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $stss_entries_data_offset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stss_entries_data_offset, 4)); + $stss_entries_data_offset += 4; + } + */ + break; + + + case 'stsc': // Sample Table Sample-to-Chunk atom + /* + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $stsc_entries_data_offset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsc_entries_data_offset, 4)); + $stsc_entries_data_offset += 4; + $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsc_entries_data_offset, 4)); + $stsc_entries_data_offset += 4; + $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsc_entries_data_offset, 4)); + $stsc_entries_data_offset += 4; + } + */ + break; + + + case 'stsz': // Sample Table SiZe atom + /* + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); + $stsz_entries_data_offset = 12; + if ($atom_structure['sample_size'] == 0) { + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stsz_entries_data_offset, 4)); + $stsz_entries_data_offset += 4; + } + } + */ + break; + + + case 'stco': // Sample Table Chunk Offset atom + /* + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $stco_entries_data_offset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stco_entries_data_offset, 4)); + $stco_entries_data_offset += 4; + } + */ + break; + + + case 'dref': // Data REFerence atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'number_entries' => 4 + ) + ); + + $dref_data_offset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure['data_references'][$i], $atom_data, $dref_data_offset, + array ( + 'size' => 4, + 'type' => -4, + 'version' => 1, + 'flags_raw' => 3 // hardcoded: 0x0000 + ) + ); + $dref_data_offset += 12; + + $atom_structure['data_references'][$i]['data'] = substr($atom_data, $dref_data_offset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3)); + $dref_data_offset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3); + + $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool)($atom_structure['data_references'][$i]['flags_raw'] & 0x001); + } + break; + + + case 'gmin': // base Media INformation atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'graphics_mode' => 2, + 'opcolor_red' => 2, + 'opcolor_green' => 2, + 'opcolor_blue' => 2, + 'balance' => 2, + 'reserved' => 2 + ) + ); + break; + + + case 'smhd': // Sound Media information HeaDer atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'balance' => 2, + 'reserved' => 2 + ) + ); + break; + + + case 'vmhd': // Video Media information HeaDer atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, + 'graphics_mode' => 2, + 'opcolor_red' => 2, + 'opcolor_green' => 2, + 'opcolor_blue' => 2 + ) + ); + $atom_structure['flags']['no_lean_ahead'] = (bool)($atom_structure['flags_raw'] & 0x001); + break; + + + case 'hdlr': // HanDLeR reference atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'component_type' => -4, + 'component_subtype' => -4, + 'component_manufacturer' => -4, + 'component_flags_raw' => 4, + 'component_flags_mask' => 4 + ) + ); + + $atom_structure['component_name'] = substr(substr($atom_data, 24), 1); /// Pascal2String + + if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) { + $info['video']['dataformat'] = 'quicktimevr'; + } + break; + + + case 'mdhd': // MeDia HeaDer atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'creation_time' => 4, + 'modify_time' => 4, + 'time_scale' => 4, + 'duration' => 4, + 'language_id' => 2, + 'quality' => 2 + ) + ); + + if ($atom_structure['time_scale'] == 0) { + throw new getid3_exception('Corrupt Quicktime file: mdhd.time_scale == zero'); + } + + $atom_structure['creation_time_unix'] = (int)($atom_structure['creation_time'] - 2082844800); // DateMac2Unix() + $atom_structure['modify_time_unix'] = (int)($atom_structure['modify_time'] - 2082844800); // DateMac2Unix() + $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; + $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); + if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { + $info['comments']['language'][] = $atom_structure['language']; + } + break; + + + case 'pnot': // Preview atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'modification_date' => 4, // "standard Macintosh format" + 'version_number' => 2, // hardcoded: 0x00 + 'atom_type' => -4, // usually: 'PICT' + 'atom_index' => 2 // usually: 0x01 + ) + ); + $atom_structure['modification_date_unix'] = (int)($atom_structure['modification_date'] - 2082844800); // DateMac2Unix() + break; + + + case 'crgn': // Clipping ReGioN atom + $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box, + $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields + $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region. + break; + + + case 'load': // track LOAD settings atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'preload_start_time' => 4, + 'preload_duration' => 4, + 'preload_flags_raw' => 4, + 'default_hints_raw' => 4 + ) + ); + + $atom_structure['default_hints']['double_buffer'] = (bool)($atom_structure['default_hints_raw'] & 0x0020); + $atom_structure['default_hints']['high_quality'] = (bool)($atom_structure['default_hints_raw'] & 0x0100); + break; + + + case 'tmcd': // TiMe CoDe atom + case 'chap': // CHAPter list atom + case 'sync': // SYNChronization atom + case 'scpt': // tranSCriPT atom + case 'ssrc': // non-primary SouRCe atom + for ($i = 0; $i < (strlen($atom_data) % 4); $i++) { + $atom_structure['track_id'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $i * 4, 4)); + } + break; + + + case 'elst': // Edit LiST atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, // hardcoded: 0x0000 + 'number_entries' => 4 + ) + ); + + for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) { + $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4)); + $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4)); + $atom_structure['edit_list'][$i]['media_rate'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4)); + } + break; + + + case 'kmat': // compressed MATte atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['matte_data_raw'] = substr($atom_data, 4); + break; + + + case 'ctab': // Color TABle atom + $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000 + $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000 + $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1; + for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) { + $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2)); + $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2)); + $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2)); + $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2)); + } + break; + + + case 'mvhd': // MoVie HeaDer atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, + 'creation_time' => 4, + 'modify_time' => 4, + 'time_scale' => 4, + 'duration' => 4 + ) + ); + + $atom_structure['preferred_rate'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 20, 4)); + $atom_structure['preferred_volume'] = getid3_quicktime::FixedPoint8_8(substr($atom_data, 24, 2)); + $atom_structure['reserved'] = substr($atom_data, 26, 10); + $atom_structure['matrix_a'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 36, 4)); + $atom_structure['matrix_b'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 40, 4)); + $atom_structure['matrix_u'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 44, 4)); + $atom_structure['matrix_c'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 48, 4)); + $atom_structure['matrix_d'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 52, 4)); + $atom_structure['matrix_v'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 56, 4)); + $atom_structure['matrix_x'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 60, 4)); + $atom_structure['matrix_y'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 64, 4)); + $atom_structure['matrix_w'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 68, 4)); + + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 72, + array ( + 'preview_time' => 4, + 'preview_duration' => 4, + 'poster_time' => 4, + 'selection_time' => 4, + 'selection_duration' => 4, + 'current_time' => 4, + 'next_track_id' => 4 + ) + ); + + if ($atom_structure['time_scale'] == 0) { + throw new getid3_exception('Corrupt Quicktime file: mvhd.time_scale == zero'); + } + + $atom_structure['creation_time_unix'] = (int)($atom_structure['creation_time'] - 2082844800); // DateMac2Unix() + $atom_structure['modify_time_unix'] = (int)($atom_structure['modify_time'] - 2082844800); // DateMac2Unix() + $info_quicktime['time_scale'] = $atom_structure['time_scale']; + $info_quicktime['display_scale'] = $atom_structure['matrix_a']; + $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; + break; + + + case 'tkhd': // TracK HeaDer atom + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'version' => 1, + 'flags_raw' => 3, + 'creation_time' => 4, + 'modify_time' => 4, + 'trackid' => 4, + 'reserved1' => 4, + 'duration' => 4, + 'reserved2' => 8, + 'layer' => 2, + 'alternate_group' => 2 + ) + ); + + $atom_structure['volume'] = getid3_quicktime::FixedPoint8_8(substr($atom_data, 36, 2)); + $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2)); + $atom_structure['matrix_a'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 40, 4)); + $atom_structure['matrix_b'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 44, 4)); + $atom_structure['matrix_u'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 48, 4)); + $atom_structure['matrix_c'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 52, 4)); + $atom_structure['matrix_v'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 56, 4)); + $atom_structure['matrix_d'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 60, 4)); + $atom_structure['matrix_x'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 64, 4)); + $atom_structure['matrix_y'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 68, 4)); + $atom_structure['matrix_w'] = getid3_quicktime::FixedPoint2_30(substr($atom_data, 72, 4)); + $atom_structure['width'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 76, 4)); + $atom_structure['height'] = getid3_quicktime::FixedPoint16_16(substr($atom_data, 80, 4)); + + $atom_structure['flags']['enabled'] = (bool)($atom_structure['flags_raw'] & 0x0001); + $atom_structure['flags']['in_movie'] = (bool)($atom_structure['flags_raw'] & 0x0002); + $atom_structure['flags']['in_preview'] = (bool)($atom_structure['flags_raw'] & 0x0004); + $atom_structure['flags']['in_poster'] = (bool)($atom_structure['flags_raw'] & 0x0008); + $atom_structure['creation_time_unix'] = (int)($atom_structure['creation_time'] - 2082844800); // DateMac2Unix() + $atom_structure['modify_time_unix'] = (int)($atom_structure['modify_time'] - 2082844800); // DateMac2Unix() + + if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) { + $info['video']['resolution_x'] = $atom_structure['width']; + $info['video']['resolution_y'] = $atom_structure['height']; + } + + if ($atom_structure['flags']['enabled'] == 1) { + $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']); + $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']); + } + + if (!empty($info['video']['resolution_x']) && !empty($info['video']['resolution_y'])) { + $info_quicktime['video']['resolution_x'] = $info['video']['resolution_x']; + $info_quicktime['video']['resolution_y'] = $info['video']['resolution_y']; + } else { + unset($info['video']['resolution_x']); + unset($info['video']['resolution_y']); + unset($info_quicktime['video']); + } + break; + + + case 'meta': // METAdata atom + // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt + $next_tag_position = strpos($atom_data, ''); + while ($next_tag_position < strlen($atom_data)) { + $meta_item_size = getid3_lib::BigEndian2Int(substr($atom_data, $next_tag_position - 4, 4)) - 4; + if ($meta_item_size == -4) { + break; + } + $meta_item_raw = substr($atom_data, $next_tag_position, $meta_item_size); + $meta_item_key = substr($meta_item_raw, 0, 4); + $meta_item_data = substr($meta_item_raw, 20); + $next_tag_position += $meta_item_size + 4; + + $this->CopyToAppropriateCommentsSection($meta_item_key, $meta_item_data); + } + break; + + case 'ftyp': // FileTYPe (?) atom (for MP4 it seems) + getid3_lib::ReadSequence('BigEndian2Int', $atom_structure, $atom_data, 0, + array ( + 'signature' => -4, + 'unknown_1' => 4, + 'fourcc' => -4, + ) + ); + break; + + case 'mdat': // Media DATa atom + case 'free': // FREE space atom + case 'skip': // SKIP atom + case 'wide': // 64-bit expansion placeholder atom + // 'mdat' data is too big to deal with, contains no useful metadata + // 'free', 'skip' and 'wide' are just padding, contains no useful data at all + + // When writing QuickTime files, it is sometimes necessary to update an atom's size. + // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom + // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime + // puts an 8-byte placeholder atom before any atoms it may have to update the size of. + // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the + // placeholder atom can be overwritten to obtain the necessary 8 extra bytes. + // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ). + break; + + + case 'nsav': // NoSAVe atom + // http://developer.apple.com/technotes/tn/tn2038.html + $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); + break; + + case 'ctyp': // Controller TYPe atom (seen on QTVR) + // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt + // some controller names are: + // 0x00 + 'std' for linear movie + // 'none' for no controls + $atom_structure['ctyp'] = substr($atom_data, 0, 4); + switch ($atom_structure['ctyp']) { + case 'qtvr': + $info['video']['dataformat'] = 'quicktimevr'; + break; + } + break; + + case 'pano': // PANOrama track (seen on QTVR) + $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); + break; + + case 'hint': // HINT track + case 'hinf': // + case 'hinv': // + case 'hnti': // + $info['quicktime']['hinting'] = true; + break; + + case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR) + for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) { + $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4)); + } + break; + + case 'FXTC': // Something to do with Adobe After Effects (?) + case 'PrmA': + case 'code': + case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html + // Observed-but-not-handled atom types are just listed here + // to prevent warnings being generated + $atom_structure['data'] = $atom_data; + break; + + default: + $getid3->warning('Unknown QuickTime atom type: "'.$atom_name.'" at offset '.$base_offset); + $atom_structure['data'] = $atom_data; + break; + } + array_pop($atom_hierarchy); + return $atom_structure; + } + + + + private function QuicktimeParseContainerAtom($atom_data, $base_offset, &$atom_hierarchy) { + + if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) { + return false; + } + + $atom_structure = false; + $subatom_offset = 0; + + while ($subatom_offset < strlen($atom_data)) { + + $subatom_size = getid3_lib::BigEndian2Int(substr($atom_data, $subatom_offset + 0, 4)); + $subatom_name = substr($atom_data, $subatom_offset + 4, 4); + $subatom_data = substr($atom_data, $subatom_offset + 8, $subatom_size - 8); + + if ($subatom_size == 0) { + // Furthermore, for historical reasons the list of atoms is optionally + // terminated by a 32-bit integer set to 0. If you are writing a program + // to read user data atoms, you should allow for the terminating 0. + return $atom_structure; + } + + $atom_structure[] = $this->QuicktimeParseAtom($subatom_name, $subatom_size, $subatom_data, $base_offset + $subatom_offset, $atom_hierarchy); + + $subatom_offset += $subatom_size; + } + return $atom_structure; + } + + + + private function CopyToAppropriateCommentsSection($key_name, $data) { + + // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt + + static $translator = array ( + 'cpy' => 'copyright', + 'day' => 'creation_date', + 'dir' => 'director', + 'ed1' => 'edit1', + 'ed2' => 'edit2', + 'ed3' => 'edit3', + 'ed4' => 'edit4', + 'ed5' => 'edit5', + 'ed6' => 'edit6', + 'ed7' => 'edit7', + 'ed8' => 'edit8', + 'ed9' => 'edit9', + 'fmt' => 'format', + 'inf' => 'information', + 'prd' => 'producer', + 'prf' => 'performers', + 'req' => 'system_requirements', + 'src' => 'source_credit', + 'wrt' => 'writer', + 'nam' => 'title', + 'cmt' => 'comment', + 'wrn' => 'warning', + 'hst' => 'host_computer', + 'mak' => 'make', + 'mod' => 'model', + 'PRD' => 'product', + 'swr' => 'software', + 'aut' => 'author', + 'ART' => 'artist', + 'trk' => 'track', + 'alb' => 'album', + 'com' => 'comment', + 'gen' => 'genre', + 'ope' => 'composer', + 'url' => 'url', + 'enc' => 'encoder' + ); + + if (isset($translator[$key_name])) { + $this->getid3->info['quicktime']['comments'][$translator[$key_name]][] = $data; + } + + return true; + } + + + + public static function QuicktimeLanguageLookup($language_id) { + + static $lookup = array ( + 0 => 'English', + 1 => 'French', + 2 => 'German', + 3 => 'Italian', + 4 => 'Dutch', + 5 => 'Swedish', + 6 => 'Spanish', + 7 => 'Danish', + 8 => 'Portuguese', + 9 => 'Norwegian', + 10 => 'Hebrew', + 11 => 'Japanese', + 12 => 'Arabic', + 13 => 'Finnish', + 14 => 'Greek', + 15 => 'Icelandic', + 16 => 'Maltese', + 17 => 'Turkish', + 18 => 'Croatian', + 19 => 'Chinese (Traditional)', + 20 => 'Urdu', + 21 => 'Hindi', + 22 => 'Thai', + 23 => 'Korean', + 24 => 'Lithuanian', + 25 => 'Polish', + 26 => 'Hungarian', + 27 => 'Estonian', + 28 => 'Lettish', + 28 => 'Latvian', + 29 => 'Saamisk', + 29 => 'Lappish', + 30 => 'Faeroese', + 31 => 'Farsi', + 31 => 'Persian', + 32 => 'Russian', + 33 => 'Chinese (Simplified)', + 34 => 'Flemish', + 35 => 'Irish', + 36 => 'Albanian', + 37 => 'Romanian', + 38 => 'Czech', + 39 => 'Slovak', + 40 => 'Slovenian', + 41 => 'Yiddish', + 42 => 'Serbian', + 43 => 'Macedonian', + 44 => 'Bulgarian', + 45 => 'Ukrainian', + 46 => 'Byelorussian', + 47 => 'Uzbek', + 48 => 'Kazakh', + 49 => 'Azerbaijani', + 50 => 'AzerbaijanAr', + 51 => 'Armenian', + 52 => 'Georgian', + 53 => 'Moldavian', + 54 => 'Kirghiz', + 55 => 'Tajiki', + 56 => 'Turkmen', + 57 => 'Mongolian', + 58 => 'MongolianCyr', + 59 => 'Pashto', + 60 => 'Kurdish', + 61 => 'Kashmiri', + 62 => 'Sindhi', + 63 => 'Tibetan', + 64 => 'Nepali', + 65 => 'Sanskrit', + 66 => 'Marathi', + 67 => 'Bengali', + 68 => 'Assamese', + 69 => 'Gujarati', + 70 => 'Punjabi', + 71 => 'Oriya', + 72 => 'Malayalam', + 73 => 'Kannada', + 74 => 'Tamil', + 75 => 'Telugu', + 76 => 'Sinhalese', + 77 => 'Burmese', + 78 => 'Khmer', + 79 => 'Lao', + 80 => 'Vietnamese', + 81 => 'Indonesian', + 82 => 'Tagalog', + 83 => 'MalayRoman', + 84 => 'MalayArabic', + 85 => 'Amharic', + 86 => 'Tigrinya', + 87 => 'Galla', + 87 => 'Oromo', + 88 => 'Somali', + 89 => 'Swahili', + 90 => 'Ruanda', + 91 => 'Rundi', + 92 => 'Chewa', + 93 => 'Malagasy', + 94 => 'Esperanto', + 128 => 'Welsh', + 129 => 'Basque', + 130 => 'Catalan', + 131 => 'Latin', + 132 => 'Quechua', + 133 => 'Guarani', + 134 => 'Aymara', + 135 => 'Tatar', + 136 => 'Uighur', + 137 => 'Dzongkha', + 138 => 'JavaneseRom' + ); + + return (isset($lookup[$language_id]) ? $lookup[$language_id] : 'invalid'); + } + + + + public static function QuicktimeVideoCodecLookup($codec_id) { + + static $lookup = array ( + '3IVX' => '3ivx MPEG-4', + '3IV1' => '3ivx MPEG-4 v1', + '3IV2' => '3ivx MPEG-4 v2', + 'avr ' => 'AVR-JPEG', + 'base' => 'Base', + 'WRLE' => 'BMP', + 'cvid' => 'Cinepak', + 'clou' => 'Cloud', + 'cmyk' => 'CMYK', + 'yuv2' => 'ComponentVideo', + 'yuvu' => 'ComponentVideoSigned', + 'yuvs' => 'ComponentVideoUnsigned', + 'dvc ' => 'DVC-NTSC', + 'dvcp' => 'DVC-PAL', + 'dvpn' => 'DVCPro-NTSC', + 'dvpp' => 'DVCPro-PAL', + 'fire' => 'Fire', + 'flic' => 'FLC', + 'b48r' => '48RGB', + 'gif ' => 'GIF', + 'smc ' => 'Graphics', + 'h261' => 'H261', + 'h263' => 'H263', + 'IV41' => 'Indeo4', + 'jpeg' => 'JPEG', + 'PNTG' => 'MacPaint', + 'msvc' => 'Microsoft Video1', + 'mjpa' => 'Motion JPEG-A', + 'mjpb' => 'Motion JPEG-B', + 'myuv' => 'MPEG YUV420', + 'dmb1' => 'OpenDML JPEG', + 'kpcd' => 'PhotoCD', + '8BPS' => 'Planar RGB', + 'png ' => 'PNG', + 'qdrw' => 'QuickDraw', + 'qdgx' => 'QuickDrawGX', + 'raw ' => 'RAW', + '.SGI' => 'SGI', + 'b16g' => '16Gray', + 'b64a' => '64ARGB', + 'SVQ1' => 'Sorenson Video 1', + 'SVQ1' => 'Sorenson Video 3', + 'syv9' => 'Sorenson YUV9', + 'tga ' => 'Targa', + 'b32a' => '32AlphaGray', + 'tiff' => 'TIFF', + 'path' => 'Vector', + 'rpza' => 'Video', + 'ripl' => 'WaterRipple', + 'WRAW' => 'Windows RAW', + 'y420' => 'YUV420' + ); + + return (isset($lookup[$codec_id]) ? $lookup[$codec_id] : ''); + } + + + + public static function QuicktimeAudioCodecLookup($codec_id) { + + static $lookup = array ( + '.mp3' => 'Fraunhofer MPEG Layer-III alias', + 'aac ' => 'ISO/IEC 14496-3 AAC', + 'agsm' => 'Apple GSM 10:1', + 'alac' => 'Apple Lossless Audio Codec', + 'alaw' => 'A-law 2:1', + 'conv' => 'Sample Format', + 'dvca' => 'DV', + 'dvi ' => 'DV 4:1', + 'eqal' => 'Frequency Equalizer', + 'fl32' => '32-bit Floating Point', + 'fl64' => '64-bit Floating Point', + 'ima4' => 'Interactive Multimedia Association 4:1', + 'in24' => '24-bit Integer', + 'in32' => '32-bit Integer', + 'lpc ' => 'LPC 23:1', + 'MAC3' => 'Macintosh Audio Compression/Expansion (MACE) 3:1', + 'MAC6' => 'Macintosh Audio Compression/Expansion (MACE) 6:1', + 'mixb' => '8-bit Mixer', + 'mixw' => '16-bit Mixer', + 'mp4a' => 'ISO/IEC 14496-3 AAC', + "MS'\x00\x02" => 'Microsoft ADPCM', + "MS'\x00\x11" => 'DV IMA', + "MS\x00\x55" => 'Fraunhofer MPEG Layer III', + 'NONE' => 'No Encoding', + 'Qclp' => 'Qualcomm PureVoice', + 'QDM2' => 'QDesign Music 2', + 'QDMC' => 'QDesign Music 1', + 'ratb' => '8-bit Rate', + 'ratw' => '16-bit Rate', + 'raw ' => 'raw PCM', + 'sour' => 'Sound Source', + 'sowt' => 'signed/two\'s complement (Little Endian)', + 'str1' => 'Iomega MPEG layer II', + 'str2' => 'Iomega MPEG *layer II', + 'str3' => 'Iomega MPEG **layer II', + 'str4' => 'Iomega MPEG ***layer II', + 'twos' => 'signed/two\'s complement (Big Endian)', + 'ulaw' => 'mu-law 2:1', + ); + + return (isset($lookup[$codec_id]) ? $lookup[$codec_id] : ''); + } + + + + public static function QuicktimeDCOMLookup($compression_id) { + + static $lookup = array ( + 'zlib' => 'ZLib Deflate', + 'adec' => 'Apple Compression' + ); + + return (isset($lookup[$compression_id]) ? $lookup[$compression_id] : ''); + } + + + + public static function QuicktimeColorNameLookup($color_depth_id) { + + static $lookup = array ( + 1 => '2-color (monochrome)', + 2 => '4-color', + 4 => '16-color', + 8 => '256-color', + 16 => 'thousands (16-bit color)', + 24 => 'millions (24-bit color)', + 32 => 'millions+ (32-bit color)', + 33 => 'black & white', + 34 => '4-gray', + 36 => '16-gray', + 40 => '256-gray', + ); + + return (isset($lookup[$color_depth_id]) ? $lookup[$color_depth_id] : 'invalid'); + } + + + + public static function NoNullString($null_terminated_string) { + + // remove the single null terminator on null terminated strings + if (substr($null_terminated_string, strlen($null_terminated_string) - 1, 1) === "\x00") { + return substr($null_terminated_string, 0, strlen($null_terminated_string) - 1); + } + + return $null_terminated_string; + } + + + + public static function FixedPoint8_8($raw_data) { + + return getid3_lib::BigEndian2Int($raw_data{0}) + (float)(getid3_lib::BigEndian2Int($raw_data{1}) / 256); + } + + + + public static function FixedPoint16_16($raw_data) { + + return getid3_lib::BigEndian2Int(substr($raw_data, 0, 2)) + (float)(getid3_lib::BigEndian2Int(substr($raw_data, 2, 2)) / 65536); + } + + + + public static function FixedPoint2_30($raw_data) { + + $binary_string = getid3_lib::BigEndian2Bin($raw_data); + return bindec(substr($binary_string, 0, 2)) + (float)(bindec(substr($binary_string, 2, 30)) / 1073741824); + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.real.php b/plugins/getId3Plugin/lib/module.audio-video.real.php new file mode 100644 index 0000000..4cd9b55 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.real.php @@ -0,0 +1,591 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio-video.real.php | +// | Module for analyzing Real Audio/Video files | +// | dependencies: module.audio-video.riff.php | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio-video.real.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_real extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->include_module('audio-video.riff'); + + $getid3->info['fileformat'] = 'real'; + $getid3->info['bitrate'] = 0; + $getid3->info['playtime_seconds'] = 0; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $chunk_counter = 0; + + while (ftell($getid3->fp) < $getid3->info['avdataend']) { + + $chunk_data = fread($getid3->fp, 8); + $chunk_name = substr($chunk_data, 0, 4); + $chunk_size = getid3_lib::BigEndian2Int(substr($chunk_data, 4, 4)); + + if ($chunk_name == '.ra'."\xFD") { + $chunk_data .= fread($getid3->fp, $chunk_size - 8); + + if ($this->ParseOldRAheader(substr($chunk_data, 0, 128), $getid3->info['real']['old_ra_header'])) { + + $getid3->info['audio']['dataformat'] = 'real'; + $getid3->info['audio']['lossless'] = false; + $getid3->info['audio']['sample_rate'] = $getid3->info['real']['old_ra_header']['sample_rate']; + $getid3->info['audio']['bits_per_sample'] = $getid3->info['real']['old_ra_header']['bits_per_sample']; + $getid3->info['audio']['channels'] = $getid3->info['real']['old_ra_header']['channels']; + + $getid3->info['playtime_seconds'] = 60 * ($getid3->info['real']['old_ra_header']['audio_bytes'] / $getid3->info['real']['old_ra_header']['bytes_per_minute']); + $getid3->info['audio']['bitrate'] = 8 * ($getid3->info['real']['old_ra_header']['audio_bytes'] / $getid3->info['playtime_seconds']); + $getid3->info['audio']['codec'] = $this->RealAudioCodecFourCClookup($getid3->info['real']['old_ra_header']['fourcc'], $getid3->info['audio']['bitrate']); + + foreach ($getid3->info['real']['old_ra_header']['comments'] as $key => $value_array) { + + if (strlen(trim($value_array[0])) > 0) { + $getid3->info['real']['comments'][$key][] = trim($value_array[0]); + } + } + return true; + } + + throw new getid3_exception('There was a problem parsing this RealAudio file. Please submit it for analysis to http://www.getid3.org/upload/ or info@getid3.org'); + } + + $getid3->info['real']['chunks'][$chunk_counter] = array (); + $info_real_chunks_current_chunk = &$getid3->info['real']['chunks'][$chunk_counter]; + + $info_real_chunks_current_chunk['name'] = $chunk_name; + $info_real_chunks_current_chunk['offset'] = ftell($getid3->fp) - 8; + $info_real_chunks_current_chunk['length'] = $chunk_size; + + if (($info_real_chunks_current_chunk['offset'] + $info_real_chunks_current_chunk['length']) > $getid3->info['avdataend']) { + $getid3->warning('Chunk "'.$info_real_chunks_current_chunk['name'].'" at offset '.$info_real_chunks_current_chunk['offset'].' claims to be '.$info_real_chunks_current_chunk['length'].' bytes long, which is beyond end of file'); + return false; + } + + if ($chunk_size > (getid3::FREAD_BUFFER_SIZE + 8)) { + $chunk_data .= fread($getid3->fp, getid3::FREAD_BUFFER_SIZE - 8); + fseek($getid3->fp, $info_real_chunks_current_chunk['offset'] + $chunk_size, SEEK_SET); + + } else { + $chunk_data .= fread($getid3->fp, $chunk_size - 8); + } + $offset = 8; + + switch ($chunk_name) { + + case '.RMF': // RealMedia File Header + + $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + switch ($info_real_chunks_current_chunk['object_version']) { + + case 0: + $info_real_chunks_current_chunk['file_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4)); + $offset += 4; + + $info_real_chunks_current_chunk['headers_count'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4)); + $offset += 4; + break; + + default: + //$getid3->warning('Expected .RMF-object_version to be "0", actual value is "'.$info_real_chunks_current_chunk['object_version'].'" (should not be a problem)'; + break; + + } + break; + + + case 'PROP': // Properties Header + + $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + if ($info_real_chunks_current_chunk['object_version'] == 0) { + + getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset, + array ( + 'max_bit_rate' => 4, + 'avg_bit_rate' => 4, + 'max_packet_size' => 4, + 'avg_packet_size' => 4, + 'num_packets' => 4, + 'duration' => 4, + 'preroll' => 4, + 'index_offset' => 4, + 'data_offset' => 4, + 'num_streams' => 2, + 'flags_raw' => 2 + ) + ); + $offset += 40; + + $getid3->info['playtime_seconds'] = $info_real_chunks_current_chunk['duration'] / 1000; + if ($info_real_chunks_current_chunk['duration'] > 0) { + $getid3->info['bitrate'] += $info_real_chunks_current_chunk['avg_bit_rate']; + } + + $info_real_chunks_current_chunk['flags']['save_enabled'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0001); + $info_real_chunks_current_chunk['flags']['perfect_play'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0002); + $info_real_chunks_current_chunk['flags']['live_broadcast'] = (bool)($info_real_chunks_current_chunk['flags_raw'] & 0x0004); + } + break; + + + case 'MDPR': // Media Properties Header + + $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + if ($info_real_chunks_current_chunk['object_version'] == 0) { + + getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset, + array ( + 'stream_number' => 2, + 'max_bit_rate' => 4, + 'avg_bit_rate' => 4, + 'max_packet_size' => 4, + 'avg_packet_size' => 4, + 'start_time' => 4, + 'preroll' => 4, + 'duration' => 4, + 'stream_name_size' => 1 + ) + ); + $offset += 31; + + $info_real_chunks_current_chunk['stream_name'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['stream_name_size']); + $offset += $info_real_chunks_current_chunk['stream_name_size']; + + $info_real_chunks_current_chunk['mime_type_size'] = getid3_lib::BigEndian2Int($chunk_data{$offset++}); + + $info_real_chunks_current_chunk['mime_type'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['mime_type_size']); + $offset += $info_real_chunks_current_chunk['mime_type_size']; + + $info_real_chunks_current_chunk['type_specific_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 4)); + $offset += 4; + + $info_real_chunks_current_chunk['type_specific_data'] = substr($chunk_data, $offset, $info_real_chunks_current_chunk['type_specific_len']); + $offset += $info_real_chunks_current_chunk['type_specific_len']; + + $info_real_chunks_current_chunk_typespecificdata = &$info_real_chunks_current_chunk['type_specific_data']; + + switch ($info_real_chunks_current_chunk['mime_type']) { + + case 'video/x-pn-realvideo': + case 'video/x-pn-multirate-realvideo': + // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html + + $info_real_chunks_current_chunk['video_info'] = array (); + $info_real_chunks_current_chunk_video_info = &$info_real_chunks_current_chunk['video_info']; + + getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk_video_info, $info_real_chunks_current_chunk_typespecificdata, 0, + array ( + 'dwSize' => 4, + 'fourcc1' => -4, + 'fourcc2' => -4, + 'width' => 2, + 'height' => 2, + 'bits_per_sample' => 2, + 'IGNORE-unknown1' => 2, + 'IGNORE-unknown2' => 2, + 'frames_per_second' => 2, + 'IGNORE-unknown3' => 2, + 'IGNORE-unknown4' => 2, + 'IGNORE-unknown5' => 2, + 'IGNORE-unknown6' => 2, + 'IGNORE-unknown7' => 2, + 'IGNORE-unknown8' => 2, + 'IGNORE-unknown9' => 2 + ) + ); + + $info_real_chunks_current_chunk_video_info['codec'] = getid3_riff::RIFFfourccLookup($info_real_chunks_current_chunk_video_info['fourcc2']); + + $getid3->info['video']['resolution_x'] = $info_real_chunks_current_chunk_video_info['width']; + $getid3->info['video']['resolution_y'] = $info_real_chunks_current_chunk_video_info['height']; + $getid3->info['video']['frame_rate'] = (float)$info_real_chunks_current_chunk_video_info['frames_per_second']; + $getid3->info['video']['codec'] = $info_real_chunks_current_chunk_video_info['codec']; + $getid3->info['video']['bits_per_sample'] = $info_real_chunks_current_chunk_video_info['bits_per_sample']; + break; + + + case 'audio/x-pn-realaudio': + case 'audio/x-pn-multirate-realaudio': + + $this->ParseOldRAheader($info_real_chunks_current_chunk_typespecificdata, $info_real_chunks_current_chunk['parsed_audio_data']); + + $getid3->info['audio']['sample_rate'] = $info_real_chunks_current_chunk['parsed_audio_data']['sample_rate']; + $getid3->info['audio']['bits_per_sample'] = $info_real_chunks_current_chunk['parsed_audio_data']['bits_per_sample']; + $getid3->info['audio']['channels'] = $info_real_chunks_current_chunk['parsed_audio_data']['channels']; + + if (!empty($getid3->info['audio']['dataformat'])) { + foreach ($getid3->info['audio'] as $key => $value) { + if ($key != 'streams') { + $getid3->info['audio']['streams'][$info_real_chunks_current_chunk['stream_number']][$key] = $value; + } + } + } + break; + + + case 'logical-fileinfo': + + $info_real_chunks_current_chunk['logical_fileinfo']['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 0, 4)); + // $info_real_chunks_current_chunk['logical_fileinfo']['IGNORE-unknown1'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 4, 4)); + $info_real_chunks_current_chunk['logical_fileinfo']['num_tags'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 8, 4)); + // $info_real_chunks_current_chunk['logical_fileinfo']['IGNORE-unknown2'] = getid3_lib::BigEndian2Int(substr($info_real_chunks_current_chunk_typespecificdata, 12, 4)); + break; + + } + + + if (empty($getid3->info['playtime_seconds'])) { + $getid3->info['playtime_seconds'] = max($getid3->info['playtime_seconds'], ($info_real_chunks_current_chunk['duration'] + $info_real_chunks_current_chunk['start_time']) / 1000); + } + + if ($info_real_chunks_current_chunk['duration'] > 0) { + + switch ($info_real_chunks_current_chunk['mime_type']) { + + case 'audio/x-pn-realaudio': + case 'audio/x-pn-multirate-realaudio': + + $getid3->info['audio']['bitrate'] = (isset($getid3->info['audio']['bitrate']) ? $getid3->info['audio']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate']; + $getid3->info['audio']['codec'] = $this->RealAudioCodecFourCClookup($info_real_chunks_current_chunk['parsed_audio_data']['fourcc'], $getid3->info['audio']['bitrate']); + $getid3->info['audio']['dataformat'] = 'real'; + $getid3->info['audio']['lossless'] = false; + break; + + + case 'video/x-pn-realvideo': + case 'video/x-pn-multirate-realvideo': + + $getid3->info['video']['bitrate'] = (isset($getid3->info['video']['bitrate']) ? $getid3->info['video']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate']; + $getid3->info['video']['bitrate_mode'] = 'cbr'; + $getid3->info['video']['dataformat'] = 'real'; + $getid3->info['video']['lossless'] = false; + $getid3->info['video']['pixel_aspect_ratio'] = (float)1; + break; + + + case 'audio/x-ralf-mpeg4-generic': + + $getid3->info['audio']['bitrate'] = (isset($getid3->info['audio']['bitrate']) ? $getid3->info['audio']['bitrate'] : 0) + $info_real_chunks_current_chunk['avg_bit_rate']; + $getid3->info['audio']['codec'] = 'RealAudio Lossless'; + $getid3->info['audio']['dataformat'] = 'real'; + $getid3->info['audio']['lossless'] = true; + break; + + } + + $getid3->info['bitrate'] = (isset($getid3->info['video']['bitrate']) ? $getid3->info['video']['bitrate'] : 0) + (isset($getid3->info['audio']['bitrate']) ? $getid3->info['audio']['bitrate'] : 0); + } + } + break; + + + case 'CONT': // Content Description Header (text comments) + + $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + if ($info_real_chunks_current_chunk['object_version'] == 0) { + + $info_real_chunks_current_chunk['title_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + $info_real_chunks_current_chunk['title'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['title_len']); + $offset += $info_real_chunks_current_chunk['title_len']; + + $info_real_chunks_current_chunk['artist_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + $info_real_chunks_current_chunk['artist'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['artist_len']); + $offset += $info_real_chunks_current_chunk['artist_len']; + + $info_real_chunks_current_chunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + $info_real_chunks_current_chunk['copyright'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['copyright_len']); + $offset += $info_real_chunks_current_chunk['copyright_len']; + + $info_real_chunks_current_chunk['comment_len'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + $info_real_chunks_current_chunk['comment'] = (string) substr($chunk_data, $offset, $info_real_chunks_current_chunk['comment_len']); + $offset += $info_real_chunks_current_chunk['comment_len']; + + foreach (array ('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment') as $key => $val) { + if ($info_real_chunks_current_chunk[$key]) { + $getid3->info['real']['comments'][$val][] = trim($info_real_chunks_current_chunk[$key]); + } + } + } + break; + + + case 'DATA': // Data Chunk Header + + // do nothing + break; + + + case 'INDX': // Index Section Header + + $info_real_chunks_current_chunk['object_version'] = getid3_lib::BigEndian2Int(substr($chunk_data, $offset, 2)); + $offset += 2; + + if ($info_real_chunks_current_chunk['object_version'] == 0) { + + getid3_lib::ReadSequence('BigEndian2Int', $info_real_chunks_current_chunk, $chunk_data, $offset, + array ( + 'num_indices' => 4, + 'stream_number' => 2, + 'next_index_header' => 4 + ) + ); + $offset += 10; + + if ($info_real_chunks_current_chunk['next_index_header'] == 0) { + // last index chunk found, ignore rest of file + break 2; + } else { + // non-last index chunk, seek to next index chunk (skipping actual index data) + fseek($getid3->fp, $info_real_chunks_current_chunk['next_index_header'], SEEK_SET); + } + } + break; + + + default: + $getid3->warning('Unhandled RealMedia chunk "'.$chunk_name.'" at offset '.$info_real_chunks_current_chunk['offset']); + break; + } + $chunk_counter++; + } + + if (!empty($getid3->info['audio']['streams'])) { + + $getid3->info['audio']['bitrate'] = 0; + + foreach ($getid3->info['audio']['streams'] as $key => $value_array) { + $getid3->info['audio']['bitrate'] += $value_array['bitrate']; + } + } + + return true; + } + + + + public static function ParseOldRAheader($old_ra_header_data, &$parsed_array) { + + // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html + + $parsed_array = array (); + $parsed_array['magic'] = substr($old_ra_header_data, 0, 4); + + if ($parsed_array['magic'] != '.ra'."\xFD") { + return false; + } + + $parsed_array['version1'] = getid3_lib::BigEndian2Int(substr($old_ra_header_data, 4, 2)); + + if ($parsed_array['version1'] < 3) { + + return false; + } + + if ($parsed_array['version1'] == 3) { + + $parsed_array['fourcc1'] = '.ra3'; + $parsed_array['bits_per_sample'] = 16; // hard-coded for old versions? + $parsed_array['sample_rate'] = 8000; // hard-coded for old versions? + + getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 6, + array ( + 'header_size' => 2, + 'channels' => 2, // always 1 (?) + 'IGNORE-unknown1' => 2, + 'IGNORE-unknown2' => 2, + 'IGNORE-unknown3' => 2, + 'bytes_per_minute' => 2, + 'audio_bytes' => 4, + ) + ); + + $parsed_array['comments_raw'] = substr($old_ra_header_data, 22, $parsed_array['header_size'] - 22 + 1); // not including null terminator + + $comment_offset = 0; + + foreach (array ('title', 'artist', 'copyright') as $name) { + $comment_length = getid3_lib::BigEndian2Int($parsed_array['comments_raw']{$comment_offset++}); + $parsed_array['comments'][$name][]= substr($parsed_array['comments_raw'], $comment_offset, $comment_length); + $comment_offset += $comment_length; + } + + $comment_offset++; // final null terminator (?) + $comment_offset++; // fourcc length (?) should be 4 + + $parsed_array['fourcc'] = substr($old_ra_header_data, 23 + $comment_offset, 4); + + + } elseif ($parsed_array['version1'] <= 5) { + + getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 6, + array ( + 'IGNORE-unknown1' => 2, + 'fourcc1' => -4, + 'file_size' => 4, + 'version2' => 2, + 'header_size' => 4, + 'codec_flavor_id' => 2, + 'coded_frame_size' => 4, + 'audio_bytes' => 4, + 'bytes_per_minute' => 4, + 'IGNORE-unknown5' => 4, + 'sub_packet_h' => 2, + 'frame_size' => 2, + 'sub_packet_size' => 2, + 'IGNORE-unknown6' => 2 + ) + ); + + switch ($parsed_array['version1']) { + + case 4: + + getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 48, + array ( + 'sample_rate' => 2, + 'IGNORE-unknown8' => 2, + 'bits_per_sample' => 2, + 'channels' => 2, + 'length_fourcc2' => 1, + 'fourcc2' => -4, + 'length_fourcc3' => 1, + 'fourcc3' => -4, + 'IGNORE-unknown9' => 1, + 'IGNORE-unknown10' => 2, + ) + ); + + $parsed_array['comments_raw'] = substr($old_ra_header_data, 69, $parsed_array['header_size'] - 69 + 16); + + $comment_offset = 0; + + foreach (array ('title', 'artist', 'copyright') as $name) { + $comment_length = getid3_lib::BigEndian2Int($parsed_array['comments_raw']{$comment_offset++}); + $parsed_array['comments'][$name][]= substr($parsed_array['comments_raw'], $comment_offset, $comment_length); + $comment_offset += $comment_length; + } + break; + + + case 5: + + getid3_lib::ReadSequence('BigEndian2Int', $parsed_array, $old_ra_header_data, 48, + array ( + 'sample_rate' => 4, + 'sample_rate2' => 4, + 'bits_per_sample' => 4, + 'channels' => 2, + 'genr' => -4, + 'fourcc3' => -4, + ) + ); + $parsed_array['comments'] = array (); + break; + + } + + $parsed_array['fourcc'] = $parsed_array['fourcc3']; + + } + + foreach ($parsed_array['comments'] as $key => $value) { + + if ($parsed_array['comments'][$key][0] === false) { + $parsed_array['comments'][$key][0] = ''; + } + } + + return true; + } + + + + public static function RealAudioCodecFourCClookup($fourcc, $bitrate) { + + // http://www.its.msstate.edu/net/real/reports/config/tags.stats + // http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html + + static $lookup; + + if (empty($lookup)) { + $lookup['14_4'][8000] = 'RealAudio v2 (14.4kbps)'; + $lookup['14.4'][8000] = 'RealAudio v2 (14.4kbps)'; + $lookup['lpcJ'][8000] = 'RealAudio v2 (14.4kbps)'; + $lookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)'; + $lookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)'; + $lookup['sipr'][4933] = 'RealAudio v4 (5kbps Voice)'; + $lookup['sipr'][6444] = 'RealAudio v4 (6.5kbps Voice)'; + $lookup['sipr'][8444] = 'RealAudio v4 (8.5kbps Voice)'; + $lookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)'; + $lookup['dnet'][8000] = 'RealAudio v3 (8kbps Music)'; + $lookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)'; + $lookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)'; + $lookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)'; + $lookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)'; + $lookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)'; + $lookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)'; + $lookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)'; + $lookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)'; + $lookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)'; + + $lookup['dnet'][0] = 'RealAudio v3'; + $lookup['sipr'][0] = 'RealAudio v4'; + $lookup['cook'][0] = 'RealAudio G2'; + $lookup['atrc'][0] = 'RealAudio 8'; + } + + $round_bitrate = intval(round($bitrate)); + + if (isset($lookup[$fourcc][$round_bitrate])) { + return $lookup[$fourcc][$round_bitrate]; + } + + if (isset($lookup[$fourcc][0])) { + return $lookup[$fourcc][0]; + } + + return $fourcc; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.riff.php b/plugins/getId3Plugin/lib/module.audio-video.riff.php new file mode 100644 index 0000000..f04a198 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.riff.php @@ -0,0 +1,2294 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio-video.riff.php | +// | module for analyzing RIFF files: | +// | Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack3, 8SVX | +// | dependencies: module.audio.mp3.php (optional) | +// | module.audio.ac3.php (optional) | +// | module.audio-video.mpeg.php (optional) | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio-video.riff.php,v 1.5 2006/06/24 22:58:30 ah Exp $ + + + +class getid3_riff extends getid3_handler +{ + + private $endian_function = 'LittleEndian2Int'; + + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['riff']['raw'] = array (); + $info_riff = &$getid3->info['riff']; + $info_riff_raw = &$info_riff['raw']; + $info_audio = &$getid3->info['audio']; + $info_video = &$getid3->info['video']; + $info_avdataoffset = &$getid3->info['avdataoffset']; + $info_avdataend = &$getid3->info['avdataend']; + $info_audio_dataformat = &$info_audio['dataformat']; + $info_riff_audio = &$info_riff['audio']; + $info_riff_video = &$info_riff['video']; + + $original['avdataend'] = $info_avdataend; + + $this->fseek($info_avdataoffset, SEEK_SET); + $riff_header = $this->fread(12); + + $riff_sub_type = substr($riff_header, 8, 4); + + switch (substr($riff_header, 0, 4)) { + + case 'FORM': + $getid3->info['fileformat'] = 'aiff'; + $this->endian_function = 'BigEndian2Int'; + $riff_header_size = getid3_lib::BigEndian2Int(substr($riff_header, 4, 4)); + $info_riff[$riff_sub_type] = $this->ParseRIFF($info_avdataoffset + 12, $info_avdataoffset + $riff_header_size); + $info_riff['header_size'] = $riff_header_size; + break; + + + case 'RIFF': + case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com) + case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s + + if ($riff_sub_type == 'RMP3') { + $riff_sub_type = 'WAVE'; + } + + $getid3->info['fileformat'] = 'riff'; + $this->endian_function = 'LittleEndian2Int'; + $riff_header_size = getid3_lib::LittleEndian2Int(substr($riff_header, 4, 4)); + $info_riff[$riff_sub_type] = $this->ParseRIFF($info_avdataoffset + 12, $info_avdataoffset + $riff_header_size); + $info_riff['header_size'] = $riff_header_size; + if ($riff_sub_type == 'WAVE') { + $info_riff_wave = &$info_riff['WAVE']; + } + break; + + + default: + throw new getid3_exception('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$riff_sub_type.'" instead'); + } + + $endian_function = $this->endian_function; + + $stream_index = 0; + switch ($riff_sub_type) { + + case 'WAVE': + + if (empty($info_audio['bitrate_mode'])) { + $info_audio['bitrate_mode'] = 'cbr'; + } + + if (empty($info_audio_dataformat)) { + $info_audio_dataformat = 'wav'; + } + + if (isset($info_riff_wave['data'][0]['offset'])) { + $info_avdataoffset = $info_riff_wave['data'][0]['offset'] + 8; + $info_avdataend = $info_avdataoffset + $info_riff_wave['data'][0]['size']; + } + + if (isset($info_riff_wave['fmt '][0]['data'])) { + + $info_riff_audio[$stream_index] = getid3_riff::RIFFparseWAVEFORMATex($info_riff_wave['fmt '][0]['data']); + $info_audio['wformattag'] = $info_riff_audio[$stream_index]['raw']['wFormatTag']; + $info_riff_raw['fmt '] = $info_riff_audio[$stream_index]['raw']; + unset($info_riff_audio[$stream_index]['raw']); + $info_audio['streams'][$stream_index] = $info_riff_audio[$stream_index]; + + $info_audio = getid3_riff::array_merge_noclobber($info_audio, $info_riff_audio[$stream_index]); + if (substr($info_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') { + $getid3->warning('Audio codec = '.$info_audio['codec']); + } + $info_audio['bitrate'] = $info_riff_audio[$stream_index]['bitrate']; + + $getid3->info['playtime_seconds'] = (float)((($info_avdataend - $info_avdataoffset) * 8) / $info_audio['bitrate']); + + $info_audio['lossless'] = false; + + if (isset($info_riff_wave['data'][0]['offset']) && isset($info_riff_raw['fmt ']['wFormatTag'])) { + + switch ($info_riff_raw['fmt ']['wFormatTag']) { + + case 0x0001: // PCM + $info_audio['lossless'] = true; + break; + + case 0x2000: // AC-3 + $info_audio_dataformat = 'ac3'; + break; + + default: + // do nothing + break; + + } + } + + $info_audio['streams'][$stream_index]['wformattag'] = $info_audio['wformattag']; + $info_audio['streams'][$stream_index]['bitrate_mode'] = $info_audio['bitrate_mode']; + $info_audio['streams'][$stream_index]['lossless'] = $info_audio['lossless']; + $info_audio['streams'][$stream_index]['dataformat'] = $info_audio_dataformat; + } + + + if (isset($info_riff_wave['rgad'][0]['data'])) { + + // shortcuts + $rgadData = &$info_riff_wave['rgad'][0]['data']; + $info_riff_raw['rgad'] = array ('track'=>array(), 'album'=>array()); + $info_riff_raw_rgad = &$info_riff_raw['rgad']; + $info_riff_raw_rgad_track = &$info_riff_raw_rgad['track']; + $info_riff_raw_rgad_album = &$info_riff_raw_rgad['album']; + + $info_riff_raw_rgad['fPeakAmplitude'] = getid3_riff::BigEndian2Float(strrev(substr($rgadData, 0, 4))); // LittleEndian2Float() + $info_riff_raw_rgad['nRadioRgAdjust'] = getid3_lib::$endian_function(substr($rgadData, 4, 2)); + $info_riff_raw_rgad['nAudiophileRgAdjust'] = getid3_lib::$endian_function(substr($rgadData, 6, 2)); + + $n_track_rg_adjust_bit_string = str_pad(decbin($info_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT); + $n_album_rg_adjust_bit_string = str_pad(decbin($info_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT); + + $info_riff_raw_rgad_track['name'] = bindec(substr($n_track_rg_adjust_bit_string, 0, 3)); + $info_riff_raw_rgad_track['originator'] = bindec(substr($n_track_rg_adjust_bit_string, 3, 3)); + $info_riff_raw_rgad_track['signbit'] = bindec($n_track_rg_adjust_bit_string[6]); + $info_riff_raw_rgad_track['adjustment'] = bindec(substr($n_track_rg_adjust_bit_string, 7, 9)); + $info_riff_raw_rgad_album['name'] = bindec(substr($n_album_rg_adjust_bit_string, 0, 3)); + $info_riff_raw_rgad_album['originator'] = bindec(substr($n_album_rg_adjust_bit_string, 3, 3)); + $info_riff_raw_rgad_album['signbit'] = bindec($n_album_rg_adjust_bit_string[6]); + $info_riff_raw_rgad_album['adjustment'] = bindec(substr($n_album_rg_adjust_bit_string, 7, 9)); + + $info_riff['rgad']['peakamplitude'] = $info_riff_raw_rgad['fPeakAmplitude']; + if (($info_riff_raw_rgad_track['name'] != 0) && ($info_riff_raw_rgad_track['originator'] != 0)) { + $info_riff['rgad']['track']['name'] = getid3_lib_replaygain::NameLookup($info_riff_raw_rgad_track['name']); + $info_riff['rgad']['track']['originator'] = getid3_lib_replaygain::OriginatorLookup($info_riff_raw_rgad_track['originator']); + $info_riff['rgad']['track']['adjustment'] = getid3_lib_replaygain::AdjustmentLookup($info_riff_raw_rgad_track['adjustment'], $info_riff_raw_rgad_track['signbit']); + } + + if (($info_riff_raw_rgad_album['name'] != 0) && ($info_riff_raw_rgad_album['originator'] != 0)) { + $info_riff['rgad']['album']['name'] = getid3_lib_replaygain::NameLookup($info_riff_raw_rgad_album['name']); + $info_riff['rgad']['album']['originator'] = getid3_lib_replaygain::OriginatorLookup($info_riff_raw_rgad_album['originator']); + $info_riff['rgad']['album']['adjustment'] = getid3_lib_replaygain::AdjustmentLookup($info_riff_raw_rgad_album['adjustment'], $info_riff_raw_rgad_album['signbit']); + } + } + + if (isset($info_riff_wave['fact'][0]['data'])) { + + $info_riff_raw['fact']['NumberOfSamples'] = getid3_lib::$endian_function(substr($info_riff_wave['fact'][0]['data'], 0, 4)); + + // This should be a good way of calculating exact playtime, but some sample files have had incorrect number of samples, so cannot use this method + // if (!empty($info_riff_raw['fmt ']['nSamplesPerSec'])) { + // $getid3->info['playtime_seconds'] = (float)$info_riff_raw['fact']['NumberOfSamples'] / $info_riff_raw['fmt ']['nSamplesPerSec']; + // } + } + + + if (!empty($info_riff_raw['fmt ']['nAvgBytesPerSec'])) { + $info_audio['bitrate'] = (int)$info_riff_raw['fmt ']['nAvgBytesPerSec'] * 8; + } + + if (isset($info_riff_wave['bext'][0]['data'])) { + + $info_riff_wave_bext_0 = &$info_riff_wave['bext'][0]; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_riff_wave_bext_0, $info_riff_wave_bext_0['data'], 0, + array ( + 'title' => -256, + 'author' => -32, + 'reference' => -32, + 'origin_date' => -10, + 'origin_time' => -8, + 'time_reference' => 8, + 'bwf_version' => 1, + 'reserved' => 254 + ) + ); + + foreach (array ('title', 'author', 'reference') as $key) { + $info_riff_wave_bext_0[$key] = trim($info_riff_wave_bext_0[$key]); + } + + $info_riff_wave_bext_0['coding_history'] = explode("\r\n", trim(substr($info_riff_wave_bext_0['data'], 601))); + + $info_riff_wave_bext_0['origin_date_unix'] = gmmktime(substr($info_riff_wave_bext_0['origin_time'], 0, 2), + substr($info_riff_wave_bext_0['origin_time'], 3, 2), + substr($info_riff_wave_bext_0['origin_time'], 6, 2), + substr($info_riff_wave_bext_0['origin_date'], 5, 2), + substr($info_riff_wave_bext_0['origin_date'], 8, 2), + substr($info_riff_wave_bext_0['origin_date'], 0, 4)); + + $info_riff['comments']['author'][] = $info_riff_wave_bext_0['author']; + $info_riff['comments']['title'][] = $info_riff_wave_bext_0['title']; + } + + if (isset($info_riff_wave['MEXT'][0]['data'])) { + + $info_riff_wave_mext_0 = &$info_riff_wave['MEXT'][0]; + + $info_riff_wave_mext_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_mext_0['data'], 0, 2)); + $info_riff_wave_mext_0['flags']['homogenous'] = (bool)($info_riff_wave_mext_0['raw']['sound_information'] & 0x0001); + if ($info_riff_wave_mext_0['flags']['homogenous']) { + $info_riff_wave_mext_0['flags']['padding'] = ($info_riff_wave_mext_0['raw']['sound_information'] & 0x0002) ? false : true; + $info_riff_wave_mext_0['flags']['22_or_44'] = (bool)($info_riff_wave_mext_0['raw']['sound_information'] & 0x0004); + $info_riff_wave_mext_0['flags']['free_format'] = (bool)($info_riff_wave_mext_0['raw']['sound_information'] & 0x0008); + + $info_riff_wave_mext_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_mext_0['data'], 2, 2)); + } + $info_riff_wave_mext_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_mext_0['data'], 6, 2)); + $info_riff_wave_mext_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_mext_0['data'], 8, 2)); + $info_riff_wave_mext_0['flags']['anciliary_data_left'] = (bool)($info_riff_wave_mext_0['raw']['anciliary_data_def'] & 0x0001); + $info_riff_wave_mext_0['flags']['anciliary_data_free'] = (bool)($info_riff_wave_mext_0['raw']['anciliary_data_def'] & 0x0002); + $info_riff_wave_mext_0['flags']['anciliary_data_right'] = (bool)($info_riff_wave_mext_0['raw']['anciliary_data_def'] & 0x0004); + } + + if (isset($info_riff_wave['cart'][0]['data'])) { + + $info_riff_wave_cart_0 = &$info_riff_wave['cart'][0]; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_riff_wave_cart_0, $info_riff_wave_cart_0['data'], 0, + array ( + 'version' => -4, + 'title' => -64, + 'artist' => -64, + 'cut_id' => -64, + 'client_id' => -64, + 'category' => -64, + 'classification' => -64, + 'out_cue' => -64, + 'start_date' => -10, + 'start_time' => -8, + 'end_date' => -10, + 'end_time' => -8, + 'producer_app_id' => -64, + 'producer_app_version' => -64, + 'user_defined_text' => -64, + ) + ); + + foreach (array ('artist', 'cut_id', 'client_id', 'category', 'classification', 'out_cue', 'start_date', 'start_time', 'end_date', 'end_time', 'producer_app_id', 'producer_app_version', 'user_defined_text') as $key) { + $info_riff_wave_cart_0[$key] = trim($info_riff_wave_cart_0[$key]); + } + + $info_riff_wave_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_cart_0['data'], 680, 4), true); + + for ($i = 0; $i < 8; $i++) { + $info_riff_wave_cart_0['post_time'][$i]['usage_fourcc'] = substr($info_riff_wave_cart_0['data'], 684 + ($i * 8), 4); + $info_riff_wave_cart_0['post_time'][$i]['timer_value'] = getid3_lib::LittleEndian2Int(substr($info_riff_wave_cart_0['data'], 684 + ($i * 8) + 4, 4)); + } + $info_riff_wave_cart_0['url'] = trim(substr($info_riff_wave_cart_0['data'], 748, 1024)); + $info_riff_wave_cart_0['tag_text'] = explode("\r\n", trim(substr($info_riff_wave_cart_0['data'], 1772))); + + $info_riff['comments']['artist'][] = $info_riff_wave_cart_0['artist']; + $info_riff['comments']['title'][] = $info_riff_wave_cart_0['title']; + } + + if (!isset($info_audio['bitrate']) && isset($info_riff_audio[$stream_index]['bitrate'])) { + $info_audio['bitrate'] = $info_riff_audio[$stream_index]['bitrate']; + $getid3->info['playtime_seconds'] = (float)((($info_avdataend - $info_avdataoffset) * 8) / $info_audio['bitrate']); + } + + if (@$getid3->info['wavpack']) { + + if (!$this->data_string_flag) { + + $info_audio_dataformat = 'wavpack'; + $info_audio['bitrate_mode'] = 'vbr'; + $info_audio['encoder'] = 'WavPack v'.$getid3->info['wavpack']['version']; + + // Reset to the way it was - RIFF parsing will have messed this up + $info_avdataend = $original['avdataend']; + $info_audio['bitrate'] = (($info_avdataend - $info_avdataoffset) * 8) / $getid3->info['playtime_seconds']; + + $this->fseek($info_avdataoffset - 44, SEEK_SET); + $riff_data = $this->fread(44); + $orignal_riff_header_size = getid3_lib::LittleEndian2Int(substr($riff_data, 4, 4)) + 8; + $orignal_riff_data_size = getid3_lib::LittleEndian2Int(substr($riff_data, 40, 4)) + 44; + + if ($orignal_riff_header_size > $orignal_riff_data_size) { + $info_avdataend -= ($orignal_riff_header_size - $orignal_riff_data_size); + $this->fseek($info_avdataend, SEEK_SET); + $riff_data .= $this->fread($orignal_riff_header_size - $orignal_riff_data_size); + } + + // move the data chunk after all other chunks (if any) + // so that the RIFF parser doesn't see EOF when trying + // to skip over the data chunk + $riff_data = substr($riff_data, 0, 36).substr($riff_data, 44).substr($riff_data, 36, 8); + + // Save audio info key + $saved_info_audio = $info_audio; + + // Analyze riff_data + $this->AnalyzeString($riff_data); + + // Restore info key + $info_audio = $saved_info_audio; + } + } + + if (isset($info_riff_raw['fmt ']['wFormatTag'])) { + + switch ($info_riff_raw['fmt ']['wFormatTag']) { + + case 0x08AE: // ClearJump LiteWave + $info_audio['bitrate_mode'] = 'vbr'; + $info_audio_dataformat = 'litewave'; + + //typedef struct tagSLwFormat { + // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags + // DWORD m_dwScale; // scale factor for lossy compression + // DWORD m_dwBlockSize; // number of samples in encoded blocks + // WORD m_wQuality; // alias for the scale factor + // WORD m_wMarkDistance; // distance between marks in bytes + // WORD m_wReserved; + // + // //following paramters are ignored if CF_FILESRC is not set + // DWORD m_dwOrgSize; // original file size in bytes + // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file + // DWORD m_dwRiffChunkSize; // riff chunk size in the original file + // + // PCMWAVEFORMAT m_OrgWf; // original wave format + // }SLwFormat, *PSLwFormat; + + $info_riff['litewave']['raw'] = array (); + $info_riff_litewave = &$info_riff['litewave']; + $info_riff_litewave_raw = &$info_riff_litewave['raw']; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_riff_litewave_raw, $info_riff_wave['fmt '][0]['data'], 18, + array ( + 'compression_method' => 1, + 'compression_flags' => 1, + 'm_dwScale' => 4, + 'm_dwBlockSize' => 4, + 'm_wQuality' => 2, + 'm_wMarkDistance' => 2, + 'm_wReserved' => 2, + 'm_dwOrgSize' => 4, + 'm_bFactExists' => 2, + 'm_dwRiffChunkSize' => 4 + ) + ); + + //$info_riff_litewave['quality_factor'] = intval(round((2000 - $info_riff_litewave_raw['m_dwScale']) / 20)); + $info_riff_litewave['quality_factor'] = $info_riff_litewave_raw['m_wQuality']; + + $info_riff_litewave['flags']['raw_source'] = ($info_riff_litewave_raw['compression_flags'] & 0x01) ? false : true; + $info_riff_litewave['flags']['vbr_blocksize'] = ($info_riff_litewave_raw['compression_flags'] & 0x02) ? false : true; + $info_riff_litewave['flags']['seekpoints'] = (bool)($info_riff_litewave_raw['compression_flags'] & 0x04); + + $info_audio['lossless'] = (($info_riff_litewave_raw['m_wQuality'] == 100) ? true : false); + $info_audio['encoder_options'] = '-q'.$info_riff_litewave['quality_factor']; + break; + } + } + + if ($info_avdataend > $getid3->info['filesize']) { + + switch (@$info_audio_dataformat) { + + case 'wavpack': // WavPack + case 'lpac': // LPAC + case 'ofr': // OptimFROG + case 'ofs': // OptimFROG DualStream + // lossless compressed audio formats that keep original RIFF headers - skip warning + break; + + + case 'litewave': + + if (($info_avdataend - $getid3->info['filesize']) == 1) { + // LiteWave appears to incorrectly *not* pad actual output file + // to nearest WORD boundary so may appear to be short by one + // byte, in which case - skip warning + } else { + // Short by more than one byte, throw warning + $getid3->warning('Probably truncated file - expecting '.$info_riff[$riff_sub_type]['data'][0]['size'].' bytes of data, only found '.($getid3->info['filesize'] - $info_avdataoffset).' (short by '.($info_riff[$riff_sub_type]['data'][0]['size'] - ($getid3->info['filesize'] - $info_avdataoffset)).' bytes)'); + } + break; + + + default: + + if ((($info_avdataend - $getid3->info['filesize']) == 1) && (($info_riff[$riff_sub_type]['data'][0]['size'] % 2) == 0) && ((($getid3->info['filesize'] - $info_avdataoffset) % 2) == 1)) { + // output file appears to be incorrectly *not* padded to nearest WORD boundary + // Output less severe warning + $getid3->warning('File should probably be padded to nearest WORD boundary, but it is not (expecting '.$info_riff[$riff_sub_type]['data'][0]['size'].' bytes of data, only found '.($getid3->info['filesize'] - $info_avdataoffset).' therefore short by '.($info_riff[$riff_sub_type]['data'][0]['size'] - ($getid3->info['filesize'] - $info_avdataoffset)).' bytes)'); + $info_avdataend = $getid3->info['filesize']; + break; + + } + // Short by more than one byte, throw warning + $getid3->warning('Probably truncated file - expecting '.$info_riff[$riff_sub_type]['data'][0]['size'].' bytes of data, only found '.($getid3->info['filesize'] - $info_avdataoffset).' (short by '.($info_riff[$riff_sub_type]['data'][0]['size'] - ($getid3->info['filesize'] - $info_avdataoffset)).' bytes)'); + $info_avdataend = $getid3->info['filesize']; + break; + } + } + + if (!empty($getid3->info['mpeg']['audio']['LAME']['audio_bytes'])) { + if ((($info_avdataend - $info_avdataoffset) - $getid3->info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { + $info_avdataend--; + $getid3->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'); + } + } + + if (@$info_audio_dataformat == 'ac3') { + unset($info_audio['bits_per_sample']); + if (!empty($getid3->info['ac3']['bitrate']) && ($getid3->info['ac3']['bitrate'] != $info_audio['bitrate'])) { + $info_audio['bitrate'] = $getid3->info['ac3']['bitrate']; + } + } + break; + + + case 'AVI ': + $info_video['bitrate_mode'] = 'vbr'; // maybe not, but probably + $info_video['dataformat'] = 'avi'; + $getid3->info['mime_type'] = 'video/avi'; + + if (isset($info_riff[$riff_sub_type]['movi']['offset'])) { + $info_avdataoffset = $info_riff[$riff_sub_type]['movi']['offset'] + 8; + $info_avdataend = $info_avdataoffset + $info_riff[$riff_sub_type]['movi']['size']; + if ($info_avdataend > $getid3->info['filesize']) { + $getid3->warning('Probably truncated file - expecting '.$info_riff[$riff_sub_type]['movi']['size'].' bytes of data, only found '.($getid3->info['filesize'] - $info_avdataoffset).' (short by '.($info_riff[$riff_sub_type]['movi']['size'] - ($getid3->info['filesize'] - $info_avdataoffset)).' bytes)'); + $info_avdataend = $getid3->info['filesize']; + } + } + + if (isset($info_riff['AVI ']['hdrl']['avih'][$stream_index]['data'])) { + $avihData = $info_riff['AVI ']['hdrl']['avih'][$stream_index]['data']; + + $info_riff_raw['avih'] = array (); + $info_riff_raw_avih = &$info_riff_raw['avih']; + + getid3_lib::ReadSequence($this->endian_function, $info_riff_raw_avih, $avihData, 0, + array ( + 'dwMicroSecPerFrame' => 4, // frame display rate (or 0L) + 'dwMaxBytesPerSec' => 4, // max. transfer rate + 'dwPaddingGranularity' => 4, // pad to multiples of this size; normally 2K. + 'dwFlags' => 4, // the ever-present flags + 'dwTotalFrames' => 4, // # frames in file + 'dwInitialFrames' => 4, + 'dwStreams' => 4, + 'dwSuggestedBufferSize' => 4, + 'dwWidth' => 4, + 'dwHeight' => 4, + 'dwScale' => 4, + 'dwRate' => 4, + 'dwStart' => 4, + 'dwLength' => 4 + ) + ); + + $info_riff_raw_avih['flags']['hasindex'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00000010); + $info_riff_raw_avih['flags']['mustuseindex'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00000020); + $info_riff_raw_avih['flags']['interleaved'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00000100); + $info_riff_raw_avih['flags']['trustcktype'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00000800); + $info_riff_raw_avih['flags']['capturedfile'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00010000); + $info_riff_raw_avih['flags']['copyrighted'] = (bool)($info_riff_raw_avih['dwFlags'] & 0x00020010); + + $info_riff_video[$stream_index] = array (); + $info_riff_video_current = &$info_riff_video[$stream_index]; + + if ($info_riff_raw_avih['dwWidth'] > 0) { + $info_riff_video_current['frame_width'] = $info_riff_raw_avih['dwWidth']; + $info_video['resolution_x'] = $info_riff_video_current['frame_width']; + } + + if ($info_riff_raw_avih['dwHeight'] > 0) { + $info_riff_video_current['frame_height'] = $info_riff_raw_avih['dwHeight']; + $info_video['resolution_y'] = $info_riff_video_current['frame_height']; + } + + if ($info_riff_raw_avih['dwTotalFrames'] > 0) { + $info_riff_video_current['total_frames'] = $info_riff_raw_avih['dwTotalFrames']; + $info_video['total_frames'] = $info_riff_video_current['total_frames']; + } + + $info_riff_video_current['frame_rate'] = round(1000000 / $info_riff_raw_avih['dwMicroSecPerFrame'], 3); + $info_video['frame_rate'] = $info_riff_video_current['frame_rate']; + } + + if (isset($info_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) { + if (is_array($info_riff['AVI ']['hdrl']['strl']['strh'])) { + for ($i = 0; $i < count($info_riff['AVI ']['hdrl']['strl']['strh']); $i++) { + if (isset($info_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) { + $strh_data = $info_riff['AVI ']['hdrl']['strl']['strh'][$i]['data']; + $strh_fcc_type = substr($strh_data, 0, 4); + + if (isset($info_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) { + $strf_data = $info_riff['AVI ']['hdrl']['strl']['strf'][$i]['data']; + + // shortcut + $info_riff_raw_strf_strh_fcc_type_stream_index = &$info_riff_raw['strf'][$strh_fcc_type][$stream_index]; + + switch ($strh_fcc_type) { + case 'auds': + $info_audio['bitrate_mode'] = 'cbr'; + $info_audio_dataformat = 'wav'; + if (isset($info_riff_audio) && is_array($info_riff_audio)) { + $stream_index = count($info_riff_audio); + } + + $info_riff_audio[$stream_index] = getid3_riff::RIFFparseWAVEFORMATex($strf_data); + $info_audio['wformattag'] = $info_riff_audio[$stream_index]['raw']['wFormatTag']; + + // shortcut + $info_audio['streams'][$stream_index] = $info_riff_audio[$stream_index]; + $info_audio_streams_currentstream = &$info_audio['streams'][$stream_index]; + + if (@$info_audio_streams_currentstream['bits_per_sample'] === 0) { + unset($info_audio_streams_currentstream['bits_per_sample']); + } + $info_audio_streams_currentstream['wformattag'] = $info_audio_streams_currentstream['raw']['wFormatTag']; + unset($info_audio_streams_currentstream['raw']); + + // shortcut + $info_riff_raw['strf'][$strh_fcc_type][$stream_index] = $info_riff_audio[$stream_index]['raw']; + + unset($info_riff_audio[$stream_index]['raw']); + $info_audio = getid3_riff::array_merge_noclobber($info_audio, $info_riff_audio[$stream_index]); + + $info_audio['lossless'] = false; + switch ($info_riff_raw_strf_strh_fcc_type_stream_index['wFormatTag']) { + + case 0x0001: // PCM + $info_audio_dataformat = 'wav'; + $info_audio['lossless'] = true; + break; + + case 0x0050: // MPEG Layer 2 or Layer 1 + $info_audio_dataformat = 'mp2'; // Assume Layer-2 + break; + + case 0x0055: // MPEG Layer 3 + $info_audio_dataformat = 'mp3'; + break; + + case 0x00FF: // AAC + $info_audio_dataformat = 'aac'; + break; + + case 0x0161: // Windows Media v7 / v8 / v9 + case 0x0162: // Windows Media Professional v9 + case 0x0163: // Windows Media Lossess v9 + $info_audio_dataformat = 'wma'; + break; + + case 0x2000: // AC-3 + $info_audio_dataformat = 'ac3'; + break; + + case 0x2001: // DTS + $info_audio_dataformat = 'dts'; + break; + + default: + $info_audio_dataformat = 'wav'; + break; + } + $info_audio_streams_currentstream['dataformat'] = $info_audio_dataformat; + $info_audio_streams_currentstream['lossless'] = $info_audio['lossless']; + $info_audio_streams_currentstream['bitrate_mode'] = $info_audio['bitrate_mode']; + break; + + + case 'iavs': + case 'vids': + // shortcut + $info_riff_raw['strh'][$i] = array (); + $info_riff_raw_strh_current = &$info_riff_raw['strh'][$i]; + + getid3_lib::ReadSequence($this->endian_function, $info_riff_raw_strh_current, $strh_data, 0, + array ( + 'fccType' => -4, // same as $strh_fcc_type; + 'fccHandler' => -4, + 'dwFlags' => 4, // Contains AVITF_* flags + 'wPriority' => 2, + 'wLanguage' => 2, + 'dwInitialFrames' => 4, + 'dwScale' => 4, + 'dwRate' => 4, + 'dwStart' => 4, + 'dwLength' => 4, + 'dwSuggestedBufferSize' => 4, + 'dwQuality' => 4, + 'dwSampleSize' => 4, + 'rcFrame' => 4 + ) + ); + + $info_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($info_riff_raw_strh_current['fccHandler']); + $info_video['fourcc'] = $info_riff_raw_strh_current['fccHandler']; + + if (!$info_riff_video_current['codec'] && isset($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']) && getid3_riff::RIFFfourccLookup($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc'])) { + $info_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']); + $info_video['fourcc'] = $info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']; + } + + $info_video['codec'] = $info_riff_video_current['codec']; + $info_video['pixel_aspect_ratio'] = (float)1; + + switch ($info_riff_raw_strh_current['fccHandler']) { + + case 'HFYU': // Huffman Lossless Codec + case 'IRAW': // Intel YUV Uncompressed + case 'YUY2': // Uncompressed YUV 4:2:2 + $info_video['lossless'] = true; + break; + + default: + $info_video['lossless'] = false; + break; + } + + switch ($strh_fcc_type) { + + case 'vids': + getid3_lib::ReadSequence($this->endian_function, $info_riff_raw_strf_strh_fcc_type_stream_index, $strf_data, 0, + array ( + 'biSize' => 4, // number of bytes required by the BITMAPINFOHEADER structure + 'biWidth' => 4, // width of the bitmap in pixels + 'biHeight' => 4, // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner + 'biPlanes' => 2, // number of color planes on the target device. In most cases this value must be set to 1 + 'biBitCount' => 2, // Specifies the number of bits per pixels + 'fourcc' => -4, // + 'biSizeImage' => 4, // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures) + 'biXPelsPerMeter' => 4, // horizontal resolution, in pixels per metre, of the target device + 'biYPelsPerMeter' => 4, // vertical resolution, in pixels per metre, of the target device + 'biClrUsed' => 4, // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression + 'biClrImportant' => 4 // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important + ) + ); + + $info_video['bits_per_sample'] = $info_riff_raw_strf_strh_fcc_type_stream_index['biBitCount']; + + if ($info_riff_video_current['codec'] == 'DV') { + $info_riff_video_current['dv_type'] = 2; + } + break; + + case 'iavs': + $info_riff_video_current['dv_type'] = 1; + break; + } + break; + + default: + $getid3->warning('Unhandled fccType for stream ('.$i.'): "'.$strh_fcc_type.'"'); + break; + + } + } + } + + if (isset($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']) && getid3_riff::RIFFfourccLookup($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc'])) { + + $info_riff_video_current['codec'] = getid3_riff::RIFFfourccLookup($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']); + $info_video['codec'] = $info_riff_video_current['codec']; + $info_video['fourcc'] = $info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']; + + switch ($info_riff_raw_strf_strh_fcc_type_stream_index['fourcc']) { + + case 'HFYU': // Huffman Lossless Codec + case 'IRAW': // Intel YUV Uncompressed + case 'YUY2': // Uncompressed YUV 4:2:2 + $info_video['lossless'] = true; + $info_video['bits_per_sample'] = 24; + break; + + default: + $info_video['lossless'] = false; + $info_video['bits_per_sample'] = 24; + break; + } + + } + } + } + } + break; + + + case 'CDDA': + $info_audio['bitrate_mode'] = 'cbr'; + $info_audio_dataformat = 'cda'; + $info_audio['lossless'] = true; + unset($getid3->info['mime_type']); + + $info_avdataoffset = 44; + + if (isset($info_riff['CDDA']['fmt '][0]['data'])) { + + $info_riff_cdda_fmt_0 = &$info_riff['CDDA']['fmt '][0]; + + getid3_lib::ReadSequence($this->endian_function, $info_riff_cdda_fmt_0, $info_riff_cdda_fmt_0['data'], 0, + array ( + 'unknown1' => 2, + 'track_num' => 2, + 'disc_id' => 4, + 'start_offset_frame' => 4, + 'playtime_frames' => 4, + 'unknown6' => 4, + 'unknown7' => 4 + ) + ); + + $info_riff_cdda_fmt_0['start_offset_seconds'] = (float)$info_riff_cdda_fmt_0['start_offset_frame'] / 75; + $info_riff_cdda_fmt_0['playtime_seconds'] = (float)$info_riff_cdda_fmt_0['playtime_frames'] / 75; + $getid3->info['comments']['track'] = $info_riff_cdda_fmt_0['track_num']; + $getid3->info['playtime_seconds'] = $info_riff_cdda_fmt_0['playtime_seconds']; + + // hardcoded data for CD-audio + $info_audio['sample_rate'] = 44100; + $info_audio['channels'] = 2; + $info_audio['bits_per_sample'] = 16; + $info_audio['bitrate'] = $info_audio['sample_rate'] * $info_audio['channels'] * $info_audio['bits_per_sample']; + $info_audio['bitrate_mode'] = 'cbr'; + } + break; + + + case 'AIFF': + case 'AIFC': + $info_audio['bitrate_mode'] = 'cbr'; + $info_audio_dataformat = 'aiff'; + $info_audio['lossless'] = true; + $getid3->info['mime_type'] = 'audio/x-aiff'; + + if (isset($info_riff[$riff_sub_type]['SSND'][0]['offset'])) { + $info_avdataoffset = $info_riff[$riff_sub_type]['SSND'][0]['offset'] + 8; + $info_avdataend = $info_avdataoffset + $info_riff[$riff_sub_type]['SSND'][0]['size']; + if ($info_avdataend > $getid3->info['filesize']) { + if (($info_avdataend == ($getid3->info['filesize'] + 1)) && (($getid3->info['filesize'] % 2) == 1)) { + // structures rounded to 2-byte boundary, but dumb encoders + // forget to pad end of file to make this actually work + } else { + $getid3->warning('Probable truncated AIFF file: expecting '.$info_riff[$riff_sub_type]['SSND'][0]['size'].' bytes of audio data, only '.($getid3->info['filesize'] - $info_avdataoffset).' bytes found'); + } + $info_avdataend = $getid3->info['filesize']; + } + } + + if (isset($info_riff[$riff_sub_type]['COMM'][0]['data'])) { + + // shortcut + $info_riff_RIFFsubtype_COMM_0_data = &$info_riff[$riff_sub_type]['COMM'][0]['data']; + + $info_riff_audio['channels'] = getid3_lib::BigEndianSyncSafe2Int(substr($info_riff_RIFFsubtype_COMM_0_data, 0, 2)); + $info_riff_audio['total_samples'] = getid3_lib::BigEndian2Int( substr($info_riff_RIFFsubtype_COMM_0_data, 2, 4)); + $info_riff_audio['bits_per_sample'] = getid3_lib::BigEndianSyncSafe2Int(substr($info_riff_RIFFsubtype_COMM_0_data, 6, 2)); + $info_riff_audio['sample_rate'] = (int)getid3_riff::BigEndian2Float(substr($info_riff_RIFFsubtype_COMM_0_data, 8, 10)); + + if ($info_riff[$riff_sub_type]['COMM'][0]['size'] > 18) { + $info_riff_audio['codec_fourcc'] = substr($info_riff_RIFFsubtype_COMM_0_data, 18, 4); + $codec_name_size = getid3_lib::BigEndian2Int(substr($info_riff_RIFFsubtype_COMM_0_data, 22, 1)); + $info_riff_audio['codec_name'] = substr($info_riff_RIFFsubtype_COMM_0_data, 23, $codec_name_size); + + switch ($info_riff_audio['codec_name']) { + + case 'NONE': + $info_audio['codec'] = 'Pulse Code Modulation (PCM)'; + $info_audio['lossless'] = true; + break; + + case '': + switch ($info_riff_audio['codec_fourcc']) { + + // http://developer.apple.com/qa/snd/snd07.html + case 'sowt': + $info_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM'; + $info_audio['lossless'] = true; + break; + + case 'twos': + $info_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM'; + $info_audio['lossless'] = true; + break; + + default: + break; + } + break; + + default: + $info_audio['codec'] = $info_riff_audio['codec_name']; + $info_audio['lossless'] = false; + break; + } + } + + $info_audio['channels'] = $info_riff_audio['channels']; + + if ($info_riff_audio['bits_per_sample'] > 0) { + $info_audio['bits_per_sample'] = $info_riff_audio['bits_per_sample']; + } + + $info_audio['sample_rate'] = $info_riff_audio['sample_rate']; + $getid3->info['playtime_seconds'] = $info_riff_audio['total_samples'] / $info_audio['sample_rate']; + } + + if (isset($info_riff[$riff_sub_type]['COMT'])) { + + $comment_count = getid3_lib::BigEndian2Int(substr($info_riff[$riff_sub_type]['COMT'][0]['data'], 0, 2)); + $offset = 2; + + for ($i = 0; $i < $comment_count; $i++) { + + $getid3->info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int( substr($info_riff[$riff_sub_type]['COMT'][0]['data'], $offset, 4)); + $offset += 4; + + $getid3->info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndianSyncSafe2Int(substr($info_riff[$riff_sub_type]['COMT'][0]['data'], $offset, 2)); + $offset += 2; + + $comment_length = getid3_lib::BigEndian2Int( substr($info_riff[$riff_sub_type]['COMT'][0]['data'], $offset, 2)); + $offset += 2; + + $getid3->info['comments_raw'][$i]['comment'] = substr($info_riff[$riff_sub_type]['COMT'][0]['data'], $offset, $comment_length); + $offset += $comment_length; + + $getid3->info['comments_raw'][$i]['timestamp_unix'] = getid3_riff::DateMac2Unix($getid3->info['comments_raw'][$i]['timestamp']); + $info_riff['comments']['comment'][] = $getid3->info['comments_raw'][$i]['comment']; + } + } + + foreach (array ('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment') as $key => $value) { + if (isset($info_riff[$riff_sub_type][$key][0]['data'])) { + $info_riff['comments'][$value][] = $info_riff[$riff_sub_type][$key][0]['data']; + } + } + break; + + + case '8SVX': + $info_audio['bitrate_mode'] = 'cbr'; + $info_audio_dataformat = '8svx'; + $info_audio['bits_per_sample'] = 8; + $info_audio['channels'] = 1; // overridden below, if need be + $getid3->info['mime_type'] = 'audio/x-aiff'; + + if (isset($info_riff[$riff_sub_type]['BODY'][0]['offset'])) { + $info_avdataoffset = $info_riff[$riff_sub_type]['BODY'][0]['offset'] + 8; + $info_avdataend = $info_avdataoffset + $info_riff[$riff_sub_type]['BODY'][0]['size']; + if ($info_avdataend > $getid3->info['filesize']) { + $getid3->warning('Probable truncated AIFF file: expecting '.$info_riff[$riff_sub_type]['BODY'][0]['size'].' bytes of audio data, only '.($getid3->info['filesize'] - $info_avdataoffset).' bytes found'); + } + } + + if (isset($info_riff[$riff_sub_type]['VHDR'][0]['offset'])) { + // shortcut + $info_riff_riff_sub_type_vhdr_0 = &$info_riff[$riff_sub_type]['VHDR'][0]; + + getid3_lib::ReadSequence('BigEndian2Int', $info_riff_riff_sub_type_vhdr_0, $info_riff_riff_sub_type_vhdr_0['data'], 0, + array ( + 'oneShotHiSamples' => 4, + 'repeatHiSamples' => 4, + 'samplesPerHiCycle' => 4, + 'samplesPerSec' => 2, + 'ctOctave' => 1, + 'sCompression' => 1, + 'Volume' => -4 + ) + ); + + $info_riff_riff_sub_type_vhdr_0['Volume'] = getid3_riff::FixedPoint16_16($info_riff_riff_sub_type_vhdr_0['Volume']); + + $info_audio['sample_rate'] = $info_riff_riff_sub_type_vhdr_0['samplesPerSec']; + + switch ($info_riff_riff_sub_type_vhdr_0['sCompression']) { + case 0: + $info_audio['codec'] = 'Pulse Code Modulation (PCM)'; + $info_audio['lossless'] = true; + $actual_bits_per_sample = 8; + break; + + case 1: + $info_audio['codec'] = 'Fibonacci-delta encoding'; + $info_audio['lossless'] = false; + $actual_bits_per_sample = 4; + break; + + default: + $getid3->warning('Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"'); + break; + } + } + + if (isset($info_riff[$riff_sub_type]['CHAN'][0]['data'])) { + $ChannelsIndex = getid3_lib::BigEndian2Int(substr($info_riff[$riff_sub_type]['CHAN'][0]['data'], 0, 4)); + switch ($ChannelsIndex) { + case 6: // Stereo + $info_audio['channels'] = 2; + break; + + case 2: // Left channel only + case 4: // Right channel only + $info_audio['channels'] = 1; + break; + + default: + $getid3->warning('Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"'); + break; + } + + } + + foreach (array ('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment') as $key => $value) { + if (isset($info_riff[$riff_sub_type][$key][0]['data'])) { + $info_riff['comments'][$value][] = $info_riff[$riff_sub_type][$key][0]['data']; + } + } + + $info_audio['bitrate'] = $info_audio['sample_rate'] * $actual_bits_per_sample * $info_audio['channels']; + if (!empty($info_audio['bitrate'])) { + $getid3->info['playtime_seconds'] = ($info_avdataend - $info_avdataoffset) / ($info_audio['bitrate'] / 8); + } + break; + + + case 'CDXA': + + $getid3->info['mime_type'] = 'video/mpeg'; + if (!empty($info_riff['CDXA']['data'][0]['size'])) { + $GETID3_ERRORARRAY = &$getid3->info['warning']; + + if (!$getid3->include_module_optional('audio-video.mpeg')) { + $getid3->warning('MPEG skipped because mpeg module is missing.'); + } + + else { + + // Clone getid3 - messing with offsets - better safe than sorry + $clone = clone $getid3; + + // Analyse + $mpeg = new getid3_mpeg($clone); + $mpeg->Analyze(); + + // Import from clone and destroy + $getid3->info['audio'] = $clone->info['audio']; + $getid3->info['video'] = $clone->info['video']; + $getid3->info['mpeg'] = $clone->info['mpeg']; + $getid3->info['warning'] = $clone->info['warning']; + + unset($clone); + } + } + + break; + + + default: + throw new getid3_exception('Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$riff_sub_type.'" instead'); + } + + if (@is_array($info_riff_wave['DISP'])) { + $info_riff['comments']['title'][] = trim(substr($info_riff_wave['DISP'][count($info_riff_wave['DISP']) - 1]['data'], 4)); + } + + if (@is_array($info_riff_wave['INFO'])) { + getid3_riff::RIFFCommentsParse($info_riff_wave['INFO'], $info_riff['comments']); + } + + if (isset($info_riff_wave['INFO']) && is_array($info_riff_wave['INFO'])) { + + foreach (array ('IARL' => 'archivallocation', 'IART' => 'artist', 'ICDS' => 'costumedesigner', 'ICMS' => 'commissionedby', 'ICMT' => 'comment', 'ICNT' => 'country', 'ICOP' => 'copyright', 'ICRD' => 'creationdate', 'IDIM' => 'dimensions', 'IDIT' => 'digitizationdate', 'IDPI' => 'resolution', 'IDST' => 'distributor', 'IEDT' => 'editor', 'IENG' => 'engineers', 'IFRM' => 'accountofparts', 'IGNR' => 'genre', 'IKEY' => 'keywords', 'ILGT' => 'lightness', 'ILNG' => 'language', 'IMED' => 'orignalmedium', 'IMUS' => 'composer', 'INAM' => 'title', 'IPDS' => 'productiondesigner', 'IPLT' => 'palette', 'IPRD' => 'product', 'IPRO' => 'producer', 'IPRT' => 'part', 'IRTD' => 'rating', 'ISBJ' => 'subject', 'ISFT' => 'software', 'ISGN' => 'secondarygenre', 'ISHP' => 'sharpness', 'ISRC' => 'sourcesupplier', 'ISRF' => 'digitizationsource', 'ISTD' => 'productionstudio', 'ISTR' => 'starring', 'ITCH' => 'encoded_by', 'IWEB' => 'url', 'IWRI' => 'writer') as $key => $value) { + if (isset($info_riff_wave['INFO'][$key])) { + foreach ($info_riff_wave['INFO'][$key] as $comment_id => $comment_data) { + if (trim($comment_data['data']) != '') { + $info_riff['comments'][$value][] = trim($comment_data['data']); + } + } + } + } + } + + if (empty($info_audio['encoder']) && !empty($getid3->info['mpeg']['audio']['LAME']['short_version'])) { + $info_audio['encoder'] = $getid3->info['mpeg']['audio']['LAME']['short_version']; + } + + if (!isset($getid3->info['playtime_seconds'])) { + $getid3->info['playtime_seconds'] = 0; + } + + if (isset($info_riff_raw['avih']['dwTotalFrames']) && isset($info_riff_raw['avih']['dwMicroSecPerFrame'])) { + $getid3->info['playtime_seconds'] = $info_riff_raw['avih']['dwTotalFrames'] * ($info_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); + } + + if ($getid3->info['playtime_seconds'] > 0) { + if (isset($info_riff_audio) && isset($info_riff_video)) { + + if (!isset($getid3->info['bitrate'])) { + $getid3->info['bitrate'] = ((($info_avdataend - $info_avdataoffset) / $getid3->info['playtime_seconds']) * 8); + } + + } elseif (isset($info_riff_audio) && !isset($info_riff_video)) { + + if (!isset($info_audio['bitrate'])) { + $info_audio['bitrate'] = ((($info_avdataend - $info_avdataoffset) / $getid3->info['playtime_seconds']) * 8); + } + + } elseif (!isset($info_riff_audio) && isset($info_riff_video)) { + + if (!isset($info_video['bitrate'])) { + $info_video['bitrate'] = ((($info_avdataend - $info_avdataoffset) / $getid3->info['playtime_seconds']) * 8); + } + + } + } + + + if (isset($info_riff_video) && isset($info_audio['bitrate']) && ($info_audio['bitrate'] > 0) && ($getid3->info['playtime_seconds'] > 0)) { + + $getid3->info['bitrate'] = ((($info_avdataend - $info_avdataoffset) / $getid3->info['playtime_seconds']) * 8); + $info_audio['bitrate'] = 0; + $info_video['bitrate'] = $getid3->info['bitrate']; + foreach ($info_riff_audio as $channelnumber => $audioinfoarray) { + $info_video['bitrate'] -= $audioinfoarray['bitrate']; + $info_audio['bitrate'] += $audioinfoarray['bitrate']; + } + if ($info_video['bitrate'] <= 0) { + unset($info_video['bitrate']); + } + if ($info_audio['bitrate'] <= 0) { + unset($info_audio['bitrate']); + } + } + + if (isset($getid3->info['mpeg']['audio'])) { + $info_audio_dataformat = 'mp'.$getid3->info['mpeg']['audio']['layer']; + $info_audio['sample_rate'] = $getid3->info['mpeg']['audio']['sample_rate']; + $info_audio['channels'] = $getid3->info['mpeg']['audio']['channels']; + $info_audio['bitrate'] = $getid3->info['mpeg']['audio']['bitrate']; + $info_audio['bitrate_mode'] = strtolower($getid3->info['mpeg']['audio']['bitrate_mode']); + + if (!empty($getid3->info['mpeg']['audio']['codec'])) { + $info_audio['codec'] = $getid3->info['mpeg']['audio']['codec'].' '.$info_audio['codec']; + } + + if (!empty($info_audio['streams'])) { + foreach ($info_audio['streams'] as $streamnumber => $streamdata) { + if ($streamdata['dataformat'] == $info_audio_dataformat) { + $info_audio['streams'][$streamnumber]['sample_rate'] = $info_audio['sample_rate']; + $info_audio['streams'][$streamnumber]['channels'] = $info_audio['channels']; + $info_audio['streams'][$streamnumber]['bitrate'] = $info_audio['bitrate']; + $info_audio['streams'][$streamnumber]['bitrate_mode'] = $info_audio['bitrate_mode']; + $info_audio['streams'][$streamnumber]['codec'] = $info_audio['codec']; + } + } + } + $info_audio['encoder_options'] = getid3_mp3::GuessEncoderOptions($getid3->info); + } + + + if (!empty($info_riff_raw['fmt ']['wBitsPerSample']) && ($info_riff_raw['fmt ']['wBitsPerSample'] > 0)) { + switch ($info_audio_dataformat) { + case 'ac3': + // ignore bits_per_sample + break; + + default: + $info_audio['bits_per_sample'] = $info_riff_raw['fmt ']['wBitsPerSample']; + break; + } + } + + + if (empty($info_riff_raw)) { + unset($info_riff['raw']); + } + if (empty($info_riff_audio)) { + unset($info_riff['audio']); + } + if (empty($info_riff_video)) { + unset($info_riff['video']); + } + if (empty($info_audio_dataformat)) { + unset($info_audio['dataformat']); + } + if (empty($getid3->info['audio'])) { + unset($getid3->info['audio']); + } + if (empty($info_video)) { + unset($getid3->info['video']); + } + + return true; + } + + + + public function ParseRIFF($start_offset, $max_offset) { + + $getid3 = $this->getid3; + + $info = &$getid3->info; + + $endian_function = $this->endian_function; + + $max_offset = min($max_offset, $info['avdataend']); + + $riff_chunk = false; + + $this->fseek($start_offset, SEEK_SET); + + while ($this->ftell() < $max_offset) { + + $chunk_name = $this->fread(4); + + if (strlen($chunk_name) < 4) { + throw new getid3_exception('Expecting chunk name at offset '.($this->ftell() - 4).' but found nothing. Aborting RIFF parsing.'); + } + + $chunk_size = getid3_lib::$endian_function($this->fread(4)); + + if ($chunk_size == 0) { + throw new getid3_exception('Chunk size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.'); + } + + if (($chunk_size % 2) != 0) { + // all structures are packed on word boundaries + $chunk_size++; + } + + switch ($chunk_name) { + + case 'LIST': + $list_name = $this->fread(4); + + switch ($list_name) { + + case 'movi': + case 'rec ': + $riff_chunk[$list_name]['offset'] = $this->ftell() - 4; + $riff_chunk[$list_name]['size'] = $chunk_size; + + static $parsed_audio_stream = false; + + if (!$parsed_audio_stream) { + $where_we_were = $this->ftell(); + $audio_chunk_header = $this->fread(12); + $audio_chunk_stream_num = substr($audio_chunk_header, 0, 2); + $audio_chunk_stream_type = substr($audio_chunk_header, 2, 2); + $audio_chunk_size = getid3_lib::LittleEndian2Int(substr($audio_chunk_header, 4, 4)); + + if ($audio_chunk_stream_type == 'wb') { + $first_four_bytes = substr($audio_chunk_header, 8, 4); + + + //// MPEG + + if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $first_four_bytes)) { + + if (!$getid3->include_module_optional('audio.mp3')) { + $getid3->warning('MP3 skipped because mp3 module is missing.'); + } + + elseif (getid3_mp3::MPEGaudioHeaderBytesValid($first_four_bytes)) { + + // Clone getid3 - messing with offsets - better safe than sorry + $clone = clone $getid3; + $clone->info['avdataoffset'] = $this->ftell() - 4; + $clone->info['avdataend'] = $this->ftell() + $audio_chunk_size; + + $mp3 = new getid3_mp3($clone); + $mp3->AnalyzeMPEGaudioInfo(); + + // Import from clone and destroy + if (isset($clone->info['mpeg']['audio'])) { + + $info['mpeg']['audio'] = $clone->info['mpeg']['audio']; + + $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer']; + $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; + $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); + $info['bitrate'] = $info['audio']['bitrate']; + + $getid3->warning($clone->warnings()); + unset($clone); + } + } + } + + //// AC3-WAVE + + elseif (preg_match('/^\x0B\x77/s', $first_four_bytes)) { + + if (!$getid3->include_module_optional('audio.ac3')) { + $getid3->warning('AC3 skipped because ac3 module is missing.'); + } + + else { + + // Clone getid3 - messing with offsets - better safe than sorry + $clone = clone $getid3; + $clone->info['avdataoffset'] = $this->ftell() - 4; + $clone->info['avdataend'] = $this->ftell() + $audio_chunk_size; + + // Analyze clone by fp + $ac3 = new getid3_ac3($clone); + $ac3->Analyze(); + + // Import from clone and destroy + $info['audio'] = $clone->info['audio']; + $info['ac3'] = $clone->info['ac3']; + $getid3->warning($clone->warnings()); + unset($clone); + } + } + } + + $parsed_audio_stream = true; + $this->fseek($where_we_were, SEEK_SET); + + } + $this->fseek($chunk_size - 4, SEEK_CUR); + break; + + default: + if (!isset($riff_chunk[$list_name])) { + $riff_chunk[$list_name] = array (); + } + $list_chunk_parent = $list_name; + $list_chunk_max_offset = $this->ftell() - 4 + $chunk_size; + if ($parsed_chunk = $this->ParseRIFF($this->ftell(), $this->ftell() + $chunk_size - 4)) { + $riff_chunk[$list_name] = array_merge_recursive($riff_chunk[$list_name], $parsed_chunk); + } + break; + } + break; + + + default: + + $this_index = 0; + if (isset($riff_chunk[$chunk_name]) && is_array($riff_chunk[$chunk_name])) { + $this_index = count($riff_chunk[$chunk_name]); + } + $riff_chunk[$chunk_name][$this_index]['offset'] = $this->ftell() - 8; + $riff_chunk[$chunk_name][$this_index]['size'] = $chunk_size; + switch ($chunk_name) { + case 'data': + $info['avdataoffset'] = $this->ftell(); + $info['avdataend'] = $info['avdataoffset'] + $chunk_size; + + $riff_data_chunk_contents_test = $this->fread(36); + + + //// This is probably MP3 data + + if ((strlen($riff_data_chunk_contents_test) > 0) && preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($riff_data_chunk_contents_test, 0, 4))) { + + if (!$getid3->include_module_optional('audio.mp3')) { + $getid3->warning('MP3 skipped because mp3 module is missing.'); + } + + + // Clone getid3 - messing with offsets - better safe than sorry + $clone = clone $getid3; + + if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($riff_data_chunk_contents_test, 0, 4))) { + + $mp3 = new getid3_mp3($clone); + $mp3->AnalyzeMPEGaudioInfo(); + + // Import from clone and destroy + if (isset($clone->info['mpeg']['audio'])) { + + $info['mpeg']['audio'] = $clone->info['mpeg']['audio']; + + $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; + $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); + $info['bitrate'] = $info['audio']['bitrate']; + + $getid3->warning($clone->warnings()); + unset($clone); + } + } + + } else + + + //// This is probably AC-3 data + + if ((strlen($riff_data_chunk_contents_test) > 0) && (substr($riff_data_chunk_contents_test, 0, 2) == "\x0B\x77")) { + + if (!$getid3->include_module_optional('audio.ac3')) { + $getid3->warning('AC3 skipped because ac3 module is missing.'); + } + + else { + + // Clone getid3 - messing with offsets - better safe than sorry + $clone = clone $getid3; + $clone->info['avdataoffset'] = $riff_chunk[$chunk_name][$this_index]['offset']; + $clone->info['avdataend'] = $clone->info['avdataoffset'] + $riff_chunk[$chunk_name][$this_index]['size']; + + // Analyze clone by fp + $ac3 = new getid3_ac3($clone); + $ac3->Analyze(); + + // Import from clone and destroy + $info['audio'] = $clone->info['audio']; + $info['ac3'] = $clone->info['ac3']; + $getid3->warning($clone->warnings()); + unset($clone); + } + } + + + // Dolby Digital WAV + // AC-3 content, but not encoded in same format as normal AC-3 file + // For one thing, byte order is swapped + + elseif ((strlen($riff_data_chunk_contents_test) > 0) && (substr($riff_data_chunk_contents_test, 8, 2) == "\x77\x0B")) { + + if (!$getid3->include_module_optional('audio.ac3')) { + $getid3->warning('AC3 skipped because ac3 module is missing.'); + } + + else { + + // Extract ac3 data to string + $ac3_data = ''; + for ($i = 0; $i < 28; $i += 2) { + // swap byte order + $ac3_data .= substr($riff_data_chunk_contents_test, 8 + $i + 1, 1); + $ac3_data .= substr($riff_data_chunk_contents_test, 8 + $i + 0, 1); + } + + // Clone getid3 - messing with offsets - better safe than sorry + $clone = clone $getid3; + $clone->info['avdataoffset'] = 0; + $clone->info['avdataend'] = 20; + + // Analyse clone by string + $ac3 = new getid3_ac3($clone); + $ac3->AnalyzeString($ac3_data); + + // Import from clone and destroy + $info['audio'] = $clone->info['audio']; + $info['ac3'] = $clone->info['ac3']; + $getid3->warning($clone->warnings()); + unset($clone); + } + } + + + if ((strlen($riff_data_chunk_contents_test) > 0) && (substr($riff_data_chunk_contents_test, 0, 4) == 'wvpk')) { + + // This is WavPack data + $info['wavpack']['offset'] = $riff_chunk[$chunk_name][$this_index]['offset']; + $info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($riff_data_chunk_contents_test, 4, 4)); + $this->RIFFparseWavPackHeader(substr($riff_data_chunk_contents_test, 8, 28)); + + } else { + + // This is some other kind of data (quite possibly just PCM) + // do nothing special, just skip it + + } + $this->fseek($riff_chunk[$chunk_name][$this_index]['offset'] + 8 + $chunk_size, SEEK_SET); + break; + + case 'bext': + case 'cart': + case 'fmt ': + case 'MEXT': + case 'DISP': + // always read data in + $riff_chunk[$chunk_name][$this_index]['data'] = $this->fread($chunk_size); + break; + + default: + if (!empty($list_chunk_parent) && (($riff_chunk[$chunk_name][$this_index]['offset'] + $riff_chunk[$chunk_name][$this_index]['size']) <= $list_chunk_max_offset)) { + $riff_chunk[$list_chunk_parent][$chunk_name][$this_index]['offset'] = $riff_chunk[$chunk_name][$this_index]['offset']; + $riff_chunk[$list_chunk_parent][$chunk_name][$this_index]['size'] = $riff_chunk[$chunk_name][$this_index]['size']; + unset($riff_chunk[$chunk_name][$this_index]['offset']); + unset($riff_chunk[$chunk_name][$this_index]['size']); + if (isset($riff_chunk[$chunk_name][$this_index]) && empty($riff_chunk[$chunk_name][$this_index])) { + unset($riff_chunk[$chunk_name][$this_index]); + } + if (isset($riff_chunk[$chunk_name]) && empty($riff_chunk[$chunk_name])) { + unset($riff_chunk[$chunk_name]); + } + $riff_chunk[$list_chunk_parent][$chunk_name][$this_index]['data'] = $this->fread($chunk_size); + } elseif ($chunk_size < 2048) { + // only read data in if smaller than 2kB + $riff_chunk[$chunk_name][$this_index]['data'] = $this->fread($chunk_size); + } else { + $this->fseek($chunk_size, SEEK_CUR); + } + break; + } + break; + + } + + } + + return $riff_chunk; + } + + + + private function RIFFparseWavPackHeader($wavpack3_chunk_data) { + + // typedef struct { + // char ckID [4]; + // long ckSize; + // short version; + // short bits; // added for version 2.00 + // short flags, shift; // added for version 3.00 + // long total_samples, crc, crc2; + // char extension [4], extra_bc, extras [3]; + // } WavpackHeader; + + $this->getid3->info['wavpack'] = array (); + $info_wavpack = &$this->getid3->info['wavpack']; + + $info_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($wavpack3_chunk_data, 0, 2)); + + if ($info_wavpack['version'] >= 2) { + $info_wavpack['bits'] = getid3_lib::LittleEndian2Int(substr($wavpack3_chunk_data, 2, 2)); + } + + if ($info_wavpack['version'] >= 3) { + + getid3_lib::ReadSequence('LittleEndian2Int', $info_wavpack, $wavpack3_chunk_data, 4, + array ( + 'flags_raw' => 2, + 'shift' => 2, + 'total_samples' => 4, + 'crc1' => 4, + 'crc2' => 4, + 'extension' => -4, + 'extra_bc' => 1 + ) + ); + + for ($i = 0; $i < 3; $i++) { + $info_wavpack['extras'][] = getid3_lib::LittleEndian2Int($wavpack3_chunk_data{25 + $i}); + } + + $info_wavpack['flags'] = array (); + $info_wavpack_flags = &$info_wavpack['flags']; + + $info_wavpack_flags['mono'] = (bool)($info_wavpack['flags_raw'] & 0x000001); + $info_wavpack_flags['fast_mode'] = (bool)($info_wavpack['flags_raw'] & 0x000002); + $info_wavpack_flags['raw_mode'] = (bool)($info_wavpack['flags_raw'] & 0x000004); + $info_wavpack_flags['calc_noise'] = (bool)($info_wavpack['flags_raw'] & 0x000008); + $info_wavpack_flags['high_quality'] = (bool)($info_wavpack['flags_raw'] & 0x000010); + $info_wavpack_flags['3_byte_samples'] = (bool)($info_wavpack['flags_raw'] & 0x000020); + $info_wavpack_flags['over_20_bits'] = (bool)($info_wavpack['flags_raw'] & 0x000040); + $info_wavpack_flags['use_wvc'] = (bool)($info_wavpack['flags_raw'] & 0x000080); + $info_wavpack_flags['noiseshaping'] = (bool)($info_wavpack['flags_raw'] & 0x000100); + $info_wavpack_flags['very_fast_mode'] = (bool)($info_wavpack['flags_raw'] & 0x000200); + $info_wavpack_flags['new_high_quality'] = (bool)($info_wavpack['flags_raw'] & 0x000400); + $info_wavpack_flags['cancel_extreme'] = (bool)($info_wavpack['flags_raw'] & 0x000800); + $info_wavpack_flags['cross_decorrelation'] = (bool)($info_wavpack['flags_raw'] & 0x001000); + $info_wavpack_flags['new_decorrelation'] = (bool)($info_wavpack['flags_raw'] & 0x002000); + $info_wavpack_flags['joint_stereo'] = (bool)($info_wavpack['flags_raw'] & 0x004000); + $info_wavpack_flags['extra_decorrelation'] = (bool)($info_wavpack['flags_raw'] & 0x008000); + $info_wavpack_flags['override_noiseshape'] = (bool)($info_wavpack['flags_raw'] & 0x010000); + $info_wavpack_flags['override_jointstereo'] = (bool)($info_wavpack['flags_raw'] & 0x020000); + $info_wavpack_flags['copy_source_filetime'] = (bool)($info_wavpack['flags_raw'] & 0x040000); + $info_wavpack_flags['create_exe'] = (bool)($info_wavpack['flags_raw'] & 0x080000); + } + + return true; + } + + + + public function AnalyzeString(&$string) { + + // Rewrite header_size in header + $new_header_size = getid3_lib::LittleEndian2String(strlen($string), 4); + for ($i = 0; $i < 4; $i++) { + $string{$i + 4} = $new_header_size{$i}; + } + + return parent::AnalyzeString($string); + } + + + + public static function RIFFparseWAVEFORMATex($wave_format_ex_data) { + + $wave_format_ex['raw'] = array (); + $wave_format_ex_raw = &$wave_format_ex['raw']; + + getid3_lib::ReadSequence('LittleEndian2Int', $wave_format_ex_raw, $wave_format_ex_data, 0, + array ( + 'wFormatTag' => 2, + 'nChannels' => 2, + 'nSamplesPerSec' => 4, + 'nAvgBytesPerSec' => 4, + 'nBlockAlign' => 2, + 'wBitsPerSample' => 2 + ) + ); + + if (strlen($wave_format_ex_data) > 16) { + $wave_format_ex_raw['cbSize'] = getid3_lib::LittleEndian2Int(substr($wave_format_ex_data, 16, 2)); + } + + $wave_format_ex['codec'] = getid3_riff::RIFFwFormatTagLookup($wave_format_ex_raw['wFormatTag']); + $wave_format_ex['channels'] = $wave_format_ex_raw['nChannels']; + $wave_format_ex['sample_rate'] = $wave_format_ex_raw['nSamplesPerSec']; + $wave_format_ex['bitrate'] = $wave_format_ex_raw['nAvgBytesPerSec'] * 8; + if (@$wave_format_ex_raw['wBitsPerSample']) { + $wave_format_ex['bits_per_sample'] = $wave_format_ex_raw['wBitsPerSample']; + } + + return $wave_format_ex; + } + + + + public static function RIFFwFormatTagLookup($w_format_tag) { + + static $lookup = array ( + 0x0000 => 'Microsoft Unknown Wave Format', + 0x0001 => 'Pulse Code Modulation (PCM)', + 0x0002 => 'Microsoft ADPCM', + 0x0003 => 'IEEE Float', + 0x0004 => 'Compaq Computer VSELP', + 0x0005 => 'IBM CVSD', + 0x0006 => 'Microsoft A-Law', + 0x0007 => 'Microsoft mu-Law', + 0x0008 => 'Microsoft DTS', + 0x0010 => 'OKI ADPCM', + 0x0011 => 'Intel DVI/IMA ADPCM', + 0x0012 => 'Videologic MediaSpace ADPCM', + 0x0013 => 'Sierra Semiconductor ADPCM', + 0x0014 => 'Antex Electronics G.723 ADPCM', + 0x0015 => 'DSP Solutions DigiSTD', + 0x0016 => 'DSP Solutions DigiFIX', + 0x0017 => 'Dialogic OKI ADPCM', + 0x0018 => 'MediaVision ADPCM', + 0x0019 => 'Hewlett-Packard CU', + 0x0020 => 'Yamaha ADPCM', + 0x0021 => 'Speech Compression Sonarc', + 0x0022 => 'DSP Group TrueSpeech', + 0x0023 => 'Echo Speech EchoSC1', + 0x0024 => 'Audiofile AF36', + 0x0025 => 'Audio Processing Technology APTX', + 0x0026 => 'AudioFile AF10', + 0x0027 => 'Prosody 1612', + 0x0028 => 'LRC', + 0x0030 => 'Dolby AC2', + 0x0031 => 'Microsoft GSM 6.10', + 0x0032 => 'MSNAudio', + 0x0033 => 'Antex Electronics ADPCME', + 0x0034 => 'Control Resources VQLPC', + 0x0035 => 'DSP Solutions DigiREAL', + 0x0036 => 'DSP Solutions DigiADPCM', + 0x0037 => 'Control Resources CR10', + 0x0038 => 'Natural MicroSystems VBXADPCM', + 0x0039 => 'Crystal Semiconductor IMA ADPCM', + 0x003A => 'EchoSC3', + 0x003B => 'Rockwell ADPCM', + 0x003C => 'Rockwell Digit LK', + 0x003D => 'Xebec', + 0x0040 => 'Antex Electronics G.721 ADPCM', + 0x0041 => 'G.728 CELP', + 0x0042 => 'MSG723', + 0x0050 => 'MPEG Layer-2 or Layer-1', + 0x0052 => 'RT24', + 0x0053 => 'PAC', + 0x0055 => 'MPEG Layer-3', + 0x0059 => 'Lucent G.723', + 0x0060 => 'Cirrus', + 0x0061 => 'ESPCM', + 0x0062 => 'Voxware', + 0x0063 => 'Canopus Atrac', + 0x0064 => 'G.726 ADPCM', + 0x0065 => 'G.722 ADPCM', + 0x0066 => 'DSAT', + 0x0067 => 'DSAT Display', + 0x0069 => 'Voxware Byte Aligned', + 0x0070 => 'Voxware AC8', + 0x0071 => 'Voxware AC10', + 0x0072 => 'Voxware AC16', + 0x0073 => 'Voxware AC20', + 0x0074 => 'Voxware MetaVoice', + 0x0075 => 'Voxware MetaSound', + 0x0076 => 'Voxware RT29HW', + 0x0077 => 'Voxware VR12', + 0x0078 => 'Voxware VR18', + 0x0079 => 'Voxware TQ40', + 0x0080 => 'Softsound', + 0x0081 => 'Voxware TQ60', + 0x0082 => 'MSRT24', + 0x0083 => 'G.729A', + 0x0084 => 'MVI MV12', + 0x0085 => 'DF G.726', + 0x0086 => 'DF GSM610', + 0x0088 => 'ISIAudio', + 0x0089 => 'Onlive', + 0x0091 => 'SBC24', + 0x0092 => 'Dolby AC3 SPDIF', + 0x0093 => 'MediaSonic G.723', + 0x0094 => 'Aculab PLC Prosody 8kbps', + 0x0097 => 'ZyXEL ADPCM', + 0x0098 => 'Philips LPCBB', + 0x0099 => 'Packed', + 0x00FF => 'AAC', + 0x0100 => 'Rhetorex ADPCM', + 0x0101 => 'IBM mu-law', + 0x0102 => 'IBM A-law', + 0x0103 => 'IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)', + 0x0111 => 'Vivo G.723', + 0x0112 => 'Vivo Siren', + 0x0123 => 'Digital G.723', + 0x0125 => 'Sanyo LD ADPCM', + 0x0130 => 'Sipro Lab Telecom ACELP NET', + 0x0131 => 'Sipro Lab Telecom ACELP 4800', + 0x0132 => 'Sipro Lab Telecom ACELP 8V3', + 0x0133 => 'Sipro Lab Telecom G.729', + 0x0134 => 'Sipro Lab Telecom G.729A', + 0x0135 => 'Sipro Lab Telecom Kelvin', + 0x0140 => 'Windows Media Video V8', + 0x0150 => 'Qualcomm PureVoice', + 0x0151 => 'Qualcomm HalfRate', + 0x0155 => 'Ring Zero Systems TUB GSM', + 0x0160 => 'Microsoft Audio 1', + 0x0161 => 'Windows Media Audio V7 / V8 / V9', + 0x0162 => 'Windows Media Audio Professional V9', + 0x0163 => 'Windows Media Audio Lossless V9', + 0x0200 => 'Creative Labs ADPCM', + 0x0202 => 'Creative Labs Fastspeech8', + 0x0203 => 'Creative Labs Fastspeech10', + 0x0210 => 'UHER Informatic GmbH ADPCM', + 0x0220 => 'Quarterdeck', + 0x0230 => 'I-link Worldwide VC', + 0x0240 => 'Aureal RAW Sport', + 0x0250 => 'Interactive Products HSX', + 0x0251 => 'Interactive Products RPELP', + 0x0260 => 'Consistent Software CS2', + 0x0270 => 'Sony SCX', + 0x0300 => 'Fujitsu FM Towns Snd', + 0x0400 => 'BTV Digital', + 0x0401 => 'Intel Music Coder', + 0x0450 => 'QDesign Music', + 0x0680 => 'VME VMPCM', + 0x0681 => 'AT&T Labs TPC', + 0x08AE => 'ClearJump LiteWave', + 0x1000 => 'Olivetti GSM', + 0x1001 => 'Olivetti ADPCM', + 0x1002 => 'Olivetti CELP', + 0x1003 => 'Olivetti SBC', + 0x1004 => 'Olivetti OPR', + 0x1100 => 'Lernout & Hauspie Codec (0x1100)', + 0x1101 => 'Lernout & Hauspie CELP Codec (0x1101)', + 0x1102 => 'Lernout & Hauspie SBC Codec (0x1102)', + 0x1103 => 'Lernout & Hauspie SBC Codec (0x1103)', + 0x1104 => 'Lernout & Hauspie SBC Codec (0x1104)', + 0x1400 => 'Norris', + 0x1401 => 'AT&T ISIAudio', + 0x1500 => 'Soundspace Music Compression', + 0x181C => 'VoxWare RT24 Speech', + 0x1FC4 => 'NCT Soft ALF2CD (www.nctsoft.com)', + 0x2000 => 'Dolby AC3', + 0x2001 => 'Dolby DTS', + 0x2002 => 'WAVE_FORMAT_14_4', + 0x2003 => 'WAVE_FORMAT_28_8', + 0x2004 => 'WAVE_FORMAT_COOK', + 0x2005 => 'WAVE_FORMAT_DNET', + 0x674F => 'Ogg Vorbis 1', + 0x6750 => 'Ogg Vorbis 2', + 0x6751 => 'Ogg Vorbis 3', + 0x676F => 'Ogg Vorbis 1+', + 0x6770 => 'Ogg Vorbis 2+', + 0x6771 => 'Ogg Vorbis 3+', + 0x7A21 => 'GSM-AMR (CBR, no SID)', + 0x7A22 => 'GSM-AMR (VBR, including SID)', + 0xFFFE => 'WAVE_FORMAT_EXTENSIBLE', + 0xFFFF => 'WAVE_FORMAT_DEVELOPMENT' + ); + + return @$lookup[$w_format_tag]; + } + + + + public static function RIFFfourccLookup($four_cc) { + + static $lookup = array ( + 'swot' => 'http://developer.apple.com/qa/snd/snd07.html', + '____' => 'No Codec (____)', + '_BIT' => 'BI_BITFIELDS (Raw RGB)', + '_JPG' => 'JPEG compressed', + '_PNG' => 'PNG compressed W3C/ISO/IEC (RFC-2083)', + '_RAW' => 'Full Frames (Uncompressed)', + '_RGB' => 'Raw RGB Bitmap', + '_RL4' => 'RLE 4bpp RGB', + '_RL8' => 'RLE 8bpp RGB', + '3IV1' => '3ivx MPEG-4 v1', + '3IV2' => '3ivx MPEG-4 v2', + '3IVX' => '3ivx MPEG-4', + 'AASC' => 'Autodesk Animator', + 'ABYR' => 'Kensington ?ABYR?', + 'AEMI' => 'Array Microsystems VideoONE MPEG1-I Capture', + 'AFLC' => 'Autodesk Animator FLC', + 'AFLI' => 'Autodesk Animator FLI', + 'AMPG' => 'Array Microsystems VideoONE MPEG', + 'ANIM' => 'Intel RDX (ANIM)', + 'AP41' => 'AngelPotion Definitive', + 'ASV1' => 'Asus Video v1', + 'ASV2' => 'Asus Video v2', + 'ASVX' => 'Asus Video 2.0 (audio)', + 'AUR2' => 'AuraVision Aura 2 Codec - YUV 4:2:2', + 'AURA' => 'AuraVision Aura 1 Codec - YUV 4:1:1', + 'AVDJ' => 'Independent JPEG Group\'s codec (AVDJ)', + 'AVRN' => 'Independent JPEG Group\'s codec (AVRN)', + 'AYUV' => '4:4:4 YUV (AYUV)', + 'AZPR' => 'Quicktime Apple Video (AZPR)', + 'BGR ' => 'Raw RGB32', + 'BLZ0' => 'FFmpeg MPEG-4', + 'BTVC' => 'Conexant Composite Video', + 'BINK' => 'RAD Game Tools Bink Video', + 'BT20' => 'Conexant Prosumer Video', + 'BTCV' => 'Conexant Composite Video Codec', + 'BW10' => 'Data Translation Broadway MPEG Capture', + 'CC12' => 'Intel YUV12', + 'CDVC' => 'Canopus DV', + 'CFCC' => 'Digital Processing Systems DPS Perception', + 'CGDI' => 'Microsoft Office 97 Camcorder Video', + 'CHAM' => 'Winnov Caviara Champagne', + 'CJPG' => 'Creative WebCam JPEG', + 'CLJR' => 'Cirrus Logic YUV 4:1:1', + 'CMYK' => 'Common Data Format in Printing (Colorgraph)', + 'CPLA' => 'Weitek 4:2:0 YUV Planar', + 'CRAM' => 'Microsoft Video 1 (CRAM)', + 'cvid' => 'Radius Cinepak', + 'CVID' => 'Radius Cinepak', + 'CWLT' => 'Microsoft Color WLT DIB', + 'CYUV' => 'Creative Labs YUV', + 'CYUY' => 'ATI YUV', + 'D261' => 'H.261', + 'D263' => 'H.263', + 'DIB ' => 'Device Independent Bitmap', + 'DIV1' => 'FFmpeg OpenDivX', + 'DIV2' => 'Microsoft MPEG-4 v1/v2', + 'DIV3' => 'DivX ;-) MPEG-4 v3.x Low-Motion', + 'DIV4' => 'DivX ;-) MPEG-4 v3.x Fast-Motion', + 'DIV5' => 'DivX MPEG-4 v5.x', + 'DIV6' => 'DivX ;-) (MS MPEG-4 v3.x)', + 'DIVX' => 'DivX MPEG-4 v4 (OpenDivX / Project Mayo)', + 'divx' => 'DivX MPEG-4', + 'DMB1' => 'Matrox Rainbow Runner hardware MJPEG', + 'DMB2' => 'Paradigm MJPEG', + 'DSVD' => '?DSVD?', + 'DUCK' => 'Duck TrueMotion 1.0', + 'DPS0' => 'DPS/Leitch Reality Motion JPEG', + 'DPSC' => 'DPS/Leitch PAR Motion JPEG', + 'DV25' => 'Matrox DVCPRO codec', + 'DV50' => 'Matrox DVCPRO50 codec', + 'DVC ' => 'IEC 61834 and SMPTE 314M (DVC/DV Video)', + 'DVCP' => 'IEC 61834 and SMPTE 314M (DVC/DV Video)', + 'DVHD' => 'IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps', + 'DVMA' => 'Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com)', + 'DVSL' => 'IEC Standard DV compressed in SD (SDL)', + 'DVAN' => '?DVAN?', + 'DVE2' => 'InSoft DVE-2 Videoconferencing', + 'dvsd' => 'IEC 61834 and SMPTE 314M DVC/DV Video', + 'DVSD' => 'IEC 61834 and SMPTE 314M DVC/DV Video', + 'DVX1' => 'Lucent DVX1000SP Video Decoder', + 'DVX2' => 'Lucent DVX2000S Video Decoder', + 'DVX3' => 'Lucent DVX3000S Video Decoder', + 'DX50' => 'DivX v5', + 'DXT1' => 'Microsoft DirectX Compressed Texture (DXT1)', + 'DXT2' => 'Microsoft DirectX Compressed Texture (DXT2)', + 'DXT3' => 'Microsoft DirectX Compressed Texture (DXT3)', + 'DXT4' => 'Microsoft DirectX Compressed Texture (DXT4)', + 'DXT5' => 'Microsoft DirectX Compressed Texture (DXT5)', + 'DXTC' => 'Microsoft DirectX Compressed Texture (DXTC)', + 'DXTn' => 'Microsoft DirectX Compressed Texture (DXTn)', + 'EM2V' => 'Etymonix MPEG-2 I-frame (www.etymonix.com)', + 'EKQ0' => 'Elsa ?EKQ0?', + 'ELK0' => 'Elsa ?ELK0?', + 'ESCP' => 'Eidos Escape', + 'ETV1' => 'eTreppid Video ETV1', + 'ETV2' => 'eTreppid Video ETV2', + 'ETVC' => 'eTreppid Video ETVC', + 'FLIC' => 'Autodesk FLI/FLC Animation', + 'FRWT' => 'Darim Vision Forward Motion JPEG (www.darvision.com)', + 'FRWU' => 'Darim Vision Forward Uncompressed (www.darvision.com)', + 'FLJP' => 'D-Vision Field Encoded Motion JPEG', + 'FRWA' => 'SoftLab-Nsk Forward Motion JPEG w/ alpha channel', + 'FRWD' => 'SoftLab-Nsk Forward Motion JPEG', + 'FVF1' => 'Iterated Systems Fractal Video Frame', + 'GLZW' => 'Motion LZW (gabest@freemail.hu)', + 'GPEG' => 'Motion JPEG (gabest@freemail.hu)', + 'GWLT' => 'Microsoft Greyscale WLT DIB', + 'H260' => 'Intel ITU H.260 Videoconferencing', + 'H261' => 'Intel ITU H.261 Videoconferencing', + 'H262' => 'Intel ITU H.262 Videoconferencing', + 'H263' => 'Intel ITU H.263 Videoconferencing', + 'H264' => 'Intel ITU H.264 Videoconferencing', + 'H265' => 'Intel ITU H.265 Videoconferencing', + 'H266' => 'Intel ITU H.266 Videoconferencing', + 'H267' => 'Intel ITU H.267 Videoconferencing', + 'H268' => 'Intel ITU H.268 Videoconferencing', + 'H269' => 'Intel ITU H.269 Videoconferencing', + 'HFYU' => 'Huffman Lossless Codec', + 'HMCR' => 'Rendition Motion Compensation Format (HMCR)', + 'HMRR' => 'Rendition Motion Compensation Format (HMRR)', + 'I263' => 'FFmpeg I263 decoder', + 'IF09' => 'Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane")', + 'IUYV' => 'Interlaced version of UYVY (www.leadtools.com)', + 'IY41' => 'Interlaced version of Y41P (www.leadtools.com)', + 'IYU1' => '12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard', + 'IYU2' => '24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard', + 'IYUV' => 'Planar YUV format (8-bpp Y plane, followed by 8-bpp 22 U and V planes)', + 'i263' => 'Intel ITU H.263 Videoconferencing (i263)', + 'I420' => 'Intel Indeo 4', + 'IAN ' => 'Intel Indeo 4 (RDX)', + 'ICLB' => 'InSoft CellB Videoconferencing', + 'IGOR' => 'Power DVD', + 'IJPG' => 'Intergraph JPEG', + 'ILVC' => 'Intel Layered Video', + 'ILVR' => 'ITU-T H.263+', + 'IPDV' => 'I-O Data Device Giga AVI DV Codec', + 'IR21' => 'Intel Indeo 2.1', + 'IRAW' => 'Intel YUV Uncompressed', + 'IV30' => 'Intel Indeo 3.0', + 'IV31' => 'Intel Indeo 3.1', + 'IV32' => 'Ligos Indeo 3.2', + 'IV33' => 'Ligos Indeo 3.3', + 'IV34' => 'Ligos Indeo 3.4', + 'IV35' => 'Ligos Indeo 3.5', + 'IV36' => 'Ligos Indeo 3.6', + 'IV37' => 'Ligos Indeo 3.7', + 'IV38' => 'Ligos Indeo 3.8', + 'IV39' => 'Ligos Indeo 3.9', + 'IV40' => 'Ligos Indeo Interactive 4.0', + 'IV41' => 'Ligos Indeo Interactive 4.1', + 'IV42' => 'Ligos Indeo Interactive 4.2', + 'IV43' => 'Ligos Indeo Interactive 4.3', + 'IV44' => 'Ligos Indeo Interactive 4.4', + 'IV45' => 'Ligos Indeo Interactive 4.5', + 'IV46' => 'Ligos Indeo Interactive 4.6', + 'IV47' => 'Ligos Indeo Interactive 4.7', + 'IV48' => 'Ligos Indeo Interactive 4.8', + 'IV49' => 'Ligos Indeo Interactive 4.9', + 'IV50' => 'Ligos Indeo Interactive 5.0', + 'JBYR' => 'Kensington ?JBYR?', + 'JPEG' => 'Still Image JPEG DIB', + 'JPGL' => 'Pegasus Lossless Motion JPEG', + 'KMVC' => 'Team17 Software Karl Morton\'s Video Codec', + 'LSVM' => 'Vianet Lighting Strike Vmail (Streaming) (www.vianet.com)', + 'LEAD' => 'LEAD Video Codec', + 'Ljpg' => 'LEAD MJPEG Codec', + 'MDVD' => 'Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de)', + 'MJPA' => 'Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com)', + 'MJPB' => 'Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com)', + 'MMES' => 'Matrox MPEG-2 I-frame', + 'MP2v' => 'Microsoft S-Mpeg 4 version 1 (MP2v)', + 'MP42' => 'Microsoft S-Mpeg 4 version 2 (MP42)', + 'MP43' => 'Microsoft S-Mpeg 4 version 3 (MP43)', + 'MP4S' => 'Microsoft S-Mpeg 4 version 3 (MP4S)', + 'MP4V' => 'FFmpeg MPEG-4', + 'MPG1' => 'FFmpeg MPEG 1/2', + 'MPG2' => 'FFmpeg MPEG 1/2', + 'MPG3' => 'FFmpeg DivX ;-) (MS MPEG-4 v3)', + 'MPG4' => 'Microsoft MPEG-4', + 'MPGI' => 'Sigma Designs MPEG', + 'MPNG' => 'PNG images decoder', + 'MSS1' => 'Microsoft Windows Screen Video', + 'MSZH' => 'LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)', + 'M261' => 'Microsoft H.261', + 'M263' => 'Microsoft H.263', + 'M4S2' => 'Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2)', + 'm4s2' => 'Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2)', + 'MC12' => 'ATI Motion Compensation Format (MC12)', + 'MCAM' => 'ATI Motion Compensation Format (MCAM)', + 'MJ2C' => 'Morgan Multimedia Motion JPEG2000', + 'mJPG' => 'IBM Motion JPEG w/ Huffman Tables', + 'MJPG' => 'Microsoft Motion JPEG DIB', + 'MP42' => 'Microsoft MPEG-4 (low-motion)', + 'MP43' => 'Microsoft MPEG-4 (fast-motion)', + 'MP4S' => 'Microsoft MPEG-4 (MP4S)', + 'mp4s' => 'Microsoft MPEG-4 (mp4s)', + 'MPEG' => 'Chromatic Research MPEG-1 Video I-Frame', + 'MPG4' => 'Microsoft MPEG-4 Video High Speed Compressor', + 'MPGI' => 'Sigma Designs MPEG', + 'MRCA' => 'FAST Multimedia Martin Regen Codec', + 'MRLE' => 'Microsoft Run Length Encoding', + 'MSVC' => 'Microsoft Video 1', + 'MTX1' => 'Matrox ?MTX1?', + 'MTX2' => 'Matrox ?MTX2?', + 'MTX3' => 'Matrox ?MTX3?', + 'MTX4' => 'Matrox ?MTX4?', + 'MTX5' => 'Matrox ?MTX5?', + 'MTX6' => 'Matrox ?MTX6?', + 'MTX7' => 'Matrox ?MTX7?', + 'MTX8' => 'Matrox ?MTX8?', + 'MTX9' => 'Matrox ?MTX9?', + 'MV12' => 'Motion Pixels Codec (old)', + 'MWV1' => 'Aware Motion Wavelets', + 'nAVI' => 'SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm)', + 'NT00' => 'NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com)', + 'NUV1' => 'NuppelVideo', + 'NTN1' => 'Nogatech Video Compression 1', + 'NVS0' => 'nVidia GeForce Texture (NVS0)', + 'NVS1' => 'nVidia GeForce Texture (NVS1)', + 'NVS2' => 'nVidia GeForce Texture (NVS2)', + 'NVS3' => 'nVidia GeForce Texture (NVS3)', + 'NVS4' => 'nVidia GeForce Texture (NVS4)', + 'NVS5' => 'nVidia GeForce Texture (NVS5)', + 'NVT0' => 'nVidia GeForce Texture (NVT0)', + 'NVT1' => 'nVidia GeForce Texture (NVT1)', + 'NVT2' => 'nVidia GeForce Texture (NVT2)', + 'NVT3' => 'nVidia GeForce Texture (NVT3)', + 'NVT4' => 'nVidia GeForce Texture (NVT4)', + 'NVT5' => 'nVidia GeForce Texture (NVT5)', + 'PIXL' => 'MiroXL, Pinnacle PCTV', + 'PDVC' => 'I-O Data Device Digital Video Capture DV codec', + 'PGVV' => 'Radius Video Vision', + 'PHMO' => 'IBM Photomotion', + 'PIM1' => 'MPEG Realtime (Pinnacle Cards)', + 'PIM2' => 'Pegasus Imaging ?PIM2?', + 'PIMJ' => 'Pegasus Imaging Lossless JPEG', + 'PVEZ' => 'Horizons Technology PowerEZ', + 'PVMM' => 'PacketVideo Corporation MPEG-4', + 'PVW2' => 'Pegasus Imaging Wavelet Compression', + 'Q1.0' => 'Q-Team\'s QPEG 1.0 (www.q-team.de)', + 'Q1.1' => 'Q-Team\'s QPEG 1.1 (www.q-team.de)', + 'QPEG' => 'Q-Team QPEG 1.0', + 'qpeq' => 'Q-Team QPEG 1.1', + 'RGB ' => 'Raw BGR32', + 'RGBA' => 'Raw RGB w/ Alpha', + 'RMP4' => 'REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com)', + 'ROQV' => 'Id RoQ File Video Decoder', + 'RPZA' => 'Quicktime Apple Video (RPZA)', + 'RUD0' => 'Rududu video codec (http://rududu.ifrance.com/rududu/)', + 'RV10' => 'RealVideo 1.0 (aka RealVideo 5.0)', + 'RV13' => 'RealVideo 1.0 (RV13)', + 'RV20' => 'RealVideo G2', + 'RV30' => 'RealVideo 8', + 'RV40' => 'RealVideo 9', + 'RGBT' => 'Raw RGB w/ Transparency', + 'RLE ' => 'Microsoft Run Length Encoder', + 'RLE4' => 'Run Length Encoded (4bpp, 16-color)', + 'RLE8' => 'Run Length Encoded (8bpp, 256-color)', + 'RT21' => 'Intel Indeo RealTime Video 2.1', + 'rv20' => 'RealVideo G2', + 'rv30' => 'RealVideo 8', + 'RVX ' => 'Intel RDX (RVX )', + 'SMC ' => 'Apple Graphics (SMC )', + 'SP54' => 'Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2', + 'SPIG' => 'Radius Spigot', + 'SVQ3' => 'Sorenson Video 3 (Apple Quicktime 5)', + 's422' => 'Tekram VideoCap C210 YUV 4:2:2', + 'SDCC' => 'Sun Communication Digital Camera Codec', + 'SFMC' => 'CrystalNet Surface Fitting Method', + 'SMSC' => 'Radius SMSC', + 'SMSD' => 'Radius SMSD', + 'smsv' => 'WorldConnect Wavelet Video', + 'SPIG' => 'Radius Spigot', + 'SPLC' => 'Splash Studios ACM Audio Codec (www.splashstudios.net)', + 'SQZ2' => 'Microsoft VXTreme Video Codec V2', + 'STVA' => 'ST Microelectronics CMOS Imager Data (Bayer)', + 'STVB' => 'ST Microelectronics CMOS Imager Data (Nudged Bayer)', + 'STVC' => 'ST Microelectronics CMOS Imager Data (Bunched)', + 'STVX' => 'ST Microelectronics CMOS Imager Data (Extended CODEC Data Format)', + 'STVY' => 'ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data)', + 'SV10' => 'Sorenson Video R1', + 'SVQ1' => 'Sorenson Video', + 'T420' => 'Toshiba YUV 4:2:0', + 'TM2A' => 'Duck TrueMotion Archiver 2.0 (www.duck.com)', + 'TVJP' => 'Pinnacle/Truevision Targa 2000 board (TVJP)', + 'TVMJ' => 'Pinnacle/Truevision Targa 2000 board (TVMJ)', + 'TY0N' => 'Tecomac Low-Bit Rate Codec (www.tecomac.com)', + 'TY2C' => 'Trident Decompression Driver', + 'TLMS' => 'TeraLogic Motion Intraframe Codec (TLMS)', + 'TLST' => 'TeraLogic Motion Intraframe Codec (TLST)', + 'TM20' => 'Duck TrueMotion 2.0', + 'TM2X' => 'Duck TrueMotion 2X', + 'TMIC' => 'TeraLogic Motion Intraframe Codec (TMIC)', + 'TMOT' => 'Horizons Technology TrueMotion S', + 'tmot' => 'Horizons TrueMotion Video Compression', + 'TR20' => 'Duck TrueMotion RealTime 2.0', + 'TSCC' => 'TechSmith Screen Capture Codec', + 'TV10' => 'Tecomac Low-Bit Rate Codec', + 'TY2N' => 'Trident ?TY2N?', + 'U263' => 'UB Video H.263/H.263+/H.263++ Decoder', + 'UMP4' => 'UB Video MPEG 4 (www.ubvideo.com)', + 'UYNV' => 'Nvidia UYVY packed 4:2:2', + 'UYVP' => 'Evans & Sutherland YCbCr 4:2:2 extended precision', + 'UCOD' => 'eMajix.com ClearVideo', + 'ULTI' => 'IBM Ultimotion', + 'UYVY' => 'UYVY packed 4:2:2', + 'V261' => 'Lucent VX2000S', + 'VIFP' => 'VFAPI Reader Codec (www.yks.ne.jp/~hori/)', + 'VIV1' => 'FFmpeg H263+ decoder', + 'VIV2' => 'Vivo H.263', + 'VQC2' => 'Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf)', + 'VTLP' => 'Alaris VideoGramPiX', + 'VYU9' => 'ATI YUV (VYU9)', + 'VYUY' => 'ATI YUV (VYUY)', + 'V261' => 'Lucent VX2000S', + 'V422' => 'Vitec Multimedia 24-bit YUV 4:2:2 Format', + 'V655' => 'Vitec Multimedia 16-bit YUV 4:2:2 Format', + 'VCR1' => 'ATI Video Codec 1', + 'VCR2' => 'ATI Video Codec 2', + 'VCR3' => 'ATI VCR 3.0', + 'VCR4' => 'ATI VCR 4.0', + 'VCR5' => 'ATI VCR 5.0', + 'VCR6' => 'ATI VCR 6.0', + 'VCR7' => 'ATI VCR 7.0', + 'VCR8' => 'ATI VCR 8.0', + 'VCR9' => 'ATI VCR 9.0', + 'VDCT' => 'Vitec Multimedia Video Maker Pro DIB', + 'VDOM' => 'VDOnet VDOWave', + 'VDOW' => 'VDOnet VDOLive (H.263)', + 'VDTZ' => 'Darim Vison VideoTizer YUV', + 'VGPX' => 'Alaris VideoGramPiX', + 'VIDS' => 'Vitec Multimedia YUV 4:2:2 CCIR 601 for V422', + 'VIVO' => 'Vivo H.263 v2.00', + 'vivo' => 'Vivo H.263', + 'VIXL' => 'Miro/Pinnacle Video XL', + 'VLV1' => 'VideoLogic/PURE Digital Videologic Capture', + 'VP30' => 'On2 VP3.0', + 'VP31' => 'On2 VP3.1', + 'VX1K' => 'Lucent VX1000S Video Codec', + 'VX2K' => 'Lucent VX2000S Video Codec', + 'VXSP' => 'Lucent VX1000SP Video Codec', + 'WBVC' => 'Winbond W9960', + 'WHAM' => 'Microsoft Video 1 (WHAM)', + 'WINX' => 'Winnov Software Compression', + 'WJPG' => 'AverMedia Winbond JPEG', + 'WMV1' => 'Windows Media Video V7', + 'WMV2' => 'Windows Media Video V8', + 'WMV3' => 'Windows Media Video V9', + 'WNV1' => 'Winnov Hardware Compression', + 'XYZP' => 'Extended PAL format XYZ palette (www.riff.org)', + 'x263' => 'Xirlink H.263', + 'XLV0' => 'NetXL Video Decoder', + 'XMPG' => 'Xing MPEG (I-Frame only)', + 'XVID' => 'XviD MPEG-4 (www.xvid.org)', + 'XXAN' => '?XXAN?', + 'YU92' => 'Intel YUV (YU92)', + 'YUNV' => 'Nvidia Uncompressed YUV 4:2:2', + 'YUVP' => 'Extended PAL format YUV palette (www.riff.org)', + 'Y211' => 'YUV 2:1:1 Packed', + 'Y411' => 'YUV 4:1:1 Packed', + 'Y41B' => 'Weitek YUV 4:1:1 Planar', + 'Y41P' => 'Brooktree PC1 YUV 4:1:1 Packed', + 'Y41T' => 'Brooktree PC1 YUV 4:1:1 with transparency', + 'Y42B' => 'Weitek YUV 4:2:2 Planar', + 'Y42T' => 'Brooktree UYUV 4:2:2 with transparency', + 'Y422' => 'ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera', + 'Y800' => 'Simple, single Y plane for monochrome images', + 'Y8 ' => 'Grayscale video', + 'YC12' => 'Intel YUV 12 codec', + 'YUV8' => 'Winnov Caviar YUV8', + 'YUV9' => 'Intel YUV9', + 'YUY2' => 'Uncompressed YUV 4:2:2', + 'YUYV' => 'Canopus YUV', + 'YV12' => 'YVU12 Planar', + 'YVU9' => 'Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes)', + 'YVYU' => 'YVYU 4:2:2 Packed', + 'ZLIB' => 'Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)', + 'ZPEG' => 'Metheus Video Zipper' + ); + + return @$lookup[$four_cc]; + } + + + + public static function RIFFcommentsParse(&$riff_info_aray, &$comments_target_array) { + + static $lookup = array( + 'IARL' => 'archivallocation', + 'IART' => 'artist', + 'ICDS' => 'costumedesigner', + 'ICMS' => 'commissionedby', + 'ICMT' => 'comment', + 'ICNT' => 'country', + 'ICOP' => 'copyright', + 'ICRD' => 'creationdate', + 'IDIM' => 'dimensions', + 'IDIT' => 'digitizationdate', + 'IDPI' => 'resolution', + 'IDST' => 'distributor', + 'IEDT' => 'editor', + 'IENG' => 'engineers', + 'IFRM' => 'accountofparts', + 'IGNR' => 'genre', + 'IKEY' => 'keywords', + 'ILGT' => 'lightness', + 'ILNG' => 'language', + 'IMED' => 'orignalmedium', + 'IMUS' => 'composer', + 'INAM' => 'title', + 'IPDS' => 'productiondesigner', + 'IPLT' => 'palette', + 'IPRD' => 'product', + 'IPRO' => 'producer', + 'IPRT' => 'part', + 'IRTD' => 'rating', + 'ISBJ' => 'subject', + 'ISFT' => 'software', + 'ISGN' => 'secondarygenre', + 'ISHP' => 'sharpness', + 'ISRC' => 'sourcesupplier', + 'ISRF' => 'digitizationsource', + 'ISTD' => 'productionstudio', + 'ISTR' => 'starring', + 'ITCH' => 'encoded_by', + 'IWEB' => 'url', + 'IWRI' => 'writer' + ); + + foreach ($lookup as $key => $value) { + if (isset($riff_info_aray[$key])) { + foreach ($riff_info_aray[$key] as $comment_id => $comment_data) { + if (trim($comment_data['data']) != '') { + @$comments_target_array[$value][] = trim($comment_data['data']); + } + } + } + } + return true; + } + + + + public static function array_merge_noclobber($array1, $array2) { + if (!is_array($array1) || !is_array($array2)) { + return false; + } + $new_array = $array1; + foreach ($array2 as $key => $val) { + if (is_array($val) && isset($new_array[$key]) && is_array($new_array[$key])) { + $new_array[$key] = getid3_riff::array_merge_noclobber($new_array[$key], $val); + } elseif (!isset($new_array[$key])) { + $new_array[$key] = $val; + } + } + return $new_array; + } + + + + public static function DateMac2Unix($mac_date) { + + // Macintosh timestamp: seconds since 00:00h January 1, 1904 + // UNIX timestamp: seconds since 00:00h January 1, 1970 + return (int)($mac_date - 2082844800); + } + + + + public static function FixedPoint16_16($raw_data) { + + return getid3_lib::BigEndian2Int(substr($raw_data, 0, 2)) + (float)(getid3_lib::BigEndian2Int(substr($raw_data, 2, 2)) / 65536); // pow(2, 16) = 65536 + } + + + + function BigEndian2Float($byte_word) { + + // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic + // http://www.psc.edu/general/software/packages/ieee/ieee.html + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html + + $bit_word = getid3_lib::BigEndian2Bin($byte_word); + $sign_bit = $bit_word{0}; + + switch (strlen($byte_word) * 8) { + case 32: + $exponent_bits = 8; + $fraction_bits = 23; + break; + + case 64: + $exponent_bits = 11; + $fraction_bits = 52; + break; + + case 80: + // 80-bit Apple SANE format + // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ + $exponent_string = substr($bit_word, 1, 15); + $is_normalized = intval($bit_word{16}); + $fraction_string = substr($bit_word, 17, 63); + $exponent = pow(2, bindec($exponent_string) - 16383); + $fraction = $is_normalized + bindec($fraction_string) / bindec('1'.str_repeat('0', strlen($fraction_string))); + $float_value = $exponent * $fraction; + if ($sign_bit == '1') { + $float_value *= -1; + } + return $float_value; + break; + + default: + return false; + break; + } + $exponent_string = substr($bit_word, 1, $exponent_bits); + $fraction_string = substr($bit_word, $exponent_bits + 1, $fraction_bits); + $exponent = bindec($exponent_string); + $fraction = bindec($fraction_string); + + if (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction != 0)) { + // Not a Number + $float_value = false; + } elseif (($exponent == (pow(2, $exponent_bits) - 1)) && ($fraction == 0)) { + if ($sign_bit == '1') { + $float_value = '-infinity'; + } else { + $float_value = '+infinity'; + } + } elseif (($exponent == 0) && ($fraction == 0)) { + if ($sign_bit == '1') { + $float_value = -0; + } else { + $float_value = 0; + } + $float_value = ($sign_bit ? 0 : -0); + } elseif (($exponent == 0) && ($fraction != 0)) { + // These are 'unnormalized' values + $float_value = pow(2, (-1 * (pow(2, $exponent_bits - 1) - 2))) * bindec($fraction_string) / bindec('1'.str_repeat('0', strlen($fraction_string))); + if ($sign_bit == '1') { + $float_value *= -1; + } + } elseif ($exponent != 0) { + $float_value = pow(2, ($exponent - (pow(2, $exponent_bits - 1) - 1))) * (1 + bindec($fraction_string) / bindec('1'.str_repeat('0', strlen($fraction_string)))); + if ($sign_bit == '1') { + $float_value *= -1; + } + } + return (float) $float_value; + } +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio-video.swf.php b/plugins/getId3Plugin/lib/module.audio-video.swf.php new file mode 100644 index 0000000..fe556f8 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio-video.swf.php @@ -0,0 +1,154 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio-video.swf.php | +// | module for analyzing Macromedia Shockwave Flash files. | +// | dependencies: zlib support in PHP | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio-video.swf.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_swf extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['fileformat'] = 'swf'; + $getid3->info['video']['dataformat'] = 'swf'; + + // http://www.openswf.org/spec/SWFfileformat.html + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + $swf_file_data = fread($getid3->fp, $getid3->info['avdataend'] - $getid3->info['avdataoffset']); // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data + + $getid3->info['swf']['header']['signature'] = substr($swf_file_data, 0, 3); + switch ($getid3->info['swf']['header']['signature']) { + + case 'FWS': + $getid3->info['swf']['header']['compressed'] = false; + break; + + case 'CWS': + $getid3->info['swf']['header']['compressed'] = true; + break; + + default: + throw new getid3_exception('Expecting "FWS" or "CWS" at offset '.$getid3->info['avdataoffset'].', found "'.$getid3->info['swf']['header']['signature'].'"'); + } + $getid3->info['swf']['header']['version'] = getid3_lib::LittleEndian2Int($swf_file_data{3}); + $getid3->info['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($swf_file_data, 4, 4)); + + if (!function_exists('gzuncompress')) { + throw new getid3_exception('getid3_swf requires --zlib support in PHP.'); + } + + if ($getid3->info['swf']['header']['compressed']) { + + if ($uncompressed_file_data = @gzuncompress(substr($swf_file_data, 8))) { + $swf_file_data = substr($swf_file_data, 0, 8).$uncompressed_file_data; + + } else { + throw new getid3_exception('Error decompressing compressed SWF data'); + } + + } + + $frame_size_bits_per_value = (ord(substr($swf_file_data, 8, 1)) & 0xF8) >> 3; + $frame_size_data_length = ceil((5 + (4 * $frame_size_bits_per_value)) / 8); + $frame_size_data_string = str_pad(decbin(ord($swf_file_data[8]) & 0x07), 3, '0', STR_PAD_LEFT); + + for ($i = 1; $i < $frame_size_data_length; $i++) { + $frame_size_data_string .= str_pad(decbin(ord(substr($swf_file_data, 8 + $i, 1))), 8, '0', STR_PAD_LEFT); + } + + list($x1, $x2, $y1, $y2) = explode("\n", wordwrap($frame_size_data_string, $frame_size_bits_per_value, "\n", 1)); + $getid3->info['swf']['header']['frame_width'] = bindec($x2); + $getid3->info['swf']['header']['frame_height'] = bindec($y2); + + // http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm + // Next in the header is the frame rate, which is kind of weird. + // It is supposed to be stored as a 16bit integer, but the first byte + // (or last depending on how you look at it) is completely ignored. + // Example: 0x000C -> 0x0C -> 12 So the frame rate is 12 fps. + + // Byte at (8 + $frame_size_data_length) is always zero and ignored + $getid3->info['swf']['header']['frame_rate'] = getid3_lib::LittleEndian2Int($swf_file_data[9 + $frame_size_data_length]); + $getid3->info['swf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($swf_file_data, 10 + $frame_size_data_length, 2)); + + $getid3->info['video']['frame_rate'] = $getid3->info['swf']['header']['frame_rate']; + $getid3->info['video']['resolution_x'] = intval(round($getid3->info['swf']['header']['frame_width'] / 20)); + $getid3->info['video']['resolution_y'] = intval(round($getid3->info['swf']['header']['frame_height'] / 20)); + $getid3->info['video']['pixel_aspect_ratio'] = (float)1; + + if (($getid3->info['swf']['header']['frame_count'] > 0) && ($getid3->info['swf']['header']['frame_rate'] > 0)) { + $getid3->info['playtime_seconds'] = $getid3->info['swf']['header']['frame_count'] / $getid3->info['swf']['header']['frame_rate']; + } + + + // SWF tags + + $current_offset = 12 + $frame_size_data_length; + $swf_data_length = strlen($swf_file_data); + + while ($current_offset < $swf_data_length) { + + $tag_ID_tag_length = getid3_lib::LittleEndian2Int(substr($swf_file_data, $current_offset, 2)); + $tag_ID = ($tag_ID_tag_length & 0xFFFC) >> 6; + $tag_length = ($tag_ID_tag_length & 0x003F); + $current_offset += 2; + if ($tag_length == 0x3F) { + $tag_length = getid3_lib::LittleEndian2Int(substr($swf_file_data, $current_offset, 4)); + $current_offset += 4; + } + + unset($tag_data); + $tag_data['offset'] = $current_offset; + $tag_data['size'] = $tag_length; + $tag_data['id'] = $tag_ID; + $tag_data['data'] = substr($swf_file_data, $current_offset, $tag_length); + switch ($tag_ID) { + + case 0: // end of movie + break 2; + + case 9: // Set background color + $getid3->info['swf']['bgcolor'] = strtoupper(str_pad(dechex(getid3_lib::BigEndian2Int($tag_data['data'])), 6, '0', STR_PAD_LEFT)); + break; + + default: + /* + if ($ReturnAllTagData) { + $getid3->info['swf']['tags'][] = $tag_data; + } + */ + break; + } + + $current_offset += $tag_length; + } + + return true; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.aac.php b/plugins/getId3Plugin/lib/module.audio.aac.php new file mode 100644 index 0000000..4d35fb2 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.aac.php @@ -0,0 +1,538 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.aac.php // +// module for analyzing AAC Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_aac +{ + + // new combined constructor + function getid3_aac(&$fd, &$ThisFileInfo, $option) { + + if ($option === 'adif') { + $this->getAACADIFheaderFilepointer($fd, $ThisFileInfo); + } + elseif ($option === 'adts') { + $this->getAACADTSheaderFilepointer($fd, $ThisFileInfo); + } + } + + + + function getAACADIFheaderFilepointer(&$fd, &$ThisFileInfo) { + $ThisFileInfo['fileformat'] = 'aac'; + $ThisFileInfo['audio']['dataformat'] = 'aac'; + $ThisFileInfo['audio']['lossless'] = false; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $AACheader = fread($fd, 1024); + $offset = 0; + + if (substr($AACheader, 0, 4) == 'ADIF') { + + // http://faac.sourceforge.net/wiki/index.php?page=ADIF + + // http://libmpeg.org/mpeg4/doc/w2203tfs.pdf + // adif_header() { + // adif_id 32 + // copyright_id_present 1 + // if( copyright_id_present ) + // copyright_id 72 + // original_copy 1 + // home 1 + // bitstream_type 1 + // bitrate 23 + // num_program_config_elements 4 + // for (i = 0; i < num_program_config_elements + 1; i++ ) { + // if( bitstream_type == '0' ) + // adif_buffer_fullness 20 + // program_config_element() + // } + // } + + $AACheaderBitstream = getid3_lib::BigEndian2Bin($AACheader); + $bitoffset = 0; + + $ThisFileInfo['aac']['header_type'] = 'ADIF'; + $bitoffset += 32; + $ThisFileInfo['aac']['header']['mpeg_version'] = 4; + + $ThisFileInfo['aac']['header']['copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); + $bitoffset += 1; + if ($ThisFileInfo['aac']['header']['copyright']) { + $ThisFileInfo['aac']['header']['copyright_id'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72)); + $bitoffset += 72; + } + $ThisFileInfo['aac']['header']['original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); + $bitoffset += 1; + $ThisFileInfo['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); + $bitoffset += 1; + $ThisFileInfo['aac']['header']['is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); + $bitoffset += 1; + if ($ThisFileInfo['aac']['header']['is_vbr']) { + $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; + $ThisFileInfo['aac']['header']['bitrate_max'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23)); + $bitoffset += 23; + } else { + $ThisFileInfo['audio']['bitrate_mode'] = 'cbr'; + $ThisFileInfo['aac']['header']['bitrate'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23)); + $bitoffset += 23; + $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['aac']['header']['bitrate']; + } + if ($ThisFileInfo['audio']['bitrate'] == 0) { + $ThisFileInfo['error'][] = 'Corrupt AAC file: bitrate_audio == zero'; + return false; + } + $ThisFileInfo['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + + for ($i = 0; $i < $ThisFileInfo['aac']['header']['num_program_configs']; $i++) { + // http://www.audiocoding.com/wiki/index.php?page=program_config_element + + // buffer_fullness 20 + + // element_instance_tag 4 + // object_type 2 + // sampling_frequency_index 4 + // num_front_channel_elements 4 + // num_side_channel_elements 4 + // num_back_channel_elements 4 + // num_lfe_channel_elements 2 + // num_assoc_data_elements 3 + // num_valid_cc_elements 4 + // mono_mixdown_present 1 + // mono_mixdown_element_number 4 if mono_mixdown_present == 1 + // stereo_mixdown_present 1 + // stereo_mixdown_element_number 4 if stereo_mixdown_present == 1 + // matrix_mixdown_idx_present 1 + // matrix_mixdown_idx 2 if matrix_mixdown_idx_present == 1 + // pseudo_surround_enable 1 if matrix_mixdown_idx_present == 1 + // for (i = 0; i < num_front_channel_elements; i++) { + // front_element_is_cpe[i] 1 + // front_element_tag_select[i] 4 + // } + // for (i = 0; i < num_side_channel_elements; i++) { + // side_element_is_cpe[i] 1 + // side_element_tag_select[i] 4 + // } + // for (i = 0; i < num_back_channel_elements; i++) { + // back_element_is_cpe[i] 1 + // back_element_tag_select[i] 4 + // } + // for (i = 0; i < num_lfe_channel_elements; i++) { + // lfe_element_tag_select[i] 4 + // } + // for (i = 0; i < num_assoc_data_elements; i++) { + // assoc_data_element_tag_select[i] 4 + // } + // for (i = 0; i < num_valid_cc_elements; i++) { + // cc_element_is_ind_sw[i] 1 + // valid_cc_element_tag_select[i] 4 + // } + // byte_alignment() VAR + // comment_field_bytes 8 + // for (i = 0; i < comment_field_bytes; i++) { + // comment_field_data[i] 8 + // } + + if (!$ThisFileInfo['aac']['header']['is_vbr']) { + $ThisFileInfo['aac']['program_configs'][$i]['buffer_fullness'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20)); + $bitoffset += 20; + } + $ThisFileInfo['aac']['program_configs'][$i]['element_instance_tag'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $ThisFileInfo['aac']['program_configs'][$i]['object_type'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + $ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $ThisFileInfo['aac']['program_configs'][$i]['num_front_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $ThisFileInfo['aac']['program_configs'][$i]['num_side_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $ThisFileInfo['aac']['program_configs'][$i]['num_back_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $ThisFileInfo['aac']['program_configs'][$i]['num_lfe_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + $ThisFileInfo['aac']['program_configs'][$i]['num_assoc_data_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3)); + $bitoffset += 3; + $ThisFileInfo['aac']['program_configs'][$i]['num_valid_cc_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + if ($ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_present']) { + $ThisFileInfo['aac']['program_configs'][$i]['mono_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + $ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + if ($ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_present']) { + $ThisFileInfo['aac']['program_configs'][$i]['stereo_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + $ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + if ($ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) { + $ThisFileInfo['aac']['program_configs'][$i]['matrix_mixdown_idx'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + $ThisFileInfo['aac']['program_configs'][$i]['pseudo_surround_enable'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + } + for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) { + $ThisFileInfo['aac']['program_configs'][$i]['front_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $ThisFileInfo['aac']['program_configs'][$i]['front_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) { + $ThisFileInfo['aac']['program_configs'][$i]['side_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $ThisFileInfo['aac']['program_configs'][$i]['side_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) { + $ThisFileInfo['aac']['program_configs'][$i]['back_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $ThisFileInfo['aac']['program_configs'][$i]['back_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) { + $ThisFileInfo['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) { + $ThisFileInfo['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $ThisFileInfo['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) { + $ThisFileInfo['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $ThisFileInfo['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + + $bitoffset = ceil($bitoffset / 8) * 8; + + $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8)); + $bitoffset += 8; + $ThisFileInfo['aac']['program_configs'][$i]['comment_field'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes'])); + $bitoffset += 8 * $ThisFileInfo['aac']['program_configs'][$i]['comment_field_bytes']; + + + $ThisFileInfo['aac']['header']['profile_text'] = $this->AACprofileLookup($ThisFileInfo['aac']['program_configs'][$i]['object_type'], $ThisFileInfo['aac']['header']['mpeg_version']); + $ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency'] = $this->AACsampleRateLookup($ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency_index']); + $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['aac']['program_configs'][$i]['sampling_frequency']; + $ThisFileInfo['audio']['channels'] = $this->AACchannelCountCalculate($ThisFileInfo['aac']['program_configs'][$i]); + if ($ThisFileInfo['aac']['program_configs'][$i]['comment_field']) { + $ThisFileInfo['aac']['comments'][] = $ThisFileInfo['aac']['program_configs'][$i]['comment_field']; + } + } + $ThisFileInfo['playtime_seconds'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate']; + + $ThisFileInfo['audio']['encoder_options'] = $ThisFileInfo['aac']['header_type'].' '.$ThisFileInfo['aac']['header']['profile_text']; + + + + return true; + + } else { + + unset($ThisFileInfo['fileformat']); + unset($ThisFileInfo['aac']); + $ThisFileInfo['error'][] = 'AAC-ADIF synch not found at offset '.$ThisFileInfo['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)'; + return false; + + } + + } + + + function getAACADTSheaderFilepointer(&$fd, &$ThisFileInfo, $MaxFramesToScan=1000000, $ReturnExtendedInfo=false) { + // based loosely on code from AACfile by Jurgen Faul + // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html + + + // http://faac.sourceforge.net/wiki/index.php?page=ADTS + + // * ADTS Fixed Header: these don't change from frame to frame + // syncword 12 always: '111111111111' + // ID 1 0: MPEG-4, 1: MPEG-2 + // layer 2 always: '00' + // protection_absent 1 + // profile 2 + // sampling_frequency_index 4 + // private_bit 1 + // channel_configuration 3 + // original/copy 1 + // home 1 + // emphasis 2 only if ID == 0 (ie MPEG-4) + + // * ADTS Variable Header: these can change from frame to frame + // copyright_identification_bit 1 + // copyright_identification_start 1 + // aac_frame_length 13 length of the frame including header (in bytes) + // adts_buffer_fullness 11 0x7FF indicates VBR + // no_raw_data_blocks_in_frame 2 + + // * ADTS Error check + // crc_check 16 only if protection_absent == 0 + + $byteoffset = 0; + $framenumber = 0; + + // Init bit pattern array + static $decbin = array(); + + // Populate $bindec + for ($i = 0; $i < 256; $i++) { + $decbin[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); + } + + // used to calculate bitrate below + $BitrateCache = array(); + + + while (true) { + // breaks out when end-of-file encountered, or invalid data found, + // or MaxFramesToScan frames have been scanned + + fseek($fd, $byteoffset, SEEK_SET); + + // First get substring + $substring = fread($fd, 10); + $substringlength = strlen($substring); + if ($substringlength != 10) { + $ThisFileInfo['error'][] = 'Failed to read 10 bytes at offset '.(ftell($fd) - $substringlength).' (only read '.$substringlength.' bytes)'; + return false; + } + + // Initialise $AACheaderBitstream + $AACheaderBitstream = ''; + + // Loop thru substring chars + for ($i = 0; $i < 10; $i++) { + $AACheaderBitstream .= $decbin[$substring{$i}]; + } + + $bitoffset = 0; + + $synctest = bindec(substr($AACheaderBitstream, $bitoffset, 12)); + + $bitoffset += 12; + if ($synctest != 0x0FFF) { + $ThisFileInfo['error'][] = 'Synch pattern (0x0FFF) not found at offset '.(ftell($fd) - 10).' (found 0x0'.strtoupper(dechex($synctest)).' instead)'; + if ($ThisFileInfo['fileformat'] == 'aac') { + return true; + } + return false; + } + + // Gather info for first frame only - this takes time to do 1000 times! + if ($framenumber > 0) { + + if (!$AACheaderBitstream[$bitoffset]) { + + // MPEG-4 + $bitoffset += 20; + + } else { + + // MPEG-2 + $bitoffset += 18; + + } + + } else { + + $ThisFileInfo['aac']['header_type'] = 'ADTS'; + $ThisFileInfo['aac']['header']['synch'] = $synctest; + $ThisFileInfo['fileformat'] = 'aac'; + $ThisFileInfo['audio']['dataformat'] = 'aac'; + + $ThisFileInfo['aac']['header']['mpeg_version'] = ((substr($AACheaderBitstream, $bitoffset, 1) == '0') ? 4 : 2); + $bitoffset += 1; + $ThisFileInfo['aac']['header']['layer'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + if ($ThisFileInfo['aac']['header']['layer'] != 0) { + $ThisFileInfo['error'][] = 'Layer error - expected 0x00, found 0x'.dechex($ThisFileInfo['aac']['header']['layer']).' instead'; + return false; + } + $ThisFileInfo['aac']['header']['crc_present'] = ((substr($AACheaderBitstream, $bitoffset, 1) == '0') ? true : false); + $bitoffset += 1; + $ThisFileInfo['aac']['header']['profile_id'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + $ThisFileInfo['aac']['header']['profile_text'] = $this->AACprofileLookup($ThisFileInfo['aac']['header']['profile_id'], $ThisFileInfo['aac']['header']['mpeg_version']); + + $ThisFileInfo['aac']['header']['sample_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $ThisFileInfo['aac']['header']['sample_frequency'] = $this->AACsampleRateLookup($ThisFileInfo['aac']['header']['sample_frequency_index']); + if ($ThisFileInfo['aac']['header']['sample_frequency'] == 0) { + $ThisFileInfo['error'][] = 'Corrupt AAC file: sample_frequency == zero'; + return false; + } + $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['aac']['header']['sample_frequency']; + + $ThisFileInfo['aac']['header']['private'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $ThisFileInfo['aac']['header']['channel_configuration'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3)); + $bitoffset += 3; + $ThisFileInfo['audio']['channels'] = $ThisFileInfo['aac']['header']['channel_configuration']; + $ThisFileInfo['aac']['header']['original'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $ThisFileInfo['aac']['header']['home'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + + if ($ThisFileInfo['aac']['header']['mpeg_version'] == 4) { + $ThisFileInfo['aac']['header']['emphasis'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + } + + if ($ReturnExtendedInfo) { + + $ThisFileInfo['aac'][$framenumber]['copyright_id_bit'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $ThisFileInfo['aac'][$framenumber]['copyright_id_start'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + + } else { + + $bitoffset += 2; + + } + + } + + $FrameLength = bindec(substr($AACheaderBitstream, $bitoffset, 13)); + + if (!isset($BitrateCache[$FrameLength])) { + $BitrateCache[$FrameLength] = ($ThisFileInfo['aac']['header']['sample_frequency'] / 1024) * $FrameLength * 8; + } + @$ThisFileInfo['aac']['bitrate_distribution'][$BitrateCache[$FrameLength]]++; + + $ThisFileInfo['aac'][$framenumber]['aac_frame_length'] = $FrameLength; + $bitoffset += 13; + $ThisFileInfo['aac'][$framenumber]['adts_buffer_fullness'] = bindec(substr($AACheaderBitstream, $bitoffset, 11)); + $bitoffset += 11; + if ($ThisFileInfo['aac'][$framenumber]['adts_buffer_fullness'] == 0x07FF) { + $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; + } else { + $ThisFileInfo['audio']['bitrate_mode'] = 'cbr'; + } + $ThisFileInfo['aac'][$framenumber]['num_raw_data_blocks'] = bindec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + + if ($ThisFileInfo['aac']['header']['crc_present']) { + //$ThisFileInfo['aac'][$framenumber]['crc'] = bindec(substr($AACheaderBitstream, $bitoffset, 16)); + $bitoffset += 16; + } + + if (!$ReturnExtendedInfo) { + unset($ThisFileInfo['aac'][$framenumber]); + } + + $byteoffset += $FrameLength; + if ((++$framenumber < $MaxFramesToScan) && (($byteoffset + 10) < $ThisFileInfo['avdataend'])) { + + // keep scanning + + } else { + + $ThisFileInfo['aac']['frames'] = $framenumber; + $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] / $byteoffset) * (($framenumber * 1024) / $ThisFileInfo['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds + if ($ThisFileInfo['playtime_seconds'] == 0) { + $ThisFileInfo['error'][] = 'Corrupt AAC file: playtime_seconds == zero'; + return false; + } + $ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds']; + ksort($ThisFileInfo['aac']['bitrate_distribution']); + + $ThisFileInfo['audio']['encoder_options'] = $ThisFileInfo['aac']['header_type'].' '.$ThisFileInfo['aac']['header']['profile_text']; + + return true; + + } + } + // should never get here. + } + + function AACsampleRateLookup($samplerateid) { + static $AACsampleRateLookup = array(); + if (empty($AACsampleRateLookup)) { + $AACsampleRateLookup[0] = 96000; + $AACsampleRateLookup[1] = 88200; + $AACsampleRateLookup[2] = 64000; + $AACsampleRateLookup[3] = 48000; + $AACsampleRateLookup[4] = 44100; + $AACsampleRateLookup[5] = 32000; + $AACsampleRateLookup[6] = 24000; + $AACsampleRateLookup[7] = 22050; + $AACsampleRateLookup[8] = 16000; + $AACsampleRateLookup[9] = 12000; + $AACsampleRateLookup[10] = 11025; + $AACsampleRateLookup[11] = 8000; + $AACsampleRateLookup[12] = 0; + $AACsampleRateLookup[13] = 0; + $AACsampleRateLookup[14] = 0; + $AACsampleRateLookup[15] = 0; + } + return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid'); + } + + function AACprofileLookup($profileid, $mpegversion) { + static $AACprofileLookup = array(); + if (empty($AACprofileLookup)) { + $AACprofileLookup[2][0] = 'Main profile'; + $AACprofileLookup[2][1] = 'Low Complexity profile (LC)'; + $AACprofileLookup[2][2] = 'Scalable Sample Rate profile (SSR)'; + $AACprofileLookup[2][3] = '(reserved)'; + $AACprofileLookup[4][0] = 'AAC_MAIN'; + $AACprofileLookup[4][1] = 'AAC_LC'; + $AACprofileLookup[4][2] = 'AAC_SSR'; + $AACprofileLookup[4][3] = 'AAC_LTP'; + } + return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid'); + } + + function AACchannelCountCalculate($program_configs) { + $channels = 0; + for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) { + $channels++; + if ($program_configs['front_element_is_cpe'][$i]) { + // each front element is channel pair (CPE = Channel Pair Element) + $channels++; + } + } + for ($i = 0; $i < $program_configs['num_side_channel_elements']; $i++) { + $channels++; + if ($program_configs['side_element_is_cpe'][$i]) { + // each side element is channel pair (CPE = Channel Pair Element) + $channels++; + } + } + for ($i = 0; $i < $program_configs['num_back_channel_elements']; $i++) { + $channels++; + if ($program_configs['back_element_is_cpe'][$i]) { + // each back element is channel pair (CPE = Channel Pair Element) + $channels++; + } + } + for ($i = 0; $i < $program_configs['num_lfe_channel_elements']; $i++) { + $channels++; + } + return $channels; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.aac_adif.php b/plugins/getId3Plugin/lib/module.audio.aac_adif.php new file mode 100644 index 0000000..cb4238e --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.aac_adif.php @@ -0,0 +1,311 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.aac_adif.php | +// | Module for analyzing AAC files with ADIF header. | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.aac_adif.php,v 1.2 2004/11/01 03:11:16 ah Exp $ + + + +class getid3_aac_adif extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + // http://faac.sourceforge.net/wiki/index.php?page=ADIF + // http://libmpeg.org/mpeg4/doc/w2203tfs.pdf + // adif_header() { + // adif_id 32 + // copyright_id_present 1 + // if( copyright_id_present ) + // copyright_id 72 + // original_copy 1 + // home 1 + // bitstream_type 1 + // bitrate 23 + // num_program_config_elements 4 + // for (i = 0; i < num_program_config_elements + 1; i++ ) { + // if( bitstream_type == '0' ) + // adif_buffer_fullness 20 + // program_config_element() + // } + // } + + + $getid3->info['fileformat'] = 'aac'; + $getid3->info['audio']['dataformat'] = 'aac'; + $getid3->info['audio']['lossless'] = false; + + $getid3->info['aac']['header'] = array () ; + $info_aac = &$getid3->info['aac']; + $info_aac_header = & $info_aac['header']; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $aac_header_bitstream = getid3_lib::BigEndian2Bin(fread($getid3->fp, 1024)); + + $info_aac['header_type'] = 'ADIF'; + $info_aac_header['mpeg_version'] = 4; + $bit_offset = 32; + + $info_aac_header['copyright'] = $aac_header_bitstream{$bit_offset++} == '1'; + if ($info_aac_header['copyright']) { + $info_aac_header['copyright_id'] = getid3_aac_adif::Bin2String(substr($aac_header_bitstream, $bit_offset, 72)); + $bit_offset += 72; + } + + $info_aac_header['original_copy'] = $aac_header_bitstream{$bit_offset++} == '1'; + $info_aac_header['home'] = $aac_header_bitstream{$bit_offset++} == '1'; + $info_aac_header['is_vbr'] = $aac_header_bitstream{$bit_offset++} == '1'; + + if ($info_aac_header['is_vbr']) { + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + $info_aac_header['bitrate_max'] = bindec(substr($aac_header_bitstream, $bit_offset, 23)); + $bit_offset += 23; + } + else { + $getid3->info['audio']['bitrate_mode'] = 'cbr'; + $info_aac_header['bitrate'] = bindec(substr($aac_header_bitstream, $bit_offset, 23)); + $bit_offset += 23; + $getid3->info['audio']['bitrate'] = $info_aac_header['bitrate']; + } + + $info_aac_header['num_program_configs'] = 1 + bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + + for ($i = 0; $i < $info_aac_header['num_program_configs']; $i++) { + + // http://www.audiocoding.com/wiki/index.php?page=program_config_element + + // buffer_fullness 20 + + // element_instance_tag 4 + // object_type 2 + // sampling_frequency_index 4 + // num_front_channel_elements 4 + // num_side_channel_elements 4 + // num_back_channel_elements 4 + // num_lfe_channel_elements 2 + // num_assoc_data_elements 3 + // num_valid_cc_elements 4 + // mono_mixdown_present 1 + // mono_mixdown_element_number 4 if mono_mixdown_present == 1 + // stereo_mixdown_present 1 + // stereo_mixdown_element_number 4 if stereo_mixdown_present == 1 + // matrix_mixdown_idx_present 1 + // matrix_mixdown_idx 2 if matrix_mixdown_idx_present == 1 + // pseudo_surround_enable 1 if matrix_mixdown_idx_present == 1 + // for (i = 0; i < num_front_channel_elements; i++) { + // front_element_is_cpe[i] 1 + // front_element_tag_select[i] 4 + // } + // for (i = 0; i < num_side_channel_elements; i++) { + // side_element_is_cpe[i] 1 + // side_element_tag_select[i] 4 + // } + // for (i = 0; i < num_back_channel_elements; i++) { + // back_element_is_cpe[i] 1 + // back_element_tag_select[i] 4 + // } + // for (i = 0; i < num_lfe_channel_elements; i++) { + // lfe_element_tag_select[i] 4 + // } + // for (i = 0; i < num_assoc_data_elements; i++) { + // assoc_data_element_tag_select[i] 4 + // } + // for (i = 0; i < num_valid_cc_elements; i++) { + // cc_element_is_ind_sw[i] 1 + // valid_cc_element_tag_select[i] 4 + // } + // byte_alignment() VAR + // comment_field_bytes 8 + // for (i = 0; i < comment_field_bytes; i++) { + // comment_field_data[i] 8 + // } + + $info_aac['program_configs'][$i] = array (); + $info_aac_program_configs_i = &$info_aac['program_configs'][$i]; + + if (!$info_aac_header['is_vbr']) { + $info_aac_program_configs_i['buffer_fullness'] = bindec(substr($aac_header_bitstream, $bit_offset, 20)); + $bit_offset += 20; + } + + $info_aac_program_configs_i['element_instance_tag'] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $info_aac_program_configs_i['object_type'] = bindec(substr($aac_header_bitstream, $bit_offset + 4, 2)); + $info_aac_program_configs_i['sampling_frequency_index'] = bindec(substr($aac_header_bitstream, $bit_offset + 6, 4)); + $info_aac_program_configs_i['num_front_channel_elements'] = bindec(substr($aac_header_bitstream, $bit_offset + 10, 4)); + $info_aac_program_configs_i['num_side_channel_elements'] = bindec(substr($aac_header_bitstream, $bit_offset + 14, 4)); + $info_aac_program_configs_i['num_back_channel_elements'] = bindec(substr($aac_header_bitstream, $bit_offset + 18, 4)); + $info_aac_program_configs_i['num_lfe_channel_elements'] = bindec(substr($aac_header_bitstream, $bit_offset + 22, 2)); + $info_aac_program_configs_i['num_assoc_data_elements'] = bindec(substr($aac_header_bitstream, $bit_offset + 24, 3)); + $info_aac_program_configs_i['num_valid_cc_elements'] = bindec(substr($aac_header_bitstream, $bit_offset + 27, 4)); + $bit_offset += 31; + + $info_aac_program_configs_i['mono_mixdown_present'] = $aac_header_bitstream{$bit_offset++} == 1; + if ($info_aac_program_configs_i['mono_mixdown_present']) { + $info_aac_program_configs_i['mono_mixdown_element_number'] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + } + + $info_aac_program_configs_i['stereo_mixdown_present'] = $aac_header_bitstream{$bit_offset++} == 1; + if ($info_aac_program_configs_i['stereo_mixdown_present']) { + $info_aac_program_configs_i['stereo_mixdown_element_number'] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + } + + $info_aac_program_configs_i['matrix_mixdown_idx_present'] = $aac_header_bitstream{$bit_offset++} == 1; + if ($info_aac_program_configs_i['matrix_mixdown_idx_present']) { + $info_aac_program_configs_i['matrix_mixdown_idx'] = bindec(substr($aac_header_bitstream, $bit_offset, 2)); + $bit_offset += 2; + $info_aac_program_configs_i['pseudo_surround_enable'] = $aac_header_bitstream{$bit_offset++} == 1; + } + + for ($j = 0; $j < $info_aac_program_configs_i['num_front_channel_elements']; $j++) { + $info_aac_program_configs_i['front_element_is_cpe'][$j] = $aac_header_bitstream{$bit_offset++} == 1; + $info_aac_program_configs_i['front_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + } + for ($j = 0; $j < $info_aac_program_configs_i['num_side_channel_elements']; $j++) { + $info_aac_program_configs_i['side_element_is_cpe'][$j] = $aac_header_bitstream{$bit_offset++} == 1; + $info_aac_program_configs_i['side_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + } + for ($j = 0; $j < $info_aac_program_configs_i['num_back_channel_elements']; $j++) { + $info_aac_program_configs_i['back_element_is_cpe'][$j] = $aac_header_bitstream{$bit_offset++} == 1; + $info_aac_program_configs_i['back_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + } + for ($j = 0; $j < $info_aac_program_configs_i['num_lfe_channel_elements']; $j++) { + $info_aac_program_configs_i['lfe_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + } + for ($j = 0; $j < $info_aac_program_configs_i['num_assoc_data_elements']; $j++) { + $info_aac_program_configs_i['assoc_data_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + } + for ($j = 0; $j < $info_aac_program_configs_i['num_valid_cc_elements']; $j++) { + $info_aac_program_configs_i['cc_element_is_ind_sw'][$j] = $aac_header_bitstream{$bit_offset++} == 1; + $info_aac_program_configs_i['valid_cc_element_tag_select'][$j] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + } + + $bit_offset = ceil($bit_offset / 8) * 8; + + $info_aac_program_configs_i['comment_field_bytes'] = bindec(substr($aac_header_bitstream, $bit_offset, 8)); + $bit_offset += 8; + + $info_aac_program_configs_i['comment_field'] = getid3_aac_adif::Bin2String(substr($aac_header_bitstream, $bit_offset, 8 * $info_aac_program_configs_i['comment_field_bytes'])); + $bit_offset += 8 * $info_aac_program_configs_i['comment_field_bytes']; + + $info_aac_header['profile_text'] = getid3_aac_adif::AACprofileLookup($info_aac_program_configs_i['object_type'], $info_aac_header['mpeg_version']); + $info_aac_program_configs_i['sampling_frequency'] = $getid3->info['audio']['sample_rate'] = getid3_aac_adif::AACsampleRateLookup($info_aac_program_configs_i['sampling_frequency_index']); + $getid3->info['audio']['channels'] = getid3_aac_adif::AACchannelCountCalculate($info_aac_program_configs_i); + + if ($info_aac_program_configs_i['comment_field']) { + $info_aac['comments'][] = $info_aac_program_configs_i['comment_field']; + } + } + + $getid3->info['playtime_seconds'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['audio']['bitrate']; + $getid3->info['audio']['encoder_options'] = $info_aac['header_type'].' '.$info_aac_header['profile_text']; + + return true; + } + + + + public static function Bin2String($bin_string) { + // return 'hi' for input of '0110100001101001' + $string = ''; + $bin_string_reversed = strrev($bin_string); + for ($i = 0; $i < strlen($bin_string_reversed); $i += 8) { + $string = chr(bindec(strrev(substr($bin_string_reversed, $i, 8)))).$string; + } + return $string; + } + + + + public static function AACsampleRateLookup($samplerate_id) { + + static $lookup = array ( + 0 => 96000, + 1 => 88200, + 2 => 64000, + 3 => 48000, + 4 => 44100, + 5 => 32000, + 6 => 24000, + 7 => 22050, + 8 => 16000, + 9 => 12000, + 10 => 11025, + 11 => 8000, + 12 => 0, + 13 => 0, + 14 => 0, + 15 => 0 + ); + return (isset($lookup[$samplerate_id]) ? $lookup[$samplerate_id] : 'invalid'); + } + + + + public static function AACprofileLookup($profile_id, $mpeg_version) { + + static $lookup = array ( + 2 => array ( + 0 => 'Main profile', + 1 => 'Low Complexity profile (LC)', + 2 => 'Scalable Sample Rate profile (SSR)', + 3 => '(reserved)' + ), + 4 => array ( + 0 => 'AAC_MAIN', + 1 => 'AAC_LC', + 2 => 'AAC_SSR', + 3 => 'AAC_LTP' + ) + ); + return (isset($lookup[$mpeg_version][$profile_id]) ? $lookup[$mpeg_version][$profile_id] : 'invalid'); + } + + + + public static function AACchannelCountCalculate($program_configs) { + + $channels = 0; + + foreach (array ('front', 'side', 'back') as $placement) { + for ($i = 0; $i < $program_configs['num_'.$placement.'_channel_elements']; $i++) { + + // Each element is channel pair (CPE = Channel Pair Element) + $channels += 1 + ($program_configs[$placement.'_element_is_cpe'][$i] ? 1 : 0); + } + } + + return $channels + $program_configs['num_lfe_channel_elements']; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.aac_adts.php b/plugins/getId3Plugin/lib/module.audio.aac_adts.php new file mode 100644 index 0000000..7d3b776 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.aac_adts.php @@ -0,0 +1,282 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.aac_adts.php | +// | Module for analyzing AAC files with ADTS header. | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.aac_adts.php,v 1.3 2006/06/06 18:38:54 ah Exp $ + + + +class getid3_aac_adts extends getid3_handler +{ + + public $option_max_frames_to_scan = 1000000; + public $option_return_extended_info = false; + + + private $decbin_cache; + private $bitrate_cache; + + + + public function __construct(getID3 $getid3) { + + parent::__construct($getid3); + + // Populate bindec_cache + for ($i = 0; $i < 256; $i++) { + $this->decbin_cache[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); + } + + // Init cache + $this->bitrate_cache = array (); + + // Fast scanning? + if (!$getid3->option_accurate_results) { + $this->option_max_frames_to_scan = 200; + $getid3->warning('option_accurate_results set to false - bitrate and playing time are not accurate.'); + } + } + + + + public function Analyze() { + + $getid3 = $this->getid3; + + // based loosely on code from AACfile by Jurgen Faul + // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html + + + // http://faac.sourceforge.net/wiki/index.php?page=ADTS + + // * ADTS Fixed Header: these don't change from frame to frame + // syncword 12 always: '111111111111' + // ID 1 0: MPEG-4, 1: MPEG-2 + // layer 2 always: '00' + // protection_absent 1 + // profile 2 + // sampling_frequency_index 4 + // private_bit 1 + // channel_configuration 3 + // original/copy 1 + // home 1 + // emphasis 2 only if ID == 0 (ie MPEG-4) + + // * ADTS Variable Header: these can change from frame to frame + // copyright_identification_bit 1 + // copyright_identification_start 1 + // aac_frame_length 13 length of the frame including header (in bytes) + // adts_buffer_fullness 11 0x7FF indicates VBR + // no_raw_data_blocks_in_frame 2 + + // * ADTS Error check + // crc_check 16 only if protection_absent == 0 + + $getid3->info['aac']['header'] = array () ; + $info_aac = &$getid3->info['aac']; + $info_aac_header = & $info_aac['header']; + + $byte_offset = $frame_number = 0; + + while (true) { + + // Breaks out when end-of-file encountered, or invalid data found, + // or MaxFramesToScan frames have been scanned + + fseek($getid3->fp, $byte_offset, SEEK_SET); + + // First get substring + $sub_string = fread($getid3->fp, 10); + $sub_string_length = strlen($sub_string); + if ($sub_string_length != 10) { + throw new getid3_exception('Failed to read 10 bytes at offset '.(ftell($getid3->fp) - $sub_string_length).' (only read '.$sub_string_length.' bytes)'); + } + + // Initialise $aac_header_bitstream + $aac_header_bitstream = ''; + + // Loop thru substring chars + for ($i = 0; $i < 10; $i++) { + $aac_header_bitstream .= $this->decbin_cache[$sub_string[$i]]; + } + + $sync_test = bindec(substr($aac_header_bitstream, 0, 12)); + $bit_offset = 12; + + if ($sync_test != 0x0FFF) { + throw new getid3_exception('Synch pattern (0x0FFF) not found at offset '.(ftell($getid3->fp) - 10).' (found 0x0'.strtoupper(dechex($sync_test)).' instead)'); + } + + // Only gather info once - this takes time to do 1000 times! + if ($frame_number > 0) { + + // MPEG-4: 20, // MPEG-2: 18 + $bit_offset += $aac_header_bitstream[$bit_offset] ? 18 : 20; + } + + // Gather info for first frame only - this takes time to do 1000 times! + else { + + $info_aac['header_type'] = 'ADTS'; + $info_aac_header['synch'] = $sync_test; + $getid3->info['fileformat'] = 'aac'; + $getid3->info['audio']['dataformat'] = 'aac'; + + $info_aac_header['mpeg_version'] = $aac_header_bitstream{$bit_offset++} == '0' ? 4 : 2; + $info_aac_header['layer'] = bindec(substr($aac_header_bitstream, $bit_offset, 2)); + $bit_offset += 2; + + if ($info_aac_header['layer'] != 0) { + throw new getid3_exception('Layer error - expected 0x00, found 0x'.dechex($info_aac_header['layer']).' instead'); + } + + $info_aac_header['crc_present'] = $aac_header_bitstream{$bit_offset++} == '0' ? true : false; + + $info_aac_header['profile_id'] = bindec(substr($aac_header_bitstream, $bit_offset, 2)); + $bit_offset += 2; + + $info_aac_header['profile_text'] = getid3_aac_adts::AACprofileLookup($info_aac_header['profile_id'], $info_aac_header['mpeg_version']); + + $info_aac_header['sample_frequency_index'] = bindec(substr($aac_header_bitstream, $bit_offset, 4)); + $bit_offset += 4; + + $info_aac_header['sample_frequency'] = getid3_aac_adts::AACsampleRateLookup($info_aac_header['sample_frequency_index']); + + $getid3->info['audio']['sample_rate'] = $info_aac_header['sample_frequency']; + + $info_aac_header['private'] = $aac_header_bitstream{$bit_offset++} == 1; + + $info_aac_header['channel_configuration'] = $getid3->info['audio']['channels'] = bindec(substr($aac_header_bitstream, $bit_offset, 3)); + $bit_offset += 3; + + $info_aac_header['original'] = $aac_header_bitstream{$bit_offset++} == 1; + $info_aac_header['home'] = $aac_header_bitstream{$bit_offset++} == 1; + + if ($info_aac_header['mpeg_version'] == 4) { + $info_aac_header['emphasis'] = bindec(substr($aac_header_bitstream, $bit_offset, 2)); + $bit_offset += 2; + } + + if ($this->option_return_extended_info) { + + $info_aac[$frame_number]['copyright_id_bit'] = $aac_header_bitstream{$bit_offset++} == 1; + $info_aac[$frame_number]['copyright_id_start'] = $aac_header_bitstream{$bit_offset++} == 1; + + } else { + $bit_offset += 2; + } + } + + $frame_length = bindec(substr($aac_header_bitstream, $bit_offset, 13)); + + if (!isset($this->bitrate_cache[$frame_length])) { + $this->bitrate_cache[$frame_length] = ($info_aac_header['sample_frequency'] / 1024) * $frame_length * 8; + } + @$info_aac['bitrate_distribution'][$this->bitrate_cache[$frame_length]]++; + + $info_aac[$frame_number]['aac_frame_length'] = $frame_length; + $bit_offset += 13; + + $info_aac[$frame_number]['adts_buffer_fullness'] = bindec(substr($aac_header_bitstream, $bit_offset, 11)); + $bit_offset += 11; + + $getid3->info['audio']['bitrate_mode'] = ($info_aac[$frame_number]['adts_buffer_fullness'] == 0x07FF) ? 'vbr' : 'cbr'; + + $info_aac[$frame_number]['num_raw_data_blocks'] = bindec(substr($aac_header_bitstream, $bit_offset, 2)); + $bit_offset += 2; + + if ($info_aac_header['crc_present']) { + $bit_offset += 16; + } + + if (!$this->option_return_extended_info) { + unset($info_aac[$frame_number]); + } + + $byte_offset += $frame_length; + if ((++$frame_number < $this->option_max_frames_to_scan) && (($byte_offset + 10) < $getid3->info['avdataend'])) { + + // keep scanning + + } else { + + $info_aac['frames'] = $frame_number; + $getid3->info['playtime_seconds'] = ($getid3->info['avdataend'] / $byte_offset) * (($frame_number * 1024) / $info_aac_header['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + ksort($info_aac['bitrate_distribution']); + + $getid3->info['audio']['encoder_options'] = $info_aac['header_type'].' '.$info_aac_header['profile_text']; + + return true; + } + } + } + + + + public static function AACsampleRateLookup($samplerate_id) { + + static $lookup = array ( + 0 => 96000, + 1 => 88200, + 2 => 64000, + 3 => 48000, + 4 => 44100, + 5 => 32000, + 6 => 24000, + 7 => 22050, + 8 => 16000, + 9 => 12000, + 10 => 11025, + 11 => 8000, + 12 => 0, + 13 => 0, + 14 => 0, + 15 => 0 + ); + return (isset($lookup[$samplerate_id]) ? $lookup[$samplerate_id] : 'invalid'); + } + + + + public static function AACprofileLookup($profile_id, $mpeg_version) { + + static $lookup = array ( + 2 => array ( + 0 => 'Main profile', + 1 => 'Low Complexity profile (LC)', + 2 => 'Scalable Sample Rate profile (SSR)', + 3 => '(reserved)' + ), + 4 => array ( + 0 => 'AAC_MAIN', + 1 => 'AAC_LC', + 2 => 'AAC_SSR', + 3 => 'AAC_LTP' + ) + ); + return (isset($lookup[$mpeg_version][$profile_id]) ? $lookup[$mpeg_version][$profile_id] : 'invalid'); + } + + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.ac3.php b/plugins/getId3Plugin/lib/module.audio.ac3.php new file mode 100644 index 0000000..2331010 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.ac3.php @@ -0,0 +1,500 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.ac3.php | +// | Module for analyzing AC-3 (aka Dolby Digital) audio files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.ac3.php,v 1.2 2006/06/06 18:38:54 ah Exp $ + + + +class getid3_ac3 extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + // http://www.atsc.org/standards/a_52a.pdf + + $getid3->info['fileformat'] = 'ac3'; + $getid3->info['audio']['dataformat'] = 'ac3'; + $getid3->info['audio']['bitrate_mode'] = 'cbr'; + $getid3->info['audio']['lossless'] = false; + + $getid3->info['ac3']['raw']['bsi'] = array (); + $info_ac3 = &$getid3->info['ac3']; + $info_ac3_raw = &$info_ac3['raw']; + $info_ac3_raw_bsi = &$info_ac3_raw['bsi']; + + + // An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames + // Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256 + // new audio samples per channel. A synchronization information (SI) header at the beginning + // of each frame contains information needed to acquire and maintain synchronization. A + // bit stream information (BSI) header follows SI, and contains parameters describing the coded + // audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the + // end of each frame is an error check field that includes a CRC word for error detection. An + // additional CRC word is located in the SI header, the use of which, by a decoder, is optional. + // + // syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC + + $this->fseek($getid3->info['avdataoffset'], SEEK_SET); + $ac3_header['syncinfo'] = $this->fread(5); + $info_ac3_raw['synchinfo']['synchword'] = substr($ac3_header['syncinfo'], 0, 2); + + if ($info_ac3_raw['synchinfo']['synchword'] != "\x0B\x77") { + throw new getid3_exception('Expecting "\x0B\x77" at offset '.$getid3->info['avdataoffset'].', found \x'.strtoupper(dechex($ac3_header['syncinfo']{0})).'\x'.strtoupper(dechex($ac3_header['syncinfo']{1})).' instead'); + } + + + // syncinfo() { + // syncword 16 + // crc1 16 + // fscod 2 + // frmsizecod 6 + // } /* end of syncinfo */ + + $info_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($ac3_header['syncinfo'], 2, 2)); + $ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($ac3_header['syncinfo'], 4, 1)); + $info_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6; + $info_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F); + + $info_ac3['sample_rate'] = getid3_ac3::AC3sampleRateCodeLookup($info_ac3_raw['synchinfo']['fscod']); + if ($info_ac3_raw['synchinfo']['fscod'] <= 3) { + $getid3->info['audio']['sample_rate'] = $info_ac3['sample_rate']; + } + + $info_ac3['frame_length'] = getid3_ac3::AC3frameSizeLookup($info_ac3_raw['synchinfo']['frmsizecod'], $info_ac3_raw['synchinfo']['fscod']); + $info_ac3['bitrate'] = getid3_ac3::AC3bitrateLookup($info_ac3_raw['synchinfo']['frmsizecod']); + $getid3->info['audio']['bitrate'] = $info_ac3['bitrate']; + + $ac3_header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15)); + + $info_ac3_raw_bsi['bsid'] = bindec(substr($ac3_header['bsi'], 0, 5)); + if ($info_ac3_raw_bsi['bsid'] > 8) { + // Decoders which can decode version 8 will thus be able to decode version numbers less than 8. + // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used. + // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8. + throw new getid3_exception('Bit stream identification is version '.$info_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8'); + } + + $info_ac3_raw_bsi['bsmod'] = bindec(substr($ac3_header['bsi'], 5, 3)); + $info_ac3_raw_bsi['acmod'] = bindec(substr($ac3_header['bsi'], 8, 3)); + + $info_ac3['service_type'] = getid3_ac3::AC3serviceTypeLookup($info_ac3_raw_bsi['bsmod'], $info_ac3_raw_bsi['acmod']); + $ac3_coding_mode = getid3_ac3::AC3audioCodingModeLookup($info_ac3_raw_bsi['acmod']); + foreach($ac3_coding_mode as $key => $value) { + $info_ac3[$key] = $value; + } + switch ($info_ac3_raw_bsi['acmod']) { + case 0: + case 1: + $getid3->info['audio']['channelmode'] = 'mono'; + break; + case 3: + case 4: + $getid3->info['audio']['channelmode'] = 'stereo'; + break; + default: + $getid3->info['audio']['channelmode'] = 'surround'; + break; + } + $getid3->info['audio']['channels'] = $info_ac3['num_channels']; + + $offset = 11; + + if ($info_ac3_raw_bsi['acmod'] & 0x01) { + // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream. + $info_ac3_raw_bsi['cmixlev'] = bindec(substr($ac3_header['bsi'], $offset, 2)); + $info_ac3['center_mix_level'] = getid3_ac3::AC3centerMixLevelLookup($info_ac3_raw_bsi['cmixlev']); + $offset += 2; + } + + if ($info_ac3_raw_bsi['acmod'] & 0x04) { + // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream. + $info_ac3_raw_bsi['surmixlev'] = bindec(substr($ac3_header['bsi'], $offset, 2)); + $info_ac3['surround_mix_level'] = getid3_ac3::AC3surroundMixLevelLookup($info_ac3_raw_bsi['surmixlev']); + $offset += 2; + } + + if ($info_ac3_raw_bsi['acmod'] == 0x02) { + // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround. + $info_ac3_raw_bsi['dsurmod'] = bindec(substr($ac3_header['bsi'], $offset, 2)); + $info_ac3['dolby_surround_mode'] = getid3_ac3::AC3dolbySurroundModeLookup($info_ac3_raw_bsi['dsurmod']); + $offset += 2; + } + + $info_ac3_raw_bsi['lfeon'] = $ac3_header['bsi']{$offset++} == '1'; + $info_ac3['lfe_enabled'] = $info_ac3_raw_bsi['lfeon']; + if ($info_ac3_raw_bsi['lfeon']) { + $getid3->info['audio']['channels'] .= '.1'; + } + + $info_ac3['channels_enabled'] = getid3_ac3::AC3channelsEnabledLookup($info_ac3_raw_bsi['acmod'], $info_ac3_raw_bsi['lfeon']); + + // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 131. + // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. + $info_ac3_raw_bsi['dialnorm'] = bindec(substr($ac3_header['bsi'], $offset, 5)); + $offset += 5; + $info_ac3['dialogue_normalization'] = '-'.$info_ac3_raw_bsi['dialnorm'].'dB'; + + $info_ac3_raw_bsi['compre_flag'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['compre_flag']) { + $info_ac3_raw_bsi['compr'] = bindec(substr($ac3_header['bsi'], $offset, 8)); + $offset += 8; + + $info_ac3['heavy_compression'] = getid3_ac3::AC3heavyCompression($info_ac3_raw_bsi['compr']); + } + + $info_ac3_raw_bsi['langcode_flag'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['langcode_flag']) { + $info_ac3_raw_bsi['langcod'] = bindec(substr($ac3_header['bsi'], $offset, 8)); + $offset += 8; + } + + $info_ac3_raw_bsi['audprodie'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['audprodie']) { + $info_ac3_raw_bsi['mixlevel'] = bindec(substr($ac3_header['bsi'], $offset, 5)); + $offset += 5; + + $info_ac3_raw_bsi['roomtyp'] = bindec(substr($ac3_header['bsi'], $offset, 2)); + $offset += 2; + + $info_ac3['mixing_level'] = (80 + $info_ac3_raw_bsi['mixlevel']).'dB'; + $info_ac3['room_type'] = getid3_ac3::AC3roomTypeLookup($info_ac3_raw_bsi['roomtyp']); + } + + if ($info_ac3_raw_bsi['acmod'] == 0x00) { + // If acmod is 0, then two completely independent program channels (dual mono) + // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case, + // a number of additional items are present in BSI or audblk to fully describe Ch2. + + + // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 131. + // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. + $info_ac3_raw_bsi['dialnorm2'] = bindec(substr($ac3_header['bsi'], $offset, 5)); + $offset += 5; + + $info_ac3['dialogue_normalization2'] = '-'.$info_ac3_raw_bsi['dialnorm2'].'dB'; + + $info_ac3_raw_bsi['compre_flag2'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['compre_flag2']) { + $info_ac3_raw_bsi['compr2'] = bindec(substr($ac3_header['bsi'], $offset, 8)); + $offset += 8; + + $info_ac3['heavy_compression2'] = getid3_ac3::AC3heavyCompression($info_ac3_raw_bsi['compr2']); + } + + $info_ac3_raw_bsi['langcode_flag2'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['langcode_flag2']) { + $info_ac3_raw_bsi['langcod2'] = bindec(substr($ac3_header['bsi'], $offset, 8)); + $offset += 8; + } + + $info_ac3_raw_bsi['audprodie2'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['audprodie2']) { + $info_ac3_raw_bsi['mixlevel2'] = bindec(substr($ac3_header['bsi'], $offset, 5)); + $offset += 5; + + $info_ac3_raw_bsi['roomtyp2'] = bindec(substr($ac3_header['bsi'], $offset, 2)); + $offset += 2; + + $info_ac3['mixing_level2'] = (80 + $info_ac3_raw_bsi['mixlevel2']).'dB'; + $info_ac3['room_type2'] = getid3_ac3::AC3roomTypeLookup($info_ac3_raw_bsi['roomtyp2']); + } + + } + + $info_ac3_raw_bsi['copyright'] = $ac3_header['bsi']{$offset++} == '1'; + + $info_ac3_raw_bsi['original'] = $ac3_header['bsi']{$offset++} == '1'; + + $info_ac3_raw_bsi['timecode1_flag'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['timecode1_flag']) { + $info_ac3_raw_bsi['timecode1'] = bindec(substr($ac3_header['bsi'], $offset, 14)); + $offset += 14; + } + + $info_ac3_raw_bsi['timecode2_flag'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['timecode2_flag']) { + $info_ac3_raw_bsi['timecode2'] = bindec(substr($ac3_header['bsi'], $offset, 14)); + $offset += 14; + } + + $info_ac3_raw_bsi['addbsi_flag'] = $ac3_header['bsi']{$offset++} == '1'; + if ($info_ac3_raw_bsi['addbsi_flag']) { + $info_ac3_raw_bsi['addbsi_length'] = bindec(substr($ac3_header['bsi'], $offset, 6)); + $offset += 6; + + $ac3_header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($info_ac3_raw_bsi['addbsi_length'])); + + $info_ac3_raw_bsi['addbsi_data'] = substr($ac3_header['bsi'], 119, $info_ac3_raw_bsi['addbsi_length'] * 8); + } + + return true; + } + + + + public static function AC3sampleRateCodeLookup($fscod) { + + static $lookup = array ( + 0 => 48000, + 1 => 44100, + 2 => 32000, + 3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute. + ); + return (isset($lookup[$fscod]) ? $lookup[$fscod] : false); + } + + + + public static function AC3serviceTypeLookup($bsmod, $acmod) { + + static $lookup = array ( + 0 => 'main audio service: complete main (CM)', + 1 => 'main audio service: music and effects (ME)', + 2 => 'associated service: visually impaired (VI)', + 3 => 'associated service: hearing impaired (HI)', + 4 => 'associated service: dialogue (D)', + 5 => 'associated service: commentary (C)', + 6 => 'associated service: emergency (E)', + 7 => 'main audio service: karaoke' + ); + + if ($bsmod == 7 && $acmod == 1) { + return 'associated service: voice over (VO)'; + } + + return (isset($lookup[$bsmod]) ? $lookup[$bsmod] : false); + } + + + + public static function AC3audioCodingModeLookup($acmod) { + + // array (channel configuration, # channels (not incl LFE), channel order) + static $lookup = array ( + 0 => array ('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'), + 1 => array ('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'), + 2 => array ('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'), + 3 => array ('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'), + 4 => array ('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'), + 5 => array ('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'), + 6 => array ('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'), + 7 => array ('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR') + ); + return (isset($lookup[$acmod]) ? $lookup[$acmod] : false); + } + + + + public static function AC3centerMixLevelLookup($cmixlev) { + + static $lookup; + if (!@$lookup) { + $lookup = array ( + 0 => pow(2, -3.0 / 6), // 0.707 (3.0 dB) + 1 => pow(2, -4.5 / 6), // 0.595 (4.5 dB) + 2 => pow(2, -6.0 / 6), // 0.500 (6.0 dB) + 3 => 'reserved' + ); + } + return (isset($lookup[$cmixlev]) ? $lookup[$cmixlev] : false); + } + + + + public static function AC3surroundMixLevelLookup($surmixlev) { + + static $lookup; + if (!@$lookup) { + $lookup = array ( + 0 => pow(2, -3.0 / 6), + 1 => pow(2, -6.0 / 6), + 2 => 0, + 3 => 'reserved' + ); + } + return (isset($lookup[$surmixlev]) ? $lookup[$surmixlev] : false); + } + + + + public static function AC3dolbySurroundModeLookup($dsurmod) { + + static $lookup = array ( + 0 => 'not indicated', + 1 => 'Not Dolby Surround encoded', + 2 => 'Dolby Surround encoded', + 3 => 'reserved' + ); + return (isset($lookup[$dsurmod]) ? $lookup[$dsurmod] : false); + } + + + + public static function AC3channelsEnabledLookup($acmod, $lfeon) { + + return array ( + 'ch1' => $acmod == 0, + 'ch2' => $acmod == 0, + 'left' => $acmod > 1, + 'right' => $acmod > 1, + 'center' => (bool)($acmod & 0x01), + 'surround_mono' => $acmod == 4 || $acmod == 5, + 'surround_left' => $acmod == 6 || $acmod == 7, + 'surround_right' => $acmod == 6 || $acmod == 7, + 'lfe' => $lfeon + ); + } + + + + public static function AC3heavyCompression($compre) { + + // The first four bits indicate gain changes in 6.02dB increments which can be + // implemented with an arithmetic shift operation. The following four bits + // indicate linear gain changes, and require a 5-bit multiply. + // We will represent the two 4-bit fields of compr as follows: + // X0 X1 X2 X3 . Y4 Y5 Y6 Y7 + // The meaning of the X values is most simply described by considering X to represent a 4-bit + // signed integer with values from 8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The + // following table shows this in detail. + + // Meaning of 4 msb of compr + // 7 +48.16 dB + // 6 +42.14 dB + // 5 +36.12 dB + // 4 +30.10 dB + // 3 +24.08 dB + // 2 +18.06 dB + // 1 +12.04 dB + // 0 +6.02 dB + // -1 0 dB + // -2 6.02 dB + // -3 12.04 dB + // -4 18.06 dB + // -5 24.08 dB + // -6 30.10 dB + // -7 36.12 dB + // -8 42.14 dB + + $fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT); + if ($fourbit{0} == '1') { + $log_gain = -8 + bindec(substr($fourbit, 1)); + } else { + $log_gain = bindec(substr($fourbit, 1)); + } + $log_gain = ($log_gain + 1) * (20 * log10(2)); + + // The value of Y is a linear representation of a gain change of up to 6 dB. Y is considered to + // be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can + // represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain + // changes from 0.28 dB to 6.02 dB. + + $lin_gain = (16 + ($compre & 0x0F)) / 32; + + // The combination of X and Y values allows compr to indicate gain changes from + // 48.16 0.28 = +47.89 dB, to + // 42.14 6.02 = 48.16 dB. + + return $log_gain - $lin_gain; + } + + + + public static function AC3roomTypeLookup($roomtyp) { + + static $lookup = array ( + 0 => 'not indicated', + 1 => 'large room, X curve monitor', + 2 => 'small room, flat monitor', + 3 => 'reserved' + ); + return (isset($lookup[$roomtyp]) ? $lookup[$roomtyp] : false); + } + + + + public static function AC3frameSizeLookup($frmsizecod, $fscod) { + + $padding = (bool)($frmsizecod % 2); + $frame_size_id = floor($frmsizecod / 2); + + static $lookup = array ( + 0 => array (128, 138, 192), + 1 => array (40, 160, 174, 240), + 2 => array (48, 192, 208, 288), + 3 => array (56, 224, 242, 336), + 4 => array (64, 256, 278, 384), + 5 => array (80, 320, 348, 480), + 6 => array (96, 384, 416, 576), + 7 => array (112, 448, 486, 672), + 8 => array (128, 512, 556, 768), + 9 => array (160, 640, 696, 960), + 10 => array (192, 768, 834, 1152), + 11 => array (224, 896, 974, 1344), + 12 => array (256, 1024, 1114, 1536), + 13 => array (320, 1280, 1392, 1920), + 14 => array (384, 1536, 1670, 2304), + 15 => array (448, 1792, 1950, 2688), + 16 => array (512, 2048, 2228, 3072), + 17 => array (576, 2304, 2506, 3456), + 18 => array (640, 2560, 2786, 3840) + ); + if (($fscod == 1) && $padding) { + // frame lengths are padded by 1 word (16 bits) at 44100 + $lookup[$frmsizecod] += 2; + } + return (isset($lookup[$frame_size_id][$fscod]) ? $lookup[$frame_size_id][$fscod] : false); + } + + + + public static function AC3bitrateLookup($frmsizecod) { + + static $lookup = array ( + 0 => 32000, + 1 => 40000, + 2 => 48000, + 3 => 56000, + 4 => 64000, + 5 => 80000, + 6 => 96000, + 7 => 112000, + 8 => 128000, + 9 => 160000, + 10 => 192000, + 11 => 224000, + 12 => 256000, + 13 => 320000, + 14 => 384000, + 15 => 448000, + 16 => 512000, + 17 => 576000, + 18 => 640000 + ); + $frame_size_id = floor($frmsizecod / 2); + return (isset($lookup[$frame_size_id]) ? $lookup[$frame_size_id] : false); + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.au.php b/plugins/getId3Plugin/lib/module.audio.au.php new file mode 100644 index 0000000..5a2320c --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.au.php @@ -0,0 +1,184 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.au.php | +// | module for analyzing AU files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.au.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_au extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $au_header = fread($getid3->fp, 8); + + // Magic bytes: .snd + + $getid3->info['au'] = array (); + $info_au = &$getid3->info['au']; + + $getid3->info['fileformat'] = 'au'; + $getid3->info['audio']['dataformat'] = 'au'; + $getid3->info['audio']['bitrate_mode'] = 'cbr'; + $info_au['encoding'] = 'ISO-8859-1'; + + $info_au['header_length'] = getid3_lib::BigEndian2Int(substr($au_header, 4, 4)); + $au_header .= fread($getid3->fp, $info_au['header_length'] - 8); + $getid3->info['avdataoffset'] += $info_au['header_length']; + + getid3_lib::ReadSequence('BigEndian2Int', $info_au, $au_header, 8, + array ( + 'data_size' => 4, + 'data_format_id'=> 4, + 'sample_rate' => 4, + 'channels' => 4 + ) + ); + $info_au['comments']['comment'][] = trim(substr($au_header, 24)); + + $info_au['data_format'] = getid3_au::AUdataFormatNameLookup($info_au['data_format_id']); + $info_au['used_bits_per_sample'] = getid3_au::AUdataFormatUsedBitsPerSampleLookup($info_au['data_format_id']); + if ($info_au['bits_per_sample'] = getid3_au::AUdataFormatBitsPerSampleLookup($info_au['data_format_id'])) { + $getid3->info['audio']['bits_per_sample'] = $info_au['bits_per_sample']; + } else { + unset($info_au['bits_per_sample']); + } + + $getid3->info['audio']['sample_rate'] = $info_au['sample_rate']; + $getid3->info['audio']['channels'] = $info_au['channels']; + + if (($getid3->info['avdataoffset'] + $info_au['data_size']) > $getid3->info['avdataend']) { + $getid3->warning('Possible truncated file - expecting "'.$info_au['data_size'].'" bytes of audio data, only found '.($getid3->info['avdataend'] - $getid3->info['avdataoffset']).' bytes"'); + } + + $getid3->info['playtime_seconds'] = $info_au['data_size'] / ($info_au['sample_rate'] * $info_au['channels'] * ($info_au['used_bits_per_sample'] / 8)); + $getid3->info['audio']['bitrate'] = ($info_au['data_size'] * 8) / $getid3->info['playtime_seconds']; + + return true; + } + + + + public static function AUdataFormatNameLookup($id) { + + static $lookup = array ( + 0 => 'unspecified format', + 1 => '8-bit mu-law', + 2 => '8-bit linear', + 3 => '16-bit linear', + 4 => '24-bit linear', + 5 => '32-bit linear', + 6 => 'floating-point', + 7 => 'double-precision float', + 8 => 'fragmented sampled data', + 9 => 'SUN_FORMAT_NESTED', + 10 => 'DSP program', + 11 => '8-bit fixed-point', + 12 => '16-bit fixed-point', + 13 => '24-bit fixed-point', + 14 => '32-bit fixed-point', + + 16 => 'non-audio display data', + 17 => 'SND_FORMAT_MULAW_SQUELCH', + 18 => '16-bit linear with emphasis', + 19 => '16-bit linear with compression', + 20 => '16-bit linear with emphasis + compression', + 21 => 'Music Kit DSP commands', + 22 => 'SND_FORMAT_DSP_COMMANDS_SAMPLES', + 23 => 'CCITT g.721 4-bit ADPCM', + 24 => 'CCITT g.722 ADPCM', + 25 => 'CCITT g.723 3-bit ADPCM', + 26 => 'CCITT g.723 5-bit ADPCM', + 27 => 'A-Law 8-bit' + ); + + return (isset($lookup[$id]) ? $lookup[$id] : false); + } + + + + public static function AUdataFormatBitsPerSampleLookup($id) { + + static $lookup = array ( + 1 => 8, + 2 => 8, + 3 => 16, + 4 => 24, + 5 => 32, + 6 => 32, + 7 => 64, + + 11 => 8, + 12 => 16, + 13 => 24, + 14 => 32, + + 18 => 16, + 19 => 16, + 20 => 16, + + 23 => 16, + + 25 => 16, + 26 => 16, + 27 => 8 + ); + return (isset($lookup[$id]) ? $lookup[$id] : false); + } + + + + public static function AUdataFormatUsedBitsPerSampleLookup($id) { + + static $lookup = array ( + 1 => 8, + 2 => 8, + 3 => 16, + 4 => 24, + 5 => 32, + 6 => 32, + 7 => 64, + + 11 => 8, + 12 => 16, + 13 => 24, + 14 => 32, + + 18 => 16, + 19 => 16, + 20 => 16, + + 23 => 4, + + 25 => 3, + 26 => 5, + 27 => 8, + ); + return (isset($lookup[$id]) ? $lookup[$id] : false); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.avr.php b/plugins/getId3Plugin/lib/module.audio.avr.php new file mode 100644 index 0000000..6fb73c1 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.avr.php @@ -0,0 +1,135 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.avr.php | +// | Module for analyzing AVR audio files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.avr.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_avr extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + // http://cui.unige.ch/OSG/info/AudioFormats/ap11.html + // http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html + // offset type length name comments + // --------------------------------------------------------------------- + // 0 char 4 ID format ID == "2BIT" + // 4 char 8 name sample name (unused space filled with 0) + // 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo + // With stereo, samples are alternated, + // the first voice is the left : + // (LRLRLRLRLRLRLRLRLR...) + // 14 short 1 resolution 8, 12 or 16 (bits) + // 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed + // 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on + // 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127 + // 0xFFFF means "no MIDI note defined" + // 22 byte 1 Replay speed Frequence in the Replay software + // 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz, + // 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz + // 6=43.885 Khz, 7=47.261 Khz + // -1 (0xFF)=no defined Frequence + // 23 byte 3 sample rate in Hertz + // 26 long 1 size in bytes (2 * bytes in stereo) + // 30 long 1 loop begin 0 for no loop + // 34 long 1 loop size equal to 'size' for no loop + // 38 short 2 Reserved, MIDI keyboard split */ + // 40 short 2 Reserved, sample compression */ + // 42 short 2 Reserved */ + // 44 char 20; Additional filename space, used if (name[7] != 0) + // 64 byte 64 user data + // 128 bytes ? sample data (12 bits samples are coded on 16 bits: + // 0000 xxxx xxxx xxxx) + // --------------------------------------------------------------------- + + // Note that all values are in motorola (big-endian) format, and that long is + // assumed to be 4 bytes, and short 2 bytes. + // When reading the samples, you should handle both signed and unsigned data, + // and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert + // 8-bit data between signed/unsigned just add 127 to the sample values. + // Simularly for 16-bit data you should add 32769 + + + // Magic bytes: '2BIT' + + $getid3->info['avr'] = array (); + $info_avr = &$getid3->info['avr']; + + $getid3->info['fileformat'] = 'avr'; + $info_avr['raw']['magic'] = '2BIT'; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $avr_header = fread($getid3->fp, 128); + + $getid3->info['avdataoffset'] += 128; + + $info_avr['sample_name'] = rtrim(substr($avr_header, 4, 8)); + + $info_avr['raw']['mono'] = getid3_lib::BigEndian2Int(substr($avr_header, 12, 2)); + $info_avr['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($avr_header, 14, 2)); + $info_avr['raw']['signed'] = getid3_lib::BigEndian2Int(substr($avr_header, 16, 2)); + $info_avr['raw']['loop'] = getid3_lib::BigEndian2Int(substr($avr_header, 18, 2)); + $info_avr['raw']['midi'] = getid3_lib::BigEndian2Int(substr($avr_header, 20, 2)); + $info_avr['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($avr_header, 22, 1)); + $info_avr['sample_rate'] = getid3_lib::BigEndian2Int(substr($avr_header, 23, 3)); + $info_avr['sample_length'] = getid3_lib::BigEndian2Int(substr($avr_header, 26, 4)); + $info_avr['loop_start'] = getid3_lib::BigEndian2Int(substr($avr_header, 30, 4)); + $info_avr['loop_end'] = getid3_lib::BigEndian2Int(substr($avr_header, 34, 4)); + $info_avr['midi_split'] = getid3_lib::BigEndian2Int(substr($avr_header, 38, 2)); + $info_avr['sample_compression'] = getid3_lib::BigEndian2Int(substr($avr_header, 40, 2)); + $info_avr['reserved'] = getid3_lib::BigEndian2Int(substr($avr_header, 42, 2)); + $info_avr['sample_name_extra'] = rtrim(substr($avr_header, 44, 20)); + $info_avr['comment'] = rtrim(substr($avr_header, 64, 64)); + + $info_avr['flags']['stereo'] = (($info_avr['raw']['mono'] == 0) ? false : true); + $info_avr['flags']['signed'] = (($info_avr['raw']['signed'] == 0) ? false : true); + $info_avr['flags']['loop'] = (($info_avr['raw']['loop'] == 0) ? false : true); + + $info_avr['midi_notes'] = array (); + if (($info_avr['raw']['midi'] & 0xFF00) != 0xFF00) { + $info_avr['midi_notes'][] = ($info_avr['raw']['midi'] & 0xFF00) >> 8; + } + if (($info_avr['raw']['midi'] & 0x00FF) != 0x00FF) { + $info_avr['midi_notes'][] = ($info_avr['raw']['midi'] & 0x00FF); + } + + if (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) != ($info_avr['sample_length'] * (($info_avr['bits_per_sample'] == 8) ? 1 : 2))) { + $getid3->warning('Probable truncated file: expecting '.($info_avr['sample_length'] * (($info_avr['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($getid3->info['avdataend'] - $getid3->info['avdataoffset'])); + } + + $getid3->info['audio']['dataformat'] = 'avr'; + $getid3->info['audio']['lossless'] = true; + $getid3->info['audio']['bitrate_mode'] = 'cbr'; + $getid3->info['audio']['bits_per_sample'] = $info_avr['bits_per_sample']; + $getid3->info['audio']['sample_rate'] = $info_avr['sample_rate']; + $getid3->info['audio']['channels'] = ($info_avr['flags']['stereo'] ? 2 : 1); + $getid3->info['playtime_seconds'] = ($info_avr['sample_length'] / $getid3->info['audio']['channels']) / $info_avr['sample_rate']; + $getid3->info['audio']['bitrate'] = ($info_avr['sample_length'] * (($info_avr['bits_per_sample'] == 8) ? 8 : 16)) / $getid3->info['playtime_seconds']; + + return true; + } +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.bonk.php b/plugins/getId3Plugin/lib/module.audio.bonk.php new file mode 100644 index 0000000..2fc08ba --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.bonk.php @@ -0,0 +1,235 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.bonk.php | +// | Module for analyzing BONK audio files | +// | dependencies: module.tag.id3v2.php (optional) | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.bonk.php,v 1.2 2004/11/01 03:11:16 ah Exp $ + + + +class getid3_bonk extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['bonk'] = array (); + $info_bonk = &$getid3->info['bonk']; + + $info_bonk['dataoffset'] = $getid3->info['avdataoffset']; + $info_bonk['dataend'] = $getid3->info['avdataend']; + + + // Scan-from-end method, for v0.6 and higher + fseek($getid3->fp, $info_bonk['dataend'] - 8, SEEK_SET); + $possible_bonk_tag = fread($getid3->fp, 8); + while (getid3_bonk::BonkIsValidTagName(substr($possible_bonk_tag, 4, 4), true)) { + $bonk_tag_size = getid3_lib::LittleEndian2Int(substr($possible_bonk_tag, 0, 4)); + fseek($getid3->fp, 0 - $bonk_tag_size, SEEK_CUR); + $bonk_tag_offset = ftell($getid3->fp); + $tag_header_test = fread($getid3->fp, 5); + if (($tag_header_test{0} != "\x00") || (substr($possible_bonk_tag, 4, 4) != strtolower(substr($possible_bonk_tag, 4, 4)))) { + throw new getid3_exception('Expecting "'.strtoupper(substr($possible_bonk_tag, 4, 4)).'" at offset '.$bonk_tag_offset.', found "'.$tag_header_test.'"'); + } + $bonk_tag_name = substr($tag_header_test, 1, 4); + + $info_bonk[$bonk_tag_name]['size'] = $bonk_tag_size; + $info_bonk[$bonk_tag_name]['offset'] = $bonk_tag_offset; + $this->HandleBonkTags($bonk_tag_name); + + $next_tag_end_offset = $bonk_tag_offset - 8; + if ($next_tag_end_offset < $info_bonk['dataoffset']) { + if (empty($getid3->info['audio']['encoder'])) { + $getid3->info['audio']['encoder'] = 'Extended BONK v0.9+'; + } + return true; + } + fseek($getid3->fp, $next_tag_end_offset, SEEK_SET); + $possible_bonk_tag = fread($getid3->fp, 8); + } + + // Seek-from-beginning method for v0.4 and v0.5 + if (empty($info_bonk['BONK'])) { + fseek($getid3->fp, $info_bonk['dataoffset'], SEEK_SET); + do { + $tag_header_test = fread($getid3->fp, 5); + switch ($tag_header_test) { + case "\x00".'BONK': + if (empty($getid3->info['audio']['encoder'])) { + $getid3->info['audio']['encoder'] = 'BONK v0.4'; + } + break; + + case "\x00".'INFO': + $getid3->info['audio']['encoder'] = 'Extended BONK v0.5'; + break; + + default: + break 2; + } + $bonk_tag_name = substr($tag_header_test, 1, 4); + $info_bonk[$bonk_tag_name]['size'] = $info_bonk['dataend'] - $info_bonk['dataoffset']; + $info_bonk[$bonk_tag_name]['offset'] = $info_bonk['dataoffset']; + $this->HandleBonkTags($bonk_tag_name); + + } while (true); + } + + + // Parse META block for v0.6 - v0.8 + if (!@$info_bonk['INFO'] && isset($info_bonk['META']['tags']['info'])) { + fseek($getid3->fp, $info_bonk['META']['tags']['info'], SEEK_SET); + $tag_header_test = fread($getid3->fp, 5); + if ($tag_header_test == "\x00".'INFO') { + $getid3->info['audio']['encoder'] = 'Extended BONK v0.6 - v0.8'; + + $bonk_tag_name = substr($tag_header_test, 1, 4); + $info_bonk[$bonk_tag_name]['size'] = $info_bonk['dataend'] - $info_bonk['dataoffset']; + $info_bonk[$bonk_tag_name]['offset'] = $info_bonk['dataoffset']; + $this->HandleBonkTags($bonk_tag_name); + } + } + + if (empty($getid3->info['audio']['encoder'])) { + $getid3->info['audio']['encoder'] = 'Extended BONK v0.9+'; + } + if (empty($info_bonk['BONK'])) { + unset($getid3->info['bonk']); + } + return true; + + } + + + + private function HandleBonkTags(&$bonk_tag_name) { + + // Shortcut to getid3 pointer + $getid3 = $this->getid3; + $info_audio = &$getid3->info['audio']; + + switch ($bonk_tag_name) { + + case 'BONK': + // shortcut + $info_bonk_BONK = &$getid3->info['bonk']['BONK']; + + $bonk_data = "\x00".'BONK'.fread($getid3->fp, 17); + + getid3_lib::ReadSequence('LittleEndian2Int', $info_bonk_BONK, $bonk_data, 5, + array ( + 'version' => 1, + 'number_samples' => 4, + 'sample_rate' => 4, + 'channels' => 1, + 'lossless' => 1, + 'joint_stereo' => 1, + 'number_taps' => 2, + 'downsampling_ratio' => 1, + 'samples_per_packet' => 2 + ) + ); + + $info_bonk_BONK['lossless'] = (bool)$info_bonk_BONK['lossless']; + $info_bonk_BONK['joint_stereo'] = (bool)$info_bonk_BONK['joint_stereo']; + + $getid3->info['avdataoffset'] = $info_bonk_BONK['offset'] + 5 + 17; + $getid3->info['avdataend'] = $info_bonk_BONK['offset'] + $info_bonk_BONK['size']; + + $getid3->info['fileformat'] = 'bonk'; + $info_audio['dataformat'] = 'bonk'; + $info_audio['bitrate_mode'] = 'vbr'; // assumed + $info_audio['channels'] = $info_bonk_BONK['channels']; + $info_audio['sample_rate'] = $info_bonk_BONK['sample_rate']; + $info_audio['channelmode'] = $info_bonk_BONK['joint_stereo'] ? 'joint stereo' : 'stereo'; + $info_audio['lossless'] = $info_bonk_BONK['lossless']; + $info_audio['codec'] = 'bonk'; + + $getid3->info['playtime_seconds'] = $info_bonk_BONK['number_samples'] / ($info_bonk_BONK['sample_rate'] * $info_bonk_BONK['channels']); + if ($getid3->info['playtime_seconds'] > 0) { + $info_audio['bitrate'] = (($getid3->info['bonk']['dataend'] - $getid3->info['bonk']['dataoffset']) * 8) / $getid3->info['playtime_seconds']; + } + break; + + case 'INFO': + // shortcut + $info_bonk_INFO = &$getid3->info['bonk']['INFO']; + + $info_bonk_INFO['version'] = getid3_lib::LittleEndian2Int(fread($getid3->fp, 1)); + $info_bonk_INFO['entries_count'] = 0; + $next_info_data_pair = fread($getid3->fp, 5); + if (!getid3_bonk::BonkIsValidTagName(substr($next_info_data_pair, 1, 4))) { + while (!feof($getid3->fp)) { + $next_info_data_pair = fread($getid3->fp, 5); + if (getid3_bonk::BonkIsValidTagName(substr($next_info_data_pair, 1, 4))) { + fseek($getid3->fp, -5, SEEK_CUR); + break; + } + $info_bonk_INFO['entries_count']++; + } + } + break; + + case 'META': + $bonk_data = "\x00".'META'.fread($getid3->fp, $getid3->info['bonk']['META']['size'] - 5); + $getid3->info['bonk']['META']['version'] = getid3_lib::LittleEndian2Int(substr($bonk_data, 5, 1)); + + $meta_tag_entries = floor(((strlen($bonk_data) - 8) - 6) / 8); // BonkData - xxxxmeta - META + $offset = 6; + for ($i = 0; $i < $meta_tag_entries; $i++) { + $meta_entry_tag_name = substr($bonk_data, $offset, 4); + $offset += 4; + $meta_entry_tag_offset = getid3_lib::LittleEndian2Int(substr($bonk_data, $offset, 4)); + $offset += 4; + $getid3->info['bonk']['META']['tags'][$meta_entry_tag_name] = $meta_entry_tag_offset; + } + break; + + case ' ID3': + $info_audio['encoder'] = 'Extended BONK v0.9+'; + + // ID3v2 checking is optional + if (class_exists('getid3_id3v2')) { + + $id3v2 = new getid3_id3v2($getid3); + $id3v2->option_starting_offset = $getid3->info['bonk'][' ID3']['offset'] + 2; + $getid3->info['bonk'][' ID3']['valid'] = $id3v2->Analyze(); + } + break; + + default: + $getid3->warning('Unexpected Bonk tag "'.$bonk_tag_name.'" at offset '.$getid3->info['bonk'][$bonk_tag_name]['offset']); + break; + + } + } + + + + public static function BonkIsValidTagName($possible_bonk_tag, $ignore_case=false) { + + $ignore_case = $ignore_case ? 'i' : ''; + return preg_match('/^(BONK|INFO| ID3|META)$/'.$ignore_case, $possible_bonk_tag); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.flac.php b/plugins/getId3Plugin/lib/module.audio.flac.php new file mode 100644 index 0000000..573ed98 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.flac.php @@ -0,0 +1,309 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.flac.php // +// module for analyzing FLAC and OggFLAC audio files // +// dependencies: module.audio.ogg.php // +// /// +///////////////////////////////////////////////////////////////// + + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true); + +class getid3_flac +{ + + function getid3_flac(&$fd, &$ThisFileInfo) { + // http://flac.sourceforge.net/format.html + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $StreamMarker = fread($fd, 4); + if ($StreamMarker != 'fLaC') { + $ThisFileInfo['error'][] = 'Expecting "fLaC" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$StreamMarker.'"'; + return false; + } + $ThisFileInfo['fileformat'] = 'flac'; + $ThisFileInfo['audio']['dataformat'] = 'flac'; + $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; + $ThisFileInfo['audio']['lossless'] = true; + + return getid3_flac::FLACparseMETAdata($fd, $ThisFileInfo); + } + + + function FLACparseMETAdata(&$fd, &$ThisFileInfo) { + + do { + $METAdataBlockOffset = ftell($fd); + $METAdataBlockHeader = fread($fd, 4); + $METAdataLastBlockFlag = (bool) (getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 0, 1)) & 0x80); + $METAdataBlockType = getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 0, 1)) & 0x7F; + $METAdataBlockLength = getid3_lib::BigEndian2Int(substr($METAdataBlockHeader, 1, 3)); + $METAdataBlockTypeText = getid3_flac::FLACmetaBlockTypeLookup($METAdataBlockType); + + if ($METAdataBlockLength < 0) { + $ThisFileInfo['error'][] = 'corrupt or invalid METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset; + break; + } + + $ThisFileInfo['flac'][$METAdataBlockTypeText]['raw'] = array(); + $ThisFileInfo_flac_METAdataBlockTypeText_raw = &$ThisFileInfo['flac'][$METAdataBlockTypeText]['raw']; + + $ThisFileInfo_flac_METAdataBlockTypeText_raw['offset'] = $METAdataBlockOffset; + $ThisFileInfo_flac_METAdataBlockTypeText_raw['last_meta_block'] = $METAdataLastBlockFlag; + $ThisFileInfo_flac_METAdataBlockTypeText_raw['block_type'] = $METAdataBlockType; + $ThisFileInfo_flac_METAdataBlockTypeText_raw['block_type_text'] = $METAdataBlockTypeText; + $ThisFileInfo_flac_METAdataBlockTypeText_raw['block_length'] = $METAdataBlockLength; + $ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'] = @fread($fd, $METAdataBlockLength); + $ThisFileInfo['avdataoffset'] = ftell($fd); + + switch ($METAdataBlockTypeText) { + + case 'STREAMINFO': + if (!getid3_flac::FLACparseSTREAMINFO($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) { + return false; + } + break; + + case 'PADDING': + // ignore + break; + + case 'APPLICATION': + if (!getid3_flac::FLACparseAPPLICATION($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) { + return false; + } + break; + + case 'SEEKTABLE': + if (!getid3_flac::FLACparseSEEKTABLE($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) { + return false; + } + break; + + case 'VORBIS_COMMENT': + $OldOffset = ftell($fd); + fseek($fd, 0 - $METAdataBlockLength, SEEK_CUR); + getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo); + fseek($fd, $OldOffset, SEEK_SET); + break; + + case 'CUESHEET': + if (!getid3_flac::FLACparseCUESHEET($ThisFileInfo_flac_METAdataBlockTypeText_raw['block_data'], $ThisFileInfo)) { + return false; + } + break; + + default: + $ThisFileInfo['warning'][] = 'Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$METAdataBlockType.') at offset '.$METAdataBlockOffset; + break; + } + + } while ($METAdataLastBlockFlag === false); + + + if (isset($ThisFileInfo['flac']['STREAMINFO'])) { + $ThisFileInfo['flac']['compressed_audio_bytes'] = $ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']; + $ThisFileInfo['flac']['uncompressed_audio_bytes'] = $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] * $ThisFileInfo['flac']['STREAMINFO']['channels'] * ($ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'] / 8); + if ($ThisFileInfo['flac']['uncompressed_audio_bytes'] == 0) { + $ThisFileInfo['error'][] = 'Corrupt FLAC file: uncompressed_audio_bytes == zero'; + return false; + } + $ThisFileInfo['flac']['compression_ratio'] = $ThisFileInfo['flac']['compressed_audio_bytes'] / $ThisFileInfo['flac']['uncompressed_audio_bytes']; + } + + // set md5_data_source - built into flac 0.5+ + if (isset($ThisFileInfo['flac']['STREAMINFO']['audio_signature'])) { + + if ($ThisFileInfo['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) { + + $ThisFileInfo['warning'][] = 'FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)'; + + } else { + + $ThisFileInfo['md5_data_source'] = ''; + $md5 = $ThisFileInfo['flac']['STREAMINFO']['audio_signature']; + for ($i = 0; $i < strlen($md5); $i++) { + $ThisFileInfo['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT); + } + if (!preg_match('/^[0-9a-f]{32}$/', $ThisFileInfo['md5_data_source'])) { + unset($ThisFileInfo['md5_data_source']); + } + + } + + } + + $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample']; + if ($ThisFileInfo['audio']['bits_per_sample'] == 8) { + // special case + // must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value + // MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed + $ThisFileInfo['warning'][] = 'FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file'; + } + if (!empty($ThisFileInfo['ogg']['vendor'])) { + $ThisFileInfo['audio']['encoder'] = $ThisFileInfo['ogg']['vendor']; + } + + return true; + } + + function FLACmetaBlockTypeLookup($blocktype) { + static $FLACmetaBlockTypeLookup = array(); + if (empty($FLACmetaBlockTypeLookup)) { + $FLACmetaBlockTypeLookup[0] = 'STREAMINFO'; + $FLACmetaBlockTypeLookup[1] = 'PADDING'; + $FLACmetaBlockTypeLookup[2] = 'APPLICATION'; + $FLACmetaBlockTypeLookup[3] = 'SEEKTABLE'; + $FLACmetaBlockTypeLookup[4] = 'VORBIS_COMMENT'; + $FLACmetaBlockTypeLookup[5] = 'CUESHEET'; + } + return (isset($FLACmetaBlockTypeLookup[$blocktype]) ? $FLACmetaBlockTypeLookup[$blocktype] : 'reserved'); + } + + function FLACapplicationIDLookup($applicationid) { + static $FLACapplicationIDLookup = array(); + if (empty($FLACapplicationIDLookup)) { + // http://flac.sourceforge.net/id.html + $FLACapplicationIDLookup[0x46746F6C] = 'flac-tools'; // 'Ftol' + $FLACapplicationIDLookup[0x46746F6C] = 'Sound Font FLAC'; // 'SFFL' + } + return (isset($FLACapplicationIDLookup[$applicationid]) ? $FLACapplicationIDLookup[$applicationid] : 'reserved'); + } + + function FLACparseSTREAMINFO($METAdataBlockData, &$ThisFileInfo) { + $offset = 0; + $ThisFileInfo['flac']['STREAMINFO']['min_block_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2)); + $offset += 2; + $ThisFileInfo['flac']['STREAMINFO']['max_block_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2)); + $offset += 2; + $ThisFileInfo['flac']['STREAMINFO']['min_frame_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 3)); + $offset += 3; + $ThisFileInfo['flac']['STREAMINFO']['max_frame_size'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 3)); + $offset += 3; + + $SampleRateChannelsSampleBitsStreamSamples = getid3_lib::BigEndian2Bin(substr($METAdataBlockData, $offset, 8)); + $ThisFileInfo['flac']['STREAMINFO']['sample_rate'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 0, 20)); + $ThisFileInfo['flac']['STREAMINFO']['channels'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 20, 3)) + 1; + $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 23, 5)) + 1; + $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] = getid3_lib::Bin2Dec(substr($SampleRateChannelsSampleBitsStreamSamples, 28, 36)); + $offset += 8; + + $ThisFileInfo['flac']['STREAMINFO']['audio_signature'] = substr($METAdataBlockData, $offset, 16); + $offset += 16; + + if (!empty($ThisFileInfo['flac']['STREAMINFO']['sample_rate'])) { + + $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; + $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['flac']['STREAMINFO']['sample_rate']; + $ThisFileInfo['audio']['channels'] = $ThisFileInfo['flac']['STREAMINFO']['channels']; + $ThisFileInfo['audio']['bits_per_sample'] = $ThisFileInfo['flac']['STREAMINFO']['bits_per_sample']; + $ThisFileInfo['playtime_seconds'] = $ThisFileInfo['flac']['STREAMINFO']['samples_stream'] / $ThisFileInfo['flac']['STREAMINFO']['sample_rate']; + $ThisFileInfo['audio']['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds']; + + } else { + + $ThisFileInfo['error'][] = 'Corrupt METAdata block: STREAMINFO'; + return false; + + } + return true; + } + + + function FLACparseAPPLICATION($METAdataBlockData, &$ThisFileInfo) { + $offset = 0; + $ApplicationID = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 4)); + $offset += 4; + $ThisFileInfo['flac']['APPLICATION'][$ApplicationID]['name'] = getid3_flac::FLACapplicationIDLookup($ApplicationID); + $ThisFileInfo['flac']['APPLICATION'][$ApplicationID]['data'] = substr($METAdataBlockData, $offset); + $offset = $METAdataBlockLength; + + return true; + } + + + function FLACparseSEEKTABLE($METAdataBlockData, &$ThisFileInfo) { + $offset = 0; + $METAdataBlockLength = strlen($METAdataBlockData); + $placeholderpattern = str_repeat("\xFF", 8); + while ($offset < $METAdataBlockLength) { + $SampleNumberString = substr($METAdataBlockData, $offset, 8); + $offset += 8; + if ($SampleNumberString == $placeholderpattern) { + + // placeholder point + @$ThisFileInfo['flac']['SEEKTABLE']['placeholders']++; + $offset += 10; + + } else { + + $SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString); + $ThisFileInfo['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8)); + $offset += 8; + $ThisFileInfo['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 2)); + $offset += 2; + + } + } + return true; + } + + function FLACparseCUESHEET($METAdataBlockData, &$ThisFileInfo) { + $offset = 0; + $ThisFileInfo['flac']['CUESHEET']['media_catalog_number'] = trim(substr($METAdataBlockData, $offset, 128), "\0"); + $offset += 128; + $ThisFileInfo['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8)); + $offset += 8; + $ThisFileInfo['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)) & 0x80); + $offset += 1; + + $offset += 258; // reserved + + $ThisFileInfo['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)); + $offset += 1; + + for ($track = 0; $track < $ThisFileInfo['flac']['CUESHEET']['number_tracks']; $track++) { + $TrackSampleOffset = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8)); + $offset += 8; + $TrackNumber = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)); + $offset += 1; + + $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset; + + $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($METAdataBlockData, $offset, 12); + $offset += 12; + + $TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)); + $offset += 1; + $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80); + $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40); + + $offset += 13; // reserved + + $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)); + $offset += 1; + + for ($index = 0; $index < $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points']; $index++) { + $IndexSampleOffset = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 8)); + $offset += 8; + $IndexNumber = getid3_lib::BigEndian2Int(substr($METAdataBlockData, $offset, 1)); + $offset += 1; + + $offset += 3; // reserved + + $ThisFileInfo['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset; + } + } + return true; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.la.php b/plugins/getId3Plugin/lib/module.audio.la.php new file mode 100644 index 0000000..244d29a --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.la.php @@ -0,0 +1,196 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.la.php | +// | Module for analyzing LA udio files | +// | dependencies: module.audio-video.riff.php | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.la.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_la extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->include_module('audio-video.riff'); + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $raw_data = fread($getid3->fp, getid3::FREAD_BUFFER_SIZE); + + $getid3->info['fileformat'] = 'la'; + $getid3->info['audio']['dataformat'] = 'la'; + $getid3->info['audio']['lossless'] = true; + + $getid3->info['la']['version_major'] = (int)$raw_data{2}; + $getid3->info['la']['version_minor'] = (int)$raw_data{3}; + $getid3->info['la']['version'] = (float)$getid3->info['la']['version_major'] + ($getid3->info['la']['version_minor'] / 10); + + $getid3->info['la']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($raw_data, 4, 4)); + + $wave_chunk = substr($raw_data, 8, 4); + if ($wave_chunk !== 'WAVE') { + throw new getid3_exception('Expected "WAVE" ('.getid3_lib::PrintHexBytes('WAVE').') at offset 8, found "'.$wave_chunk.'" ('.getid3_lib::PrintHexBytes($wave_chunk).') instead.'); + } + + $offset = 12; + + $getid3->info['la']['fmt_size'] = 24; + if ($getid3->info['la']['version'] >= 0.3) { + + $getid3->info['la']['fmt_size'] = getid3_lib::LittleEndian2Int(substr($raw_data, $offset, 4)); + $getid3->info['la']['header_size'] = 49 + $getid3->info['la']['fmt_size'] - 24; + $offset += 4; + + } else { + + // version 0.2 didn't support additional data blocks + $getid3->info['la']['header_size'] = 41; + } + + $fmt_chunk = substr($raw_data, $offset, 4); + if ($fmt_chunk !== 'fmt ') { + throw new getid3_exception('Expected "fmt " ('.getid3_lib::PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.getid3_lib::PrintHexBytes($fmt_chunk).') instead.'); + } + $offset += 4; + + $fmt_size = getid3_lib::LittleEndian2Int(substr($raw_data, $offset, 4)); + $offset += 4; + + $getid3->info['la']['raw']['format'] = getid3_lib::LittleEndian2Int(substr($raw_data, $offset, 2)); + $offset += 2; + + getid3_lib::ReadSequence('LittleEndian2Int', $getid3->info['la'], $raw_data, $offset, + array ( + 'channels' => 2, + 'sample_rate' => 4, + 'bytes_per_second' => 4, + 'bytes_per_sample' => 2, + 'bits_per_sample' => 2, + 'samples' => 4 + ) + ); + $offset += 18; + + $getid3->info['la']['raw']['flags'] = getid3_lib::LittleEndian2Int($raw_data{$offset++}); + + $getid3->info['la']['flags']['seekable'] = (bool)($getid3->info['la']['raw']['flags'] & 0x01); + if ($getid3->info['la']['version'] >= 0.4) { + $getid3->info['la']['flags']['high_compression'] = (bool)($getid3->info['la']['raw']['flags'] & 0x02); + } + + $getid3->info['la']['original_crc'] = getid3_lib::LittleEndian2Int(substr($raw_data, $offset, 4)); + $offset += 4; + + // mikebevin*de + // Basically, the blocksize/seekevery are 61440/19 in La0.4 and 73728/16 + // in earlier versions. A seekpoint is added every blocksize * seekevery + // samples, so 4 * int(totalSamples / (blockSize * seekEvery)) should + // give the number of bytes used for the seekpoints. Of course, if seeking + // is disabled, there are no seekpoints stored. + + if ($getid3->info['la']['version'] >= 0.4) { + $getid3->info['la']['blocksize'] = 61440; + $getid3->info['la']['seekevery'] = 19; + } else { + $getid3->info['la']['blocksize'] = 73728; + $getid3->info['la']['seekevery'] = 16; + } + + $getid3->info['la']['seekpoint_count'] = 0; + if ($getid3->info['la']['flags']['seekable']) { + $getid3->info['la']['seekpoint_count'] = floor($getid3->info['la']['samples'] / ($getid3->info['la']['blocksize'] * $getid3->info['la']['seekevery'])); + + for ($i = 0; $i < $getid3->info['la']['seekpoint_count']; $i++) { + $getid3->info['la']['seekpoints'][] = getid3_lib::LittleEndian2Int(substr($raw_data, $offset, 4)); + $offset += 4; + } + } + + if ($getid3->info['la']['version'] >= 0.3) { + + // Following the main header information, the program outputs all of the + // seekpoints. Following these is what I called the 'footer start', + // i.e. the position immediately after the La audio data is finished. + + $getid3->info['la']['footerstart'] = getid3_lib::LittleEndian2Int(substr($raw_data, $offset, 4)); + $offset += 4; + + if ($getid3->info['la']['footerstart'] > $getid3->info['filesize']) { + $getid3->warning('FooterStart value points to offset '.$getid3->info['la']['footerstart'].' which is beyond end-of-file ('.$getid3->info['filesize'].')'); + $getid3->info['la']['footerstart'] = $getid3->info['filesize']; + } + + } else { + + // La v0.2 didn't have FooterStart value + $getid3->info['la']['footerstart'] = $getid3->info['avdataend']; + + } + + if ($getid3->info['la']['footerstart'] < $getid3->info['avdataend']) { + + // Create riff header + $riff_data = 'WAVE'; + if ($getid3->info['la']['version'] == 0.2) { + $riff_data .= substr($raw_data, 12, 24); + } else { + $riff_data .= substr($raw_data, 16, 24); + } + if ($getid3->info['la']['footerstart'] < $getid3->info['avdataend']) { + fseek($getid3->fp, $getid3->info['la']['footerstart'], SEEK_SET); + $riff_data .= fread($getid3->fp, $getid3->info['avdataend'] - $getid3->info['la']['footerstart']); + } + $riff_data = 'RIFF'.getid3_lib::LittleEndian2String(strlen($riff_data), 4, false).$riff_data; + + // Clone getid3 - messing with offsets - better safe than sorry + $clone = clone $getid3; + + // Analyze clone by string + $riff = new getid3_riff($clone); + $riff->AnalyzeString($riff_data); + + // Import from clone and destroy + $getid3->info['riff'] = $clone->info['riff']; + $getid3->warnings($clone->warnings()); + unset($clone); + } + + // $getid3->info['avdataoffset'] should be zero to begin with, but just in case it's not, include the addition anyway + $getid3->info['avdataend'] = $getid3->info['avdataoffset'] + $getid3->info['la']['footerstart']; + $getid3->info['avdataoffset'] = $getid3->info['avdataoffset'] + $offset; + + $getid3->info['la']['compression_ratio'] = (float)(($getid3->info['avdataend'] - $getid3->info['avdataoffset']) / $getid3->info['la']['uncompressed_size']); + $getid3->info['playtime_seconds'] = (float)($getid3->info['la']['samples'] / $getid3->info['la']['sample_rate']) / $getid3->info['la']['channels']; + + $getid3->info['audio']['bitrate'] = ($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8 / $getid3->info['playtime_seconds']; + $getid3->info['audio']['bits_per_sample'] = $getid3->info['la']['bits_per_sample']; + + $getid3->info['audio']['channels'] = $getid3->info['la']['channels']; + $getid3->info['audio']['sample_rate'] = (int)$getid3->info['la']['sample_rate']; + $getid3->info['audio']['encoder'] = 'LA v'.$getid3->info['la']['version']; + + return true; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.lpac.php b/plugins/getId3Plugin/lib/module.audio.lpac.php new file mode 100644 index 0000000..5884c20 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.lpac.php @@ -0,0 +1,148 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.lpac.php | +// | Module for analyzing LPAC Audio files | +// | dependencies: module.audio-video.riff.php | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.lpac.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_lpac extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->include_module('audio-video.riff'); + + // Magic bytes - 'LPAC' + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $lpac_header = fread($getid3->fp, 14); + + $getid3->info['avdataoffset'] += 14; + + $getid3->info['lpac'] = array (); + $info_lpac = &$getid3->info['lpac']; + + $getid3->info['fileformat'] = 'lpac'; + $getid3->info['audio']['dataformat'] = 'lpac'; + $getid3->info['audio']['lossless'] = true; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + + $info_lpac['file_version'] = getid3_lib::BigEndian2Int($lpac_header{4}); + $flags['audio_type'] = getid3_lib::BigEndian2Int($lpac_header{5}); + $info_lpac['total_samples'] = getid3_lib::BigEndian2Int(substr($lpac_header, 6, 4)); + $flags['parameters'] = getid3_lib::BigEndian2Int(substr($lpac_header, 10, 4)); + + $info_lpac['flags']['is_wave'] = (bool)($flags['audio_type'] & 0x40); + $info_lpac['flags']['stereo'] = (bool)($flags['audio_type'] & 0x04); + $info_lpac['flags']['24_bit'] = (bool)($flags['audio_type'] & 0x02); + $info_lpac['flags']['16_bit'] = (bool)($flags['audio_type'] & 0x01); + + if ($info_lpac['flags']['24_bit'] && $info_lpac['flags']['16_bit']) { + $getid3->warning('24-bit and 16-bit flags cannot both be set'); + } + + $info_lpac['flags']['fast_compress'] = (bool)($flags['parameters'] & 0x40000000); + $info_lpac['flags']['random_access'] = (bool)($flags['parameters'] & 0x08000000); + $info_lpac['block_length'] = pow(2, (($flags['parameters'] & 0x07000000) >> 24)) * 256; + $info_lpac['flags']['adaptive_prediction_order'] = (bool)($flags['parameters'] & 0x00800000); + $info_lpac['flags']['adaptive_quantization'] = (bool)($flags['parameters'] & 0x00400000); + $info_lpac['flags']['joint_stereo'] = (bool)($flags['parameters'] & 0x00040000); + $info_lpac['quantization'] = ($flags['parameters'] & 0x00001F00) >> 8; + $info_lpac['max_prediction_order'] = ($flags['parameters'] & 0x0000003F); + + if ($info_lpac['flags']['fast_compress'] && ($info_lpac['max_prediction_order'] != 3)) { + $getid3->warning('max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$info_lpac['max_prediction_order'].'"'); + } + + switch ($info_lpac['file_version']) { + + case 6: + if ($info_lpac['flags']['adaptive_quantization']) { + $getid3->warning('adaptive_quantization expected to be false in LPAC file stucture v6, actually true'); + } + if ($info_lpac['quantization'] != 20) { + $getid3->warning('Quantization expected to be 20 in LPAC file stucture v6, actually '.$info_lpac['flags']['Q']); + } + break; + + + default: + //$getid3->warning('This version of getID3() only supports LPAC file format version 6, this file is version '.$info_lpac['file_version'].' - please report to info@getid3.org'); + break; + } + + // Clone getid3 - messing with something - better safe than sorry + $clone = clone $getid3; + + // Analyze clone by fp + $riff = new getid3_riff($clone); + $riff->Analyze(); + + // Import from clone and destroy + $getid3->info['avdataoffset'] = $clone->info['avdataoffset']; + $getid3->info['riff'] = $clone->info['riff']; + //$info_lpac['comments']['comment'] = $clone->info['comments']; + $getid3->info['audio']['sample_rate'] = $clone->info['audio']['sample_rate']; + $getid3->warnings($clone->warnings()); + unset($clone); + + $getid3->info['audio']['channels'] = ($info_lpac['flags']['stereo'] ? 2 : 1); + + if ($info_lpac['flags']['24_bit']) { + $getid3->info['audio']['bits_per_sample'] = $getid3->info['riff']['audio'][0]['bits_per_sample']; + } elseif ($info_lpac['flags']['16_bit']) { + $getid3->info['audio']['bits_per_sample'] = 16; + } else { + $getid3->info['audio']['bits_per_sample'] = 8; + } + + if ($info_lpac['flags']['fast_compress']) { + // fast + $getid3->info['audio']['encoder_options'] = '-1'; + } else { + switch ($info_lpac['max_prediction_order']) { + case 20: // simple + $getid3->info['audio']['encoder_options'] = '-2'; + break; + case 30: // medium + $getid3->info['audio']['encoder_options'] = '-3'; + break; + case 40: // high + $getid3->info['audio']['encoder_options'] = '-4'; + break; + case 60: // extrahigh + $getid3->info['audio']['encoder_options'] = '-5'; + break; + } + } + + $getid3->info['playtime_seconds'] = $info_lpac['total_samples'] / $getid3->info['audio']['sample_rate']; + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + + return true; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.midi.php b/plugins/getId3Plugin/lib/module.audio.midi.php new file mode 100644 index 0000000..1c2d1f6 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.midi.php @@ -0,0 +1,551 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.midi.php | +// | Module for analyzing midi audio files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.midi.php,v 1.3 2006/06/06 18:38:54 ah Exp $ + + + +class getid3_midi extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['midi']['raw'] = array (); + $info_midi = &$getid3->info['midi']; + $info_midi_raw = &$info_midi['raw']; + + $getid3->info['fileformat'] = 'midi'; + $getid3->info['audio']['dataformat'] = 'midi'; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $midi_data = fread($getid3->fp, getid3::FREAD_BUFFER_SIZE); + + // Magic bytes: 'MThd' + + getid3_lib::ReadSequence('BigEndian2Int', $info_midi_raw, $midi_data, 4, + array ( + 'headersize' => 4, + 'fileformat' => 2, + 'tracks' => 2, + 'ticksperqnote' => 2 + ) + ); + + $offset = 14; + + for ($i = 0; $i < $info_midi_raw['tracks']; $i++) { + + if ((strlen($midi_data) - $offset) < 8) { + $midi_data .= fread($getid3->fp, getid3::FREAD_BUFFER_SIZE); + } + + $track_id = substr($midi_data, $offset, 4); + $offset += 4; + + if ($track_id != 'MTrk') { + throw new getid3_exception('Expecting "MTrk" at '.$offset.', found '.$track_id.' instead'); + } + + $track_size = getid3_lib::BigEndian2Int(substr($midi_data, $offset, 4)); + $offset += 4; + + $track_data_array[$i] = substr($midi_data, $offset, $track_size); + $offset += $track_size; + } + + if (!isset($track_data_array) || !is_array($track_data_array)) { + throw new getid3_exception('Cannot find MIDI track information'); + } + + + $info_midi['totalticks'] = 0; + $getid3->info['playtime_seconds'] = 0; + $current_ms_per_beat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat + $current_beats_per_min = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat + + foreach ($track_data_array as $track_number => $track_data) { + + $events_offset = $last_issued_midi_command = $last_issued_midi_channel = $cumulative_delta_time = $ticks_at_current_bpm = 0; + + while ($events_offset < strlen($track_data)) { + + $event_id = 0; + if (isset($midi_events[$track_number]) && is_array($midi_events[$track_number])) { + $event_id = count($midi_events[$track_number]); + } + $delta_time = 0; + for ($i = 0; $i < 4; $i++) { + $delta_time_byte = ord($track_data{$events_offset++}); + $delta_time = ($delta_time << 7) + ($delta_time_byte & 0x7F); + if ($delta_time_byte & 0x80) { + // another byte follows + } else { + break; + } + } + + $cumulative_delta_time += $delta_time; + $ticks_at_current_bpm += $delta_time; + + $midi_events[$track_number][$event_id]['deltatime'] = $delta_time; + + $midi_event_channel = ord($track_data{$events_offset++}); + + // OK, normal event - MIDI command has MSB set + if ($midi_event_channel & 0x80) { + $last_issued_midi_command = $midi_event_channel >> 4; + $last_issued_midi_channel = $midi_event_channel & 0x0F; + } + + // Running event - assume last command + else { + $events_offset--; + } + + $midi_events[$track_number][$event_id]['eventid'] = $last_issued_midi_command; + $midi_events[$track_number][$event_id]['channel'] = $last_issued_midi_channel; + + switch ($midi_events[$track_number][$event_id]['eventid']) { + + case 0x8: // Note off (key is released) + case 0x9: // Note on (key is pressed) + case 0xA: // Key after-touch + + //$notenumber = ord($track_data{$events_offset++}); + //$velocity = ord($track_data{$events_offset++}); + $events_offset += 2; + break; + + + case 0xB: // Control Change + + //$controllernum = ord($track_data{$events_offset++}); + //$newvalue = ord($track_data{$events_offset++}); + $events_offset += 2; + break; + + + case 0xC: // Program (patch) change + + $new_program_num = ord($track_data{$events_offset++}); + + $info_midi_raw['track'][$track_number]['instrumentid'] = $new_program_num; + $info_midi_raw['track'][$track_number]['instrument'] = $track_number == 10 ? getid3_midi::GeneralMIDIpercussionLookup($new_program_num) : getid3_midi::GeneralMIDIinstrumentLookup($new_program_num); + break; + + + case 0xD: // Channel after-touch + + //$channelnumber = ord($track_data{$events_offset++}); + break; + + + case 0xE: // Pitch wheel change (2000H is normal or no change) + + //$changeLSB = ord($track_data{$events_offset++}); + //$changeMSB = ord($track_data{$events_offset++}); + //$pitchwheelchange = (($changeMSB & 0x7F) << 7) & ($changeLSB & 0x7F); + $events_offset += 2; + break; + + + case 0xF: + + if ($midi_events[$track_number][$event_id]['channel'] == 0xF) { + + $meta_event_command = ord($track_data{$events_offset++}); + $meta_event_length = ord($track_data{$events_offset++}); + $meta_event_data = substr($track_data, $events_offset, $meta_event_length); + $events_offset += $meta_event_length; + + switch ($meta_event_command) { + + case 0x00: // Set track sequence number + + //$track_sequence_number = getid3_lib::BigEndian2Int(substr($meta_event_data, 0, $meta_event_length)); + //$info_midi_raw['events'][$track_number][$event_id]['seqno'] = $track_sequence_number; + break; + + + case 0x01: // Text: generic + + $text_generic = substr($meta_event_data, 0, $meta_event_length); + //$info_midi_raw['events'][$track_number][$event_id]['text'] = $text_generic; + $info_midi['comments']['comment'][] = $text_generic; + break; + + + case 0x02: // Text: copyright + + $text_copyright = substr($meta_event_data, 0, $meta_event_length); + //$info_midi_raw['events'][$track_number][$event_id]['copyright'] = $text_copyright; + $info_midi['comments']['copyright'][] = $text_copyright; + break; + + + case 0x03: // Text: track name + + $text_trackname = substr($meta_event_data, 0, $meta_event_length); + $info_midi_raw['track'][$track_number]['name'] = $text_trackname; + break; + + + case 0x04: // Text: track instrument name + + //$text_instrument = substr($meta_event_data, 0, $meta_event_length); + //$info_midi_raw['events'][$track_number][$event_id]['instrument'] = $text_instrument; + break; + + + case 0x05: // Text: lyrics + + $text_lyrics = substr($meta_event_data, 0, $meta_event_length); + //$info_midi_raw['events'][$track_number][$event_id]['lyrics'] = $text_lyrics; + if (!isset($info_midi['lyrics'])) { + $info_midi['lyrics'] = ''; + } + $info_midi['lyrics'] .= $text_lyrics . "\n"; + break; + + + case 0x06: // Text: marker + + //$text_marker = substr($meta_event_data, 0, $meta_event_length); + //$info_midi_raw['events'][$track_number][$event_id]['marker'] = $text_marker; + break; + + + case 0x07: // Text: cue point + + //$text_cuepoint = substr($meta_event_data, 0, $meta_event_length); + //$info_midi_raw['events'][$track_number][$event_id]['cuepoint'] = $text_cuepoint; + break; + + + case 0x2F: // End Of Track + + //$info_midi_raw['events'][$track_number][$event_id]['EOT'] = $cumulative_delta_time; + break; + + + case 0x51: // Tempo: microseconds / quarter note + + $current_ms_per_beat = getid3_lib::BigEndian2Int(substr($meta_event_data, 0, $meta_event_length)); + $info_midi_raw['events'][$track_number][$cumulative_delta_time]['us_qnote'] = $current_ms_per_beat; + $current_beats_per_min = (1000000 / $current_ms_per_beat) * 60; + $ms_per_quarter_note_after[$cumulative_delta_time] = $current_ms_per_beat; + $ticks_at_current_bpm = 0; + break; + + + case 0x58: // Time signature + $timesig_numerator = getid3_lib::BigEndian2Int($meta_event_data[0]); + $timesig_denominator = pow(2, getid3_lib::BigEndian2Int($meta_event_data[1])); // $02 -> x/4, $03 -> x/8, etc + //$timesig_32inqnote = getid3_lib::BigEndian2Int($meta_event_data[2]); // number of 32nd notes to the quarter note + //$info_midi_raw['events'][$track_number][$event_id]['timesig_32inqnote'] = $timesig_32inqnote; + //$info_midi_raw['events'][$track_number][$event_id]['timesig_numerator'] = $timesig_numerator; + //$info_midi_raw['events'][$track_number][$event_id]['timesig_denominator'] = $timesig_denominator; + //$info_midi_raw['events'][$track_number][$event_id]['timesig_text'] = $timesig_numerator.'/'.$timesig_denominator; + $info_midi['timesignature'][] = $timesig_numerator.'/'.$timesig_denominator; + break; + + + case 0x59: // Keysignature + + $keysig_sharpsflats = getid3_lib::BigEndian2Int($meta_event_data{0}); + if ($keysig_sharpsflats & 0x80) { + // (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps) + $keysig_sharpsflats -= 256; + } + + $keysig_majorminor = getid3_lib::BigEndian2Int($meta_event_data{1}); // 0 -> major, 1 -> minor + $keysigs = array (-7=>'Cb', -6=>'Gb', -5=>'Db', -4=>'Ab', -3=>'Eb', -2=>'Bb', -1=>'F', 0=>'C', 1=>'G', 2=>'D', 3=>'A', 4=>'E', 5=>'B', 6=>'F#', 7=>'C#'); + //$info_midi_raw['events'][$track_number][$event_id]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0); + //$info_midi_raw['events'][$track_number][$event_id]['keysig_flats'] = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0); + //$info_midi_raw['events'][$track_number][$event_id]['keysig_minor'] = (bool)$keysig_majorminor; + //$info_midi_raw['events'][$track_number][$event_id]['keysig_text'] = $keysigs[$keysig_sharpsflats].' '.($info_midi_raw['events'][$track_number][$event_id]['keysig_minor'] ? 'minor' : 'major'); + + // $keysigs[$keysig_sharpsflats] gets an int key (correct) - $keysigs["$keysig_sharpsflats"] gets a string key (incorrect) + $info_midi['keysignature'][] = $keysigs[$keysig_sharpsflats].' '.((bool)$keysig_majorminor ? 'minor' : 'major'); + break; + + + case 0x7F: // Sequencer specific information + + $custom_data = substr($meta_event_data, 0, $meta_event_length); + break; + + + default: + + $getid3->warning('Unhandled META Event Command: '.$meta_event_command); + } + } + break; + + + default: + $getid3->warning('Unhandled MIDI Event ID: '.$midi_events[$track_number][$event_id]['eventid']); + } + } + + if (($track_number > 0) || (count($track_data_array) == 1)) { + $info_midi['totalticks'] = max($info_midi['totalticks'], $cumulative_delta_time); + } + } + + $previous_tick_offset = null; + + ksort($ms_per_quarter_note_after); + foreach ($ms_per_quarter_note_after as $tick_offset => $ms_per_beat) { + + if (is_null($previous_tick_offset)) { + $prev_ms_per_beat = $ms_per_beat; + $previous_tick_offset = $tick_offset; + continue; + } + + if ($info_midi['totalticks'] > $tick_offset) { + $getid3->info['playtime_seconds'] += (($tick_offset - $previous_tick_offset) / $info_midi_raw['ticksperqnote']) * ($prev_ms_per_beat / 1000000); + + $prev_ms_per_beat = $ms_per_beat; + $previous_tick_offset = $tick_offset; + } + } + + if ($info_midi['totalticks'] > $previous_tick_offset) { + $getid3->info['playtime_seconds'] += (($info_midi['totalticks'] - $previous_tick_offset) / $info_midi_raw['ticksperqnote']) * ($ms_per_beat / 1000000); + } + + if ($getid3->info['playtime_seconds'] > 0) { + $getid3->info['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + } + + if (!empty($info_midi['lyrics'])) { + $info_midi['comments']['lyrics'][] = $info_midi['lyrics']; + } + + return true; + } + + + + public static function GeneralMIDIinstrumentLookup($instrument_id) { + + static $lookup = array ( + + 0 => 'Acoustic Grand', + 1 => 'Bright Acoustic', + 2 => 'Electric Grand', + 3 => 'Honky-Tonk', + 4 => 'Electric Piano 1', + 5 => 'Electric Piano 2', + 6 => 'Harpsichord', + 7 => 'Clavier', + 8 => 'Celesta', + 9 => 'Glockenspiel', + 10 => 'Music Box', + 11 => 'Vibraphone', + 12 => 'Marimba', + 13 => 'Xylophone', + 14 => 'Tubular Bells', + 15 => 'Dulcimer', + 16 => 'Drawbar Organ', + 17 => 'Percussive Organ', + 18 => 'Rock Organ', + 19 => 'Church Organ', + 20 => 'Reed Organ', + 21 => 'Accordian', + 22 => 'Harmonica', + 23 => 'Tango Accordian', + 24 => 'Acoustic Guitar (nylon)', + 25 => 'Acoustic Guitar (steel)', + 26 => 'Electric Guitar (jazz)', + 27 => 'Electric Guitar (clean)', + 28 => 'Electric Guitar (muted)', + 29 => 'Overdriven Guitar', + 30 => 'Distortion Guitar', + 31 => 'Guitar Harmonics', + 32 => 'Acoustic Bass', + 33 => 'Electric Bass (finger)', + 34 => 'Electric Bass (pick)', + 35 => 'Fretless Bass', + 36 => 'Slap Bass 1', + 37 => 'Slap Bass 2', + 38 => 'Synth Bass 1', + 39 => 'Synth Bass 2', + 40 => 'Violin', + 41 => 'Viola', + 42 => 'Cello', + 43 => 'Contrabass', + 44 => 'Tremolo Strings', + 45 => 'Pizzicato Strings', + 46 => 'Orchestral Strings', + 47 => 'Timpani', + 48 => 'String Ensemble 1', + 49 => 'String Ensemble 2', + 50 => 'SynthStrings 1', + 51 => 'SynthStrings 2', + 52 => 'Choir Aahs', + 53 => 'Voice Oohs', + 54 => 'Synth Voice', + 55 => 'Orchestra Hit', + 56 => 'Trumpet', + 57 => 'Trombone', + 58 => 'Tuba', + 59 => 'Muted Trumpet', + 60 => 'French Horn', + 61 => 'Brass Section', + 62 => 'SynthBrass 1', + 63 => 'SynthBrass 2', + 64 => 'Soprano Sax', + 65 => 'Alto Sax', + 66 => 'Tenor Sax', + 67 => 'Baritone Sax', + 68 => 'Oboe', + 69 => 'English Horn', + 70 => 'Bassoon', + 71 => 'Clarinet', + 72 => 'Piccolo', + 73 => 'Flute', + 74 => 'Recorder', + 75 => 'Pan Flute', + 76 => 'Blown Bottle', + 77 => 'Shakuhachi', + 78 => 'Whistle', + 79 => 'Ocarina', + 80 => 'Lead 1 (square)', + 81 => 'Lead 2 (sawtooth)', + 82 => 'Lead 3 (calliope)', + 83 => 'Lead 4 (chiff)', + 84 => 'Lead 5 (charang)', + 85 => 'Lead 6 (voice)', + 86 => 'Lead 7 (fifths)', + 87 => 'Lead 8 (bass + lead)', + 88 => 'Pad 1 (new age)', + 89 => 'Pad 2 (warm)', + 90 => 'Pad 3 (polysynth)', + 91 => 'Pad 4 (choir)', + 92 => 'Pad 5 (bowed)', + 93 => 'Pad 6 (metallic)', + 94 => 'Pad 7 (halo)', + 95 => 'Pad 8 (sweep)', + 96 => 'FX 1 (rain)', + 97 => 'FX 2 (soundtrack)', + 98 => 'FX 3 (crystal)', + 99 => 'FX 4 (atmosphere)', + 100 => 'FX 5 (brightness)', + 101 => 'FX 6 (goblins)', + 102 => 'FX 7 (echoes)', + 103 => 'FX 8 (sci-fi)', + 104 => 'Sitar', + 105 => 'Banjo', + 106 => 'Shamisen', + 107 => 'Koto', + 108 => 'Kalimba', + 109 => 'Bagpipe', + 110 => 'Fiddle', + 111 => 'Shanai', + 112 => 'Tinkle Bell', + 113 => 'Agogo', + 114 => 'Steel Drums', + 115 => 'Woodblock', + 116 => 'Taiko Drum', + 117 => 'Melodic Tom', + 118 => 'Synth Drum', + 119 => 'Reverse Cymbal', + 120 => 'Guitar Fret Noise', + 121 => 'Breath Noise', + 122 => 'Seashore', + 123 => 'Bird Tweet', + 124 => 'Telephone Ring', + 125 => 'Helicopter', + 126 => 'Applause', + 127 => 'Gunshot' + ); + + return @$lookup[$instrument_id]; + } + + + + public static function GeneralMIDIpercussionLookup($instrument_id) { + + static $lookup = array ( + + 35 => 'Acoustic Bass Drum', + 36 => 'Bass Drum 1', + 37 => 'Side Stick', + 38 => 'Acoustic Snare', + 39 => 'Hand Clap', + 40 => 'Electric Snare', + 41 => 'Low Floor Tom', + 42 => 'Closed Hi-Hat', + 43 => 'High Floor Tom', + 44 => 'Pedal Hi-Hat', + 45 => 'Low Tom', + 46 => 'Open Hi-Hat', + 47 => 'Low-Mid Tom', + 48 => 'Hi-Mid Tom', + 49 => 'Crash Cymbal 1', + 50 => 'High Tom', + 51 => 'Ride Cymbal 1', + 52 => 'Chinese Cymbal', + 53 => 'Ride Bell', + 54 => 'Tambourine', + 55 => 'Splash Cymbal', + 56 => 'Cowbell', + 57 => 'Crash Cymbal 2', + 59 => 'Ride Cymbal 2', + 60 => 'Hi Bongo', + 61 => 'Low Bongo', + 62 => 'Mute Hi Conga', + 63 => 'Open Hi Conga', + 64 => 'Low Conga', + 65 => 'High Timbale', + 66 => 'Low Timbale', + 67 => 'High Agogo', + 68 => 'Low Agogo', + 69 => 'Cabasa', + 70 => 'Maracas', + 71 => 'Short Whistle', + 72 => 'Long Whistle', + 73 => 'Short Guiro', + 74 => 'Long Guiro', + 75 => 'Claves', + 76 => 'Hi Wood Block', + 77 => 'Low Wood Block', + 78 => 'Mute Cuica', + 79 => 'Open Cuica', + 80 => 'Mute Triangle', + 81 => 'Open Triangle' + ); + + return @$lookup[$instrument_id]; + } + + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.mod.php b/plugins/getId3Plugin/lib/module.audio.mod.php new file mode 100644 index 0000000..7f81ff3 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.mod.php @@ -0,0 +1,101 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.mod.php // +// module for analyzing MOD Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_mod +{ + + // new combined constructor + function getid3_mod(&$fd, &$ThisFileInfo, $option) { + + if ($option === 'mod') { + $this->getMODheaderFilepointer($fd, $ThisFileInfo); + } + elseif ($option === 'xm') { + $this->getXMheaderFilepointer($fd, $ThisFileInfo); + } + elseif ($option === 'it') { + $this->getITheaderFilepointer($fd, $ThisFileInfo); + } + elseif ($option === 's3m') { + $this->getS3MheaderFilepointer($fd, $ThisFileInfo); + } + } + + + function getMODheaderFilepointer(&$fd, &$ThisFileInfo) { + + fseek($fd, $ThisFileInfo['avdataoffset'] + 1080); + $FormatID = fread($fd, 4); + if (!ereg('^(M.K.|[5-9]CHN|[1-3][0-9]CH)$', $FormatID)) { + $ThisFileInfo['error'][] = 'This is not a known type of MOD file'; + return false; + } + + $ThisFileInfo['fileformat'] = 'mod'; + + $ThisFileInfo['error'][] = 'MOD parsing not enabled in this version of getID3()'; + return false; + } + + function getXMheaderFilepointer(&$fd, &$ThisFileInfo) { + + fseek($fd, $ThisFileInfo['avdataoffset']); + $FormatID = fread($fd, 15); + if (!ereg('^Extended Module$', $FormatID)) { + $ThisFileInfo['error'][] = 'This is not a known type of XM-MOD file'; + return false; + } + + $ThisFileInfo['fileformat'] = 'xm'; + + $ThisFileInfo['error'][] = 'XM-MOD parsing not enabled in this version of getID3()'; + return false; + } + + function getS3MheaderFilepointer(&$fd, &$ThisFileInfo) { + + fseek($fd, $ThisFileInfo['avdataoffset'] + 44); + $FormatID = fread($fd, 4); + if (!ereg('^SCRM$', $FormatID)) { + $ThisFileInfo['error'][] = 'This is not a ScreamTracker MOD file'; + return false; + } + + $ThisFileInfo['fileformat'] = 's3m'; + + $ThisFileInfo['error'][] = 'ScreamTracker parsing not enabled in this version of getID3()'; + return false; + } + + function getITheaderFilepointer(&$fd, &$ThisFileInfo) { + + fseek($fd, $ThisFileInfo['avdataoffset']); + $FormatID = fread($fd, 4); + if (!ereg('^IMPM$', $FormatID)) { + $ThisFileInfo['error'][] = 'This is not an ImpulseTracker MOD file'; + return false; + } + + $ThisFileInfo['fileformat'] = 'it'; + + $ThisFileInfo['error'][] = 'ImpulseTracker parsing not enabled in this version of getID3()'; + return false; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.monkey.php b/plugins/getId3Plugin/lib/module.audio.monkey.php new file mode 100644 index 0000000..7940c1c --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.monkey.php @@ -0,0 +1,216 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.monkey.php | +// | Module for analyzing Monkey's Audio files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.monkey.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_monkey extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + // based loosely on code from TMonkey by Jurgen Faul + // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html + + $getid3->info['fileformat'] = 'mac'; + $getid3->info['audio']['dataformat'] = 'mac'; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + $getid3->info['audio']['lossless'] = true; + + $getid3->info['monkeys_audio']['raw'] = array (); + $info_monkeys_audio = &$getid3->info['monkeys_audio']; + $info_monkeys_audio_raw = &$info_monkeys_audio['raw']; + + // Read file header + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $mac_header_data = fread($getid3->fp, 74); + + $info_monkeys_audio_raw['magic'] = 'MAC '; // Magic bytes + + // Read MAC version + $info_monkeys_audio_raw['nVersion'] = getid3_lib::LittleEndian2Int(substr($mac_header_data, 4, 2)); // appears to be uint32 in 3.98+ + + // Parse MAC Header < v3980 + if ($info_monkeys_audio_raw['nVersion'] < 3980) { + + getid3_lib::ReadSequence("LittleEndian2Int", $info_monkeys_audio_raw, $mac_header_data, 6, + array ( + 'nCompressionLevel' => 2, + 'nFormatFlags' => 2, + 'nChannels' => 2, + 'nSampleRate' => 4, + 'nHeaderDataBytes' => 4, + 'nWAVTerminatingBytes' => 4, + 'nTotalFrames' => 4, + 'nFinalFrameSamples' => 4, + 'nPeakLevel' => 4, + 'IGNORE-1' => 2, + 'nSeekElements' => 2 + ) + ); + } + + // Parse MAC Header >= v3980 + else { + + getid3_lib::ReadSequence("LittleEndian2Int", $info_monkeys_audio_raw, $mac_header_data, 8, + array ( + // APE_DESCRIPTOR + 'nDescriptorBytes' => 4, + 'nHeaderBytes' => 4, + 'nSeekTableBytes' => 4, + 'nHeaderDataBytes' => 4, + 'nAPEFrameDataBytes' => 4, + 'nAPEFrameDataBytesHigh'=> 4, + 'nTerminatingDataBytes' => 4, + + // MD5 - string + 'cFileMD5' => -16, + + // APE_HEADER + 'nCompressionLevel' => 2, + 'nFormatFlags' => 2, + 'nBlocksPerFrame' => 4, + 'nFinalFrameBlocks' => 4, + 'nTotalFrames' => 4, + 'nBitsPerSample' => 2, + 'nChannels' => 2, + 'nSampleRate' => 4 + ) + ); + } + + // Process data + $info_monkeys_audio['flags']['8-bit'] = (bool)($info_monkeys_audio_raw['nFormatFlags'] & 0x0001); + $info_monkeys_audio['flags']['crc-32'] = (bool)($info_monkeys_audio_raw['nFormatFlags'] & 0x0002); + $info_monkeys_audio['flags']['peak_level'] = (bool)($info_monkeys_audio_raw['nFormatFlags'] & 0x0004); + $info_monkeys_audio['flags']['24-bit'] = (bool)($info_monkeys_audio_raw['nFormatFlags'] & 0x0008); + $info_monkeys_audio['flags']['seek_elements'] = (bool)($info_monkeys_audio_raw['nFormatFlags'] & 0x0010); + $info_monkeys_audio['flags']['no_wav_header'] = (bool)($info_monkeys_audio_raw['nFormatFlags'] & 0x0020); + + $info_monkeys_audio['version'] = $info_monkeys_audio_raw['nVersion'] / 1000; + + $info_monkeys_audio['compression'] = getid3_monkey::MonkeyCompressionLevelNameLookup($info_monkeys_audio_raw['nCompressionLevel']); + + $info_monkeys_audio['bits_per_sample'] = ($info_monkeys_audio['flags']['24-bit'] ? 24 : ($info_monkeys_audio['flags']['8-bit'] ? 8 : 16)); + + $info_monkeys_audio['channels'] = $info_monkeys_audio_raw['nChannels']; + + $getid3->info['audio']['channels'] = $info_monkeys_audio['channels']; + + $info_monkeys_audio['sample_rate'] = $info_monkeys_audio_raw['nSampleRate']; + + $getid3->info['audio']['sample_rate'] = $info_monkeys_audio['sample_rate']; + + if ($info_monkeys_audio['flags']['peak_level']) { + $info_monkeys_audio['peak_level'] = $info_monkeys_audio_raw['nPeakLevel']; + $info_monkeys_audio['peak_ratio'] = $info_monkeys_audio['peak_level'] / pow(2, $info_monkeys_audio['bits_per_sample'] - 1); + } + + // MAC >= v3980 + if ($info_monkeys_audio_raw['nVersion'] >= 3980) { + $info_monkeys_audio['samples'] = (($info_monkeys_audio_raw['nTotalFrames'] - 1) * $info_monkeys_audio_raw['nBlocksPerFrame']) + $info_monkeys_audio_raw['nFinalFrameBlocks']; + } + + // MAC < v3980 + else { + $info_monkeys_audio['samples_per_frame'] = getid3_monkey::MonkeySamplesPerFrame($info_monkeys_audio_raw['nVersion'], $info_monkeys_audio_raw['nCompressionLevel']); + $info_monkeys_audio['samples'] = (($info_monkeys_audio_raw['nTotalFrames'] - 1) * $info_monkeys_audio['samples_per_frame']) + $info_monkeys_audio_raw['nFinalFrameSamples']; + } + + $info_monkeys_audio['playtime'] = $info_monkeys_audio['samples'] / $info_monkeys_audio['sample_rate']; + + $getid3->info['playtime_seconds'] = $info_monkeys_audio['playtime']; + + $info_monkeys_audio['compressed_size'] = $getid3->info['avdataend'] - $getid3->info['avdataoffset']; + $info_monkeys_audio['uncompressed_size'] = $info_monkeys_audio['samples'] * $info_monkeys_audio['channels'] * ($info_monkeys_audio['bits_per_sample'] / 8); + $info_monkeys_audio['compression_ratio'] = $info_monkeys_audio['compressed_size'] / ($info_monkeys_audio['uncompressed_size'] + $info_monkeys_audio_raw['nHeaderDataBytes']); + $info_monkeys_audio['bitrate'] = (($info_monkeys_audio['samples'] * $info_monkeys_audio['channels'] * $info_monkeys_audio['bits_per_sample']) / $info_monkeys_audio['playtime']) * $info_monkeys_audio['compression_ratio']; + + $getid3->info['audio']['bitrate'] = $info_monkeys_audio['bitrate']; + + $getid3->info['audio']['bits_per_sample'] = $info_monkeys_audio['bits_per_sample']; + $getid3->info['audio']['encoder'] = 'MAC v'.number_format($info_monkeys_audio['version'], 2); + $getid3->info['audio']['encoder_options'] = ucfirst($info_monkeys_audio['compression']).' compression'; + + // MAC >= v3980 - get avdataoffsets from MAC header + if ($info_monkeys_audio_raw['nVersion'] >= 3980) { + $getid3->info['avdataoffset'] += $info_monkeys_audio_raw['nDescriptorBytes'] + $info_monkeys_audio_raw['nHeaderBytes'] + $info_monkeys_audio_raw['nSeekTableBytes'] + $info_monkeys_audio_raw['nHeaderDataBytes']; + $getid3->info['avdataend'] -= $info_monkeys_audio_raw['nTerminatingDataBytes']; + } + + // MAC < v3980 Add size of MAC header to avdataoffset + else { + $getid3->info['avdataoffset'] += 8; + } + + // Convert md5sum to 32 byte string + if (@$info_monkeys_audio_raw['cFileMD5']) { + if ($info_monkeys_audio_raw['cFileMD5'] !== str_repeat("\x00", 16)) { + $getid3->info['md5_data_source'] = ''; + $md5 = $info_monkeys_audio_raw['cFileMD5']; + for ($i = 0; $i < strlen($md5); $i++) { + $getid3->info['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT); + } + if (!preg_match('/^[0-9a-f]{32}$/', $getid3->info['md5_data_source'])) { + unset($getid3->info['md5_data_source']); + } + } + } + + + return true; + } + + + + public static function MonkeyCompressionLevelNameLookup($compression_level) { + + static $lookup = array ( + 0 => 'unknown', + 1000 => 'fast', + 2000 => 'normal', + 3000 => 'high', + 4000 => 'extra-high', + 5000 => 'insane' + ); + return (isset($lookup[$compression_level]) ? $lookup[$compression_level] : 'invalid'); + } + + + + public static function MonkeySamplesPerFrame($version_id, $compression_level) { + + if ($version_id >= 3950) { + return 73728 * 4; + } + if (($version_id >= 3900) || (($version_id >= 3800) && ($compression_level == 4000))) { + return 73728; + } + return 9216; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.mp3.php b/plugins/getId3Plugin/lib/module.audio.mp3.php new file mode 100644 index 0000000..3d4573b --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.mp3.php @@ -0,0 +1,1710 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.mp3.php | +// | Module for analyzing MPEG Audio Layer 1,2,3 files. | +// | dependencies: none | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.mp3.php,v 1.5 2006/06/24 22:58:30 ah Exp $ + + + +class getid3_mp3 extends getid3_handler +{ + // Number of frames to scan to determine if MPEG-audio sequence is valid. + // Lower this number to 5-20 for faster scanning + // Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams + const VALID_CHECK_FRAMES = 35; + + + public function test() { + + static $hest = array (); + + $hest[] = 42; + + print '


    '; print_r($hest); + + + } + + + + public function Analyze() { + + $this->getAllMPEGInfo($this->getid3->fp, $this->getid3->info); + + return true; + } + + + public function AnalyzeMPEGaudioInfo() { + + $this->getOnlyMPEGaudioInfo($this->getid3->fp, $this->getid3->info, $this->getid3->info['avdataoffset'], false); + } + + + public function getAllMPEGInfo(&$fd, &$info) { + + $this->getOnlyMPEGaudioInfo($fd, $info, 0 + $info['avdataoffset']); + + if (isset($info['mpeg']['audio']['bitrate_mode'])) { + $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); + } + + if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0)))) { + + $synch_offset_warning = 'Unknown data before synch '; + if (isset($info['id3v2']['headerlength'])) { + $synch_offset_warning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, '; + } else { + $synch_offset_warning .= '(should be at beginning of file, '; + } + $synch_offset_warning .= 'synch detected at '.$info['avdataoffset'].')'; + if ($info['audio']['bitrate_mode'] == 'cbr') { + + if (!empty($info['id3v2']['headerlength']) && (($info['avdataoffset'] - $info['id3v2']['headerlength']) == $info['mpeg']['audio']['framelength'])) { + + $synch_offset_warning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.'; + $info['audio']['codec'] = 'LAME'; + $current_data_lame_version_string = 'LAME3.'; + + } elseif (empty($info['id3v2']['headerlength']) && ($info['avdataoffset'] == $info['mpeg']['audio']['framelength'])) { + + $synch_offset_warning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.'; + $info['audio']['codec'] = 'LAME'; + $current_data_lame_version_string = 'LAME3.'; + + } + + } + $this->getid3->warning($synch_offset_warning); + + } + + if (isset($info['mpeg']['audio']['LAME'])) { + $info['audio']['codec'] = 'LAME'; + if (!empty($info['mpeg']['audio']['LAME']['long_version'])) { + $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['long_version'], "\x00"); + } elseif (!empty($info['mpeg']['audio']['LAME']['short_version'])) { + $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['short_version'], "\x00"); + } + } + + $current_data_lame_version_string = (!empty($current_data_lame_version_string) ? $current_data_lame_version_string : @$info['audio']['encoder']); + if (!empty($current_data_lame_version_string) && (substr($current_data_lame_version_string, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($current_data_lame_version_string, -1))) { + // a version number of LAME that does not end with a number like "LAME3.92" + // or with a closing parenthesis like "LAME3.88 (alpha)" + // or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92) + + // not sure what the actual last frame length will be, but will be less than or equal to 1441 + $possibly_longer_lame_version_frame_length = 1441; + + // Not sure what version of LAME this is - look in padding of last frame for longer version string + $possible_lame_version_string_offset = $info['avdataend'] - $possibly_longer_lame_version_frame_length; + fseek($fd, $possible_lame_version_string_offset); + $possibly_longer_lame_version_data = fread($fd, $possibly_longer_lame_version_frame_length); + switch (substr($current_data_lame_version_string, -1)) { + case 'a': + case 'b': + // "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example + // need to trim off "a" to match longer string + $current_data_lame_version_string = substr($current_data_lame_version_string, 0, -1); + break; + } + if (($possibly_longer_lame_version_string = strstr($possibly_longer_lame_version_data, $current_data_lame_version_string)) !== false) { + if (substr($possibly_longer_lame_version_string, 0, strlen($current_data_lame_version_string)) == $current_data_lame_version_string) { + $possibly_longer_lame_version_new_string = substr($possibly_longer_lame_version_string, 0, strspn($possibly_longer_lame_version_string, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)" + if (strlen($possibly_longer_lame_version_new_string) > strlen(@$info['audio']['encoder'])) { + $info['audio']['encoder'] = $possibly_longer_lame_version_new_string; + } + } + } + } + if (!empty($info['audio']['encoder'])) { + $info['audio']['encoder'] = rtrim($info['audio']['encoder'], "\x00 "); + } + + switch (@$info['mpeg']['audio']['layer']) { + case 1: + case 2: + $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer']; + break; + } + if (@$info['fileformat'] == 'mp3') { + switch ($info['audio']['dataformat']) { + case 'mp1': + case 'mp2': + case 'mp3': + $info['fileformat'] = $info['audio']['dataformat']; + break; + + default: + $this->getid3->warning('Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"'); + break; + } + } + + $info['mime_type'] = 'audio/mpeg'; + $info['audio']['lossless'] = false; + + // Calculate playtime + if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) { + $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate']; + } + + $info['audio']['encoder_options'] = getid3_mp3::GuessEncoderOptions($info); + + return true; + } + + + + public static function GuessEncoderOptions(&$info) { + // shortcuts + if (!empty($info['mpeg']['audio'])) { + $thisfile_mpeg_audio = &$info['mpeg']['audio']; + if (!empty($thisfile_mpeg_audio['LAME'])) { + $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME']; + } + } + + $encoder_options = ''; + static $named_preset_bitrates = array (16, 24, 40, 56, 112, 128, 160, 192, 256); + + if ((@$thisfile_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($thisfile_mpeg_audio['VBR_quality'])) { + + $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality']; + + } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $named_preset_bitrates))) { + + $encoder_options = $thisfile_mpeg_audio_lame['preset_used']; + + } elseif (!empty($thisfile_mpeg_audio_lame['vbr_quality'])) { + + static $known_encoder_values = array (); + if (empty($known_encoder_values)) { + + //$known_encoder_values[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name'; + $known_encoder_values[0xFF][58][1][1][3][2][20500] = '--alt-preset insane'; // 3.90, 3.90.1, 3.92 + $known_encoder_values[0xFF][58][1][1][3][2][20600] = '--alt-preset insane'; // 3.90.2, 3.90.3, 3.91 + $known_encoder_values[0xFF][57][1][1][3][4][20500] = '--alt-preset insane'; // 3.94, 3.95 + $known_encoder_values['**'][78][3][2][3][2][19500] = '--alt-preset extreme'; // 3.90, 3.90.1, 3.92 + $known_encoder_values['**'][78][3][2][3][2][19600] = '--alt-preset extreme'; // 3.90.2, 3.91 + $known_encoder_values['**'][78][3][1][3][2][19600] = '--alt-preset extreme'; // 3.90.3 + $known_encoder_values['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme'; // 3.90, 3.90.1, 3.92 + $known_encoder_values['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme'; // 3.90.2, 3.90.3, 3.91 + $known_encoder_values['**'][78][3][2][3][4][19000] = '--alt-preset standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $known_encoder_values['**'][78][3][1][3][4][19000] = '--alt-preset standard'; // 3.90.3 + $known_encoder_values['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $known_encoder_values['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3 + $known_encoder_values['**'][88][4][1][3][3][19500] = '--r3mix'; // 3.90, 3.90.1, 3.92 + $known_encoder_values['**'][88][4][1][3][3][19600] = '--r3mix'; // 3.90.2, 3.90.3, 3.91 + $known_encoder_values['**'][67][4][1][3][4][18000] = '--r3mix'; // 3.94, 3.95 + $known_encoder_values['**'][68][3][2][3][4][18000] = '--alt-preset medium'; // 3.90.3 + $known_encoder_values['**'][68][4][2][3][4][18000] = '--alt-preset fast medium'; // 3.90.3 + + $known_encoder_values[0xFF][99][1][1][1][2][0] = '--preset studio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $known_encoder_values[0xFF][58][2][1][3][2][20600] = '--preset studio'; // 3.90.3, 3.93.1 + $known_encoder_values[0xFF][58][2][1][3][2][20500] = '--preset studio'; // 3.93 + $known_encoder_values[0xFF][57][2][1][3][4][20500] = '--preset studio'; // 3.94, 3.95 + $known_encoder_values[0xC0][88][1][1][1][2][0] = '--preset cd'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $known_encoder_values[0xC0][58][2][2][3][2][19600] = '--preset cd'; // 3.90.3, 3.93.1 + $known_encoder_values[0xC0][58][2][2][3][2][19500] = '--preset cd'; // 3.93 + $known_encoder_values[0xC0][57][2][1][3][4][19500] = '--preset cd'; // 3.94, 3.95 + $known_encoder_values[0xA0][78][1][1][3][2][18000] = '--preset hifi'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $known_encoder_values[0xA0][58][2][2][3][2][18000] = '--preset hifi'; // 3.90.3, 3.93, 3.93.1 + $known_encoder_values[0xA0][57][2][1][3][4][18000] = '--preset hifi'; // 3.94, 3.95 + $known_encoder_values[0x80][67][1][1][3][2][18000] = '--preset tape'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $known_encoder_values[0x80][67][1][1][3][2][15000] = '--preset radio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $known_encoder_values[0x70][67][1][1][3][2][15000] = '--preset fm'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $known_encoder_values[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm'; // 3.90.3, 3.93, 3.93.1 + $known_encoder_values[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm'; // 3.94, 3.95 + $known_encoder_values[0x38][58][2][2][0][2][10000] = '--preset voice'; // 3.90.3, 3.93, 3.93.1 + $known_encoder_values[0x38][57][2][1][0][4][15000] = '--preset voice'; // 3.94, 3.95 + $known_encoder_values[0x38][57][2][1][0][4][16000] = '--preset voice'; // 3.94a14 + $known_encoder_values[0x28][65][1][1][0][2][7500] = '--preset mw-us'; // 3.90, 3.90.1, 3.92 + $known_encoder_values[0x28][65][1][1][0][2][7600] = '--preset mw-us'; // 3.90.2, 3.91 + $known_encoder_values[0x28][58][2][2][0][2][7000] = '--preset mw-us'; // 3.90.3, 3.93, 3.93.1 + $known_encoder_values[0x28][57][2][1][0][4][10500] = '--preset mw-us'; // 3.94, 3.95 + $known_encoder_values[0x28][57][2][1][0][4][11200] = '--preset mw-us'; // 3.94a14 + $known_encoder_values[0x28][57][2][1][0][4][8800] = '--preset mw-us'; // 3.94a15 + $known_encoder_values[0x18][58][2][2][0][2][4000] = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1 + $known_encoder_values[0x18][58][2][2][0][2][3900] = '--preset phon+/lw/mw-eu/sw'; // 3.93 + $known_encoder_values[0x18][57][2][1][0][4][5900] = '--preset phon+/lw/mw-eu/sw'; // 3.94, 3.95 + $known_encoder_values[0x18][57][2][1][0][4][6200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a14 + $known_encoder_values[0x18][57][2][1][0][4][3200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a15 + $known_encoder_values[0x10][58][2][2][0][2][3800] = '--preset phone'; // 3.90.3, 3.93.1 + $known_encoder_values[0x10][58][2][2][0][2][3700] = '--preset phone'; // 3.93 + $known_encoder_values[0x10][57][2][1][0][4][5600] = '--preset phone'; // 3.94, 3.95 + } + + if (isset($known_encoder_values[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) { + + $encoder_options = $known_encoder_values[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']]; + + } elseif (isset($known_encoder_values['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) { + + $encoder_options = $known_encoder_values['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']]; + + } elseif ($info['audio']['bitrate_mode'] == 'vbr') { + + // http://gabriel.mp3-tech.org/mp3infotag.html + // int Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h + + + $lame_v_value = 10 - ceil($thisfile_mpeg_audio_lame['vbr_quality'] / 10); + $lame_q_value = 100 - $thisfile_mpeg_audio_lame['vbr_quality'] - ($lame_v_value * 10); + $encoder_options = '-V'.$lame_v_value.' -q'.$lame_q_value; + + } elseif ($info['audio']['bitrate_mode'] == 'cbr') { + + $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); + + } else { + + $encoder_options = strtoupper($info['audio']['bitrate_mode']); + + } + + } elseif (!empty($thisfile_mpeg_audio_lame['bitrate_abr'])) { + + $encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr']; + + } elseif (!empty($info['audio']['bitrate'])) { + + if ($info['audio']['bitrate_mode'] == 'cbr') { + $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); + } else { + $encoder_options = strtoupper($info['audio']['bitrate_mode']); + } + + } + if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) { + $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min']; + } + + if (@$thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] || @$thisfile_mpeg_audio_lame['encoding_flags']['nogap_next']) { + $encoder_options .= ' --nogap'; + } + + if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) { + $exploded_options = explode(' ', $encoder_options, 4); + if ($exploded_options[0] == '--r3mix') { + $exploded_options[1] = 'r3mix'; + } + switch ($exploded_options[0]) { + case '--preset': + case '--alt-preset': + case '--r3mix': + if ($exploded_options[1] == 'fast') { + $exploded_options[1] .= ' '.$exploded_options[2]; + } + switch ($exploded_options[1]) { + case 'portable': + case 'medium': + case 'standard': + case 'extreme': + case 'insane': + case 'fast portable': + case 'fast medium': + case 'fast standard': + case 'fast extreme': + case 'fast insane': + case 'r3mix': + static $expected_lowpass = array ( + 'insane|20500' => 20500, + 'insane|20600' => 20600, // 3.90.2, 3.90.3, 3.91 + 'medium|18000' => 18000, + 'fast medium|18000' => 18000, + 'extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95 + 'extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1 + 'fast extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95 + 'fast extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1 + 'standard|19000' => 19000, + 'fast standard|19000' => 19000, + 'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92 + 'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91 + 'r3mix|18000' => 18000, // 3.94, 3.95 + ); + if (!isset($expected_lowpass[$exploded_options[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) { + $encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency']; + } + break; + + default: + break; + } + break; + } + } + + if (isset($thisfile_mpeg_audio_lame['raw']['source_sample_freq'])) { + if (($thisfile_mpeg_audio['sample_rate'] == 44100) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) { + $encoder_options .= ' --resample 44100'; + } elseif (($thisfile_mpeg_audio['sample_rate'] == 48000) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) { + $encoder_options .= ' --resample 48000'; + } elseif ($thisfile_mpeg_audio['sample_rate'] < 44100) { + switch ($thisfile_mpeg_audio_lame['raw']['source_sample_freq']) { + case 0: // <= 32000 + // may or may not be same as source frequency - ignore + break; + case 1: // 44100 + case 2: // 48000 + case 3: // 48000+ + $exploded_options = explode(' ', $encoder_options, 4); + switch ($exploded_options[0]) { + case '--preset': + case '--alt-preset': + switch ($exploded_options[1]) { + case 'fast': + case 'portable': + case 'medium': + case 'standard': + case 'extreme': + case 'insane': + $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; + break; + + default: + static $expected_resampled_rate = array ( + 'phon+/lw/mw-eu/sw|16000' => 16000, + 'mw-us|24000' => 24000, // 3.95 + 'mw-us|32000' => 32000, // 3.93 + 'mw-us|16000' => 16000, // 3.92 + 'phone|16000' => 16000, + 'phone|11025' => 11025, // 3.94a15 + 'radio|32000' => 32000, // 3.94a15 + 'fm/radio|32000' => 32000, // 3.92 + 'fm|32000' => 32000, // 3.90 + 'voice|32000' => 32000); + if (!isset($expected_resampled_rate[$exploded_options[1].'|'.$thisfile_mpeg_audio['sample_rate']])) { + $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; + } + break; + } + break; + + case '--r3mix': + default: + $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; + break; + } + break; + } + } + } + if (empty($encoder_options) && !empty($info['audio']['bitrate']) && !empty($info['audio']['bitrate_mode'])) { + //$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); + $encoder_options = strtoupper($info['audio']['bitrate_mode']); + } + + return $encoder_options; + } + + + + public function decodeMPEGaudioHeader($fd, $offset, &$info, $recursive_search=true, $scan_as_cbr=false, $fast_mpeg_header_scan=false) { + + static $mpeg_audio_version_lookup; + static $mpeg_audio_layer_lookup; + static $mpeg_audio_bitrate_lookup; + static $mpeg_audio_frequency_lookup; + static $mpeg_audio_channel_mode_lookup; + static $mpeg_audio_mode_extension_lookup; + static $mpeg_audio_emphasis_lookup; + if (empty($mpeg_audio_version_lookup)) { + $mpeg_audio_version_lookup = getid3_mp3::MPEGaudioVersionarray(); + $mpeg_audio_layer_lookup = getid3_mp3::MPEGaudioLayerarray(); + $mpeg_audio_bitrate_lookup = getid3_mp3::MPEGaudioBitratearray(); + $mpeg_audio_frequency_lookup = getid3_mp3::MPEGaudioFrequencyarray(); + $mpeg_audio_channel_mode_lookup = getid3_mp3::MPEGaudioChannelModearray(); + $mpeg_audio_mode_extension_lookup = getid3_mp3::MPEGaudioModeExtensionarray(); + $mpeg_audio_emphasis_lookup = getid3_mp3::MPEGaudioEmphasisarray(); + } + + if ($offset >= $info['avdataend']) { + + // non-fatal error: 'end of file encounter looking for MPEG synch' + return; + + } + fseek($fd, $offset, SEEK_SET); + $header_string = fread($fd, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data + + // MP3 audio frame structure: + // $aa $aa $aa $aa [$bb $bb] $cc... + // where $aa..$aa is the four-byte mpeg-audio header (below) + // $bb $bb is the optional 2-byte CRC + // and $cc... is the audio data + + $head4 = substr($header_string, 0, 4); + + if (isset($mpeg_audio_header_decode_cache[$head4])) { + $mpeg_header_raw_array= $mpeg_audio_header_decode_cache[$head4]; + } else { + $mpeg_header_raw_array = getid3_mp3::MPEGaudioHeaderDecode($head4); + $mpeg_audio_header_decode_cache[$head4] = $mpeg_header_raw_array; + } + + // Not in cache + if (!isset($mpeg_audio_header_valid_cache[$head4])) { + $mpeg_audio_header_valid_cache[$head4] = getid3_mp3::MPEGaudioHeaderValid($mpeg_header_raw_array, false, false); + } + + // shortcut + if (!isset($info['mpeg']['audio'])) { + $info['mpeg']['audio'] = array (); + } + $thisfile_mpeg_audio = &$info['mpeg']['audio']; + + + if ($mpeg_audio_header_valid_cache[$head4]) { + $thisfile_mpeg_audio['raw'] = $mpeg_header_raw_array; + } else { + + // non-fatal error: Invalid MPEG audio header at offset $offset + return; + } + + if (!$fast_mpeg_header_scan) { + + $thisfile_mpeg_audio['version'] = $mpeg_audio_version_lookup[$thisfile_mpeg_audio['raw']['version']]; + $thisfile_mpeg_audio['layer'] = $mpeg_audio_layer_lookup[$thisfile_mpeg_audio['raw']['layer']]; + + $thisfile_mpeg_audio['channelmode'] = $mpeg_audio_channel_mode_lookup[$thisfile_mpeg_audio['raw']['channelmode']]; + $thisfile_mpeg_audio['channels'] = (($thisfile_mpeg_audio['channelmode'] == 'mono') ? 1 : 2); + $thisfile_mpeg_audio['sample_rate'] = $mpeg_audio_frequency_lookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['raw']['sample_rate']]; + $thisfile_mpeg_audio['protection'] = !$thisfile_mpeg_audio['raw']['protection']; + $thisfile_mpeg_audio['private'] = (bool) $thisfile_mpeg_audio['raw']['private']; + $thisfile_mpeg_audio['modeextension'] = $mpeg_audio_mode_extension_lookup[$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['modeextension']]; + $thisfile_mpeg_audio['copyright'] = (bool) $thisfile_mpeg_audio['raw']['copyright']; + $thisfile_mpeg_audio['original'] = (bool) $thisfile_mpeg_audio['raw']['original']; + $thisfile_mpeg_audio['emphasis'] = $mpeg_audio_emphasis_lookup[$thisfile_mpeg_audio['raw']['emphasis']]; + + $info['audio']['channels'] = $thisfile_mpeg_audio['channels']; + $info['audio']['sample_rate'] = $thisfile_mpeg_audio['sample_rate']; + + if ($thisfile_mpeg_audio['protection']) { + $thisfile_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($header_string, 4, 2)); + } + + } + + if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) { + // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0 + $this->getid3->warning('Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1'); + $thisfile_mpeg_audio['raw']['bitrate'] = 0; + } + $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding']; + $thisfile_mpeg_audio['bitrate'] = $mpeg_audio_bitrate_lookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['bitrate']]; + + if (($thisfile_mpeg_audio['bitrate'] == 'free') && ($offset == $info['avdataoffset'])) { + // only skip multiple frame check if free-format bitstream found at beginning of file + // otherwise is quite possibly simply corrupted data + $recursive_search = false; + } + + // For Layer 2 there are some combinations of bitrate and mode which are not allowed. + if (!$fast_mpeg_header_scan && ($thisfile_mpeg_audio['layer'] == '2')) { + + $info['audio']['dataformat'] = 'mp2'; + switch ($thisfile_mpeg_audio['channelmode']) { + + case 'mono': + if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) { + // these are ok + } else { + + // non-fatal error: bitrate not allowed in Layer 2/mono + return; + } + break; + + case 'stereo': + case 'joint stereo': + case 'dual channel': + if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) { + // these are ok + } else { + + // non-fatal error: bitrate not allowed in Layer 2/stereo/joint stereo/dual channel + return; + } + break; + + } + + } + + + if ($info['audio']['sample_rate'] > 0) { + $thisfile_mpeg_audio['framelength'] = getid3_mp3::MPEGaudioFrameLength($thisfile_mpeg_audio['bitrate'], $thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['layer'], (int) $thisfile_mpeg_audio['padding'], $info['audio']['sample_rate']); + } + + $next_frame_test_offset = $offset + 1; + if ($thisfile_mpeg_audio['bitrate'] != 'free') { + + $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; + + if (isset($thisfile_mpeg_audio['framelength'])) { + $next_frame_test_offset = $offset + $thisfile_mpeg_audio['framelength']; + } else { + + // non-fatal error: Frame at offset('.$offset.') is has an invalid frame length. + return; + } + + } + + $expected_number_of_audio_bytes = 0; + + //////////////////////////////////////////////////////////////////////////////////// + // Variable-bitrate headers + + if (substr($header_string, 4 + 32, 4) == 'VBRI') { + // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36) + // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html + + $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; + $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer'; + $info['audio']['codec'] = 'Fraunhofer'; + + $side_info_data = substr($header_string, 4 + 2, 32); + + $fraunhofer_vbr_offset = 36; + + $thisfile_mpeg_audio['VBR_encoder_version'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 4, 2)); // VbriVersion + $thisfile_mpeg_audio['VBR_encoder_delay'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 6, 2)); // VbriDelay + $thisfile_mpeg_audio['VBR_quality'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 8, 2)); // VbriQuality + $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 10, 4)); // VbriStreamBytes + $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 14, 4)); // VbriStreamFrames + $thisfile_mpeg_audio['VBR_seek_offsets'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 18, 2)); // VbriTableSize + $thisfile_mpeg_audio['VBR_seek_scale'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 20, 2)); // VbriTableScale + $thisfile_mpeg_audio['VBR_entry_bytes'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 22, 2)); // VbriEntryBytes + $thisfile_mpeg_audio['VBR_entry_frames'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 24, 2)); // VbriEntryFrames + + $expected_number_of_audio_bytes = $thisfile_mpeg_audio['VBR_bytes']; + + $previous_byte_offset = $offset; + for ($i = 0; $i < $thisfile_mpeg_audio['VBR_seek_offsets']; $i++) { + $fraunhofer_offset_n = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset, $thisfile_mpeg_audio['VBR_entry_bytes'])); + $fraunhofer_vbr_offset += $thisfile_mpeg_audio['VBR_entry_bytes']; + $thisfile_mpeg_audio['VBR_offsets_relative'][$i] = ($fraunhofer_offset_n * $thisfile_mpeg_audio['VBR_seek_scale']); + $thisfile_mpeg_audio['VBR_offsets_absolute'][$i] = ($fraunhofer_offset_n * $thisfile_mpeg_audio['VBR_seek_scale']) + $previous_byte_offset; + $previous_byte_offset += $fraunhofer_offset_n; + } + + + } else { + + // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36) + // depending on MPEG layer and number of channels + + $vbr_id_offset = getid3_mp3::XingVBRidOffset($thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['channelmode']); + $side_info_data = substr($header_string, 4 + 2, $vbr_id_offset - 4); + + if ((substr($header_string, $vbr_id_offset, strlen('Xing')) == 'Xing') || (substr($header_string, $vbr_id_offset, strlen('Info')) == 'Info')) { + // 'Xing' is traditional Xing VBR frame + // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.) + // 'Info' *can* legally be used to specify a VBR file as well, however. + + // http://www.multiweb.cz/twoinches/MP3inside.htm + //00..03 = "Xing" or "Info" + //04..07 = Flags: + // 0x01 Frames Flag set if value for number of frames in file is stored + // 0x02 Bytes Flag set if value for filesize in bytes is stored + // 0x04 TOC Flag set if values for TOC are stored + // 0x08 VBR Scale Flag set if values for VBR scale is stored + //08..11 Frames: Number of frames in file (including the first Xing/Info one) + //12..15 Bytes: File length in Bytes + //16..115 TOC (Table of Contents): + // Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file. + // Each Byte has a value according this formula: + // (TOC[i] / 256) * fileLenInBytes + // So if song lasts eg. 240 sec. and you want to jump to 60. sec. (and file is 5 000 000 Bytes length) you can use: + // TOC[(60/240)*100] = TOC[25] + // and corresponding Byte in file is then approximately at: + // (TOC[25]/256) * 5000000 + //116..119 VBR Scale + + + // should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME + $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; + $thisfile_mpeg_audio['VBR_method'] = 'Xing'; + + $thisfile_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($header_string, $vbr_id_offset + 4, 4)); + + $thisfile_mpeg_audio['xing_flags']['frames'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000001); + $thisfile_mpeg_audio['xing_flags']['bytes'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000002); + $thisfile_mpeg_audio['xing_flags']['toc'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000004); + $thisfile_mpeg_audio['xing_flags']['vbr_scale'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000008); + + if ($thisfile_mpeg_audio['xing_flags']['frames']) { + $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($header_string, $vbr_id_offset + 8, 4)); + } + if ($thisfile_mpeg_audio['xing_flags']['bytes']) { + $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($header_string, $vbr_id_offset + 12, 4)); + } + + if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { + + $frame_lengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']; + + if ($thisfile_mpeg_audio['layer'] == '1') { + // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12 + $info['audio']['bitrate'] = ($frame_lengthfloat / 4) * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 12; + } else { + // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144 + $info['audio']['bitrate'] = $frame_lengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144; + } + $thisfile_mpeg_audio['framelength'] = floor($frame_lengthfloat); + } + + if ($thisfile_mpeg_audio['xing_flags']['toc']) { + $lame_toc_data = substr($header_string, $vbr_id_offset + 16, 100); + for ($i = 0; $i < 100; $i++) { + $thisfile_mpeg_audio['toc'][$i] = ord($lame_toc_data{$i}); + } + } + if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) { + $thisfile_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($header_string, $vbr_id_offset + 116, 4)); + } + + + // http://gabriel.mp3-tech.org/mp3infotag.html + if (substr($header_string, $vbr_id_offset + 120, 4) == 'LAME') { + + // shortcut + $thisfile_mpeg_audio['LAME'] = array (); + $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME']; + + + $thisfile_mpeg_audio_lame['long_version'] = substr($header_string, $vbr_id_offset + 120, 20); + $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9); + + if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') { + + // extra 11 chars are not part of version string when LAMEtag present + unset($thisfile_mpeg_audio_lame['long_version']); + + // It the LAME tag was only introduced in LAME v3.90 + // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933 + + // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html + // are assuming a 'Xing' identifier offset of 0x24, which is the case for + // MPEG-1 non-mono, but not for other combinations + $lame_tag_offset_contant = $vbr_id_offset - 0x24; + + // shortcuts + $thisfile_mpeg_audio_lame['RGAD'] = array ('track'=>array(), 'album'=>array()); + $thisfile_mpeg_audio_lame_rgad = &$thisfile_mpeg_audio_lame['RGAD']; + $thisfile_mpeg_audio_lame_rgad_track = &$thisfile_mpeg_audio_lame_rgad['track']; + $thisfile_mpeg_audio_lame_rgad_album = &$thisfile_mpeg_audio_lame_rgad['album']; + $thisfile_mpeg_audio_lame['raw'] = array (); + $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw']; + + // byte $9B VBR Quality + // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications. + // Actually overwrites original Xing bytes + unset($thisfile_mpeg_audio['VBR_scale']); + $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0x9B, 1)); + + // bytes $9C-$A4 Encoder short VersionString + $thisfile_mpeg_audio_lame['short_version'] = substr($header_string, $lame_tag_offset_contant + 0x9C, 9); + + // byte $A5 Info Tag revision + VBR method + $lame_tagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xA5, 1)); + + $thisfile_mpeg_audio_lame['tag_revision'] = ($lame_tagRevisionVBRmethod & 0xF0) >> 4; + $thisfile_mpeg_audio_lame_raw['vbr_method'] = $lame_tagRevisionVBRmethod & 0x0F; + $thisfile_mpeg_audio_lame['vbr_method'] = getid3_mp3::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']); + $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr' + + // byte $A6 Lowpass filter value + $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xA6, 1)) * 100; + + // bytes $A7-$AE Replay Gain + // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html + // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude" + if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') { + // LAME 3.94a16 and later - 9.23 fixed point + // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375 + $thisfile_mpeg_audio_lame_rgad['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xA7, 4))) / 8388608); + } else { + // LAME 3.94a15 and earlier - 32-bit floating point + // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15 + $thisfile_mpeg_audio_lame_rgad['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($header_string, $lame_tag_offset_contant + 0xA7, 4)); + } + if ($thisfile_mpeg_audio_lame_rgad['peak_amplitude'] == 0) { + unset($thisfile_mpeg_audio_lame_rgad['peak_amplitude']); + } else { + $thisfile_mpeg_audio_lame_rgad['peak_db'] = 20 * log10($thisfile_mpeg_audio_lame_rgad['peak_amplitude']); + } + + $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xAB, 2)); + $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xAD, 2)); + + + if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) { + + $thisfile_mpeg_audio_lame_rgad_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13; + $thisfile_mpeg_audio_lame_rgad_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10; + $thisfile_mpeg_audio_lame_rgad_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9; + $thisfile_mpeg_audio_lame_rgad_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF; + $thisfile_mpeg_audio_lame_rgad_track['name'] = getid3_lib_replaygain::NameLookup($thisfile_mpeg_audio_lame_rgad_track['raw']['name']); + $thisfile_mpeg_audio_lame_rgad_track['originator'] = getid3_lib_replaygain::OriginatorLookup($thisfile_mpeg_audio_lame_rgad_track['raw']['originator']); + $thisfile_mpeg_audio_lame_rgad_track['gain_db'] = getid3_lib_replaygain::AdjustmentLookup($thisfile_mpeg_audio_lame_rgad_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_rgad_track['raw']['sign_bit']); + + if (!empty($thisfile_mpeg_audio_lame_rgad['peak_amplitude'])) { + $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_rgad['peak_amplitude']; + } + $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_rgad_track['originator']; + $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_rgad_track['gain_db']; + } else { + unset($thisfile_mpeg_audio_lame_rgad['track']); + } + if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) { + + $thisfile_mpeg_audio_lame_rgad_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13; + $thisfile_mpeg_audio_lame_rgad_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10; + $thisfile_mpeg_audio_lame_rgad_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9; + $thisfile_mpeg_audio_lame_rgad_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF; + $thisfile_mpeg_audio_lame_rgad_album['name'] = getid3_lib_replaygain::NameLookup($thisfile_mpeg_audio_lame_rgad_album['raw']['name']); + $thisfile_mpeg_audio_lame_rgad_album['originator'] = getid3_lib_replaygain::OriginatorLookup($thisfile_mpeg_audio_lame_rgad_album['raw']['originator']); + $thisfile_mpeg_audio_lame_rgad_album['gain_db'] = getid3_lib_replaygain::AdjustmentLookup($thisfile_mpeg_audio_lame_rgad_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_rgad_album['raw']['sign_bit']); + + if (!empty($thisfile_mpeg_audio_lame_rgad['peak_amplitude'])) { + $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_rgad['peak_amplitude']; + } + $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_rgad_album['originator']; + $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_rgad_album['gain_db']; + } else { + unset($thisfile_mpeg_audio_lame_rgad['album']); + } + if (empty($thisfile_mpeg_audio_lame_rgad)) { + unset($thisfile_mpeg_audio_lame['RGAD']); + } + + + // byte $AF Encoding flags + ATH Type + $encoding_flags_ath_type = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xAF, 1)); + $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($encoding_flags_ath_type & 0x10); + $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($encoding_flags_ath_type & 0x20); + $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($encoding_flags_ath_type & 0x40); + $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($encoding_flags_ath_type & 0x80); + $thisfile_mpeg_audio_lame['ath_type'] = $encoding_flags_ath_type & 0x0F; + + // byte $B0 if ABR {specified bitrate} else {minimal bitrate} + $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB0, 1)); + if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR) + $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']; + } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR) + // ignore + } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate + $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']; + } + + // bytes $B1-$B3 Encoder delays + $encoder_delays = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB1, 3)); + $thisfile_mpeg_audio_lame['encoder_delay'] = ($encoder_delays & 0xFFF000) >> 12; + $thisfile_mpeg_audio_lame['end_padding'] = $encoder_delays & 0x000FFF; + + // byte $B4 Misc + $misc_byte = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB4, 1)); + $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($misc_byte & 0x03); + $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($misc_byte & 0x1C) >> 2; + $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($misc_byte & 0x20) >> 5; + $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($misc_byte & 0xC0) >> 6; + $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping']; + $thisfile_mpeg_audio_lame['stereo_mode'] = getid3_mp3::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']); + $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality']; + $thisfile_mpeg_audio_lame['source_sample_freq'] = getid3_mp3::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']); + + // byte $B5 MP3 Gain + $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB5, 1), false, true); + $thisfile_mpeg_audio_lame['mp3_gain_db'] = (20 * log10(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain']; + $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6)); + + // bytes $B6-$B7 Preset and surround info + $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB6, 2)); + // Reserved = ($PresetSurroundBytes & 0xC000); + $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800); + $thisfile_mpeg_audio_lame['surround_info'] = getid3_mp3::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']); + $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF); + $thisfile_mpeg_audio_lame['preset_used'] = getid3_mp3::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame); + if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) { + $this->getid3->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org'); + } + if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) { + // this may change if 3.90.4 ever comes out + $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3'; + } + + // bytes $B8-$BB MusicLength + $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB8, 4)); + $expected_number_of_audio_bytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']); + + // bytes $BC-$BD MusicCRC + $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xBC, 2)); + + // bytes $BE-$BF CRC-16 of Info Tag + $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xBE, 2)); + + + // LAME CBR + if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { + + $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; + $thisfile_mpeg_audio['bitrate'] = getid3_mp3::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']); + $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; + + } + + } + } + + } else { + + // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header) + $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; + if ($recursive_search) { + $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; + if (getid3_mp3::RecursiveFrameScanning($fd, $info, $offset, $next_frame_test_offset, true)) { + $recursive_search = false; + $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; + } + if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') { + $this->getid3->warning('VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.'); + } + } + + } + + } + + if (($expected_number_of_audio_bytes > 0) && ($expected_number_of_audio_bytes != ($info['avdataend'] - $info['avdataoffset']))) { + if ($expected_number_of_audio_bytes > ($info['avdataend'] - $info['avdataoffset'])) { + if (($expected_number_of_audio_bytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) { + $this->getid3->warning('Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)'); + } else { + $this->getid3->warning('Probable truncated file: expecting '.$expected_number_of_audio_bytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($expected_number_of_audio_bytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)'); + } + } else { + if ((($info['avdataend'] - $info['avdataoffset']) - $expected_number_of_audio_bytes) == 1) { + $info['avdataend']--; + } else { + $this->getid3->warning('Too much data in file: expecting '.$expected_number_of_audio_bytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $expected_number_of_audio_bytes).' bytes too many)'); + } + } + } + + if (($thisfile_mpeg_audio['bitrate'] == 'free') && empty($info['audio']['bitrate'])) { + if (($offset == $info['avdataoffset']) && empty($thisfile_mpeg_audio['VBR_frames'])) { + $frame_byte_length = getid3_mp3::FreeFormatFrameLength($fd, $offset, $info, true); + if ($frame_byte_length > 0) { + $thisfile_mpeg_audio['framelength'] = $frame_byte_length; + if ($thisfile_mpeg_audio['layer'] == '1') { + // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12 + $info['audio']['bitrate'] = ((($frame_byte_length / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12; + } else { + // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144 + $info['audio']['bitrate'] = (($frame_byte_length - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144; + } + } else { + + // non-fatal error: Error calculating frame length of free-format MP3 without Xing/LAME header. + return; + } + } + } + + if (!empty($thisfile_mpeg_audio['VBR_frames'])) { + switch ($thisfile_mpeg_audio['bitrate_mode']) { + case 'vbr': + case 'abr': + if (($thisfile_mpeg_audio['version'] == '1') && ($thisfile_mpeg_audio['layer'] == 1)) { + $thisfile_mpeg_audio['VBR_bitrate'] = (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / 384); + } elseif ((($thisfile_mpeg_audio['version'] == '2') || ($thisfile_mpeg_audio['version'] == '2.5')) && ($thisfile_mpeg_audio['layer'] == 3)) { + $thisfile_mpeg_audio['VBR_bitrate'] = (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / 576); + } else { + $thisfile_mpeg_audio['VBR_bitrate'] = (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / 1152); + } + if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) { + $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; + $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion + } + break; + } + } + + // End variable-bitrate headers + //////////////////////////////////////////////////////////////////////////////////// + + if ($recursive_search) { + + if (!getid3_mp3::RecursiveFrameScanning($fd, $info, $offset, $next_frame_test_offset, $scan_as_cbr)) { + return false; + } + + } + + return true; + } + + + + public function RecursiveFrameScanning(&$fd, &$info, &$offset, &$next_frame_test_offset, $scan_as_cbr) { + for ($i = 0; $i < getid3_mp3::VALID_CHECK_FRAMES; $i++) { + // check next getid3_mp3::VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch + if (($next_frame_test_offset + 4) >= $info['avdataend']) { + // end of file + return true; + } + + $next_frame_test_array = array ('avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']); + if ($this->decodeMPEGaudioHeader($fd, $next_frame_test_offset, $next_frame_test_array, false)) { + if ($scan_as_cbr) { + // force CBR mode, used for trying to pick out invalid audio streams with + // valid(?) VBR headers, or VBR streams with no VBR header + if (!isset($next_frame_test_array['mpeg']['audio']['bitrate']) || !isset($info['mpeg']['audio']['bitrate']) || ($next_frame_test_array['mpeg']['audio']['bitrate'] != $info['mpeg']['audio']['bitrate'])) { + return false; + } + } + + + // next frame is OK, get ready to check the one after that + if (isset($next_frame_test_array['mpeg']['audio']['framelength']) && ($next_frame_test_array['mpeg']['audio']['framelength'] > 0)) { + $next_frame_test_offset += $next_frame_test_array['mpeg']['audio']['framelength']; + } else { + + // non-fatal error: Frame at offset $offset has an invalid frame length. + return; + } + + } else { + + // non-fatal error: Next frame is not valid. + return; + } + } + return true; + } + + + + public function FreeFormatFrameLength($fd, $offset, &$info, $deep_scan=false) { + fseek($fd, $offset, SEEK_SET); + $mpeg_audio_data = fread($fd, 32768); + + $sync_pattern1 = substr($mpeg_audio_data, 0, 4); + // may be different pattern due to padding + $sync_pattern2 = $sync_pattern1{0}.$sync_pattern1{1}.chr(ord($sync_pattern1{2}) | 0x02).$sync_pattern1{3}; + if ($sync_pattern2 === $sync_pattern1) { + $sync_pattern2 = $sync_pattern1{0}.$sync_pattern1{1}.chr(ord($sync_pattern1{2}) & 0xFD).$sync_pattern1{3}; + } + + $frame_length = false; + $frame_length1 = strpos($mpeg_audio_data, $sync_pattern1, 4); + $frame_length2 = strpos($mpeg_audio_data, $sync_pattern2, 4); + if ($frame_length1 > 4) { + $frame_length = $frame_length1; + } + if (($frame_length2 > 4) && ($frame_length2 < $frame_length1)) { + $frame_length = $frame_length2; + } + if (!$frame_length) { + + // LAME 3.88 has a different value for modeextension on the first frame vs the rest + $frame_length1 = strpos($mpeg_audio_data, substr($sync_pattern1, 0, 3), 4); + $frame_length2 = strpos($mpeg_audio_data, substr($sync_pattern2, 0, 3), 4); + + if ($frame_length1 > 4) { + $frame_length = $frame_length1; + } + if (($frame_length2 > 4) && ($frame_length2 < $frame_length1)) { + $frame_length = $frame_length2; + } + if (!$frame_length) { + throw new getid3_exception('Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($sync_pattern1).' or '.getid3_lib::PrintHexBytes($sync_pattern2).') after offset '.$offset); + } else { + $this->getid3->warning('ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)'); + $info['audio']['codec'] = 'LAME'; + $info['audio']['encoder'] = 'LAME3.88'; + $sync_pattern1 = substr($sync_pattern1, 0, 3); + $sync_pattern2 = substr($sync_pattern2, 0, 3); + } + } + + if ($deep_scan) { + + $actual_frame_length_values = array (); + $next_offset = $offset + $frame_length; + while ($next_offset < ($info['avdataend'] - 6)) { + fseek($fd, $next_offset - 1, SEEK_SET); + $NextSyncPattern = fread($fd, 6); + if ((substr($NextSyncPattern, 1, strlen($sync_pattern1)) == $sync_pattern1) || (substr($NextSyncPattern, 1, strlen($sync_pattern2)) == $sync_pattern2)) { + // good - found where expected + $actual_frame_length_values[] = $frame_length; + } elseif ((substr($NextSyncPattern, 0, strlen($sync_pattern1)) == $sync_pattern1) || (substr($NextSyncPattern, 0, strlen($sync_pattern2)) == $sync_pattern2)) { + // ok - found one byte earlier than expected (last frame wasn't padded, first frame was) + $actual_frame_length_values[] = ($frame_length - 1); + $next_offset--; + } elseif ((substr($NextSyncPattern, 2, strlen($sync_pattern1)) == $sync_pattern1) || (substr($NextSyncPattern, 2, strlen($sync_pattern2)) == $sync_pattern2)) { + // ok - found one byte later than expected (last frame was padded, first frame wasn't) + $actual_frame_length_values[] = ($frame_length + 1); + $next_offset++; + } else { + throw new getid3_exception('Did not find expected free-format sync pattern at offset '.$next_offset); + } + $next_offset += $frame_length; + } + if (count($actual_frame_length_values) > 0) { + $frame_length = intval(round(array_sum($actual_frame_length_values) / count($actual_frame_length_values))); + } + } + return $frame_length; + } + + + + public function getOnlyMPEGaudioInfo($fd, &$info, $avdata_offset, $bit_rate_histogram=false) { + // looks for synch, decodes MPEG audio header + + fseek($fd, $avdata_offset, SEEK_SET); + $header = ''; + $synch_seek_offset = 0; + + static $mpeg_audio_version_lookup; + static $mpeg_audio_layer_lookup; + static $mpeg_audio_bitrate_lookup; + if (empty($mpeg_audio_version_lookup)) { + $mpeg_audio_version_lookup = getid3_mp3::MPEGaudioVersionarray(); + $mpeg_audio_layer_lookup = getid3_mp3::MPEGaudioLayerarray(); + $mpeg_audio_bitrate_lookup = getid3_mp3::MPEGaudioBitratearray(); + + } + + $header_len = strlen($header) - intval(round(getid3::FREAD_BUFFER_SIZE / 2)); + + while (true) { + + if (($synch_seek_offset > $header_len) && (($avdata_offset + $synch_seek_offset) < $info['avdataend']) && !feof($fd)) { + + if ($synch_seek_offset > 131072) { + + // if a synch's not found within the first 128k bytes, then give up + throw new getid3_exception('could not find valid MPEG audio synch within the first 128k bytes'); + + } elseif ($header .= fread($fd, getid3::FREAD_BUFFER_SIZE)) { + + // great + $header_len = strlen($header) - intval(round(getid3::FREAD_BUFFER_SIZE / 2)); + + } else { + + throw new getid3_exception('could not find valid MPEG audio synch before end of file'); + } + } + + if (($synch_seek_offset + 1) >= strlen($header)) { + throw new getid3_exception('could not find valid MPEG synch before end of file'); + } + + if (($header{$synch_seek_offset} == "\xFF") && ($header{($synch_seek_offset + 1)} > "\xE0")) { // synch detected + + if (!isset($first_frame_info) && !isset($info['mpeg']['audio'])) { + $first_frame_info = $info; + $first_frame_avdata_offset = $avdata_offset + $synch_seek_offset; + if (!getid3_mp3::decodeMPEGaudioHeader($fd, $avdata_offset + $synch_seek_offset, $first_frame_info, false)) { + // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's + // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below + unset($first_frame_info); + } + } + + $dummy = $info; // only overwrite real data if valid header found + if (getid3_mp3::decodeMPEGaudioHeader($fd, $avdata_offset + $synch_seek_offset, $dummy, true)) { + $info = $dummy; + $info['avdataoffset'] = $avdata_offset + $synch_seek_offset; + + switch (@$info['fileformat']) { + case '': + case 'mp3': + $info['fileformat'] = 'mp3'; + $info['audio']['dataformat'] = 'mp3'; + break; + } + if (isset($first_frame_info['mpeg']['audio']['bitrate_mode']) && ($first_frame_info['mpeg']['audio']['bitrate_mode'] == 'vbr')) { + if (!(abs($info['audio']['bitrate'] - $first_frame_info['audio']['bitrate']) <= 1)) { + // If there is garbage data between a valid VBR header frame and a sequence + // of valid MPEG-audio frames the VBR data is no longer discarded. + $info = $first_frame_info; + $info['avdataoffset'] = $first_frame_avdata_offset; + $info['fileformat'] = 'mp3'; + $info['audio']['dataformat'] = 'mp3'; + $dummy = $info; + unset($dummy['mpeg']['audio']); + $GarbageOffsetStart = $first_frame_avdata_offset + $first_frame_info['mpeg']['audio']['framelength']; + $GarbageOffsetEnd = $avdata_offset + $synch_seek_offset; + if (getid3_mp3::decodeMPEGaudioHeader($fd, $GarbageOffsetEnd, $dummy, true, true)) { + + $info = $dummy; + $info['avdataoffset'] = $GarbageOffsetEnd; + $this->getid3->warning('apparently-valid VBR header not used because could not find '.getid3_mp3::VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd); + + } else { + + $this->getid3->warning('using data from VBR header even though could not find '.getid3_mp3::VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')'); + + } + } + } + if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) { + // VBR file with no VBR header + $bit_rate_histogram = true; + } + + if ($bit_rate_histogram) { + + $info['mpeg']['audio']['stereo_distribution'] = array ('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0); + $info['mpeg']['audio']['version_distribution'] = array ('1'=>0, '2'=>0, '2.5'=>0); + + if ($info['mpeg']['audio']['version'] == '1') { + if ($info['mpeg']['audio']['layer'] == 3) { + $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0); + } elseif ($info['mpeg']['audio']['layer'] == 2) { + $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0, 384000=>0); + } elseif ($info['mpeg']['audio']['layer'] == 1) { + $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 32000=>0, 64000=>0, 96000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 288000=>0, 320000=>0, 352000=>0, 384000=>0, 416000=>0, 448000=>0); + } + } elseif ($info['mpeg']['audio']['layer'] == 1) { + $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0, 176000=>0, 192000=>0, 224000=>0, 256000=>0); + } else { + $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0); + } + + $dummy = array ('avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']); + $synch_start_offset = $info['avdataoffset']; + + $fast_mode = false; + $synch_errors_found = 0; + while ($this->decodeMPEGaudioHeader($fd, $synch_start_offset, $dummy, false, false, $fast_mode)) { + $fast_mode = true; + $thisframebitrate = $mpeg_audio_bitrate_lookup[$mpeg_audio_version_lookup[$dummy['mpeg']['audio']['raw']['version']]][$mpeg_audio_layer_lookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']]; + + if (empty($dummy['mpeg']['audio']['framelength'])) { + $synch_errors_found++; + } else { + $info['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]++; + $info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]++; + $info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]++; + + $synch_start_offset += $dummy['mpeg']['audio']['framelength']; + } + } + if ($synch_errors_found > 0) { + $this->getid3->warning('Found '.$synch_errors_found.' synch errors in histogram analysis'); + } + + $bit_total = 0; + $frame_counter = 0; + foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bit_rate_value => $bit_rate_count) { + $frame_counter += $bit_rate_count; + if ($bit_rate_value != 'free') { + $bit_total += ($bit_rate_value * $bit_rate_count); + } + } + if ($frame_counter == 0) { + throw new getid3_exception('Corrupt MP3 file: framecounter == zero'); + } + $info['mpeg']['audio']['frame_count'] = $frame_counter; + $info['mpeg']['audio']['bitrate'] = ($bit_total / $frame_counter); + + $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; + + + // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently + $distinct_bit_rates = 0; + foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bit_rate_value => $bit_rate_count) { + if ($bit_rate_count > 0) { + $distinct_bit_rates++; + } + } + if ($distinct_bit_rates > 1) { + $info['mpeg']['audio']['bitrate_mode'] = 'vbr'; + } else { + $info['mpeg']['audio']['bitrate_mode'] = 'cbr'; + } + $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode']; + + } + + break; // exit while() + } + } + + $synch_seek_offset++; + if (($avdata_offset + $synch_seek_offset) >= $info['avdataend']) { + // end of file/data + + if (empty($info['mpeg']['audio'])) { + + throw new getid3_exception('could not find valid MPEG synch before end of file'); + } + break; + } + + } + + $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode']; + $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + return true; + } + + + + public static function MPEGaudioVersionarray() { + + static $array = array ('2.5', false, '2', '1'); + return $array; + } + + + + public static function MPEGaudioLayerarray() { + + static $array = array (false, 3, 2, 1); + return $array; + } + + + + public static function MPEGaudioBitratearray() { + + static $array; + if (empty($array)) { + $array = array ( + '1' => array (1 => array ('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000), + 2 => array ('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000), + 3 => array ('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000) + ), + + '2' => array (1 => array ('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000), + 2 => array ('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000), + ) + ); + $array['2'][3] = $array['2'][2]; + $array['2.5'] = $array['2']; + } + return $array; + } + + + + public static function MPEGaudioFrequencyarray() { + + static $array = array ( + '1' => array (44100, 48000, 32000), + '2' => array (22050, 24000, 16000), + '2.5' => array (11025, 12000, 8000) + ); + return $array; + } + + + + public static function MPEGaudioChannelModearray() { + + static $array = array ('stereo', 'joint stereo', 'dual channel', 'mono'); + return $array; + } + + + + public static function MPEGaudioModeExtensionarray() { + + static $array = array ( + 1 => array ('4-31', '8-31', '12-31', '16-31'), + 2 => array ('4-31', '8-31', '12-31', '16-31'), + 3 => array ('', 'IS', 'MS', 'IS+MS') + ); + return $array; + } + + + + public static function MPEGaudioEmphasisarray() { + + static $array = array ('none', '50/15ms', false, 'CCIT J.17'); + return $array; + } + + + + public static function MPEGaudioHeaderBytesValid($head4, $allow_bitrate_15=false) { + + return getid3_mp3::MPEGaudioHeaderValid(getid3_mp3::MPEGaudioHeaderDecode($head4), false, $allow_bitrate_15); + } + + + + public static function MPEGaudioHeaderValid($raw_array, $echo_errors=false, $allow_bitrate_15=false) { + + if (($raw_array['synch'] & 0x0FFE) != 0x0FFE) { + return false; + } + + static $mpeg_audio_version_lookup; + static $mpeg_audio_layer_lookup; + static $mpeg_audio_bitrate_lookup; + static $mpeg_audio_frequency_lookup; + static $mpeg_audio_channel_mode_lookup; + static $mpeg_audio_mode_extension_lookup; + static $mpeg_audio_emphasis_lookup; + if (empty($mpeg_audio_version_lookup)) { + $mpeg_audio_version_lookup = getid3_mp3::MPEGaudioVersionarray(); + $mpeg_audio_layer_lookup = getid3_mp3::MPEGaudioLayerarray(); + $mpeg_audio_bitrate_lookup = getid3_mp3::MPEGaudioBitratearray(); + $mpeg_audio_frequency_lookup = getid3_mp3::MPEGaudioFrequencyarray(); + $mpeg_audio_channel_mode_lookup = getid3_mp3::MPEGaudioChannelModearray(); + $mpeg_audio_mode_extension_lookup = getid3_mp3::MPEGaudioModeExtensionarray(); + $mpeg_audio_emphasis_lookup = getid3_mp3::MPEGaudioEmphasisarray(); + } + + if (isset($mpeg_audio_version_lookup[$raw_array['version']])) { + $decodedVersion = $mpeg_audio_version_lookup[$raw_array['version']]; + } else { + echo ($echo_errors ? "\n".'invalid Version ('.$raw_array['version'].')' : ''); + return false; + } + if (isset($mpeg_audio_layer_lookup[$raw_array['layer']])) { + $decodedLayer = $mpeg_audio_layer_lookup[$raw_array['layer']]; + } else { + echo ($echo_errors ? "\n".'invalid Layer ('.$raw_array['layer'].')' : ''); + return false; + } + if (!isset($mpeg_audio_bitrate_lookup[$decodedVersion][$decodedLayer][$raw_array['bitrate']])) { + echo ($echo_errors ? "\n".'invalid Bitrate ('.$raw_array['bitrate'].')' : ''); + if ($raw_array['bitrate'] == 15) { + // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0 + // let it go through here otherwise file will not be identified + if (!$allow_bitrate_15) { + return false; + } + } else { + return false; + } + } + if (!isset($mpeg_audio_frequency_lookup[$decodedVersion][$raw_array['sample_rate']])) { + echo ($echo_errors ? "\n".'invalid Frequency ('.$raw_array['sample_rate'].')' : ''); + return false; + } + if (!isset($mpeg_audio_channel_mode_lookup[$raw_array['channelmode']])) { + echo ($echo_errors ? "\n".'invalid ChannelMode ('.$raw_array['channelmode'].')' : ''); + return false; + } + if (!isset($mpeg_audio_mode_extension_lookup[$decodedLayer][$raw_array['modeextension']])) { + echo ($echo_errors ? "\n".'invalid Mode Extension ('.$raw_array['modeextension'].')' : ''); + return false; + } + if (!isset($mpeg_audio_emphasis_lookup[$raw_array['emphasis']])) { + echo ($echo_errors ? "\n".'invalid Emphasis ('.$raw_array['emphasis'].')' : ''); + return false; + } + // These are just either set or not set, you can't mess that up :) + // $raw_array['protection']; + // $raw_array['padding']; + // $raw_array['private']; + // $raw_array['copyright']; + // $raw_array['original']; + + return true; + } + + + + public static function MPEGaudioHeaderDecode($header_four_bytes) { + // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM + // A - Frame sync (all bits set) + // B - MPEG Audio version ID + // C - Layer description + // D - Protection bit + // E - Bitrate index + // F - Sampling rate frequency index + // G - Padding bit + // H - Private bit + // I - Channel Mode + // J - Mode extension (Only if Joint stereo) + // K - Copyright + // L - Original + // M - Emphasis + + if (strlen($header_four_bytes) != 4) { + return false; + } + + $mpeg_raw_header['synch'] = (getid3_lib::BigEndian2Int(substr($header_four_bytes, 0, 2)) & 0xFFE0) >> 4; + $mpeg_raw_header['version'] = (ord($header_four_bytes{1}) & 0x18) >> 3; // BB + $mpeg_raw_header['layer'] = (ord($header_four_bytes{1}) & 0x06) >> 1; // CC + $mpeg_raw_header['protection'] = (ord($header_four_bytes{1}) & 0x01); // D + $mpeg_raw_header['bitrate'] = (ord($header_four_bytes{2}) & 0xF0) >> 4; // EEEE + $mpeg_raw_header['sample_rate'] = (ord($header_four_bytes{2}) & 0x0C) >> 2; // FF + $mpeg_raw_header['padding'] = (ord($header_four_bytes{2}) & 0x02) >> 1; // G + $mpeg_raw_header['private'] = (ord($header_four_bytes{2}) & 0x01); // H + $mpeg_raw_header['channelmode'] = (ord($header_four_bytes{3}) & 0xC0) >> 6; // II + $mpeg_raw_header['modeextension'] = (ord($header_four_bytes{3}) & 0x30) >> 4; // JJ + $mpeg_raw_header['copyright'] = (ord($header_four_bytes{3}) & 0x08) >> 3; // K + $mpeg_raw_header['original'] = (ord($header_four_bytes{3}) & 0x04) >> 2; // L + $mpeg_raw_header['emphasis'] = (ord($header_four_bytes{3}) & 0x03); // MM + + return $mpeg_raw_header; + } + + + + public static function MPEGaudioFrameLength(&$bit_rate, &$version, &$layer, $padding, &$sample_rate) { + + if (!isset($cache[$bit_rate][$version][$layer][$padding][$sample_rate])) { + $cache[$bit_rate][$version][$layer][$padding][$sample_rate] = false; + if ($bit_rate != 'free') { + + if ($version == '1') { + + if ($layer == '1') { + + // For Layer I slot is 32 bits long + $frame_length_coefficient = 48; + $slot_length = 4; + + } else { // Layer 2 / 3 + + // for Layer 2 and Layer 3 slot is 8 bits long. + $frame_length_coefficient = 144; + $slot_length = 1; + + } + + } else { // MPEG-2 / MPEG-2.5 + + if ($layer == '1') { + + // For Layer I slot is 32 bits long + $frame_length_coefficient = 24; + $slot_length = 4; + + } elseif ($layer == '2') { + + // for Layer 2 and Layer 3 slot is 8 bits long. + $frame_length_coefficient = 144; + $slot_length = 1; + + } else { // layer 3 + + // for Layer 2 and Layer 3 slot is 8 bits long. + $frame_length_coefficient = 72; + $slot_length = 1; + + } + + } + + // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding + if ($sample_rate > 0) { + $new_frame_length = ($frame_length_coefficient * $bit_rate) / $sample_rate; + $new_frame_length = floor($new_frame_length / $slot_length) * $slot_length; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I) + if ($padding) { + $new_frame_length += $slot_length; + } + $cache[$bit_rate][$version][$layer][$padding][$sample_rate] = (int) $new_frame_length; + } + } + } + return $cache[$bit_rate][$version][$layer][$padding][$sample_rate]; + } + + + + public static function ClosestStandardMP3Bitrate($bit_rate) { + + static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000); + static $bit_rate_table = array (0=>'-'); + $round_bit_rate = intval(round($bit_rate, -3)); + if (!isset($bit_rate_table[$round_bit_rate])) { + if ($round_bit_rate > 320000) { + $bit_rate_table[$round_bit_rate] = round($bit_rate, -4); + } else { + $last_bit_rate = 320000; + foreach ($standard_bit_rates as $standard_bit_rate) { + $bit_rate_table[$round_bit_rate] = $standard_bit_rate; + if ($round_bit_rate >= $standard_bit_rate - (($last_bit_rate - $standard_bit_rate) / 2)) { + break; + } + $last_bit_rate = $standard_bit_rate; + } + } + } + return $bit_rate_table[$round_bit_rate]; + } + + + + public static function XingVBRidOffset($version, $channel_mode) { + + static $lookup = array ( + '1' => array ('mono' => 0x15, // 4 + 17 = 21 + 'stereo' => 0x24, // 4 + 32 = 36 + 'joint stereo' => 0x24, + 'dual channel' => 0x24 + ), + + '2' => array ('mono' => 0x0D, // 4 + 9 = 13 + 'stereo' => 0x15, // 4 + 17 = 21 + 'joint stereo' => 0x15, + 'dual channel' => 0x15 + ), + + '2.5' => array ('mono' => 0x15, + 'stereo' => 0x15, + 'joint stereo' => 0x15, + 'dual channel' => 0x15 + ) + ); + + return $lookup[$version][$channel_mode]; + } + + + + public static function LAMEvbrMethodLookup($vbr_method_id) { + + static $lookup = array ( + 0x00 => 'unknown', + 0x01 => 'cbr', + 0x02 => 'abr', + 0x03 => 'vbr-old / vbr-rh', + 0x04 => 'vbr-new / vbr-mtrh', + 0x05 => 'vbr-mt', + 0x06 => 'Full VBR Method 4', + 0x08 => 'constant bitrate 2 pass', + 0x09 => 'abr 2 pass', + 0x0F => 'reserved' + ); + return (isset($lookup[$vbr_method_id]) ? $lookup[$vbr_method_id] : ''); + } + + + + public static function LAMEmiscStereoModeLookup($stereo_mode_id) { + + static $lookup = array ( + 0 => 'mono', + 1 => 'stereo', + 2 => 'dual mono', + 3 => 'joint stereo', + 4 => 'forced stereo', + 5 => 'auto', + 6 => 'intensity stereo', + 7 => 'other' + ); + return (isset($lookup[$stereo_mode_id]) ? $lookup[$stereo_mode_id] : ''); + } + + + + public static function LAMEmiscSourceSampleFrequencyLookup($source_sample_frequency_id) { + + static $lookup = array ( + 0 => '<= 32 kHz', + 1 => '44.1 kHz', + 2 => '48 kHz', + 3 => '> 48kHz' + ); + return (isset($lookup[$source_sample_frequency_id]) ? $lookup[$source_sample_frequency_id] : ''); + } + + + + public static function LAMEsurroundInfoLookup($surround_info_id) { + + static $lookup = array ( + 0 => 'no surround info', + 1 => 'DPL encoding', + 2 => 'DPL2 encoding', + 3 => 'Ambisonic encoding' + ); + return (isset($lookup[$surround_info_id]) ? $lookup[$surround_info_id] : 'reserved'); + } + + + + public static function LAMEpresetUsedLookup($lame_tag) { + + if ($lame_tag['preset_used_id'] == 0) { + // no preset used (LAME >=3.93) + // no preset recorded (LAME <3.93) + return ''; + } + + $lame_preset_used_lookup = array (); + + for ($i = 8; $i <= 320; $i++) { + switch ($lame_tag['vbr_method']) { + case 'cbr': + $lame_preset_used_lookup[$i] = '--alt-preset '.$lame_tag['vbr_method'].' '.$i; + break; + case 'abr': + default: // other VBR modes shouldn't be here(?) + $lame_preset_used_lookup[$i] = '--alt-preset '.$i; + break; + } + } + + // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions() + + // named alt-presets + $lame_preset_used_lookup[1000] = '--r3mix'; + $lame_preset_used_lookup[1001] = '--alt-preset standard'; + $lame_preset_used_lookup[1002] = '--alt-preset extreme'; + $lame_preset_used_lookup[1003] = '--alt-preset insane'; + $lame_preset_used_lookup[1004] = '--alt-preset fast standard'; + $lame_preset_used_lookup[1005] = '--alt-preset fast extreme'; + $lame_preset_used_lookup[1006] = '--alt-preset medium'; + $lame_preset_used_lookup[1007] = '--alt-preset fast medium'; + + // LAME 3.94 additions/changes + $lame_preset_used_lookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003 + $lame_preset_used_lookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003 + + $lame_preset_used_lookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003 + $lame_preset_used_lookup[410] = '-V9'; + $lame_preset_used_lookup[420] = '-V8'; + $lame_preset_used_lookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003 + $lame_preset_used_lookup[440] = '-V6'; + $lame_preset_used_lookup[450] = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003 + $lame_preset_used_lookup[460] = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003 + $lame_preset_used_lookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003 + $lame_preset_used_lookup[480] = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003 + $lame_preset_used_lookup[490] = '-V1'; + $lame_preset_used_lookup[500] = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003 + + return (isset($lame_preset_used_lookup[$lame_tag['preset_used_id']]) ? $lame_preset_used_lookup[$lame_tag['preset_used_id']] : 'new/unknown preset: '.$lame_tag['preset_used_id'].' - report to info@getid3.org'); + } + + +} diff --git a/plugins/getId3Plugin/lib/module.audio.mpc.php b/plugins/getId3Plugin/lib/module.audio.mpc.php new file mode 100644 index 0000000..ccf4310 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.mpc.php @@ -0,0 +1,211 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.mpc.php | +// | Module for analyzing Musepack/MPEG+ Audio files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.mpc.php,v 1.2 2004/11/01 03:11:16 ah Exp $ + + + +class getid3_mpc extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + // http://www.uni-jena.de/~pfk/mpp/sv8/header.html + + $getid3->info['fileformat'] = 'mpc'; + $getid3->info['audio']['dataformat'] = 'mpc'; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + $getid3->info['audio']['channels'] = 2; // the format appears to be hardcoded for stereo only + $getid3->info['audio']['lossless'] = false; + + $getid3->info['mpc']['header'] = array (); + $info_mpc_header = &$getid3->info['mpc']['header']; + $info_mpc_header['size'] = 28; + $info_mpc_header['raw']['preamble'] = 'MP+'; // Magic bytes + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $mpc_header_data = fread($getid3->fp, 28); + + $stream_version_byte = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 3, 1)); + $info_mpc_header['stream_major_version'] = ($stream_version_byte & 0x0F); + $info_mpc_header['stream_minor_version'] = ($stream_version_byte & 0xF0) >> 4; + if ($info_mpc_header['stream_major_version'] != 7) { + throw new getid3_exception('Only Musepack SV7 supported'); + } + + $info_mpc_header['frame_count'] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 4, 4)); + + $info_mpc_header['raw']['title_peak'] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 12, 2)); + $info_mpc_header['raw']['title_gain'] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 14, 2), true); + $info_mpc_header['raw']['album_peak'] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 16, 2)); + $info_mpc_header['raw']['album_gain'] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 18, 2), true); + + $info_mpc_header['raw']['not_sure_what'] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 24, 3)); + $info_mpc_header['raw']['encoder_version'] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 27, 1)); + + $flags_dword1 = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 8, 4)); + $flags_dword2 = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 20, 4)); + + $info_mpc_header['intensity_stereo'] = (bool)(($flags_dword1 & 0x80000000) >> 31); + $info_mpc_header['mid_side_stereo'] = (bool)(($flags_dword1 & 0x40000000) >> 30); + $info_mpc_header['max_subband'] = ($flags_dword1 & 0x3F000000) >> 24; + $info_mpc_header['raw']['profile'] = ($flags_dword1 & 0x00F00000) >> 20; + $info_mpc_header['begin_loud'] = (bool)(($flags_dword1 & 0x00080000) >> 19); + $info_mpc_header['end_loud'] = (bool)(($flags_dword1 & 0x00040000) >> 18); + $info_mpc_header['raw']['sample_rate'] = ($flags_dword1 & 0x00030000) >> 16; + $info_mpc_header['max_level'] = ($flags_dword1 & 0x0000FFFF); + + $info_mpc_header['true_gapless'] = (bool)(($flags_dword2 & 0x80000000) >> 31); + $info_mpc_header['last_frame_length'] = ($flags_dword2 & 0x7FF00000) >> 20; + + $info_mpc_header['profile'] = getid3_mpc::MPCprofileNameLookup($info_mpc_header['raw']['profile']); + $info_mpc_header['sample_rate'] = getid3_mpc::MPCfrequencyLookup($info_mpc_header['raw']['sample_rate']); + $getid3->info['audio']['sample_rate'] = $info_mpc_header['sample_rate']; + $info_mpc_header['samples'] = ((($info_mpc_header['frame_count'] - 1) * 1152) + $info_mpc_header['last_frame_length']) * $getid3->info['audio']['channels']; + + $getid3->info['playtime_seconds'] = ($info_mpc_header['samples'] / $getid3->info['audio']['channels']) / $getid3->info['audio']['sample_rate']; + + $getid3->info['avdataoffset'] += $info_mpc_header['size']; + + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + + $info_mpc_header['title_peak'] = $info_mpc_header['raw']['title_peak']; + $info_mpc_header['title_peak_db'] = getid3_mpc::MPCpeakDBLookup($info_mpc_header['title_peak']); + if ($info_mpc_header['raw']['title_gain'] < 0) { + $info_mpc_header['title_gain_db'] = (float)(32768 + $info_mpc_header['raw']['title_gain']) / -100; + } + else { + $info_mpc_header['title_gain_db'] = (float)$info_mpc_header['raw']['title_gain'] / 100; + } + + $info_mpc_header['album_peak'] = $info_mpc_header['raw']['album_peak']; + $info_mpc_header['album_peak_db'] = getid3_mpc::MPCpeakDBLookup($info_mpc_header['album_peak']); + if ($info_mpc_header['raw']['album_gain'] < 0) { + $info_mpc_header['album_gain_db'] = (float)(32768 + $info_mpc_header['raw']['album_gain']) / -100; + } + else { + $info_mpc_header['album_gain_db'] = (float)$info_mpc_header['raw']['album_gain'] / 100;; + } + $info_mpc_header['encoder_version'] = getid3_mpc::MPCencoderVersionLookup($info_mpc_header['raw']['encoder_version']); + + $getid3->info['replay_gain']['track']['adjustment'] = $info_mpc_header['title_gain_db']; + $getid3->info['replay_gain']['album']['adjustment'] = $info_mpc_header['album_gain_db']; + + if ($info_mpc_header['title_peak'] > 0) { + $getid3->info['replay_gain']['track']['peak'] = $info_mpc_header['title_peak']; + } + elseif (round($info_mpc_header['max_level'] * 1.18) > 0) { + $getid3->info['replay_gain']['track']['peak'] = (int)(round($info_mpc_header['max_level'] * 1.18)); // why? I don't know - see mppdec.c + } + if ($info_mpc_header['album_peak'] > 0) { + $getid3->info['replay_gain']['album']['peak'] = $info_mpc_header['album_peak']; + } + + $getid3->info['audio']['encoder'] = $info_mpc_header['encoder_version']; + $getid3->info['audio']['encoder_options'] = $info_mpc_header['profile']; + + return true; + } + + + + public static function MPCprofileNameLookup($profileid) { + + static $lookup = array ( + 0 => 'no profile', + 1 => 'Experimental', + 2 => 'unused', + 3 => 'unused', + 4 => 'unused', + 5 => 'below Telephone (q = 0.0)', + 6 => 'below Telephone (q = 1.0)', + 7 => 'Telephone (q = 2.0)', + 8 => 'Thumb (q = 3.0)', + 9 => 'Radio (q = 4.0)', + 10 => 'Standard (q = 5.0)', + 11 => 'Extreme (q = 6.0)', + 12 => 'Insane (q = 7.0)', + 13 => 'BrainDead (q = 8.0)', + 14 => 'above BrainDead (q = 9.0)', + 15 => 'above BrainDead (q = 10.0)' + ); + return (isset($lookup[$profileid]) ? $lookup[$profileid] : 'invalid'); + } + + + + public static function MPCfrequencyLookup($frequencyid) { + + static $lookup = array ( + 0 => 44100, + 1 => 48000, + 2 => 37800, + 3 => 32000 + ); + return (isset($lookup[$frequencyid]) ? $lookup[$frequencyid] : 'invalid'); + } + + + + public static function MPCpeakDBLookup($int_value) { + + if ($int_value > 0) { + return ((log10($int_value) / log10(2)) - 15) * 6; + } + return false; + } + + + + public static function MPCencoderVersionLookup($encoder_version) { + + //Encoder version * 100 (106 = 1.06) + //EncoderVersion % 10 == 0 Release (1.0) + //EncoderVersion % 2 == 0 Beta (1.06) + //EncoderVersion % 2 == 1 Alpha (1.05a...z) + + if ($encoder_version == 0) { + // very old version, not known exactly which + return 'Buschmann v1.7.0-v1.7.9 or Klemm v0.90-v1.05'; + } + + if (($encoder_version % 10) == 0) { + + // release version + return number_format($encoder_version / 100, 2); + + } elseif (($encoder_version % 2) == 0) { + + // beta version + return number_format($encoder_version / 100, 2).' beta'; + + } + + // alpha version + return number_format($encoder_version / 100, 2).' alpha'; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.mpc_old.php b/plugins/getId3Plugin/lib/module.audio.mpc_old.php new file mode 100644 index 0000000..86acd66 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.mpc_old.php @@ -0,0 +1,107 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.mpc_old.php | +// | Module for analyzing Musepack/MPEG+ Audio files - SV4-SV6 | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.mpc_old.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_mpc_old extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + // http://www.uni-jena.de/~pfk/mpp/sv8/header.html + + $getid3->info['mpc']['header'] = array (); + $info_mpc_header = &$getid3->info['mpc']['header']; + + $getid3->info['fileformat'] = 'mpc'; + $getid3->info['audio']['dataformat'] = 'mpc'; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + $getid3->info['audio']['channels'] = 2; // the format appears to be hardcoded for stereo only + $getid3->info['audio']['lossless'] = false; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + $info_mpc_header['size'] = 8; + $getid3->info['avdataoffset'] += $info_mpc_header['size']; + + $mpc_header_data = fread($getid3->fp, $info_mpc_header['size']); + + + // Most of this code adapted from Jurgen Faul's MPEGplus source code - thanks Jurgen! :) + $header_dword[0] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 0, 4)); + $header_dword[1] = getid3_lib::LittleEndian2Int(substr($mpc_header_data, 4, 4)); + + + // DDDD DDDD CCCC CCCC BBBB BBBB AAAA AAAA + // aaaa aaaa abcd dddd dddd deee eeff ffff + // + // a = bitrate = anything + // b = IS = anything + // c = MS = anything + // d = streamversion = 0000000004 or 0000000005 or 0000000006 + // e = maxband = anything + // f = blocksize = 000001 for SV5+, anything(?) for SV4 + + $info_mpc_header['target_bitrate'] = (($header_dword[0] & 0xFF800000) >> 23); + $info_mpc_header['intensity_stereo'] = (bool)(($header_dword[0] & 0x00400000) >> 22); + $info_mpc_header['mid-side_stereo'] = (bool)(($header_dword[0] & 0x00200000) >> 21); + $info_mpc_header['stream_major_version'] = ($header_dword[0] & 0x001FF800) >> 11; + $info_mpc_header['stream_minor_version'] = 0; + $info_mpc_header['max_band'] = ($header_dword[0] & 0x000007C0) >> 6; // related to lowpass frequency, not sure how it translates exactly + $info_mpc_header['block_size'] = ($header_dword[0] & 0x0000003F); + + switch ($info_mpc_header['stream_major_version']) { + case 4: + $info_mpc_header['frame_count'] = ($header_dword[1] >> 16); + break; + case 5: + case 6: + $info_mpc_header['frame_count'] = $header_dword[1]; + break; + + default: + throw new getid3_exception('Expecting 4, 5 or 6 in version field, found '.$info_mpc_header['stream_major_version'].' instead'); + } + + if (($info_mpc_header['stream_major_version'] > 4) && ($info_mpc_header['block_size'] != 1)) { + $getid3->warning('Block size expected to be 1, actual value found: '.$info_mpc_header['block_size']); + } + + $info_mpc_header['sample_rate'] = $getid3->info['audio']['sample_rate'] = 44100; // AB: used by all files up to SV7 + $info_mpc_header['samples'] = $info_mpc_header['frame_count'] * 1152 * $getid3->info['audio']['channels']; + + $getid3->info['audio']['bitrate_mode'] = $info_mpc_header['target_bitrate'] == 0 ? 'vbr' : 'cbr'; + + $getid3->info['mpc']['bitrate'] = ($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8 * 44100 / $info_mpc_header['frame_count'] / 1152; + $getid3->info['audio']['bitrate'] = $getid3->info['mpc']['bitrate']; + $getid3->info['audio']['encoder'] = 'SV'.$info_mpc_header['stream_major_version']; + + return true; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.ogg.php b/plugins/getId3Plugin/lib/module.audio.ogg.php new file mode 100644 index 0000000..f722b33 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.ogg.php @@ -0,0 +1,543 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.ogg.php // +// module for analyzing Ogg Vorbis, OggFLAC and Speex files // +// dependencies: module.audio.flac.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true); + +class getid3_ogg +{ + + function getid3_ogg(&$fd, &$ThisFileInfo) { + + $ThisFileInfo['fileformat'] = 'ogg'; + + // Warn about illegal tags - only vorbiscomments are allowed + if (isset($ThisFileInfo['id3v2'])) { + $ThisFileInfo['warning'][] = 'Illegal ID3v2 tag present.'; + } + if (isset($ThisFileInfo['id3v1'])) { + $ThisFileInfo['warning'][] = 'Illegal ID3v1 tag present.'; + } + if (isset($ThisFileInfo['ape'])) { + $ThisFileInfo['warning'][] = 'Illegal APE tag present.'; + } + + + // Page 1 - Stream Header + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + + $oggpageinfo = getid3_ogg::ParseOggPageHeader($fd); + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; + + if (ftell($fd) >= GETID3_FREAD_BUFFER_SIZE) { + $ThisFileInfo['error'][] = 'Could not find start of Ogg page in the first '.GETID3_FREAD_BUFFER_SIZE.' bytes (this might not be an Ogg-Vorbis file?)'; + unset($ThisFileInfo['fileformat']); + unset($ThisFileInfo['ogg']); + return false; + } + + $filedata = fread($fd, $oggpageinfo['page_length']); + $filedataoffset = 0; + + if (substr($filedata, 0, 4) == 'fLaC') { + + $ThisFileInfo['audio']['dataformat'] = 'flac'; + $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; + $ThisFileInfo['audio']['lossless'] = true; + + } elseif (substr($filedata, 1, 6) == 'vorbis') { + + $ThisFileInfo['audio']['dataformat'] = 'vorbis'; + $ThisFileInfo['audio']['lossless'] = false; + + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis' + $filedataoffset += 6; + $ThisFileInfo['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $ThisFileInfo['audio']['channels'] = $ThisFileInfo['ogg']['numberofchannels']; + $ThisFileInfo['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + if ($ThisFileInfo['ogg']['samplerate'] == 0) { + $ThisFileInfo['error'][] = 'Corrupt Ogg file: sample rate == zero'; + return false; + } + $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['ogg']['samplerate']; + $ThisFileInfo['ogg']['samples'] = 0; // filled in later + $ThisFileInfo['ogg']['bitrate_average'] = 0; // filled in later + $ThisFileInfo['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F); + $ThisFileInfo['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4); + $ThisFileInfo['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet + + $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr + if ($ThisFileInfo['ogg']['bitrate_max'] == 0xFFFFFFFF) { + unset($ThisFileInfo['ogg']['bitrate_max']); + $ThisFileInfo['audio']['bitrate_mode'] = 'abr'; + } + if ($ThisFileInfo['ogg']['bitrate_nominal'] == 0xFFFFFFFF) { + unset($ThisFileInfo['ogg']['bitrate_nominal']); + } + if ($ThisFileInfo['ogg']['bitrate_min'] == 0xFFFFFFFF) { + unset($ThisFileInfo['ogg']['bitrate_min']); + $ThisFileInfo['audio']['bitrate_mode'] = 'abr'; + } + + } elseif (substr($filedata, 0, 8) == 'Speex ') { + + // http://www.speex.org/manual/node10.html + + $ThisFileInfo['audio']['dataformat'] = 'speex'; + $ThisFileInfo['mime_type'] = 'audio/speex'; + $ThisFileInfo['audio']['bitrate_mode'] = 'abr'; + $ThisFileInfo['audio']['lossless'] = false; + + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex ' + $filedataoffset += 8; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20); + $filedataoffset += 20; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + + $ThisFileInfo['speex']['speex_version'] = trim($ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']); + $ThisFileInfo['speex']['sample_rate'] = $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate']; + $ThisFileInfo['speex']['channels'] = $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels']; + $ThisFileInfo['speex']['vbr'] = (bool) $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr']; + $ThisFileInfo['speex']['band_type'] = getid3_ogg::SpeexBandModeLookup($ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']); + + $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['speex']['sample_rate']; + $ThisFileInfo['audio']['channels'] = $ThisFileInfo['speex']['channels']; + if ($ThisFileInfo['speex']['vbr']) { + $ThisFileInfo['audio']['bitrate_mode'] = 'vbr'; + } + + } else { + + $ThisFileInfo['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found neither'; + unset($ThisFileInfo['ogg']); + unset($ThisFileInfo['mime_type']); + return false; + + } + + + // Page 2 - Comment Header + + $oggpageinfo = getid3_ogg::ParseOggPageHeader($fd); + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; + + switch ($ThisFileInfo['audio']['dataformat']) { + + case 'vorbis': + $filedata = fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1)); + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis' + + getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo); + break; + + case 'flac': + if (!getid3_flac::FLACparseMETAdata($fd, $ThisFileInfo)) { + $ThisFileInfo['error'][] = 'Failed to parse FLAC headers'; + return false; + } + break; + + case 'speex': + fseek($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR); + getid3_ogg::ParseVorbisCommentsFilepointer($fd, $ThisFileInfo); + break; + + } + + + + // Last Page - Number of Samples + + fseek($fd, max($ThisFileInfo['avdataend'] - GETID3_FREAD_BUFFER_SIZE, 0), SEEK_SET); + $LastChunkOfOgg = strrev(fread($fd, GETID3_FREAD_BUFFER_SIZE)); + if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) { + fseek($fd, $ThisFileInfo['avdataend'] - ($LastOggSpostion + strlen('SggO')), SEEK_SET); + $ThisFileInfo['avdataend'] = ftell($fd); + $ThisFileInfo['ogg']['pageheader']['eos'] = getid3_ogg::ParseOggPageHeader($fd); + $ThisFileInfo['ogg']['samples'] = $ThisFileInfo['ogg']['pageheader']['eos']['pcm_abs_position']; + if ($ThisFileInfo['ogg']['samples'] == 0) { + $ThisFileInfo['error'][] = 'Corrupt Ogg file: eos.number of samples == zero'; + return false; + } + $ThisFileInfo['ogg']['bitrate_average'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / ($ThisFileInfo['ogg']['samples'] / $ThisFileInfo['audio']['sample_rate']); + } + + if (!empty($ThisFileInfo['ogg']['bitrate_average'])) { + $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['ogg']['bitrate_average']; + } elseif (!empty($ThisFileInfo['ogg']['bitrate_nominal'])) { + $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['ogg']['bitrate_nominal']; + } elseif (!empty($ThisFileInfo['ogg']['bitrate_min']) && !empty($ThisFileInfo['ogg']['bitrate_max'])) { + $ThisFileInfo['audio']['bitrate'] = ($ThisFileInfo['ogg']['bitrate_min'] + $ThisFileInfo['ogg']['bitrate_max']) / 2; + } + if (isset($ThisFileInfo['audio']['bitrate']) && !isset($ThisFileInfo['playtime_seconds'])) { + if ($ThisFileInfo['audio']['bitrate'] == 0) { + $ThisFileInfo['error'][] = 'Corrupt Ogg file: bitrate_audio == zero'; + return false; + } + $ThisFileInfo['playtime_seconds'] = (float) ((($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['audio']['bitrate']); + } + + if (isset($ThisFileInfo['ogg']['vendor'])) { + $ThisFileInfo['audio']['encoder'] = preg_replace('/^Encoded with /', '', $ThisFileInfo['ogg']['vendor']); + + // Vorbis only + if ($ThisFileInfo['audio']['dataformat'] == 'vorbis') { + + // Vorbis 1.0 starts with Xiph.Org + if (preg_match('/^Xiph.Org/', $ThisFileInfo['audio']['encoder'])) { + + if ($ThisFileInfo['audio']['bitrate_mode'] == 'abr') { + + // Set -b 128 on abr files + $ThisFileInfo['audio']['encoder_options'] = '-b '.round($ThisFileInfo['ogg']['bitrate_nominal'] / 1000); + + } elseif (($ThisFileInfo['audio']['bitrate_mode'] == 'vbr') && ($ThisFileInfo['audio']['channels'] == 2) && ($ThisFileInfo['audio']['sample_rate'] >= 44100) && ($ThisFileInfo['audio']['sample_rate'] <= 48000)) { + // Set -q N on vbr files + $ThisFileInfo['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($ThisFileInfo['ogg']['bitrate_nominal']); + + } + } + + if (empty($ThisFileInfo['audio']['encoder_options']) && !empty($ThisFileInfo['ogg']['bitrate_nominal'])) { + $ThisFileInfo['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($ThisFileInfo['ogg']['bitrate_nominal'] / 1000)).'kbps'; + } + } + } + + return true; + } + + + function ParseOggPageHeader(&$fd) { + // http://xiph.org/ogg/vorbis/doc/framing.html + $oggheader['page_start_offset'] = ftell($fd); // where we started from in the file + + $filedata = fread($fd, GETID3_FREAD_BUFFER_SIZE); + $filedataoffset = 0; + while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) { + if ((ftell($fd) - $oggheader['page_start_offset']) >= GETID3_FREAD_BUFFER_SIZE) { + // should be found before here + return false; + } + if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) { + if (feof($fd) || (($filedata .= fread($fd, GETID3_FREAD_BUFFER_SIZE)) === false)) { + // get some more data, unless eof, in which case fail + return false; + } + } + } + $filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS' + + $oggheader['stream_structver'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $oggheader['flags_raw'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $oggheader['flags']['fresh'] = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet + $oggheader['flags']['bos'] = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos) + $oggheader['flags']['eos'] = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos) + + $oggheader['pcm_abs_position'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $oggheader['stream_serialno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $oggheader['page_seqno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $oggheader['page_checksum'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $oggheader['page_segments'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $oggheader['page_length'] = 0; + for ($i = 0; $i < $oggheader['page_segments']; $i++) { + $oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $oggheader['page_length'] += $oggheader['segment_table'][$i]; + } + $oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset; + $oggheader['page_end_offset'] = $oggheader['header_end_offset'] + $oggheader['page_length']; + fseek($fd, $oggheader['header_end_offset'], SEEK_SET); + + return $oggheader; + } + + + function ParseVorbisCommentsFilepointer(&$fd, &$ThisFileInfo) { + + $OriginalOffset = ftell($fd); + $CommentStartOffset = $OriginalOffset; + $commentdataoffset = 0; + $VorbisCommentPage = 1; + + switch ($ThisFileInfo['audio']['dataformat']) { + case 'vorbis': + $CommentStartOffset = $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block + fseek($fd, $CommentStartOffset, SEEK_SET); + $commentdataoffset = 27 + $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_segments']; + $commentdata = fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset); + + $commentdataoffset += (strlen('vorbis') + 1); + break; + + case 'flac': + fseek($fd, $ThisFileInfo['flac']['VORBIS_COMMENT']['raw']['offset'] + 4, SEEK_SET); + $commentdata = fread($fd, $ThisFileInfo['flac']['VORBIS_COMMENT']['raw']['block_length']); + break; + + case 'speex': + $CommentStartOffset = $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block + fseek($fd, $CommentStartOffset, SEEK_SET); + $commentdataoffset = 27 + $ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage]['page_segments']; + $commentdata = fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset); + break; + + default: + return false; + break; + } + + $VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); + $commentdataoffset += 4; + + $ThisFileInfo['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize); + $commentdataoffset += $VendorSize; + + $CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); + $commentdataoffset += 4; + $ThisFileInfo['avdataoffset'] = $CommentStartOffset + $commentdataoffset; + + $basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT'); + for ($i = 0; $i < $CommentsCount; $i++) { + + $ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset; + + if (ftell($fd) < ($ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] + 4)) { + $VorbisCommentPage++; + + $oggpageinfo = getid3_ogg::ParseOggPageHeader($fd); + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; + + // First, save what we haven't read yet + $AsYetUnusedData = substr($commentdata, $commentdataoffset); + + // Then take that data off the end + $commentdata = substr($commentdata, 0, $commentdataoffset); + + // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct + $commentdata .= str_repeat("\x00", 27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); + $commentdataoffset += (27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); + + // Finally, stick the unused data back on the end + $commentdata .= $AsYetUnusedData; + + //$commentdata .= fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); + $commentdata .= fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1)); + + } + $ThisFileInfo['ogg']['comments_raw'][$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); + + // replace avdataoffset with position just after the last vorbiscomment + $ThisFileInfo['avdataoffset'] = $ThisFileInfo['ogg']['comments_raw'][$i]['dataoffset'] + $ThisFileInfo['ogg']['comments_raw'][$i]['size'] + 4; + + $commentdataoffset += 4; + while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo['ogg']['comments_raw'][$i]['size']) { + if (($ThisFileInfo['ogg']['comments_raw'][$i]['size'] > $ThisFileInfo['avdataend']) || ($ThisFileInfo['ogg']['comments_raw'][$i]['size'] < 0)) { + $ThisFileInfo['error'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo['ogg']['comments_raw'][$i]['size']).' bytes) - aborting reading comments'; + break 2; + } + + $VorbisCommentPage++; + + $oggpageinfo = getid3_ogg::ParseOggPageHeader($fd); + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; + + // First, save what we haven't read yet + $AsYetUnusedData = substr($commentdata, $commentdataoffset); + + // Then take that data off the end + $commentdata = substr($commentdata, 0, $commentdataoffset); + + // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct + $commentdata .= str_repeat("\x00", 27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); + $commentdataoffset += (27 + $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); + + // Finally, stick the unused data back on the end + $commentdata .= $AsYetUnusedData; + + //$commentdata .= fread($fd, $ThisFileInfo['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); + $commentdata .= fread($fd, getid3_ogg::OggPageSegmentLength($ThisFileInfo['ogg']['pageheader'][$VorbisCommentPage], 1)); + + //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset']; + } + $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo['ogg']['comments_raw'][$i]['size']); + $commentdataoffset += $ThisFileInfo['ogg']['comments_raw'][$i]['size']; + + if (!$commentstring) { + + // no comment? + $ThisFileInfo['warning'][] = 'Blank Ogg comment ['.$i.']'; + + } elseif (strstr($commentstring, '=')) { + + $commentexploded = explode('=', $commentstring, 2); + $ThisFileInfo['ogg']['comments_raw'][$i]['key'] = strtoupper($commentexploded[0]); + $ThisFileInfo['ogg']['comments_raw'][$i]['value'] = @$commentexploded[1]; + $ThisFileInfo['ogg']['comments_raw'][$i]['data'] = base64_decode($ThisFileInfo['ogg']['comments_raw'][$i]['value']); + + $ThisFileInfo['ogg']['comments'][strtolower($ThisFileInfo['ogg']['comments_raw'][$i]['key'])][] = $ThisFileInfo['ogg']['comments_raw'][$i]['value']; + + $imagechunkcheck = getid3_lib::GetDataImageSize($ThisFileInfo['ogg']['comments_raw'][$i]['data']); + $ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] = getid3_lib::image_type_to_mime_type($imagechunkcheck[2]); + if (!$ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] || ($ThisFileInfo['ogg']['comments_raw'][$i]['image_mime'] == 'application/octet-stream')) { + unset($ThisFileInfo['ogg']['comments_raw'][$i]['image_mime']); + unset($ThisFileInfo['ogg']['comments_raw'][$i]['data']); + } + + } else { + + $ThisFileInfo['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring; + + } + } + + + // Replay Gain Adjustment + // http://privatewww.essex.ac.uk/~djmrob/replaygain/ + if (isset($ThisFileInfo['ogg']['comments']) && is_array($ThisFileInfo['ogg']['comments'])) { + foreach ($ThisFileInfo['ogg']['comments'] as $index => $commentvalue) { + switch ($index) { + case 'rg_audiophile': + case 'replaygain_album_gain': + $ThisFileInfo['replay_gain']['album']['adjustment'] = (double) $commentvalue[0]; + unset($ThisFileInfo['ogg']['comments'][$index]); + break; + + case 'rg_radio': + case 'replaygain_track_gain': + $ThisFileInfo['replay_gain']['track']['adjustment'] = (double) $commentvalue[0]; + unset($ThisFileInfo['ogg']['comments'][$index]); + break; + + case 'replaygain_album_peak': + $ThisFileInfo['replay_gain']['album']['peak'] = (double) $commentvalue[0]; + unset($ThisFileInfo['ogg']['comments'][$index]); + break; + + case 'rg_peak': + case 'replaygain_track_peak': + $ThisFileInfo['replay_gain']['track']['peak'] = (double) $commentvalue[0]; + unset($ThisFileInfo['ogg']['comments'][$index]); + break; + + + default: + // do nothing + break; + } + } + } + + fseek($fd, $OriginalOffset, SEEK_SET); + + return true; + } + + function SpeexBandModeLookup($mode) { + static $SpeexBandModeLookup = array(); + if (empty($SpeexBandModeLookup)) { + $SpeexBandModeLookup[0] = 'narrow'; + $SpeexBandModeLookup[1] = 'wide'; + $SpeexBandModeLookup[2] = 'ultra-wide'; + } + return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null); + } + + + function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) { + for ($i = 0; $i < $SegmentNumber; $i++) { + $segmentlength = 0; + foreach ($OggInfoArray['segment_table'] as $key => $value) { + $segmentlength += $value; + if ($value < 255) { + break; + } + } + } + return $segmentlength; + } + + + function get_quality_from_nominal_bitrate($nominal_bitrate) { + + // decrease precision + $nominal_bitrate = $nominal_bitrate / 1000; + + if ($nominal_bitrate < 128) { + // q-1 to q4 + $qval = ($nominal_bitrate - 64) / 16; + } elseif ($nominal_bitrate < 256) { + // q4 to q8 + $qval = $nominal_bitrate / 32; + } elseif ($nominal_bitrate < 320) { + // q8 to q9 + $qval = ($nominal_bitrate + 256) / 64; + } else { + // q9 to q10 + $qval = ($nominal_bitrate + 1300) / 180; + } + //return $qval; // 5.031324 + //return intval($qval); // 5 + return round($qval, 1); // 5 or 4.9 + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.optimfrog.php b/plugins/getId3Plugin/lib/module.audio.optimfrog.php new file mode 100644 index 0000000..8204ed1 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.optimfrog.php @@ -0,0 +1,468 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.optimfrog.php | +// | Module for analyzing OptimFROG Audio files | +// | dependencies: module.audio-video.riff.php | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.optimfrog.php,v 1.2 2004/11/01 03:11:16 ah Exp $ + + + +class getid3_optimfrog extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->include_module('audio-video.riff'); + + $getid3->info['audio']['dataformat'] = 'ofr'; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + $getid3->info['audio']['lossless'] = true; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $ofr_header = fread($getid3->fp, 8); + + if (substr($ofr_header, 0, 5) == '*RIFF') { + return $this->ParseOptimFROGheader42($getid3->fp, $getid3->info); + + } elseif (substr($ofr_header, 0, 3) == 'OFR') { + return $this->ParseOptimFROGheader45($getid3->fp, $getid3->info); + } + + throw new getid3_exception('Expecting "*RIFF" or "OFR " at offset '.$getid3->info['avdataoffset'].', found "'.$ofr_header.'"'); + } + + + + private function ParseOptimFROGheader42() { + + $getid3 = $this->getid3; + + // for fileformat of v4.21 and older + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + $ofr_header_data = fread($getid3->fp, 45); + $getid3->info['avdataoffset'] = 45; + + $ofr_encoder_version_raw = getid3_lib::LittleEndian2Int(substr($ofr_header_data, 0, 1)); + $ofr_encoder_version_major = floor($ofr_encoder_version_raw / 10); + $ofr_encoder_version_minor = $ofr_encoder_version_raw - ($ofr_encoder_version_major * 10); + $riff_data = substr($ofr_header_data, 1, 44); + $origna_riff_header_size = getid3_lib::LittleEndian2Int(substr($riff_data, 4, 4)) + 8; + $origna_riff_data_size = getid3_lib::LittleEndian2Int(substr($riff_data, 40, 4)) + 44; + + if ($origna_riff_header_size > $origna_riff_data_size) { + $getid3->info['avdataend'] -= ($origna_riff_header_size - $origna_riff_data_size); + fseek($getid3->fp, $getid3->info['avdataend'], SEEK_SET); + $riff_data .= fread($getid3->fp, $origna_riff_header_size - $origna_riff_data_size); + } + + // move the data chunk after all other chunks (if any) + // so that the RIFF parser doesn't see EOF when trying + // to skip over the data chunk + + $riff_data = substr($riff_data, 0, 36).substr($riff_data, 44).substr($riff_data, 36, 8); + + // Save audio info key + $saved_info_audio = $getid3->info['audio']; + + // Instantiate riff module and analyze string + $riff = new getid3_riff($getid3); + $riff->AnalyzeString($riff_data); + + // Restore info key + $getid3->info['audio'] = $saved_info_audio; + + $getid3->info['audio']['encoder'] = 'OptimFROG '.$ofr_encoder_version_major.'.'.$ofr_encoder_version_minor; + $getid3->info['audio']['channels'] = $getid3->info['riff']['audio'][0]['channels']; + $getid3->info['audio']['sample_rate'] = $getid3->info['riff']['audio'][0]['sample_rate']; + $getid3->info['audio']['bits_per_sample'] = $getid3->info['riff']['audio'][0]['bits_per_sample']; + $getid3->info['playtime_seconds'] = $origna_riff_data_size / ($getid3->info['audio']['channels'] * $getid3->info['audio']['sample_rate'] * ($getid3->info['audio']['bits_per_sample'] / 8)); + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + + $getid3->info['fileformat'] = 'ofr'; + + return true; + } + + + + private function ParseOptimFROGheader45() { + + $getid3 = $this->getid3; + + // for fileformat of v4.50a and higher + + $riff_data = ''; + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + while (!feof($getid3->fp) && (ftell($getid3->fp) < $getid3->info['avdataend'])) { + + $block_offset = ftell($getid3->fp); + $block_data = fread($getid3->fp, 8); + $offset = 8; + $block_name = substr($block_data, 0, 4); + $block_size = getid3_lib::LittleEndian2Int(substr($block_data, 4, 4)); + + if ($block_name == 'OFRX') { + $block_name = 'OFR '; + } + if (!isset($getid3->info['ofr'][$block_name])) { + $getid3->info['ofr'][$block_name] = array (); + } + $info_ofr_this_block = &$getid3->info['ofr'][$block_name]; + + switch ($block_name) { + case 'OFR ': + + // shortcut + $info_ofr_this_block['offset'] = $block_offset; + $info_ofr_this_block['size'] = $block_size; + + $getid3->info['audio']['encoder'] = 'OptimFROG 4.50 alpha'; + switch ($block_size) { + case 12: + case 15: + // good + break; + + default: + $getid3->warning('"'.$block_name.'" contains more data than expected (expected 12 or 15 bytes, found '.$block_size.' bytes)'); + break; + } + $block_data .= fread($getid3->fp, $block_size); + + $info_ofr_this_block['total_samples'] = getid3_lib::LittleEndian2Int(substr($block_data, $offset, 6)); + $offset += 6; + + $info_ofr_this_block['raw']['sample_type'] = getid3_lib::LittleEndian2Int($block_data{$offset++}); + $info_ofr_this_block['sample_type'] = $this->OptimFROGsampleTypeLookup($info_ofr_this_block['raw']['sample_type']); + + $info_ofr_this_block['channel_config'] = getid3_lib::LittleEndian2Int($block_data{$offset++}); + $info_ofr_this_block['channels'] = $info_ofr_this_block['channel_config']; + + $info_ofr_this_block['sample_rate'] = getid3_lib::LittleEndian2Int(substr($block_data, $offset, 4)); + $offset += 4; + + if ($block_size > 12) { + + // OFR 4.504b or higher + $info_ofr_this_block['channels'] = $this->OptimFROGchannelConfigNumChannelsLookup($info_ofr_this_block['channel_config']); + $info_ofr_this_block['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($block_data, $offset, 2)); + $info_ofr_this_block['encoder'] = $this->OptimFROGencoderNameLookup($info_ofr_this_block['raw']['encoder_id']); + $offset += 2; + + $info_ofr_this_block['raw']['compression'] = getid3_lib::LittleEndian2Int($block_data{$offset++}); + $info_ofr_this_block['compression'] = $this->OptimFROGcompressionLookup($info_ofr_this_block['raw']['compression']); + $info_ofr_this_block['speedup'] = $this->OptimFROGspeedupLookup($info_ofr_this_block['raw']['compression']); + + $getid3->info['audio']['encoder'] = 'OptimFROG '.$info_ofr_this_block['encoder']; + $getid3->info['audio']['encoder_options'] = '--mode '.$info_ofr_this_block['compression']; + + if ((($info_ofr_this_block['raw']['encoder_id'] & 0xF0) >> 4) == 7) { // v4.507 + if (preg_match('/\.ofs$/i', $getid3->filename)) { + // OptimFROG DualStream format is lossy, but as of v4.507 there is no way to tell the difference + // between lossless and lossy other than the file extension. + $getid3->info['audio']['dataformat'] = 'ofs'; + $getid3->info['audio']['lossless'] = true; + } + } + } + + $getid3->info['audio']['channels'] = $info_ofr_this_block['channels']; + $getid3->info['audio']['sample_rate'] = $info_ofr_this_block['sample_rate']; + $getid3->info['audio']['bits_per_sample'] = $this->OptimFROGbitsPerSampleTypeLookup($info_ofr_this_block['raw']['sample_type']); + break; + + + case 'COMP': + // unlike other block types, there CAN be multiple COMP blocks + + $comp_data['offset'] = $block_offset; + $comp_data['size'] = $block_size; + + if ($getid3->info['avdataoffset'] == 0) { + $getid3->info['avdataoffset'] = $block_offset; + } + + // Only interested in first 14 bytes (only first 12 needed for v4.50 alpha), not actual audio data + $block_data .= fread($getid3->fp, 14); + fseek($getid3->fp, $block_size - 14, SEEK_CUR); + + $comp_data['crc_32'] = getid3_lib::LittleEndian2Int(substr($block_data, $offset, 4)); + $offset += 4; + + $comp_data['sample_count'] = getid3_lib::LittleEndian2Int(substr($block_data, $offset, 4)); + $offset += 4; + + $comp_data['raw']['sample_type'] = getid3_lib::LittleEndian2Int($block_data{$offset++}); + $comp_data['sample_type'] = $this->OptimFROGsampleTypeLookup($comp_data['raw']['sample_type']); + + $comp_data['raw']['channel_configuration'] = getid3_lib::LittleEndian2Int($block_data{$offset++}); + $comp_data['channel_configuration'] = $this->OptimFROGchannelConfigurationLookup($comp_data['raw']['channel_configuration']); + + $comp_data['raw']['algorithm_id'] = getid3_lib::LittleEndian2Int(substr($block_data, $offset, 2)); + $offset += 2; + + if ($getid3->info['ofr']['OFR ']['size'] > 12) { + + // OFR 4.504b or higher + $comp_data['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($block_data, $offset, 2)); + $comp_data['encoder'] = $this->OptimFROGencoderNameLookup($comp_data['raw']['encoder_id']); + $offset += 2; + } + + if ($comp_data['crc_32'] == 0x454E4F4E) { + // ASCII value of 'NONE' - placeholder value in v4.50a + $comp_data['crc_32'] = false; + } + + $info_ofr_this_block[] = $comp_data; + break; + + case 'HEAD': + $info_ofr_this_block['offset'] = $block_offset; + $info_ofr_this_block['size'] = $block_size; + + $riff_data .= fread($getid3->fp, $block_size); + break; + + case 'TAIL': + $info_ofr_this_block['offset'] = $block_offset; + $info_ofr_this_block['size'] = $block_size; + + if ($block_size > 0) { + $riff_data .= fread($getid3->fp, $block_size); + } + break; + + case 'RECV': + // block contains no useful meta data - simply note and skip + + $info_ofr_this_block['offset'] = $block_offset; + $info_ofr_this_block['size'] = $block_size; + + fseek($getid3->fp, $block_size, SEEK_CUR); + break; + + + case 'APET': + // APEtag v2 + + $info_ofr_this_block['offset'] = $block_offset; + $info_ofr_this_block['size'] = $block_size; + $getid3->warning('APEtag processing inside OptimFROG not supported in this version ('.GETID3_VERSION.') of getID3()'); + + fseek($getid3->fp, $block_size, SEEK_CUR); + break; + + + case 'MD5 ': + // APEtag v2 + + $info_ofr_this_block['offset'] = $block_offset; + $info_ofr_this_block['size'] = $block_size; + + if ($block_size == 16) { + + $info_ofr_this_block['md5_binary'] = fread($getid3->fp, $block_size); + $info_ofr_this_block['md5_string'] = getid3_lib::PrintHexBytes($info_ofr_this_block['md5_binary'], true, false, false); + $getid3->info['md5_data_source'] = $info_ofr_this_block['md5_string']; + + } else { + + $getid3->warning('Expecting block size of 16 in "MD5 " chunk, found '.$block_size.' instead'); + fseek($getid3->fp, $block_size, SEEK_CUR); + + } + break; + + + default: + $info_ofr_this_block['offset'] = $block_offset; + $info_ofr_this_block['size'] = $block_size; + + $getid3->warning('Unhandled OptimFROG block type "'.$block_name.'" at offset '.$info_ofr_this_block['offset']); + fseek($getid3->fp, $block_size, SEEK_CUR); + break; + } + } + + if (isset($getid3->info['ofr']['TAIL']['offset'])) { + $getid3->info['avdataend'] = $getid3->info['ofr']['TAIL']['offset']; + } + + $getid3->info['playtime_seconds'] = (float)$getid3->info['ofr']['OFR ']['total_samples'] / ($getid3->info['audio']['channels'] * $getid3->info['audio']['sample_rate']); + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + + // move the data chunk after all other chunks (if any) + // so that the RIFF parser doesn't see EOF when trying + // to skip over the data chunk + + $riff_data = substr($riff_data, 0, 36).substr($riff_data, 44).substr($riff_data, 36, 8); + + // Save audio info key + $saved_info_audio = $getid3->info['audio']; + + // Instantiate riff module and analyze string + $riff = new getid3_riff($getid3); + $riff->AnalyzeString($riff_data); + + // Restore info key + $getid3->info['audio'] = $saved_info_audio; + + $getid3->info['fileformat'] = 'ofr'; + + return true; + } + + + + public static function OptimFROGsampleTypeLookup($sample_type) { + + static $lookup = array ( + 0 => 'unsigned int (8-bit)', + 1 => 'signed int (8-bit)', + 2 => 'unsigned int (16-bit)', + 3 => 'signed int (16-bit)', + 4 => 'unsigned int (24-bit)', + 5 => 'signed int (24-bit)', + 6 => 'unsigned int (32-bit)', + 7 => 'signed int (32-bit)', + 8 => 'float 0.24 (32-bit)', + 9 => 'float 16.8 (32-bit)', + 10 => 'float 24.0 (32-bit)' + ); + + return @$lookup[$sample_type]; + } + + + + public static function OptimFROGbitsPerSampleTypeLookup($sample_type) { + + static $lookup = array ( + 0 => 8, + 1 => 8, + 2 => 16, + 3 => 16, + 4 => 24, + 5 => 24, + 6 => 32, + 7 => 32, + 8 => 32, + 9 => 32, + 10 => 32 + ); + + return @$lookup[$sample_type]; + } + + + + public static function OptimFROGchannelConfigurationLookup($channel_configuration) { + + static $lookup = array ( + 0 => 'mono', + 1 => 'stereo' + ); + + return @$lookup[$channel_configuration]; + } + + + + public static function OptimFROGchannelConfigNumChannelsLookup($channel_configuration) { + + static $lookup = array ( + 0 => 1, + 1 => 2 + ); + + return @$lookup[$channel_configuration]; + } + + + + public static function OptimFROGencoderNameLookup($encoder_id) { + + // version = (encoderID >> 4) + 4500 + // system = encoderID & 0xF + + $encoder_version = number_format(((($encoder_id & 0xF0) >> 4) + 4500) / 1000, 3); + $encoder_system_id = ($encoder_id & 0x0F); + + static $lookup = array ( + 0x00 => 'Windows console', + 0x01 => 'Linux console', + 0x0F => 'unknown' + ); + return $encoder_version.' ('.(isset($lookup[$encoder_system_id]) ? $lookup[$encoder_system_id] : 'undefined encoder type (0x'.dechex($encoder_system_id).')').')'; + } + + + + public static function OptimFROGcompressionLookup($compression_id) { + + // mode = compression >> 3 + // speedup = compression & 0x07 + + $compression_mode_id = ($compression_id & 0xF8) >> 3; + //$compression_speed_up_id = ($compression_id & 0x07); + + static $lookup = array ( + 0x00 => 'fast', + 0x01 => 'normal', + 0x02 => 'high', + 0x03 => 'extra', // extranew (some versions) + 0x04 => 'best', // bestnew (some versions) + 0x05 => 'ultra', + 0x06 => 'insane', + 0x07 => 'highnew', + 0x08 => 'extranew', + 0x09 => 'bestnew' + ); + return (isset($lookup[$compression_mode_id]) ? $lookup[$compression_mode_id] : 'undefined mode (0x'.str_pad(dechex($compression_mode_id), 2, '0', STR_PAD_LEFT).')'); + } + + + + public static function OptimFROGspeedupLookup($compression_id) { + + // mode = compression >> 3 + // speedup = compression & 0x07 + + //$compression_mode_id = ($compression_id & 0xF8) >> 3; + $compression_speed_up_id = ($compression_id & 0x07); + + static $lookup = array ( + 0x00 => '1x', + 0x01 => '2x', + 0x02 => '4x' + ); + + return (isset($lookup[$compression_speed_up_id]) ? $lookup[$compression_speed_up_id] : 'undefined mode (0x'.dechex($compression_speed_up_id)); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.rkau.php b/plugins/getId3Plugin/lib/module.audio.rkau.php new file mode 100644 index 0000000..9775a2c --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.rkau.php @@ -0,0 +1,101 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.rkau.php | +// | Module for analyzing RKAU Audio files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.rkau.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_rkau extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $rkau_header = fread($getid3->fp, 20); + + // Magic bytes 'RKA' + + $getid3->info['fileformat'] = 'rkau'; + $getid3->info['audio']['dataformat'] = 'rkau'; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + + // Shortcut + $getid3->info['rkau'] = array (); + $info_rkau = &$getid3->info['rkau']; + + $info_rkau['raw']['version'] = getid3_lib::LittleEndian2Int(substr($rkau_header, 3, 1)); + $info_rkau['version'] = '1.'.str_pad($info_rkau['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT); + if (($info_rkau['version'] > 1.07) || ($info_rkau['version'] < 1.06)) { + throw new getid3_exception('This version of getID3() can only parse RKAU files v1.06 and 1.07 (this file is v'.$info_rkau['version'].')'); + } + + getid3_lib::ReadSequence('LittleEndian2Int', $info_rkau, $rkau_header, 4, + array ( + 'source_bytes' => 4, + 'sample_rate' => 4, + 'channels' => 1, + 'bits_per_sample' => 1 + ) + ); + + $info_rkau['raw']['quality'] = getid3_lib::LittleEndian2Int(substr($rkau_header, 14, 1)); + + $quality = $info_rkau['raw']['quality'] & 0x0F; + + $info_rkau['lossless'] = (($quality == 0) ? true : false); + $info_rkau['compression_level'] = (($info_rkau['raw']['quality'] & 0xF0) >> 4) + 1; + if (!$info_rkau['lossless']) { + $info_rkau['quality_setting'] = $quality; + } + + $info_rkau['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($rkau_header, 15, 1)); + $info_rkau['flags']['joint_stereo'] = (bool)(!($info_rkau['raw']['flags'] & 0x01)); + $info_rkau['flags']['streaming'] = (bool) ($info_rkau['raw']['flags'] & 0x02); + $info_rkau['flags']['vrq_lossy_mode'] = (bool) ($info_rkau['raw']['flags'] & 0x04); + + if ($info_rkau['flags']['streaming']) { + $getid3->info['avdataoffset'] += 20; + $info_rkau['compressed_bytes'] = getid3_lib::LittleEndian2Int(substr($rkau_header, 16, 4)); + } + else { + $getid3->info['avdataoffset'] += 16; + $info_rkau['compressed_bytes'] = $getid3->info['avdataend'] - $getid3->info['avdataoffset'] - 1; + } + // Note: compressed_bytes does not always equal what appears to be the actual number of compressed bytes, + // sometimes it's more, sometimes less. No idea why(?) + + $getid3->info['audio']['lossless'] = $info_rkau['lossless']; + $getid3->info['audio']['channels'] = $info_rkau['channels']; + $getid3->info['audio']['bits_per_sample'] = $info_rkau['bits_per_sample']; + $getid3->info['audio']['sample_rate'] = $info_rkau['sample_rate']; + + $getid3->info['playtime_seconds'] = $info_rkau['source_bytes'] / ($info_rkau['sample_rate'] * $info_rkau['channels'] * ($info_rkau['bits_per_sample'] / 8)); + $getid3->info['audio']['bitrate'] = ($info_rkau['compressed_bytes'] * 8) / $getid3->info['playtime_seconds']; + + return true; + + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.shorten.php b/plugins/getId3Plugin/lib/module.audio.shorten.php new file mode 100644 index 0000000..668a603 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.shorten.php @@ -0,0 +1,205 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.shorten.php | +// | Module for analyzing Shorten Audio files | +// | dependencies: module.audio-video.riff.php | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.shorten.php,v 1.2 2006/06/13 08:44:50 ah Exp $ + + + +class getid3_shorten extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->include_module('audio-video.riff'); + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + $shn_header = fread($getid3->fp, 8); + + // Magic bytes: "ajkg" + + $getid3->info['fileformat'] = 'shn'; + $getid3->info['audio']['dataformat'] = 'shn'; + $getid3->info['audio']['lossless'] = true; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + + $getid3->info['shn']['version'] = getid3_lib::LittleEndian2Int($shn_header{4}); + + fseek($getid3->fp, $getid3->info['avdataend'] - 12, SEEK_SET); + + $seek_table_signature_test = fread($getid3->fp, 12); + + $getid3->info['shn']['seektable']['present'] = (bool)(substr($seek_table_signature_test, 4, 8) == 'SHNAMPSK'); + if ($getid3->info['shn']['seektable']['present']) { + + $getid3->info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($seek_table_signature_test, 0, 4)); + $getid3->info['shn']['seektable']['offset'] = $getid3->info['avdataend'] - $getid3->info['shn']['seektable']['length']; + fseek($getid3->fp, $getid3->info['shn']['seektable']['offset'], SEEK_SET); + $seek_table_magic = fread($getid3->fp, 4); + + if ($seek_table_magic != 'SEEK') { + + throw new getid3_exception('Expecting "SEEK" at offset '.$getid3->info['shn']['seektable']['offset'].', found "'.$seek_table_magic.'"'); + + } else { + + // typedef struct tag_TSeekEntry + // { + // unsigned long SampleNumber; + // unsigned long SHNFileByteOffset; + // unsigned long SHNLastBufferReadPosition; + // unsigned short SHNByteGet; + // unsigned short SHNBufferOffset; + // unsigned short SHNFileBitOffset; + // unsigned long SHNGBuffer; + // unsigned short SHNBitShift; + // long CBuf0[3]; + // long CBuf1[3]; + // long Offset0[4]; + // long Offset1[4]; + // }TSeekEntry; + + $seek_table_data = fread($getid3->fp, $getid3->info['shn']['seektable']['length'] - 16); + $getid3->info['shn']['seektable']['entry_count'] = floor(strlen($seek_table_data) / 80); + + //$getid3->info['shn']['seektable']['entries'] = array (); + //$SeekTableOffset = 0; + //for ($i = 0; $i < $getid3->info['shn']['seektable']['entry_count']; $i++) { + // $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 2)); + // $SeekTableOffset += 2; + // $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 2)); + // $SeekTableOffset += 2; + // $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 2)); + // $SeekTableOffset += 2; + // $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 2)); + // $SeekTableOffset += 2; + // for ($j = 0; $j < 3; $j++) { + // $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // } + // for ($j = 0; $j < 3; $j++) { + // $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // } + // for ($j = 0; $j < 4; $j++) { + // $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // } + // for ($j = 0; $j < 4; $j++) { + // $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($seek_table_data, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // } + // + // $getid3->info['shn']['seektable']['entries'][] = $SeekTableEntry; + //} + + } + + } + + if ((bool)ini_get('safe_mode')) { + throw new getid3_exception('PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files'); + } + + + // Running windows + if ($getid3->windowed) { + + foreach (array ('shorten' => 'shorten.exe', 'cygwin' => 'cygwin1.dll', 'head' => 'head.exe') as $name => $req_filename) { + + $$name = $getid3->option_helperapps_dir.'\\'.$req_filename; + + if (!is_readable($$name)) { + throw new getid3_exception($$name.' does not exist.'); + } + } + + $commandline = $shorten.' -x "'.realpath($getid3->filename).'" - | '.$head.' -c 44'; + } + + // Running UNIX + else { + + static $shorten_exe; + if (!isset($shorten_exe)) { + + // which returns only executeable + if ($shorten_exe = trim(`which shorten`)) { + // great + } + elseif (is_executable('/usr/local/bin/shorten')) { + $shorten_exe = '/usr/local/bin/shorten'; + } + elseif (is_executable('/usr/bin/shorten')) { + $shorten_exe = '/usr/bin/shorten'; + } + } + + if (!$shorten_exe) { + throw new getid3_exception('shorten binary was not found in path or /usr/local/bin or /usr/bin'); + } + + $commandline = $shorten_exe . ' -x '.escapeshellarg(realpath($getid3->filename)).' - | head -c 44'; + } + + $output = `$commandline`; + + if (@$output && substr($output, 12, 4) == 'fmt ') { + + $decoded_wav_format_ex = getid3_riff::RIFFparseWAVEFORMATex(substr($output, 20, 16)); + + $getid3->info['audio']['channels'] = $decoded_wav_format_ex['channels']; + $getid3->info['audio']['bits_per_sample'] = $decoded_wav_format_ex['bits_per_sample']; + $getid3->info['audio']['sample_rate'] = $decoded_wav_format_ex['sample_rate']; + + if (substr($output, 36, 4) == 'data') { + + $getid3->info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 40, 4)) / $decoded_wav_format_ex['raw']['nAvgBytesPerSec']; + + } else { + + throw new getid3_exception('shorten failed to decode DATA chunk to expected location, cannot determine playtime'); + } + + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) / $getid3->info['playtime_seconds']) * 8; + + } else { + + throw new getid3_exception('shorten failed to decode file to WAV for parsing'); + return false; + } + + return true; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.tta.php b/plugins/getId3Plugin/lib/module.audio.tta.php new file mode 100644 index 0000000..6e700e0 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.tta.php @@ -0,0 +1,125 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.tta.php | +// | Module for analyzing TTA Audio files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.tta.php,v 1.1.1.1 2004/08/23 00:01:26 ah Exp $ + + + +class getid3_tta extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['fileformat'] = 'tta'; + $getid3->info['audio']['dataformat'] = 'tta'; + $getid3->info['audio']['lossless'] = true; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $tta_header = fread($getid3->fp, 26); + + $getid3->info['tta']['magic'] = 'TTA'; // Magic bytes + + switch ($tta_header{3}) { + + case "\x01": // TTA v1.x + case "\x02": // TTA v1.x + case "\x03": // TTA v1.x + + // "It was the demo-version of the TTA encoder. There is no released format with such header. TTA encoder v1 is not supported about a year." + $getid3->info['tta']['major_version'] = 1; + $getid3->info['avdataoffset'] += 16; + + getid3_lib::ReadSequence('LittleEndian2Int', $getid3->info['tta'], $tta_header, 4, + array ( + 'channels' => 2, + 'bits_per_sample' => 2, + 'sample_rate' => 4, + 'samples_per_channel' => 4 + ) + ); + $getid3->info['tta']['compression_level'] = ord($tta_header{3}); + + $getid3->info['audio']['encoder_options'] = '-e'.$getid3->info['tta']['compression_level']; + $getid3->info['playtime_seconds'] = $getid3->info['tta']['samples_per_channel'] / $getid3->info['tta']['sample_rate']; + break; + + case '2': // TTA v2.x + // "I have hurried to release the TTA 2.0 encoder. Format documentation is removed from our site. This format still in development. Please wait the TTA2 format, encoder v4." + $getid3->info['tta']['major_version'] = 2; + $getid3->info['avdataoffset'] += 20; + + getid3_lib::ReadSequence('LittleEndian2Int', $getid3->info['tta'], $tta_header, 4, + array ( + 'compression_level' => 2, + 'audio_format' => 2, + 'channels' => 2, + 'bits_per_sample' => 2, + 'sample_rate' => 4, + 'data_length' => 4 + ) + ); + + $getid3->info['audio']['encoder_options'] = '-e'.$getid3->info['tta']['compression_level']; + $getid3->info['playtime_seconds'] = $getid3->info['tta']['data_length'] / $getid3->info['tta']['sample_rate']; + break; + + case '1': // TTA v3.x + // "This is a first stable release of the TTA format. It will be supported by the encoders v3 or higher." + $getid3->info['tta']['major_version'] = 3; + $getid3->info['avdataoffset'] += 26; + + getid3_lib::ReadSequence('LittleEndian2Int', $getid3->info['tta'], $tta_header, 4, + array ( + 'audio_format' => 2, + 'channels' => 2, + 'bits_per_sample'=> 2, + 'sample_rate' => 4, + 'data_length' => 4, + 'crc32_footer' => -4, // string + 'seek_point' => 4 + ) + ); + + $getid3->info['playtime_seconds'] = $getid3->info['tta']['data_length'] / $getid3->info['tta']['sample_rate']; + break; + + default: + throw new getid3_exception('This version of getID3() only knows how to handle TTA v1, v2 and v3 - it may not work correctly with this file which appears to be TTA v'.$tta_header{3}); + return false; + break; + } + + $getid3->info['audio']['encoder'] = 'TTA v'.$getid3->info['tta']['major_version']; + $getid3->info['audio']['bits_per_sample'] = $getid3->info['tta']['bits_per_sample']; + $getid3->info['audio']['sample_rate'] = $getid3->info['tta']['sample_rate']; + $getid3->info['audio']['channels'] = $getid3->info['tta']['channels']; + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + + return true; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.voc.php b/plugins/getId3Plugin/lib/module.audio.voc.php new file mode 100644 index 0000000..226f991 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.voc.php @@ -0,0 +1,240 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.voc.php | +// | Module for analyzing Creative VOC Audio files. | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.voc.php,v 1.2 2004/11/01 03:11:16 ah Exp $ + + + +class getid3_voc extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $original_av_data_offset = $getid3->info['avdataoffset']; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $voc_header= fread($getid3->fp, 26); + + // Magic bytes: 'Creative Voice File' + + $info_audio = &$getid3->info['audio']; + $getid3->info['voc'] = array (); + $info_voc = &$getid3->info['voc']; + + $getid3->info['fileformat'] = 'voc'; + $info_audio['dataformat'] = 'voc'; + $info_audio['bitrate_mode'] = 'cbr'; + $info_audio['lossless'] = true; + $info_audio['channels'] = 1; // might be overriden below + $info_audio['bits_per_sample'] = 8; // might be overriden below + + // byte # Description + // ------ ------------------------------------------ + // 00-12 'Creative Voice File' + // 13 1A (eof to abort printing of file) + // 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation) + // 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) + // 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) + + getid3_lib::ReadSequence('LittleEndian2Int', $info_voc['header'], $voc_header, 20, + array ( + 'datablock_offset' => 2, + 'minor_version' => 1, + 'major_version' => 1 + ) + ); + + do { + $block_offset = ftell($getid3->fp); + $block_data = fread($getid3->fp, 4); + $block_type = ord($block_data{0}); + $block_size = getid3_lib::LittleEndian2Int(substr($block_data, 1, 3)); + $this_block = array (); + + @$info_voc['blocktypes'][$block_type]++; + + switch ($block_type) { + + case 0: // Terminator + // do nothing, we'll break out of the loop down below + break; + + case 1: // Sound data + $block_data .= fread($getid3->fp, 2); + if ($getid3->info['avdataoffset'] <= $original_av_data_offset) { + $getid3->info['avdataoffset'] = ftell($getid3->fp); + } + fseek($getid3->fp, $block_size - 2, SEEK_CUR); + + getid3_lib::ReadSequence('LittleEndian2Int', $this_block, $block_data, 4, + array ( + 'sample_rate_id' => 1, + 'compression_type' => 1 + ) + ); + + $this_block['compression_name'] = getid3_voc::VOCcompressionTypeLookup($this_block['compression_type']); + if ($this_block['compression_type'] <= 3) { + $info_voc['compressed_bits_per_sample'] = (int)(str_replace('-bit', '', $this_block['compression_name'])); + } + + // Less accurate sample_rate calculation than the Extended block (#8) data (but better than nothing if Extended Block is not available) + if (empty($info_audio['sample_rate'])) { + // SR byte = 256 - (1000000 / sample_rate) + $info_audio['sample_rate'] = (int)floor((1000000 / (256 - $this_block['sample_rate_id'])) / $info_audio['channels']); + } + break; + + case 2: // Sound continue + case 3: // Silence + case 4: // Marker + case 6: // Repeat + case 7: // End repeat + // nothing useful, just skip + fseek($getid3->fp, $block_size, SEEK_CUR); + break; + + case 8: // Extended + $block_data .= fread($getid3->fp, 4); + + //00-01 Time Constant: + // Mono: 65536 - (256000000 / sample_rate) + // Stereo: 65536 - (256000000 / (sample_rate * 2)) + getid3_lib::ReadSequence('LittleEndian2Int', $this_block, $block_data, 4, + array ( + 'time_constant' => 2, + 'pack_method' => 1, + 'stereo' => 1 + ) + ); + $this_block['stereo'] = (bool)$this_block['stereo']; + + $info_audio['channels'] = ($this_block['stereo'] ? 2 : 1); + $info_audio['sample_rate'] = (int)floor((256000000 / (65536 - $this_block['time_constant'])) / $info_audio['channels']); + break; + + case 9: // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit + $block_data .= fread($getid3->fp, 12); + if ($getid3->info['avdataoffset'] <= $original_av_data_offset) { + $getid3->info['avdataoffset'] = ftell($getid3->fp); + } + fseek($getid3->fp, $block_size - 12, SEEK_CUR); + + getid3_lib::ReadSequence('LittleEndian2Int', $this_block, $block_data, 4, + array ( + 'sample_rate' => 4, + 'bits_per_sample' => 1, + 'channels' => 1, + 'wFormat' => 2 + ) + ); + + $this_block['compression_name'] = getid3_voc::VOCwFormatLookup($this_block['wFormat']); + if (getid3_voc::VOCwFormatActualBitsPerSampleLookup($this_block['wFormat'])) { + $info_voc['compressed_bits_per_sample'] = getid3_voc::VOCwFormatActualBitsPerSampleLookup($this_block['wFormat']); + } + + $info_audio['sample_rate'] = $this_block['sample_rate']; + $info_audio['bits_per_sample'] = $this_block['bits_per_sample']; + $info_audio['channels'] = $this_block['channels']; + break; + + default: + $getid3->warning('Unhandled block type "'.$block_type.'" at offset '.$block_offset); + fseek($getid3->fp, $block_size, SEEK_CUR); + break; + } + + if (!empty($this_block)) { + $this_block['block_offset'] = $block_offset; + $this_block['block_size'] = $block_size; + $this_block['block_type_id'] = $block_type; + $info_voc['blocks'][] = $this_block; + } + + } while (!feof($getid3->fp) && ($block_type != 0)); + + // Terminator block doesn't have size field, so seek back 3 spaces + fseek($getid3->fp, -3, SEEK_CUR); + + ksort($info_voc['blocktypes']); + + if (!empty($info_voc['compressed_bits_per_sample'])) { + $getid3->info['playtime_seconds'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / ($info_voc['compressed_bits_per_sample'] * $info_audio['channels'] * $info_audio['sample_rate']); + $info_audio['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + } + + return true; + } + + + + public static function VOCcompressionTypeLookup($index) { + + static $lookup = array ( + 0 => '8-bit', + 1 => '4-bit', + 2 => '2.6-bit', + 3 => '2-bit' + ); + return (isset($lookup[$index]) ? $lookup[$index] : 'Multi DAC ('.($index - 3).') channels'); + } + + + + public static function VOCwFormatLookup($index) { + + static $lookup = array ( + 0x0000 => '8-bit unsigned PCM', + 0x0001 => 'Creative 8-bit to 4-bit ADPCM', + 0x0002 => 'Creative 8-bit to 3-bit ADPCM', + 0x0003 => 'Creative 8-bit to 2-bit ADPCM', + 0x0004 => '16-bit signed PCM', + 0x0006 => 'CCITT a-Law', + 0x0007 => 'CCITT u-Law', + 0x2000 => 'Creative 16-bit to 4-bit ADPCM' + ); + return (isset($lookup[$index]) ? $lookup[$index] : false); + } + + + + public static function VOCwFormatActualBitsPerSampleLookup($index) { + + static $lookup = array ( + 0x0000 => 8, + 0x0001 => 4, + 0x0002 => 3, + 0x0003 => 2, + 0x0004 => 16, + 0x0006 => 8, + 0x0007 => 8, + 0x2000 => 4 + ); + return (isset($lookup[$index]) ? $lookup[$index] : false); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.vqf.php b/plugins/getId3Plugin/lib/module.audio.vqf.php new file mode 100644 index 0000000..74f952f --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.vqf.php @@ -0,0 +1,164 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.vqf.php | +// | Module for analyzing VQF Audio files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.vqf.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_vqf extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + // based loosely on code from TTwinVQ by Jurgen Faul + // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html + + $getid3->info['fileformat'] = 'vqf'; + $getid3->info['audio']['dataformat'] = 'vqf'; + $getid3->info['audio']['bitrate_mode'] = 'cbr'; + $getid3->info['audio']['lossless'] = false; + + // Shortcuts + $getid3->info['vqf']['raw'] = array (); + $info_vqf = &$getid3->info['vqf']; + $info_vqf_raw = &$info_vqf['raw']; + + // Get header + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $vqf_header_data = fread($getid3->fp, 16); + + $info_vqf_raw['header_tag'] = 'TWIN'; // Magic bytes + $info_vqf_raw['version'] = substr($vqf_header_data, 4, 8); + $info_vqf_raw['size'] = getid3_lib::BigEndian2Int(substr($vqf_header_data, 12, 4)); + + while (ftell($getid3->fp) < $getid3->info['avdataend']) { + + $chunk_base_offset = ftell($getid3->fp); + $chunk_data = fread($getid3->fp, 8); + $chunk_name = substr($chunk_data, 0, 4); + + if ($chunk_name == 'DATA') { + $getid3->info['avdataoffset'] = $chunk_base_offset; + break; + } + + $chunk_size = getid3_lib::BigEndian2Int(substr($chunk_data, 4, 4)); + if ($chunk_size > ($getid3->info['avdataend'] - ftell($getid3->fp))) { + throw new getid3_exception('Invalid chunk size ('.$chunk_size.') for chunk "'.$chunk_name.'" at offset 8.'); + } + if ($chunk_size > 0) { + $chunk_data .= fread($getid3->fp, $chunk_size); + } + + switch ($chunk_name) { + + case 'COMM': + $info_vqf['COMM'] = array (); + getid3_lib::ReadSequence('BigEndian2Int', &$info_vqf['COMM'], $chunk_data, 8, + array ( + 'channel_mode' => 4, + 'bitrate' => 4, + 'sample_rate' => 4, + 'security_level' => 4 + ) + ); + + $getid3->info['audio']['channels'] = $info_vqf['COMM']['channel_mode'] + 1; + $getid3->info['audio']['sample_rate'] = getid3_vqf::VQFchannelFrequencyLookup($info_vqf['COMM']['sample_rate']); + $getid3->info['audio']['bitrate'] = $info_vqf['COMM']['bitrate'] * 1000; + $getid3->info['audio']['encoder_options'] = 'CBR' . ceil($getid3->info['audio']['bitrate']/1000); + + if ($getid3->info['audio']['bitrate'] == 0) { + throw new getid3_exception('Corrupt VQF file: bitrate_audio == zero'); + } + break; + + case 'NAME': + case 'AUTH': + case '(c) ': + case 'FILE': + case 'COMT': + case 'ALBM': + $info_vqf['comments'][getid3_vqf::VQFcommentNiceNameLookup($chunk_name)][] = trim(substr($chunk_data, 8)); + break; + + case 'DSIZ': + $info_vqf['DSIZ'] = getid3_lib::BigEndian2Int(substr($chunk_data, 8, 4)); + break; + + default: + $getid3->warning('Unhandled chunk type "'.$chunk_name.'" at offset 8'); + break; + } + } + + $getid3->info['playtime_seconds'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['audio']['bitrate']; + + if (isset($info_vqf['DSIZ']) && (($info_vqf['DSIZ'] != ($getid3->info['avdataend'] - $getid3->info['avdataoffset'] - strlen('DATA'))))) { + switch ($info_vqf['DSIZ']) { + case 0: + case 1: + $getid3->warning('Invalid DSIZ value "'.$info_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($info_vqf['DSIZ'] + 1).'.0'); + $getid3->info['audio']['encoder'] = 'Ahead Nero'; + break; + + default: + $getid3->warning('Probable corrupted file - should be '.$info_vqf['DSIZ'].' bytes, actually '.($getid3->info['avdataend'] - $getid3->info['avdataoffset'] - strlen('DATA'))); + break; + } + } + + return true; + } + + + + public static function VQFchannelFrequencyLookup($frequencyid) { + + static $lookup = array ( + 11 => 11025, + 22 => 22050, + 44 => 44100 + ); + return (isset($lookup[$frequencyid]) ? $lookup[$frequencyid] : $frequencyid * 1000); + } + + + + public static function VQFcommentNiceNameLookup($shortname) { + + static $lookup = array ( + 'NAME' => 'title', + 'AUTH' => 'artist', + '(c) ' => 'copyright', + 'FILE' => 'filename', + 'COMT' => 'comment', + 'ALBM' => 'album' + ); + return (isset($lookup[$shortname]) ? $lookup[$shortname] : $shortname); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.wavpack.php b/plugins/getId3Plugin/lib/module.audio.wavpack.php new file mode 100644 index 0000000..c4c617c --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.wavpack.php @@ -0,0 +1,399 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.wavpack.php | +// | module for analyzing WavPack v4.0+ Audio files | +// | dependencies: audio-video.riff | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.wavpack.php,v 1.1 2004/11/01 03:12:10 ah Exp $ + + +class getid3_wavpack extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->include_module('audio-video.riff'); + + $getid3->info['wavpack'] = array (); + $info_wavpack = &$getid3->info['wavpack']; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + while (true) { + + $wavpack_header = fread($getid3->fp, 32); + + if (ftell($getid3->fp) >= $getid3->info['avdataend']) { + break; + } elseif (feof($getid3->fp)) { + break; + } elseif ( + (@$info_wavpack_blockheader['total_samples'] > 0) && + (@$info_wavpack_blockheader['block_samples'] > 0) && + (!isset($info_wavpack['riff_trailer_size']) || ($info_wavpack['riff_trailer_size'] <= 0)) && + ((@$info_wavpack['config_flags']['md5_checksum'] === false) || !empty($getid3->info['md5_data_source']))) { + break; + } + + $block_header_offset = ftell($getid3->fp) - 32; + $block_header_magic = substr($wavpack_header, 0, 4); + $block_header_size = getid3_lib::LittleEndian2Int(substr($wavpack_header, 4, 4)); + + if ($block_header_magic != 'wvpk') { + throw new getid3_exception('Expecting "wvpk" at offset '.$block_header_offset.', found "'.$block_header_magic.'"'); + } + + if ((@$info_wavpack_blockheader['block_samples'] <= 0) || (@$info_wavpack_blockheader['total_samples'] <= 0)) { + + // Also, it is possible that the first block might not have + // any samples (block_samples == 0) and in this case you should skip blocks + // until you find one with samples because the other information (like + // total_samples) are not guaranteed to be correct until (block_samples > 0) + + // Finally, I have defined a format for files in which the length is not known + // (for example when raw files are created using pipes). In these cases + // total_samples will be -1 and you must seek to the final block to determine + // the total number of samples. + + + $getid3->info['audio']['dataformat'] = 'wavpack'; + $getid3->info['fileformat'] = 'wavpack'; + $getid3->info['audio']['lossless'] = true; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + + $info_wavpack['blockheader']['offset'] = $block_header_offset; + $info_wavpack['blockheader']['magic'] = $block_header_magic; + $info_wavpack['blockheader']['size'] = $block_header_size; + $info_wavpack_blockheader = &$info_wavpack['blockheader']; + + if ($info_wavpack_blockheader['size'] >= 0x100000) { + throw new getid3_exception('Expecting WavPack block size less than "0x100000", found "'.$info_wavpack_blockheader['size'].'" at offset '.$info_wavpack_blockheader['offset']); + } + + $info_wavpack_blockheader['minor_version'] = ord($wavpack_header{8}); + $info_wavpack_blockheader['major_version'] = ord($wavpack_header{9}); + + if (($info_wavpack_blockheader['major_version'] != 4) || + (($info_wavpack_blockheader['minor_version'] < 4) && + ($info_wavpack_blockheader['minor_version'] > 16))) { + throw new getid3_exception('Expecting WavPack version between "4.2" and "4.16", found version "'.$info_wavpack_blockheader['major_version'].'.'.$info_wavpack_blockheader['minor_version'].'" at offset '.$info_wavpack_blockheader['offset']); + } + + $info_wavpack_blockheader['track_number'] = ord($wavpack_header{10}); // unused + $info_wavpack_blockheader['index_number'] = ord($wavpack_header{11}); // unused + + getid3_lib::ReadSequence('LittleEndian2Int', $info_wavpack_blockheader, $wavpack_header, 12, + array ( + 'total_samples' => 4, + 'block_index' => 4, + 'block_samples' => 4, + 'flags_raw' => 4, + 'crc' => 4 + ) + ); + + + $info_wavpack_blockheader['flags']['bytes_per_sample'] = 1 + ($info_wavpack_blockheader['flags_raw'] & 0x00000003); + $info_wavpack_blockheader['flags']['mono'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000004); + $info_wavpack_blockheader['flags']['hybrid'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000008); + $info_wavpack_blockheader['flags']['joint_stereo'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000010); + $info_wavpack_blockheader['flags']['cross_decorrelation'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000020); + $info_wavpack_blockheader['flags']['hybrid_noiseshape'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000040); + $info_wavpack_blockheader['flags']['ieee_32bit_float'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000080); + $info_wavpack_blockheader['flags']['int_32bit'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000100); + $info_wavpack_blockheader['flags']['hybrid_bitrate_noise'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000200); + $info_wavpack_blockheader['flags']['hybrid_balance_noise'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000400); + $info_wavpack_blockheader['flags']['multichannel_initial'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00000800); + $info_wavpack_blockheader['flags']['multichannel_final'] = (bool) ($info_wavpack_blockheader['flags_raw'] & 0x00001000); + + $getid3->info['audio']['lossless'] = !$info_wavpack_blockheader['flags']['hybrid']; + } + + + while (!feof($getid3->fp) && (ftell($getid3->fp) < ($block_header_offset + $block_header_size + 8))) { + + $metablock = array('offset'=>ftell($getid3->fp)); + $metablockheader = fread($getid3->fp, 2); + if (feof($getid3->fp)) { + break; + } + $metablock['id'] = ord($metablockheader{0}); + $metablock['function_id'] = ($metablock['id'] & 0x3F); + $metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']); + + // The 0x20 bit in the id of the meta subblocks (which is defined as + // ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that + // if a decoder encounters an id that it does not know about, it uses + // that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set + // then the decoder simply ignores the metadata, but if it is zero + // then the decoder should quit because it means that an understanding + // of the metadata is required to correctly decode the audio. + + $metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20); + $metablock['padded_data'] = (bool) ($metablock['id'] & 0x40); + $metablock['large_block'] = (bool) ($metablock['id'] & 0x80); + if ($metablock['large_block']) { + $metablockheader .= fread($getid3->fp, 2); + } + $metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words + $metablock['data'] = null; + + if ($metablock['size'] > 0) { + + switch ($metablock['function_id']) { + + case 0x21: // ID_RIFF_HEADER + case 0x22: // ID_RIFF_TRAILER + case 0x23: // ID_REPLAY_GAIN + case 0x24: // ID_CUESHEET + case 0x25: // ID_CONFIG_BLOCK + case 0x26: // ID_MD5_CHECKSUM + $metablock['data'] = fread($getid3->fp, $metablock['size']); + + if ($metablock['padded_data']) { + // padded to the nearest even byte + $metablock['size']--; + $metablock['data'] = substr($metablock['data'], 0, -1); + } + break; + + + case 0x00: // ID_DUMMY + case 0x01: // ID_ENCODER_INFO + case 0x02: // ID_DECORR_TERMS + case 0x03: // ID_DECORR_WEIGHTS + case 0x04: // ID_DECORR_SAMPLES + case 0x05: // ID_ENTROPY_VARS + case 0x06: // ID_HYBRID_PROFILE + case 0x07: // ID_SHAPING_WEIGHTS + case 0x08: // ID_FLOAT_INFO + case 0x09: // ID_INT32_INFO + case 0x0A: // ID_WV_BITSTREAM + case 0x0B: // ID_WVC_BITSTREAM + case 0x0C: // ID_WVX_BITSTREAM + case 0x0D: // ID_CHANNEL_INFO + fseek($getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); + break; + + + default: + $getid3->warning('Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset']); + fseek($getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); + break; + } + + + switch ($metablock['function_id']) { + + case 0x21: // ID_RIFF_HEADER + + $original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4)); + + // Clone getid3 + $clone = clone $getid3; + + // Analyze clone by string + $riff = new getid3_riff($clone); + $riff->AnalyzeString($metablock['data']); + + // Import from clone and destroy + $metablock['riff'] = $clone->info['riff']; + $getid3->warnings($clone->warnings()); + unset($clone); + + // Save RIFF header - we may need it later for RIFF footer parsing + $this->riff_header = $metablock['data']; + + $metablock['riff']['original_filesize'] = $original_wav_filesize; + $info_wavpack['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size']; + + $getid3->info['audio']['sample_rate'] = $metablock['riff']['raw']['fmt ']['nSamplesPerSec']; + $getid3->info['playtime_seconds'] = $info_wavpack_blockheader['total_samples'] / $getid3->info['audio']['sample_rate']; + + // Safe RIFF header in case there's a RIFF footer later + $metablock_riff_header = $metablock['data']; + break; + + + case 0x22: // ID_RIFF_TRAILER + + $metablock_riff_footer = $metablock_riff_header.$metablock['data']; + + $start_offset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2); + + $ftell_old = ftell($getid3->fp); + + // Clone getid3 + $clone = clone $getid3; + + // Call public method that really should be private + $riff = new getid3_riff($clone); + $metablock['riff'] = $riff->ParseRIFF($start_offset, $start_offset + $metablock['size']); + unset($clone); + + fseek($getid3->fp, $ftell_old, SEEK_SET); + + if (!empty($metablock['riff']['INFO'])) { + getid3_riff::RIFFCommentsParse($metablock['riff']['INFO'], $metablock['comments']); + $getid3->info['tags']['riff'] = $metablock['comments']; + } + break; + + + case 0x23: // ID_REPLAY_GAIN + $getid3->warning('WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']); + break; + + + case 0x24: // ID_CUESHEET + $getid3->warning('WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']); + break; + + + case 0x25: // ID_CONFIG_BLOCK + $metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3)); + + $metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats + $metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000002); // fast mode + $metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000004); // double fast + $metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x000008); // high quality mode + $metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x000010); // double high (not used yet) + $metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample + $metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x000040); // automatic noise shaping + $metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x000080); // shaping mode specified + $metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified + $metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x000200); // copy file-time from source + $metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x000400); // create executable + $metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x000800); // create correction file + $metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x001000); // maximize bybrid compression + $metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode + $metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet) + $metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode + $metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x010000); // obsolete (for information) + $metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x020000); // extra processing mode + $metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints + $metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature + $metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000); // don't report progress % + + $info_wavpack['config_flags'] = $metablock['flags']; + + $getid3->info['audio']['encoder_options'] = trim( + ($info_wavpack_blockheader['flags']['hybrid'] ? ' -b???' : '') . + ($metablock['flags']['adobe_mode'] ? ' -a' : '') . + ($metablock['flags']['optimize_wvc'] ? ' -cc' : '') . + ($metablock['flags']['create_exe'] ? ' -e' : '') . + ($metablock['flags']['fast_flag'] ? ' -f' : '') . + ($metablock['flags']['joint_override'] ? ' -j?' : '') . + ($metablock['flags']['high_flag'] ? ' -h' : '') . + ($metablock['flags']['md5_checksum'] ? ' -m' : '') . + ($metablock['flags']['calc_noise'] ? ' -n' : '') . + ($metablock['flags']['shape_override'] ? ' -s?' : '') . + ($metablock['flags']['extra_mode'] ? ' -x?' : '') + ); + if (!$getid3->info['audio']['encoder_options']) { + unset($getid3->info['audio']['encoder_options']); + } + break; + + + case 0x26: // ID_MD5_CHECKSUM + if (strlen($metablock['data']) == 16) { + $getid3->info['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false)); + } else { + $getid3->warning('Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock['offset'].', but found '.strlen($metablock['data']).' bytes'); + } + break; + + + case 0x00: // ID_DUMMY + case 0x01: // ID_ENCODER_INFO + case 0x02: // ID_DECORR_TERMS + case 0x03: // ID_DECORR_WEIGHTS + case 0x04: // ID_DECORR_SAMPLES + case 0x05: // ID_ENTROPY_VARS + case 0x06: // ID_HYBRID_PROFILE + case 0x07: // ID_SHAPING_WEIGHTS + case 0x08: // ID_FLOAT_INFO + case 0x09: // ID_INT32_INFO + case 0x0A: // ID_WV_BITSTREAM + case 0x0B: // ID_WVC_BITSTREAM + case 0x0C: // ID_WVX_BITSTREAM + case 0x0D: // ID_CHANNEL_INFO + unset($metablock); + break; + } + + } + + if (!empty($metablock)) { + $info_wavpack['metablocks'][] = $metablock; + } + + } + + } + + $getid3->info['audio']['encoder'] = 'WavPack v'.$info_wavpack_blockheader['major_version'].'.'.str_pad($info_wavpack_blockheader['minor_version'], 2, '0', STR_PAD_LEFT); + $getid3->info['audio']['bits_per_sample'] = $info_wavpack_blockheader['flags']['bytes_per_sample'] * 8; + $getid3->info['audio']['channels'] = ($info_wavpack_blockheader['flags']['mono'] ? 1 : 2); + + if (@$getid3->info['playtime_seconds']) { + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + } else { + $getid3->info['audio']['dataformat'] = 'wvc'; + } + + return true; + } + + + + public static function WavPackMetablockNameLookup($id) { + + static $lookup = array( + 0x00 => 'Dummy', + 0x01 => 'Encoder Info', + 0x02 => 'Decorrelation Terms', + 0x03 => 'Decorrelation Weights', + 0x04 => 'Decorrelation Samples', + 0x05 => 'Entropy Variables', + 0x06 => 'Hybrid Profile', + 0x07 => 'Shaping Weights', + 0x08 => 'Float Info', + 0x09 => 'Int32 Info', + 0x0A => 'WV Bitstream', + 0x0B => 'WVC Bitstream', + 0x0C => 'WVX Bitstream', + 0x0D => 'Channel Info', + 0x21 => 'RIFF header', + 0x22 => 'RIFF trailer', + 0x23 => 'Replay Gain', + 0x24 => 'Cuesheet', + 0x25 => 'Config Block', + 0x26 => 'MD5 Checksum', + ); + + return (@$lookup[$id]); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.audio.xiph.php b/plugins/getId3Plugin/lib/module.audio.xiph.php new file mode 100644 index 0000000..7145b9e --- /dev/null +++ b/plugins/getId3Plugin/lib/module.audio.xiph.php @@ -0,0 +1,852 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.audio.xiph.php | +// | Module for analyzing Xiph.org audio file formats: | +// | Ogg Vorbis, FLAC, OggFLAC and Speex - not Ogg Theora | +// | dependencies: module.lib.image_size.php (optional) | +// +----------------------------------------------------------------------+ +// +// $Id: module.audio.xiph.php,v 1.2 2006/06/24 22:58:30 ah Exp $ + + + +class getid3_xiph extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + if ($getid3->option_tags_images) { + $getid3->include_module('lib.image_size'); + } + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + $magic = fread($getid3->fp, 4); + + if ($magic == 'OggS') { + return $this->ParseOgg(); + } + + if ($magic == 'fLaC') { + return $this->ParseFLAC(); + } + + } + + + + private function ParseOgg() { + + $getid3 = $this->getid3; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + $getid3->info['audio'] = $getid3->info['ogg'] = array (); + $info_ogg = &$getid3->info['ogg']; + $info_audio = &$getid3->info['audio']; + + $getid3->info['fileformat'] = 'ogg'; + + + //// Page 1 - Stream Header + + $ogg_page_info = $this->ParseOggPageHeader(); + $info_ogg['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info; + + if (ftell($getid3->fp) >= getid3::FREAD_BUFFER_SIZE) { + throw new getid3_exception('Could not find start of Ogg page in the first '.getid3::FREAD_BUFFER_SIZE.' bytes (this might not be an Ogg file?)'); + } + + $file_data = fread($getid3->fp, $ogg_page_info['page_length']); + $file_data_offset = 0; + + + // OggFLAC + if (substr($file_data, 0, 4) == 'fLaC') { + + $info_audio['dataformat'] = 'flac'; + $info_audio['bitrate_mode'] = 'vbr'; + $info_audio['lossless'] = true; + + } + + + // Ogg Vorbis + elseif (substr($file_data, 1, 6) == 'vorbis') { + + $info_audio['dataformat'] = 'vorbis'; + $info_audio['lossless'] = false; + + $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int($file_data[0]); + $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['stream_type'] = substr($file_data, 1, 6); // hard-coded to 'vorbis' + + getid3_lib::ReadSequence('LittleEndian2Int', $info_ogg, $file_data, 7, + array ( + 'bitstreamversion' => 4, + 'numberofchannels' => 1, + 'samplerate' => 4, + 'bitrate_max' => 4, + 'bitrate_nominal' => 4, + 'bitrate_min' => 4 + ) + ); + + $n28 = getid3_lib::LittleEndian2Int($file_data{28}); + $info_ogg['blocksize_small'] = pow(2, $n28 & 0x0F); + $info_ogg['blocksize_large'] = pow(2, ($n28 & 0xF0) >> 4); + $info_ogg['stop_bit'] = $n28; + + $info_audio['channels'] = $info_ogg['numberofchannels']; + $info_audio['sample_rate'] = $info_ogg['samplerate']; + + $info_audio['bitrate_mode'] = 'vbr'; // overridden if actually abr + + if ($info_ogg['bitrate_max'] == 0xFFFFFFFF) { + unset($info_ogg['bitrate_max']); + $info_audio['bitrate_mode'] = 'abr'; + } + + if ($info_ogg['bitrate_nominal'] == 0xFFFFFFFF) { + unset($info_ogg['bitrate_nominal']); + } + + if ($info_ogg['bitrate_min'] == 0xFFFFFFFF) { + unset($info_ogg['bitrate_min']); + $info_audio['bitrate_mode'] = 'abr'; + } + } + + + // Speex + elseif (substr($file_data, 0, 8) == 'Speex ') { + + // http://www.speex.org/manual/node10.html + + $info_audio['dataformat'] = 'speex'; + $getid3->info['mime_type'] = 'audio/speex'; + $info_audio['bitrate_mode'] = 'abr'; + $info_audio['lossless'] = false; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_ogg['pageheader'][$ogg_page_info['page_seqno']], $file_data, 0, + array ( + 'speex_string' => -8, // hard-coded to 'Speex ' + 'speex_version' => -20, // string + 'speex_version_id' => 4, + 'header_size' => 4, + 'rate' => 4, + 'mode' => 4, + 'mode_bitstream_version' => 4, + 'nb_channels' => 4, + 'bitrate' => 4, + 'framesize' => 4, + 'vbr' => 4, + 'frames_per_packet' => 4, + 'extra_headers' => 4, + 'reserved1' => 4, + 'reserved2' => 4 + ) + ); + + $getid3->info['speex']['speex_version'] = trim($info_ogg['pageheader'][$ogg_page_info['page_seqno']]['speex_version']); + $getid3->info['speex']['sample_rate'] = $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['rate']; + $getid3->info['speex']['channels'] = $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['nb_channels']; + $getid3->info['speex']['vbr'] = (bool)$info_ogg['pageheader'][$ogg_page_info['page_seqno']]['vbr']; + $getid3->info['speex']['band_type'] = getid3_xiph::SpeexBandModeLookup($info_ogg['pageheader'][$ogg_page_info['page_seqno']]['mode']); + + $info_audio['sample_rate'] = $getid3->info['speex']['sample_rate']; + $info_audio['channels'] = $getid3->info['speex']['channels']; + + if ($getid3->info['speex']['vbr']) { + $info_audio['bitrate_mode'] = 'vbr'; + } + } + + // Unsupported Ogg file + else { + + throw new getid3_exception('Expecting either "Speex " or "vorbis" identifier strings, found neither'); + } + + + //// Page 2 - Comment Header + + $ogg_page_info = $this->ParseOggPageHeader(); + $info_ogg['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info; + + switch ($info_audio['dataformat']) { + + case 'vorbis': + $file_data = fread($getid3->fp, $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['page_length']); + $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($file_data, 0, 1)); + $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['stream_type'] = substr($file_data, 1, 6); // hard-coded to 'vorbis' + $this->ParseVorbisCommentsFilepointer(); + break; + + case 'flac': + if (!$this->FLACparseMETAdata()) { + throw new getid3_exception('Failed to parse FLAC headers'); + } + break; + + case 'speex': + fseek($getid3->fp, $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['page_length'], SEEK_CUR); + $this->ParseVorbisCommentsFilepointer(); + break; + } + + + //// Last Page - Number of Samples + + fseek($getid3->fp, max($getid3->info['avdataend'] - getid3::FREAD_BUFFER_SIZE, 0), SEEK_SET); + $last_chunk_of_ogg = strrev(fread($getid3->fp, getid3::FREAD_BUFFER_SIZE)); + + if ($last_OggS_postion = strpos($last_chunk_of_ogg, 'SggO')) { + fseek($getid3->fp, $getid3->info['avdataend'] - ($last_OggS_postion + strlen('SggO')), SEEK_SET); + $getid3->info['avdataend'] = ftell($getid3->fp); + $info_ogg['pageheader']['eos'] = $this->ParseOggPageHeader(); + $info_ogg['samples'] = $info_ogg['pageheader']['eos']['pcm_abs_position']; + $info_ogg['bitrate_average'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / ($info_ogg['samples'] / $info_audio['sample_rate']); + } + + if (!empty($info_ogg['bitrate_average'])) { + $info_audio['bitrate'] = $info_ogg['bitrate_average']; + } elseif (!empty($info_ogg['bitrate_nominal'])) { + $info_audio['bitrate'] = $info_ogg['bitrate_nominal']; + } elseif (!empty($info_ogg['bitrate_min']) && !empty($info_ogg['bitrate_max'])) { + $info_audio['bitrate'] = ($info_ogg['bitrate_min'] + $info_ogg['bitrate_max']) / 2; + } + if (isset($info_audio['bitrate']) && !isset($getid3->info['playtime_seconds'])) { + $getid3->info['playtime_seconds'] = (float)((($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $info_audio['bitrate']); + } + + if (isset($info_ogg['vendor'])) { + $info_audio['encoder'] = preg_replace('/^Encoded with /', '', $info_ogg['vendor']); + + // Vorbis only + if ($info_audio['dataformat'] == 'vorbis') { + + // Vorbis 1.0 starts with Xiph.Org + if (preg_match('/^Xiph.Org/', $info_audio['encoder'])) { + + if ($info_audio['bitrate_mode'] == 'abr') { + + // Set -b 128 on abr files + $info_audio['encoder_options'] = '-b '.round($info_ogg['bitrate_nominal'] / 1000); + + } elseif (($info_audio['bitrate_mode'] == 'vbr') && ($info_audio['channels'] == 2) && ($info_audio['sample_rate'] >= 44100) && ($info_audio['sample_rate'] <= 48000)) { + // Set -q N on vbr files + $info_audio['encoder_options'] = '-q '.getid3_xiph::GetQualityFromNominalBitrate($info_ogg['bitrate_nominal']); + } + } + + if (empty($info_audio['encoder_options']) && !empty($info_ogg['bitrate_nominal'])) { + $info_audio['encoder_options'] = 'Nominal bitrate: '.intval(round($info_ogg['bitrate_nominal'] / 1000)).'kbps'; + } + } + } + + return true; + } + + + + private function ParseOggPageHeader() { + + $getid3 = $this->getid3; + + // http://xiph.org/ogg/vorbis/doc/framing.html + $ogg_header['page_start_offset'] = ftell($getid3->fp); // where we started from in the file + + $file_data = fread($getid3->fp, getid3::FREAD_BUFFER_SIZE); + $file_data_offset = 0; + + while ((substr($file_data, $file_data_offset++, 4) != 'OggS')) { + if ((ftell($getid3->fp) - $ogg_header['page_start_offset']) >= getid3::FREAD_BUFFER_SIZE) { + // should be found before here + return false; + } + if ((($file_data_offset + 28) > strlen($file_data)) || (strlen($file_data) < 28)) { + if (feof($getid3->fp) || (($file_data .= fread($getid3->fp, getid3::FREAD_BUFFER_SIZE)) === false)) { + // get some more data, unless eof, in which case fail + return false; + } + } + } + + $file_data_offset += 3; // page, delimited by 'OggS' + + getid3_lib::ReadSequence('LittleEndian2Int', $ogg_header, $file_data, $file_data_offset, + array ( + 'stream_structver' => 1, + 'flags_raw' => 1, + 'pcm_abs_position' => 8, + 'stream_serialno' => 4, + 'page_seqno' => 4, + 'page_checksum' => 4, + 'page_segments' => 1 + ) + ); + + $file_data_offset += 23; + + $ogg_header['flags']['fresh'] = (bool)($ogg_header['flags_raw'] & 0x01); // fresh packet + $ogg_header['flags']['bos'] = (bool)($ogg_header['flags_raw'] & 0x02); // first page of logical bitstream (bos) + $ogg_header['flags']['eos'] = (bool)($ogg_header['flags_raw'] & 0x04); // last page of logical bitstream (eos) + + $ogg_header['page_length'] = 0; + for ($i = 0; $i < $ogg_header['page_segments']; $i++) { + $ogg_header['segment_table'][$i] = getid3_lib::LittleEndian2Int($file_data{$file_data_offset++}); + $ogg_header['page_length'] += $ogg_header['segment_table'][$i]; + } + $ogg_header['header_end_offset'] = $ogg_header['page_start_offset'] + $file_data_offset; + $ogg_header['page_end_offset'] = $ogg_header['header_end_offset'] + $ogg_header['page_length']; + fseek($getid3->fp, $ogg_header['header_end_offset'], SEEK_SET); + + return $ogg_header; + } + + + + private function ParseVorbisCommentsFilepointer() { + + $getid3 = $this->getid3; + + $original_offset = ftell($getid3->fp); + $comment_start_offset = $original_offset; + $comment_data_offset = 0; + $vorbis_comment_page = 1; + + switch ($getid3->info['audio']['dataformat']) { + + case 'vorbis': + $comment_start_offset = $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_start_offset']; // Second Ogg page, after header block + fseek($getid3->fp, $comment_start_offset, SEEK_SET); + $comment_data_offset = 27 + $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_segments']; + $comment_data = fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1) + $comment_data_offset); + $comment_data_offset += (strlen('vorbis') + 1); + break; + + + case 'flac': + fseek($getid3->fp, $getid3->info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4, SEEK_SET); + $comment_data = fread($getid3->fp, $getid3->info['flac']['VORBIS_COMMENT']['raw']['block_length']); + break; + + + case 'speex': + $comment_start_offset = $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_start_offset']; // Second Ogg page, after header block + fseek($getid3->fp, $comment_start_offset, SEEK_SET); + $comment_data_offset = 27 + $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_segments']; + $comment_data = fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1) + $comment_data_offset); + break; + + + default: + return false; + } + + $vendor_size = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4)); + $comment_data_offset += 4; + + $getid3->info['ogg']['vendor'] = substr($comment_data, $comment_data_offset, $vendor_size); + $comment_data_offset += $vendor_size; + + $comments_count = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4)); + $comment_data_offset += 4; + + $getid3->info['avdataoffset'] = $comment_start_offset + $comment_data_offset; + + for ($i = 0; $i < $comments_count; $i++) { + + $getid3->info['ogg']['comments_raw'][$i]['dataoffset'] = $comment_start_offset + $comment_data_offset; + + if (ftell($getid3->fp) < ($getid3->info['ogg']['comments_raw'][$i]['dataoffset'] + 4)) { + $vorbis_comment_page++; + + $ogg_page_info = $this->ParseOggPageHeader(); + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info; + + // First, save what we haven't read yet + $as_yet_unused_data = substr($comment_data, $comment_data_offset); + + // Then take that data off the end + $comment_data = substr($comment_data, 0, $comment_data_offset); + + // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct + $comment_data .= str_repeat("\x00", 27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']); + $comment_data_offset += (27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']); + + // Finally, stick the unused data back on the end + $comment_data .= $as_yet_unused_data; + + $comment_data .= fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1)); + } + $getid3->info['ogg']['comments_raw'][$i]['size'] = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4)); + + // replace avdataoffset with position just after the last vorbiscomment + $getid3->info['avdataoffset'] = $getid3->info['ogg']['comments_raw'][$i]['dataoffset'] + $getid3->info['ogg']['comments_raw'][$i]['size'] + 4; + + $comment_data_offset += 4; + while ((strlen($comment_data) - $comment_data_offset) < $getid3->info['ogg']['comments_raw'][$i]['size']) { + + if (($getid3->info['ogg']['comments_raw'][$i]['size'] > $getid3->info['avdataend']) || ($getid3->info['ogg']['comments_raw'][$i]['size'] < 0)) { + throw new getid3_exception('Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($getid3->info['ogg']['comments_raw'][$i]['size']).' bytes) - aborting reading comments'); + } + + $vorbis_comment_page++; + + $ogg_page_info = $this->ParseOggPageHeader(); + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info; + + // First, save what we haven't read yet + $as_yet_unused_data = substr($comment_data, $comment_data_offset); + + // Then take that data off the end + $comment_data = substr($comment_data, 0, $comment_data_offset); + + // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct + $comment_data .= str_repeat("\x00", 27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']); + $comment_data_offset += (27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']); + + // Finally, stick the unused data back on the end + $comment_data .= $as_yet_unused_data; + + //$comment_data .= fread($getid3->fp, $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_length']); + $comment_data .= fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1)); + + //$filebaseoffset += $ogg_page_info['header_end_offset'] - $ogg_page_info['page_start_offset']; + } + $comment_string = substr($comment_data, $comment_data_offset, $getid3->info['ogg']['comments_raw'][$i]['size']); + $comment_data_offset += $getid3->info['ogg']['comments_raw'][$i]['size']; + + if (!$comment_string) { + + // no comment? + $getid3->warning('Blank Ogg comment ['.$i.']'); + + } elseif (strstr($comment_string, '=')) { + + $comment_exploded = explode('=', $comment_string, 2); + $getid3->info['ogg']['comments_raw'][$i]['key'] = strtoupper($comment_exploded[0]); + $getid3->info['ogg']['comments_raw'][$i]['value'] = @$comment_exploded[1]; + $getid3->info['ogg']['comments_raw'][$i]['data'] = base64_decode($getid3->info['ogg']['comments_raw'][$i]['value']); + + $getid3->info['ogg']['comments'][strtolower($getid3->info['ogg']['comments_raw'][$i]['key'])][] = $getid3->info['ogg']['comments_raw'][$i]['value']; + + if ($getid3->option_tags_images) { + $image_chunk_check = getid3_lib_image_size::get($getid3->info['ogg']['comments_raw'][$i]['data']); + $getid3->info['ogg']['comments_raw'][$i]['image_mime'] = image_type_to_mime_type($image_chunk_check[2]); + } + + if (!@$getid3->info['ogg']['comments_raw'][$i]['image_mime'] || ($getid3->info['ogg']['comments_raw'][$i]['image_mime'] == 'application/octet-stream')) { + unset($getid3->info['ogg']['comments_raw'][$i]['image_mime']); + unset($getid3->info['ogg']['comments_raw'][$i]['data']); + } + + + } else { + + $getid3->warning('[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$comment_string); + } + } + + + // Replay Gain Adjustment + // http://privatewww.essex.ac.uk/~djmrob/replaygain/ + if (isset($getid3->info['ogg']['comments']) && is_array($getid3->info['ogg']['comments'])) { + foreach ($getid3->info['ogg']['comments'] as $index => $commentvalue) { + switch ($index) { + case 'rg_audiophile': + case 'replaygain_album_gain': + $getid3->info['replay_gain']['album']['adjustment'] = (float)$commentvalue[0]; + unset($getid3->info['ogg']['comments'][$index]); + break; + + case 'rg_radio': + case 'replaygain_track_gain': + $getid3->info['replay_gain']['track']['adjustment'] = (float)$commentvalue[0]; + unset($getid3->info['ogg']['comments'][$index]); + break; + + case 'replaygain_album_peak': + $getid3->info['replay_gain']['album']['peak'] = (float)$commentvalue[0]; + unset($getid3->info['ogg']['comments'][$index]); + break; + + case 'rg_peak': + case 'replaygain_track_peak': + $getid3->info['replay_gain']['track']['peak'] = (float)$commentvalue[0]; + unset($getid3->info['ogg']['comments'][$index]); + break; + } + } + } + + fseek($getid3->fp, $original_offset, SEEK_SET); + + return true; + } + + + + private function ParseFLAC() { + + $getid3 = $this->getid3; + + // http://flac.sourceforge.net/format.html + + $getid3->info['fileformat'] = 'flac'; + $getid3->info['audio']['dataformat'] = 'flac'; + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + $getid3->info['audio']['lossless'] = true; + + return $this->FLACparseMETAdata(); + } + + + + private function FLACparseMETAdata() { + + $getid3 = $this->getid3; + + do { + + $meta_data_block_offset = ftell($getid3->fp); + $meta_data_block_header = fread($getid3->fp, 4); + $meta_data_last_block_flag = (bool)(getid3_lib::BigEndian2Int($meta_data_block_header[0]) & 0x80); + $meta_data_block_type = getid3_lib::BigEndian2Int($meta_data_block_header[0]) & 0x7F; + $meta_data_block_length = getid3_lib::BigEndian2Int(substr($meta_data_block_header, 1, 3)); + $meta_data_block_type_text = getid3_xiph::FLACmetaBlockTypeLookup($meta_data_block_type); + + if ($meta_data_block_length < 0) { + throw new getid3_exception('corrupt or invalid METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$meta_data_block_type.') at offset '.$meta_data_block_offset); + } + + $getid3->info['flac'][$meta_data_block_type_text]['raw'] = array ( + 'offset' => $meta_data_block_offset, + 'last_meta_block' => $meta_data_last_block_flag, + 'block_type' => $meta_data_block_type, + 'block_type_text' => $meta_data_block_type_text, + 'block_length' => $meta_data_block_length, + 'block_data' => @fread($getid3->fp, $meta_data_block_length) + ); + $getid3->info['avdataoffset'] = ftell($getid3->fp); + + switch ($meta_data_block_type_text) { + + case 'STREAMINFO': + if (!$this->FLACparseSTREAMINFO($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { + return false; + } + break; + + case 'PADDING': + // ignore + break; + + case 'APPLICATION': + if (!$this->FLACparseAPPLICATION($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { + return false; + } + break; + + case 'SEEKTABLE': + if (!$this->FLACparseSEEKTABLE($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { + return false; + } + break; + + case 'VORBIS_COMMENT': + $old_offset = ftell($getid3->fp); + fseek($getid3->fp, 0 - $meta_data_block_length, SEEK_CUR); + $this->ParseVorbisCommentsFilepointer($getid3->fp, $getid3->info); + fseek($getid3->fp, $old_offset, SEEK_SET); + break; + + case 'CUESHEET': + if (!$this->FLACparseCUESHEET($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { + return false; + } + break; + + default: + $getid3->warning('Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$meta_data_block_type.') at offset '.$meta_data_block_offset); + } + + } while ($meta_data_last_block_flag === false); + + + if (isset($getid3->info['flac']['STREAMINFO'])) { + $getid3->info['flac']['compressed_audio_bytes'] = $getid3->info['avdataend'] - $getid3->info['avdataoffset']; + $getid3->info['flac']['uncompressed_audio_bytes'] = $getid3->info['flac']['STREAMINFO']['samples_stream'] * $getid3->info['flac']['STREAMINFO']['channels'] * ($getid3->info['flac']['STREAMINFO']['bits_per_sample'] / 8); + $getid3->info['flac']['compression_ratio'] = $getid3->info['flac']['compressed_audio_bytes'] / $getid3->info['flac']['uncompressed_audio_bytes']; + } + + // set md5_data_source - built into flac 0.5+ + if (isset($getid3->info['flac']['STREAMINFO']['audio_signature'])) { + + if ($getid3->info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) { + $getid3->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)'); + + } else { + + $getid3->info['md5_data_source'] = ''; + $md5 = $getid3->info['flac']['STREAMINFO']['audio_signature']; + for ($i = 0; $i < strlen($md5); $i++) { + $getid3->info['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT); + } + if (!preg_match('/^[0-9a-f]{32}$/', $getid3->info['md5_data_source'])) { + unset($getid3->info['md5_data_source']); + } + + } + + } + + $getid3->info['audio']['bits_per_sample'] = $getid3->info['flac']['STREAMINFO']['bits_per_sample']; + if ($getid3->info['audio']['bits_per_sample'] == 8) { + // special case + // must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value + // MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed + $getid3->warning('FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file'); + } + if (!empty($getid3->info['ogg']['vendor'])) { + $getid3->info['audio']['encoder'] = $getid3->info['ogg']['vendor']; + } + + return true; + } + + + + private function FLACparseSTREAMINFO($meta_data_block_data) { + + $getid3 = $this->getid3; + + getid3_lib::ReadSequence('BigEndian2Int', $getid3->info['flac']['STREAMINFO'], $meta_data_block_data, 0, + array ( + 'min_block_size' => 2, + 'max_block_size' => 2, + 'min_frame_size' => 3, + 'max_frame_size' => 3 + ) + ); + + $sample_rate_channels_sample_bits_stream_samples = getid3_lib::BigEndian2Bin(substr($meta_data_block_data, 10, 8)); + + $getid3->info['flac']['STREAMINFO']['sample_rate'] = bindec(substr($sample_rate_channels_sample_bits_stream_samples, 0, 20)); + $getid3->info['flac']['STREAMINFO']['channels'] = bindec(substr($sample_rate_channels_sample_bits_stream_samples, 20, 3)) + 1; + $getid3->info['flac']['STREAMINFO']['bits_per_sample'] = bindec(substr($sample_rate_channels_sample_bits_stream_samples, 23, 5)) + 1; + $getid3->info['flac']['STREAMINFO']['samples_stream'] = bindec(substr($sample_rate_channels_sample_bits_stream_samples, 28, 36)); // bindec() returns float in case of int overrun + $getid3->info['flac']['STREAMINFO']['audio_signature'] = substr($meta_data_block_data, 18, 16); + + if (!empty($getid3->info['flac']['STREAMINFO']['sample_rate'])) { + + $getid3->info['audio']['bitrate_mode'] = 'vbr'; + $getid3->info['audio']['sample_rate'] = $getid3->info['flac']['STREAMINFO']['sample_rate']; + $getid3->info['audio']['channels'] = $getid3->info['flac']['STREAMINFO']['channels']; + $getid3->info['audio']['bits_per_sample'] = $getid3->info['flac']['STREAMINFO']['bits_per_sample']; + $getid3->info['playtime_seconds'] = $getid3->info['flac']['STREAMINFO']['samples_stream'] / $getid3->info['flac']['STREAMINFO']['sample_rate']; + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; + + } else { + + throw new getid3_exception('Corrupt METAdata block: STREAMINFO'); + } + + return true; + } + + + + private function FLACparseAPPLICATION($meta_data_block_data) { + + $getid3 = $this->getid3; + + $application_id = getid3_lib::BigEndian2Int(substr($meta_data_block_data, 0, 4)); + + $getid3->info['flac']['APPLICATION'][$application_id]['name'] = getid3_xiph::FLACapplicationIDLookup($application_id); + $getid3->info['flac']['APPLICATION'][$application_id]['data'] = substr($meta_data_block_data, 4); + + return true; + } + + + + private function FLACparseSEEKTABLE($meta_data_block_data) { + + $getid3 = $this->getid3; + + $offset = 0; + $meta_data_block_length = strlen($meta_data_block_data); + while ($offset < $meta_data_block_length) { + $sample_number_string = substr($meta_data_block_data, $offset, 8); + $offset += 8; + if ($sample_number_string == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF") { + + // placeholder point + @$getid3->info['flac']['SEEKTABLE']['placeholders']++; + $offset += 10; + + } else { + + $sample_number = getid3_lib::BigEndian2Int($sample_number_string); + + $getid3->info['flac']['SEEKTABLE'][$sample_number]['offset'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 8)); + $offset += 8; + + $getid3->info['flac']['SEEKTABLE'][$sample_number]['samples'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 2)); + $offset += 2; + + } + } + return true; + } + + + + private function FLACparseCUESHEET($meta_data_block_data) { + + $getid3 = $this->getid3; + + $getid3->info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($meta_data_block_data, 0, 128), "\0"); + $getid3->info['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, 128, 8)); + $getid3->info['flac']['CUESHEET']['flags']['is_cd'] = (bool)(getid3_lib::BigEndian2Int($meta_data_block_data[136]) & 0x80); + $getid3->info['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int($meta_data_block_data[395]); + + $offset = 396; + + for ($track = 0; $track < $getid3->info['flac']['CUESHEET']['number_tracks']; $track++) { + + $track_sample_offset = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 8)); + $offset += 8; + + $track_number = getid3_lib::BigEndian2Int($meta_data_block_data{$offset++}); + + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['sample_offset'] = $track_sample_offset; + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['isrc'] = substr($meta_data_block_data, $offset, 12); + $offset += 12; + + $track_flags_raw = getid3_lib::BigEndian2Int($meta_data_block_data{$offset++}); + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['flags']['is_audio'] = (bool)($track_flags_raw & 0x80); + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['flags']['pre_emphasis'] = (bool)($track_flags_raw & 0x40); + + $offset += 13; // reserved + + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['index_points'] = getid3_lib::BigEndian2Int($meta_data_block_data{$offset++}); + + for ($index = 0; $index < $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['index_points']; $index++) { + + $index_sample_offset = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 8)); + $offset += 8; + + $index_number = getid3_lib::BigEndian2Int($meta_data_block_data{$offset++}); + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['indexes'][$index_number] = $index_sample_offset; + + $offset += 3; // reserved + } + } + return true; + } + + + + public static function SpeexBandModeLookup($mode) { + + static $lookup = array ( + 0 => 'narrow', + 1 => 'wide', + 2 => 'ultra-wide' + ); + return (isset($lookup[$mode]) ? $lookup[$mode] : null); + } + + + + public static function OggPageSegmentLength($ogg_info_array, $segment_number=1) { + + for ($i = 0; $i < $segment_number; $i++) { + $segment_length = 0; + foreach ($ogg_info_array['segment_table'] as $key => $value) { + $segment_length += $value; + if ($value < 255) { + break; + } + } + } + return $segment_length; + } + + + + public static function GetQualityFromNominalBitrate($nominal_bitrate) { + + // decrease precision + $nominal_bitrate = $nominal_bitrate / 1000; + + if ($nominal_bitrate < 128) { + // q-1 to q4 + $qval = ($nominal_bitrate - 64) / 16; + } elseif ($nominal_bitrate < 256) { + // q4 to q8 + $qval = $nominal_bitrate / 32; + } elseif ($nominal_bitrate < 320) { + // q8 to q9 + $qval = ($nominal_bitrate + 256) / 64; + } else { + // q9 to q10 + $qval = ($nominal_bitrate + 1300) / 180; + } + return round($qval, 1); // 5 or 4.9 + } + + + + public static function FLACmetaBlockTypeLookup($block_type) { + + static $lookup = array ( + 0 => 'STREAMINFO', + 1 => 'PADDING', + 2 => 'APPLICATION', + 3 => 'SEEKTABLE', + 4 => 'VORBIS_COMMENT', + 5 => 'CUESHEET' + ); + return (isset($lookup[$block_type]) ? $lookup[$block_type] : 'reserved'); + } + + + + public static function FLACapplicationIDLookup($application_id) { + + // http://flac.sourceforge.net/id.html + + static $lookup = array ( + 0x46746F6C => 'flac-tools', // 'Ftol' + 0x46746F6C => 'Sound Font FLAC', // 'SFFL' + 0x7065656D => 'Parseable Embedded Extensible Metadata (specification)', // 'peem' + 0x786D6364 => 'xmcd' + + ); + return (isset($lookup[$application_id]) ? $lookup[$application_id] : 'reserved'); + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.graphic.bmp.php b/plugins/getId3Plugin/lib/module.graphic.bmp.php new file mode 100644 index 0000000..480de97 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.graphic.bmp.php @@ -0,0 +1,319 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.graphic.bmp.php | +// | Module for analyzing BMP graphic files. | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.graphic.bmp.php,v 1.3 2006/06/07 09:01:57 ah Exp $ + + + +class getid3_bmp extends getid3_handler +{ + + + public function Analyze() { + + $getid3 = $this->getid3; + + // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp + // all versions + // WORD bfType; + // DWORD bfSize; + // WORD bfReserved1; + // WORD bfReserved2; + // DWORD bfOffBits; + + // shortcuts + $getid3->info['bmp']['header']['raw'] = array (); + $info_bmp = &$getid3->info['bmp']; + $info_bmp_header = &$info_bmp['header']; + $info_bmp_header_raw = &$info_bmp_header['raw']; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $bmp_header = fread($getid3->fp, 14 + 40); + + // Magic bytes + $info_bmp_header_raw['identifier'] = 'BM'; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 2, + array ( + 'filesize' => 4, + 'reserved1' => 2, + 'reserved2' => 2, + 'data_offset' => 4, + 'header_size' => 4 + ) + ); + + // Check if the hardcoded-to-1 "planes" is at offset 22 or 26 + $planes22 = getid3_lib::LittleEndian2Int(substr($bmp_header, 22, 2)); + $planes26 = getid3_lib::LittleEndian2Int(substr($bmp_header, 26, 2)); + if (($planes22 == 1) && ($planes26 != 1)) { + $info_bmp['type_os'] = 'OS/2'; + $info_bmp['type_version'] = 1; + } + elseif (($planes26 == 1) && ($planes22 != 1)) { + $info_bmp['type_os'] = 'Windows'; + $info_bmp['type_version'] = 1; + } + elseif ($info_bmp_header_raw['header_size'] == 12) { + $info_bmp['type_os'] = 'OS/2'; + $info_bmp['type_version'] = 1; + } + elseif ($info_bmp_header_raw['header_size'] == 40) { + $info_bmp['type_os'] = 'Windows'; + $info_bmp['type_version'] = 1; + } + elseif ($info_bmp_header_raw['header_size'] == 84) { + $info_bmp['type_os'] = 'Windows'; + $info_bmp['type_version'] = 4; + } + elseif ($info_bmp_header_raw['header_size'] == 100) { + $info_bmp['type_os'] = 'Windows'; + $info_bmp['type_version'] = 5; + } + else { + throw new getid3_exception('Unknown BMP subtype (or not a BMP file)'); + } + + $getid3->info['fileformat'] = 'bmp'; + $getid3->info['video']['dataformat'] = 'bmp'; + $getid3->info['video']['lossless'] = true; + $getid3->info['video']['pixel_aspect_ratio'] = (float)1; + + if ($info_bmp['type_os'] == 'OS/2') { + + // OS/2-format BMP + // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm + + // DWORD Size; /* Size of this structure in bytes */ + // DWORD Width; /* Bitmap width in pixels */ + // DWORD Height; /* Bitmap height in pixel */ + // WORD NumPlanes; /* Number of bit planes (color depth) */ + // WORD BitsPerPixel; /* Number of bits per pixel per plane */ + + getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 18, + array ( + 'width' => 2, + 'height' => 2, + 'planes' => 2, + 'bits_per_pixel' => 2 + ) + ); + + $getid3->info['video']['resolution_x'] = $info_bmp_header_raw['width']; + $getid3->info['video']['resolution_y'] = $info_bmp_header_raw['height']; + $getid3->info['video']['codec'] = 'BI_RGB '.$info_bmp_header_raw['bits_per_pixel'].'-bit'; + $getid3->info['video']['bits_per_sample'] = $info_bmp_header_raw['bits_per_pixel']; + + if ($info_bmp['type_version'] >= 2) { + // DWORD Compression; /* Bitmap compression scheme */ + // DWORD ImageDataSize; /* Size of bitmap data in bytes */ + // DWORD XResolution; /* X resolution of display device */ + // DWORD YResolution; /* Y resolution of display device */ + // DWORD ColorsUsed; /* Number of color table indices used */ + // DWORD ColorsImportant; /* Number of important color indices */ + // WORD Units; /* Type of units used to measure resolution */ + // WORD Reserved; /* Pad structure to 4-byte boundary */ + // WORD Recording; /* Recording algorithm */ + // WORD Rendering; /* Halftoning algorithm used */ + // DWORD Size1; /* Reserved for halftoning algorithm use */ + // DWORD Size2; /* Reserved for halftoning algorithm use */ + // DWORD ColorEncoding; /* Color model used in bitmap */ + // DWORD Identifier; /* Reserved for application use */ + + getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 26, + array ( + 'compression' => 4, + 'bmp_data_size' => 4, + 'resolution_h' => 4, + 'resolution_v' => 4, + 'colors_used' => 4, + 'colors_important' => 4, + 'resolution_units' => 2, + 'reserved1' => 2, + 'recording' => 2, + 'rendering' => 2, + 'size1' => 4, + 'size2' => 4, + 'color_encoding' => 4, + 'identifier' => 4 + ) + ); + + $info_bmp_header['compression'] = getid3_bmp::BMPcompressionOS2Lookup($info_bmp_header_raw['compression']); + $getid3->info['video']['codec'] = $info_bmp_header['compression'].' '.$info_bmp_header_raw['bits_per_pixel'].'-bit'; + } + + return true; + } + + + if ($info_bmp['type_os'] == 'Windows') { + + // Windows-format BMP + + // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp + // all versions + // DWORD biSize; + // LONG biWidth; + // LONG biHeight; + // WORD biPlanes; + // WORD biBitCount; + // DWORD biCompression; + // DWORD biSizeImage; + // LONG biXPelsPerMeter; + // LONG biYPelsPerMeter; + // DWORD biClrUsed; + // DWORD biClrImportant; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 18, + array ( + 'width' => -4, //signed + 'height' => -4, //signed + 'planes' => 2, + 'bits_per_pixel' => 2, + 'compression' => 4, + 'bmp_data_size' => 4, + 'resolution_h' => -4, //signed + 'resolution_v' => -4, //signed + 'colors_used' => 4, + 'colors_important' => 4 + ) + ); + foreach (array ('width', 'height', 'resolution_h', 'resolution_v') as $key) { + $info_bmp_header_raw[$key] = getid3_lib::LittleEndian2Int($info_bmp_header_raw[$key], true); + } + + $info_bmp_header['compression'] = getid3_bmp::BMPcompressionWindowsLookup($info_bmp_header_raw['compression']); + $getid3->info['video']['resolution_x'] = $info_bmp_header_raw['width']; + $getid3->info['video']['resolution_y'] = $info_bmp_header_raw['height']; + $getid3->info['video']['codec'] = $info_bmp_header['compression'].' '.$info_bmp_header_raw['bits_per_pixel'].'-bit'; + $getid3->info['video']['bits_per_sample'] = $info_bmp_header_raw['bits_per_pixel']; + + // should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen + if (($info_bmp['type_version'] >= 4) || ($info_bmp_header_raw['compression'] == 3)) { + + + $bmp_header .= fread($getid3->fp, 44); + + // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp + // Win95+, WinNT4.0+ + // DWORD bV4RedMask; + // DWORD bV4GreenMask; + // DWORD bV4BlueMask; + // DWORD bV4AlphaMask; + // DWORD bV4CSType; + // CIEXYZTRIPLE bV4Endpoints; + // DWORD bV4GammaRed; + // DWORD bV4GammaGreen; + // DWORD bV4GammaBlue; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 54, + array ( + 'red_mask' => 4, + 'green_mask' => 4, + 'blue_mask' => 4, + 'alpha_mask' => 4, + 'cs_type' => 4, + 'ciexyz_red' => -4, //string + 'ciexyz_green' => -4, //string + 'ciexyz_blue' => -4, //string + 'gamma_red' => 4, + 'gamma_green' => 4, + 'gamma_blue' => 4 + ) + ); + + $info_bmp_header['ciexyz_red'] = getid3_bmp::FixedPoint2_30(strrev($info_bmp_header_raw['ciexyz_red'])); + $info_bmp_header['ciexyz_green'] = getid3_bmp::FixedPoint2_30(strrev($info_bmp_header_raw['ciexyz_green'])); + $info_bmp_header['ciexyz_blue'] = getid3_bmp::FixedPoint2_30(strrev($info_bmp_header_raw['ciexyz_blue'])); + + + if ($info_bmp['type_version'] >= 5) { + $bmp_header .= fread($getid3->fp, 16); + + // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp + // Win98+, Win2000+ + // DWORD bV5Intent; + // DWORD bV5ProfileData; + // DWORD bV5ProfileSize; + // DWORD bV5Reserved; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_bmp_header_raw, $bmp_header, 98, + array ( + 'intent' => 4, + 'profile_data_offset' => 4, + 'profile_data_size' => 4, + 'reserved3' => 4 + ) + ); + + } + } + + return true; + } + + + throw new getid3_exception('Unknown BMP format in header.'); + + } + + + + public static function BMPcompressionWindowsLookup($compression_id) { + + static $lookup = array ( + 0 => 'BI_RGB', + 1 => 'BI_RLE8', + 2 => 'BI_RLE4', + 3 => 'BI_BITFIELDS', + 4 => 'BI_JPEG', + 5 => 'BI_PNG' + ); + return (isset($lookup[$compression_id]) ? $lookup[$compression_id] : 'invalid'); + } + + + + public static function BMPcompressionOS2Lookup($compression_id) { + + static $lookup = array ( + 0 => 'BI_RGB', + 1 => 'BI_RLE8', + 2 => 'BI_RLE4', + 3 => 'Huffman 1D', + 4 => 'BI_RLE24', + ); + return (isset($lookup[$compression_id]) ? $lookup[$compression_id] : 'invalid'); + } + + + public static function FixedPoint2_30($raw_data) { + + $binary_string = getid3_lib::BigEndian2Bin($raw_data); + return bindec(substr($binary_string, 0, 2)) + (float)(bindec(substr($binary_string, 2, 30)) / 1073741824); // pow(2, 30) = 1073741824 + } + + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.graphic.gif.php b/plugins/getId3Plugin/lib/module.graphic.gif.php new file mode 100644 index 0000000..cfd0bb0 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.graphic.gif.php @@ -0,0 +1,92 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.graphic.gif.php | +// | Module for analyzing CompuServe GIF graphic files. | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.graphic.gif.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_gif extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['fileformat'] = 'gif'; + $getid3->info['video']['dataformat'] = 'gif'; + $getid3->info['video']['lossless'] = true; + $getid3->info['video']['pixel_aspect_ratio'] = (float)1; + + $getid3->info['gif']['header'] = array (); + $info_gif_header = &$getid3->info['gif']['header']; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $gif_header = fread($getid3->fp, 13); + + // Magic bytes + $info_gif_header['raw']['identifier'] = 'GIF'; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_gif_header['raw'], $gif_header, 3, + array ( + 'version' => -3, // string + 'width' => 2, + 'height' => 2, + 'flags' => 1, + 'bg_color_index' => 1, + 'aspect_ratio' => 1 + ) + ); + + $getid3->info['video']['resolution_x'] = $info_gif_header['raw']['width']; + $getid3->info['video']['resolution_y'] = $info_gif_header['raw']['height']; + $getid3->info['gif']['version'] = $info_gif_header['raw']['version']; + + $info_gif_header['flags']['global_color_table'] = (bool)($info_gif_header['raw']['flags'] & 0x80); + + if ($info_gif_header['raw']['flags'] & 0x80) { + // Number of bits per primary color available to the original image, minus 1 + $info_gif_header['bits_per_pixel'] = 3 * ((($info_gif_header['raw']['flags'] & 0x70) >> 4) + 1); + } else { + $info_gif_header['bits_per_pixel'] = 0; + } + + $info_gif_header['flags']['global_color_sorted'] = (bool)($info_gif_header['raw']['flags'] & 0x40); + if ($info_gif_header['flags']['global_color_table']) { + // the number of bytes contained in the Global Color Table. To determine that + // actual size of the color table, raise 2 to [the value of the field + 1] + $info_gif_header['global_color_size'] = pow(2, ($info_gif_header['raw']['flags'] & 0x07) + 1); + $getid3->info['video']['bits_per_sample'] = ($info_gif_header['raw']['flags'] & 0x07) + 1; + } else { + $info_gif_header['global_color_size'] = 0; + } + + if ($info_gif_header['raw']['aspect_ratio'] != 0) { + // Aspect Ratio = (Pixel Aspect Ratio + 15) / 64 + $info_gif_header['aspect_ratio'] = ($info_gif_header['raw']['aspect_ratio'] + 15) / 64; + } + + return true; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.graphic.jpeg.php b/plugins/getId3Plugin/lib/module.graphic.jpeg.php new file mode 100644 index 0000000..3ea88fc --- /dev/null +++ b/plugins/getId3Plugin/lib/module.graphic.jpeg.php @@ -0,0 +1,62 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.graphic.jpeg.php | +// | Module for analyzing JPEG graphic files. | +// | dependencies: exif support in PHP (optional) | +// +----------------------------------------------------------------------+ +// +// $Id: module.graphic.jpeg.php,v 1.3 2006/06/06 18:38:54 ah Exp $ + + + +class getid3_jpeg extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['fileformat'] = 'jpg'; + $getid3->info['video']['dataformat'] = 'jpg'; + $getid3->info['video']['lossless'] = false; + $getid3->info['video']['bits_per_sample'] = 24; + $getid3->info['video']['pixel_aspect_ratio'] = (float)1; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + + list($getid3->info['video']['resolution_x'], $getid3->info['video']['resolution_y'], $type) = getimagesize($getid3->filename); + + if ($type != 2) { + throw new getid3_exception('File detected as JPEG, but is currupt.'); + } + + if (function_exists('exif_read_data')) { + + $getid3->info['jpg']['exif'] = exif_read_data($getid3->filename, '', true, false); + + } else { + + $getid3->warning('EXIF parsing only available when compiled with --enable-exif (or php_exif.dll enabled for Windows).'); + } + + return true; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.graphic.jpg.php b/plugins/getId3Plugin/lib/module.graphic.jpg.php new file mode 100644 index 0000000..0cd305c --- /dev/null +++ b/plugins/getId3Plugin/lib/module.graphic.jpg.php @@ -0,0 +1,72 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.graphic.jpg.php // +// module for analyzing JPEG Image files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_jpg +{ + + + function getid3_jpg(&$fd, &$ThisFileInfo) { + $ThisFileInfo['fileformat'] = 'jpg'; + $ThisFileInfo['video']['dataformat'] = 'jpg'; + $ThisFileInfo['video']['lossless'] = false; + $ThisFileInfo['video']['bits_per_sample'] = 24; + $ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1; + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + + list($width, $height, $type) = getid3_lib::GetDataImageSize(fread($fd, $ThisFileInfo['filesize'])); + if ($type == 2) { + + $ThisFileInfo['video']['resolution_x'] = $width; + $ThisFileInfo['video']['resolution_y'] = $height; + + if (version_compare(phpversion(), '4.2.0', '>=')) { + + if (function_exists('exif_read_data')) { + + ob_start(); + $ThisFileInfo['jpg']['exif'] = exif_read_data($ThisFileInfo['filenamepath'], '', true, false); + $errors = ob_get_contents(); + if ($errors) { + $ThisFileInfo['error'][] = strip_tags($errors); + unset($ThisFileInfo['jpg']['exif']); + } + ob_end_clean(); + + } else { + + $ThisFileInfo['warning'][] = 'EXIF parsing only available when '.(GETID3_OS_ISWINDOWS ? 'php_exif.dll enabled' : 'compiled with --enable-exif'); + + } + + } else { + + $ThisFileInfo['warning'][] = 'EXIF parsing only available in PHP v4.2.0 and higher compiled with --enable-exif (or php_exif.dll enabled for Windows). You are using PHP v'.phpversion(); + + } + + return true; + + } + + unset($ThisFileInfo['fileformat']); + return false; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.graphic.pcd.php b/plugins/getId3Plugin/lib/module.graphic.pcd.php new file mode 100644 index 0000000..3ef550e --- /dev/null +++ b/plugins/getId3Plugin/lib/module.graphic.pcd.php @@ -0,0 +1,56 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.graphic.pcd.php | +// | Module for analyzing PhotoCD (PCD) Image files. | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.graphic.pcd.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_pcd extends getid3_handler +{ + + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['fileformat'] = 'pcd'; + $getid3->info['video']['dataformat'] = 'pcd'; + $getid3->info['video']['lossless'] = false; + + fseek($getid3->fp, $getid3->info['avdataoffset'] + 72, SEEK_SET); + + $pcd_flags = fread($getid3->fp, 1); + $pcd_is_vertical = ((ord($pcd_flags) & 0x01) ? true : false); + + if ($pcd_is_vertical) { + $getid3->info['video']['resolution_x'] = 3072; + $getid3->info['video']['resolution_y'] = 2048; + } else { + $getid3->info['video']['resolution_x'] = 2048; + $getid3->info['video']['resolution_y'] = 3072; + } + + } + + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.graphic.png.php b/plugins/getId3Plugin/lib/module.graphic.png.php new file mode 100644 index 0000000..dcbc688 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.graphic.png.php @@ -0,0 +1,556 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.graphic.png.php | +// | Module for analyzing PNG graphic files. | +// | dependencies: zlib support in PHP (optional) | +// +----------------------------------------------------------------------+ +// +// $Id: module.graphic.png.php,v 1.2 2004/11/01 03:11:16 ah Exp $ + + + +class getid3_png extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['png'] = array (); + $info_png = &$getid3->info['png']; + + $getid3->info['fileformat'] = 'png'; + $getid3->info['video']['dataformat'] = 'png'; + $getid3->info['video']['lossless'] = false; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $png_filedata = fread($getid3->fp, getid3::FREAD_BUFFER_SIZE); + + // Magic bytes "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A" + + $offset = 8; + + while (((ftell($getid3->fp) - (strlen($png_filedata) - $offset)) < $getid3->info['filesize'])) { + + $chunk['data_length'] = getid3_lib::BigEndian2Int(substr($png_filedata, $offset, 4)); + $offset += 4; + while (((strlen($png_filedata) - $offset) < ($chunk['data_length'] + 4)) && (ftell($getid3->fp) < $getid3->info['filesize'])) { + $png_filedata .= fread($getid3->fp, getid3::FREAD_BUFFER_SIZE); + } + + $chunk['type_text'] = substr($png_filedata, $offset, 4); + $chunk['type_raw'] = getid3_lib::BigEndian2Int($chunk['type_text']); + $offset += 4; + + $chunk['data'] = substr($png_filedata, $offset, $chunk['data_length']); + $offset += $chunk['data_length']; + + $chunk['crc'] = getid3_lib::BigEndian2Int(substr($png_filedata, $offset, 4)); + $offset += 4; + + $chunk['flags']['ancilliary'] = (bool)($chunk['type_raw'] & 0x20000000); + $chunk['flags']['private'] = (bool)($chunk['type_raw'] & 0x00200000); + $chunk['flags']['reserved'] = (bool)($chunk['type_raw'] & 0x00002000); + $chunk['flags']['safe_to_copy'] = (bool)($chunk['type_raw'] & 0x00000020); + + // shortcut + $info_png[$chunk['type_text']] = array (); + $info_png_chunk_type_text = &$info_png[$chunk['type_text']]; + + switch ($chunk['type_text']) { + + case 'IHDR': // Image Header + $info_png_chunk_type_text['header'] = $chunk; + $info_png_chunk_type_text['width'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 4)); + $info_png_chunk_type_text['height'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 4, 4)); + + getid3_lib::ReadSequence('BigEndian2Int', $info_png_chunk_type_text['raw'], $info_png_chunk_type_text['header']['data'], 8, + array ( + 'bit_depth' => 1, + 'color_type' => 1, + 'compression_method' => 1, + 'filter_method' => 1, + 'interlace_method' => 1 + ) + ); + + $info_png_chunk_type_text['compression_method_text'] = getid3_png::PNGcompressionMethodLookup($info_png_chunk_type_text['raw']['compression_method']); + $info_png_chunk_type_text['color_type']['palette'] = (bool)($info_png_chunk_type_text['raw']['color_type'] & 0x01); + $info_png_chunk_type_text['color_type']['true_color'] = (bool)($info_png_chunk_type_text['raw']['color_type'] & 0x02); + $info_png_chunk_type_text['color_type']['alpha'] = (bool)($info_png_chunk_type_text['raw']['color_type'] & 0x04); + + $getid3->info['video']['resolution_x'] = $info_png_chunk_type_text['width']; + $getid3->info['video']['resolution_y'] = $info_png_chunk_type_text['height']; + + $getid3->info['video']['bits_per_sample'] = getid3_png::IHDRcalculateBitsPerSample($info_png_chunk_type_text['raw']['color_type'], $info_png_chunk_type_text['raw']['bit_depth']); + break; + + + case 'PLTE': // Palette + $info_png_chunk_type_text['header'] = $chunk; + $palette_offset = 0; + for ($i = 0; $i <= 255; $i++) { + $red = @getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']{$palette_offset++}); + $green = @getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']{$palette_offset++}); + $blue = @getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']{$palette_offset++}); + $info_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue)); + } + break; + + + case 'tRNS': // Transparency + $info_png_chunk_type_text['header'] = $chunk; + switch ($info_png['IHDR']['raw']['color_type']) { + case 0: + $info_png_chunk_type_text['transparent_color_gray'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 2)); + break; + + case 2: + $info_png_chunk_type_text['transparent_color_red'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 2)); + $info_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 2, 2)); + $info_png_chunk_type_text['transparent_color_blue'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 4, 2)); + break; + + case 3: + for ($i = 0; $i < strlen($info_png_chunk_type_text['header']['data']); $i++) { + $info_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][$i]); + } + break; + + case 4: + case 6: + throw new getid3_exception('Invalid color_type in tRNS chunk: '.$info_png['IHDR']['raw']['color_type']); + + default: + $getid3->warning('Unhandled color_type in tRNS chunk: '.$info_png['IHDR']['raw']['color_type']); + break; + } + break; + + + case 'gAMA': // Image Gamma + $info_png_chunk_type_text['header'] = $chunk; + $info_png_chunk_type_text['gamma'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']) / 100000; + break; + + + case 'cHRM': // Primary Chromaticities + $info_png_chunk_type_text['header'] = $chunk; + $info_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 4)) / 100000; + $info_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 4, 4)) / 100000; + $info_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 8, 4)) / 100000; + $info_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 12, 4)) / 100000; + $info_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 16, 4)) / 100000; + $info_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 20, 4)) / 100000; + $info_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 24, 4)) / 100000; + $info_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 28, 4)) / 100000; + break; + + + case 'sRGB': // Standard RGB Color Space + $info_png_chunk_type_text['header'] = $chunk; + $info_png_chunk_type_text['reindering_intent'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']); + $info_png_chunk_type_text['reindering_intent_text'] = getid3_png::PNGsRGBintentLookup($info_png_chunk_type_text['reindering_intent']); + break; + + + case 'iCCP': // Embedded ICC Profile + $info_png_chunk_type_text['header'] = $chunk; + list($profilename, $compressiondata) = explode("\x00", $info_png_chunk_type_text['header']['data'], 2); + $info_png_chunk_type_text['profile_name'] = $profilename; + $info_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int($compressiondata[0]); + $info_png_chunk_type_text['compression_profile'] = substr($compressiondata, 1); + $info_png_chunk_type_text['compression_method_text'] = getid3_png::PNGcompressionMethodLookup($info_png_chunk_type_text['compression_method']); + break; + + + case 'tEXt': // Textual Data + $info_png_chunk_type_text['header'] = $chunk; + list($keyword, $text) = explode("\x00", $info_png_chunk_type_text['header']['data'], 2); + $info_png_chunk_type_text['keyword'] = $keyword; + $info_png_chunk_type_text['text'] = $text; + + $info_png['comments'][$info_png_chunk_type_text['keyword']][] = $info_png_chunk_type_text['text']; + break; + + + case 'zTXt': // Compressed Textual Data + $info_png_chunk_type_text['header'] = $chunk; + list($keyword, $otherdata) = explode("\x00", $info_png_chunk_type_text['header']['data'], 2); + $info_png_chunk_type_text['keyword'] = $keyword; + $info_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1)); + $info_png_chunk_type_text['compressed_text'] = substr($otherdata, 1); + $info_png_chunk_type_text['compression_method_text'] = getid3_png::PNGcompressionMethodLookup($info_png_chunk_type_text['compression_method']); + + if ($info_png_chunk_type_text['compression_method'] != 0) { + // unknown compression method + break; + } + + if (function_exists('gzuncompress')) { + $info_png_chunk_type_text['text'] = gzuncompress($info_png_chunk_type_text['compressed_text']); + } + else { + if (!@$this->zlib_warning) { + $getid3->warning('PHP does not have --with-zlib support - cannot gzuncompress()'); + } + $this->zlib_warning = true; + } + + + if (isset($info_png_chunk_type_text['text'])) { + $info_png['comments'][$info_png_chunk_type_text['keyword']][] = $info_png_chunk_type_text['text']; + } + break; + + + case 'iTXt': // International Textual Data + $info_png_chunk_type_text['header'] = $chunk; + list($keyword, $otherdata) = explode("\x00", $info_png_chunk_type_text['header']['data'], 2); + $info_png_chunk_type_text['keyword'] = $keyword; + $info_png_chunk_type_text['compression'] = (bool)getid3_lib::BigEndian2Int(substr($otherdata, 0, 1)); + $info_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int($otherdata[1]); + $info_png_chunk_type_text['compression_method_text'] = getid3_png::PNGcompressionMethodLookup($info_png_chunk_type_text['compression_method']); + list($languagetag, $translatedkeyword, $text) = explode("\x00", substr($otherdata, 2), 3); + $info_png_chunk_type_text['language_tag'] = $languagetag; + $info_png_chunk_type_text['translated_keyword'] = $translatedkeyword; + + if ($info_png_chunk_type_text['compression']) { + + switch ($info_png_chunk_type_text['compression_method']) { + case 0: + if (function_exists('gzuncompress')) { + $info_png_chunk_type_text['text'] = gzuncompress($text); + } + else { + if (!@$this->zlib_warning) { + $getid3->warning('PHP does not have --with-zlib support - cannot gzuncompress()'); + } + $this->zlib_warning = true; + } + break; + + default: + // unknown compression method + break; + } + + } else { + + $info_png_chunk_type_text['text'] = $text; + + } + + if (isset($info_png_chunk_type_text['text'])) { + $info_png['comments'][$info_png_chunk_type_text['keyword']][] = $info_png_chunk_type_text['text']; + } + break; + + + case 'bKGD': // Background Color + $info_png_chunk_type_text['header'] = $chunk; + switch ($info_png['IHDR']['raw']['color_type']) { + case 0: + case 4: + $info_png_chunk_type_text['background_gray'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']); + break; + + case 2: + case 6: + $info_png_chunk_type_text['background_red'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0 * $info_png['IHDR']['raw']['bit_depth'], $info_png['IHDR']['raw']['bit_depth'])); + $info_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 1 * $info_png['IHDR']['raw']['bit_depth'], $info_png['IHDR']['raw']['bit_depth'])); + $info_png_chunk_type_text['background_blue'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 2 * $info_png['IHDR']['raw']['bit_depth'], $info_png['IHDR']['raw']['bit_depth'])); + break; + + case 3: + $info_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']); + break; + + default: + break; + } + break; + + + case 'pHYs': // Physical Pixel Dimensions + $info_png_chunk_type_text['header'] = $chunk; + $info_png_chunk_type_text['pixels_per_unit_x'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 4)); + $info_png_chunk_type_text['pixels_per_unit_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 4, 4)); + $info_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 8, 1)); + $info_png_chunk_type_text['unit'] = getid3_png::PNGpHYsUnitLookup($info_png_chunk_type_text['unit_specifier']); + break; + + + case 'sBIT': // Significant Bits + $info_png_chunk_type_text['header'] = $chunk; + switch ($info_png['IHDR']['raw']['color_type']) { + case 0: + $info_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 1)); + break; + + case 2: + case 3: + $info_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][0]); + $info_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][1]); + $info_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][2]); + break; + + case 4: + $info_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][0]); + $info_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][1]); + break; + + case 6: + $info_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][0]); + $info_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][1]); + $info_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][2]); + $info_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][3]); + break; + + default: + break; + } + break; + + + case 'sPLT': // Suggested Palette + $info_png_chunk_type_text['header'] = $chunk; + + list($palettename, $otherdata) = explode("\x00", $info_png_chunk_type_text['header']['data'], 2); + $info_png_chunk_type_text['palette_name'] = $palettename; + + $info_png_chunk_type_text['sample_depth_bits'] = getid3_lib::BigEndian2Int($otherdata[0]); + $info_png_chunk_type_text['sample_depth_bytes'] = $info_png_chunk_type_text['sample_depth_bits'] / 8; + + $s_plt_offset = 1; + $paletteCounter = 0; + while ($s_plt_offset < strlen($otherdata)) { + + $info_png_chunk_type_text['red'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $s_plt_offset, $info_png_chunk_type_text['sample_depth_bytes'])); + $s_plt_offset += $info_png_chunk_type_text['sample_depth_bytes']; + + $info_png_chunk_type_text['green'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $s_plt_offset, $info_png_chunk_type_text['sample_depth_bytes'])); + $s_plt_offset += $info_png_chunk_type_text['sample_depth_bytes']; + + $info_png_chunk_type_text['blue'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $s_plt_offset, $info_png_chunk_type_text['sample_depth_bytes'])); + $s_plt_offset += $info_png_chunk_type_text['sample_depth_bytes']; + + $info_png_chunk_type_text['alpha'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $s_plt_offset, $info_png_chunk_type_text['sample_depth_bytes'])); + $s_plt_offset += $info_png_chunk_type_text['sample_depth_bytes']; + + $info_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $s_plt_offset, 2)); + $s_plt_offset += 2; + + $paletteCounter++; + } + break; + + + case 'hIST': // Palette Histogram + $info_png_chunk_type_text['header'] = $chunk; + $h_ist_counter = 0; + while ($h_ist_counter < strlen($info_png_chunk_type_text['header']['data'])) { + $info_png_chunk_type_text[$h_ist_counter] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], $h_ist_counter / 2, 2)); + $h_ist_counter += 2; + } + break; + + + case 'tIME': // Image Last-Modification Time + $info_png_chunk_type_text['header'] = $chunk; + $info_png_chunk_type_text['year'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 2)); + $info_png_chunk_type_text['month'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']{2}); + $info_png_chunk_type_text['day'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']{3}); + $info_png_chunk_type_text['hour'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']{4}); + $info_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']{5}); + $info_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data']{6}); + $info_png_chunk_type_text['unix'] = gmmktime($info_png_chunk_type_text['hour'], $info_png_chunk_type_text['minute'], $info_png_chunk_type_text['second'], $info_png_chunk_type_text['month'], $info_png_chunk_type_text['day'], $info_png_chunk_type_text['year']); + break; + + + case 'oFFs': // Image Offset + $info_png_chunk_type_text['header'] = $chunk; + $info_png_chunk_type_text['position_x'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 4), false, true); + $info_png_chunk_type_text['position_y'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 4, 4), false, true); + $info_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][8]); + $info_png_chunk_type_text['unit'] = getid3_png::PNGoFFsUnitLookup($info_png_chunk_type_text['unit_specifier']); + break; + + + case 'pCAL': // Calibration Of Pixel Values + $info_png_chunk_type_text['header'] = $chunk; + list($calibrationname, $otherdata) = explode("\x00", $info_png_chunk_type_text['header']['data'], 2); + $info_png_chunk_type_text['calibration_name'] = $calibrationname; + $info_png_chunk_type_text['original_zero'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 4), false, true); + $info_png_chunk_type_text['original_max'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 4, 4), false, true); + $info_png_chunk_type_text['equation_type'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][8]); + $info_png_chunk_type_text['equation_type_text'] = getid3_png::PNGpCALequationTypeLookup($info_png_chunk_type_text['equation_type']); + $info_png_chunk_type_text['parameter_count'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][9]); + $info_png_chunk_type_text['parameters'] = explode("\x00", substr($info_png_chunk_type_text['header']['data'], 10)); + break; + + + case 'sCAL': // Physical Scale Of Image Subject + $info_png_chunk_type_text['header'] = $chunk; + $info_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($info_png_chunk_type_text['header']['data'], 0, 1)); + $info_png_chunk_type_text['unit'] = getid3_png::PNGsCALUnitLookup($info_png_chunk_type_text['unit_specifier']); + list($info_png_chunk_type_text['pixel_width'], $info_png_chunk_type_text['pixel_height']) = explode("\x00", substr($info_png_chunk_type_text['header']['data'], 1)); + break; + + + case 'gIFg': // GIF Graphic Control Extension + $gIFg_counter = 0; + if (isset($info_png_chunk_type_text) && is_array($info_png_chunk_type_text)) { + $gIFg_counter = count($info_png_chunk_type_text); + } + $info_png_chunk_type_text[$gIFg_counter]['header'] = $chunk; + $info_png_chunk_type_text[$gIFg_counter]['disposal_method'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][0]); + $info_png_chunk_type_text[$gIFg_counter]['user_input_flag'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][1]); + $info_png_chunk_type_text[$gIFg_counter]['delay_time'] = getid3_lib::BigEndian2Int($info_png_chunk_type_text['header']['data'][2]); + break; + + + case 'gIFx': // GIF Application Extension + $gIFx_counter = 0; + if (isset($info_png_chunk_type_text) && is_array($info_png_chunk_type_text)) { + $gIFx_counter = count($info_png_chunk_type_text); + } + $info_png_chunk_type_text[$gIFx_counter]['header'] = $chunk; + $info_png_chunk_type_text[$gIFx_counter]['application_identifier'] = substr($info_png_chunk_type_text['header']['data'], 0, 8); + $info_png_chunk_type_text[$gIFx_counter]['authentication_code'] = substr($info_png_chunk_type_text['header']['data'], 8, 3); + $info_png_chunk_type_text[$gIFx_counter]['application_data'] = substr($info_png_chunk_type_text['header']['data'], 11); + break; + + + case 'IDAT': // Image Data + $idat_information_field_index = 0; + if (isset($info_png['IDAT']) && is_array($info_png['IDAT'])) { + $idat_information_field_index = count($info_png['IDAT']); + } + unset($chunk['data']); + $info_png_chunk_type_text[$idat_information_field_index]['header'] = $chunk; + break; + + + case 'IEND': // Image Trailer + $info_png_chunk_type_text['header'] = $chunk; + break; + + + default: + $info_png_chunk_type_text['header'] = $chunk; + $getid3->warning('Unhandled chunk type: '.$chunk['type_text']); + break; + } + } + + return true; + } + + + + public static function PNGsRGBintentLookup($sRGB) { + + static $lookup = array ( + 0 => 'Perceptual', + 1 => 'Relative colorimetric', + 2 => 'Saturation', + 3 => 'Absolute colorimetric' + ); + return (isset($lookup[$sRGB]) ? $lookup[$sRGB] : 'invalid'); + } + + + + public static function PNGcompressionMethodLookup($compression_method) { + + return ($compression_method == 0 ? 'deflate/inflate' : 'invalid'); + } + + + + public static function PNGpHYsUnitLookup($unit_id) { + + static $lookup = array ( + 0 => 'unknown', + 1 => 'meter' + ); + return (isset($lookup[$unit_id]) ? $lookup[$unit_id] : 'invalid'); + } + + + + public static function PNGoFFsUnitLookup($unit_id) { + + static $lookup = array ( + 0 => 'pixel', + 1 => 'micrometer' + ); + return (isset($lookup[$unit_id]) ? $lookup[$unit_id] : 'invalid'); + } + + + + public static function PNGpCALequationTypeLookup($equation_type) { + + static $lookup = array ( + 0 => 'Linear mapping', + 1 => 'Base-e exponential mapping', + 2 => 'Arbitrary-base exponential mapping', + 3 => 'Hyperbolic mapping' + ); + return (isset($lookup[$equation_type]) ? $lookup[$equation_type] : 'invalid'); + } + + + + public static function PNGsCALUnitLookup($unit_id) { + + static $lookup = array ( + 0 => 'meter', + 1 => 'radian' + ); + return (isset($lookup[$unit_id]) ? $lookup[$unit_id] : 'invalid'); + } + + + + public static function IHDRcalculateBitsPerSample($color_type, $bit_depth) { + + switch ($color_type) { + case 0: // Each pixel is a grayscale sample. + return $bit_depth; + + case 2: // Each pixel is an R,G,B triple + return 3 * $bit_depth; + + case 3: // Each pixel is a palette index; a PLTE chunk must appear. + return $bit_depth; + + case 4: // Each pixel is a grayscale sample, followed by an alpha sample. + return 2 * $bit_depth; + + case 6: // Each pixel is an R,G,B triple, followed by an alpha sample. + return 4 * $bit_depth; + } + return false; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.graphic.svg.php b/plugins/getId3Plugin/lib/module.graphic.svg.php new file mode 100644 index 0000000..e447145 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.graphic.svg.php @@ -0,0 +1,52 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.graphic.svg.php // +// module for analyzing SVG Image files // +// dependencies: NONE // +// author: Bryce Harrington // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_svg +{ + + + function getid3_svg(&$fd, &$ThisFileInfo) { + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + + // I'm making this up, please modify as appropriate + $SVGheader = fread($fd, 32); + $ThisFileInfo['svg']['magic'] = substr($SVGheader, 0, 4); + if ($ThisFileInfo['svg']['magic'] == 'aBcD') { + + $ThisFileInfo['fileformat'] = 'svg'; + $ThisFileInfo['video']['dataformat'] = 'svg'; + $ThisFileInfo['video']['lossless'] = true; + $ThisFileInfo['video']['bits_per_sample'] = 24; + $ThisFileInfo['video']['pixel_aspect_ratio'] = (float) 1; + + $ThisFileInfo['svg']['width'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4)); + $ThisFileInfo['svg']['height'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 4)); + + $ThisFileInfo['video']['resolution_x'] = $ThisFileInfo['svg']['width']; + $ThisFileInfo['video']['resolution_y'] = $ThisFileInfo['svg']['height']; + + return true; + } + $ThisFileInfo['error'][] = 'Did not find SVG magic bytes "aBcD" at '.$ThisFileInfo['avdataoffset']; + unset($ThisFileInfo['fileformat']); + return false; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.graphic.tiff.php b/plugins/getId3Plugin/lib/module.graphic.tiff.php new file mode 100644 index 0000000..40438e1 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.graphic.tiff.php @@ -0,0 +1,215 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.graphic.tiff.php | +// | Module for analyzing TIFF graphic files. | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.graphic.tiff.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_tiff extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); + $tiff_header = fread($getid3->fp, 4); + + $getid3->info['tiff']['byte_order'] = substr($tiff_header, 0, 2) == 'II' ? 'Intel' : 'Motorola'; + $endian2int = substr($tiff_header, 0, 2) == 'II' ? 'LittleEndian2Int' : 'BigEndian2Int'; + + $getid3->info['fileformat'] = 'tiff'; + $getid3->info['video']['dataformat'] = 'tiff'; + $getid3->info['video']['lossless'] = true; + $getid3->info['tiff']['ifd'] = array (); + $current_ifd = array (); + + $field_type_byte_length = array (1=>1, 2=>1, 3=>2, 4=>4, 5=>8); + + $next_ifd_offset = getid3_lib::$endian2int(fread($getid3->fp, 4)); + + while ($next_ifd_offset > 0) { + + $current_ifd['offset'] = $next_ifd_offset; + + fseek($getid3->fp, $getid3->info['avdataoffset'] + $next_ifd_offset, SEEK_SET); + $current_ifd['fieldcount'] = getid3_lib::$endian2int(fread($getid3->fp, 2)); + + for ($i = 0; $i < $current_ifd['fieldcount']; $i++) { + + // shortcut + $current_ifd['fields'][$i] = array (); + $current_ifd_fields_i = &$current_ifd['fields'][$i]; + + $current_ifd_fields_i['raw']['tag'] = getid3_lib::$endian2int(fread($getid3->fp, 2)); + $current_ifd_fields_i['raw']['type'] = getid3_lib::$endian2int(fread($getid3->fp, 2)); + $current_ifd_fields_i['raw']['length'] = getid3_lib::$endian2int(fread($getid3->fp, 4)); + $current_ifd_fields_i['raw']['offset'] = fread($getid3->fp, 4); + + switch ($current_ifd_fields_i['raw']['type']) { + case 1: // BYTE An 8-bit unsigned integer. + if ($current_ifd_fields_i['raw']['length'] <= 4) { + $current_ifd_fields_i['value'] = getid3_lib::$endian2int(substr($current_ifd_fields_i['raw']['offset'], 0, 1)); + } else { + $current_ifd_fields_i['offset'] = getid3_lib::$endian2int($current_ifd_fields_i['raw']['offset']); + } + break; + + case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null. + if ($current_ifd_fields_i['raw']['length'] <= 4) { + $current_ifd_fields_i['value'] = substr($current_ifd_fields_i['raw']['offset'], 3); + } else { + $current_ifd_fields_i['offset'] = getid3_lib::$endian2int($current_ifd_fields_i['raw']['offset']); + } + break; + + case 3: // SHORT A 16-bit (2-byte) unsigned integer. + if ($current_ifd_fields_i['raw']['length'] <= 2) { + $current_ifd_fields_i['value'] = getid3_lib::$endian2int(substr($current_ifd_fields_i['raw']['offset'], 0, 2)); + } else { + $current_ifd_fields_i['offset'] = getid3_lib::$endian2int($current_ifd_fields_i['raw']['offset']); + } + break; + + case 4: // LONG A 32-bit (4-byte) unsigned integer. + if ($current_ifd_fields_i['raw']['length'] <= 1) { + $current_ifd_fields_i['value'] = getid3_lib::$endian2int($current_ifd_fields_i['raw']['offset']); + } else { + $current_ifd_fields_i['offset'] = getid3_lib::$endian2int($current_ifd_fields_i['raw']['offset']); + } + break; + + case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator. + break; + } + } + + $getid3->info['tiff']['ifd'][] = $current_ifd; + $current_ifd = array (); + $next_ifd_offset = getid3_lib::$endian2int(fread($getid3->fp, 4)); + + } + + foreach ($getid3->info['tiff']['ifd'] as $ifd_id => $ifd_array) { + foreach ($ifd_array['fields'] as $key => $field_array) { + switch ($field_array['raw']['tag']) { + case 256: // ImageWidth + case 257: // ImageLength + case 258: // BitsPerSample + case 259: // Compression + if (!isset($field_array['value'])) { + fseek($getid3->fp, $field_array['offset'], SEEK_SET); + $getid3->info['tiff']['ifd'][$ifd_id]['fields'][$key]['raw']['data'] = fread($getid3->fp, $field_array['raw']['length'] * $field_type_byte_length[$field_array['raw']['type']]); + } + break; + + case 270: // ImageDescription + case 271: // Make + case 272: // Model + case 305: // Software + case 306: // DateTime + case 315: // Artist + case 316: // HostComputer + if (isset($field_array['value'])) { + $getid3->info['tiff']['ifd'][$ifd_id]['fields'][$key]['raw']['data'] = $field_array['value']; + } else { + fseek($getid3->fp, $field_array['offset'], SEEK_SET); + $getid3->info['tiff']['ifd'][$ifd_id]['fields'][$key]['raw']['data'] = fread($getid3->fp, $field_array['raw']['length'] * $field_type_byte_length[$field_array['raw']['type']]); + } + break; + } + switch ($field_array['raw']['tag']) { + case 256: // ImageWidth + $getid3->info['video']['resolution_x'] = $field_array['value']; + break; + + case 257: // ImageLength + $getid3->info['video']['resolution_y'] = $field_array['value']; + break; + + case 258: // BitsPerSample + if (isset($field_array['value'])) { + $getid3->info['video']['bits_per_sample'] = $field_array['value']; + } else { + $getid3->info['video']['bits_per_sample'] = 0; + for ($i = 0; $i < $field_array['raw']['length']; $i++) { + $getid3->info['video']['bits_per_sample'] += getid3_lib::$endian2int(substr($getid3->info['tiff']['ifd'][$ifd_id]['fields'][$key]['raw']['data'], $i * $field_type_byte_length[$field_array['raw']['type']], $field_type_byte_length[$field_array['raw']['type']])); + } + } + break; + + case 259: // Compression + $getid3->info['video']['codec'] = getid3_tiff::TIFFcompressionMethod($field_array['value']); + break; + + case 270: // ImageDescription + case 271: // Make + case 272: // Model + case 305: // Software + case 306: // DateTime + case 315: // Artist + case 316: // HostComputer + @$getid3->info['tiff']['comments'][getid3_tiff::TIFFcommentName($field_array['raw']['tag'])][] = $getid3->info['tiff']['ifd'][$ifd_id]['fields'][$key]['raw']['data']; + break; + + default: + break; + } + } + } + + return true; + } + + + + public static function TIFFcompressionMethod($id) { + + static $lookup = array ( + 1 => 'Uncompressed', + 2 => 'Huffman', + 3 => 'Fax - CCITT 3', + 5 => 'LZW', + 32773 => 'PackBits', + ); + return (isset($lookup[$id]) ? $lookup[$id] : 'unknown/invalid ('.$id.')'); + } + + + + public static function TIFFcommentName($id) { + + static $lookup = array ( + 270 => 'imagedescription', + 271 => 'make', + 272 => 'model', + 305 => 'software', + 306 => 'datetime', + 315 => 'artist', + 316 => 'hostcomputer', + ); + return (isset($lookup[$id]) ? $lookup[$id] : 'unknown/invalid ('.$id.')'); + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.lib.data_hash.php b/plugins/getId3Plugin/lib/module.lib.data_hash.php new file mode 100644 index 0000000..2165085 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.lib.data_hash.php @@ -0,0 +1,216 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.lib.data-hash.php | +// | getID3() library file. | +// | dependencies: NONE. | +// +----------------------------------------------------------------------+ +// +// $Id: module.lib.data_hash.php,v 1.3 2006/06/13 08:44:50 ah Exp $ + + + +class getid3_lib_data_hash +{ + + private $getid3; + + + // constructer - calculate md5/sha1 data + public function __construct(getID3 $getid3, $algorithm) { + + $this->getid3 = $getid3; + + // Check algorithm + if (!preg_match('/^(md5|sha1)$/', $algorithm)) { + throw new getid3_exception('Unsupported algorithm, "'.$algorithm.'", in GetHashdata()'); + } + + + //// Handle ogg vorbis files + + if ((@$getid3->info['fileformat'] == 'ogg') && (@$getid3->info['audio']['dataformat'] == 'vorbis')) { + + // We cannot get an identical md5_data value for Ogg files where the comments + // span more than 1 Ogg page (compared to the same audio data with smaller + // comments) using the normal getID3() method of MD5'ing the data between the + // end of the comments and the end of the file (minus any trailing tags), + // because the page sequence numbers of the pages that the audio data is on + // do not match. Under normal circumstances, where comments are smaller than + // the nominal 4-8kB page size, then this is not a problem, but if there are + // very large comments, the only way around it is to strip off the comment + // tags with vorbiscomment and MD5 that file. + // This procedure must be applied to ALL Ogg files, not just the ones with + // comments larger than 1 page, because the below method simply MD5's the + // whole file with the comments stripped, not just the portion after the + // comments block (which is the standard getID3() method. + + // The above-mentioned problem of comments spanning multiple pages and changing + // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but + // currently vorbiscomment only works on OggVorbis files. + + if ((bool)ini_get('safe_mode')) { + throw new getid3_exception('PHP running in Safe Mode - cannot make system call to vorbiscomment[.exe] needed for '.$algorithm.'_data.'); + } + + // Prevent user from aborting script + $old_abort = ignore_user_abort(true); + + // Create empty file + $empty = tempnam('*', 'getID3'); + touch($empty); + + // Use vorbiscomment to make temp file without comments + $temp = tempnam('*', 'getID3'); + + if ($getid3->windowed) { + + $vorbiscomment = $getid3->option_helperapps_dir.'\\vorbiscomment.exe'; + if (!is_readable($vorbiscomment)) { + throw new getid3_exception($vorbiscomment.' does not exist.'); + } + + $command_line = $vorbiscomment.' -w -c "'.$empty.'" "'.realpath($getid3->filename).'" "'.$temp.'"'; + + } else { + + $command_line = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg(realpath($getid3->filename)).' '.escapeshellarg($temp).' 2>&1'; + } + + // Error from vorbiscomment + if ($vorbis_comment_error = `$command_line`) { + throw new getid3_exception('System call to vorbiscomment[.exe] needed for '.$algorithm.'_data failed. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp. Error returned: '.$vorbis_comment_error); + } + + // Get hash of newly created file + $hash_function = $algorithm . '_file'; + $getid3->info[$algorithm.'_data'] = $hash_function($temp); + + // Clean up + unlink($empty); + unlink($temp); + + // Reset abort setting + ignore_user_abort($old_abort); + + // Return success + return true; + } + + //// Handle other file formats + + // Get hash from part of file + if (@$getid3->info['avdataoffset'] || (@$getid3->info['avdataend'] && @$getid3->info['avdataend'] < $getid3->info['filesize'])) { + + if ((bool)ini_get('safe_mode')) { + $getid3->warning('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm.'); + $hash_function = 'hash_file_partial_safe_mode'; + } + else { + $hash_function = $getid3->windowed ? 'hash_file_partial_windows' : 'hash_file_partial_unix'; + } + + $getid3->info[$algorithm.'_data'] = $this->$hash_function($getid3->filename, $getid3->info['avdataoffset'], $getid3->info['avdataend'], $algorithm); + } + + // Get hash from whole file - use built-in md5_file() and sha1_file() + else { + $hash_function = $algorithm . '_file'; + $getid3->info[$algorithm.'_data'] = $hash_function($getid3->filename); + } + } + + + + // Return md5/sha1sum for a file from starting position to absolute end position + // Using windows system call + private function hash_file_partial_windows($file, $offset, $end, $algorithm) { + + $size = $end - $offset; + + // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data + // Fall back to create-temp-file method: + if ($algorithm == 'sha1') { + return $this->hash_file_partial_safe_mode($file, $offset, $end, $algorithm); + } + + foreach (array ('alg_sum' => $algorithm.'sum.exe', 'cygwin' => 'cygwin1.dll', 'head' => 'head.exe', 'tail' => 'tail.exe') as $name => $req_filename) { + + $$name = $this->getid3->option_helperapps_dir.'\\'.$req_filename; + + // helper apps not available - fall back to old method + if (!is_readable($$name)) { + return $this->hash_file_partial_safe_mode($file, $offset, $end, $algorithm); + } + } + + $command_line = $head.' -c'.$end.' "'.realpath($file).'" | '.$tail.' -c'.$size.' | '.$alg_sum; + + return substr(`$command_line`, 0, $algorithm == 'md5' ? 32 : 40); + } + + + + // Return md5/sha1sum for a file from starting position to absolute end position + // Using unix system call + private function hash_file_partial_unix($file, $offset, $end, $algorithm) { + + $size = $end - $offset; + + $command_line = "head -c $end \"$file\" | tail -c $size | ${algorithm}sum"; + + return substr(`$command_line`, 0, $algorithm == 'md5' ? 32 : 40); + } + + + + // Return md5/sha1sum for a file from starting position to absolute end position + // Using slow safe_mode temp file + private function hash_file_partial_safe_mode($file, $offset, $end, $algorithm) { + + // Attempt to create a temporary file in the system temp directory - invalid dirname should force to system temp dir + if (($data_filename = tempnam('*', 'getID3')) === false) { + throw new getid3_exception('Unable to create temporary file.'); + } + + // Init + $result = false; + + // Copy parts of file + if ($fp = @fopen($file, 'rb')) { + + if ($fp_data = @fopen($data_filename, 'wb')) { + + fseek($fp, $offset, SEEK_SET); + $bytes_left_to_write = $end - $offset; + while (($bytes_left_to_write > 0) && ($buffer = fread($fp, getid3::FREAD_BUFFER_SIZE))) { + $bytes_written = fwrite($fp_data, $buffer, $bytes_left_to_write); + $bytes_left_to_write -= $bytes_written; + } + fclose($fp_data); + $hash_function = $algorithm . '_file'; + $result = $hash_function($data_filename); + + } + fclose($fp); + } + unlink($data_filename); + return $result; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.lib.iconv_replacement.php b/plugins/getId3Plugin/lib/module.lib.iconv_replacement.php new file mode 100644 index 0000000..5f48f78 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.lib.iconv_replacement.php @@ -0,0 +1,415 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.lib.iconv_replacement.php | +// | getID3() library file. | +// | dependencies: NONE, required by getid3.php if no iconv() present. | +// +----------------------------------------------------------------------+ +// +// $Id: module.lib.iconv_replacement.php,v 1.3 2006/06/24 22:58:31 ah Exp $ + + +class getid3_iconv_replacement +{ + + public static function iconv($in_charset, $out_charset, $string) { + + if ($in_charset == $out_charset) { + return $string; + } + + static $supported_charsets = array ( + 'ISO-8859-1' => 'iso88591', + 'UTF-8' => 'utf8', + 'UTF-16BE' => 'utf16be', + 'UTF-16LE' => 'utf16le', + 'UTF-16' => 'utf16' + ); + + // Convert + $function_name = 'iconv_' . @$supported_charsets[$in_charset] . '_' . @$supported_charsets[$out_charset]; + + if (is_callable(array('getid3_iconv_replacement', $function_name))) { + return getid3_iconv_replacement::$function_name($string); + } + + // Invalid charset used + if (!@$supported_charsets[$in_charset]) { + throw new getid3_exception('PHP does not have iconv() support - cannot use ' . $in_charset . ' charset.'); + } + + if (!@$supported_charsets[$out_charset]) { + throw new getid3_exception('PHP does not have iconv() support - cannot use ' . $out_charset . ' charset.'); + } + } + + + + public static function iconv_int_utf8($charval) { + if ($charval < 128) { + // 0bbbbbbb + $newcharstring = chr($charval); + } elseif ($charval < 2048) { + // 110bbbbb 10bbbbbb + $newcharstring = chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } elseif ($charval < 65536) { + // 1110bbbb 10bbbbbb 10bbbbbb + $newcharstring = chr(($charval >> 12) | 0xE0); + $newcharstring .= chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } else { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $newcharstring = chr(($charval >> 18) | 0xF0); + $newcharstring .= chr(($charval >> 12) | 0xC0); + $newcharstring .= chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } + return $newcharstring; + } + + + + // ISO-8859-1 => UTF-8 + public static function iconv_iso88591_utf8($string, $bom=false) { + if (function_exists('utf8_encode')) { + return utf8_encode($string); + } + // utf8_encode() unavailable, use getID3()'s iconv() conversions (possibly PHP is compiled without XML support) + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xEF\xBB\xBF"; + } + for ($i = 0; $i < strlen($string); $i++) { + $charval = ord($string{$i}); + $newcharstring .= getid3_iconv_replacement::iconv_int_utf8($charval); + } + return $newcharstring; + } + + + + // ISO-8859-1 => UTF-16BE + public static function iconv_iso88591_utf16be($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFE\xFF"; + } + for ($i = 0; $i < strlen($string); $i++) { + $newcharstring .= "\x00".$string{$i}; + } + return $newcharstring; + } + + + + // ISO-8859-1 => UTF-16LE + public static function iconv_iso88591_utf16le($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFF\xFE"; + } + for ($i = 0; $i < strlen($string); $i++) { + $newcharstring .= $string{$i}."\x00"; + } + return $newcharstring; + } + + + + // ISO-8859-1 => UTF-16 + public static function iconv_iso88591_utf16($string) { + return getid3_lib::iconv_iso88591_utf16le($string, true); + } + + + + // UTF-8 => ISO-8859-1 + public static function iconv_utf8_iso88591($string) { + if (function_exists('utf8_decode')) { + return utf8_decode($string); + } + // utf8_decode() unavailable, use getID3()'s iconv() conversions (possibly PHP is compiled without XML support) + $newcharstring = ''; + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? throw some kind of warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + } + return $newcharstring; + } + + + + // UTF-8 => UTF-16BE + public static function iconv_utf8_utf16be($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFE\xFF"; + } + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? throw some kind of warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 65536) ? getid3_lib::BigEndian2String($charval, 2) : "\x00".'?'); + } + } + return $newcharstring; + } + + + + // UTF-8 => UTF-16LE + public static function iconv_utf8_utf16le($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFF\xFE"; + } + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? maybe throw some warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 65536) ? getid3_lib::LittleEndian2String($charval, 2) : '?'."\x00"); + } + } + return $newcharstring; + } + + + + // UTF-8 => UTF-16 + public static function iconv_utf8_utf16($string) { + return getid3_lib::iconv_utf8_utf16le($string, true); + } + + + + // UTF-16BE => ISO-8859-1 + public static function iconv_utf16be_iso88591($string) { + if (substr($string, 0, 2) == "\xFE\xFF") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::BigEndian2Int(substr($string, $i, 2)); + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + return $newcharstring; + } + + + + // UTF-16BE => UTF-8 + public static function iconv_utf16be_utf8($string) { + if (substr($string, 0, 2) == "\xFE\xFF") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::BigEndian2Int(substr($string, $i, 2)); + $newcharstring .= getid3_iconv_replacement::iconv_int_utf8($charval); + } + return $newcharstring; + } + + + + // UTF-16BE => UTF-16LE + public static function iconv_utf16be_utf16le($string) { + return getid3_iconv_replacement::iconv_utf8_utf16le(getid3_iconv_replacement::iconv_utf16be_utf8($string)); + } + + + + // UTF-16BE => UTF-16 + public static function iconv_utf16be_utf16($string) { + return getid3_iconv_replacement::iconv_utf8_utf16(getid3_iconv_replacement::iconv_utf16be_utf8($string)); + } + + + + // UTF-16LE => ISO-8859-1 + public static function iconv_utf16le_iso88591($string) { + if (substr($string, 0, 2) == "\xFF\xFE") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::LittleEndian2Int(substr($string, $i, 2)); + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + return $newcharstring; + } + + + + // UTF-16LE => UTF-8 + public static function iconv_utf16le_utf8($string) { + if (substr($string, 0, 2) == "\xFF\xFE") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = getid3_lib::LittleEndian2Int(substr($string, $i, 2)); + $newcharstring .= getid3_iconv_replacement::iconv_int_utf8($charval); + } + return $newcharstring; + } + + + + // UTF-16LE => UTF-16BE + public static function iconv_utf16le_utf16be($string) { + return getid3_iconv_replacement::iconv_utf8_utf16be(getid3_iconv_replacement::iconv_utf16le_utf8($string)); + } + + + + // UTF-16LE => UTF-16 + public static function iconv_utf16le_utf16($string) { + return getid3_iconv_replacement::iconv_utf8_utf16(getid3_iconv_replacement::iconv_utf16le_utf8($string)); + } + + + + // UTF-16 => ISO-8859-1 + public static function iconv_utf16_iso88591($string) { + $bom = substr($string, 0, 2); + if ($bom == "\xFE\xFF") { + return getid3_lib::iconv_utf16be_iso88591(substr($string, 2)); + } elseif ($bom == "\xFF\xFE") { + return getid3_lib::iconv_utf16le_iso88591(substr($string, 2)); + } + return $string; + } + + + + // UTF-16 => UTF-8 + public static function iconv_utf16_utf8($string) { + $bom = substr($string, 0, 2); + if ($bom == "\xFE\xFF") { + return getid3_iconv_replacement::iconv_utf16be_utf8(substr($string, 2)); + } elseif ($bom == "\xFF\xFE") { + return getid3_iconv_replacement::iconv_utf16le_utf8(substr($string, 2)); + } + return $string; + } + + + + // UTF-16 => UTF-16BE + public static function iconv_utf16_utf16be($string) { + return getid3_iconv_replacement::iconv_utf8_utf16be(getid3_iconv_replacement::iconv_utf16_utf8($string)); + } + + + + // UTF-16 => UTF-16LE + public static function iconv_utf16_utf16le($string) { + return getid3_iconv_replacement::iconv_utf8_utf16le(getid3_iconv_replacement::iconv_utf16_utf8($string)); + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.lib.image_size.php b/plugins/getId3Plugin/lib/module.lib.image_size.php new file mode 100644 index 0000000..18b37ee --- /dev/null +++ b/plugins/getId3Plugin/lib/module.lib.image_size.php @@ -0,0 +1,126 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.lib.data-hash.php | +// | getID3() library file. | +// | dependencies: NONE. | +// +----------------------------------------------------------------------+ +// +// $Id: module.lib.image_size.php,v 1.1.1.1 2004/08/23 00:01:25 ah Exp $ + + + +class getid3_lib_image_size +{ + + const GIF_SIG = "\x47\x49\x46"; // 'GIF' + const PNG_SIG = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"; + const JPG_SIG = "\xFF\xD8\xFF"; + const JPG_SOS = "\xDA"; // Start Of Scan - image data start + const JPG_SOF0 = "\xC0"; // Start Of Frame N + const JPG_SOF1 = "\xC1"; // N indicates which compression process + const JPG_SOF2 = "\xC2"; // Only SOF0-SOF2 are now in common use + const JPG_SOF3 = "\xC3"; // NB: codes C4 and CC are *not* SOF markers + const JPG_SOF5 = "\xC5"; + const JPG_SOF6 = "\xC6"; + const JPG_SOF7 = "\xC7"; + const JPG_SOF9 = "\xC9"; + const JPG_SOF10 = "\xCA"; + const JPG_SOF11 = "\xCB"; // NB: codes C4 and CC are *not* SOF markers + const JPG_SOF13 = "\xCD"; + const JPG_SOF14 = "\xCE"; + const JPG_SOF15 = "\xCF"; + const JPG_EOI = "\xD9"; // End Of Image (end of datastream) + + + static public function get($img_data) { + + $height = $width = $type = ''; + + if ((substr($img_data, 0, 3) == getid3_lib_image_size::GIF_SIG) && (strlen($img_data) > 10)) { + + $dim = unpack('v2dim', substr($img_data, 6, 4)); + $width = $dim['dim1']; + $height = $dim['dim2']; + $type = 1; + + } elseif ((substr($img_data, 0, 8) == getid3_lib_image_size::PNG_SIG) && (strlen($img_data) > 24)) { + + $dim = unpack('N2dim', substr($img_data, 16, 8)); + $width = $dim['dim1']; + $height = $dim['dim2']; + $type = 3; + + } elseif ((substr($img_data, 0, 3) == getid3_lib_image_size::JPG_SIG) && (strlen($img_data) > 4)) { + + ///////////////// JPG CHUNK SCAN //////////////////// + $img_pos = $type = 2; + $buffer = strlen($img_data) - 2; + while ($img_pos < strlen($img_data)) { + + // synchronize to the marker 0xFF + $img_pos = strpos($img_data, 0xFF, $img_pos) + 1; + $marker = $img_data[$img_pos]; + do { + $marker = ord($img_data[$img_pos++]); + } while ($marker == 255); + + // find dimensions of block + switch (chr($marker)) { + + // Grab width/height from SOF segment (these are acceptable chunk types) + case getid3_lib_image_size::JPG_SOF0: + case getid3_lib_image_size::JPG_SOF1: + case getid3_lib_image_size::JPG_SOF2: + case getid3_lib_image_size::JPG_SOF3: + case getid3_lib_image_size::JPG_SOF5: + case getid3_lib_image_size::JPG_SOF6: + case getid3_lib_image_size::JPG_SOF7: + case getid3_lib_image_size::JPG_SOF9: + case getid3_lib_image_size::JPG_SOF10: + case getid3_lib_image_size::JPG_SOF11: + case getid3_lib_image_size::JPG_SOF13: + case getid3_lib_image_size::JPG_SOF14: + case getid3_lib_image_size::JPG_SOF15: + $dim = unpack('n2dim', substr($img_data, $img_pos + 3, 4)); + $height = $dim['dim1']; + $width = $dim['dim2']; + break 2; // found it so exit + + case getid3_lib_image_size::JPG_EOI: + case getid3_lib_image_size::JPG_SOS: + return false; + + default: // We're not interested in other markers + $skiplen = (ord($img_data[$img_pos++]) << 8) + ord($img_data[$img_pos++]) - 2; + // if the skip is more than what we've read in, read more + $buffer -= $skiplen; + if ($buffer < 512) { // if the buffer of data is too low, read more file. + return false; + } + $img_pos += $skiplen; + break; + } + } + } + + return array ($width, $height, $type); + } // end function + + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.misc.exe.php b/plugins/getId3Plugin/lib/module.misc.exe.php new file mode 100644 index 0000000..8c6bfcf --- /dev/null +++ b/plugins/getId3Plugin/lib/module.misc.exe.php @@ -0,0 +1,59 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.exe.php // +// module for analyzing EXE files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_exe +{ + + function getid3_exe(&$fd, &$ThisFileInfo) { + + fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET); + $EXEheader = fread($fd, 28); + + if (substr($EXEheader, 0, 2) != 'MZ') { + $ThisFileInfo['error'][] = 'Expecting "MZ" at offset '.$ThisFileInfo['avdataoffset'].', found "'.substr($EXEheader, 0, 2).'" instead.'; + return false; + } + + $ThisFileInfo['fileformat'] = 'exe'; + $ThisFileInfo['exe']['mz']['magic'] = 'MZ'; + + $ThisFileInfo['exe']['mz']['raw']['last_page_size'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 2, 2)); + $ThisFileInfo['exe']['mz']['raw']['page_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 4, 2)); + $ThisFileInfo['exe']['mz']['raw']['relocation_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 6, 2)); + $ThisFileInfo['exe']['mz']['raw']['header_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 8, 2)); + $ThisFileInfo['exe']['mz']['raw']['min_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 10, 2)); + $ThisFileInfo['exe']['mz']['raw']['max_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 12, 2)); + $ThisFileInfo['exe']['mz']['raw']['initial_ss'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 14, 2)); + $ThisFileInfo['exe']['mz']['raw']['initial_sp'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 16, 2)); + $ThisFileInfo['exe']['mz']['raw']['checksum'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 18, 2)); + $ThisFileInfo['exe']['mz']['raw']['cs_ip'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 20, 4)); + $ThisFileInfo['exe']['mz']['raw']['relocation_table_offset'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 24, 2)); + $ThisFileInfo['exe']['mz']['raw']['overlay_number'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 26, 2)); + + $ThisFileInfo['exe']['mz']['byte_size'] = (($ThisFileInfo['exe']['mz']['raw']['page_count'] - 1)) * 512 + $ThisFileInfo['exe']['mz']['raw']['last_page_size']; + $ThisFileInfo['exe']['mz']['header_size'] = $ThisFileInfo['exe']['mz']['raw']['header_paragraphs'] * 16; + $ThisFileInfo['exe']['mz']['memory_minimum'] = $ThisFileInfo['exe']['mz']['raw']['min_memory_paragraphs'] * 16; + $ThisFileInfo['exe']['mz']['memory_recommended'] = $ThisFileInfo['exe']['mz']['raw']['max_memory_paragraphs'] * 16; + +$ThisFileInfo['error'][] = 'EXE parsing not enabled in this version of getID3()'; +return false; + + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.misc.iso.php b/plugins/getId3Plugin/lib/module.misc.iso.php new file mode 100644 index 0000000..5dd2496 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.misc.iso.php @@ -0,0 +1,450 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.misc.iso.php | +// | Module for analyzing ISO files | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.misc.iso.php,v 1.2 2006/06/24 22:58:31 ah Exp $ + + + +class getid3_iso extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + $getid3->info['fileformat'] = 'iso'; + + for ($i = 16; $i <= 19; $i++) { + fseek($getid3->fp, 2048 * $i, SEEK_SET); + $iso_header = fread($getid3->fp, 2048); + if (substr($iso_header, 1, 5) == 'CD001') { + switch (ord($iso_header{0})) { + case 1: + $getid3->info['iso']['primary_volume_descriptor']['offset'] = 2048 * $i; + $this->ParsePrimaryVolumeDescriptor($iso_header); + break; + + case 2: + $getid3->info['iso']['supplementary_volume_descriptor']['offset'] = 2048 * $i; + $this->ParseSupplementaryVolumeDescriptor($iso_header); + break; + + default: + // skip + break; + } + } + } + + $this->ParsePathTable(); + + $getid3->info['iso']['files'] = array (); + foreach ($getid3->info['iso']['path_table']['directories'] as $directory_num => $directory_data) { + $getid3->info['iso']['directories'][$directory_num] = $this->ParseDirectoryRecord($directory_data); + } + + return true; + } + + + + private function ParsePrimaryVolumeDescriptor(&$iso_header) { + + $getid3 = $this->getid3; + + // ISO integer values are stored *BOTH* Little-Endian AND Big-Endian format!! + // ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field + + $getid3->info['iso']['primary_volume_descriptor']['raw'] = array (); + $info_iso_primaryVD = &$getid3->info['iso']['primary_volume_descriptor']; + $info_iso_primaryVD_raw = &$info_iso_primaryVD['raw']; + + $info_iso_primaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($iso_header, 0, 1)); + $info_iso_primaryVD_raw['standard_identifier'] = substr($iso_header, 1, 5); + if ($info_iso_primaryVD_raw['standard_identifier'] != 'CD001') { + throw new getid3_exception('Expected "CD001" at offset ('.($info_iso_primaryVD['offset'] + 1).'), found "'.$info_iso_primaryVD_raw['standard_identifier'].'" instead'); + } + + getid3_lib::ReadSequence('LittleEndian2Int', $info_iso_primaryVD_raw, $iso_header, 6, + array ( + 'volume_descriptor_version' => 1, + 'IGNORE-unused_1' => 1, + 'system_identifier' => -32, // string + 'volume_identifier' => -32, // string + 'IGNORE-unused_2' => 8, + 'volume_space_size' => 4, + 'IGNORE-1' => 4, + 'IGNORE-unused_3' => 32, + 'volume_set_size' => 2, + 'IGNORE-2' => 2, + 'volume_sequence_number' => 2, + 'IGNORE-3' => 2, + 'logical_block_size' => 2, + 'IGNORE-4' => 2, + 'path_table_size' => 4, + 'IGNORE-5' => 4, + 'path_table_l_location' => 2, + 'IGNORE-6' => 2, + 'path_table_l_opt_location' => 2, + 'IGNORE-7' => 2, + 'path_table_m_location' => 2, + 'IGNORE-8' => 2, + 'path_table_m_opt_location' => 2, + 'IGNORE-9' => 2, + 'root_directory_record' => -34, // string + 'volume_set_identifier' => -128, // string + 'publisher_identifier' => -128, // string + 'data_preparer_identifier' => -128, // string + 'application_identifier' => -128, // string + 'copyright_file_identifier' => -37, // string + 'abstract_file_identifier' => -37, // string + 'bibliographic_file_identifier' => -37, // string + 'volume_creation_date_time' => -17, // string + 'volume_modification_date_time' => -17, // string + 'volume_expiration_date_time' => -17, // string + 'volume_effective_date_time' => -17, // string + 'file_structure_version' => 1, + 'IGNORE-unused_4' => 1, + 'application_data' => -512 // string + ) + ); + + $info_iso_primaryVD['system_identifier'] = trim($info_iso_primaryVD_raw['system_identifier']); + $info_iso_primaryVD['volume_identifier'] = trim($info_iso_primaryVD_raw['volume_identifier']); + $info_iso_primaryVD['volume_set_identifier'] = trim($info_iso_primaryVD_raw['volume_set_identifier']); + $info_iso_primaryVD['publisher_identifier'] = trim($info_iso_primaryVD_raw['publisher_identifier']); + $info_iso_primaryVD['data_preparer_identifier'] = trim($info_iso_primaryVD_raw['data_preparer_identifier']); + $info_iso_primaryVD['application_identifier'] = trim($info_iso_primaryVD_raw['application_identifier']); + $info_iso_primaryVD['copyright_file_identifier'] = trim($info_iso_primaryVD_raw['copyright_file_identifier']); + $info_iso_primaryVD['abstract_file_identifier'] = trim($info_iso_primaryVD_raw['abstract_file_identifier']); + $info_iso_primaryVD['bibliographic_file_identifier'] = trim($info_iso_primaryVD_raw['bibliographic_file_identifier']); + + $info_iso_primaryVD['volume_creation_date_time'] = getid3_iso::ISOtimeText2UNIXtime($info_iso_primaryVD_raw['volume_creation_date_time']); + $info_iso_primaryVD['volume_modification_date_time'] = getid3_iso::ISOtimeText2UNIXtime($info_iso_primaryVD_raw['volume_modification_date_time']); + $info_iso_primaryVD['volume_expiration_date_time'] = getid3_iso::ISOtimeText2UNIXtime($info_iso_primaryVD_raw['volume_expiration_date_time']); + $info_iso_primaryVD['volume_effective_date_time'] = getid3_iso::ISOtimeText2UNIXtime($info_iso_primaryVD_raw['volume_effective_date_time']); + + if (($info_iso_primaryVD_raw['volume_space_size'] * 2048) > $getid3->info['filesize']) { + throw new getid3_exception('Volume Space Size ('.($info_iso_primaryVD_raw['volume_space_size'] * 2048).' bytes) is larger than the file size ('.$getid3->info['filesize'].' bytes) (truncated file?)'); + } + + return true; + } + + + + private function ParseSupplementaryVolumeDescriptor(&$iso_header) { + + $getid3 = $this->getid3; + + // ISO integer values are stored Both-Endian format!! + // ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field + + $getid3->info['iso']['supplementary_volume_descriptor']['raw'] = array (); + $info_iso_supplementaryVD = &$getid3->info['iso']['supplementary_volume_descriptor']; + $info_iso_supplementaryVD_raw = &$info_iso_supplementaryVD['raw']; + + $info_iso_supplementaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($iso_header, 0, 1)); + $info_iso_supplementaryVD_raw['standard_identifier'] = substr($iso_header, 1, 5); + if ($info_iso_supplementaryVD_raw['standard_identifier'] != 'CD001') { + throw new getid3_exception('Expected "CD001" at offset ('.($info_iso_supplementaryVD['offset'] + 1).'), found "'.$info_iso_supplementaryVD_raw['standard_identifier'].'" instead'); + } + + getid3_lib::ReadSequence('LittleEndian2Int', $info_iso_supplementaryVD_raw, $iso_header, 6, + array ( + 'volume_descriptor_version' => 1, + 'IGNORE-unused_1' => -1, + 'system_identifier' => -32, + 'volume_identifier' => -32, + 'IGNORE-unused_2' => -8, + 'volume_space_size' => 4, + 'IGNORE-1' => 4, + 'IGNORE-unused_3' => -32, + 'volume_set_size' => 2, + 'IGNORE-2' => 2, + 'volume_sequence_number' => 2, + 'IGNORE-3' => 2, + 'logical_block_size' => 2, + 'IGNORE-4' => 2, + 'path_table_size' => 4, + 'IGNORE-5' => 4, + 'path_table_l_location' => 2, + 'IGNORE-6' => 2, + 'path_table_l_opt_location' => 2, + 'IGNORE-7' => 2, + 'path_table_m_location' => 2, + 'IGNORE-8' => 2, + 'path_table_m_opt_location' => 2, + 'IGNORE-9' => 2, + 'root_directory_record' => -34, + 'volume_set_identifier' => -128, + 'publisher_identifier' => -128, + 'data_preparer_identifier' => -128, + 'application_identifier' => -128, + 'copyright_file_identifier' => -37, + 'abstract_file_identifier' => -37, + 'bibliographic_file_identifier' => -37, + 'volume_creation_date_time' => -17, + 'volume_modification_date_time' => -17, + 'volume_expiration_date_time' => -17, + 'volume_effective_date_time' => -17, + 'file_structure_version' => 1, + 'IGNORE-unused_4' => 1, + 'application_data' => -512 + ) + ); + + $info_iso_supplementaryVD['system_identifier'] = trim($info_iso_supplementaryVD_raw['system_identifier']); + $info_iso_supplementaryVD['volume_identifier'] = trim($info_iso_supplementaryVD_raw['volume_identifier']); + $info_iso_supplementaryVD['volume_set_identifier'] = trim($info_iso_supplementaryVD_raw['volume_set_identifier']); + $info_iso_supplementaryVD['publisher_identifier'] = trim($info_iso_supplementaryVD_raw['publisher_identifier']); + $info_iso_supplementaryVD['data_preparer_identifier'] = trim($info_iso_supplementaryVD_raw['data_preparer_identifier']); + $info_iso_supplementaryVD['application_identifier'] = trim($info_iso_supplementaryVD_raw['application_identifier']); + $info_iso_supplementaryVD['copyright_file_identifier'] = trim($info_iso_supplementaryVD_raw['copyright_file_identifier']); + $info_iso_supplementaryVD['abstract_file_identifier'] = trim($info_iso_supplementaryVD_raw['abstract_file_identifier']); + $info_iso_supplementaryVD['bibliographic_file_identifier'] = trim($info_iso_supplementaryVD_raw['bibliographic_file_identifier']); + + $info_iso_supplementaryVD['volume_creation_date_time'] = getid3_iso::ISOtimeText2UNIXtime($info_iso_supplementaryVD_raw['volume_creation_date_time']); + $info_iso_supplementaryVD['volume_modification_date_time'] = getid3_iso::ISOtimeText2UNIXtime($info_iso_supplementaryVD_raw['volume_modification_date_time']); + $info_iso_supplementaryVD['volume_expiration_date_time'] = getid3_iso::ISOtimeText2UNIXtime($info_iso_supplementaryVD_raw['volume_expiration_date_time']); + $info_iso_supplementaryVD['volume_effective_date_time'] = getid3_iso::ISOtimeText2UNIXtime($info_iso_supplementaryVD_raw['volume_effective_date_time']); + + if (($info_iso_supplementaryVD_raw['volume_space_size'] * $info_iso_supplementaryVD_raw['logical_block_size']) > $getid3->info['filesize']) { + throw new getid3_exception('Volume Space Size ('.($info_iso_supplementaryVD_raw['volume_space_size'] * $info_iso_supplementaryVD_raw['logical_block_size']).' bytes) is larger than the file size ('.$getid3->info['filesize'].' bytes) (truncated file?)'); + } + + return true; + } + + + + private function ParsePathTable() { + + $getid3 = $this->getid3; + + if (!isset($getid3->info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']) && !isset($getid3->info['iso']['primary_volume_descriptor']['raw']['path_table_l_location'])) { + return false; + } + if (isset($getid3->info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'])) { + $path_table_location = $getid3->info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']; + $path_table_size = $getid3->info['iso']['supplementary_volume_descriptor']['raw']['path_table_size']; + $text_encoding = 'UTF-16BE'; // Big-Endian Unicode + } + else { + $path_table_location = $getid3->info['iso']['primary_volume_descriptor']['raw']['path_table_l_location']; + $path_table_size = $getid3->info['iso']['primary_volume_descriptor']['raw']['path_table_size']; + $text_encoding = 'ISO-8859-1'; // Latin-1 + } + + if (($path_table_location * 2048) > $getid3->info['filesize']) { + throw new getid3_exception('Path Table Location specifies an offset ('.($path_table_location * 2048).') beyond the end-of-file ('.$getid3->info['filesize'].')'); + } + + $getid3->info['iso']['path_table']['offset'] = $path_table_location * 2048; + fseek($getid3->fp, $getid3->info['iso']['path_table']['offset'], SEEK_SET); + $getid3->info['iso']['path_table']['raw'] = fread($getid3->fp, $path_table_size); + + $offset = 0; + $pathcounter = 1; + while ($offset < $path_table_size) { + + $getid3->info['iso']['path_table']['directories'][$pathcounter] = array (); + $info_iso_pathtable_directories_current = &$getid3->info['iso']['path_table']['directories'][$pathcounter]; + + getid3_lib::ReadSequence('LittleEndian2Int', $info_iso_pathtable_directories_current, $getid3->info['iso']['path_table']['raw'], $offset, + array ( + 'length' => 1, + 'extended_length' => 1, + 'location_logical' => 4, + 'parent_directory' => 2, + ) + ); + + $info_iso_pathtable_directories_current['name'] = substr($getid3->info['iso']['path_table']['raw'], $offset+8, $info_iso_pathtable_directories_current['length']); + + $offset += 8 + $info_iso_pathtable_directories_current['length'] + ($info_iso_pathtable_directories_current['length'] % 2); + + $info_iso_pathtable_directories_current['name_ascii'] = $getid3->iconv($text_encoding, $getid3->encoding, $info_iso_pathtable_directories_current['name'], true); + + $info_iso_pathtable_directories_current['location_bytes'] = $info_iso_pathtable_directories_current['location_logical'] * 2048; + if ($pathcounter == 1) { + $info_iso_pathtable_directories_current['full_path'] = '/'; + } + else { + $info_iso_pathtable_directories_current['full_path'] = $getid3->info['iso']['path_table']['directories'][$info_iso_pathtable_directories_current['parent_directory']]['full_path'].$info_iso_pathtable_directories_current['name_ascii'].'/'; + } + $full_path_array[] = $info_iso_pathtable_directories_current['full_path']; + + $pathcounter++; + } + + return true; + } + + + + private function ParseDirectoryRecord($directory_data) { + + $getid3 = $this->getid3; + + $text_encoding = isset($getid3->info['iso']['supplementary_volume_descriptor']) ? 'UTF-16BE' : 'ISO-8859-1'; + + fseek($getid3->fp, $directory_data['location_bytes'], SEEK_SET); + $directory_record_data = fread($getid3->fp, 1); + + while (ord($directory_record_data{0}) > 33) { + + $directory_record_data .= fread($getid3->fp, ord($directory_record_data{0}) - 1); + + $this_directory_record = array (); + $this_directory_record['raw'] = array (); + $this_directory_record_raw = &$this_directory_record['raw']; + + getid3_lib::ReadSequence('LittleEndian2Int', $this_directory_record_raw, $directory_record_data, 0, + array ( + 'length' => 1, + 'extended_attribute_length' => 1, + 'offset_logical' => 4, + 'IGNORE-1' => 4, + 'filesize' => 4, + 'IGNORE-2' => 4, + 'recording_date_time' => -7, + 'file_flags' => 1, + 'file_unit_size' => 1, + 'interleave_gap_size' => 1, + 'volume_sequence_number' => 2, + 'IGNORE-3' => 2, + 'file_identifier_length' => 1, + ) + ); + + $this_directory_record_raw['file_identifier'] = substr($directory_record_data, 33, $this_directory_record_raw['file_identifier_length']); + + $this_directory_record['file_identifier_ascii'] = $getid3->iconv($text_encoding, $getid3->encoding, $this_directory_record_raw['file_identifier'], true); + $this_directory_record['filesize'] = $this_directory_record_raw['filesize']; + $this_directory_record['offset_bytes'] = $this_directory_record_raw['offset_logical'] * 2048; + $this_directory_record['file_flags']['hidden'] = (bool)($this_directory_record_raw['file_flags'] & 0x01); + $this_directory_record['file_flags']['directory'] = (bool)($this_directory_record_raw['file_flags'] & 0x02); + $this_directory_record['file_flags']['associated'] = (bool)($this_directory_record_raw['file_flags'] & 0x04); + $this_directory_record['file_flags']['extended'] = (bool)($this_directory_record_raw['file_flags'] & 0x08); + $this_directory_record['file_flags']['permissions'] = (bool)($this_directory_record_raw['file_flags'] & 0x10); + $this_directory_record['file_flags']['multiple'] = (bool)($this_directory_record_raw['file_flags'] & 0x80); + $this_directory_record['recording_timestamp'] = getid3_iso::ISOtime2UNIXtime($this_directory_record_raw['recording_date_time']); + + if ($this_directory_record['file_flags']['directory']) { + $this_directory_record['filename'] = $directory_data['full_path']; + } + else { + $this_directory_record['filename'] = $directory_data['full_path'].getid3_iso::ISOstripFilenameVersion($this_directory_record['file_identifier_ascii']); + $getid3->info['iso']['files'] = getid3_iso::array_merge_clobber($getid3->info['iso']['files'], getid3_iso::CreateDeepArray($this_directory_record['filename'], '/', $this_directory_record['filesize'])); + } + + $directory_record[] = $this_directory_record; + $directory_record_data = fread($getid3->fp, 1); + } + + return $directory_record; + } + + + + public static function ISOstripFilenameVersion($iso_filename) { + + // convert 'filename.ext;1' to 'filename.ext' + if (!strstr($iso_filename, ';')) { + return $iso_filename; + } + return substr($iso_filename, 0, strpos($iso_filename, ';')); + } + + + + public static function ISOtimeText2UNIXtime($iso_time) { + + if (!(int)substr($iso_time, 0, 4)) { + return false; + } + + return gmmktime((int)substr($iso_time, 8, 2), (int)substr($iso_time, 10, 2), (int)substr($iso_time, 12, 2), (int)substr($iso_time, 4, 2), (int)substr($iso_time, 6, 2), (int)substr($iso_time, 0, 4)); + } + + + + public static function ISOtime2UNIXtime($iso_time) { + + // Represented by seven bytes: + // 1: Number of years since 1900 + // 2: Month of the year from 1 to 12 + // 3: Day of the Month from 1 to 31 + // 4: Hour of the day from 0 to 23 + // 5: Minute of the hour from 0 to 59 + // 6: second of the minute from 0 to 59 + // 7: Offset from Greenwich Mean Time in number of 15 minute intervals from -48 (West) to +52 (East) + + return gmmktime(ord($iso_time[3]), ord($iso_time[4]), ord($iso_time[5]), ord($iso_time[1]), ord($iso_time[2]), ord($iso_time[0]) + 1900); + } + + + + public static function array_merge_clobber($array1, $array2) { + + // written by kchireability*com + // taken from http://www.php.net/manual/en/function.array-merge-recursive.php + + if (!is_array($array1) || !is_array($array2)) { + return false; + } + + $newarray = $array1; + foreach ($array2 as $key => $val) { + if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { + $newarray[$key] = getid3_iso::array_merge_clobber($newarray[$key], $val); + } else { + $newarray[$key] = $val; + } + } + return $newarray; + } + + + + public static function CreateDeepArray($array_path, $separator, $value) { + + // assigns $value to a nested array path: + // $foo = getid3_lib::CreateDeepArray('/path/to/my', '/', 'file.txt') + // is the same as: + // $foo = array ('path'=>array('to'=>'array('my'=>array('file.txt')))); + // or + // $foo['path']['to']['my'] = 'file.txt'; + + while ($array_path{0} == $separator) { + $array_path = substr($array_path, 1); + } + if (($pos = strpos($array_path, $separator)) !== false) { + return array (substr($array_path, 0, $pos) => getid3_iso::CreateDeepArray(substr($array_path, $pos + 1), $separator, $value)); + } + + return array ($array_path => $value); + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.tag.apetag.php b/plugins/getId3Plugin/lib/module.tag.apetag.php new file mode 100644 index 0000000..75f36e4 --- /dev/null +++ b/plugins/getId3Plugin/lib/module.tag.apetag.php @@ -0,0 +1,312 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.tag.apetag.php | +// | module for analyzing APE tags | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.tag.apetag.php,v 1.3 2006/06/06 18:38:54 ah Exp $ + + + +class getid3_apetag extends getid3_handler +{ + /* + ID3v1_TAG_SIZE = 128; + APETAG_HEADER_SIZE = 32; + LYRICS3_TAG_SIZE = 10; + */ + + public $option_override_end_offset = 0; + + + + public function Analyze() { + + $getid3 = $this->getid3; + + if ($this->option_override_end_offset == 0) { + + fseek($getid3->fp, 0 - 170, SEEK_END); // 170 = ID3v1_TAG_SIZE + APETAG_HEADER_SIZE + LYRICS3_TAG_SIZE + $apetag_footer_id3v1 = fread($getid3->fp, 170); // 170 = ID3v1_TAG_SIZE + APETAG_HEADER_SIZE + LYRICS3_TAG_SIZE + + // APE tag found before ID3v1 + if (substr($apetag_footer_id3v1, strlen($apetag_footer_id3v1) - 160, 8) == 'APETAGEX') { // 160 = ID3v1_TAG_SIZE + APETAG_HEADER_SIZE + $getid3->info['ape']['tag_offset_end'] = $getid3->info['filesize'] - 128; // 128 = ID3v1_TAG_SIZE + } + + // APE tag found, no ID3v1 + elseif (substr($apetag_footer_id3v1, strlen($apetag_footer_id3v1) - 32, 8) == 'APETAGEX') { // 32 = APETAG_HEADER_SIZE + $getid3->info['ape']['tag_offset_end'] = $getid3->info['filesize']; + } + + } + else { + + fseek($getid3->fp, $this->option_override_end_offset - 32, SEEK_SET); // 32 = APETAG_HEADER_SIZE + if (fread($getid3->fp, 8) == 'APETAGEX') { + $getid3->info['ape']['tag_offset_end'] = $this->option_override_end_offset; + } + + } + + // APE tag not found + if (!@$getid3->info['ape']['tag_offset_end']) { + return false; + } + + // Shortcut + $info_ape = &$getid3->info['ape']; + + // Read and parse footer + fseek($getid3->fp, $info_ape['tag_offset_end'] - 32, SEEK_SET); // 32 = APETAG_HEADER_SIZE + $apetag_footer_data = fread($getid3->fp, 32); + if (!($this->ParseAPEHeaderFooter($apetag_footer_data, $info_ape['footer']))) { + throw new getid3_exception('Error parsing APE footer at offset '.$info_ape['tag_offset_end']); + } + + if (isset($info_ape['footer']['flags']['header']) && $info_ape['footer']['flags']['header']) { + fseek($getid3->fp, $info_ape['tag_offset_end'] - $info_ape['footer']['raw']['tagsize'] - 32, SEEK_SET); + $info_ape['tag_offset_start'] = ftell($getid3->fp); + $apetag_data = fread($getid3->fp, $info_ape['footer']['raw']['tagsize'] + 32); + } + else { + $info_ape['tag_offset_start'] = $info_ape['tag_offset_end'] - $info_ape['footer']['raw']['tagsize']; + fseek($getid3->fp, $info_ape['tag_offset_start'], SEEK_SET); + $apetag_data = fread($getid3->fp, $info_ape['footer']['raw']['tagsize']); + } + $getid3->info['avdataend'] = $info_ape['tag_offset_start']; + + if (isset($getid3->info['id3v1']['tag_offset_start']) && ($getid3->info['id3v1']['tag_offset_start'] < $info_ape['tag_offset_end'])) { + $getid3->warning('ID3v1 tag information ignored since it appears to be a false synch in APEtag data'); + unset($getid3->info['id3v1']); + } + + $offset = 0; + if (isset($info_ape['footer']['flags']['header']) && $info_ape['footer']['flags']['header']) { + if (!$this->ParseAPEHeaderFooter(substr($apetag_data, 0, 32), $info_ape['header'])) { + throw new getid3_exception('Error parsing APE header at offset '.$info_ape['tag_offset_start']); + } + $offset = 32; + } + + // Shortcut + $getid3->info['replay_gain'] = array (); + $info_replaygain = &$getid3->info['replay_gain']; + + for ($i = 0; $i < $info_ape['footer']['raw']['tag_items']; $i++) { + $value_size = getid3_lib::LittleEndian2Int(substr($apetag_data, $offset, 4)); + $item_flags = getid3_lib::LittleEndian2Int(substr($apetag_data, $offset + 4, 4)); + $offset += 8; + + if (strstr(substr($apetag_data, $offset), "\x00") === false) { + throw new getid3_exception('Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts ' . $offset . ' bytes into the APE tag, at file offset '.($info_ape['tag_offset_start'] + $offset)); + } + + $item_key_length = strpos($apetag_data, "\x00", $offset) - $offset; + $item_key = strtolower(substr($apetag_data, $offset, $item_key_length)); + + // Shortcut + $info_ape['items'][$item_key] = array (); + $info_ape_items_current = &$info_ape['items'][$item_key]; + + $offset += $item_key_length + 1; // skip 0x00 terminator + $info_ape_items_current['data'] = substr($apetag_data, $offset, $value_size); + $offset += $value_size; + + + $info_ape_items_current['flags'] = $this->ParseAPEtagFlags($item_flags); + + switch ($info_ape_items_current['flags']['item_contents_raw']) { + case 0: // UTF-8 + case 3: // Locator (URL, filename, etc), UTF-8 encoded + $info_ape_items_current['data'] = explode("\x00", trim($info_ape_items_current['data'])); + break; + + default: // binary data + break; + } + + switch (strtolower($item_key)) { + case 'replaygain_track_gain': + $info_replaygain['track']['adjustment'] = (float)str_replace(',', '.', $info_ape_items_current['data'][0]); // float casting will see "0,95" as zero! + $info_replaygain['track']['originator'] = 'unspecified'; + break; + + case 'replaygain_track_peak': + $info_replaygain['track']['peak'] = (float)str_replace(',', '.', $info_ape_items_current['data'][0]); // float casting will see "0,95" as zero! + $info_replaygain['track']['originator'] = 'unspecified'; + if ($info_replaygain['track']['peak'] <= 0) { + $getid3->warning('ReplayGain Track peak from APEtag appears invalid: '.$info_replaygain['track']['peak'].' (original value = "'.$info_ape_items_current['data'][0].'")'); + } + break; + + case 'replaygain_album_gain': + $info_replaygain['album']['adjustment'] = (float)str_replace(',', '.', $info_ape_items_current['data'][0]); // float casting will see "0,95" as zero! + $info_replaygain['album']['originator'] = 'unspecified'; + break; + + case 'replaygain_album_peak': + $info_replaygain['album']['peak'] = (float)str_replace(',', '.', $info_ape_items_current['data'][0]); // float casting will see "0,95" as zero! + $info_replaygain['album']['originator'] = 'unspecified'; + if ($info_replaygain['album']['peak'] <= 0) { + $getid3->warning('ReplayGain Album peak from APEtag appears invalid: '.$info_replaygain['album']['peak'].' (original value = "'.$info_ape_items_current['data'][0].'")'); + } + break; + + case 'mp3gain_undo': + list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $info_ape_items_current['data'][0]); + $info_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left); + $info_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right); + $info_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false); + break; + + case 'mp3gain_minmax': + list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $info_ape_items_current['data'][0]); + $info_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min); + $info_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max); + break; + + case 'mp3gain_album_minmax': + list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $info_ape_items_current['data'][0]); + $info_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min); + $info_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max); + break; + + case 'tracknumber': + foreach ($info_ape_items_current['data'] as $comment) { + $info_ape['comments']['track'][] = $comment; + } + break; + + default: + foreach ($info_ape_items_current['data'] as $comment) { + $info_ape['comments'][strtolower($item_key)][] = $comment; + } + break; + } + + } + if (empty($info_replaygain)) { + unset($getid3->info['replay_gain']); + } + + return true; + } + + + + protected function ParseAPEheaderFooter($data, &$target) { + + // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html + + if (substr($data, 0, 8) != 'APETAGEX') { + return false; + } + + // shortcut + $target['raw'] = array (); + $target_raw = &$target['raw']; + + $target_raw['footer_tag'] = 'APETAGEX'; + + getid3_lib::ReadSequence("LittleEndian2Int", $target_raw, $data, 8, + array ( + 'version' => 4, + 'tagsize' => 4, + 'tag_items' => 4, + 'global_flags' => 4 + ) + ); + $target_raw['reserved'] = substr($data, 24, 8); + + $target['tag_version'] = $target_raw['version'] / 1000; + if ($target['tag_version'] >= 2) { + + $target['flags'] = $this->ParseAPEtagFlags($target_raw['global_flags']); + } + + return true; + } + + + + protected function ParseAPEtagFlags($raw_flag_int) { + + // "Note: APE Tags 1.0 do not use any of the APE Tag flags. + // All are set to zero on creation and ignored on reading." + // http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html + + $target['header'] = (bool) ($raw_flag_int & 0x80000000); + $target['footer'] = (bool) ($raw_flag_int & 0x40000000); + $target['this_is_header'] = (bool) ($raw_flag_int & 0x20000000); + $target['item_contents_raw'] = ($raw_flag_int & 0x00000006) >> 1; + $target['read_only'] = (bool) ($raw_flag_int & 0x00000001); + + $target['item_contents'] = getid3_apetag::APEcontentTypeFlagLookup($target['item_contents_raw']); + + return $target; + } + + + + public static function APEcontentTypeFlagLookup($content_type_id) { + + static $lookup = array ( + 0 => 'utf-8', + 1 => 'binary', + 2 => 'external', + 3 => 'reserved' + ); + return (isset($lookup[$content_type_id]) ? $lookup[$content_type_id] : 'invalid'); + } + + + + public static function APEtagItemIsUTF8Lookup($item_key) { + + static $lookup = array ( + 'title', + 'subtitle', + 'artist', + 'album', + 'debut album', + 'publisher', + 'conductor', + 'track', + 'composer', + 'comment', + 'copyright', + 'publicationright', + 'file', + 'year', + 'record date', + 'record location', + 'genre', + 'media', + 'related', + 'isrc', + 'abstract', + 'language', + 'bibliography' + ); + return in_array(strtolower($item_key), $lookup); + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.tag.id3v1.php b/plugins/getId3Plugin/lib/module.tag.id3v1.php new file mode 100644 index 0000000..c179fef --- /dev/null +++ b/plugins/getId3Plugin/lib/module.tag.id3v1.php @@ -0,0 +1,366 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.tag.id3v1.php | +// | module for analyzing ID3v1 tags | +// | dependencies: NONE | +// +----------------------------------------------------------------------+ +// +// $Id: module.tag.id3v1.php,v 1.3 2006/06/13 08:44:50 ah Exp $ + + + +class getid3_id3v1 extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + fseek($getid3->fp, -256, SEEK_END); + $pre_id3v1 = fread($getid3->fp, 128); + $id3v1_tag = fread($getid3->fp, 128); + + if (substr($id3v1_tag, 0, 3) == 'TAG') { + + $getid3->info['avdataend'] -= 128; + + // Shortcut + $getid3->info['id3v1'] = array (); + $info_id3v1 = &$getid3->info['id3v1']; + + $info_id3v1['title'] = getid3_id3v1::cutfield(substr($id3v1_tag, 3, 30)); + $info_id3v1['artist'] = getid3_id3v1::cutfield(substr($id3v1_tag, 33, 30)); + $info_id3v1['album'] = getid3_id3v1::cutfield(substr($id3v1_tag, 63, 30)); + $info_id3v1['year'] = getid3_id3v1::cutfield(substr($id3v1_tag, 93, 4)); + $info_id3v1['comment'] = substr($id3v1_tag, 97, 30); // can't remove nulls yet, track detection depends on them + $info_id3v1['genreid'] = ord(substr($id3v1_tag, 127, 1)); + + // If second-last byte of comment field is null and last byte of comment field is non-null then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number + if (($id3v1_tag{125} === "\x00") && ($id3v1_tag{126} !== "\x00")) { + $info_id3v1['track'] = ord(substr($info_id3v1['comment'], 29, 1)); + $info_id3v1['comment'] = substr($info_id3v1['comment'], 0, 28); + } + $info_id3v1['comment'] = getid3_id3v1::cutfield($info_id3v1['comment']); + + $info_id3v1['genre'] = getid3_id3v1::LookupGenreName($info_id3v1['genreid']); + if (!empty($info_id3v1['genre'])) { + unset($info_id3v1['genreid']); + } + if (empty($info_id3v1['genre']) || (@$info_id3v1['genre'] == 'Unknown')) { + unset($info_id3v1['genre']); + } + + foreach ($info_id3v1 as $key => $value) { + $key != 'comments' and $info_id3v1['comments'][$key][0] = $value; + } + + // ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces + $good_format_id3v1_tag = getid3_id3v1::GenerateID3v1Tag($info_id3v1['title'], $info_id3v1['artist'], $info_id3v1['album'], $info_id3v1['year'], getid3_id3v1::LookupGenreID(@$info_id3v1['genre']), $info_id3v1['comment'], @$info_id3v1['track']); + if ($id3v1_tag !== $good_format_id3v1_tag) { + $getid3->warning('Some ID3v1 fields do not use NULL characters for padding'); + } + + $info_id3v1['tag_offset_end'] = $getid3->info['filesize']; + $info_id3v1['tag_offset_start'] = $info_id3v1['tag_offset_end'] - 128; + } + + if (substr($pre_id3v1, 0, 3) == 'TAG') { + // The way iTunes handles tags is, well, brain-damaged. + // It completely ignores v1 if ID3v2 is present. + // This goes as far as adding a new v1 tag *even if there already is one* + + // A suspected double-ID3v1 tag has been detected, but it could be that the "TAG" identifier is a legitimate part of an APE or Lyrics3 tag + if (substr($pre_id3v1, 96, 8) == 'APETAGEX') { + // an APE tag footer was found before the last ID3v1, assume false "TAG" synch + } elseif (substr($pre_id3v1, 119, 6) == 'LYRICS') { + // a Lyrics3 tag footer was found before the last ID3v1, assume false "TAG" synch + } else { + // APE and Lyrics3 footers not found - assume double ID3v1 + $getid3->warning('Duplicate ID3v1 tag detected - this has been known to happen with iTunes.'); + $getid3->info['avdataend'] -= 128; + } + } + + return true; + } + + + + public static function cutfield($str) { + + return trim(substr($str, 0, strcspn($str, "\x00"))); + } + + + + public static function ArrayOfGenres($allow_SCMPX_extended=false) { + + static $lookup = array ( + 0 => 'Blues', + 1 => 'Classic Rock', + 2 => 'Country', + 3 => 'Dance', + 4 => 'Disco', + 5 => 'Funk', + 6 => 'Grunge', + 7 => 'Hip-Hop', + 8 => 'Jazz', + 9 => 'Metal', + 10 => 'New Age', + 11 => 'Oldies', + 12 => 'Other', + 13 => 'Pop', + 14 => 'R&B', + 15 => 'Rap', + 16 => 'Reggae', + 17 => 'Rock', + 18 => 'Techno', + 19 => 'Industrial', + 20 => 'Alternative', + 21 => 'Ska', + 22 => 'Death Metal', + 23 => 'Pranks', + 24 => 'Soundtrack', + 25 => 'Euro-Techno', + 26 => 'Ambient', + 27 => 'Trip-Hop', + 28 => 'Vocal', + 29 => 'Jazz+Funk', + 30 => 'Fusion', + 31 => 'Trance', + 32 => 'Classical', + 33 => 'Instrumental', + 34 => 'Acid', + 35 => 'House', + 36 => 'Game', + 37 => 'Sound Clip', + 38 => 'Gospel', + 39 => 'Noise', + 40 => 'Alt. Rock', + 41 => 'Bass', + 42 => 'Soul', + 43 => 'Punk', + 44 => 'Space', + 45 => 'Meditative', + 46 => 'Instrumental Pop', + 47 => 'Instrumental Rock', + 48 => 'Ethnic', + 49 => 'Gothic', + 50 => 'Darkwave', + 51 => 'Techno-Industrial', + 52 => 'Electronic', + 53 => 'Pop-Folk', + 54 => 'Eurodance', + 55 => 'Dream', + 56 => 'Southern Rock', + 57 => 'Comedy', + 58 => 'Cult', + 59 => 'Gangsta Rap', + 60 => 'Top 40', + 61 => 'Christian Rap', + 62 => 'Pop/Funk', + 63 => 'Jungle', + 64 => 'Native American', + 65 => 'Cabaret', + 66 => 'New Wave', + 67 => 'Psychedelic', + 68 => 'Rave', + 69 => 'Showtunes', + 70 => 'Trailer', + 71 => 'Lo-Fi', + 72 => 'Tribal', + 73 => 'Acid Punk', + 74 => 'Acid Jazz', + 75 => 'Polka', + 76 => 'Retro', + 77 => 'Musical', + 78 => 'Rock & Roll', + 79 => 'Hard Rock', + 80 => 'Folk', + 81 => 'Folk/Rock', + 82 => 'National Folk', + 83 => 'Swing', + 84 => 'Fast-Fusion', + 85 => 'Bebob', + 86 => 'Latin', + 87 => 'Revival', + 88 => 'Celtic', + 89 => 'Bluegrass', + 90 => 'Avantgarde', + 91 => 'Gothic Rock', + 92 => 'Progressive Rock', + 93 => 'Psychedelic Rock', + 94 => 'Symphonic Rock', + 95 => 'Slow Rock', + 96 => 'Big Band', + 97 => 'Chorus', + 98 => 'Easy Listening', + 99 => 'Acoustic', + 100 => 'Humour', + 101 => 'Speech', + 102 => 'Chanson', + 103 => 'Opera', + 104 => 'Chamber Music', + 105 => 'Sonata', + 106 => 'Symphony', + 107 => 'Booty Bass', + 108 => 'Primus', + 109 => 'Porn Groove', + 110 => 'Satire', + 111 => 'Slow Jam', + 112 => 'Club', + 113 => 'Tango', + 114 => 'Samba', + 115 => 'Folklore', + 116 => 'Ballad', + 117 => 'Power Ballad', + 118 => 'Rhythmic Soul', + 119 => 'Freestyle', + 120 => 'Duet', + 121 => 'Punk Rock', + 122 => 'Drum Solo', + 123 => 'A Cappella', + 124 => 'Euro-House', + 125 => 'Dance Hall', + 126 => 'Goa', + 127 => 'Drum & Bass', + 128 => 'Club-House', + 129 => 'Hardcore', + 130 => 'Terror', + 131 => 'Indie', + 132 => 'BritPop', + 133 => 'Negerpunk', + 134 => 'Polsk Punk', + 135 => 'Beat', + 136 => 'Christian Gangsta Rap', + 137 => 'Heavy Metal', + 138 => 'Black Metal', + 139 => 'Crossover', + 140 => 'Contemporary Christian', + 141 => 'Christian Rock', + 142 => 'Merengue', + 143 => 'Salsa', + 144 => 'Trash Metal', + 145 => 'Anime', + 146 => 'JPop', + 147 => 'Synthpop', + + 255 => 'Unknown', + + 'CR' => 'Cover', + 'RX' => 'Remix' + ); + + static $lookupSCMPX = array (); + if ($allow_SCMPX_extended && empty($lookupSCMPX)) { + $lookupSCMPX = $lookup; + // http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended + // Extended ID3v1 genres invented by SCMPX + // Note that 255 "Japanese Anime" conflicts with standard "Unknown" + $lookupSCMPX[240] = 'Sacred'; + $lookupSCMPX[241] = 'Northern Europe'; + $lookupSCMPX[242] = 'Irish & Scottish'; + $lookupSCMPX[243] = 'Scotland'; + $lookupSCMPX[244] = 'Ethnic Europe'; + $lookupSCMPX[245] = 'Enka'; + $lookupSCMPX[246] = 'Children\'s Song'; + $lookupSCMPX[247] = 'Japanese Sky'; + $lookupSCMPX[248] = 'Japanese Heavy Rock'; + $lookupSCMPX[249] = 'Japanese Doom Rock'; + $lookupSCMPX[250] = 'Japanese J-POP'; + $lookupSCMPX[251] = 'Japanese Seiyu'; + $lookupSCMPX[252] = 'Japanese Ambient Techno'; + $lookupSCMPX[253] = 'Japanese Moemoe'; + $lookupSCMPX[254] = 'Japanese Tokusatsu'; + //$lookupSCMPX[255] = 'Japanese Anime'; + } + + return ($allow_SCMPX_extended ? $lookupSCMPX : $lookup); + } + + + + public static function LookupGenreName($genre_id, $allow_SCMPX_extended=true) { + + switch ($genre_id) { + case 'RX': + case 'CR': + break; + default: + $genre_id = intval($genre_id); // to handle 3 or '3' or '03' + break; + } + $lookup = getid3_id3v1::ArrayOfGenres($allow_SCMPX_extended); + return (isset($lookup[$genre_id]) ? $lookup[$genre_id] : false); + } + + + public static function LookupGenreID($genre, $allow_SCMPX_extended=false) { + + $lookup = getid3_id3v1::ArrayOfGenres($allow_SCMPX_extended); + $lower_case_no_space_search_term = strtolower(str_replace(' ', '', $genre)); + foreach ($lookup as $key => $value) { + foreach ($lookup as $key => $value) { + if (strtolower(str_replace(' ', '', $value)) == $lower_case_no_space_search_term) { + return $key; + } + } + return false; + } + return (isset($lookup[$genre_id]) ? $lookup[$genre_id] : false); + } + + + + public static function GenerateID3v1Tag($title, $artist, $album, $year, $genre_id, $comment, $track='') { + + $id3v1_tag = 'TAG'; + $id3v1_tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT); + $id3v1_tag .= str_pad(trim(substr($artist, 0, 30)), 30, "\x00", STR_PAD_RIGHT); + $id3v1_tag .= str_pad(trim(substr($album, 0, 30)), 30, "\x00", STR_PAD_RIGHT); + $id3v1_tag .= str_pad(trim(substr($year, 0, 4)), 4, "\x00", STR_PAD_LEFT); + + if (!empty($track) && ($track > 0) && ($track <= 255)) { + $id3v1_tag .= str_pad(trim(substr($comment, 0, 28)), 28, "\x00", STR_PAD_RIGHT); + $id3v1_tag .= "\x00"; + if (gettype($track) == 'string') { + $track = (int)$track; + } + $id3v1_tag .= chr($track); + } else { + $id3v1_tag .= str_pad(trim(substr($comment, 0, 30)), 30, "\x00", STR_PAD_RIGHT); + } + if (($genre_id < 0) || ($genre_id > 147)) { + $genre_id = 255; // 'unknown' genre + } + switch (gettype($genre_id)) { + case 'string': + case 'integer': + $id3v1_tag .= chr(intval($genre_id)); + break; + default: + $id3v1_tag .= chr(255); // 'unknown' genre + break; + } + + return $id3v1_tag; + } + +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/module.tag.id3v2.php b/plugins/getId3Plugin/lib/module.tag.id3v2.php new file mode 100644 index 0000000..93ddbef --- /dev/null +++ b/plugins/getId3Plugin/lib/module.tag.id3v2.php @@ -0,0 +1,3228 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.tag.id3v2.php | +// | module for analyzing ID3v2 tags | +// | dependencies: module.tag.id3v1.php | +// | module.lib.image_size.php (optional) | +// | zlib support in PHP (optional) | +// +----------------------------------------------------------------------+ +// +// $Id: module.tag.id3v2.php,v 1.5 2006/06/24 22:58:31 ah Exp $ + + + + +class getid3_id3v2 extends getid3_handler +{ + + public $option_starting_offset = 0; + + + public function Analyze() { + + $getid3 = $this->getid3; + + // dependency + $getid3->include_module('tag.id3v1'); + + if ($getid3->option_tags_images) { + $getid3->include_module('lib.image_size'); + } + + + // Overall tag structure: + // +-----------------------------+ + // | Header (10 bytes) | + // +-----------------------------+ + // | Extended Header | + // | (variable length, OPTIONAL) | + // +-----------------------------+ + // | Frames (variable length) | + // +-----------------------------+ + // | Padding | + // | (variable length, OPTIONAL) | + // +-----------------------------+ + // | Footer (10 bytes, OPTIONAL) | + // +-----------------------------+ + + // Header + // ID3v2/file identifier "ID3" + // ID3v2 version $04 00 + // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x) + // ID3v2 size 4 * %0xxxxxxx + + + // shortcuts + $getid3->info['id3v2']['header'] = true; + $info_id3v2 = &$getid3->info['id3v2']; + $info_id3v2['flags'] = array (); + $info_id3v2_flags = &$info_id3v2['flags']; + + + $this->fseek($this->option_starting_offset, SEEK_SET); + $header = $this->fread(10); + if (substr($header, 0, 3) == 'ID3') { + + $info_id3v2['majorversion'] = ord($header{3}); + $info_id3v2['minorversion'] = ord($header{4}); + + // shortcut + $id3v2_major_version = &$info_id3v2['majorversion']; + + } else { + unset($getid3->info['id3v2']); + return false; + + } + + if ($id3v2_major_version > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists) + throw new getid3_exception('this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_major_version.'.'.$info_id3v2['minorversion']); + } + + $id3_flags = ord($header{5}); + switch ($id3v2_major_version) { + case 2: + // %ab000000 in v2.2 + $info_id3v2_flags['unsynch'] = (bool)($id3_flags & 0x80); // a - Unsynchronisation + $info_id3v2_flags['compression'] = (bool)($id3_flags & 0x40); // b - Compression + break; + + case 3: + // %abc00000 in v2.3 + $info_id3v2_flags['unsynch'] = (bool)($id3_flags & 0x80); // a - Unsynchronisation + $info_id3v2_flags['exthead'] = (bool)($id3_flags & 0x40); // b - Extended header + $info_id3v2_flags['experim'] = (bool)($id3_flags & 0x20); // c - Experimental indicator + break; + + case 4: + // %abcd0000 in v2.4 + $info_id3v2_flags['unsynch'] = (bool)($id3_flags & 0x80); // a - Unsynchronisation + $info_id3v2_flags['exthead'] = (bool)($id3_flags & 0x40); // b - Extended header + $info_id3v2_flags['experim'] = (bool)($id3_flags & 0x20); // c - Experimental indicator + $info_id3v2_flags['isfooter'] = (bool)($id3_flags & 0x10); // d - Footer present + break; + } + + $info_id3v2['headerlength'] = getid3_lib::BigEndianSyncSafe2Int(substr($header, 6, 4)) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length + + $info_id3v2['tag_offset_start'] = $this->option_starting_offset; + $info_id3v2['tag_offset_end'] = $info_id3v2['tag_offset_start'] + $info_id3v2['headerlength']; + + // Extended Header + if (isset($info_id3v2_flags['exthead']) && $info_id3v2_flags['exthead']) { + + // Extended header size 4 * %0xxxxxxx + // Number of flag bytes $01 + // Extended Flags $xx + // Where the 'Extended header size' is the size of the whole extended header, stored as a 32 bit synchsafe integer. + + $ext_header = fread ($getid3->fp, 4); + $info_id3v2['extheaderlength'] = getid3_lib::BigEndianSyncSafe2Int($ext_header); + + // The extended flags field, with its size described by 'number of flag bytes', is defined as: + // %0bcd0000 + // b - Tag is an update + // Flag data length $00 + // c - CRC data present + // Flag data length $05 + // Total frame CRC 5 * %0xxxxxxx + // d - Tag restrictions + // Flag data length $01 + + $ext_header_flag_bytes = fread ($getid3->fp, 1); + $ext_headerflags = fread ($getid3->fp, $ext_header_flag_bytes); + $id3_exthead_flags = getid3_lib::BigEndian2Bin($header[5]); + $info_id3v2['exthead_flags']['update'] = $id3_exthead_flags[1]; + $info_id3v2['exthead_flags']['CRC'] = $id3_exthead_flags[2]; + + if ($info_id3v2['exthead_flags']['CRC']) { + $ext_header_raw_crc = fread ($getid3->fp, 5); + $info_id3v2['exthead_flags']['CRC'] = getid3_lib::BigEndianSyncSafe2Int($ext_header_raw_crc); + } + + $info_id3v2['exthead_flags']['restrictions'] = substr($id3_exthead_flags, 3, 1); + if ($info_id3v2['exthead_flags']['restrictions']) { + + // Restrictions %ppqrrstt + $ext_headerrawrestrictions = fread ($getid3->fp, 1); + $info_id3v2['exthead_flags']['restrictions_tagsize'] = (bindec('11000000') & ord($ext_headerrawrestrictions)) >> 6; // p - Tag size restrictions + $info_id3v2['exthead_flags']['restrictions_textenc'] = (bindec('00100000') & ord($ext_headerrawrestrictions)) >> 5; // q - Text encoding restrictions + $info_id3v2['exthead_flags']['restrictions_textsize'] = (bindec('00011000') & ord($ext_headerrawrestrictions)) >> 3; // r - Text fields size restrictions + $info_id3v2['exthead_flags']['restrictions_imgenc'] = (bindec('00000100') & ord($ext_headerrawrestrictions)) >> 2; // s - Image encoding restrictions + $info_id3v2['exthead_flags']['restrictions_imgsize'] = (bindec('00000011') & ord($ext_headerrawrestrictions)) >> 0; // t - Image size restrictions + } + } // end extended header + + + + // Frames + + // All ID3v2 frames consists of one frame header followed by one or more + // fields containing the actual information. The header is always 10 + // bytes and laid out as follows: + // + // Frame ID $xx xx xx xx (four characters) + // Size 4 * %0xxxxxxx + // Flags $xx xx + + $size_of_frames = $info_id3v2['headerlength'] - 10; // not including 10-byte initial header + if (isset($info_id3v2['extheaderlength'])) { + $size_of_frames -= $info_id3v2['extheaderlength']; + } + + if (@$info_id3v2_flags['isfooter']) { + $size_of_frames -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio + } + + if ($size_of_frames > 0) { + $frame_data = $this->fread($size_of_frames); // read all frames from file into $frame_data variable + + // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x) + if (@$info_id3v2_flags['unsynch'] && ($id3v2_major_version <= 3)) { + $frame_data = str_replace("\xFF\x00", "\xFF", $frame_data); + } + + // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead + // of on tag level, making it easier to skip frames, increasing the streamability + // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that + // there exists an unsynchronised frame, while the new unsynchronisation flag in + // the frame header [S:4.1.2] indicates unsynchronisation. + + $frame_data_offset = 10; // how many bytes into the stream - start from after the 10-byte header + while (isset($frame_data) && (strlen($frame_data) > 0)) { // cycle through until no more frame data is left to parse + if (strlen($frame_data) <= ($id3v2_major_version == 2 ? 6 : 10)) { + // insufficient room left in ID3v2 header for actual data - must be padding + $info_id3v2['padding']['start'] = $frame_data_offset; + $info_id3v2['padding']['length'] = strlen($frame_data); + $info_id3v2['padding']['valid'] = true; + for ($i = 0; $i < $info_id3v2['padding']['length']; $i++) { + if ($frame_data{$i} != "\x00") { + $info_id3v2['padding']['valid'] = false; + $info_id3v2['padding']['errorpos'] = $info_id3v2['padding']['start'] + $i; + $getid3->warning('Invalid ID3v2 padding found at offset '.$info_id3v2['padding']['errorpos'].' (the remaining '.($info_id3v2['padding']['length'] - $i).' bytes are considered invalid)'); + break; + } + } + break; // skip rest of ID3v2 header + } + + if ($id3v2_major_version == 2) { + // Frame ID $xx xx xx (three characters) + // Size $xx xx xx (24-bit integer) + // Flags $xx xx + + $frame_header = substr($frame_data, 0, 6); // take next 6 bytes for header + $frame_data = substr($frame_data, 6); // and leave the rest in $frame_data + $frame_name = substr($frame_header, 0, 3); + $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3)); + $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs + + + } elseif ($id3v2_major_version > 2) { + + // Frame ID $xx xx xx xx (four characters) + // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+) + // Flags $xx xx + + $frame_header = substr($frame_data, 0, 10); // take next 10 bytes for header + $frame_data = substr($frame_data, 10); // and leave the rest in $frame_data + + $frame_name = substr($frame_header, 0, 4); + + if ($id3v2_major_version == 3) { + $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4)); // 32-bit integer + + } else { // ID3v2.4+ + $frame_size = getid3_lib::BigEndianSyncSafe2Int(substr($frame_header, 4, 4)); // 32-bit synchsafe integer (28-bit value) + } + + if ($frame_size < (strlen($frame_data) + 4)) { + $nextFrameID = substr($frame_data, $frame_size, 4); + if (getid3_id3v2::IsValidID3v2FrameName($nextFrameID, $id3v2_major_version)) { + // next frame is OK + } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) { + // MP3ext known broken frames - "ok" for the purposes of this test + } elseif (($id3v2_major_version == 4) && (getid3_id3v2::IsValidID3v2FrameName(substr($frame_data, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4)), 4), 3))) { + $getid3->warning('ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3'); + $id3v2_major_version = 3; + $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4)); // 32-bit integer + } + } + + + $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2)); + } + + if ((($id3v2_major_version == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) { + // padding encountered + + $info_id3v2['padding']['start'] = $frame_data_offset; + $info_id3v2['padding']['length'] = strlen($frame_data); + $info_id3v2['padding']['valid'] = true; + for ($i = 0; $i < $info_id3v2['padding']['length']; $i++) { + if ($frame_data{$i} != "\x00") { + $info_id3v2['padding']['valid'] = false; + $info_id3v2['padding']['errorpos'] = $info_id3v2['padding']['start'] + $i; + $getid3->warning('Invalid ID3v2 padding found at offset '.$info_id3v2['padding']['errorpos'].' (the remaining '.($info_id3v2['padding']['length'] - $i).' bytes are considered invalid)'); + break; + } + } + break; // skip rest of ID3v2 header + } + + if ($frame_name == 'COM ') { + $getid3->warning('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_major_version.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]'); + $frame_name = 'COMM'; + } + if (($frame_size <= strlen($frame_data)) && (getid3_id3v2::IsValidID3v2FrameName($frame_name, $id3v2_major_version))) { + + unset($parsed_frame); + $parsed_frame['frame_name'] = $frame_name; + $parsed_frame['frame_flags_raw'] = $frame_flags; + $parsed_frame['data'] = substr($frame_data, 0, $frame_size); + $parsed_frame['datalength'] = (int)($frame_size); + $parsed_frame['dataoffset'] = $frame_data_offset; + + $this->ParseID3v2Frame($parsed_frame); + $info_id3v2[$frame_name][] = $parsed_frame; + + $frame_data = substr($frame_data, $frame_size); + + } else { // invalid frame length or FrameID + + if ($frame_size <= strlen($frame_data)) { + + if (getid3_id3v2::IsValidID3v2FrameName(substr($frame_data, $frame_size, 4), $id3v2_major_version)) { + + // next frame is valid, just skip the current frame + $frame_data = substr($frame_data, $frame_size); + $getid3->warning('Next ID3v2 frame is valid, skipping current frame.'); + + } else { + + // next frame is invalid too, abort processing + throw new getid3_exception('Next ID3v2 frame is also invalid, aborting processing.'); + + } + + } elseif ($frame_size == strlen($frame_data)) { + + // this is the last frame, just skip + $getid3->warning('This was the last ID3v2 frame.'); + + } else { + + // next frame is invalid too, abort processing + $frame_data = null; + $getid3->warning('Invalid ID3v2 frame size, aborting.'); + + } + if (!getid3_id3v2::IsValidID3v2FrameName($frame_name, $id3v2_major_version)) { + + switch ($frame_name) { + + case "\x00\x00".'MP': + case "\x00".'MP3': + case ' MP3': + case 'MP3e': + case "\x00".'MP': + case ' MP': + case 'MP3': + $getid3->warning('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_major_version.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]'); + break; + + default: + $getid3->warning('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_major_version.'))).'); + break; + } + + } elseif ($frame_size > strlen($frame_data)){ + + throw new getid3_exception('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($frame_data) ('.strlen($frame_data).')).'); + + } else { + + throw new getid3_exception('error parsing "'.$frame_name.'" ('.$frame_data_offset.' bytes into the ID3v2.'.$id3v2_major_version.' tag).'); + + } + + } + $frame_data_offset += ($frame_size + ($id3v2_major_version == 2 ? 6 : 10)); + + } + + } + + + // Footer + + // The footer is a copy of the header, but with a different identifier. + // ID3v2 identifier "3DI" + // ID3v2 version $04 00 + // ID3v2 flags %abcd0000 + // ID3v2 size 4 * %0xxxxxxx + + if (isset($info_id3v2_flags['isfooter']) && $info_id3v2_flags['isfooter']) { + $footer = fread ($getid3->fp, 10); + if (substr($footer, 0, 3) == '3DI') { + $info_id3v2['footer'] = true; + $info_id3v2['majorversion_footer'] = ord($footer{3}); + $info_id3v2['minorversion_footer'] = ord($footer{4}); + } + if ($info_id3v2['majorversion_footer'] <= 4) { + $id3_flags = ord($footer{5}); + $info_id3v2_flags['unsynch_footer'] = (bool)($id3_flags & 0x80); + $info_id3v2_flags['extfoot_footer'] = (bool)($id3_flags & 0x40); + $info_id3v2_flags['experim_footer'] = (bool)($id3_flags & 0x20); + $info_id3v2_flags['isfooter_footer'] = (bool)($id3_flags & 0x10); + + $info_id3v2['footerlength'] = getid3_lib::BigEndianSyncSafe2Int(substr($footer, 6, 4)); + } + } // end footer + + if (isset($info_id3v2['comments']['genre'])) { + foreach ($info_id3v2['comments']['genre'] as $key => $value) { + unset($info_id3v2['comments']['genre'][$key]); + $info_id3v2['comments'] = getid3_id3v2::array_merge_noclobber($info_id3v2['comments'], getid3_id3v2::ParseID3v2GenreString($value)); + } + } + + if (isset($info_id3v2['comments']['track'])) { + foreach ($info_id3v2['comments']['track'] as $key => $value) { + if (strstr($value, '/')) { + list($info_id3v2['comments']['track'][$key], $info_id3v2['comments']['totaltracks'][$key]) = explode('/', $info_id3v2['comments']['track'][$key]); + } + } + } + + // Use year from recording time if year not set + if (!isset($info_id3v2['comments']['year']) && ereg('^([0-9]{4})', @$info_id3v2['comments']['recording_time'][0], $matches)) { + $info_id3v2['comments']['year'] = array ($matches[1]); + } + + // Set avdataoffset + $getid3->info['avdataoffset'] = $info_id3v2['headerlength']; + if (isset($info_id3v2['footer'])) { + $getid3->info['avdataoffset'] += 10; + } + + return true; + } + + + + private function ParseID3v2Frame(&$parsed_frame) { + + $getid3 = $this->getid3; + + $id3v2_major_version = $getid3->info['id3v2']['majorversion']; + + $frame_name_long = getid3_id3v2::FrameNameLongLookup($parsed_frame['frame_name']); + if ($frame_name_long) { + $parsed_frame['framenamelong'] = $frame_name_long; + } + + $frame_name_short = getid3_id3v2::FrameNameShortLookup($parsed_frame['frame_name']); + if ($frame_name_short) { + $parsed_frame['framenameshort'] = $frame_name_short; + } + + if ($id3v2_major_version >= 3) { // frame flags are not part of the ID3v2.2 standard + + if ($id3v2_major_version == 3) { + + // Frame Header Flags + // %abc00000 %ijk00000 + + $parsed_frame['flags']['TagAlterPreservation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation + $parsed_frame['flags']['FileAlterPreservation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x4000); // b - File alter preservation + $parsed_frame['flags']['ReadOnly'] = (bool)($parsed_frame['frame_flags_raw'] & 0x2000); // c - Read only + $parsed_frame['flags']['compression'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0080); // i - Compression + $parsed_frame['flags']['Encryption'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0040); // j - Encryption + $parsed_frame['flags']['GroupingIdentity'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0020); // k - Grouping identity + + + } elseif ($id3v2_major_version == 4) { + + // Frame Header Flags + // %0abc0000 %0h00kmnp + + $parsed_frame['flags']['TagAlterPreservation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation + $parsed_frame['flags']['FileAlterPreservation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x2000); // b - File alter preservation + $parsed_frame['flags']['ReadOnly'] = (bool)($parsed_frame['frame_flags_raw'] & 0x1000); // c - Read only + $parsed_frame['flags']['GroupingIdentity'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0040); // h - Grouping identity + $parsed_frame['flags']['compression'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0008); // k - Compression + $parsed_frame['flags']['Encryption'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0004); // m - Encryption + $parsed_frame['flags']['Unsynchronisation'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation + $parsed_frame['flags']['DataLengthIndicator'] = (bool)($parsed_frame['frame_flags_raw'] & 0x0001); // p - Data length indicator + + // Frame-level de-unsynchronisation - ID3v2.4 + if ($parsed_frame['flags']['Unsynchronisation']) { + $parsed_frame['data'] = str_replace("\xFF\x00", "\xFF", $parsed_frame['data']); + } + } + + // Frame-level de-compression + if ($parsed_frame['flags']['compression']) { + $parsed_frame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 0, 4)); + + if (!function_exists('gzuncompress')) { + $getid3->warning('gzuncompress() support required to decompress ID3v2 frame "'.$parsed_frame['frame_name'].'"'); + } elseif ($decompressed_data = @gzuncompress(substr($parsed_frame['data'], 4))) { + $parsed_frame['data'] = $decompressed_data; + } else { + $getid3->warning('gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsed_frame['frame_name'].'"'); + } + } + } + + + if (isset($parsed_frame['datalength']) && ($parsed_frame['datalength'] == 0)) { + + $warning = 'Frame "'.$parsed_frame['frame_name'].'" at offset '.$parsed_frame['dataoffset'].' has no data portion'; + switch ($parsed_frame['frame_name']) { + case 'WCOM': + $warning .= ' (this is known to happen with files tagged by RioPort)'; + break; + + default: + break; + } + $getid3->warning($warning); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'UFI'))) { // 4.1 UFI Unique file identifier + + // There may be more than one 'UFID' frame in a tag, + // but only one with the same 'Owner identifier'. + //
    + // Owner identifier $00 + // Identifier + + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00"); + $frame_id_string = substr($parsed_frame['data'], 0, $frame_terminator_pos); + $parsed_frame['ownerid'] = $frame_id_string; + $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen("\x00")); + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'TXX'))) { // 4.2.2 TXX User defined text information frame + + // There may be more than one 'TXXX' frame in each tag, + // but only one with the same description. + //
    + // Text encoding $xx + // Description $00 (00) + // Value + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $parsed_frame['description'] = $frame_description; + $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding))); + if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = trim($getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data'])); + } + unset($parsed_frame['data']); + return true; + } + + + if ($parsed_frame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame + + // There may only be one text information frame of its kind in an tag. + //
    + // Text encoding $xx + // Information + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + + $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset); + + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']); + } + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'WXX'))) { // 4.3.2 WXX User defined URL link frame + + // There may be more than one 'WXXX' frame in each tag, + // but only one with the same description + //
    + // Text encoding $xx + // Description $00 (00) + // URL + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding))); + + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + if ($frame_terminator_pos) { + // there are null bytes after the data - this is not according to spec + // only use data up to first null byte + $frame_urldata = (string)substr($parsed_frame['data'], 0, $frame_terminator_pos); + } else { + // no null bytes following data, just use all data + $frame_urldata = (string)$parsed_frame['data']; + } + + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $parsed_frame['url'] = $frame_urldata; + $parsed_frame['description'] = $frame_description; + if (!empty($parsed_frame['framenameshort']) && $parsed_frame['url']) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['url']); + } + unset($parsed_frame['data']); + return true; + } + + + if ($parsed_frame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames + + // There may only be one URL link frame of its kind in a tag, + // except when stated otherwise in the frame description + //
    + // URL + + $parsed_frame['url'] = trim($parsed_frame['data']); + if (!empty($parsed_frame['framenameshort']) && $parsed_frame['url']) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $parsed_frame['url']; + } + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version == 3) && ($parsed_frame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only) + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only) + + // There may only be one 'IPL' frame in each tag + //
    + // Text encoding $xx + // People list strings + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($parsed_frame['encodingid']); + + $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset); + if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']); + } + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'MCI'))) { // 4.5 MCI Music CD identifier + + // There may only be one 'MCDI' frame in each tag + //
    + // CD TOC + + if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $parsed_frame['data']; + } + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'ETC'))) { // 4.6 ETC Event timing codes + + // There may only be one 'ETCO' frame in each tag + //
    + // Time stamp format $xx + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Followed by a list of key events in the following format: + // Type of event $xx + // Time stamp $xx (xx ...) + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + + $frame_offset = 0; + $parsed_frame['timestampformat'] = ord($parsed_frame['data']{$frame_offset++}); + + while ($frame_offset < strlen($parsed_frame['data'])) { + $parsed_frame['typeid'] = $parsed_frame['data']{$frame_offset++}; + $parsed_frame['type'] = getid3_id3v2::ETCOEventLookup($parsed_frame['typeid']); + $parsed_frame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4)); + $frame_offset += 4; + } + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'MLL'))) { // 4.7 MLL MPEG location lookup table + + // There may only be one 'MLLT' frame in each tag + //
    + // MPEG frames between reference $xx xx + // Bytes between reference $xx xx xx + // Milliseconds between reference $xx xx xx + // Bits for bytes deviation $xx + // Bits for milliseconds dev. $xx + // Then for every reference the following data is included; + // Deviation in bytes %xxx.... + // Deviation in milliseconds %xxx.... + + $frame_offset = 0; + $parsed_frame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 0, 2)); + $parsed_frame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 2, 3)); + $parsed_frame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], 5, 3)); + $parsed_frame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int($parsed_frame['data'][8]); + $parsed_frame['bitsformsdeviation'] = getid3_lib::BigEndian2Int($parsed_frame['data'][9]); + $parsed_frame['data'] = substr($parsed_frame['data'], 10); + + while ($frame_offset < strlen($parsed_frame['data'])) { + $deviation_bitstream .= getid3_lib::BigEndian2Bin($parsed_frame['data']{$frame_offset++}); + } + $reference_counter = 0; + while (strlen($deviation_bitstream) > 0) { + $parsed_frame[$reference_counter]['bytedeviation'] = bindec(substr($deviation_bitstream, 0, $parsed_frame['bitsforbytesdeviation'])); + $parsed_frame[$reference_counter]['msdeviation'] = bindec(substr($deviation_bitstream, $parsed_frame['bitsforbytesdeviation'], $parsed_frame['bitsformsdeviation'])); + $deviation_bitstream = substr($deviation_bitstream, $parsed_frame['bitsforbytesdeviation'] + $parsed_frame['bitsformsdeviation']); + $reference_counter++; + } + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'STC'))) { // 4.8 STC Synchronised tempo codes + + // There may only be one 'SYTC' frame in each tag + //
    + // Time stamp format $xx + // Tempo data + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + + $frame_offset = 0; + $parsed_frame['timestampformat'] = ord($parsed_frame['data']{$frame_offset++}); + $timestamp_counter = 0; + while ($frame_offset < strlen($parsed_frame['data'])) { + $parsed_frame[$timestamp_counter]['tempo'] = ord($parsed_frame['data']{$frame_offset++}); + if ($parsed_frame[$timestamp_counter]['tempo'] == 255) { + $parsed_frame[$timestamp_counter]['tempo'] += ord($parsed_frame['data']{$frame_offset++}); + } + $parsed_frame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4)); + $frame_offset += 4; + $timestamp_counter++; + } + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription + + // There may be more than one 'Unsynchronised lyrics/text transcription' frame + // in each tag, but only one with the same language and content descriptor. + //
    + // Text encoding $xx + // Language $xx xx xx + // Content descriptor $00 (00) + // Lyrics/text + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $frame_language = substr($parsed_frame['data'], $frame_offset, 3); + $frame_offset += 3; + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding))); + + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $parsed_frame['data'] = $parsed_frame['data']; + $parsed_frame['language'] = $frame_language; + $parsed_frame['languagename'] = getid3_id3v2::LanguageLookup($frame_language, false); + $parsed_frame['description'] = $frame_description; + if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']); + } + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'SLT'))) { // 4.10 SLT Synchronised lyric/text + + // There may be more than one 'SYLT' frame in each tag, + // but only one with the same language and content descriptor. + //
    + // Text encoding $xx + // Language $xx xx xx + // Time stamp format $xx + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Content type $xx + // Content descriptor $00 (00) + // Terminated text to be synced (typically a syllable) + // Sync identifier (terminator to above string) $00 (00) + // Time stamp $xx (xx ...) + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $frame_language = substr($parsed_frame['data'], $frame_offset, 3); + $frame_offset += 3; + $parsed_frame['timestampformat'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['contenttypeid'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['contenttype'] = getid3_id3v2::SYTLContentTypeLookup($parsed_frame['contenttypeid']); + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $parsed_frame['language'] = $frame_language; + $parsed_frame['languagename'] = getid3_id3v2::LanguageLookup($frame_language, false); + + $timestamp_index = 0; + $frame_remaining_data = substr($parsed_frame['data'], $frame_offset); + while (strlen($frame_remaining_data)) { + $frame_offset = 0; + $frame_terminator_pos = strpos($frame_remaining_data, getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)); + if ($frame_terminator_pos === false) { + $frame_remaining_data = ''; + } else { + if (ord(substr($frame_remaining_data, $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $parsed_frame['lyrics'][$timestamp_index]['data'] = substr($frame_remaining_data, $frame_offset, $frame_terminator_pos - $frame_offset); + + $frame_remaining_data = substr($frame_remaining_data, $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding))); + if (($timestamp_index == 0) && (ord($frame_remaining_data{0}) != 0)) { + // timestamp probably omitted for first data item + } else { + $parsed_frame['lyrics'][$timestamp_index]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, 0, 4)); + $frame_remaining_data = substr($frame_remaining_data, 4); + } + $timestamp_index++; + } + } + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'COMM')) || // 4.10 COMM Comments + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'COM'))) { // 4.11 COM Comments + + // There may be more than one comment frame in each tag, + // but only one with the same language and content descriptor. + //
    + // Text encoding $xx + // Language $xx xx xx + // Short content descrip. $00 (00) + // The actual text + + if (strlen($parsed_frame['data']) < 5) { + + $getid3->warning('Invalid data (too short) for "'.$parsed_frame['frame_name'].'" frame at offset '.$parsed_frame['dataoffset']); + return true; + } + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $frame_language = substr($parsed_frame['data'], $frame_offset, 3); + $frame_offset += 3; + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_text = (string)substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding))); + + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $parsed_frame['language'] = $frame_language; + $parsed_frame['languagename'] = getid3_id3v2::LanguageLookup($frame_language, false); + $parsed_frame['description'] = $frame_description; + $parsed_frame['data'] = $frame_text; + if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']); + } + return true; + } + + + if (($id3v2_major_version >= 4) && ($parsed_frame['frame_name'] == 'RVA2')) { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only) + + // There may be more than one 'RVA2' frame in each tag, + // but only one with the same identification string + //
    + // Identification $00 + // The 'identification' string is used to identify the situation and/or + // device where this adjustment should apply. The following is then + // repeated for every channel: + // Type of channel $xx + // Volume adjustment $xx xx + // Bits representing peak $xx + // Peak volume $xx (xx ...) + + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00"); + $frame_id_string = substr($parsed_frame['data'], 0, $frame_terminator_pos); + if (ord($frame_id_string) === 0) { + $frame_id_string = ''; + } + $frame_remaining_data = substr($parsed_frame['data'], $frame_terminator_pos + strlen("\x00")); + $parsed_frame['description'] = $frame_id_string; + + while (strlen($frame_remaining_data)) { + $frame_offset = 0; + $frame_channeltypeid = ord(substr($frame_remaining_data, $frame_offset++, 1)); + $parsed_frame[$frame_channeltypeid]['channeltypeid'] = $frame_channeltypeid; + $parsed_frame[$frame_channeltypeid]['channeltype'] = getid3_id3v2::RVA2ChannelTypeLookup($frame_channeltypeid); + $parsed_frame[$frame_channeltypeid]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, $frame_offset, 2), true); // 16-bit signed + $frame_offset += 2; + $parsed_frame[$frame_channeltypeid]['bitspeakvolume'] = ord(substr($frame_remaining_data, $frame_offset++, 1)); + $frame_bytespeakvolume = ceil($parsed_frame[$frame_channeltypeid]['bitspeakvolume'] / 8); + $parsed_frame[$frame_channeltypeid]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, $frame_offset, $frame_bytespeakvolume)); + $frame_remaining_data = substr($frame_remaining_data, $frame_offset + $frame_bytespeakvolume); + } + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version == 3) && ($parsed_frame['frame_name'] == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only) + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'RVA'))) { // 4.12 RVA Relative volume adjustment (ID3v2.2 only) + + // There may only be one 'RVA' frame in each tag + //
    + // ID3v2.2 => Increment/decrement %000000ba + // ID3v2.3 => Increment/decrement %00fedcba + // Bits used for volume descr. $xx + // Relative volume change, right $xx xx (xx ...) // a + // Relative volume change, left $xx xx (xx ...) // b + // Peak volume right $xx xx (xx ...) + // Peak volume left $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, right back $xx xx (xx ...) // c + // Relative volume change, left back $xx xx (xx ...) // d + // Peak volume right back $xx xx (xx ...) + // Peak volume left back $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, center $xx xx (xx ...) // e + // Peak volume center $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, bass $xx xx (xx ...) // f + // Peak volume bass $xx xx (xx ...) + + $frame_offset = 0; + $frame_incrdecrflags = getid3_lib::BigEndian2Bin($parsed_frame['data']{$frame_offset++}); + $parsed_frame['incdec']['right'] = (bool)substr($frame_incrdecrflags, 6, 1); + $parsed_frame['incdec']['left'] = (bool)substr($frame_incrdecrflags, 7, 1); + $parsed_frame['bitsvolume'] = ord($parsed_frame['data']{$frame_offset++}); + $frame_bytesvolume = ceil($parsed_frame['bitsvolume'] / 8); + $parsed_frame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsed_frame['incdec']['right'] === false) { + $parsed_frame['volumechange']['right'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsed_frame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsed_frame['incdec']['left'] === false) { + $parsed_frame['volumechange']['left'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsed_frame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + $parsed_frame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + if ($id3v2_major_version == 3) { + $parsed_frame['data'] = substr($parsed_frame['data'], $frame_offset); + if (strlen($parsed_frame['data']) > 0) { + $parsed_frame['incdec']['rightrear'] = (bool)substr($frame_incrdecrflags, 4, 1); + $parsed_frame['incdec']['leftrear'] = (bool)substr($frame_incrdecrflags, 5, 1); + $parsed_frame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsed_frame['incdec']['rightrear'] === false) { + $parsed_frame['volumechange']['rightrear'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsed_frame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsed_frame['incdec']['leftrear'] === false) { + $parsed_frame['volumechange']['leftrear'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsed_frame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + $parsed_frame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + $parsed_frame['data'] = substr($parsed_frame['data'], $frame_offset); + if (strlen($parsed_frame['data']) > 0) { + $parsed_frame['incdec']['center'] = (bool)substr($frame_incrdecrflags, 3, 1); + $parsed_frame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsed_frame['incdec']['center'] === false) { + $parsed_frame['volumechange']['center'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsed_frame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + $parsed_frame['data'] = substr($parsed_frame['data'], $frame_offset); + if (strlen($parsed_frame['data']) > 0) { + $parsed_frame['incdec']['bass'] = (bool)substr($frame_incrdecrflags, 2, 1); + $parsed_frame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsed_frame['incdec']['bass'] === false) { + $parsed_frame['volumechange']['bass'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsed_frame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + } + unset($parsed_frame['data']); + return true; + } + + + if (($id3v2_major_version >= 4) && ($parsed_frame['frame_name'] == 'EQU2')) { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only) + + // There may be more than one 'EQU2' frame in each tag, + // but only one with the same identification string + //
    + // Interpolation method $xx + // $00 Band + // $01 Linear + // Identification $00 + // The following is then repeated for every adjustment point + // Frequency $xx xx + // Volume adjustment $xx xx + + $frame_offset = 0; + $frame_interpolationmethod = ord($parsed_frame['data']{$frame_offset++}); + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_id_string = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_id_string) === 0) { + $frame_id_string = ''; + } + $parsed_frame['description'] = $frame_id_string; + $frame_remaining_data = substr($parsed_frame['data'], $frame_terminator_pos + strlen("\x00")); + while (strlen($frame_remaining_data)) { + $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remaining_data, 0, 2)) / 2; + $parsed_frame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, 2, 2), true); + $frame_remaining_data = substr($frame_remaining_data, 4); + } + $parsed_frame['interpolationmethod'] = $frame_interpolationmethod; + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version == 3) && ($parsed_frame['frame_name'] == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only) + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'EQU'))) { // 4.13 EQU Equalisation (ID3v2.2 only) + + // There may only be one 'EQUA' frame in each tag + //
    + // Adjustment bits $xx + // This is followed by 2 bytes + ('adjustment bits' rounded up to the + // nearest byte) for every equalisation band in the following format, + // giving a frequency range of 0 - 32767Hz: + // Increment/decrement %x (MSB of the Frequency) + // Frequency (lower 15 bits) + // Adjustment $xx (xx ...) + + $frame_offset = 0; + $parsed_frame['adjustmentbits'] = $parsed_frame['data']{$frame_offset++}; + $frame_adjustment_bytes = ceil($parsed_frame['adjustmentbits'] / 8); + + $frame_remaining_data = (string)substr($parsed_frame['data'], $frame_offset); + while (strlen($frame_remaining_data) > 0) { + $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remaining_data, 0, 2)); + $frame_incdec = (bool)substr($frame_frequencystr, 0, 1); + $frame_frequency = bindec(substr($frame_frequencystr, 1, 15)); + $parsed_frame[$frame_frequency]['incdec'] = $frame_incdec; + $parsed_frame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remaining_data, 2, $frame_adjustment_bytes)); + if ($parsed_frame[$frame_frequency]['incdec'] === false) { + $parsed_frame[$frame_frequency]['adjustment'] *= -1; + } + $frame_remaining_data = substr($frame_remaining_data, 2 + $frame_adjustment_bytes); + } + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'RVRB')) || // 4.13 RVRB Reverb + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'REV'))) { // 4.14 REV Reverb + + // There may only be one 'RVRB' frame in each tag. + //
    + // Reverb left (ms) $xx xx + // Reverb right (ms) $xx xx + // Reverb bounces, left $xx + // Reverb bounces, right $xx + // Reverb feedback, left to left $xx + // Reverb feedback, left to right $xx + // Reverb feedback, right to right $xx + // Reverb feedback, right to left $xx + // Premix left to right $xx + // Premix right to left $xx + + $frame_offset = 0; + $parsed_frame['left'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsed_frame['right'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsed_frame['bouncesL'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['bouncesR'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['feedbackLL'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['feedbackLR'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['feedbackRR'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['feedbackRL'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['premixLR'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['premixRL'] = ord($parsed_frame['data']{$frame_offset++}); + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'APIC')) || // 4.14 APIC Attached picture + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'PIC'))) { // 4.15 PIC Attached picture + + // There may be several pictures attached to one file, + // each in their individual 'APIC' frame, but only one + // with the same content descriptor + //
    + // Text encoding $xx + // ID3v2.3+ => MIME type $00 + // ID3v2.2 => Image format $xx xx xx + // Picture type $xx + // Description $00 (00) + // Picture data + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + + if ($id3v2_major_version == 2) { + $frame_imagetype = substr($parsed_frame['data'], $frame_offset, 3); + if (strtolower($frame_imagetype) == 'ima') { + // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted + // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoffpacbell*net) + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_mimetype = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype))); + if ($frame_imagetype == 'JPEG') { + $frame_imagetype = 'JPG'; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + } else { + $frame_offset += 3; + } + } + + if ($id3v2_major_version > 2) { + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_mimetype = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + } + + $frame_picturetype = ord($parsed_frame['data']{$frame_offset++}); + + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + if ($id3v2_major_version == 2) { + $parsed_frame['imagetype'] = $frame_imagetype; + } else { + $parsed_frame['mime'] = $frame_mimetype; + } + $parsed_frame['picturetypeid'] = $frame_picturetype; + $parsed_frame['picturetype'] = getid3_id3v2::APICPictureTypeLookup($frame_picturetype); + $parsed_frame['description'] = $frame_description; + $parsed_frame['data'] = substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding))); + + if ($getid3->option_tags_images) { + + $image_chunk_check = getid3_lib_image_size::get($parsed_frame['data']); + if (($image_chunk_check[2] >= 1) && ($image_chunk_check[2] <= 3)) { + $parsed_frame['image_mime'] = image_type_to_mime_type($image_chunk_check[2]); + + if ($image_chunk_check[0]) { + $parsed_frame['image_width'] = $image_chunk_check[0]; + } + + if ($image_chunk_check[1]) { + $parsed_frame['image_height'] = $image_chunk_check[1]; + } + + $parsed_frame['image_bytes'] = strlen($parsed_frame['data']); + } + } + + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'GEO'))) { // 4.16 GEO General encapsulated object + + // There may be more than one 'GEOB' frame in each tag, + // but only one with the same content descriptor + //
    + // Text encoding $xx + // MIME type $00 + // Filename $00 (00) + // Content description $00 (00) + // Encapsulated object + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_mimetype = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_filename = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_filename) === 0) { + $frame_filename = ''; + } + $frame_offset = $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)); + + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_offset = $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)); + + $parsed_frame['objectdata'] = (string)substr($parsed_frame['data'], $frame_offset); + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $parsed_frame['mime'] = $frame_mimetype; + $parsed_frame['filename'] = $frame_filename; + $parsed_frame['description'] = $frame_description; + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'PCNT')) || // 4.16 PCNT Play counter + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'CNT'))) { // 4.17 CNT Play counter + + // There may only be one 'PCNT' frame in each tag. + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + //
    + // Counter $xx xx xx xx (xx ...) + + $parsed_frame['data'] = getid3_lib::BigEndian2Int($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'POPM')) || // 4.17 POPM Popularimeter + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'POP'))) { // 4.18 POP Popularimeter + + // There may be more than one 'POPM' frame in each tag, + // but only one with the same email address + //
    + // Email to user $00 + // Rating $xx + // Counter $xx xx xx xx (xx ...) + + $frame_offset = 0; + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_email_address = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_email_address) === 0) { + $frame_email_address = ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + $frame_rating = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['data'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset)); + $parsed_frame['email'] = $frame_email_address; + $parsed_frame['rating'] = $frame_rating; + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'RBUF')) || // 4.18 RBUF Recommended buffer size + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'BUF'))) { // 4.19 BUF Recommended buffer size + + // There may only be one 'RBUF' frame in each tag + //
    + // Buffer size $xx xx xx + // Embedded info flag %0000000x + // Offset to next tag $xx xx xx xx + + $frame_offset = 0; + $parsed_frame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 3)); + $frame_offset += 3; + + $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin($parsed_frame['data']{$frame_offset++}); + $parsed_frame['flags']['embededinfo'] = (bool)substr($frame_embeddedinfoflags, 7, 1); + $parsed_frame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4)); + unset($parsed_frame['data']); + return true; + } + + + if (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'CRM')) { // 4.20 Encrypted meta frame (ID3v2.2 only) + + // There may be more than one 'CRM' frame in a tag, + // but only one with the same 'owner identifier' + //
    + // Owner identifier $00 (00) + // Content/explanation $00 (00) + // Encrypted datablock + + $frame_offset = 0; + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $parsed_frame['ownerid'] = $frame_owner_id; + $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset); + $parsed_frame['description'] = $frame_description; + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'AENC')) || // 4.19 AENC Audio encryption + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'CRA'))) { // 4.21 CRA Audio encryption + + // There may be more than one 'AENC' frames in a tag, + // but only one with the same 'Owner identifier' + //
    + // Owner identifier $00 + // Preview start $xx xx + // Preview length $xx xx + // Encryption info + + $frame_offset = 0; + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_owner_id) === 0) { + $frame_owner_id == ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + $parsed_frame['ownerid'] = $frame_owner_id; + $parsed_frame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsed_frame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsed_frame['encryptioninfo'] = (string)substr($parsed_frame['data'], $frame_offset); + unset($parsed_frame['data']); + return true; + } + + + if ((($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information + (($id3v2_major_version == 2) && ($parsed_frame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information + + // There may be more than one 'LINK' frame in a tag, + // but only one with the same contents + //
    + // ID3v2.3+ => Frame identifier $xx xx xx xx + // ID3v2.2 => Frame identifier $xx xx xx + // URL $00 + // ID and additional data + + $frame_offset = 0; + if ($id3v2_major_version == 2) { + $parsed_frame['frameid'] = substr($parsed_frame['data'], $frame_offset, 3); + $frame_offset += 3; + } else { + $parsed_frame['frameid'] = substr($parsed_frame['data'], $frame_offset, 4); + $frame_offset += 4; + } + + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_url = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_url) === 0) { + $frame_url = ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + $parsed_frame['url'] = $frame_url; + + $parsed_frame['additionaldata'] = (string)substr($parsed_frame['data'], $frame_offset); + if (!empty($parsed_frame['framenameshort']) && $parsed_frame['url']) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['url']); + } + unset($parsed_frame['data']); + return true; + } + + + if (($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'POSS')) { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only) + + // There may only be one 'POSS' frame in each tag + // + // Time stamp format $xx + // Position $xx (xx ...) + + $frame_offset = 0; + $parsed_frame['timestampformat'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['position'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset)); + unset($parsed_frame['data']); + return true; + } + + + if (($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'USER')) { // 4.22 USER Terms of use (ID3v2.3+ only) + + // There may be more than one 'Terms of use' frame in a tag, + // but only one with the same 'Language' + //
    + // Text encoding $xx + // Language $xx xx xx + // The actual text + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $frame_language = substr($parsed_frame['data'], $frame_offset, 3); + $frame_offset += 3; + $parsed_frame['language'] = $frame_language; + $parsed_frame['languagename'] = getid3_id3v2::LanguageLookup($frame_language, false); + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset); + if (!empty($parsed_frame['framenameshort']) && !empty($parsed_frame['data'])) { + $getid3->info['id3v2']['comments'][$parsed_frame['framenameshort']][] = $getid3->iconv($parsed_frame['encoding'], 'UTF-8', $parsed_frame['data']); + } + unset($parsed_frame['data']); + return true; + } + + + if (($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'OWNE')) { // 4.23 OWNE Ownership frame (ID3v2.3+ only) + + // There may only be one 'OWNE' frame in a tag + //
    + // Text encoding $xx + // Price paid $00 + // Date of purch. + // Seller + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_pricepaid = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $parsed_frame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3); + $parsed_frame['pricepaid']['currency'] = getid3_id3v2::LookupCurrencyUnits($parsed_frame['pricepaid']['currencyid']); + $parsed_frame['pricepaid']['value'] = substr($frame_pricepaid, 3); + + $parsed_frame['purchasedate'] = substr($parsed_frame['data'], $frame_offset, 8); + if (!getid3_id3v2::IsValidDateStampString($parsed_frame['purchasedate'])) { + $parsed_frame['purchasedateunix'] = gmmktime (0, 0, 0, substr($parsed_frame['purchasedate'], 4, 2), substr($parsed_frame['purchasedate'], 6, 2), substr($parsed_frame['purchasedate'], 0, 4)); + } + $frame_offset += 8; + + $parsed_frame['seller'] = (string)substr($parsed_frame['data'], $frame_offset); + unset($parsed_frame['data']); + return true; + } + + + if (($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'COMR')) { // 4.24 COMR Commercial frame (ID3v2.3+ only) + + // There may be more than one 'commercial frame' in a tag, + // but no two may be identical + //
    + // Text encoding $xx + // Price string $00 + // Valid until + // Contact URL $00 + // Received as $xx + // Name of seller $00 (00) + // Description $00 (00) + // Picture MIME type $00 + // Seller logo + + $frame_offset = 0; + $frame_text_encoding = ord($parsed_frame['data']{$frame_offset++}); + if ((($id3v2_major_version <= 3) && ($frame_text_encoding > 1)) || (($id3v2_major_version == 4) && ($frame_text_encoding > 3))) { + $getid3->warning('Invalid text encoding byte ('.$frame_text_encoding.') in frame "'.$parsed_frame['frame_name'].'" - defaulting to ISO-8859-1 encoding'); + } + + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_price_string = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + $frame_offset = $frame_terminator_pos + strlen("\x00"); + $frame_rawpricearray = explode('/', $frame_price_string); + foreach ($frame_rawpricearray as $key => $val) { + $frame_currencyid = substr($val, 0, 3); + $parsed_frame['price'][$frame_currencyid]['currency'] = getid3_id3v2::LookupCurrencyUnits($frame_currencyid); + $parsed_frame['price'][$frame_currencyid]['value'] = substr($val, 3); + } + + $frame_date_string = substr($parsed_frame['data'], $frame_offset, 8); + $frame_offset += 8; + + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_contacturl = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $frame_received_as_id = ord($parsed_frame['data']{$frame_offset++}); + + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + + $frame_sellername = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_sellername) === 0) { + $frame_sellername = ''; + } + + $frame_offset = $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)); + + $frame_terminator_pos = strpos($parsed_frame['data'], getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding), $frame_offset); + if (ord(substr($parsed_frame['data'], $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)), 1)) === 0) { + $frame_terminator_pos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + + $frame_description = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + + $frame_offset = $frame_terminator_pos + strlen(getid3_id3v2::TextEncodingTerminatorLookup($frame_text_encoding)); + + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_mimetype = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $frame_sellerlogo = substr($parsed_frame['data'], $frame_offset); + + $parsed_frame['encodingid'] = $frame_text_encoding; + $parsed_frame['encoding'] = $this->TextEncodingNameLookup($frame_text_encoding); + + $parsed_frame['pricevaliduntil'] = $frame_date_string; + $parsed_frame['contacturl'] = $frame_contacturl; + $parsed_frame['receivedasid'] = $frame_received_as_id; + $parsed_frame['receivedas'] = getid3_id3v2::COMRReceivedAsLookup($frame_received_as_id); + $parsed_frame['sellername'] = $frame_sellername; + $parsed_frame['description'] = $frame_description; + $parsed_frame['mime'] = $frame_mimetype; + $parsed_frame['logo'] = $frame_sellerlogo; + unset($parsed_frame['data']); + } + + + if (($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'ENCR')) { // 4.25 ENCR Encryption method registration (ID3v2.3+ only) + + // There may be several 'ENCR' frames in a tag, + // but only one containing the same symbol + // and only one containing the same owner identifier + //
    + // Owner identifier $00 + // Method symbol $xx + // Encryption data + + $frame_offset = 0; + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_owner_id) === 0) { + $frame_owner_id = ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $parsed_frame['ownerid'] = $frame_owner_id; + $parsed_frame['methodsymbol'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset); + return true; + } + + + if (($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'GRID')) { // 4.26 GRID Group identification registration (ID3v2.3+ only) + + // There may be several 'GRID' frames in a tag, + // but only one containing the same symbol + // and only one containing the same owner identifier + //
    + // Owner identifier $00 + // Group symbol $xx + // Group dependent data + + $frame_offset = 0; + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_owner_id) === 0) { + $frame_owner_id = ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $parsed_frame['ownerid'] = $frame_owner_id; + $parsed_frame['groupsymbol'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset); + return true; + } + + + if (($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'PRIV')) { // 4.27 PRIV Private frame (ID3v2.3+ only) + + // The tag may contain more than one 'PRIV' frame + // but only with different contents + //
    + // Owner identifier $00 + // The private data + + $frame_offset = 0; + $frame_terminator_pos = strpos($parsed_frame['data'], "\x00", $frame_offset); + $frame_owner_id = substr($parsed_frame['data'], $frame_offset, $frame_terminator_pos - $frame_offset); + if (ord($frame_owner_id) === 0) { + $frame_owner_id = ''; + } + $frame_offset = $frame_terminator_pos + strlen("\x00"); + + $parsed_frame['ownerid'] = $frame_owner_id; + $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset); + return true; + } + + + if (($id3v2_major_version >= 4) && ($parsed_frame['frame_name'] == 'SIGN')) { // 4.28 SIGN Signature frame (ID3v2.4+ only) + + // There may be more than one 'signature frame' in a tag, + // but no two may be identical + //
    + // Group symbol $xx + // Signature + + $frame_offset = 0; + $parsed_frame['groupsymbol'] = ord($parsed_frame['data']{$frame_offset++}); + $parsed_frame['data'] = (string)substr($parsed_frame['data'], $frame_offset); + return true; + } + + + if (($id3v2_major_version >= 4) && ($parsed_frame['frame_name'] == 'SEEK')) { // 4.29 SEEK Seek frame (ID3v2.4+ only) + + // There may only be one 'seek frame' in a tag + //
    + // Minimum offset to next tag $xx xx xx xx + + $frame_offset = 0; + $parsed_frame['data'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4)); + return true; + } + + + if (($id3v2_major_version >= 4) && ($parsed_frame['frame_name'] == 'ASPI')) { // 4.30 ASPI Audio seek point index (ID3v2.4+ only) + + // There may only be one 'audio seek point index' frame in a tag + //
    + // Indexed data start (S) $xx xx xx xx + // Indexed data length (L) $xx xx xx xx + // Number of index points (N) $xx xx + // Bits per index point (b) $xx + // Then for every index point the following data is included: + // Fraction at index (Fi) $xx (xx) + + $frame_offset = 0; + $parsed_frame['datastart'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4)); + $frame_offset += 4; + $parsed_frame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4)); + $frame_offset += 4; + $parsed_frame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsed_frame['bitsperpoint'] = ord($parsed_frame['data']{$frame_offset++}); + $frame_bytesperpoint = ceil($parsed_frame['bitsperpoint'] / 8); + for ($i = 0; $i < $frame_indexpoints; $i++) { + $parsed_frame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, $frame_bytesperpoint)); + $frame_offset += $frame_bytesperpoint; + } + unset($parsed_frame['data']); + return true; + } + + + if (($id3v2_major_version >= 3) && ($parsed_frame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment + + // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html + // There may only be one 'RGAD' frame in a tag + //
    + // Peak Amplitude $xx $xx $xx $xx + // Radio Replay Gain Adjustment %aaabbbcd %dddddddd + // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd + // a - name code + // b - originator code + // c - sign bit + // d - replay gain adjustment + + $frame_offset = 0; + + $parsed_frame['peakamplitude'] = (float)getid3_lib::BigEndian2Int(substr($parsed_frame['data'], $frame_offset, 4)); + $frame_offset += 4; + + $rg_track_adjustment = decbin(substr($parsed_frame['data'], $frame_offset, 2)); + $frame_offset += 2; + + $rg_album_adjustment = decbin(substr($parsed_frame['data'], $frame_offset, 2)); + $frame_offset += 2; + + $parsed_frame['raw']['track']['name'] = bindec(substr($rg_track_adjustment, 0, 3)); + $parsed_frame['raw']['track']['originator'] = bindec(substr($rg_track_adjustment, 3, 3)); + $parsed_frame['raw']['track']['signbit'] = bindec($rg_track_adjustment[6]); + $parsed_frame['raw']['track']['adjustment'] = bindec(substr($rg_track_adjustment, 7, 9)); + $parsed_frame['raw']['album']['name'] = bindec(substr($rg_album_adjustment, 0, 3)); + $parsed_frame['raw']['album']['originator'] = bindec(substr($rg_album_adjustment, 3, 3)); + $parsed_frame['raw']['album']['signbit'] = bindec($rg_album_adjustment[6]); + $parsed_frame['raw']['album']['adjustment'] = bindec(substr($rg_album_adjustment, 7, 9)); + $parsed_frame['track']['name'] = getid3_lib_replaygain::NameLookup($parsed_frame['raw']['track']['name']); + $parsed_frame['track']['originator'] = getid3_lib_replaygain::OriginatorLookup($parsed_frame['raw']['track']['originator']); + $parsed_frame['track']['adjustment'] = getid3_lib_replaygain::AdjustmentLookup($parsed_frame['raw']['track']['adjustment'], $parsed_frame['raw']['track']['signbit']); + $parsed_frame['album']['name'] = getid3_lib_replaygain::NameLookup($parsed_frame['raw']['album']['name']); + $parsed_frame['album']['originator'] = getid3_lib_replaygain::OriginatorLookup($parsed_frame['raw']['album']['originator']); + $parsed_frame['album']['adjustment'] = getid3_lib_replaygain::AdjustmentLookup($parsed_frame['raw']['album']['adjustment'], $parsed_frame['raw']['album']['signbit']); + + $getid3->info['replay_gain']['track']['peak'] = $parsed_frame['peakamplitude']; + $getid3->info['replay_gain']['track']['originator'] = $parsed_frame['track']['originator']; + $getid3->info['replay_gain']['track']['adjustment'] = $parsed_frame['track']['adjustment']; + $getid3->info['replay_gain']['album']['originator'] = $parsed_frame['album']['originator']; + $getid3->info['replay_gain']['album']['adjustment'] = $parsed_frame['album']['adjustment']; + + unset($parsed_frame['data']); + return true; + } + + return true; + } + + + + private function TextEncodingNameLookup($encoding) { + + // Override specification - BRAINDEAD taggers + if (!$encoding) { + return $this->getid3->encoding_id3v2; + } + + // http://www.id3.org/id3v2.4.0-structure.txt + static $lookup = array ( + 0 => 'ISO-8859-1', + 1 => 'UTF-16', + 2 => 'UTF-16BE', + 3 => 'UTF-8', + 255 => 'UTF-16BE' + ); + + return (isset($lookup[$encoding]) ? $lookup[$encoding] : 'ISO-8859-1'); + } + + + + public static function ParseID3v2GenreString($genre_string) { + + // Parse genres into arrays of genreName and genreID + // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)' + // ID3v2.4.x: '21' $00 'Eurodisco' $00 + + $genre_string = trim($genre_string); + $return_array = array (); + if (strpos($genre_string, "\x00") !== false) { + $unprocessed = trim($genre_string); // trailing nulls will cause an infinite loop. + $genre_string = ''; + while (strpos($unprocessed, "\x00") !== false) { + // convert null-seperated v2.4-format into v2.3 ()-seperated format + $end_pos = strpos($unprocessed, "\x00"); + $genre_string .= '('.substr($unprocessed, 0, $end_pos).')'; + $unprocessed = substr($unprocessed, $end_pos + 1); + } + unset($unprocessed); + } + if (getid3_id3v1::LookupGenreID($genre_string)) { + + $return_array['genre'][] = $genre_string; + + } else { + + while (strpos($genre_string, '(') !== false) { + + $start_pos = strpos($genre_string, '('); + $end_pos = strpos($genre_string, ')'); + if (substr($genre_string, $start_pos + 1, 1) == '(') { + $genre_string = substr($genre_string, 0, $start_pos).substr($genre_string, $start_pos + 1); + $end_pos--; + } + $element = substr($genre_string, $start_pos + 1, $end_pos - ($start_pos + 1)); + $genre_string = substr($genre_string, 0, $start_pos).substr($genre_string, $end_pos + 1); + + if (getid3_id3v1::LookupGenreName($element)) { // $element is a valid genre id/abbreviation + + if (empty($return_array['genre']) || !in_array(getid3_id3v1::LookupGenreName($element), $return_array['genre'])) { // avoid duplicate entires + $return_array['genre'][] = getid3_id3v1::LookupGenreName($element); + } + } else { + + if (empty($return_array['genre']) || !in_array($element, $return_array['genre'])) { // avoid duplicate entires + $return_array['genre'][] = $element; + } + } + } + } + if ($genre_string) { + if (empty($return_array['genre']) || !in_array($genre_string, $return_array['genre'])) { // avoid duplicate entires + $return_array['genre'][] = $genre_string; + } + } + + return $return_array; + } + + + + public static function LookupCurrencyUnits($currency_id) { + + static $lookup = array ( + 'AED' => 'Dirhams', + 'AFA' => 'Afghanis', + 'ALL' => 'Leke', + 'AMD' => 'Drams', + 'ANG' => 'Guilders', + 'AOA' => 'Kwanza', + 'ARS' => 'Pesos', + 'ATS' => 'Schillings', + 'AUD' => 'Dollars', + 'AWG' => 'Guilders', + 'AZM' => 'Manats', + 'BAM' => 'Convertible Marka', + 'BBD' => 'Dollars', + 'BDT' => 'Taka', + 'BEF' => 'Francs', + 'BGL' => 'Leva', + 'BHD' => 'Dinars', + 'BIF' => 'Francs', + 'BMD' => 'Dollars', + 'BND' => 'Dollars', + 'BOB' => 'Bolivianos', + 'BRL' => 'Brazil Real', + 'BSD' => 'Dollars', + 'BTN' => 'Ngultrum', + 'BWP' => 'Pulas', + 'BYR' => 'Rubles', + 'BZD' => 'Dollars', + 'CAD' => 'Dollars', + 'CDF' => 'Congolese Francs', + 'CHF' => 'Francs', + 'CLP' => 'Pesos', + 'CNY' => 'Yuan Renminbi', + 'COP' => 'Pesos', + 'CRC' => 'Colones', + 'CUP' => 'Pesos', + 'CVE' => 'Escudos', + 'CYP' => 'Pounds', + 'CZK' => 'Koruny', + 'DEM' => 'Deutsche Marks', + 'DJF' => 'Francs', + 'DKK' => 'Kroner', + 'DOP' => 'Pesos', + 'DZD' => 'Algeria Dinars', + 'EEK' => 'Krooni', + 'EGP' => 'Pounds', + 'ERN' => 'Nakfa', + 'ESP' => 'Pesetas', + 'ETB' => 'Birr', + 'EUR' => 'Euro', + 'FIM' => 'Markkaa', + 'FJD' => 'Dollars', + 'FKP' => 'Pounds', + 'FRF' => 'Francs', + 'GBP' => 'Pounds', + 'GEL' => 'Lari', + 'GGP' => 'Pounds', + 'GHC' => 'Cedis', + 'GIP' => 'Pounds', + 'GMD' => 'Dalasi', + 'GNF' => 'Francs', + 'GRD' => 'Drachmae', + 'GTQ' => 'Quetzales', + 'GYD' => 'Dollars', + 'HKD' => 'Dollars', + 'HNL' => 'Lempiras', + 'HRK' => 'Kuna', + 'HTG' => 'Gourdes', + 'HUF' => 'Forints', + 'IDR' => 'Rupiahs', + 'IEP' => 'Pounds', + 'ILS' => 'New Shekels', + 'IMP' => 'Pounds', + 'INR' => 'Rupees', + 'IQD' => 'Dinars', + 'IRR' => 'Rials', + 'ISK' => 'Kronur', + 'ITL' => 'Lire', + 'JEP' => 'Pounds', + 'JMD' => 'Dollars', + 'JOD' => 'Dinars', + 'JPY' => 'Yen', + 'KES' => 'Shillings', + 'KGS' => 'Soms', + 'KHR' => 'Riels', + 'KMF' => 'Francs', + 'KPW' => 'Won', + 'KWD' => 'Dinars', + 'KYD' => 'Dollars', + 'KZT' => 'Tenge', + 'LAK' => 'Kips', + 'LBP' => 'Pounds', + 'LKR' => 'Rupees', + 'LRD' => 'Dollars', + 'LSL' => 'Maloti', + 'LTL' => 'Litai', + 'LUF' => 'Francs', + 'LVL' => 'Lati', + 'LYD' => 'Dinars', + 'MAD' => 'Dirhams', + 'MDL' => 'Lei', + 'MGF' => 'Malagasy Francs', + 'MKD' => 'Denars', + 'MMK' => 'Kyats', + 'MNT' => 'Tugriks', + 'MOP' => 'Patacas', + 'MRO' => 'Ouguiyas', + 'MTL' => 'Liri', + 'MUR' => 'Rupees', + 'MVR' => 'Rufiyaa', + 'MWK' => 'Kwachas', + 'MXN' => 'Pesos', + 'MYR' => 'Ringgits', + 'MZM' => 'Meticais', + 'NAD' => 'Dollars', + 'NGN' => 'Nairas', + 'NIO' => 'Gold Cordobas', + 'NLG' => 'Guilders', + 'NOK' => 'Krone', + 'NPR' => 'Nepal Rupees', + 'NZD' => 'Dollars', + 'OMR' => 'Rials', + 'PAB' => 'Balboa', + 'PEN' => 'Nuevos Soles', + 'PGK' => 'Kina', + 'PHP' => 'Pesos', + 'PKR' => 'Rupees', + 'PLN' => 'Zlotych', + 'PTE' => 'Escudos', + 'PYG' => 'Guarani', + 'QAR' => 'Rials', + 'ROL' => 'Lei', + 'RUR' => 'Rubles', + 'RWF' => 'Rwanda Francs', + 'SAR' => 'Riyals', + 'SBD' => 'Dollars', + 'SCR' => 'Rupees', + 'SDD' => 'Dinars', + 'SEK' => 'Kronor', + 'SGD' => 'Dollars', + 'SHP' => 'Pounds', + 'SIT' => 'Tolars', + 'SKK' => 'Koruny', + 'SLL' => 'Leones', + 'SOS' => 'Shillings', + 'SPL' => 'Luigini', + 'SRG' => 'Guilders', + 'STD' => 'Dobras', + 'SVC' => 'Colones', + 'SYP' => 'Pounds', + 'SZL' => 'Emalangeni', + 'THB' => 'Baht', + 'TJR' => 'Rubles', + 'TMM' => 'Manats', + 'TND' => 'Dinars', + 'TOP' => 'Pa\'anga', + 'TRL' => 'Liras', + 'TTD' => 'Dollars', + 'TVD' => 'Tuvalu Dollars', + 'TWD' => 'New Dollars', + 'TZS' => 'Shillings', + 'UAH' => 'Hryvnia', + 'UGX' => 'Shillings', + 'USD' => 'Dollars', + 'UYU' => 'Pesos', + 'UZS' => 'Sums', + 'VAL' => 'Lire', + 'VEB' => 'Bolivares', + 'VND' => 'Dong', + 'VUV' => 'Vatu', + 'WST' => 'Tala', + 'XAF' => 'Francs', + 'XAG' => 'Ounces', + 'XAU' => 'Ounces', + 'XCD' => 'Dollars', + 'XDR' => 'Special Drawing Rights', + 'XPD' => 'Ounces', + 'XPF' => 'Francs', + 'XPT' => 'Ounces', + 'YER' => 'Rials', + 'YUM' => 'New Dinars', + 'ZAR' => 'Rand', + 'ZMK' => 'Kwacha', + 'ZWD' => 'Zimbabwe Dollars' + ); + + return @$lookup[$currency_id]; + } + + + + public static function LookupCurrencyCountry($currency_id) { + + static $lookup = array ( + 'AED' => 'United Arab Emirates', + 'AFA' => 'Afghanistan', + 'ALL' => 'Albania', + 'AMD' => 'Armenia', + 'ANG' => 'Netherlands Antilles', + 'AOA' => 'Angola', + 'ARS' => 'Argentina', + 'ATS' => 'Austria', + 'AUD' => 'Australia', + 'AWG' => 'Aruba', + 'AZM' => 'Azerbaijan', + 'BAM' => 'Bosnia and Herzegovina', + 'BBD' => 'Barbados', + 'BDT' => 'Bangladesh', + 'BEF' => 'Belgium', + 'BGL' => 'Bulgaria', + 'BHD' => 'Bahrain', + 'BIF' => 'Burundi', + 'BMD' => 'Bermuda', + 'BND' => 'Brunei Darussalam', + 'BOB' => 'Bolivia', + 'BRL' => 'Brazil', + 'BSD' => 'Bahamas', + 'BTN' => 'Bhutan', + 'BWP' => 'Botswana', + 'BYR' => 'Belarus', + 'BZD' => 'Belize', + 'CAD' => 'Canada', + 'CDF' => 'Congo/Kinshasa', + 'CHF' => 'Switzerland', + 'CLP' => 'Chile', + 'CNY' => 'China', + 'COP' => 'Colombia', + 'CRC' => 'Costa Rica', + 'CUP' => 'Cuba', + 'CVE' => 'Cape Verde', + 'CYP' => 'Cyprus', + 'CZK' => 'Czech Republic', + 'DEM' => 'Germany', + 'DJF' => 'Djibouti', + 'DKK' => 'Denmark', + 'DOP' => 'Dominican Republic', + 'DZD' => 'Algeria', + 'EEK' => 'Estonia', + 'EGP' => 'Egypt', + 'ERN' => 'Eritrea', + 'ESP' => 'Spain', + 'ETB' => 'Ethiopia', + 'EUR' => 'Euro Member Countries', + 'FIM' => 'Finland', + 'FJD' => 'Fiji', + 'FKP' => 'Falkland Islands (Malvinas)', + 'FRF' => 'France', + 'GBP' => 'United Kingdom', + 'GEL' => 'Georgia', + 'GGP' => 'Guernsey', + 'GHC' => 'Ghana', + 'GIP' => 'Gibraltar', + 'GMD' => 'Gambia', + 'GNF' => 'Guinea', + 'GRD' => 'Greece', + 'GTQ' => 'Guatemala', + 'GYD' => 'Guyana', + 'HKD' => 'Hong Kong', + 'HNL' => 'Honduras', + 'HRK' => 'Croatia', + 'HTG' => 'Haiti', + 'HUF' => 'Hungary', + 'IDR' => 'Indonesia', + 'IEP' => 'Ireland (Eire)', + 'ILS' => 'Israel', + 'IMP' => 'Isle of Man', + 'INR' => 'India', + 'IQD' => 'Iraq', + 'IRR' => 'Iran', + 'ISK' => 'Iceland', + 'ITL' => 'Italy', + 'JEP' => 'Jersey', + 'JMD' => 'Jamaica', + 'JOD' => 'Jordan', + 'JPY' => 'Japan', + 'KES' => 'Kenya', + 'KGS' => 'Kyrgyzstan', + 'KHR' => 'Cambodia', + 'KMF' => 'Comoros', + 'KPW' => 'Korea', + 'KWD' => 'Kuwait', + 'KYD' => 'Cayman Islands', + 'KZT' => 'Kazakstan', + 'LAK' => 'Laos', + 'LBP' => 'Lebanon', + 'LKR' => 'Sri Lanka', + 'LRD' => 'Liberia', + 'LSL' => 'Lesotho', + 'LTL' => 'Lithuania', + 'LUF' => 'Luxembourg', + 'LVL' => 'Latvia', + 'LYD' => 'Libya', + 'MAD' => 'Morocco', + 'MDL' => 'Moldova', + 'MGF' => 'Madagascar', + 'MKD' => 'Macedonia', + 'MMK' => 'Myanmar (Burma)', + 'MNT' => 'Mongolia', + 'MOP' => 'Macau', + 'MRO' => 'Mauritania', + 'MTL' => 'Malta', + 'MUR' => 'Mauritius', + 'MVR' => 'Maldives (Maldive Islands)', + 'MWK' => 'Malawi', + 'MXN' => 'Mexico', + 'MYR' => 'Malaysia', + 'MZM' => 'Mozambique', + 'NAD' => 'Namibia', + 'NGN' => 'Nigeria', + 'NIO' => 'Nicaragua', + 'NLG' => 'Netherlands (Holland)', + 'NOK' => 'Norway', + 'NPR' => 'Nepal', + 'NZD' => 'New Zealand', + 'OMR' => 'Oman', + 'PAB' => 'Panama', + 'PEN' => 'Peru', + 'PGK' => 'Papua New Guinea', + 'PHP' => 'Philippines', + 'PKR' => 'Pakistan', + 'PLN' => 'Poland', + 'PTE' => 'Portugal', + 'PYG' => 'Paraguay', + 'QAR' => 'Qatar', + 'ROL' => 'Romania', + 'RUR' => 'Russia', + 'RWF' => 'Rwanda', + 'SAR' => 'Saudi Arabia', + 'SBD' => 'Solomon Islands', + 'SCR' => 'Seychelles', + 'SDD' => 'Sudan', + 'SEK' => 'Sweden', + 'SGD' => 'Singapore', + 'SHP' => 'Saint Helena', + 'SIT' => 'Slovenia', + 'SKK' => 'Slovakia', + 'SLL' => 'Sierra Leone', + 'SOS' => 'Somalia', + 'SPL' => 'Seborga', + 'SRG' => 'Suriname', + 'STD' => 'So Tome and Principe', + 'SVC' => 'El Salvador', + 'SYP' => 'Syria', + 'SZL' => 'Swaziland', + 'THB' => 'Thailand', + 'TJR' => 'Tajikistan', + 'TMM' => 'Turkmenistan', + 'TND' => 'Tunisia', + 'TOP' => 'Tonga', + 'TRL' => 'Turkey', + 'TTD' => 'Trinidad and Tobago', + 'TVD' => 'Tuvalu', + 'TWD' => 'Taiwan', + 'TZS' => 'Tanzania', + 'UAH' => 'Ukraine', + 'UGX' => 'Uganda', + 'USD' => 'United States of America', + 'UYU' => 'Uruguay', + 'UZS' => 'Uzbekistan', + 'VAL' => 'Vatican City', + 'VEB' => 'Venezuela', + 'VND' => 'Viet Nam', + 'VUV' => 'Vanuatu', + 'WST' => 'Samoa', + 'XAF' => 'Communaut Financire Africaine', + 'XAG' => 'Silver', + 'XAU' => 'Gold', + 'XCD' => 'East Caribbean', + 'XDR' => 'International Monetary Fund', + 'XPD' => 'Palladium', + 'XPF' => 'Comptoirs Franais du Pacifique', + 'XPT' => 'Platinum', + 'YER' => 'Yemen', + 'YUM' => 'Yugoslavia', + 'ZAR' => 'South Africa', + 'ZMK' => 'Zambia', + 'ZWD' => 'Zimbabwe' + ); + + return @$lookup[$currency_id]; + } + + + + public static function LanguageLookup($language_code, $case_sensitive=false) { + + if (!$case_sensitive) { + $language_code = strtolower($language_code); + } + + // http://www.id3.org/id3v2.4.0-structure.txt + // [4. ID3v2 frame overview] + // The three byte language field, present in several frames, is used to + // describe the language of the frame's content, according to ISO-639-2 + // [ISO-639-2]. The language should be represented in lower case. If the + // language is not known the string "XXX" should be used. + + + // ISO 639-2 - http://www.id3.org/iso639-2.html + + static $lookup = array ( + 'XXX' => 'unknown', + 'xxx' => 'unknown', + 'aar' => 'Afar', + 'abk' => 'Abkhazian', + 'ace' => 'Achinese', + 'ach' => 'Acoli', + 'ada' => 'Adangme', + 'afa' => 'Afro-Asiatic (Other)', + 'afh' => 'Afrihili', + 'afr' => 'Afrikaans', + 'aka' => 'Akan', + 'akk' => 'Akkadian', + 'alb' => 'Albanian', + 'ale' => 'Aleut', + 'alg' => 'Algonquian Languages', + 'amh' => 'Amharic', + 'ang' => 'English, Old (ca. 450-1100)', + 'apa' => 'Apache Languages', + 'ara' => 'Arabic', + 'arc' => 'Aramaic', + 'arm' => 'Armenian', + 'arn' => 'Araucanian', + 'arp' => 'Arapaho', + 'art' => 'Artificial (Other)', + 'arw' => 'Arawak', + 'asm' => 'Assamese', + 'ath' => 'Athapascan Languages', + 'ava' => 'Avaric', + 'ave' => 'Avestan', + 'awa' => 'Awadhi', + 'aym' => 'Aymara', + 'aze' => 'Azerbaijani', + 'bad' => 'Banda', + 'bai' => 'Bamileke Languages', + 'bak' => 'Bashkir', + 'bal' => 'Baluchi', + 'bam' => 'Bambara', + 'ban' => 'Balinese', + 'baq' => 'Basque', + 'bas' => 'Basa', + 'bat' => 'Baltic (Other)', + 'bej' => 'Beja', + 'bel' => 'Byelorussian', + 'bem' => 'Bemba', + 'ben' => 'Bengali', + 'ber' => 'Berber (Other)', + 'bho' => 'Bhojpuri', + 'bih' => 'Bihari', + 'bik' => 'Bikol', + 'bin' => 'Bini', + 'bis' => 'Bislama', + 'bla' => 'Siksika', + 'bnt' => 'Bantu (Other)', + 'bod' => 'Tibetan', + 'bra' => 'Braj', + 'bre' => 'Breton', + 'bua' => 'Buriat', + 'bug' => 'Buginese', + 'bul' => 'Bulgarian', + 'bur' => 'Burmese', + 'cad' => 'Caddo', + 'cai' => 'Central American Indian (Other)', + 'car' => 'Carib', + 'cat' => 'Catalan', + 'cau' => 'Caucasian (Other)', + 'ceb' => 'Cebuano', + 'cel' => 'Celtic (Other)', + 'ces' => 'Czech', + 'cha' => 'Chamorro', + 'chb' => 'Chibcha', + 'che' => 'Chechen', + 'chg' => 'Chagatai', + 'chi' => 'Chinese', + 'chm' => 'Mari', + 'chn' => 'Chinook jargon', + 'cho' => 'Choctaw', + 'chr' => 'Cherokee', + 'chu' => 'Church Slavic', + 'chv' => 'Chuvash', + 'chy' => 'Cheyenne', + 'cop' => 'Coptic', + 'cor' => 'Cornish', + 'cos' => 'Corsican', + 'cpe' => 'Creoles and Pidgins, English-based (Other)', + 'cpf' => 'Creoles and Pidgins, French-based (Other)', + 'cpp' => 'Creoles and Pidgins, Portuguese-based (Other)', + 'cre' => 'Cree', + 'crp' => 'Creoles and Pidgins (Other)', + 'cus' => 'Cushitic (Other)', + 'cym' => 'Welsh', + 'cze' => 'Czech', + 'dak' => 'Dakota', + 'dan' => 'Danish', + 'del' => 'Delaware', + 'deu' => 'German', + 'din' => 'Dinka', + 'div' => 'Divehi', + 'doi' => 'Dogri', + 'dra' => 'Dravidian (Other)', + 'dua' => 'Duala', + 'dum' => 'Dutch, Middle (ca. 1050-1350)', + 'dut' => 'Dutch', + 'dyu' => 'Dyula', + 'dzo' => 'Dzongkha', + 'efi' => 'Efik', + 'egy' => 'Egyptian (Ancient)', + 'eka' => 'Ekajuk', + 'ell' => 'Greek, Modern (1453-)', + 'elx' => 'Elamite', + 'eng' => 'English', + 'enm' => 'English, Middle (ca. 1100-1500)', + 'epo' => 'Esperanto', + 'esk' => 'Eskimo (Other)', + 'esl' => 'Spanish', + 'est' => 'Estonian', + 'eus' => 'Basque', + 'ewe' => 'Ewe', + 'ewo' => 'Ewondo', + 'fan' => 'Fang', + 'fao' => 'Faroese', + 'fas' => 'Persian', + 'fat' => 'Fanti', + 'fij' => 'Fijian', + 'fin' => 'Finnish', + 'fiu' => 'Finno-Ugrian (Other)', + 'fon' => 'Fon', + 'fra' => 'French', + 'fre' => 'French', + 'frm' => 'French, Middle (ca. 1400-1600)', + 'fro' => 'French, Old (842- ca. 1400)', + 'fry' => 'Frisian', + 'ful' => 'Fulah', + 'gaa' => 'Ga', + 'gae' => 'Gaelic (Scots)', + 'gai' => 'Irish', + 'gay' => 'Gayo', + 'gdh' => 'Gaelic (Scots)', + 'gem' => 'Germanic (Other)', + 'geo' => 'Georgian', + 'ger' => 'German', + 'gez' => 'Geez', + 'gil' => 'Gilbertese', + 'glg' => 'Gallegan', + 'gmh' => 'German, Middle High (ca. 1050-1500)', + 'goh' => 'German, Old High (ca. 750-1050)', + 'gon' => 'Gondi', + 'got' => 'Gothic', + 'grb' => 'Grebo', + 'grc' => 'Greek, Ancient (to 1453)', + 'gre' => 'Greek, Modern (1453-)', + 'grn' => 'Guarani', + 'guj' => 'Gujarati', + 'hai' => 'Haida', + 'hau' => 'Hausa', + 'haw' => 'Hawaiian', + 'heb' => 'Hebrew', + 'her' => 'Herero', + 'hil' => 'Hiligaynon', + 'him' => 'Himachali', + 'hin' => 'Hindi', + 'hmo' => 'Hiri Motu', + 'hun' => 'Hungarian', + 'hup' => 'Hupa', + 'hye' => 'Armenian', + 'iba' => 'Iban', + 'ibo' => 'Igbo', + 'ice' => 'Icelandic', + 'ijo' => 'Ijo', + 'iku' => 'Inuktitut', + 'ilo' => 'Iloko', + 'ina' => 'Interlingua (International Auxiliary language Association)', + 'inc' => 'Indic (Other)', + 'ind' => 'Indonesian', + 'ine' => 'Indo-European (Other)', + 'ine' => 'Interlingue', + 'ipk' => 'Inupiak', + 'ira' => 'Iranian (Other)', + 'iri' => 'Irish', + 'iro' => 'Iroquoian uages', + 'isl' => 'Icelandic', + 'ita' => 'Italian', + 'jav' => 'Javanese', + 'jaw' => 'Javanese', + 'jpn' => 'Japanese', + 'jpr' => 'Judeo-Persian', + 'jrb' => 'Judeo-Arabic', + 'kaa' => 'Kara-Kalpak', + 'kab' => 'Kabyle', + 'kac' => 'Kachin', + 'kal' => 'Greenlandic', + 'kam' => 'Kamba', + 'kan' => 'Kannada', + 'kar' => 'Karen', + 'kas' => 'Kashmiri', + 'kat' => 'Georgian', + 'kau' => 'Kanuri', + 'kaw' => 'Kawi', + 'kaz' => 'Kazakh', + 'kha' => 'Khasi', + 'khi' => 'Khoisan (Other)', + 'khm' => 'Khmer', + 'kho' => 'Khotanese', + 'kik' => 'Kikuyu', + 'kin' => 'Kinyarwanda', + 'kir' => 'Kirghiz', + 'kok' => 'Konkani', + 'kom' => 'Komi', + 'kon' => 'Kongo', + 'kor' => 'Korean', + 'kpe' => 'Kpelle', + 'kro' => 'Kru', + 'kru' => 'Kurukh', + 'kua' => 'Kuanyama', + 'kum' => 'Kumyk', + 'kur' => 'Kurdish', + 'kus' => 'Kusaie', + 'kut' => 'Kutenai', + 'lad' => 'Ladino', + 'lah' => 'Lahnda', + 'lam' => 'Lamba', + 'lao' => 'Lao', + 'lat' => 'Latin', + 'lav' => 'Latvian', + 'lez' => 'Lezghian', + 'lin' => 'Lingala', + 'lit' => 'Lithuanian', + 'lol' => 'Mongo', + 'loz' => 'Lozi', + 'ltz' => 'Letzeburgesch', + 'lub' => 'Luba-Katanga', + 'lug' => 'Ganda', + 'lui' => 'Luiseno', + 'lun' => 'Lunda', + 'luo' => 'Luo (Kenya and Tanzania)', + 'mac' => 'Macedonian', + 'mad' => 'Madurese', + 'mag' => 'Magahi', + 'mah' => 'Marshall', + 'mai' => 'Maithili', + 'mak' => 'Macedonian', + 'mak' => 'Makasar', + 'mal' => 'Malayalam', + 'man' => 'Mandingo', + 'mao' => 'Maori', + 'map' => 'Austronesian (Other)', + 'mar' => 'Marathi', + 'mas' => 'Masai', + 'max' => 'Manx', + 'may' => 'Malay', + 'men' => 'Mende', + 'mga' => 'Irish, Middle (900 - 1200)', + 'mic' => 'Micmac', + 'min' => 'Minangkabau', + 'mis' => 'Miscellaneous (Other)', + 'mkh' => 'Mon-Kmer (Other)', + 'mlg' => 'Malagasy', + 'mlt' => 'Maltese', + 'mni' => 'Manipuri', + 'mno' => 'Manobo Languages', + 'moh' => 'Mohawk', + 'mol' => 'Moldavian', + 'mon' => 'Mongolian', + 'mos' => 'Mossi', + 'mri' => 'Maori', + 'msa' => 'Malay', + 'mul' => 'Multiple Languages', + 'mun' => 'Munda Languages', + 'mus' => 'Creek', + 'mwr' => 'Marwari', + 'mya' => 'Burmese', + 'myn' => 'Mayan Languages', + 'nah' => 'Aztec', + 'nai' => 'North American Indian (Other)', + 'nau' => 'Nauru', + 'nav' => 'Navajo', + 'nbl' => 'Ndebele, South', + 'nde' => 'Ndebele, North', + 'ndo' => 'Ndongo', + 'nep' => 'Nepali', + 'new' => 'Newari', + 'nic' => 'Niger-Kordofanian (Other)', + 'niu' => 'Niuean', + 'nla' => 'Dutch', + 'nno' => 'Norwegian (Nynorsk)', + 'non' => 'Norse, Old', + 'nor' => 'Norwegian', + 'nso' => 'Sotho, Northern', + 'nub' => 'Nubian Languages', + 'nya' => 'Nyanja', + 'nym' => 'Nyamwezi', + 'nyn' => 'Nyankole', + 'nyo' => 'Nyoro', + 'nzi' => 'Nzima', + 'oci' => 'Langue d\'Oc (post 1500)', + 'oji' => 'Ojibwa', + 'ori' => 'Oriya', + 'orm' => 'Oromo', + 'osa' => 'Osage', + 'oss' => 'Ossetic', + 'ota' => 'Turkish, Ottoman (1500 - 1928)', + 'oto' => 'Otomian Languages', + 'paa' => 'Papuan-Australian (Other)', + 'pag' => 'Pangasinan', + 'pal' => 'Pahlavi', + 'pam' => 'Pampanga', + 'pan' => 'Panjabi', + 'pap' => 'Papiamento', + 'pau' => 'Palauan', + 'peo' => 'Persian, Old (ca 600 - 400 B.C.)', + 'per' => 'Persian', + 'phn' => 'Phoenician', + 'pli' => 'Pali', + 'pol' => 'Polish', + 'pon' => 'Ponape', + 'por' => 'Portuguese', + 'pra' => 'Prakrit uages', + 'pro' => 'Provencal, Old (to 1500)', + 'pus' => 'Pushto', + 'que' => 'Quechua', + 'raj' => 'Rajasthani', + 'rar' => 'Rarotongan', + 'roa' => 'Romance (Other)', + 'roh' => 'Rhaeto-Romance', + 'rom' => 'Romany', + 'ron' => 'Romanian', + 'rum' => 'Romanian', + 'run' => 'Rundi', + 'rus' => 'Russian', + 'sad' => 'Sandawe', + 'sag' => 'Sango', + 'sah' => 'Yakut', + 'sai' => 'South American Indian (Other)', + 'sal' => 'Salishan Languages', + 'sam' => 'Samaritan Aramaic', + 'san' => 'Sanskrit', + 'sco' => 'Scots', + 'scr' => 'Serbo-Croatian', + 'sel' => 'Selkup', + 'sem' => 'Semitic (Other)', + 'sga' => 'Irish, Old (to 900)', + 'shn' => 'Shan', + 'sid' => 'Sidamo', + 'sin' => 'Singhalese', + 'sio' => 'Siouan Languages', + 'sit' => 'Sino-Tibetan (Other)', + 'sla' => 'Slavic (Other)', + 'slk' => 'Slovak', + 'slo' => 'Slovak', + 'slv' => 'Slovenian', + 'smi' => 'Sami Languages', + 'smo' => 'Samoan', + 'sna' => 'Shona', + 'snd' => 'Sindhi', + 'sog' => 'Sogdian', + 'som' => 'Somali', + 'son' => 'Songhai', + 'sot' => 'Sotho, Southern', + 'spa' => 'Spanish', + 'sqi' => 'Albanian', + 'srd' => 'Sardinian', + 'srr' => 'Serer', + 'ssa' => 'Nilo-Saharan (Other)', + 'ssw' => 'Siswant', + 'ssw' => 'Swazi', + 'suk' => 'Sukuma', + 'sun' => 'Sudanese', + 'sus' => 'Susu', + 'sux' => 'Sumerian', + 'sve' => 'Swedish', + 'swa' => 'Swahili', + 'swe' => 'Swedish', + 'syr' => 'Syriac', + 'tah' => 'Tahitian', + 'tam' => 'Tamil', + 'tat' => 'Tatar', + 'tel' => 'Telugu', + 'tem' => 'Timne', + 'ter' => 'Tereno', + 'tgk' => 'Tajik', + 'tgl' => 'Tagalog', + 'tha' => 'Thai', + 'tib' => 'Tibetan', + 'tig' => 'Tigre', + 'tir' => 'Tigrinya', + 'tiv' => 'Tivi', + 'tli' => 'Tlingit', + 'tmh' => 'Tamashek', + 'tog' => 'Tonga (Nyasa)', + 'ton' => 'Tonga (Tonga Islands)', + 'tru' => 'Truk', + 'tsi' => 'Tsimshian', + 'tsn' => 'Tswana', + 'tso' => 'Tsonga', + 'tuk' => 'Turkmen', + 'tum' => 'Tumbuka', + 'tur' => 'Turkish', + 'tut' => 'Altaic (Other)', + 'twi' => 'Twi', + 'tyv' => 'Tuvinian', + 'uga' => 'Ugaritic', + 'uig' => 'Uighur', + 'ukr' => 'Ukrainian', + 'umb' => 'Umbundu', + 'und' => 'Undetermined', + 'urd' => 'Urdu', + 'uzb' => 'Uzbek', + 'vai' => 'Vai', + 'ven' => 'Venda', + 'vie' => 'Vietnamese', + 'vol' => 'Volapk', + 'vot' => 'Votic', + 'wak' => 'Wakashan Languages', + 'wal' => 'Walamo', + 'war' => 'Waray', + 'was' => 'Washo', + 'wel' => 'Welsh', + 'wen' => 'Sorbian Languages', + 'wol' => 'Wolof', + 'xho' => 'Xhosa', + 'yao' => 'Yao', + 'yap' => 'Yap', + 'yid' => 'Yiddish', + 'yor' => 'Yoruba', + 'zap' => 'Zapotec', + 'zen' => 'Zenaga', + 'zha' => 'Zhuang', + 'zho' => 'Chinese', + 'zul' => 'Zulu', + 'zun' => 'Zuni' + ); + + return @$lookup[$language_code]; + } + + + + public static function ETCOEventLookup($index) { + + if (($index >= 0x17) && ($index <= 0xDF)) { + return 'reserved for future use'; + } + if (($index >= 0xE0) && ($index <= 0xEF)) { + return 'not predefined synch 0-F'; + } + if (($index >= 0xF0) && ($index <= 0xFC)) { + return 'reserved for future use'; + } + + static $lookup = array ( + 0x00 => 'padding (has no meaning)', + 0x01 => 'end of initial silence', + 0x02 => 'intro start', + 0x03 => 'main part start', + 0x04 => 'outro start', + 0x05 => 'outro end', + 0x06 => 'verse start', + 0x07 => 'refrain start', + 0x08 => 'interlude start', + 0x09 => 'theme start', + 0x0A => 'variation start', + 0x0B => 'key change', + 0x0C => 'time change', + 0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)', + 0x0E => 'sustained noise', + 0x0F => 'sustained noise end', + 0x10 => 'intro end', + 0x11 => 'main part end', + 0x12 => 'verse end', + 0x13 => 'refrain end', + 0x14 => 'theme end', + 0x15 => 'profanity', + 0x16 => 'profanity end', + 0xFD => 'audio end (start of silence)', + 0xFE => 'audio file ends', + 0xFF => 'one more byte of events follows' + ); + + return @$lookup[$index]; + } + + + + public static function SYTLContentTypeLookup($index) { + + static $lookup = array ( + 0x00 => 'other', + 0x01 => 'lyrics', + 0x02 => 'text transcription', + 0x03 => 'movement/part name', // (e.g. 'Adagio') + 0x04 => 'events', // (e.g. 'Don Quijote enters the stage') + 0x05 => 'chord', // (e.g. 'Bb F Fsus') + 0x06 => 'trivia/\'pop up\' information', + 0x07 => 'URLs to webpages', + 0x08 => 'URLs to images' + ); + + return @$lookup[$index]; + } + + + + public static function APICPictureTypeLookup($index, $return_array=false) { + + static $lookup = array ( + 0x00 => 'Other', + 0x01 => '32x32 pixels \'file icon\' (PNG only)', + 0x02 => 'Other file icon', + 0x03 => 'Cover (front)', + 0x04 => 'Cover (back)', + 0x05 => 'Leaflet page', + 0x06 => 'Media (e.g. label side of CD)', + 0x07 => 'Lead artist/lead performer/soloist', + 0x08 => 'Artist/performer', + 0x09 => 'Conductor', + 0x0A => 'Band/Orchestra', + 0x0B => 'Composer', + 0x0C => 'Lyricist/text writer', + 0x0D => 'Recording Location', + 0x0E => 'During recording', + 0x0F => 'During performance', + 0x10 => 'Movie/video screen capture', + 0x11 => 'A bright coloured fish', + 0x12 => 'Illustration', + 0x13 => 'Band/artist logotype', + 0x14 => 'Publisher/Studio logotype' + ); + + if ($return_array) { + return $lookup; + } + return @$lookup[$index]; + } + + + + public static function COMRReceivedAsLookup($index) { + + static $lookup = array ( + 0x00 => 'Other', + 0x01 => 'Standard CD album with other songs', + 0x02 => 'Compressed audio on CD', + 0x03 => 'File over the Internet', + 0x04 => 'Stream over the Internet', + 0x05 => 'As note sheets', + 0x06 => 'As note sheets in a book with other sheets', + 0x07 => 'Music on other media', + 0x08 => 'Non-musical merchandise' + ); + + return (isset($lookup[$index]) ? $lookup[$index] : ''); + } + + + + public static function RVA2ChannelTypeLookup($index) { + + static $lookup = array ( + 0x00 => 'Other', + 0x01 => 'Master volume', + 0x02 => 'Front right', + 0x03 => 'Front left', + 0x04 => 'Back right', + 0x05 => 'Back left', + 0x06 => 'Front centre', + 0x07 => 'Back centre', + 0x08 => 'Subwoofer' + ); + + return @$lookup[$index]; + } + + + + public static function FrameNameLongLookup($frame_name) { + + static $lookup = array ( + 'AENC' => 'Audio encryption', + 'APIC' => 'Attached picture', + 'ASPI' => 'Audio seek point index', + 'BUF' => 'Recommended buffer size', + 'CNT' => 'Play counter', + 'COM' => 'Comments', + 'COMM' => 'Comments', + 'COMR' => 'Commercial frame', + 'CRA' => 'Audio encryption', + 'CRM' => 'Encrypted meta frame', + 'ENCR' => 'Encryption method registration', + 'EQU' => 'Equalisation', + 'EQU2' => 'Equalisation (2)', + 'EQUA' => 'Equalisation', + 'ETC' => 'Event timing codes', + 'ETCO' => 'Event timing codes', + 'GEO' => 'General encapsulated object', + 'GEOB' => 'General encapsulated object', + 'GRID' => 'Group identification registration', + 'IPL' => 'Involved people list', + 'IPLS' => 'Involved people list', + 'LINK' => 'Linked information', + 'LNK' => 'Linked information', + 'MCDI' => 'Music CD identifier', + 'MCI' => 'Music CD Identifier', + 'MLL' => 'MPEG location lookup table', + 'MLLT' => 'MPEG location lookup table', + 'OWNE' => 'Ownership frame', + 'PCNT' => 'Play counter', + 'PIC' => 'Attached picture', + 'POP' => 'Popularimeter', + 'POPM' => 'Popularimeter', + 'POSS' => 'Position synchronisation frame', + 'PRIV' => 'Private frame', + 'RBUF' => 'Recommended buffer size', + 'REV' => 'Reverb', + 'RVA' => 'Relative volume adjustment', + 'RVA2' => 'Relative volume adjustment (2)', + 'RVAD' => 'Relative volume adjustment', + 'RVRB' => 'Reverb', + 'SEEK' => 'Seek frame', + 'SIGN' => 'Signature frame', + 'SLT' => 'Synchronised lyric/text', + 'STC' => 'Synced tempo codes', + 'SYLT' => 'Synchronised lyric/text', + 'SYTC' => 'Synchronised tempo codes', + 'TAL' => 'Album/Movie/Show title', + 'TALB' => 'Album/Movie/Show title', + 'TBP' => 'BPM (Beats Per Minute)', + 'TBPM' => 'BPM (beats per minute)', + 'TCM' => 'Composer', + 'TCO' => 'Content type', + 'TCOM' => 'Composer', + 'TCON' => 'Content type', + 'TCOP' => 'Copyright message', + 'TCR' => 'Copyright message', + 'TDA' => 'Date', + 'TDAT' => 'Date', + 'TDEN' => 'Encoding time', + 'TDLY' => 'Playlist delay', + 'TDOR' => 'Original release time', + 'TDRC' => 'Recording time', + 'TDRL' => 'Release time', + 'TDTG' => 'Tagging time', + 'TDY' => 'Playlist delay', + 'TEN' => 'Encoded by', + 'TENC' => 'Encoded by', + 'TEXT' => 'Lyricist/Text writer', + 'TFLT' => 'File type', + 'TFT' => 'File type', + 'TIM' => 'Time', + 'TIME' => 'Time', + 'TIPL' => 'Involved people list', + 'TIT1' => 'Content group description', + 'TIT2' => 'Title/songname/content description', + 'TIT3' => 'Subtitle/Description refinement', + 'TKE' => 'Initial key', + 'TKEY' => 'Initial key', + 'TLA' => 'Language(s)', + 'TLAN' => 'Language(s)', + 'TLE' => 'Length', + 'TLEN' => 'Length', + 'TMCL' => 'Musician credits list', + 'TMED' => 'Media type', + 'TMOO' => 'Mood', + 'TMT' => 'Media type', + 'TOA' => 'Original artist(s)/performer(s)', + 'TOAL' => 'Original album/movie/show title', + 'TOF' => 'Original filename', + 'TOFN' => 'Original filename', + 'TOL' => 'Original Lyricist(s)/text writer(s)', + 'TOLY' => 'Original lyricist(s)/text writer(s)', + 'TOPE' => 'Original artist(s)/performer(s)', + 'TOR' => 'Original release year', + 'TORY' => 'Original release year', + 'TOT' => 'Original album/Movie/Show title', + 'TOWN' => 'File owner/licensee', + 'TP1' => 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group', + 'TP2' => 'Band/Orchestra/Accompaniment', + 'TP3' => 'Conductor/Performer refinement', + 'TP4' => 'Interpreted, remixed, or otherwise modified by', + 'TPA' => 'Part of a set', + 'TPB' => 'Publisher', + 'TPE1' => 'Lead performer(s)/Soloist(s)', + 'TPE2' => 'Band/orchestra/accompaniment', + 'TPE3' => 'Conductor/performer refinement', + 'TPE4' => 'Interpreted, remixed, or otherwise modified by', + 'TPOS' => 'Part of a set', + 'TPRO' => 'Produced notice', + 'TPUB' => 'Publisher', + 'TRC' => 'ISRC (International Standard Recording Code)', + 'TRCK' => 'Track number/Position in set', + 'TRD' => 'Recording dates', + 'TRDA' => 'Recording dates', + 'TRK' => 'Track number/Position in set', + 'TRSN' => 'Internet radio station name', + 'TRSO' => 'Internet radio station owner', + 'TSI' => 'Size', + 'TSIZ' => 'Size', + 'TSOA' => 'Album sort order', + 'TSOP' => 'Performer sort order', + 'TSOT' => 'Title sort order', + 'TSRC' => 'ISRC (international standard recording code)', + 'TSS' => 'Software/hardware and settings used for encoding', + 'TSSE' => 'Software/Hardware and settings used for encoding', + 'TSST' => 'Set subtitle', + 'TT1' => 'Content group description', + 'TT2' => 'Title/Songname/Content description', + 'TT3' => 'Subtitle/Description refinement', + 'TXT' => 'Lyricist/text writer', + 'TXX' => 'User defined text information frame', + 'TXXX' => 'User defined text information frame', + 'TYE' => 'Year', + 'TYER' => 'Year', + 'UFI' => 'Unique file identifier', + 'UFID' => 'Unique file identifier', + 'ULT' => 'Unsychronised lyric/text transcription', + 'USER' => 'Terms of use', + 'USLT' => 'Unsynchronised lyric/text transcription', + 'WAF' => 'Official audio file webpage', + 'WAR' => 'Official artist/performer webpage', + 'WAS' => 'Official audio source webpage', + 'WCM' => 'Commercial information', + 'WCOM' => 'Commercial information', + 'WCOP' => 'Copyright/Legal information', + 'WCP' => 'Copyright/Legal information', + 'WOAF' => 'Official audio file webpage', + 'WOAR' => 'Official artist/performer webpage', + 'WOAS' => 'Official audio source webpage', + 'WORS' => 'Official Internet radio station homepage', + 'WPAY' => 'Payment', + 'WPB' => 'Publishers official webpage', + 'WPUB' => 'Publishers official webpage', + 'WXX' => 'User defined URL link frame', + 'WXXX' => 'User defined URL link frame', + 'TFEA' => 'Featured Artist', + 'TSTU' => 'Recording Studio', + 'rgad' => 'Replay Gain Adjustment' + ); + + return @$lookup[$frame_name]; + + // Last three: + // from Helium2 [www.helium2.com] + // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html + } + + + public static function FrameNameShortLookup($frame_name) { + + static $lookup = array ( + 'COM' => 'comment', + 'COMM' => 'comment', + 'TAL' => 'album', + 'TALB' => 'album', + 'TBP' => 'bpm', + 'TBPM' => 'bpm', + 'TCM' => 'composer', + 'TCO' => 'genre', + 'TCOM' => 'composer', + 'TCON' => 'genre', + 'TCOP' => 'copyright', + 'TCR' => 'copyright', + 'TEN' => 'encoded_by', + 'TENC' => 'encoded_by', + 'TEXT' => 'lyricist', + 'TIT1' => 'description', + 'TIT2' => 'title', + 'TIT3' => 'subtitle', + 'TLA' => 'language', + 'TLAN' => 'language', + 'TLE' => 'length', + 'TLEN' => 'length', + 'TMOO' => 'mood', + 'TOA' => 'original_artist', + 'TOAL' => 'original_album', + 'TOF' => 'original_filename', + 'TOFN' => 'original_filename', + 'TOL' => 'original_lyricist', + 'TOLY' => 'original_lyricist', + 'TOPE' => 'original_artist', + 'TOT' => 'original_album', + 'TP1' => 'artist', + 'TP2' => 'band', + 'TP3' => 'conductor', + 'TP4' => 'remixer', + 'TPB' => 'publisher', + 'TPE1' => 'artist', + 'TPE2' => 'band', + 'TPE3' => 'conductor', + 'TPE4' => 'remixer', + 'TPUB' => 'publisher', + 'TRC' => 'isrc', + 'TRCK' => 'track', + 'TRK' => 'track', + 'TSI' => 'size', + 'TSIZ' => 'size', + 'TSRC' => 'isrc', + 'TSS' => 'encoder_settings', + 'TSSE' => 'encoder_settings', + 'TSST' => 'subtitle', + 'TT1' => 'description', + 'TT2' => 'title', + 'TT3' => 'subtitle', + 'TXT' => 'lyricist', + 'TXX' => 'text', + 'TXXX' => 'text', + 'TYE' => 'year', + 'TYER' => 'year', + 'UFI' => 'unique_file_identifier', + 'UFID' => 'unique_file_identifier', + 'ULT' => 'unsychronised_lyric', + 'USER' => 'terms_of_use', + 'USLT' => 'unsynchronised lyric', + 'WAF' => 'url_file', + 'WAR' => 'url_artist', + 'WAS' => 'url_source', + 'WCOP' => 'copyright', + 'WCP' => 'copyright', + 'WOAF' => 'url_file', + 'WOAR' => 'url_artist', + 'WOAS' => 'url_source', + 'WORS' => 'url_station', + 'WPB' => 'url_publisher', + 'WPUB' => 'url_publisher', + 'WXX' => 'url_user', + 'WXXX' => 'url_user', + 'TFEA' => 'featured_artist', + 'TSTU' => 'studio' + ); + + return @$lookup[$frame_name]; + } + + + + public static function TextEncodingTerminatorLookup($encoding) { + + // http://www.id3.org/id3v2.4.0-structure.txt + // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: + // $00 ISO-8859-1. Terminated with $00. + // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00. + // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00. + // $03 UTF-8 encoded Unicode. Terminated with $00. + + static $lookup = array ( + 0 =>"\x00", + 1 =>"\x00\x00", + 2 =>"\x00\x00", + 3 =>"\x00", + 255 =>"\x00\x00" + ); + + return @$lookup[$encoding]; + } + + + + public static function IsValidID3v2FrameName($frame_name, $id3v2_major_version) { + + switch ($id3v2_major_version) { + case 2: + return preg_match('/[A-Z][A-Z0-9]{2}/', $frame_name); + + case 3: + case 4: + return preg_match('/[A-Z][A-Z0-9]{3}/', $frame_name); + } + return false; + } + + + + public static function IsValidDateStampString($date_stamp) { + + if (strlen($date_stamp) != 8) { + return false; + } + if ((int)$date_stamp) { + return false; + } + + $year = substr($date_stamp, 0, 4); + $month = substr($date_stamp, 4, 2); + $day = substr($date_stamp, 6, 2); + if (!$year || !$month || !$day || $month > 12 || $day > 31 ) { + return false; + } + if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) { + return false; + } + if (($day > 29) && ($month == 2)) { + return false; + } + return true; + } + + + + public static function array_merge_noclobber($array1, $array2) { + if (!is_array($array1) || !is_array($array2)) { + return false; + } + $newarray = $array1; + foreach ($array2 as $key => $val) { + if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { + $newarray[$key] = getid3_id3v2::array_merge_noclobber($newarray[$key], $val); + } elseif (!isset($newarray[$key])) { + $newarray[$key] = $val; + } + } + return $newarray; + } + + +} + +?> diff --git a/plugins/getId3Plugin/lib/module.tag.lyrics3.php b/plugins/getId3Plugin/lib/module.tag.lyrics3.php new file mode 100644 index 0000000..dd926fe --- /dev/null +++ b/plugins/getId3Plugin/lib/module.tag.lyrics3.php @@ -0,0 +1,280 @@ + | +// | Allan Hansen | +// +----------------------------------------------------------------------+ +// | module.tag.lyrics3.php | +// | module for analyzing Lyrics3 tags | +// | dependencies: module.tag.apetag.php (optional) | +// +----------------------------------------------------------------------+ +// +// $Id: module.tag.lyrics3.php,v 1.2 2006/06/06 18:38:54 ah Exp $ + + +class getid3_lyrics3 extends getid3_handler +{ + + public function Analyze() { + + $getid3 = $this->getid3; + + // http://www.volweb.cz/str/tags.htm + + fseek($getid3->fp, (0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - LYRICSEND - [Lyrics3size] + $lyrics3_id3v1 = fread($getid3->fp, 128 + 9 + 6); + $lyrics3_lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size + $lyrics3_end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200 + $id3v1_tag = substr($lyrics3_id3v1, 15, 128); // ID3v1 + + + // Lyrics3v1, ID3v1, no APE + if ($lyrics3_end == 'LYRICSEND') { + + $lyrics3_size = 5100; + $lyrics3_offset = $getid3->info['filesize'] - 128 - $lyrics3_size; + $lyrics3_version = 1; + } + + + // Lyrics3v2, ID3v1, no APE + elseif ($lyrics3_end == 'LYRICS200') { + + // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' + $lyrics3_size = $lyrics3_lsz + 6 + strlen('LYRICS200'); + $lyrics3_offset = $getid3->info['filesize'] - 128 - $lyrics3_size; + $lyrics3_version = 2; + } + + + // Lyrics3v1, no ID3v1, no APE + elseif (substr(strrev($lyrics3_id3v1), 0, 9) == 'DNESCIRYL') { // strrev('LYRICSEND') = 'DNESCIRYL' + + $lyrics3_size = 5100; + $lyrics3_offset = $getid3->info['filesize'] - $lyrics3_size; + $lyrics3_version = 1; + $lyrics3_offset = $getid3->info['filesize'] - $lyrics3_size; + } + + + // Lyrics3v2, no ID3v1, no APE + elseif (substr(strrev($lyrics3_id3v1), 0, 9) == '002SCIRYL') { // strrev('LYRICS200') = '002SCIRYL' + + $lyrics3_size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 15; // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' // 15 = 6 + strlen('LYRICS200') + $lyrics3_offset = $getid3->info['filesize'] - $lyrics3_size; + $lyrics3_version = 2; + + } + + + elseif (isset($getid3->info['ape']['tag_offset_start']) && ($getid3->info['ape']['tag_offset_start'] > 15)) { + + fseek($getid3->fp, $getid3->info['ape']['tag_offset_start'] - 15, SEEK_SET); + $lyrics3_lsz = fread($getid3->fp, 6); + $lyrics3_end = fread($getid3->fp, 9); + + + // Lyrics3v1, APE, maybe ID3v1 + if ($lyrics3_end == 'LYRICSEND') { + + $lyrics3_size = 5100; + $lyrics3_offset = $getid3->info['ape']['tag_offset_start'] - $lyrics3_size; + $getid3->info['avdataend'] = $lyrics3_offset; + $lyrics3_version = 1; + $getid3->warning('APE tag located after Lyrics3, will probably break Lyrics3 compatability'); + } + + + // Lyrics3v2, APE, maybe ID3v1 + elseif ($lyrics3_end == 'LYRICS200') { + + $lyrics3_size = $lyrics3_lsz + 15; // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' + $lyrics3_offset = $getid3->info['ape']['tag_offset_start'] - $lyrics3_size; + $lyrics3_version = 2; + $getid3->warning('APE tag located after Lyrics3, will probably break Lyrics3 compatability'); + + } + } + + + //// GetLyrics3Data() + + + if (isset($lyrics3_offset)) { + + // http://www.volweb.cz/str/tags.htm + + $getid3->info['avdataend'] = $lyrics3_offset; + + if ($lyrics3_size <= 0) { + return false; + } + + fseek($getid3->fp, $lyrics3_offset, SEEK_SET); + $raw_data = fread($getid3->fp, $lyrics3_size); + + if (substr($raw_data, 0, 11) != 'LYRICSBEGIN') { + if (strpos($raw_data, 'LYRICSBEGIN') !== false) { + + $getid3->warning('"LYRICSBEGIN" expected at '.$lyrics3_offset.' but actually found at '.($lyrics3_offset + strpos($raw_data, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$lyrics3_version); + $getid3->info['avdataend'] = $lyrics3_offset + strpos($raw_data, 'LYRICSBEGIN'); + $parsed_lyrics3['tag_offset_start'] = $getid3->info['avdataend']; + $raw_data = substr($raw_data, strpos($raw_data, 'LYRICSBEGIN')); + $lyrics3_size = strlen($raw_data); + } + else { + throw new getid3_exception('"LYRICSBEGIN" expected at '.$lyrics3_offset.' but found "'.substr($raw_data, 0, 11).'" instead.'); + } + + } + + $parsed_lyrics3['raw']['lyrics3version'] = $lyrics3_version; + $parsed_lyrics3['raw']['lyrics3tagsize'] = $lyrics3_size; + $parsed_lyrics3['tag_offset_start'] = $lyrics3_offset; + $parsed_lyrics3['tag_offset_end'] = $lyrics3_offset + $lyrics3_size; + + switch ($lyrics3_version) { + + case 1: + if (substr($raw_data, strlen($raw_data) - 9, 9) == 'LYRICSEND') { + $parsed_lyrics3['raw']['LYR'] = trim(substr($raw_data, 11, strlen($raw_data) - 11 - 9)); + getid3_lyrics3::Lyrics3LyricsTimestampParse($parsed_lyrics3); + } + else { + throw new getid3_exception('"LYRICSEND" expected at '.(ftell($getid3->fp) - 11 + $lyrics3_size - 9).' but found "'.substr($raw_data, strlen($raw_data) - 9, 9).'" instead.'); + } + break; + + case 2: + if (substr($raw_data, strlen($raw_data) - 9, 9) == 'LYRICS200') { + $parsed_lyrics3['raw']['unparsed'] = substr($raw_data, 11, strlen($raw_data) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ + $raw_data = $parsed_lyrics3['raw']['unparsed']; + while (strlen($raw_data) > 0) { + $fieldname = substr($raw_data, 0, 3); + $fieldsize = (int)substr($raw_data, 3, 5); + $parsed_lyrics3['raw'][$fieldname] = substr($raw_data, 8, $fieldsize); + $raw_data = substr($raw_data, 3 + 5 + $fieldsize); + } + + if (isset($parsed_lyrics3['raw']['IND'])) { + $i = 0; + foreach (array ('lyrics', 'timestamps', 'inhibitrandom') as $flagname) { + if (strlen($parsed_lyrics3['raw']['IND']) > ++$i) { + $parsed_lyrics3['flags'][$flagname] = getid3_lyrics3::IntString2Bool(substr($parsed_lyrics3['raw']['IND'], $i, 1)); + } + } + } + + foreach (array ('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author') as $key => $value) { + if (isset($parsed_lyrics3['raw'][$key])) { + $parsed_lyrics3['comments'][$value][] = trim($parsed_lyrics3['raw'][$key]); + } + } + + if (isset($parsed_lyrics3['raw']['IMG'])) { + foreach (explode("\r\n", $parsed_lyrics3['raw']['IMG']) as $key => $image_string) { + if (strpos($image_string, '||') !== false) { + $imagearray = explode('||', $image_string); + $parsed_lyrics3['images'][$key]['filename'] = $imagearray[0]; + $parsed_lyrics3['images'][$key]['description'] = $imagearray[1]; + $parsed_lyrics3['images'][$key]['timestamp'] = getid3_lyrics3::Lyrics3Timestamp2Seconds($imagearray[2]); + } + } + } + + if (isset($parsed_lyrics3['raw']['LYR'])) { + getid3_lyrics3::Lyrics3LyricsTimestampParse($parsed_lyrics3); + } + } + else { + throw new getid3_exception('"LYRICS200" expected at '.(ftell($getid3->fp) - 11 + $lyrics3_size - 9).' but found "'.substr($raw_data, strlen($raw_data) - 9, 9).'" instead.'); + } + break; + + default: + throw new getid3_exception('Cannot process Lyrics3 version '.$lyrics3_version.' (only v1 and v2)'); + } + + if (isset($getid3->info['id3v1']['tag_offset_start']) && ($getid3->info['id3v1']['tag_offset_start'] < $parsed_lyrics3['tag_offset_end'])) { + $getid3->warning('ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data'); + unset($getid3->info['id3v1']); + } + + $getid3->info['lyrics3'] = $parsed_lyrics3; + + + // Check for APE tag after lyrics3 + if (!@$getid3->info['ape'] && $getid3->option_tag_apetag && class_exists('getid3_apetag')) { + $apetag = new getid3_apetag($getid3); + $apetag->option_override_end_offset = $getid3->info['lyrics3']['tag_offset_start']; + $apetag->Analyze(); + } + } + + return true; + } + + + + + public static function Lyrics3Timestamp2Seconds($rawtimestamp) { + if (ereg('^\\[([0-9]{2}):([0-9]{2})\\]$', $rawtimestamp, $regs)) { + return (int)(($regs[1] * 60) + $regs[2]); + } + return false; + } + + + + public static function Lyrics3LyricsTimestampParse(&$lyrics3_data) { + + $lyrics_array = explode("\r\n", $lyrics3_data['raw']['LYR']); + foreach ($lyrics_array as $key => $lyric_line) { + + while (ereg('^(\\[[0-9]{2}:[0-9]{2}\\])', $lyric_line, $regs)) { + $this_line_timestamps[] = getid3_lyrics3::Lyrics3Timestamp2Seconds($regs[0]); + $lyric_line = str_replace($regs[0], '', $lyric_line); + } + $no_timestamp_lyrics_array[$key] = $lyric_line; + if (@is_array($this_line_timestamps)) { + sort($this_line_timestamps); + foreach ($this_line_timestamps as $timestampkey => $timestamp) { + if (isset($lyrics3_data['synchedlyrics'][$timestamp])) { + // timestamps only have a 1-second resolution, it's possible that multiple lines + // could have the same timestamp, if so, append + $lyrics3_data['synchedlyrics'][$timestamp] .= "\r\n".$lyric_line; + } else { + $lyrics3_data['synchedlyrics'][$timestamp] = $lyric_line; + } + } + } + unset($this_line_timestamps); + $regs = array (); + } + $lyrics3_data['unsynchedlyrics'] = implode("\r\n", $no_timestamp_lyrics_array); + if (isset($lyrics3_data['synchedlyrics']) && is_array($lyrics3_data['synchedlyrics'])) { + ksort($lyrics3_data['synchedlyrics']); + } + return true; + } + + + + public static function IntString2Bool($char) { + + return $char == '1' ? true : ($char == '0' ? false : null); + } +} + + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/write.apetag.php b/plugins/getId3Plugin/lib/write.apetag.php new file mode 100644 index 0000000..189160a --- /dev/null +++ b/plugins/getId3Plugin/lib/write.apetag.php @@ -0,0 +1,228 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.apetag.php // +// module for writing APE tags // +// dependencies: module.tag.apetag.php // +// /// +///////////////////////////////////////////////////////////////// + + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true); + +class getid3_write_apetag +{ + + var $filename; + var $tag_data; + var $always_preserve_replaygain = true; // ReplayGain / MP3gain tags will be copied from old tag even if not passed in data + var $warnings = array(); // any non-critical errors will be stored here + var $errors = array(); // any critical errors will be stored here + + function getid3_write_apetag() { + return true; + } + + function WriteAPEtag() { + // NOTE: All data passed to this function must be UTF-8 format + + $getID3 = new getID3; + $ThisFileInfo = $getID3->analyze($this->filename); + + if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { + if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) { + // Current APE tag between Lyrics3 and ID3v1/EOF + // This break Lyrics3 functionality + if (!$this->DeleteAPEtag()) { + return false; + } + $ThisFileInfo = $getID3->analyze($this->filename); + } + } + + if ($this->always_preserve_replaygain) { + $ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain'); + foreach ($ReplayGainTagsToPreserve as $rg_key) { + if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) { + $this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]; + } + } + } + + if ($APEtag = $this->GenerateAPEtag()) { + if ($fp = @fopen($this->filename, 'a+b')) { + $oldignoreuserabort = ignore_user_abort(true); + flock($fp, LOCK_EX); + + $PostAPEdataOffset = $ThisFileInfo['avdataend']; + if (isset($ThisFileInfo['ape']['tag_offset_end'])) { + $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']); + } + if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) { + $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']); + } + fseek($fp, $PostAPEdataOffset, SEEK_SET); + $PostAPEdata = ''; + if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) { + $PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset); + } + + fseek($fp, $PostAPEdataOffset, SEEK_SET); + if (isset($ThisFileInfo['ape']['tag_offset_start'])) { + fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); + } + ftruncate($fp, ftell($fp)); + fwrite($fp, $APEtag, strlen($APEtag)); + if (!empty($PostAPEdata)) { + fwrite($fp, $PostAPEdata, strlen($PostAPEdata)); + } + flock($fp, LOCK_UN); + fclose($fp); + ignore_user_abort($oldignoreuserabort); + return true; + + } + return false; + } + return false; + } + + function DeleteAPEtag() { + $getID3 = new getID3; + $ThisFileInfo = $getID3->analyze($this->filename); + if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) { + if ($fp = @fopen($this->filename, 'a+b')) { + + flock($fp, LOCK_EX); + $oldignoreuserabort = ignore_user_abort(true); + + fseek($fp, $ThisFileInfo['ape']['tag_offset_end'], SEEK_SET); + $DataAfterAPE = ''; + if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) { + $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']); + } + + ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']); + fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); + + if (!empty($DataAfterAPE)) { + fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE)); + } + + flock($fp, LOCK_UN); + fclose($fp); + ignore_user_abort($oldignoreuserabort); + + return true; + + } + return false; + } + return true; + } + + + function GenerateAPEtag() { + // NOTE: All data passed to this function must be UTF-8 format + + $items = array(); + if (!is_array($this->tag_data)) { + return false; + } + foreach ($this->tag_data as $key => $arrayofvalues) { + if (!is_array($arrayofvalues)) { + return false; + } + + $valuestring = ''; + foreach ($arrayofvalues as $value) { + $valuestring .= str_replace("\x00", '', $value)."\x00"; + } + $valuestring = rtrim($valuestring, "\x00"); + + // Length of the assigned value in bytes + $tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4); + + //$tagitem .= $this->GenerateAPEtagFlags(true, true, false, 0, false); + $tagitem .= "\x00\x00\x00\x00"; + + $tagitem .= $this->CleanAPEtagItemKey($key)."\x00"; + $tagitem .= $valuestring; + + $items[] = $tagitem; + + } + + return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false); + } + + function GenerateAPEtagHeaderFooter(&$items, $isheader=false) { + $tagdatalength = 0; + foreach ($items as $itemdata) { + $tagdatalength += strlen($itemdata); + } + + $APEheader = 'APETAGEX'; + $APEheader .= getid3_lib::LittleEndian2String(2000, 4); + $APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4); + $APEheader .= getid3_lib::LittleEndian2String(count($items), 4); + $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false); + $APEheader .= str_repeat("\x00", 8); + + return $APEheader; + } + + function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) { + $APEtagFlags = array_fill(0, 4, 0); + if ($header) { + $APEtagFlags[0] |= 0x80; // Tag contains a header + } + if (!$footer) { + $APEtagFlags[0] |= 0x40; // Tag contains no footer + } + if ($isheader) { + $APEtagFlags[0] |= 0x20; // This is the header, not the footer + } + + // 0: Item contains text information coded in UTF-8 + // 1: Item contains binary information ) + // 2: Item is a locator of external stored information ) + // 3: reserved + $APEtagFlags[3] |= ($encodingid << 1); + + if ($readonly) { + $APEtagFlags[3] |= 0x01; // Tag or Item is Read Only + } + + return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]); + } + + function CleanAPEtagItemKey($itemkey) { + $itemkey = eregi_replace("[^\x20-\x7E]", '', $itemkey); + + // http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html + switch (strtoupper($itemkey)) { + case 'EAN/UPC': + case 'ISBN': + case 'LC': + case 'ISRC': + $itemkey = strtoupper($itemkey); + break; + + default: + $itemkey = ucwords($itemkey); + break; + } + return $itemkey; + + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/write.id3v1.php b/plugins/getId3Plugin/lib/write.id3v1.php new file mode 100644 index 0000000..2125214 --- /dev/null +++ b/plugins/getId3Plugin/lib/write.id3v1.php @@ -0,0 +1,104 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.id3v1.php // +// module for writing ID3v1 tags // +// dependencies: module.tag.id3v1.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true); + +class getid3_write_id3v1 +{ + var $filename; + var $tag_data; + var $warnings = array(); // any non-critical errors will be stored here + var $errors = array(); // any critical errors will be stored here + + function getid3_write_id3v1() { + return true; + } + + function WriteID3v1() { + // File MUST be writeable - CHMOD(646) at least + if (is_writeable($this->filename)) { + if ($fp_source = @fopen($this->filename, 'r+b')) { + + fseek($fp_source, -128, SEEK_END); + if (fread($fp_source, 3) == 'TAG') { + fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag + } else { + fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag + } + + $new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag( + @$this->tag_data['title'], + @$this->tag_data['artist'], + @$this->tag_data['album'], + @$this->tag_data['year'], + @$this->tag_data['genreid'], + @$this->tag_data['comment'], + @$this->tag_data['track']); + fwrite($fp_source, $new_id3v1_tag_data, 128); + fclose($fp_source); + return true; + + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"'; + return false; + } + } + $this->errors[] = 'File is not writeable: '.$this->filename; + return false; + } + + function FixID3v1Padding() { + // ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces + // This function rewrites the ID3v1 tag with correct padding + + // Initialize getID3 engine + $getID3 = new getID3; + $ThisFileInfo = $getID3->analyze($this->filename); + if (isset($ThisFileInfo['tags']['id3v1'])) { + foreach ($ThisFileInfo['tags']['id3v1'] as $key => $value) { + $id3v1data[$key] = implode(',', $value); + } + $this->tag_data = $id3v1data; + return $this->WriteID3v1(); + } + return false; + } + + function RemoveID3v1() { + // File MUST be writeable - CHMOD(646) at least + if (is_writeable($this->filename)) { + if ($fp_source = @fopen($this->filename, 'r+b')) { + + fseek($fp_source, -128, SEEK_END); + if (fread($fp_source, 3) == 'TAG') { + ftruncate($fp_source, filesize($this->filename) - 128); + } else { + // no ID3v1 tag to begin with - do nothing + } + fclose($fp_source); + return true; + + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"'; + } + } else { + $this->errors[] = $this->filename.' is not writeable'; + } + return false; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/write.id3v2.php b/plugins/getId3Plugin/lib/write.id3v2.php new file mode 100644 index 0000000..52398fb --- /dev/null +++ b/plugins/getId3Plugin/lib/write.id3v2.php @@ -0,0 +1,2038 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +/// // +// write.id3v2.php // +// module for writing ID3v2 tags // +// dependencies: module.tag.id3v2.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); + +class getid3_write_id3v2 +{ + var $filename; + var $tag_data; + var $paddedlength = 4096; // minimum length of ID3v2 tag in bytes + var $majorversion = 3; // ID3v2 major version (2, 3 (recommended), 4) + var $minorversion = 0; // ID3v2 minor version - always 0 + var $merge_existing_data = false; // if true, merge new data with existing tags; if false, delete old tag data and only write new tags + var $id3v2_default_encodingid = 0; // default text encoding (ISO-8859-1) if not explicitly passed + var $id3v2_use_unsynchronisation = false; // the specs say it should be TRUE, but most other ID3v2-aware programs are broken if unsynchronization is used, so by default don't use it. + var $warnings = array(); // any non-critical errors will be stored here + var $errors = array(); // any critical errors will be stored here + + function getid3_write_id3v2() { + return true; + } + + function WriteID3v2() { + // File MUST be writeable - CHMOD(646) at least. It's best if the + // directory is also writeable, because that method is both faster and less susceptible to errors. + + if (is_writeable($this->filename) || (!file_exists($this->filename) && is_writeable(dirname($this->filename)))) { + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + if ($this->merge_existing_data) { + // merge with existing data + if (!empty($OldThisFileInfo['id3v2'])) { + $this->tag_data = $this->array_join_merge($OldThisFileInfo['id3v2'], $this->tag_data); + } + } + $this->paddedlength = max(@$OldThisFileInfo['id3v2']['headerlength'], $this->paddedlength); + + if ($NewID3v2Tag = $this->GenerateID3v2Tag()) { + + if (file_exists($this->filename) && is_writeable($this->filename) && isset($OldThisFileInfo['id3v2']['headerlength']) && ($OldThisFileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag))) { + + // best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary) + if (file_exists($this->filename)) { + + ob_start(); + if ($fp = fopen($this->filename, 'r+b')) { + rewind($fp); + fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp); + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "r+b" - '.strip_tags(ob_get_contents()); + } + ob_end_clean(); + + } else { + + ob_start(); + if ($fp = fopen($this->filename, 'wb')) { + rewind($fp); + fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp); + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "wb" - '.strip_tags(ob_get_contents()); + } + ob_end_clean(); + + } + + } else { + + if ($tempfilename = tempnam('*', 'getID3')) { + ob_start(); + if ($fp_source = fopen($this->filename, 'rb')) { + if ($fp_temp = fopen($tempfilename, 'wb')) { + + fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag)); + + rewind($fp_source); + if (!empty($OldThisFileInfo['avdataoffset'])) { + fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); + } + + while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + + fclose($fp_temp); + fclose($fp_source); + copy($tempfilename, $this->filename); + unlink($tempfilename); + ob_end_clean(); + return true; + + } else { + + $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents()); + + } + fclose($fp_source); + + } else { + + $this->errors[] = 'Could not open '.$this->filename.' mode "rb" - '.strip_tags(ob_get_contents()); + + } + ob_end_clean(); + } + return false; + + } + + } else { + + $this->errors[] = '$this->GenerateID3v2Tag() failed'; + + } + + if (!empty($this->errors)) { + return false; + } + return true; + } else { + $this->errors[] = '!is_writeable('.$this->filename.')'; + } + return false; + } + + function RemoveID3v2() { + + // File MUST be writeable - CHMOD(646) at least. It's best if the + // directory is also writeable, because that method is both faster and less susceptible to errors. + if (is_writeable(dirname($this->filename))) { + + // preferred method - only one copying operation, minimal chance of corrupting + // original file if script is interrupted, but required directory to be writeable + if ($fp_source = @fopen($this->filename, 'rb')) { + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + rewind($fp_source); + if ($OldThisFileInfo['avdataoffset'] !== false) { + fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); + } + if ($fp_temp = @fopen($this->filename.'getid3tmp', 'w+b')) { + while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_temp); + } else { + $this->errors[] = 'Could not open '.$this->filename.'getid3tmp mode "w+b"'; + } + fclose($fp_source); + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "rb"'; + } + if (file_exists($this->filename)) { + unlink($this->filename); + } + rename($this->filename.'getid3tmp', $this->filename); + + } elseif (is_writable($this->filename)) { + + // less desirable alternate method - double-copies the file, overwrites original file + // and could corrupt source file if the script is interrupted or an error occurs. + if ($fp_source = @fopen($this->filename, 'rb')) { + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + rewind($fp_source); + if ($OldThisFileInfo['avdataoffset'] !== false) { + fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); + } + if ($fp_temp = tmpfile()) { + while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_source); + if ($fp_source = @fopen($this->filename, 'wb')) { + rewind($fp_temp); + while ($buffer = fread($fp_temp, GETID3_FREAD_BUFFER_SIZE)) { + fwrite($fp_source, $buffer, strlen($buffer)); + } + fseek($fp_temp, -128, SEEK_END); + fclose($fp_source); + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "wb"'; + } + fclose($fp_temp); + } else { + $this->errors[] = 'Could not create tmpfile()'; + } + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "rb"'; + } + + } else { + + $this->errors[] = 'Directory and file both not writeable'; + + } + + if (!empty($this->errors)) { + return false; + } + return true; + } + + + function GenerateID3v2TagFlags($flags) { + switch ($this->majorversion) { + case 4: + // %abcd0000 + $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation + $flag .= (@$flags['extendedheader'] ? '1' : '0'); // b - Extended header + $flag .= (@$flags['experimental'] ? '1' : '0'); // c - Experimental indicator + $flag .= (@$flags['footer'] ? '1' : '0'); // d - Footer present + $flag .= '0000'; + break; + + case 3: + // %abc00000 + $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation + $flag .= (@$flags['extendedheader'] ? '1' : '0'); // b - Extended header + $flag .= (@$flags['experimental'] ? '1' : '0'); // c - Experimental indicator + $flag .= '00000'; + break; + + case 2: + // %ab000000 + $flag = (@$flags['unsynchronisation'] ? '1' : '0'); // a - Unsynchronisation + $flag .= (@$flags['compression'] ? '1' : '0'); // b - Compression + $flag .= '000000'; + break; + + default: + return false; + break; + } + return chr(bindec($flag)); + } + + + function GenerateID3v2FrameFlags($TagAlter=false, $FileAlter=false, $ReadOnly=false, $Compression=false, $Encryption=false, $GroupingIdentity=false, $Unsynchronisation=false, $DataLengthIndicator=false) { + switch ($this->majorversion) { + case 4: + // %0abc0000 %0h00kmnp + $flag1 = '0'; + $flag1 .= $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard) + $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard) + $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only) + $flag1 .= '0000'; + + $flag2 = '0'; + $flag2 .= $GroupingIdentity ? '1' : '0'; // h - Grouping identity (true == contains group information) + $flag2 .= '00'; + $flag2 .= $Compression ? '1' : '0'; // k - Compression (true == compressed) + $flag2 .= $Encryption ? '1' : '0'; // m - Encryption (true == encrypted) + $flag2 .= $Unsynchronisation ? '1' : '0'; // n - Unsynchronisation (true == unsynchronised) + $flag2 .= $DataLengthIndicator ? '1' : '0'; // p - Data length indicator (true == data length indicator added) + break; + + case 3: + // %abc00000 %ijk00000 + $flag1 = $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard) + $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard) + $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only) + $flag1 .= '00000'; + + $flag2 = $Compression ? '1' : '0'; // i - Compression (true == compressed) + $flag2 .= $Encryption ? '1' : '0'; // j - Encryption (true == encrypted) + $flag2 .= $GroupingIdentity ? '1' : '0'; // k - Grouping identity (true == contains group information) + $flag2 .= '00000'; + break; + + default: + return false; + break; + + } + return chr(bindec($flag1)).chr(bindec($flag2)); + } + + function GenerateID3v2FrameData($frame_name, $source_data_array) { + if (!getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) { + return false; + } + $framedata = ''; + + if (($this->majorversion < 3) || ($this->majorversion > 4)) { + + $this->errors[] = 'Only ID3v2.3 and ID3v2.4 are supported in GenerateID3v2FrameData()'; + + } else { // $this->majorversion 3 or 4 + + switch ($frame_name) { + case 'UFID': + // 4.1 UFID Unique file identifier + // Owner identifier $00 + // Identifier + if (strlen($source_data_array['data']) > 64) { + $this->errors[] = 'Identifier not allowed to be longer than 64 bytes in '.$frame_name.' (supplied data was '.strlen($source_data_array['data']).' bytes long)'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= substr($source_data_array['data'], 0, 64); // max 64 bytes - truncate anything longer + } + break; + + case 'TXXX': + // 4.2.2 TXXX User defined text information frame + // Text encoding $xx + // Description $00 (00) + // Value + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'WXXX': + // 4.3.2 WXXX User defined URL link frame + // Text encoding $xx + // Description $00 (00) + // URL + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (!isset($source_data_array['data']) || !$this->IsValidURL($source_data_array['data'], false, false)) { + //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + // probably should be an error, need to rewrite IsValidURL() to handle other encodings + $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'IPLS': + // 4.4 IPLS Involved people list (ID3v2.3 only) + // Text encoding $xx + // People list strings + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'MCDI': + // 4.4 MCDI Music CD identifier + // CD TOC + $framedata .= $source_data_array['data']; + break; + + case 'ETCO': + // 4.5 ETCO Event timing codes + // Time stamp format $xx + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Followed by a list of key events in the following format: + // Type of event $xx + // Time stamp $xx (xx ...) + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { + $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; + } else { + $framedata .= chr($source_data_array['timestampformat']); + foreach ($source_data_array as $key => $val) { + if (!$this->ID3v2IsValidETCOevent($val['typeid'])) { + $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')'; + } elseif (($key != 'timestampformat') && ($key != 'flags')) { + if (($val['timestamp'] > 0) && ($previousETCOtimestamp >= $val['timestamp'])) { + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + $this->errors[] = 'Out-of-order timestamp in '.$frame_name.' ('.$val['timestamp'].') for Event Type ('.$val['typeid'].')'; + } else { + $framedata .= chr($val['typeid']); + $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); + } + } + } + } + break; + + case 'MLLT': + // 4.6 MLLT MPEG location lookup table + // MPEG frames between reference $xx xx + // Bytes between reference $xx xx xx + // Milliseconds between reference $xx xx xx + // Bits for bytes deviation $xx + // Bits for milliseconds dev. $xx + // Then for every reference the following data is included; + // Deviation in bytes %xxx.... + // Deviation in milliseconds %xxx.... + if (($source_data_array['framesbetweenreferences'] > 0) && ($source_data_array['framesbetweenreferences'] <= 65535)) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['framesbetweenreferences'], 2, false); + } else { + $this->errors[] = 'Invalid MPEG Frames Between References in '.$frame_name.' ('.$source_data_array['framesbetweenreferences'].')'; + } + if (($source_data_array['bytesbetweenreferences'] > 0) && ($source_data_array['bytesbetweenreferences'] <= 16777215)) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['bytesbetweenreferences'], 3, false); + } else { + $this->errors[] = 'Invalid bytes Between References in '.$frame_name.' ('.$source_data_array['bytesbetweenreferences'].')'; + } + if (($source_data_array['msbetweenreferences'] > 0) && ($source_data_array['msbetweenreferences'] <= 16777215)) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['msbetweenreferences'], 3, false); + } else { + $this->errors[] = 'Invalid Milliseconds Between References in '.$frame_name.' ('.$source_data_array['msbetweenreferences'].')'; + } + if (!$this->IsWithinBitRange($source_data_array['bitsforbytesdeviation'], 8, false)) { + if (($source_data_array['bitsforbytesdeviation'] % 4) == 0) { + $framedata .= chr($source_data_array['bitsforbytesdeviation']); + } else { + $this->errors[] = 'Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.'; + } + } else { + $this->errors[] = 'Invalid Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].')'; + } + if (!$this->IsWithinBitRange($source_data_array['bitsformsdeviation'], 8, false)) { + if (($source_data_array['bitsformsdeviation'] % 4) == 0) { + $framedata .= chr($source_data_array['bitsformsdeviation']); + } else { + $this->errors[] = 'Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.'; + } + } else { + $this->errors[] = 'Invalid Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsformsdeviation'].')'; + } + foreach ($source_data_array as $key => $val) { + if (($key != 'framesbetweenreferences') && ($key != 'bytesbetweenreferences') && ($key != 'msbetweenreferences') && ($key != 'bitsforbytesdeviation') && ($key != 'bitsformsdeviation') && ($key != 'flags')) { + $unwrittenbitstream .= str_pad(getid3_lib::Dec2Bin($val['bytedeviation']), $source_data_array['bitsforbytesdeviation'], '0', STR_PAD_LEFT); + $unwrittenbitstream .= str_pad(getid3_lib::Dec2Bin($val['msdeviation']), $source_data_array['bitsformsdeviation'], '0', STR_PAD_LEFT); + } + } + for ($i = 0; $i < strlen($unwrittenbitstream); $i += 8) { + $highnibble = bindec(substr($unwrittenbitstream, $i, 4)) << 4; + $lownibble = bindec(substr($unwrittenbitstream, $i + 4, 4)); + $framedata .= chr($highnibble & $lownibble); + } + break; + + case 'SYTC': + // 4.7 SYTC Synchronised tempo codes + // Time stamp format $xx + // Tempo data + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { + $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; + } else { + $framedata .= chr($source_data_array['timestampformat']); + foreach ($source_data_array as $key => $val) { + if (!$this->ID3v2IsValidETCOevent($val['typeid'])) { + $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')'; + } elseif (($key != 'timestampformat') && ($key != 'flags')) { + if (($val['tempo'] < 0) || ($val['tempo'] > 510)) { + $this->errors[] = 'Invalid Tempo (max = 510) in '.$frame_name.' ('.$val['tempo'].') at timestamp ('.$val['timestamp'].')'; + } else { + if ($val['tempo'] > 255) { + $framedata .= chr(255); + $val['tempo'] -= 255; + } + $framedata .= chr($val['tempo']); + $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); + } + } + } + } + break; + + case 'USLT': + // 4.8 USLT Unsynchronised lyric/text transcription + // Text encoding $xx + // Language $xx xx xx + // Content descriptor $00 (00) + // Lyrics/text + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { + $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= strtolower($source_data_array['language']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'SYLT': + // 4.9 SYLT Synchronised lyric/text + // Text encoding $xx + // Language $xx xx xx + // Time stamp format $xx + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Content type $xx + // Content descriptor $00 (00) + // Terminated text to be synced (typically a syllable) + // Sync identifier (terminator to above string) $00 (00) + // Time stamp $xx (xx ...) + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { + $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; + } elseif (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { + $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; + } elseif (!$this->ID3v2IsValidSYLTtype($source_data_array['contenttypeid'])) { + $this->errors[] = 'Invalid Content Type byte in '.$frame_name.' ('.$source_data_array['contenttypeid'].')'; + } elseif (!is_array($source_data_array['data'])) { + $this->errors[] = 'Invalid Lyric/Timestamp data in '.$frame_name.' (must be an array)'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= strtolower($source_data_array['language']); + $framedata .= chr($source_data_array['timestampformat']); + $framedata .= chr($source_data_array['contenttypeid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + ksort($source_data_array['data']); + foreach ($source_data_array['data'] as $key => $val) { + $framedata .= $val['data'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); + } + } + break; + + case 'COMM': + // 4.10 COMM Comments + // Text encoding $xx + // Language $xx xx xx + // Short content descrip. $00 (00) + // The actual text + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { + $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= strtolower($source_data_array['language']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'RVA2': + // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only) + // Identification $00 + // The 'identification' string is used to identify the situation and/or + // device where this adjustment should apply. The following is then + // repeated for every channel: + // Type of channel $xx + // Volume adjustment $xx xx + // Bits representing peak $xx + // Peak volume $xx (xx ...) + $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00"; + foreach ($source_data_array as $key => $val) { + if ($key != 'description') { + $framedata .= chr($val['channeltypeid']); + $framedata .= getid3_lib::BigEndian2String($val['volumeadjust'], 2, false, true); // signed 16-bit + if (!$this->IsWithinBitRange($source_data_array['bitspeakvolume'], 8, false)) { + $framedata .= chr($val['bitspeakvolume']); + if ($val['bitspeakvolume'] > 0) { + $framedata .= getid3_lib::BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), false, false); + } + } else { + $this->errors[] = 'Invalid Bits Representing Peak Volume in '.$frame_name.' ('.$val['bitspeakvolume'].') (range = 0 to 255)'; + } + } + } + break; + + case 'RVAD': + // 4.12 RVAD Relative volume adjustment (ID3v2.3 only) + // Increment/decrement %00fedcba + // Bits used for volume descr. $xx + // Relative volume change, right $xx xx (xx ...) // a + // Relative volume change, left $xx xx (xx ...) // b + // Peak volume right $xx xx (xx ...) + // Peak volume left $xx xx (xx ...) + // Relative volume change, right back $xx xx (xx ...) // c + // Relative volume change, left back $xx xx (xx ...) // d + // Peak volume right back $xx xx (xx ...) + // Peak volume left back $xx xx (xx ...) + // Relative volume change, center $xx xx (xx ...) // e + // Peak volume center $xx xx (xx ...) + // Relative volume change, bass $xx xx (xx ...) // f + // Peak volume bass $xx xx (xx ...) + if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) { + $this->errors[] = 'Invalid Bits For Volume Description byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)'; + } else { + $incdecflag .= '00'; + $incdecflag .= $source_data_array['incdec']['right'] ? '1' : '0'; // a - Relative volume change, right + $incdecflag .= $source_data_array['incdec']['left'] ? '1' : '0'; // b - Relative volume change, left + $incdecflag .= $source_data_array['incdec']['rightrear'] ? '1' : '0'; // c - Relative volume change, right back + $incdecflag .= $source_data_array['incdec']['leftrear'] ? '1' : '0'; // d - Relative volume change, left back + $incdecflag .= $source_data_array['incdec']['center'] ? '1' : '0'; // e - Relative volume change, center + $incdecflag .= $source_data_array['incdec']['bass'] ? '1' : '0'; // f - Relative volume change, bass + $framedata .= chr(bindec($incdecflag)); + $framedata .= chr($source_data_array['bitsvolume']); + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['right'], ceil($source_data_array['bitsvolume'] / 8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['left'], ceil($source_data_array['bitsvolume'] / 8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['right'], ceil($source_data_array['bitsvolume'] / 8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['left'], ceil($source_data_array['bitsvolume'] / 8), false); + if ($source_data_array['volumechange']['rightrear'] || $source_data_array['volumechange']['leftrear'] || + $source_data_array['peakvolume']['rightrear'] || $source_data_array['peakvolume']['leftrear'] || + $source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || + $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['rightrear'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['leftrear'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['rightrear'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['leftrear'], ceil($source_data_array['bitsvolume']/8), false); + } + if ($source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || + $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['center'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['center'], ceil($source_data_array['bitsvolume']/8), false); + } + if ($source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['bass'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['bass'], ceil($source_data_array['bitsvolume']/8), false); + } + } + break; + + case 'EQU2': + // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only) + // Interpolation method $xx + // $00 Band + // $01 Linear + // Identification $00 + // The following is then repeated for every adjustment point + // Frequency $xx xx + // Volume adjustment $xx xx + if (($source_data_array['interpolationmethod'] < 0) || ($source_data_array['interpolationmethod'] > 1)) { + $this->errors[] = 'Invalid Interpolation Method byte in '.$frame_name.' ('.$source_data_array['interpolationmethod'].') (valid = 0 or 1)'; + } else { + $framedata .= chr($source_data_array['interpolationmethod']); + $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00"; + foreach ($source_data_array['data'] as $key => $val) { + $framedata .= getid3_lib::BigEndian2String(intval(round($key * 2)), 2, false); + $framedata .= getid3_lib::BigEndian2String($val, 2, false, true); // signed 16-bit + } + } + break; + + case 'EQUA': + // 4.12 EQUA Equalisation (ID3v2.3 only) + // Adjustment bits $xx + // This is followed by 2 bytes + ('adjustment bits' rounded up to the + // nearest byte) for every equalisation band in the following format, + // giving a frequency range of 0 - 32767Hz: + // Increment/decrement %x (MSB of the Frequency) + // Frequency (lower 15 bits) + // Adjustment $xx (xx ...) + if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) { + $this->errors[] = 'Invalid Adjustment Bits byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)'; + } else { + $framedata .= chr($source_data_array['adjustmentbits']); + foreach ($source_data_array as $key => $val) { + if ($key != 'bitsvolume') { + if (($key > 32767) || ($key < 0)) { + $this->errors[] = 'Invalid Frequency in '.$frame_name.' ('.$key.') (range = 0 to 32767)'; + } else { + if ($val >= 0) { + // put MSB of frequency to 1 if increment, 0 if decrement + $key |= 0x8000; + } + $framedata .= getid3_lib::BigEndian2String($key, 2, false); + $framedata .= getid3_lib::BigEndian2String($val, ceil($source_data_array['adjustmentbits'] / 8), false); + } + } + } + } + break; + + case 'RVRB': + // 4.13 RVRB Reverb + // Reverb left (ms) $xx xx + // Reverb right (ms) $xx xx + // Reverb bounces, left $xx + // Reverb bounces, right $xx + // Reverb feedback, left to left $xx + // Reverb feedback, left to right $xx + // Reverb feedback, right to right $xx + // Reverb feedback, right to left $xx + // Premix left to right $xx + // Premix right to left $xx + if (!$this->IsWithinBitRange($source_data_array['left'], 16, false)) { + $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['left'].') (range = 0 to 65535)'; + } elseif (!$this->IsWithinBitRange($source_data_array['right'], 16, false)) { + $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['right'].') (range = 0 to 65535)'; + } elseif (!$this->IsWithinBitRange($source_data_array['bouncesL'], 8, false)) { + $this->errors[] = 'Invalid Reverb Bounces, Left in '.$frame_name.' ('.$source_data_array['bouncesL'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['bouncesR'], 8, false)) { + $this->errors[] = 'Invalid Reverb Bounces, Right in '.$frame_name.' ('.$source_data_array['bouncesR'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['feedbackLL'], 8, false)) { + $this->errors[] = 'Invalid Reverb Feedback, Left-To-Left in '.$frame_name.' ('.$source_data_array['feedbackLL'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['feedbackLR'], 8, false)) { + $this->errors[] = 'Invalid Reverb Feedback, Left-To-Right in '.$frame_name.' ('.$source_data_array['feedbackLR'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['feedbackRR'], 8, false)) { + $this->errors[] = 'Invalid Reverb Feedback, Right-To-Right in '.$frame_name.' ('.$source_data_array['feedbackRR'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['feedbackRL'], 8, false)) { + $this->errors[] = 'Invalid Reverb Feedback, Right-To-Left in '.$frame_name.' ('.$source_data_array['feedbackRL'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['premixLR'], 8, false)) { + $this->errors[] = 'Invalid Premix, Left-To-Right in '.$frame_name.' ('.$source_data_array['premixLR'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['premixRL'], 8, false)) { + $this->errors[] = 'Invalid Premix, Right-To-Left in '.$frame_name.' ('.$source_data_array['premixRL'].') (range = 0 to 255)'; + } else { + $framedata .= getid3_lib::BigEndian2String($source_data_array['left'], 2, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['right'], 2, false); + $framedata .= chr($source_data_array['bouncesL']); + $framedata .= chr($source_data_array['bouncesR']); + $framedata .= chr($source_data_array['feedbackLL']); + $framedata .= chr($source_data_array['feedbackLR']); + $framedata .= chr($source_data_array['feedbackRR']); + $framedata .= chr($source_data_array['feedbackRL']); + $framedata .= chr($source_data_array['premixLR']); + $framedata .= chr($source_data_array['premixRL']); + } + break; + + case 'APIC': + // 4.14 APIC Attached picture + // Text encoding $xx + // MIME type $00 + // Picture type $xx + // Description $00 (00) + // Picture data + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (!$this->ID3v2IsValidAPICpicturetype($source_data_array['picturetypeid'])) { + $this->errors[] = 'Invalid Picture Type byte in '.$frame_name.' ('.$source_data_array['picturetypeid'].') for ID3v2.'.$this->majorversion; + } elseif (($this->majorversion >= 3) && (!$this->ID3v2IsValidAPICimageformat($source_data_array['mime']))) { + $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].') for ID3v2.'.$this->majorversion; + } elseif (($source_data_array['mime'] == '-->') && (!$this->IsValidURL($source_data_array['data'], false, false))) { + //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + // probably should be an error, need to rewrite IsValidURL() to handle other encodings + $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00"; + $framedata .= chr($source_data_array['picturetypeid']); + $framedata .= @$source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'GEOB': + // 4.15 GEOB General encapsulated object + // Text encoding $xx + // MIME type $00 + // Filename $00 (00) + // Content description $00 (00) + // Encapsulated object + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (!$this->IsValidMIMEstring($source_data_array['mime'])) { + $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')'; + } elseif (!$source_data_array['description']) { + $this->errors[] = 'Missing Description in '.$frame_name; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00"; + $framedata .= $source_data_array['filename'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'PCNT': + // 4.16 PCNT Play counter + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + // Counter $xx xx xx xx (xx ...) + $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); + break; + + case 'POPM': + // 4.17 POPM Popularimeter + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + // Email to user $00 + // Rating $xx + // Counter $xx xx xx xx (xx ...) + if (!$this->IsWithinBitRange($source_data_array['rating'], 8, false)) { + $this->errors[] = 'Invalid Rating byte in '.$frame_name.' ('.$source_data_array['rating'].') (range = 0 to 255)'; + } elseif (!IsValidEmail($source_data_array['email'])) { + $this->errors[] = 'Invalid Email in '.$frame_name.' ('.$source_data_array['email'].')'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['email'])."\x00"; + $framedata .= chr($source_data_array['rating']); + $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); + } + break; + + case 'RBUF': + // 4.18 RBUF Recommended buffer size + // Buffer size $xx xx xx + // Embedded info flag %0000000x + // Offset to next tag $xx xx xx xx + if (!$this->IsWithinBitRange($source_data_array['buffersize'], 24, false)) { + $this->errors[] = 'Invalid Buffer Size in '.$frame_name; + } elseif (!$this->IsWithinBitRange($source_data_array['nexttagoffset'], 32, false)) { + $this->errors[] = 'Invalid Offset To Next Tag in '.$frame_name; + } else { + $framedata .= getid3_lib::BigEndian2String($source_data_array['buffersize'], 3, false); + $flag .= '0000000'; + $flag .= $source_data_array['flags']['embededinfo'] ? '1' : '0'; + $framedata .= chr(bindec($flag)); + $framedata .= getid3_lib::BigEndian2String($source_data_array['nexttagoffset'], 4, false); + } + break; + + case 'AENC': + // 4.19 AENC Audio encryption + // Owner identifier $00 + // Preview start $xx xx + // Preview length $xx xx + // Encryption info + if (!$this->IsWithinBitRange($source_data_array['previewstart'], 16, false)) { + $this->errors[] = 'Invalid Preview Start in '.$frame_name.' ('.$source_data_array['previewstart'].')'; + } elseif (!$this->IsWithinBitRange($source_data_array['previewlength'], 16, false)) { + $this->errors[] = 'Invalid Preview Length in '.$frame_name.' ('.$source_data_array['previewlength'].')'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= getid3_lib::BigEndian2String($source_data_array['previewstart'], 2, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['previewlength'], 2, false); + $framedata .= $source_data_array['encryptioninfo']; + } + break; + + case 'LINK': + // 4.20 LINK Linked information + // Frame identifier $xx xx xx xx + // URL $00 + // ID and additional data + if (!getid3_id3v2::IsValidID3v2FrameName($source_data_array['frameid'], $this->majorversion)) { + $this->errors[] = 'Invalid Frame Identifier in '.$frame_name.' ('.$source_data_array['frameid'].')'; + } elseif (!$this->IsValidURL($source_data_array['data'], true, false)) { + //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + // probably should be an error, need to rewrite IsValidURL() to handle other encodings + $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + } elseif ((($source_data_array['frameid'] == 'AENC') || ($source_data_array['frameid'] == 'APIC') || ($source_data_array['frameid'] == 'GEOB') || ($source_data_array['frameid'] == 'TXXX')) && ($source_data_array['additionaldata'] == '')) { + $this->errors[] = 'Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; + } elseif (($source_data_array['frameid'] == 'USER') && (getid3_id3v2::LanguageLookup($source_data_array['additionaldata'], true) == '')) { + $this->errors[] = 'Language must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; + } elseif (($source_data_array['frameid'] == 'PRIV') && ($source_data_array['additionaldata'] == '')) { + $this->errors[] = 'Owner Identifier must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; + } elseif ((($source_data_array['frameid'] == 'COMM') || ($source_data_array['frameid'] == 'SYLT') || ($source_data_array['frameid'] == 'USLT')) && ((getid3_id3v2::LanguageLookup(substr($source_data_array['additionaldata'], 0, 3), true) == '') || (substr($source_data_array['additionaldata'], 3) == ''))) { + $this->errors[] = 'Language followed by Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; + } else { + $framedata .= $source_data_array['frameid']; + $framedata .= str_replace("\x00", '', $source_data_array['data'])."\x00"; + switch ($source_data_array['frameid']) { + case 'COMM': + case 'SYLT': + case 'USLT': + case 'PRIV': + case 'USER': + case 'AENC': + case 'APIC': + case 'GEOB': + case 'TXXX': + $framedata .= $source_data_array['additionaldata']; + break; + case 'ASPI': + case 'ETCO': + case 'EQU2': + case 'MCID': + case 'MLLT': + case 'OWNE': + case 'RVA2': + case 'RVRB': + case 'SYTC': + case 'IPLS': + case 'RVAD': + case 'EQUA': + // no additional data required + break; + case 'RBUF': + if ($this->majorversion == 3) { + // no additional data required + } else { + $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')'; + } + + default: + if ((substr($source_data_array['frameid'], 0, 1) == 'T') || (substr($source_data_array['frameid'], 0, 1) == 'W')) { + // no additional data required + } else { + $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')'; + } + break; + } + } + break; + + case 'POSS': + // 4.21 POSS Position synchronisation frame (ID3v2.3+ only) + // Time stamp format $xx + // Position $xx (xx ...) + if (($source_data_array['timestampformat'] < 1) || ($source_data_array['timestampformat'] > 2)) { + $this->errors[] = 'Invalid Time Stamp Format in '.$frame_name.' ('.$source_data_array['timestampformat'].') (valid = 1 or 2)'; + } elseif (!$this->IsWithinBitRange($source_data_array['position'], 32, false)) { + $this->errors[] = 'Invalid Position in '.$frame_name.' ('.$source_data_array['position'].') (range = 0 to 4294967295)'; + } else { + $framedata .= chr($source_data_array['timestampformat']); + $framedata .= getid3_lib::BigEndian2String($source_data_array['position'], 4, false); + } + break; + + case 'USER': + // 4.22 USER Terms of use (ID3v2.3+ only) + // Text encoding $xx + // Language $xx xx xx + // The actual text + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; + } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { + $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= strtolower($source_data_array['language']); + $framedata .= $source_data_array['data']; + } + break; + + case 'OWNE': + // 4.23 OWNE Ownership frame (ID3v2.3+ only) + // Text encoding $xx + // Price paid $00 + // Date of purch. + // Seller + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; + } elseif (!$this->IsANumber($source_data_array['pricepaid']['value'], false)) { + $this->errors[] = 'Invalid Price Paid in '.$frame_name.' ('.$source_data_array['pricepaid']['value'].')'; + } elseif (!$this->IsValidDateStampString($source_data_array['purchasedate'])) { + $this->errors[] = 'Invalid Date Of Purchase in '.$frame_name.' ('.$source_data_array['purchasedate'].') (format = YYYYMMDD)'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= str_replace("\x00", '', $source_data_array['pricepaid']['value'])."\x00"; + $framedata .= $source_data_array['purchasedate']; + $framedata .= $source_data_array['seller']; + } + break; + + case 'COMR': + // 4.24 COMR Commercial frame (ID3v2.3+ only) + // Text encoding $xx + // Price string $00 + // Valid until + // Contact URL $00 + // Received as $xx + // Name of seller $00 (00) + // Description $00 (00) + // Picture MIME type $00 + // Seller logo + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; + } elseif (!$this->IsValidDateStampString($source_data_array['pricevaliduntil'])) { + $this->errors[] = 'Invalid Valid Until date in '.$frame_name.' ('.$source_data_array['pricevaliduntil'].') (format = YYYYMMDD)'; + } elseif (!$this->IsValidURL($source_data_array['contacturl'], false, true)) { + $this->errors[] = 'Invalid Contact URL in '.$frame_name.' ('.$source_data_array['contacturl'].') (allowed schemes: http, https, ftp, mailto)'; + } elseif (!$this->ID3v2IsValidCOMRreceivedAs($source_data_array['receivedasid'])) { + $this->errors[] = 'Invalid Received As byte in '.$frame_name.' ('.$source_data_array['contacturl'].') (range = 0 to 8)'; + } elseif (!$this->IsValidMIMEstring($source_data_array['mime'])) { + $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + unset($pricestring); + foreach ($source_data_array['price'] as $key => $val) { + if ($this->ID3v2IsValidPriceString($key.$val['value'])) { + $pricestrings[] = $key.$val['value']; + } else { + $this->errors[] = 'Invalid Price String in '.$frame_name.' ('.$key.$val['value'].')'; + } + } + $framedata .= implode('/', $pricestrings); + $framedata .= $source_data_array['pricevaliduntil']; + $framedata .= str_replace("\x00", '', $source_data_array['contacturl'])."\x00"; + $framedata .= chr($source_data_array['receivedasid']); + $framedata .= $source_data_array['sellername'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['mime']."\x00"; + $framedata .= $source_data_array['logo']; + } + break; + + case 'ENCR': + // 4.25 ENCR Encryption method registration (ID3v2.3+ only) + // Owner identifier $00 + // Method symbol $xx + // Encryption data + if (!$this->IsWithinBitRange($source_data_array['methodsymbol'], 8, false)) { + $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['methodsymbol'].') (range = 0 to 255)'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= ord($source_data_array['methodsymbol']); + $framedata .= $source_data_array['data']; + } + break; + + case 'GRID': + // 4.26 GRID Group identification registration (ID3v2.3+ only) + // Owner identifier $00 + // Group symbol $xx + // Group dependent data + if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) { + $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= ord($source_data_array['groupsymbol']); + $framedata .= $source_data_array['data']; + } + break; + + case 'PRIV': + // 4.27 PRIV Private frame (ID3v2.3+ only) + // Owner identifier $00 + // The private data + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= $source_data_array['data']; + break; + + case 'SIGN': + // 4.28 SIGN Signature frame (ID3v2.4+ only) + // Group symbol $xx + // Signature + if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) { + $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)'; + } else { + $framedata .= ord($source_data_array['groupsymbol']); + $framedata .= $source_data_array['data']; + } + break; + + case 'SEEK': + // 4.29 SEEK Seek frame (ID3v2.4+ only) + // Minimum offset to next tag $xx xx xx xx + if (!$this->IsWithinBitRange($source_data_array['data'], 32, false)) { + $this->errors[] = 'Invalid Minimum Offset in '.$frame_name.' ('.$source_data_array['data'].') (range = 0 to 4294967295)'; + } else { + $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); + } + break; + + case 'ASPI': + // 4.30 ASPI Audio seek point index (ID3v2.4+ only) + // Indexed data start (S) $xx xx xx xx + // Indexed data length (L) $xx xx xx xx + // Number of index points (N) $xx xx + // Bits per index point (b) $xx + // Then for every index point the following data is included: + // Fraction at index (Fi) $xx (xx) + if (!$this->IsWithinBitRange($source_data_array['datastart'], 32, false)) { + $this->errors[] = 'Invalid Indexed Data Start in '.$frame_name.' ('.$source_data_array['datastart'].') (range = 0 to 4294967295)'; + } elseif (!$this->IsWithinBitRange($source_data_array['datalength'], 32, false)) { + $this->errors[] = 'Invalid Indexed Data Length in '.$frame_name.' ('.$source_data_array['datalength'].') (range = 0 to 4294967295)'; + } elseif (!$this->IsWithinBitRange($source_data_array['indexpoints'], 16, false)) { + $this->errors[] = 'Invalid Number Of Index Points in '.$frame_name.' ('.$source_data_array['indexpoints'].') (range = 0 to 65535)'; + } elseif (!$this->IsWithinBitRange($source_data_array['bitsperpoint'], 8, false)) { + $this->errors[] = 'Invalid Bits Per Index Point in '.$frame_name.' ('.$source_data_array['bitsperpoint'].') (range = 0 to 255)'; + } elseif ($source_data_array['indexpoints'] != count($source_data_array['indexes'])) { + $this->errors[] = 'Number Of Index Points does not match actual supplied data in '.$frame_name; + } else { + $framedata .= getid3_lib::BigEndian2String($source_data_array['datastart'], 4, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['datalength'], 4, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['indexpoints'], 2, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['bitsperpoint'], 1, false); + foreach ($source_data_array['indexes'] as $key => $val) { + $framedata .= getid3_lib::BigEndian2String($val, ceil($source_data_array['bitsperpoint'] / 8), false); + } + } + break; + + case 'RGAD': + // RGAD Replay Gain Adjustment + // http://privatewww.essex.ac.uk/~djmrob/replaygain/ + // Peak Amplitude $xx $xx $xx $xx + // Radio Replay Gain Adjustment %aaabbbcd %dddddddd + // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd + // a - name code + // b - originator code + // c - sign bit + // d - replay gain adjustment + + if (($source_data_array['track_adjustment'] > 51) || ($source_data_array['track_adjustment'] < -51)) { + $this->errors[] = 'Invalid Track Adjustment in '.$frame_name.' ('.$source_data_array['track_adjustment'].') (range = -51.0 to +51.0)'; + } elseif (($source_data_array['album_adjustment'] > 51) || ($source_data_array['album_adjustment'] < -51)) { + $this->errors[] = 'Invalid Album Adjustment in '.$frame_name.' ('.$source_data_array['album_adjustment'].') (range = -51.0 to +51.0)'; + } elseif (!$this->ID3v2IsValidRGADname($source_data_array['raw']['track_name'])) { + $this->errors[] = 'Invalid Track Name Code in '.$frame_name.' ('.$source_data_array['raw']['track_name'].') (range = 0 to 2)'; + } elseif (!$this->ID3v2IsValidRGADname($source_data_array['raw']['album_name'])) { + $this->errors[] = 'Invalid Album Name Code in '.$frame_name.' ('.$source_data_array['raw']['album_name'].') (range = 0 to 2)'; + } elseif (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['track_originator'])) { + $this->errors[] = 'Invalid Track Originator Code in '.$frame_name.' ('.$source_data_array['raw']['track_originator'].') (range = 0 to 3)'; + } elseif (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['album_originator'])) { + $this->errors[] = 'Invalid Album Originator Code in '.$frame_name.' ('.$source_data_array['raw']['album_originator'].') (range = 0 to 3)'; + } else { + $framedata .= getid3_lib::Float2String($source_data_array['peakamplitude'], 32); + $framedata .= getid3_lib::RGADgainString($source_data_array['raw']['track_name'], $source_data_array['raw']['track_originator'], $source_data_array['track_adjustment']); + $framedata .= getid3_lib::RGADgainString($source_data_array['raw']['album_name'], $source_data_array['raw']['album_originator'], $source_data_array['album_adjustment']); + } + break; + + default: + if ($frame_name{0} == 'T') { + // 4.2. T??? Text information frames + // Text encoding $xx + // Information + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + } elseif ($frame_name{0} == 'W') { + // 4.3. W??? URL link frames + // URL + if (!$this->IsValidURL($source_data_array['data'], false, false)) { + //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + // probably should be an error, need to rewrite IsValidURL() to handle other encodings + $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + } else { + $framedata .= $source_data_array['data']; + } + } else { + $this->errors[] = $frame_name.' not yet supported in $this->GenerateID3v2FrameData()'; + } + break; + } + } + if (!empty($this->errors)) { + return false; + } + return $framedata; + } + + function ID3v2FrameIsAllowed($frame_name, $source_data_array) { + static $PreviousFrames = array(); + + if ($frame_name === null) { + // if the writing functions are called multiple times, the static array needs to be + // cleared - this can be done by calling $this->ID3v2FrameIsAllowed(null, '') + $PreviousFrames = array(); + return true; + } + + if ($this->majorversion == 4) { + switch ($frame_name) { + case 'UFID': + case 'AENC': + case 'ENCR': + case 'GRID': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; + } + break; + + case 'TXXX': + case 'WXXX': + case 'RVA2': + case 'EQU2': + case 'APIC': + case 'GEOB': + if (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['description']; + } + break; + + case 'USER': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language ('.$source_data_array['language'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language']; + } + break; + + case 'USLT': + case 'SYLT': + case 'COMM': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; + } + break; + + case 'POPM': + if (!isset($source_data_array['email'])) { + $this->errors[] = '[email] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['email']; + } + break; + + case 'IPLS': + case 'MCDI': + case 'ETCO': + case 'MLLT': + case 'SYTC': + case 'RVRB': + case 'PCNT': + case 'RBUF': + case 'POSS': + case 'OWNE': + case 'SEEK': + case 'ASPI': + case 'RGAD': + if (in_array($frame_name, $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + + case 'LINK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($source_data_array['frameid'])) { + $this->errors[] = '[frameid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; + } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { + // no links to singleton tags + $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type + $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type + } + break; + + case 'COMR': + // There may be more than one 'commercial frame' in a tag, but no two may be identical + // Checking isn't implemented at all (yet) - just assumes that it's OK. + break; + + case 'PRIV': + case 'SIGN': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (!isset($source_data_array['data'])) { + $this->errors[] = '[data] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'].$source_data_array['data'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$source_data_array['ownerid'].' + '.$source_data_array['data'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid'].$source_data_array['data']; + } + break; + + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; + } + break; + } + + } elseif ($this->majorversion == 3) { + + switch ($frame_name) { + case 'UFID': + case 'AENC': + case 'ENCR': + case 'GRID': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; + } + break; + + case 'TXXX': + case 'WXXX': + case 'APIC': + case 'GEOB': + if (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['description']; + } + break; + + case 'USER': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language ('.$source_data_array['language'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language']; + } + break; + + case 'USLT': + case 'SYLT': + case 'COMM': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; + } + break; + + case 'POPM': + if (!isset($source_data_array['email'])) { + $this->errors[] = '[email] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['email']; + } + break; + + case 'IPLS': + case 'MCDI': + case 'ETCO': + case 'MLLT': + case 'SYTC': + case 'RVAD': + case 'EQUA': + case 'RVRB': + case 'PCNT': + case 'RBUF': + case 'POSS': + case 'OWNE': + case 'RGAD': + if (in_array($frame_name, $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + + case 'LINK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($source_data_array['frameid'])) { + $this->errors[] = '[frameid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; + } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { + // no links to singleton tags + $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type + $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type + } + break; + + case 'COMR': + // There may be more than one 'commercial frame' in a tag, but no two may be identical + // Checking isn't implemented at all (yet) - just assumes that it's OK. + break; + + case 'PRIV': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (!isset($source_data_array['data'])) { + $this->errors[] = '[data] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'].$source_data_array['data'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$source_data_array['ownerid'].' + '.$source_data_array['data'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid'].$source_data_array['data']; + } + break; + + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; + } + break; + } + + } elseif ($this->majorversion == 2) { + + switch ($frame_name) { + case 'UFI': + case 'CRM': + case 'CRA': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; + } + break; + + case 'TXX': + case 'WXX': + case 'PIC': + case 'GEO': + if (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['description']; + } + break; + + case 'ULT': + case 'SLT': + case 'COM': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; + } + break; + + case 'POP': + if (!isset($source_data_array['email'])) { + $this->errors[] = '[email] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['email']; + } + break; + + case 'IPL': + case 'MCI': + case 'ETC': + case 'MLL': + case 'STC': + case 'RVA': + case 'EQU': + case 'REV': + case 'CNT': + case 'BUF': + if (in_array($frame_name, $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + + case 'LNK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($source_data_array['frameid'])) { + $this->errors[] = '[frameid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; + } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { + // no links to singleton tags + $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type + $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type + } + break; + + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; + } + break; + } + } + + if (!empty($this->errors)) { + return false; + } + return true; + } + + function GenerateID3v2Tag($noerrorsonly=true) { + $this->ID3v2FrameIsAllowed(null, ''); // clear static array in case this isn't the first call to $this->GenerateID3v2Tag() + + $tagstring = ''; + if (is_array($this->tag_data)) { + foreach ($this->tag_data as $frame_name => $frame_rawinputdata) { + foreach ($frame_rawinputdata as $irrelevantindex => $source_data_array) { + if (getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) { + unset($frame_length); + unset($frame_flags); + $frame_data = false; + if ($this->ID3v2FrameIsAllowed($frame_name, $source_data_array)) { + if ($frame_data = $this->GenerateID3v2FrameData($frame_name, $source_data_array)) { + $FrameUnsynchronisation = false; + if ($this->majorversion >= 4) { + // frame-level unsynchronisation + $unsynchdata = $frame_data; + if ($this->id3v2_use_unsynchronisation) { + $unsynchdata = $this->Unsynchronise($frame_data); + } + if (strlen($unsynchdata) != strlen($frame_data)) { + // unsynchronisation needed + $FrameUnsynchronisation = true; + $frame_data = $unsynchdata; + if (isset($TagUnsynchronisation) && $TagUnsynchronisation === false) { + // only set to true if ALL frames are unsynchronised + } else { + $TagUnsynchronisation = true; + } + } else { + if (isset($TagUnsynchronisation)) { + $TagUnsynchronisation = false; + } + } + unset($unsynchdata); + + $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, true); + } else { + $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, false); + } + $frame_flags = $this->GenerateID3v2FrameFlags($this->ID3v2FrameFlagsLookupTagAlter($frame_name), $this->ID3v2FrameFlagsLookupFileAlter($frame_name), false, false, false, false, $FrameUnsynchronisation, false); + } + } else { + $this->errors[] = 'Frame "'.$frame_name.'" is NOT allowed'; + } + if ($frame_data === false) { + $this->errors[] = '$this->GenerateID3v2FrameData() failed for "'.$frame_name.'"'; + if ($noerrorsonly) { + return false; + } else { + unset($frame_name); + } + } + } else { + // ignore any invalid frame names, including 'title', 'header', etc + $this->warnings[] = 'Ignoring invalid ID3v2 frame type: "'.$frame_name.'"'; + unset($frame_name); + unset($frame_length); + unset($frame_flags); + unset($frame_data); + } + if (isset($frame_name) && isset($frame_length) && isset($frame_flags) && isset($frame_data)) { + $tagstring .= $frame_name.$frame_length.$frame_flags.$frame_data; + } + } + } + + if (!isset($TagUnsynchronisation)) { + $TagUnsynchronisation = false; + } + if (($this->majorversion <= 3) && $this->id3v2_use_unsynchronisation) { + // tag-level unsynchronisation + $unsynchdata = $this->Unsynchronise($tagstring); + if (strlen($unsynchdata) != strlen($tagstring)) { + // unsynchronisation needed + $TagUnsynchronisation = true; + $tagstring = $unsynchdata; + } + } + + while ($this->paddedlength < (strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion))) { + $this->paddedlength += 1024; + } + + $footer = false; // ID3v2 footers not yet supported in getID3() + if (!$footer && ($this->paddedlength > (strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)))) { + // pad up to $paddedlength bytes if unpadded tag is shorter than $paddedlength + // "Furthermore it MUST NOT have any padding when a tag footer is added to the tag." + $tagstring .= @str_repeat("\x00", $this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion)); + } + if ($this->id3v2_use_unsynchronisation && (substr($tagstring, strlen($tagstring) - 1, 1) == "\xFF")) { + // special unsynchronisation case: + // if last byte == $FF then appended a $00 + $TagUnsynchronisation = true; + $tagstring .= "\x00"; + } + + $tagheader = 'ID3'; + $tagheader .= chr($this->majorversion); + $tagheader .= chr($this->minorversion); + $tagheader .= $this->GenerateID3v2TagFlags(array('unsynchronisation'=>$TagUnsynchronisation)); + $tagheader .= getid3_lib::BigEndian2String(strlen($tagstring), 4, true); + + return $tagheader.$tagstring; + } + $this->errors[] = 'tag_data is not an array in GenerateID3v2Tag()'; + return false; + } + + function ID3v2IsValidPriceString($pricestring) { + if (getid3_id3v2::LanguageLookup(substr($pricestring, 0, 3), true) == '') { + return false; + } elseif (!$this->IsANumber(substr($pricestring, 3), true)) { + return false; + } + return true; + } + + function ID3v2FrameFlagsLookupTagAlter($framename) { + // unfinished + switch ($framename) { + case 'RGAD': + $allow = true; + default: + $allow = false; + break; + } + return $allow; + } + + function ID3v2FrameFlagsLookupFileAlter($framename) { + // unfinished + switch ($framename) { + case 'RGAD': + return false; + break; + + default: + return false; + break; + } + } + + function ID3v2IsValidETCOevent($eventid) { + if (($eventid < 0) || ($eventid > 0xFF)) { + // outside range of 1 byte + return false; + } elseif (($eventid >= 0xF0) && ($eventid <= 0xFC)) { + // reserved for future use + return false; + } elseif (($eventid >= 0x17) && ($eventid <= 0xDF)) { + // reserved for future use + return false; + } elseif (($eventid >= 0x0E) && ($eventid <= 0x16) && ($this->majorversion == 2)) { + // not defined in ID3v2.2 + return false; + } elseif (($eventid >= 0x15) && ($eventid <= 0x16) && ($this->majorversion == 3)) { + // not defined in ID3v2.3 + return false; + } + return true; + } + + function ID3v2IsValidSYLTtype($contenttype) { + if (($contenttype >= 0) && ($contenttype <= 8) && ($this->majorversion == 4)) { + return true; + } elseif (($contenttype >= 0) && ($contenttype <= 6) && ($this->majorversion == 3)) { + return true; + } + return false; + } + + function ID3v2IsValidRVA2channeltype($channeltype) { + if (($channeltype >= 0) && ($channeltype <= 8) && ($this->majorversion == 4)) { + return true; + } + return false; + } + + function ID3v2IsValidAPICpicturetype($picturetype) { + if (($picturetype >= 0) && ($picturetype <= 0x14) && ($this->majorversion >= 2) && ($this->majorversion <= 4)) { + return true; + } + return false; + } + + function ID3v2IsValidAPICimageformat($imageformat) { + if ($imageformat == '-->') { + return true; + } elseif ($this->majorversion == 2) { + if ((strlen($imageformat) == 3) && ($imageformat == strtoupper($imageformat))) { + return true; + } + } elseif (($this->majorversion == 3) || ($this->majorversion == 4)) { + if ($this->IsValidMIMEstring($imageformat)) { + return true; + } + } + return false; + } + + function ID3v2IsValidCOMRreceivedAs($receivedas) { + if (($this->majorversion >= 3) && ($receivedas >= 0) && ($receivedas <= 8)) { + return true; + } + return false; + } + + function ID3v2IsValidRGADname($RGADname) { + if (($RGADname >= 0) && ($RGADname <= 2)) { + return true; + } + return false; + } + + function ID3v2IsValidRGADoriginator($RGADoriginator) { + if (($RGADoriginator >= 0) && ($RGADoriginator <= 3)) { + return true; + } + return false; + } + + function ID3v2IsValidTextEncoding($textencodingbyte) { + static $ID3v2IsValidTextEncoding_cache = array( + 2 => array(true, true), + 3 => array(true, true), + 4 => array(true, true, true, true)); + return isset($ID3v2IsValidTextEncoding_cache[$this->majorversion][$textencodingbyte]); + } + + function Unsynchronise($data) { + // Whenever a false synchronisation is found within the tag, one zeroed + // byte is inserted after the first false synchronisation byte. The + // format of a correct sync that should be altered by ID3 encoders is as + // follows: + // %11111111 111xxxxx + // And should be replaced with: + // %11111111 00000000 111xxxxx + // This has the side effect that all $FF 00 combinations have to be + // altered, so they won't be affected by the decoding process. Therefore + // all the $FF 00 combinations have to be replaced with the $FF 00 00 + // combination during the unsynchronisation. + + $data = str_replace("\xFF\x00", "\xFF\x00\x00", $data); + $unsyncheddata = ''; + $datalength = strlen($data); + for ($i = 0; $i < $datalength; $i++) { + $thischar = $data{$i}; + $unsyncheddata .= $thischar; + if ($thischar == "\xFF") { + $nextchar = ord($data{$i + 1}); + if (($nextchar & 0xE0) == 0xE0) { + // previous byte = 11111111, this byte = 111????? + $unsyncheddata .= "\x00"; + } + } + } + return $unsyncheddata; + } + + function is_hash($var) { + // written by dev-nullchristophe*vg + // taken from http://www.php.net/manual/en/function.array-merge-recursive.php + if (is_array($var)) { + $keys = array_keys($var); + $all_num = true; + for ($i = 0; $i < count($keys); $i++) { + if (is_string($keys[$i])) { + return true; + } + } + } + return false; + } + + function array_join_merge($arr1, $arr2) { + // written by dev-nullchristophe*vg + // taken from http://www.php.net/manual/en/function.array-merge-recursive.php + if (is_array($arr1) && is_array($arr2)) { + // the same -> merge + $new_array = array(); + + if ($this->is_hash($arr1) && $this->is_hash($arr2)) { + // hashes -> merge based on keys + $keys = array_merge(array_keys($arr1), array_keys($arr2)); + foreach ($keys as $key) { + $new_array[$key] = $this->array_join_merge(@$arr1[$key], @$arr2[$key]); + } + } else { + // two real arrays -> merge + $new_array = array_reverse(array_unique(array_reverse(array_merge($arr1, $arr2)))); + } + return $new_array; + } else { + // not the same ... take new one if defined, else the old one stays + return $arr2 ? $arr2 : $arr1; + } + } + + function IsValidMIMEstring($mimestring) { + if ((strlen($mimestring) >= 3) && (strpos($mimestring, '/') > 0) && (strpos($mimestring, '/') < (strlen($mimestring) - 1))) { + return true; + } + return false; + } + + function IsWithinBitRange($number, $maxbits, $signed=false) { + if ($signed) { + if (($number > (0 - pow(2, $maxbits - 1))) && ($number <= pow(2, $maxbits - 1))) { + return true; + } + } else { + if (($number >= 0) && ($number <= pow(2, $maxbits))) { + return true; + } + } + return false; + } + + function safe_parse_url($url) { + $parts = @parse_url($url); + $parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : ''); + $parts['host'] = (isset($parts['host']) ? $parts['host'] : ''); + $parts['user'] = (isset($parts['user']) ? $parts['user'] : ''); + $parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : ''); + $parts['path'] = (isset($parts['path']) ? $parts['path'] : ''); + $parts['query'] = (isset($parts['query']) ? $parts['query'] : ''); + return $parts; + } + + function IsValidURL($url, $allowUserPass=false) { + if ($url == '') { + return false; + } + if ($allowUserPass !== true) { + if (strstr($url, '@')) { + // in the format http://user:pass@example.com or http://user@example.com + // but could easily be somebody incorrectly entering an email address in place of a URL + return false; + } + } + if ($parts = $this->safe_parse_url($url)) { + if (($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') && ($parts['scheme'] != 'ftp') && ($parts['scheme'] != 'gopher')) { + return false; + } elseif (!eregi("^[[:alnum:]]([-.]?[0-9a-z])*\.[a-z]{2,3}$", $parts['host'], $regs) && !IsValidDottedIP($parts['host'])) { + return false; + } elseif (!eregi("^([[:alnum:]-]|[\_])*$", $parts['user'], $regs)) { + return false; + } elseif (!eregi("^([[:alnum:]-]|[\_])*$", $parts['pass'], $regs)) { + return false; + } elseif (!eregi("^[[:alnum:]/_\.@~-]*$", $parts['path'], $regs)) { + return false; + } elseif (!eregi("^[[:alnum:]?&=+:;_()%#/,\.-]*$", $parts['query'], $regs)) { + return false; + } else { + return true; + } + } + return false; + } + + function ID3v2ShortFrameNameLookup($majorversion, $long_description) { + $long_description = str_replace(' ', '_', strtolower(trim($long_description))); + static $ID3v2ShortFrameNameLookup = array(); + if (empty($ID3v2ShortFrameNameLookup)) { + + // The following are unique to ID3v2.2 + $ID3v2ShortFrameNameLookup[2]['comment'] = 'COM'; + $ID3v2ShortFrameNameLookup[2]['album'] = 'TAL'; + $ID3v2ShortFrameNameLookup[2]['beats_per_minute'] = 'TBP'; + $ID3v2ShortFrameNameLookup[2]['composer'] = 'TCM'; + $ID3v2ShortFrameNameLookup[2]['genre'] = 'TCO'; + $ID3v2ShortFrameNameLookup[2]['copyright'] = 'TCR'; + $ID3v2ShortFrameNameLookup[2]['encoded_by'] = 'TEN'; + $ID3v2ShortFrameNameLookup[2]['language'] = 'TLA'; + $ID3v2ShortFrameNameLookup[2]['length'] = 'TLE'; + $ID3v2ShortFrameNameLookup[2]['original_artist'] = 'TOA'; + $ID3v2ShortFrameNameLookup[2]['original_filename'] = 'TOF'; + $ID3v2ShortFrameNameLookup[2]['original_lyricist'] = 'TOL'; + $ID3v2ShortFrameNameLookup[2]['original_album_title'] = 'TOT'; + $ID3v2ShortFrameNameLookup[2]['artist'] = 'TP1'; + $ID3v2ShortFrameNameLookup[2]['band'] = 'TP2'; + $ID3v2ShortFrameNameLookup[2]['conductor'] = 'TP3'; + $ID3v2ShortFrameNameLookup[2]['remixer'] = 'TP4'; + $ID3v2ShortFrameNameLookup[2]['publisher'] = 'TPB'; + $ID3v2ShortFrameNameLookup[2]['isrc'] = 'TRC'; + $ID3v2ShortFrameNameLookup[2]['tracknumber'] = 'TRK'; + $ID3v2ShortFrameNameLookup[2]['size'] = 'TSI'; + $ID3v2ShortFrameNameLookup[2]['encoder_settings'] = 'TSS'; + $ID3v2ShortFrameNameLookup[2]['description'] = 'TT1'; + $ID3v2ShortFrameNameLookup[2]['title'] = 'TT2'; + $ID3v2ShortFrameNameLookup[2]['subtitle'] = 'TT3'; + $ID3v2ShortFrameNameLookup[2]['lyricist'] = 'TXT'; + $ID3v2ShortFrameNameLookup[2]['user_text'] = 'TXX'; + $ID3v2ShortFrameNameLookup[2]['year'] = 'TYE'; + $ID3v2ShortFrameNameLookup[2]['unique_file_identifier'] = 'UFI'; + $ID3v2ShortFrameNameLookup[2]['unsynchronised_lyrics'] = 'ULT'; + $ID3v2ShortFrameNameLookup[2]['url_file'] = 'WAF'; + $ID3v2ShortFrameNameLookup[2]['url_artist'] = 'WAR'; + $ID3v2ShortFrameNameLookup[2]['url_source'] = 'WAS'; + $ID3v2ShortFrameNameLookup[2]['copyright_information'] = 'WCP'; + $ID3v2ShortFrameNameLookup[2]['url_publisher'] = 'WPB'; + $ID3v2ShortFrameNameLookup[2]['url_user'] = 'WXX'; + + // The following are common to ID3v2.3 and ID3v2.4 + $ID3v2ShortFrameNameLookup[3]['audio_encryption'] = 'AENC'; + $ID3v2ShortFrameNameLookup[3]['attached_picture'] = 'APIC'; + $ID3v2ShortFrameNameLookup[3]['comment'] = 'COMM'; + $ID3v2ShortFrameNameLookup[3]['commercial'] = 'COMR'; + $ID3v2ShortFrameNameLookup[3]['encryption_method_registration'] = 'ENCR'; + $ID3v2ShortFrameNameLookup[3]['event_timing_codes'] = 'ETCO'; + $ID3v2ShortFrameNameLookup[3]['general_encapsulated_object'] = 'GEOB'; + $ID3v2ShortFrameNameLookup[3]['group_identification_registration'] = 'GRID'; + $ID3v2ShortFrameNameLookup[3]['linked_information'] = 'LINK'; + $ID3v2ShortFrameNameLookup[3]['music_cd_identifier'] = 'MCDI'; + $ID3v2ShortFrameNameLookup[3]['mpeg_location_lookup_table'] = 'MLLT'; + $ID3v2ShortFrameNameLookup[3]['ownership'] = 'OWNE'; + $ID3v2ShortFrameNameLookup[3]['play_counter'] = 'PCNT'; + $ID3v2ShortFrameNameLookup[3]['popularimeter'] = 'POPM'; + $ID3v2ShortFrameNameLookup[3]['position_synchronisation'] = 'POSS'; + $ID3v2ShortFrameNameLookup[3]['private'] = 'PRIV'; + $ID3v2ShortFrameNameLookup[3]['recommended_buffer_size'] = 'RBUF'; + $ID3v2ShortFrameNameLookup[3]['reverb'] = 'RVRB'; + $ID3v2ShortFrameNameLookup[3]['synchronised_lyrics'] = 'SYLT'; + $ID3v2ShortFrameNameLookup[3]['synchronised_tempo_codes'] = 'SYTC'; + $ID3v2ShortFrameNameLookup[3]['album'] = 'TALB'; + $ID3v2ShortFrameNameLookup[3]['beats_per_minute'] = 'TBPM'; + $ID3v2ShortFrameNameLookup[3]['composer'] = 'TCOM'; + $ID3v2ShortFrameNameLookup[3]['genre'] = 'TCON'; + $ID3v2ShortFrameNameLookup[3]['copyright'] = 'TCOP'; + $ID3v2ShortFrameNameLookup[3]['playlist_delay'] = 'TDLY'; + $ID3v2ShortFrameNameLookup[3]['encoded_by'] = 'TENC'; + $ID3v2ShortFrameNameLookup[3]['lyricist'] = 'TEXT'; + $ID3v2ShortFrameNameLookup[3]['file_type'] = 'TFLT'; + $ID3v2ShortFrameNameLookup[3]['content_group_description'] = 'TIT1'; + $ID3v2ShortFrameNameLookup[3]['title'] = 'TIT2'; + $ID3v2ShortFrameNameLookup[3]['subtitle'] = 'TIT3'; + $ID3v2ShortFrameNameLookup[3]['initial_key'] = 'TKEY'; + $ID3v2ShortFrameNameLookup[3]['language'] = 'TLAN'; + $ID3v2ShortFrameNameLookup[3]['length'] = 'TLEN'; + $ID3v2ShortFrameNameLookup[3]['media_type'] = 'TMED'; + $ID3v2ShortFrameNameLookup[3]['original_album_title'] = 'TOAL'; + $ID3v2ShortFrameNameLookup[3]['original_filename'] = 'TOFN'; + $ID3v2ShortFrameNameLookup[3]['original_lyricist'] = 'TOLY'; + $ID3v2ShortFrameNameLookup[3]['original_artist'] = 'TOPE'; + $ID3v2ShortFrameNameLookup[3]['file_owner'] = 'TOWN'; + $ID3v2ShortFrameNameLookup[3]['artist'] = 'TPE1'; + $ID3v2ShortFrameNameLookup[3]['band'] = 'TPE2'; + $ID3v2ShortFrameNameLookup[3]['conductor'] = 'TPE3'; + $ID3v2ShortFrameNameLookup[3]['remixer'] = 'TPE4'; + $ID3v2ShortFrameNameLookup[3]['part_of_set'] = 'TPOS'; + $ID3v2ShortFrameNameLookup[3]['publisher'] = 'TPUB'; + $ID3v2ShortFrameNameLookup[3]['tracknumber'] = 'TRCK'; + $ID3v2ShortFrameNameLookup[3]['internet_radio_station_name'] = 'TRSN'; + $ID3v2ShortFrameNameLookup[3]['internet_radio_station_owner'] = 'TRSO'; + $ID3v2ShortFrameNameLookup[3]['isrc'] = 'TSRC'; + $ID3v2ShortFrameNameLookup[3]['encoder_settings'] = 'TSSE'; + $ID3v2ShortFrameNameLookup[3]['user_text'] = 'TXXX'; + $ID3v2ShortFrameNameLookup[3]['unique_file_identifier'] = 'UFID'; + $ID3v2ShortFrameNameLookup[3]['terms_of_use'] = 'USER'; + $ID3v2ShortFrameNameLookup[3]['unsynchronised_lyrics'] = 'USLT'; + $ID3v2ShortFrameNameLookup[3]['commercial'] = 'WCOM'; + $ID3v2ShortFrameNameLookup[3]['copyright_information'] = 'WCOP'; + $ID3v2ShortFrameNameLookup[3]['url_file'] = 'WOAF'; + $ID3v2ShortFrameNameLookup[3]['url_artist'] = 'WOAR'; + $ID3v2ShortFrameNameLookup[3]['url_source'] = 'WOAS'; + $ID3v2ShortFrameNameLookup[3]['url_station'] = 'WORS'; + $ID3v2ShortFrameNameLookup[3]['payment'] = 'WPAY'; + $ID3v2ShortFrameNameLookup[3]['url_publisher'] = 'WPUB'; + $ID3v2ShortFrameNameLookup[3]['url_user'] = 'WXXX'; + + // The above are common to ID3v2.3 and ID3v2.4 + // so copy them to ID3v2.4 before adding specifics for 2.3 and 2.4 + $ID3v2ShortFrameNameLookup[4] = $ID3v2ShortFrameNameLookup[3]; + + // The following are unique to ID3v2.3 + $ID3v2ShortFrameNameLookup[3]['equalisation'] = 'EQUA'; + $ID3v2ShortFrameNameLookup[3]['involved_people_list'] = 'IPLS'; + $ID3v2ShortFrameNameLookup[3]['relative_volume_adjustment'] = 'RVAD'; + $ID3v2ShortFrameNameLookup[3]['date'] = 'TDAT'; + $ID3v2ShortFrameNameLookup[3]['time'] = 'TIME'; + $ID3v2ShortFrameNameLookup[3]['original_release_year'] = 'TORY'; + $ID3v2ShortFrameNameLookup[3]['recording_dates'] = 'TRDA'; + $ID3v2ShortFrameNameLookup[3]['size'] = 'TSIZ'; + $ID3v2ShortFrameNameLookup[3]['year'] = 'TYER'; + + + // The following are unique to ID3v2.4 + $ID3v2ShortFrameNameLookup[4]['audio_seek_point_index'] = 'ASPI'; + $ID3v2ShortFrameNameLookup[4]['equalisation'] = 'EQU2'; + $ID3v2ShortFrameNameLookup[4]['relative_volume_adjustment'] = 'RVA2'; + $ID3v2ShortFrameNameLookup[4]['seek'] = 'SEEK'; + $ID3v2ShortFrameNameLookup[4]['signature'] = 'SIGN'; + $ID3v2ShortFrameNameLookup[4]['encoding_time'] = 'TDEN'; + $ID3v2ShortFrameNameLookup[4]['original_release_time'] = 'TDOR'; + $ID3v2ShortFrameNameLookup[4]['recording_time'] = 'TDRC'; + $ID3v2ShortFrameNameLookup[4]['release_time'] = 'TDRL'; + $ID3v2ShortFrameNameLookup[4]['tagging_time'] = 'TDTG'; + $ID3v2ShortFrameNameLookup[4]['involved_people_list'] = 'TIPL'; + $ID3v2ShortFrameNameLookup[4]['musician_credits_list'] = 'TMCL'; + $ID3v2ShortFrameNameLookup[4]['mood'] = 'TMOO'; + $ID3v2ShortFrameNameLookup[4]['produced_notice'] = 'TPRO'; + $ID3v2ShortFrameNameLookup[4]['album_sort_order'] = 'TSOA'; + $ID3v2ShortFrameNameLookup[4]['performer_sort_order'] = 'TSOP'; + $ID3v2ShortFrameNameLookup[4]['title_sort_order'] = 'TSOT'; + $ID3v2ShortFrameNameLookup[4]['set_subtitle'] = 'TSST'; + } + return @$ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)]; + + } + +} + +?> diff --git a/plugins/getId3Plugin/lib/write.lyrics3.php b/plugins/getId3Plugin/lib/write.lyrics3.php new file mode 100644 index 0000000..6b8a47d --- /dev/null +++ b/plugins/getId3Plugin/lib/write.lyrics3.php @@ -0,0 +1,78 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.lyrics3.php // +// module for writing Lyrics3 tags // +// dependencies: module.tag.lyrics3.php // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_write_lyrics3 +{ + var $filename; + var $tag_data; + //var $lyrics3_version = 2; // 1 or 2 + var $warnings = array(); // any non-critical errors will be stored here + var $errors = array(); // any critical errors will be stored here + + function getid3_write_lyrics3() { + return true; + } + + function WriteLyrics3() { + $this->errors[] = 'WriteLyrics3() not yet functional - cannot write Lyrics3'; + return false; + } + + function DeleteLyrics3() { + // Initialize getID3 engine + $getID3 = new getID3; + $ThisFileInfo = $getID3->analyze($this->filename); + if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { + if ($fp = @fopen($this->filename, 'a+b')) { + + flock($fp, LOCK_EX); + $oldignoreuserabort = ignore_user_abort(true); + + fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_end'], SEEK_SET); + $DataAfterLyrics3 = ''; + if ($ThisFileInfo['filesize'] > $ThisFileInfo['lyrics3']['tag_offset_end']) { + $DataAfterLyrics3 = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['lyrics3']['tag_offset_end']); + } + + ftruncate($fp, $ThisFileInfo['lyrics3']['tag_offset_start']); + + if (!empty($DataAfterLyrics3)) { + fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_start'], SEEK_SET); + fwrite($fp, $DataAfterLyrics3, strlen($DataAfterLyrics3)); + } + + flock($fp, LOCK_UN); + fclose($fp); + ignore_user_abort($oldignoreuserabort); + + return true; + + } else { + + $this->errors[] = 'Cannot open "'.$this->filename.'" in "a+b" mode'; + return false; + + } + } + // no Lyrics3 present + return true; + } + + + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/write.metaflac.php b/plugins/getId3Plugin/lib/write.metaflac.php new file mode 100644 index 0000000..c5acc8c --- /dev/null +++ b/plugins/getId3Plugin/lib/write.metaflac.php @@ -0,0 +1,167 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.metaflac.php // +// module for writing metaflac tags // +// dependencies: /helperapps/metaflac.exe // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_write_metaflac +{ + + var $filename; + var $tag_data; + var $warnings = array(); // any non-critical errors will be stored here + var $errors = array(); // any critical errors will be stored here + + function getid3_write_metaflac() { + return true; + } + + function WriteMetaFLAC() { + + if (!ini_get('safe_mode')) { + + // Create file with new comments + $tempcommentsfilename = tempnam('*', 'getID3'); + if ($fpcomments = @fopen($tempcommentsfilename, 'wb')) { + + foreach ($this->tag_data as $key => $value) { + foreach ($value as $commentdata) { + fwrite($fpcomments, $this->CleanmetaflacName($key).'='.$commentdata."\n"); + } + } + fclose($fpcomments); + + } else { + + $this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written'; + return false; + + } + + $oldignoreuserabort = ignore_user_abort(true); + if (GETID3_OS_ISWINDOWS) { + + if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) { + //$commandline = '"'.GETID3_HELPERAPPSDIR.'metaflac.exe" --no-utf8-convert --remove-vc-all --import-vc-from="'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; + // metaflac works fine if you copy-paste the above commandline into a command prompt, + // but refuses to work with `backtick` if there are "doublequotes" present around BOTH + // the metaflac pathname and the target filename. For whatever reason...?? + // The solution is simply ensure that the metaflac pathname has no spaces, + // and therefore does not need to be quoted + + // On top of that, if error messages are not always captured properly under Windows + // To at least see if there was a problem, compare file modification timestamps before and after writing + clearstatcache(); + $timestampbeforewriting = filemtime($this->filename); + + $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --no-utf8-convert --remove-vc-all --import-vc-from="'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; + $metaflacError = `$commandline`; + + if (empty($metaflacError)) { + clearstatcache(); + if ($timestampbeforewriting == filemtime($this->filename)) { + $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written'; + } + } + } else { + $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR; + } + + } else { + + // It's simpler on *nix + $commandline = 'metaflac --no-utf8-convert --remove-vc-all --import-vc-from='.$tempcommentsfilename.' "'.$this->filename.'" 2>&1'; + $metaflacError = `$commandline`; + + } + + // Remove temporary comments file + unlink($tempcommentsfilename); + ignore_user_abort($oldignoreuserabort); + + if (!empty($metaflacError)) { + + $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError; + return false; + + } + + return true; + } + + $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not written'; + return false; + } + + + function DeleteMetaFLAC() { + + if (!ini_get('safe_mode')) { + + $oldignoreuserabort = ignore_user_abort(true); + if (GETID3_OS_ISWINDOWS) { + + if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) { + // To at least see if there was a problem, compare file modification timestamps before and after writing + clearstatcache(); + $timestampbeforewriting = filemtime($this->filename); + + $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-vc-all "'.$this->filename.'" 2>&1'; + $metaflacError = `$commandline`; + + if (empty($metaflacError)) { + clearstatcache(); + if ($timestampbeforewriting == filemtime($this->filename)) { + $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted'; + } + } + } else { + $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR; + } + + } else { + + // It's simpler on *nix + $commandline = 'metaflac --remove-vc-all "'.$this->filename.'" 2>&1'; + $metaflacError = `$commandline`; + + } + + ignore_user_abort($oldignoreuserabort); + + if (!empty($metaflacError)) { + $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError; + return false; + } + return true; + } + $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted'; + return false; + } + + + function CleanmetaflacName($originalcommentname) { + // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. + // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through + // 0x7A inclusive (a-z). + + // replace invalid chars with a space, return uppercase text + // Thanks Chris Bolt for improving this function + // note: ereg_replace() replaces nulls with empty string (not space) + return strtoupper(ereg_replace('[^ -<>-}]', ' ', str_replace("\x00", ' ', $originalcommentname))); + + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/write.php b/plugins/getId3Plugin/lib/write.php new file mode 100644 index 0000000..73e2610 --- /dev/null +++ b/plugins/getId3Plugin/lib/write.php @@ -0,0 +1,592 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +/// // +// write.php // +// module for writing tags (APEv2, ID3v1, ID3v2) // +// dependencies: getid3.lib.php // +// write.apetag.php (optional) // +// write.id3v1.php (optional) // +// write.id3v2.php (optional) // +// write.vorbiscomment.php (optional) // +// write.metaflac.php (optional) // +// write.lyrics3.php (optional) // +// /// +///////////////////////////////////////////////////////////////// + +if (!defined('GETID3_INCLUDEPATH')) { + die('getid3.php MUST be included before calling getid3_writetags'); +} +if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { + die('write.php depends on getid3.lib.php, which is missing.'); +} + + +// NOTES: +// +// You should pass data here with standard field names as follows: +// * TITLE +// * ARTIST +// * ALBUM +// * TRACKNUMBER +// * COMMENT +// * GENRE +// * YEAR +// * ATTACHED_PICTURE (ID3v2 only) +// +// http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html +// The APEv2 Tag Items Keys definition says "TRACK" is correct but foobar2000 uses "TRACKNUMBER" instead +// Pass data here as "TRACKNUMBER" for compatability with all formats + + +class getid3_writetags +{ + // public + var $filename; // absolute filename of file to write tags to + var $tagformats = array(); // array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment', 'metaflac', 'real') + var $tag_data = array(array()); // 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis') + var $tag_encoding = 'ISO-8859-1'; // text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', ) + var $overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data + var $remove_other_tags = false; // if true will erase remove all existing tags and only write those passed in $tagformats; if false will ignore any tags not mentioned in $tagformats + + var $id3v2_tag_language = 'eng'; // ISO-639-2 3-character language code needed for some ID3v2 frames (http://www.id3.org/iso639-2.html) + var $id3v2_paddedlength = 4096; // minimum length of ID3v2 tags (will be padded to this length if tag data is shorter) + + var $warnings = array(); // any non-critical errors will be stored here + var $errors = array(); // any critical errors will be stored here + + // private + var $ThisFileInfo; // analysis of file before writing + + function getid3_writetags() { + return true; + } + + + function WriteTags() { + + if (empty($this->filename)) { + $this->errors[] = 'filename is undefined in getid3_writetags'; + return false; + } elseif (!file_exists($this->filename)) { + $this->errors[] = 'filename set to non-existant file "'.$this->filename.'" in getid3_writetags'; + return false; + } + + if (!is_array($this->tagformats)) { + $this->errors[] = 'tagformats must be an array in getid3_writetags'; + return false; + } + + $TagFormatsToRemove = array(); + if (filesize($this->filename) == 0) { + + // empty file special case - allow any tag format, don't check existing format + // could be useful if you want to generate tag data for a non-existant file + $this->ThisFileInfo = array('fileformat'=>''); + $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'); + + } else { + + $getID3 = new getID3; + $getID3->encoding = $this->tag_encoding; + $this->ThisFileInfo = $getID3->analyze($this->filename); + + // check for what file types are allowed on this fileformat + switch (@$this->ThisFileInfo['fileformat']) { + case 'mp3': + case 'mp2': + case 'mp1': + case 'riff': // maybe not officially, but people do it anyway + $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'); + break; + + case 'mpc': + $AllowedTagFormats = array('ape'); + break; + + case 'flac': + $AllowedTagFormats = array('metaflac'); + break; + + case 'real': + $AllowedTagFormats = array('real'); + break; + + case 'ogg': + switch (@$this->ThisFileInfo['audio']['dataformat']) { + case 'flac': + //$AllowedTagFormats = array('metaflac'); + $this->errors[] = 'metaflac is not (yet) compatible with OggFLAC files'; + return false; + break; + case 'vorbis': + $AllowedTagFormats = array('vorbiscomment'); + break; + default: + $this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis'; + return false; + break; + } + break; + + default: + $AllowedTagFormats = array(); + break; + } + foreach ($this->tagformats as $requested_tag_format) { + if (!in_array($requested_tag_format, $AllowedTagFormats)) { + $errormessage = 'Tag format "'.$requested_tag_format.'" is not allowed on "'.@$this->ThisFileInfo['fileformat']; + if (@$this->ThisFileInfo['fileformat'] != @$this->ThisFileInfo['audio']['dataformat']) { + $errormessage .= '.'.@$this->ThisFileInfo['audio']['dataformat']; + } + $errormessage .= '" files'; + $this->errors[] = $errormessage; + return false; + } + } + + // List of other tag formats, removed if requested + if ($this->remove_other_tags) { + foreach ($AllowedTagFormats as $AllowedTagFormat) { + switch ($AllowedTagFormat) { + case 'id3v2.2': + case 'id3v2.3': + case 'id3v2.4': + if (!in_array('id3v2', $TagFormatsToRemove) && !in_array('id3v2.2', $this->tagformats) && !in_array('id3v2.3', $this->tagformats) && !in_array('id3v2.4', $this->tagformats)) { + $TagFormatsToRemove[] = 'id3v2'; + } + break; + + default: + if (!in_array($AllowedTagFormat, $this->tagformats)) { + $TagFormatsToRemove[] = $AllowedTagFormat; + } + break; + } + } + } + } + + $WritingFilesToInclude = array_merge($this->tagformats, $TagFormatsToRemove); + + // Check for required include files and include them + foreach ($WritingFilesToInclude as $tagformat) { + switch ($tagformat) { + case 'ape': + $GETID3_ERRORARRAY = &$this->errors; + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.apetag.php', __FILE__, false)) { + return false; + } + break; + + case 'id3v1': + case 'lyrics3': + case 'vorbiscomment': + case 'metaflac': + case 'real': + $GETID3_ERRORARRAY = &$this->errors; + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.'.$tagformat.'.php', __FILE__, false)) { + return false; + } + break; + + case 'id3v2.2': + case 'id3v2.3': + case 'id3v2.4': + case 'id3v2': + $GETID3_ERRORARRAY = &$this->errors; + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.id3v2.php', __FILE__, false)) { + return false; + } + break; + + default: + $this->errors[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()'; + return false; + break; + } + + } + + // Validation of supplied data + if (!is_array($this->tag_data)) { + $this->errors[] = '$tag_data is not an array in WriteTags()'; + return false; + } + // convert supplied data array keys to upper case, if they're not already + foreach ($this->tag_data as $tag_key => $tag_array) { + if (strtoupper($tag_key) !== $tag_key) { + $this->tag_data[strtoupper($tag_key)] = $this->tag_data[$tag_key]; + unset($this->tag_data[$tag_key]); + } + } + // convert source data array keys to upper case, if they're not already + if (!empty($this->ThisFileInfo['tags'])) { + foreach ($this->ThisFileInfo['tags'] as $tag_format => $tag_data_array) { + foreach ($tag_data_array as $tag_key => $tag_array) { + if (strtoupper($tag_key) !== $tag_key) { + $this->ThisFileInfo['tags'][$tag_format][strtoupper($tag_key)] = $this->ThisFileInfo['tags'][$tag_format][$tag_key]; + unset($this->ThisFileInfo['tags'][$tag_format][$tag_key]); + } + } + } + } + + // Convert "TRACK" to "TRACKNUMBER" (if needed) for compatability with all formats + if (isset($this->tag_data['TRACK']) && !isset($this->tag_data['TRACKNUMBER'])) { + $this->tag_data['TRACKNUMBER'] = $this->tag_data['TRACK']; + unset($this->tag_data['TRACK']); + } + + // Remove all other tag formats, if requested + if ($this->remove_other_tags) { + $this->DeleteTags($TagFormatsToRemove); + } + + // Write data for each tag format + foreach ($this->tagformats as $tagformat) { + $success = false; // overridden if tag writing is successful + switch ($tagformat) { + case 'ape': + $ape_writer = new getid3_write_apetag; + if (($ape_writer->tag_data = $this->FormatDataForAPE()) !== false) { + $ape_writer->filename = $this->filename; + if (($success = $ape_writer->WriteAPEtag()) === false) { + $this->errors[] = 'WriteAPEtag() failed with message(s):
    • '.trim(implode('
    • ', $ape_writer->errors)).'
    '; + } + } else { + $this->errors[] = 'FormatDataForAPE() failed'; + } + break; + + case 'id3v1': + $id3v1_writer = new getid3_write_id3v1; + if (($id3v1_writer->tag_data = $this->FormatDataForID3v1()) !== false) { + $id3v1_writer->filename = $this->filename; + if (($success = $id3v1_writer->WriteID3v1()) === false) { + $this->errors[] = 'WriteID3v1() failed with message(s):
    • '.trim(implode('
    • ', $id3v1_writer->errors)).'
    '; + } + } else { + $this->errors[] = 'FormatDataForID3v1() failed'; + } + break; + + case 'id3v2.2': + case 'id3v2.3': + case 'id3v2.4': + $id3v2_writer = new getid3_write_id3v2; + $id3v2_writer->majorversion = intval(substr($tagformat, -1)); + $id3v2_writer->paddedlength = $this->id3v2_paddedlength; + if (($id3v2_writer->tag_data = $this->FormatDataForID3v2($id3v2_writer->majorversion)) !== false) { + $id3v2_writer->filename = $this->filename; + if (($success = $id3v2_writer->WriteID3v2()) === false) { + $this->errors[] = 'WriteID3v2() failed with message(s):
    • '.trim(implode('
    • ', $id3v2_writer->errors)).'
    '; + } + } else { + $this->errors[] = 'FormatDataForID3v2() failed'; + } + break; + + case 'vorbiscomment': + $vorbiscomment_writer = new getid3_write_vorbiscomment; + if (($vorbiscomment_writer->tag_data = $this->FormatDataForVorbisComment()) !== false) { + $vorbiscomment_writer->filename = $this->filename; + if (($success = $vorbiscomment_writer->WriteVorbisComment()) === false) { + $this->errors[] = 'WriteVorbisComment() failed with message(s):
    • '.trim(implode('
    • ', $vorbiscomment_writer->errors)).'
    '; + } + } else { + $this->errors[] = 'FormatDataForVorbisComment() failed'; + } + break; + + case 'metaflac': + $metaflac_writer = new getid3_write_metaflac; + if (($metaflac_writer->tag_data = $this->FormatDataForMetaFLAC()) !== false) { + $metaflac_writer->filename = $this->filename; + if (($success = $metaflac_writer->WriteMetaFLAC()) === false) { + $this->errors[] = 'WriteMetaFLAC() failed with message(s):
    • '.trim(implode('
    • ', $metaflac_writer->errors)).'
    '; + } + } else { + $this->errors[] = 'FormatDataForMetaFLAC() failed'; + } + break; + + case 'real': + $real_writer = new getid3_write_real; + if (($real_writer->tag_data = $this->FormatDataForReal()) !== false) { + $real_writer->filename = $this->filename; + if (($success = $real_writer->WriteReal()) === false) { + $this->errors[] = 'WriteReal() failed with message(s):
    • '.trim(implode('
    • ', $real_writer->errors)).'
    '; + } + } else { + $this->errors[] = 'FormatDataForReal() failed'; + } + break; + + default: + $this->errors[] = 'Invalid tag format to write: "'.$tagformat.'"'; + return false; + break; + } + if (!$success) { + return false; + } + } + return true; + + } + + + function DeleteTags($TagFormatsToDelete) { + foreach ($TagFormatsToDelete as $DeleteTagFormat) { + $success = false; // overridden if tag deletion is successful + switch ($DeleteTagFormat) { + case 'id3v1': + $id3v1_writer = new getid3_write_id3v1; + $id3v1_writer->filename = $this->filename; + if (($success = $id3v1_writer->RemoveID3v1()) === false) { + $this->errors[] = 'RemoveID3v1() failed with message(s):
    • '.trim(implode('
    • ', $id3v1_writer->errors)).'
    '; + } + break; + + case 'id3v2': + $id3v2_writer = new getid3_write_id3v2; + $id3v2_writer->filename = $this->filename; + if (($success = $id3v2_writer->RemoveID3v2()) === false) { + $this->errors[] = 'RemoveID3v2() failed with message(s):
    • '.trim(implode('
    • ', $id3v2_writer->errors)).'
    '; + } + break; + + case 'ape': + $ape_writer = new getid3_write_apetag; + $ape_writer->filename = $this->filename; + if (($success = $ape_writer->DeleteAPEtag()) === false) { + $this->errors[] = 'DeleteAPEtag() failed with message(s):
    • '.trim(implode('
    • ', $ape_writer->errors)).'
    '; + } + break; + + case 'vorbiscomment': + $vorbiscomment_writer = new getid3_write_vorbiscomment; + $vorbiscomment_writer->filename = $this->filename; + if (($success = $vorbiscomment_writer->DeleteVorbisComment()) === false) { + $this->errors[] = 'DeleteVorbisComment() failed with message(s):
    • '.trim(implode('
    • ', $vorbiscomment_writer->errors)).'
    '; + } + break; + + case 'metaflac': + $metaflac_writer = new getid3_write_metaflac; + $metaflac_writer->filename = $this->filename; + if (($success = $metaflac_writer->DeleteMetaFLAC()) === false) { + $this->errors[] = 'DeleteMetaFLAC() failed with message(s):
    • '.trim(implode('
    • ', $metaflac_writer->errors)).'
    '; + } + break; + + case 'lyrics3': + $lyrics3_writer = new getid3_write_lyrics3; + $lyrics3_writer->filename = $this->filename; + if (($success = $lyrics3_writer->DeleteLyrics3()) === false) { + $this->errors[] = 'DeleteLyrics3() failed with message(s):
    • '.trim(implode('
    • ', $lyrics3_writer->errors)).'
    '; + } + break; + + case 'real': + $real_writer = new getid3_write_real; + $real_writer->filename = $this->filename; + if (($success = $real_writer->RemoveReal()) === false) { + $this->errors[] = 'RemoveReal() failed with message(s):
    • '.trim(implode('
    • ', $real_writer->errors)).'
    '; + } + break; + + default: + $this->errors[] = 'Invalid tag format to delete: "'.$tagformat.'"'; + return false; + break; + } + if (!$success) { + return false; + } + } + return true; + } + + + function MergeExistingTagData($TagFormat, &$tag_data) { + // Merge supplied data with existing data, if requested + if ($this->overwrite_tags) { + // do nothing - ignore previous data + } else { + if (!isset($this->ThisFileInfo['tags'][$TagFormat])) { + return false; + } + $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]); + } + return true; + } + + function FormatDataForAPE() { + $ape_tag_data = array(); + foreach ($this->tag_data as $tag_key => $valuearray) { + switch ($tag_key) { + case 'ATTACHED_PICTURE': + // ATTACHED_PICTURE is ID3v2 only - ignore + $this->warnings[] = '$data['.$tag_key.'] is assumed to be ID3v2 APIC data - NOT written to APE tag'; + break; + + default: + foreach ($valuearray as $key => $value) { + if (is_string($value) || is_numeric($value)) { + $ape_tag_data[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); + } else { + $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to APE tag'; + unset($ape_tag_data[$tag_key]); + break; + } + } + break; + } + } + $this->MergeExistingTagData('ape', $ape_tag_data); + return $ape_tag_data; + } + + + function FormatDataForID3v1() { + $tag_data_id3v1['genreid'] = 255; + if (!empty($this->tag_data['GENRE'])) { + foreach ($this->tag_data['GENRE'] as $key => $value) { + if (getid3_id3v1::LookupGenreID($value) !== false) { + $tag_data_id3v1['genreid'] = getid3_id3v1::LookupGenreID($value); + break; + } + } + } + + $tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TITLE'])); + $tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ARTIST'])); + $tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ALBUM'])); + $tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['YEAR'])); + $tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COMMENT'])); + + $tag_data_id3v1['track'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TRACKNUMBER']))); + if ($tag_data_id3v1['track'] <= 0) { + $tag_data_id3v1['track'] = ''; + } + + $this->MergeExistingTagData('id3v1', $tag_data_id3v1); + return $tag_data_id3v1; + } + + function FormatDataForID3v2($id3v2_majorversion) { + $tag_data_id3v2 = array(); + + $ID3v2_text_encoding_lookup[2] = array('ISO-8859-1'=>0, 'UTF-16'=>1); + $ID3v2_text_encoding_lookup[3] = array('ISO-8859-1'=>0, 'UTF-16'=>1); + $ID3v2_text_encoding_lookup[4] = array('ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3); + foreach ($this->tag_data as $tag_key => $valuearray) { + $ID3v2_framename = getid3_write_id3v2::ID3v2ShortFrameNameLookup($id3v2_majorversion, $tag_key); + switch ($ID3v2_framename) { + case 'APIC': + foreach ($valuearray as $key => $apic_data_array) { + if (isset($apic_data_array['data']) && + isset($apic_data_array['picturetypeid']) && + isset($apic_data_array['description']) && + isset($apic_data_array['mime'])) { + $tag_data_id3v2['APIC'][] = $apic_data_array; + } else { + $this->errors[] = 'ID3v2 APIC data is not properly structured'; + return false; + } + } + break; + + case '': + $this->errors[] = 'ID3v2: Skipping "'.$tag_key.'" because cannot match it to a known ID3v2 frame type'; + // some other data type, don't know how to handle it, ignore it + break; + + default: + // most other (text) frames can be copied over as-is + foreach ($valuearray as $key => $value) { + if (isset($ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding])) { + // source encoding is valid in ID3v2 - use it with no conversion + $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = $ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding]; + $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; + } else { + // source encoding is NOT valid in ID3v2 - convert it to an ID3v2-valid encoding first + if ($id3v2_majorversion < 4) { + // convert data from other encoding to UTF-16 + $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1; + $tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16', $value); + + } else { + // convert data from other encoding to UTF-8 + $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 3; + $tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); + } + } + + // These values are not needed for all frame types, but if they're not used no matter + $tag_data_id3v2[$ID3v2_framename][$key]['description'] = ''; + $tag_data_id3v2[$ID3v2_framename][$key]['language'] = $this->id3v2_tag_language; + } + break; + } + } + $this->MergeExistingTagData('id3v2', $tag_data_id3v2); + return $tag_data_id3v2; + } + + function FormatDataForVorbisComment() { + $tag_data_vorbiscomment = $this->tag_data; + + // check for multi-line comment values - split out to multiple comments if neccesary + // and convert data to UTF-8 strings + foreach ($tag_data_vorbiscomment as $tag_key => $valuearray) { + foreach ($valuearray as $key => $value) { + str_replace("\r", "\n", $value); + if (strstr($value, "\n")) { + unset($tag_data_vorbiscomment[$tag_key][$key]); + $multilineexploded = explode("\n", $value); + foreach ($multilineexploded as $newcomment) { + if (strlen(trim($newcomment)) > 0) { + $tag_data_vorbiscomment[$tag_key][] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $newcomment); + } + } + } elseif (is_string($value) || is_numeric($value)) { + $tag_data_vorbiscomment[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); + } else { + $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to VorbisComment tag'; + unset($tag_data_vorbiscomment[$tag_key]); + break; + } + } + } + $this->MergeExistingTagData('vorbiscomment', $tag_data_vorbiscomment); + return $tag_data_vorbiscomment; + } + + function FormatDataForMetaFLAC() { + // FLAC & OggFLAC use VorbisComments same as OggVorbis + // but require metaflac to do the writing rather than vorbiscomment + return $this->FormatDataForVorbisComment(); + } + + function FormatDataForReal() { + $tag_data_real['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['TITLE'])); + $tag_data_real['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['ARTIST'])); + $tag_data_real['copyright'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COPYRIGHT'])); + $tag_data_real['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', @implode(' ', @$this->tag_data['COMMENT'])); + + $this->MergeExistingTagData('real', $tag_data_real); + return $tag_data_real; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/write.real.php b/plugins/getId3Plugin/lib/write.real.php new file mode 100644 index 0000000..1e0240c --- /dev/null +++ b/plugins/getId3Plugin/lib/write.real.php @@ -0,0 +1,295 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.real.php // +// module for writing RealAudio/RealVideo tags // +// dependencies: module.tag.real.php // +// /// +///////////////////////////////////////////////////////////////// + +class getid3_write_real +{ + var $filename; + var $tag_data = array(); + var $warnings = array(); // any non-critical errors will be stored here + var $errors = array(); // any critical errors will be stored here + var $paddedlength = 512; // minimum length of CONT tag in bytes + + function getid3_write_real() { + return true; + } + + function WriteReal() { + // File MUST be writeable - CHMOD(646) at least + if (is_writeable($this->filename)) { + if ($fp_source = @fopen($this->filename, 'r+b')) { + + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) { + $this->errors[] = 'Cannot write Real tags on old-style file format'; + fclose($fp_source); + return false; + } + + if (empty($OldThisFileInfo['real']['chunks'])) { + $this->errors[] = 'Cannot write Real tags because cannot find DATA chunk in file'; + fclose($fp_source); + return false; + } + foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) { + $oldChunkInfo[$chunkarray['name']] = $chunkarray; + } + if (!empty($oldChunkInfo['CONT']['length'])) { + $this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength); + } + + $new_CONT_tag_data = $this->GenerateCONTchunk(); + $new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data); + $new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']); + + if (@$oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data)) { + fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET); + fwrite($fp_source, $new__RMF_tag_data); + } else { + $this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)'; + fclose($fp_source); + return false; + } + + if (@$oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data)) { + fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET); + fwrite($fp_source, $new_PROP_tag_data); + } else { + $this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)'; + fclose($fp_source); + return false; + } + + if (@$oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data)) { + + // new data length is same as old data length - just overwrite + fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET); + fwrite($fp_source, $new_CONT_tag_data); + fclose($fp_source); + return true; + + } else { + + if (empty($oldChunkInfo['CONT'])) { + // no existing CONT chunk + $BeforeOffset = $oldChunkInfo['DATA']['offset']; + $AfterOffset = $oldChunkInfo['DATA']['offset']; + } else { + // new data is longer than old data + $BeforeOffset = $oldChunkInfo['CONT']['offset']; + $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length']; + } + if ($tempfilename = tempnam('*', 'getID3')) { + ob_start(); + if ($fp_temp = fopen($tempfilename, 'wb')) { + + rewind($fp_source); + fwrite($fp_temp, fread($fp_source, $BeforeOffset)); + fwrite($fp_temp, $new_CONT_tag_data); + fseek($fp_source, $AfterOffset, SEEK_SET); + while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_temp); + + if (copy($tempfilename, $this->filename)) { + unlink($tempfilename); + fclose($fp_source); + return true; + } + unlink($tempfilename); + $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents()); + + } else { + + $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents()); + + } + ob_end_clean(); + } + fclose($fp_source); + return false; + + } + + + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"'; + return false; + } + } + $this->errors[] = 'File is not writeable: '.$this->filename; + return false; + } + + function GenerateRMFchunk(&$chunks) { + $oldCONTexists = false; + foreach ($chunks as $key => $chunk) { + $chunkNameKeys[$chunk['name']] = $key; + if ($chunk['name'] == 'CONT') { + $oldCONTexists = true; + } + } + $newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1); + + $RMFchunk = "\x00\x00"; // object version + $RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4); + $RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4); + + $RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length + return $RMFchunk; + } + + function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) { + $old_CONT_length = 0; + $old_DATA_offset = 0; + $old_INDX_offset = 0; + foreach ($chunks as $key => $chunk) { + $chunkNameKeys[$chunk['name']] = $key; + if ($chunk['name'] == 'CONT') { + $old_CONT_length = $chunk['length']; + } elseif ($chunk['name'] == 'DATA') { + if (!$old_DATA_offset) { + $old_DATA_offset = $chunk['offset']; + } + } elseif ($chunk['name'] == 'INDX') { + if (!$old_INDX_offset) { + $old_INDX_offset = $chunk['offset']; + } + } + } + $CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length; + + $PROPchunk = "\x00\x00"; // object version + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4); + $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4); + $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2); + + $PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length + return $PROPchunk; + } + + function GenerateCONTchunk() { + foreach ($this->tag_data as $key => $value) { + // limit each value to 0xFFFF bytes + $this->tag_data[$key] = substr($value, 0, 65535); + } + + $CONTchunk = "\x00\x00"; // object version + + $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['title']), 2); + $CONTchunk .= @$this->tag_data['title']; + + $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['artist']), 2); + $CONTchunk .= @$this->tag_data['artist']; + + $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['copyright']), 2); + $CONTchunk .= @$this->tag_data['copyright']; + + $CONTchunk .= getid3_lib::BigEndian2String(strlen(@$this->tag_data['comment']), 2); + $CONTchunk .= @$this->tag_data['comment']; + + if ($this->paddedlength > (strlen($CONTchunk) + 8)) { + $CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8); + } + + $CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length + + return $CONTchunk; + } + + function RemoveReal() { + // File MUST be writeable - CHMOD(646) at least + if (is_writeable($this->filename)) { + if ($fp_source = @fopen($this->filename, 'r+b')) { + + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) { + $this->errors[] = 'Cannot remove Real tags from old-style file format'; + fclose($fp_source); + return false; + } + + if (empty($OldThisFileInfo['real']['chunks'])) { + $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file'; + fclose($fp_source); + return false; + } + foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) { + $oldChunkInfo[$chunkarray['name']] = $chunkarray; + } + + if (empty($oldChunkInfo['CONT'])) { + // no existing CONT chunk + fclose($fp_source); + return true; + } + + $BeforeOffset = $oldChunkInfo['CONT']['offset']; + $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length']; + if ($tempfilename = tempnam('*', 'getID3')) { + ob_start(); + if ($fp_temp = fopen($tempfilename, 'wb')) { + + rewind($fp_source); + fwrite($fp_temp, fread($fp_source, $BeforeOffset)); + fseek($fp_source, $AfterOffset, SEEK_SET); + while ($buffer = fread($fp_source, GETID3_FREAD_BUFFER_SIZE)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_temp); + + if (copy($tempfilename, $this->filename)) { + unlink($tempfilename); + fclose($fp_source); + return true; + } + unlink($tempfilename); + $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.') - '.strip_tags(ob_get_contents()); + + } else { + + $this->errors[] = 'Could not open '.$tempfilename.' mode "wb" - '.strip_tags(ob_get_contents()); + + } + ob_end_clean(); + } + fclose($fp_source); + return false; + + + } else { + $this->errors[] = 'Could not open '.$this->filename.' mode "r+b"'; + return false; + } + } + $this->errors[] = 'File is not writeable: '.$this->filename; + return false; + } + +} + +?> \ No newline at end of file diff --git a/plugins/getId3Plugin/lib/write.vorbiscomment.php b/plugins/getId3Plugin/lib/write.vorbiscomment.php new file mode 100644 index 0000000..f93b1a1 --- /dev/null +++ b/plugins/getId3Plugin/lib/write.vorbiscomment.php @@ -0,0 +1,124 @@ + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.vorbiscomment.php // +// module for writing VorbisComment tags // +// dependencies: /helperapps/vorbiscomment.exe // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_write_vorbiscomment +{ + + var $filename; + var $tag_data; + var $warnings = array(); // any non-critical errors will be stored here + var $errors = array(); // any critical errors will be stored here + + function getid3_write_vorbiscomment() { + return true; + } + + function WriteVorbisComment() { + + if (!ini_get('safe_mode')) { + + // Create file with new comments + $tempcommentsfilename = tempnam('*', 'getID3'); + if ($fpcomments = @fopen($tempcommentsfilename, 'wb')) { + + foreach ($this->tag_data as $key => $value) { + foreach ($value as $commentdata) { + fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n"); + } + } + fclose($fpcomments); + + } else { + + $this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written'; + return false; + + } + + $oldignoreuserabort = ignore_user_abort(true); + if (GETID3_OS_ISWINDOWS) { + + if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { + //$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; + // vorbiscomment works fine if you copy-paste the above commandline into a command prompt, + // but refuses to work with `backtick` if there are "doublequotes" present around BOTH + // the metaflac pathname and the target filename. For whatever reason...?? + // The solution is simply ensure that the metaflac pathname has no spaces, + // and therefore does not need to be quoted + + // On top of that, if error messages are not always captured properly under Windows + // To at least see if there was a problem, compare file modification timestamps before and after writing + clearstatcache(); + $timestampbeforewriting = filemtime($this->filename); + + $commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; + $VorbiscommentError = `$commandline`; + + if (empty($VorbiscommentError)) { + clearstatcache(); + if ($timestampbeforewriting == filemtime($this->filename)) { + $VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written'; + } + } + } else { + $VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; + } + + } else { + + $commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; + $VorbiscommentError = `$commandline`; + + } + + // Remove temporary comments file + unlink($tempcommentsfilename); + ignore_user_abort($oldignoreuserabort); + + if (!empty($VorbiscommentError)) { + + $this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError; + return false; + + } + + return true; + } + + $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written'; + return false; + } + + function DeleteVorbisComment() { + $this->tag_data = array(array()); + return $this->WriteVorbisComment(); + } + + function CleanVorbisCommentName($originalcommentname) { + // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. + // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through + // 0x7A inclusive (a-z). + + // replace invalid chars with a space, return uppercase text + // Thanks Chris Bolt for improving this function + // note: ereg_replace() replaces nulls with empty string (not space) + return strtoupper(ereg_replace('[^ -<>-}]', ' ', str_replace("\x00", ' ', $originalcommentname))); + + } + +} + +?> \ No newline at end of file diff --git a/plugins/pakeTasks/data/tasks/coverage.php b/plugins/pakeTasks/data/tasks/coverage.php new file mode 100644 index 0000000..4344921 --- /dev/null +++ b/plugins/pakeTasks/data/tasks/coverage.php @@ -0,0 +1,19 @@ +"); + } + + system("phpcs --standard=reaktor " . $args[0]); +} + +function run_lp_phpcs_all($task, $args) +{ + $project_dir = LP_PROJECT_DIR; + system("phpcs --report=summary --ignore=/om,/cache,/log,/codesniff,/test,/plugins,/templates ."); +} diff --git a/plugins/pakeTasks/data/tasks/test.php b/plugins/pakeTasks/data/tasks/test.php new file mode 100644 index 0000000..b0fb144 --- /dev/null +++ b/plugins/pakeTasks/data/tasks/test.php @@ -0,0 +1,53 @@ +ignore_version_control()->follow_link()->name(basename($path).'Test.php')->in($test_dir.DIRECTORY_SEPARATOR.'tests'.DIRECTORY_SEPARATOR.dirname($path)); + foreach ($files as $file) + { + include($file); + } + } + } + else + { + require_once(sfConfig::get('sf_symfony_lib_dir').'/vendor/lime/lime.php'); + + $h = new lime_harness(new lime_output_color()); + $h->base_dir = realpath(sfConfig::get('sf_test_dir').'/../test-todo'); + + // register all tests + $finder = pakeFinder::type('file')->ignore_version_control()->follow_link()->name('*Test.php'); + $h->register($finder->in($h->base_dir)); + + $h->run(); + } +} + + +function run_lp_test_acceptance($task, $args) +{ + throw new Exception("Task not implemented yet! Check back later ..."); +} + + +function run_lp_test_all($task, $args) +{ + throw new Exception("Task not implemented yet! Check back later ..."); +} diff --git a/plugins/sfFeed2Plugin/LICENSE b/plugins/sfFeed2Plugin/LICENSE new file mode 100644 index 0000000..4dd8b67 --- /dev/null +++ b/plugins/sfFeed2Plugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2004-2006 Francois Zaninotto + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfFeed2Plugin/README b/plugins/sfFeed2Plugin/README new file mode 100644 index 0000000..f78dee9 --- /dev/null +++ b/plugins/sfFeed2Plugin/README @@ -0,0 +1,502 @@ += sfFeed2 plugin = + +The `sfFeed2Plugin` offers an object interface for feeds and feed items, feed input methods using a web feed or an array of objects as source, and feed output methods for displaying items on a page and serving feeds through a symfony application. + +== Possible uses == + + * serving a RSS/Atom feed based on model objects + * Using web feeds as data source + * Feed aggregator + +As compared with the `sfFeedPlugin`, this plugin has a cleaner code separation in classes and offers more features. The syntax differs, but many classes have the same names, therefore the two plugins are not compatible. + +== Contents == + +This plugin contains three data structure classes: + + * `sfFeed` + * `sfFeedItem` + * `sfFeedEnclosure` + +It also contains specific classes containing specific input/output methods based on specific feed formats: + + * `sfAtom1Feed` + * `sfRssFeed` + * `sfRss10Feed` + * `sfRss201Feed` + * `sfRss091Feed` + +Last but not least, the most important (and smart) class is the feed manager, which contains only static methods: + + * `sfFeedPeer` + +Unit tests are available in the SVN repository. + +== Installation == + + * Install the plugin +{{{ +$ symfony plugin-install http://plugins.symfony-project.com/sfFeed2Plugin +}}} + + * Alternatively, if you don't have PEAR installed, you can download the latest package attached to this plugin's wiki page and extract it under your project's `plugins/` directory + + * Clear the cache to enable the autoloading to find the new class +{{{ +$ symfony cc +}}} + +== Tutorials == + +=== Building a feed from an array of objects === + +==== Example data ==== + +Let's take an example of a simple blog application with a `Post` and an `Author` table: + +||''Post'' || ''Author'' +||id || id +||author_id || first_name +||title || last_name +||description || email +||body || +||created_at || + +The `Post` class is extended by a `getStrippedTitle()` method that transforms the title into a string that can be used in an URI, replacing spaces by dashes, upper case by lower case, and removing all special characters: + +{{{ +public function getStrippedTitle() +{ + $text = strtolower($this->getTitle()); + + // strip all non word chars + $text = preg_replace('/\W/', ' ', $text); + // replace all white space sections with a dash + $text = preg_replace('/\ +/', '-', $text); + // trim dashes + $text = preg_replace('/\-$/', '', $text); + $text = preg_replace('/^\-/', '', $text); + + return $text; +} +}}} + +The `Author` class is extended by a custom `->getName()` method as follows: + +{{{ +public function getName() +{ + return $this->getFirstName().' '.$this->getLastName() +} +}}} + +If you need more details about the way to extend the model, refer to [http://www.symfony-project.com/book/trunk/08-Inside-the-Model-Layer#Extending%20the%20Model Chapter 8]. + +The `routing.yml` contains the following rule: + +{{{ +post: + url: /permalink/:stripped_title + param: { module: post, action: read } +}}} + +If you need more details about the routing system, refer to [http://www.symfony-project.com/book/trunk/09-Links-and-the-Routing-System Chapter 9]. + +A special `feed` module is built for the occasion, and all the actions and templates will be placed in it. + +{{{$ symfony init-module myapp feed}}} + +==== Expected result ==== + +The feed action has to output an [http://en.wikipedia.org/wiki/Atom_%28standard%29 Atom] feed. As a reminder of all the information that need to be included in an Atom feed, here is an example: + +{{{ + + + + The mouse blog + + 2005-12-11T16:23:51Z + + Peter Clive + pclive@myblog.com + + 4543D55FF756G734 + + + I love mice + + i-love-mice + + Peter Clive + pclive@myblog.com + + 2005-12-11T16:23:51Z + Ever since I bought my first mouse, I can't live without one. + + + + A mouse is better than a fish + + a-mouse-is-better-than-a-fish + + Bob Walter + bwalter@myblog.com + + 2005-12-09T09:11:42Z + I had a fish for four years, and now I'm sick. They smell. + + + +}}} + +==== Using the creators and setters ==== + +To build the feed, you need to initialize it with a certain format and options, and to add feed items based on the objects resulting from a database request. With the syntax of the `sfFeed` and `sfFeedItem` class, that would give: + +{{{ +public function executeLastPosts() +{ + $feed = new sfAtom1Feed(); + + $feed->setTitle('The mouse blog'); + $feed->setLink('http://www.myblog.com/'); + $feed->setAuthorEmail('pclive@myblog.com'); + $feed->setAuthorName('Peter Clive'); + + $c = new Criteria; + $c->addDescendingOrderByColumn(PostPeer::CREATED_AT); + $c->setLimit(5); + $posts = PostPeer::doSelect($c); + + foreach ($posts as $post) + { + $item = new sfFeedItem(); + $item->setTitle($post->getTitle()); + $item->setLink('@permalink?stripped_title='.$post->getStrippedTitle()); + $item->setAuthorName($post->getAuthor()->getName()); + $item->setAuthorEmail($post->getAuthor()->getEmail()); + $item->setPubdate($post->getCreatedAt('U')); + $item->setUniqueId($post->getStrippedTitle()); + $item->setDescription($post->getDescription()); + + $feed->addItem($item); + } + + $this->feed = $feed; +} +}}} + +At the end of the action, the `$feed` variable contains a `sfAtom1Feed` object which includes several `sfFeedItem` objects. To transform the object into an actual Atom feed, the `lastPostsSuccess.php` template simply contains: + +{{{ + +asXml() ?> +}}} + +The content type is automatically set by the `asXML()` method, depending on the feed format (Atom1 in this example). + +When called from a feed aggregator, the result of the action is now exactly the Atom feed described above: + +{{{http://www.myblog.com/feed/lastPosts}}} + +==== Using the `initialize()` method ==== + +The use of all the setters for the feed and item construction can be a little annoying, since there is a lot of information to define. Both the `sfFeed` and the `sfFeedItem` classes provide an `initialize()` method that uses an associative array for a shorter syntax: + +{{{ +public function executeLastPosts() +{ + $feed = new sfAtom1Feed(); + + $feed->initialize(array( + 'title' => 'The mouse blog', + 'link' => 'http://www.myblog.com/', + 'authorEmail' => 'pclive@myblog.com', + 'authorName' => 'Peter Clive' + )); + + $c = new Criteria; + $c->addDescendingOrderByColumn(PostPeer::CREATED_AT); + $c->setLimit(5); + $posts = PostPeer::doSelect($c); + + foreach ($posts as $post) + { + $item = new sfFeedItem(); + $item->initialize(array( + 'title' => $post->getTitle(), + 'link' => '@permalink?stripped_title='.$post->getStrippedTitle(), + 'authorName' => $post->getAuthor()->getName(), + 'authorEmail' => $post->getAuthor()->getEmail(), + 'pubdate' => $post->getCreatedAt(), + 'uniqueId' => $post->getStrippedTitle(), + 'description' => $post->getDescription(), + )); + + $feed->addItem($item); + } + + $this->feed = $feed; +} +}}} + +It has exactly the same effect as the previous listing, but the syntax is clearer. + +==== Using the object converter ==== + +As the method names that are used to build a feed item based on an object are more or less always the same, the `sfFeedPeer` can try to do it on its own: + +{{{ +public function executeLastPosts() +{ + $feed = new sfAtom1Feed(); + + $feed->initialize(array( + 'title' => 'The mouse blog', + 'link' => 'http://www.myblog.com/', + 'authorEmail' => 'pclive@myblog.com', + 'authorName' => 'Peter Clive' + )); + + $c = new Criteria; + $c->addDescendingOrderByColumn(PostPeer::CREATED_AT); + $c->setLimit(5); + $posts = PostPeer::doSelect($c); + + $postItems = sfFeedPeer::convertObjectsToItems($posts, array('routeName' => '@permalink')) + $feed->addItems($postItems); + + $this->feed = $feed; +} +}}} + +The rules governing the `sfFeedPeer::convertObjectsToItems` algorithm are as follows: + + * To set the item `title`, it looks for a `getFeedTitle()`, a `getTitle()`, a `getName()` or a `__toString()` method. + + In the example, the `Post` object has a `getName()` method. + + * To set the `link`, it uses the `routeName` option if defined in the second argument of the method call. It is supposed to be a route name for the feed items. If present, the method looks in the route url for parameters for which it could find a getter in the object methods. If not, it looks for a `getFeedLink()`, `getLink()`, `getUrl()` method in the object. + + In the example, the route name given as parameter is `@permalink`. The routing rule contains a `:stripped_title` parameter and the `Post` object has a `getStrippedTitle()` method, so the `convertObjectsToItems` method is able to define the URIs to link to. + + * To set the author's email, it looks for a `getFeedAuthorEmail` or a `getAuthorEmail`. If there is no such method, it looks for a `getAuthor()`, `getUser()` or `getPerson()` method. If the result returned is an object, it looks in this object for a `getEmail` or a `getMail` method. + + In the example, the `Post` object has a `getAuthor()`, and the `Author` object has a `getName()`. The same kind of rules is used for the author's name and URL. + + * To set the publication date, it looks for a `getFeedPubdate()`, `getPubdate()`, `getCreatedAt()` or a `getDate()` method. + + In the example, the `Post` object has a `getCreatedAt` + +The same goes for the other possible fields of an Atom feed (including the categories, the summary, the unique id, etc.), and you are advised to [browse the source of the `sfFeed` class](http://www.symfony-project.com/trac/browser/plugins/sfFeed2Plugin/lib) to discover all the deduction algorithms. + +All in all, the way the accessors of the `Post` and `Author` objects are built allow the built-in algorithm of the `convertObjectsToItems` method to work, and the creation of the feed to be more simple. + +==== Defining custom values for the feed ==== + +In the list of rules presented above, you can see that the first method name that the `sfFeed` object looks for is always a `getFeedXXX()`. This allows you to specify a custom value for each of the fields of a feed item by simply extended the model. + +For instance, if you don't want the author's email to be published in the feed, just add the following `getFeedAuthorEmail()` method to the `Post` object: + +{{{ +public function getFeedAuthorEmail() +{ + return ''; +} +}}} + +This method will be found before the `getAuthor()` method, and the feed will not disclose the publishers' email addresses. + +The other way to use a specific method for an item property is to pass a `methods` option to the `convertObjectsToItems` method: an associative array associating item properties with object methods. So, for instance, to tell the converter to use nothing for the feed author email and the `getUserFirstName()` method for the author name, you could write: + +{{{ + $postItems = sfFeedPeer::convertObjectsToItems($posts, array( + 'routeName' => '@permalink', + 'methods' => array( + 'authorEmail' => '', + 'authorName' => 'getUserFirstName' + ) + )); +}}} + +==== Using the sfFeedPeer static methods ==== + +The `sfFeedPeer` class offer helper methods that facilitate the creation and population of feed items. + +When the feed format is determined at runtime, create feed objects using the `sfFeedPeer::newInstance()` method, which is a factory, rather that using the `new` command: + +{{{ +$feed = sfFeedPeer::newInstance('atom1'); +// same as +$feed = new sfAtom1Feed(); +}}} + +The steps described in the `executeLastPosts` listing occur in almost every feed construction process, so the `sfFeedPeer` can reduce the code above to a simpler: + +{{{ +public function executeLastPosts() +{ + $c = new Criteria; + $c->addDescendingOrderByColumn(PostPeer::CREATED_AT); + $c->setLimit(5); + $posts = PostPeer::doSelect($c); + + $this->feed = sfFeedPeer::createFromObjects( + $posts, + array( + 'format' => 'atom1', + 'title' => 'The mouse blog', + 'link' => 'http://www.myblog.com/', + 'authorEmail' => 'pclive@myblog.com', + 'authorName' => 'Peter Clive' + 'routeName' => '@permalink', + 'methods' => array('authorEmail' => '', 'authorName' => 'getUserFirstName') + ) + ); +} +}}} + +==== Using other formats ==== + +The methods described below can be transposed to build other RSS feeds. Simply change the parameter given to the feed factory: + +{{{ +// Atom 1 +$feed = sfFeedPeer::newInstance('atom1'); +// RSS 1.0 RDF Site Summary +$feed = sfFeedPeer::newInstance('rss10'); +// RSS 0.91 Userland +$feed = sfFeedPeer::newInstance('rss091'); +// RSS 2.01 rev6 +$feed = sfFeedPeer::newInstance('rss201'); +}}} + +=== Fetching a feed from the web and displaying it === + +You may want to display the latest posts of the symfony users group in your application. The steps to retrieve this information are to fetche a feed from the Internet, create an empty feed object, and populate it with the items of the feed. You can use the `fromXML()` method and the [http://www.symfony-project.com/trac/wiki/sfWebBrowserPlugin sfWebBrowserPlugin] for that: + +{{{ +public function executeLastPosts() +{ + $uri = 'http://groups.google.com/group/symfony-users/feed/rss_v2_0_msgs.xml'; + + $browser = new sfWebBrowser(array( + 'user_agent' => 'sfFeedReader/0.9', + 'timeout' => 5 + )); + $feedString = $browser->get($uri)->getResponseText(); + + $feed = new sfRssFeed(); + $feed->setUrl($feedString); + $feed->fromXml($uri); + $this->feed = $feed; +} +}}} + +Thanks to the `sfFeedPeer` shortcuts, this can be reduced to a single line: + +{{{ +public function executeLastPosts() +{ + $this->feed = sfFeedPeer::createFromWeb('http://groups.google.com/group/symfony-users/feed/rss_v2_0_msgs.xml'); +} +}}} + +The `createFromWeb()` method first parse the response and tries to recognize a known feed format (RSS or Atom - The recognized formats are the same ones as above). Note that this method depends on the `sfWebBrowserPlugin`, so this plugin must be installed to make the method work. + +Once the feed is built, it is very easy to use it for the display in the template: + +{{{ +

    Latests posts from the mailing-list

    +
      + getItems() as $post): ?> +
    • + getPubDate(), 'd/MM H:mm') ?> - + getTitle(), $post->getLink()) ?> + by getAuthorName() ?> +
    • + +
    +}}} + +=== Aggregating several feeds === + +The `sfFeedPeer` class contains a method called `aggregate()`, which merges several feeds and reorders the items chronologically. Using it is very simple: just pass an array of feeds as parameters, and you receive a new feed object with all the items within. + +For instance, here is how you could display a feed of 10 posts populated with the latest posts from both the users and the devs groups: + +{{{ +public function executeLastPosts() +{ + $feed1 = sfFeedPeer::createFromWeb('http://groups.google.com/group/symfony-users/feed/rss_v2_0_msgs.xml'); + $feed2 = sfFeedPeer::createFromWeb('http://groups.google.com/group/symfony-devs/feed/rss_v2_0_msgs.xml'); + $this->feed = sfFeedPeer::aggregate(array($feed1, $feed2), array('limit' => 10)); +} +}}} + +== TODO == + + * unit test the `sfFeedPeer` class + * Populate feedItems from a pager rather than from an array of objects + * Deal with time zones (i.e. store dates in GMT, and handle input and output with a time zone) + +== Changelog == + +=== 2007-04-15 | 0.9.4 Beta === + + * francois: Added a `toXML` method to `sfRssFeed`, `sfRss10Feed` and `sfAtom1Feed` (based on an idea from Frank Stelzer) + * Frank.Stelzer: Added a new `sfFeedPeer::createFromXml()` method + * Frank.Stelzer: Fixed errors in the documentation where `sfFeed` methods were described + * francois: `sfFeedPeer::createFromWeb()` now throws an exception whenever the fetched URL returns an error + * Markus.Staab: Fixed a typo in `sfFeed` constructor + * francois: Fixed a warning in `sfRssFeed` causing badly formatted feeds in dev env + * francois: '''BC break''' `sfFeedPeer::convertObjectsToItems()` signature changed (`$objects, $options = array()`) to have similar signature to that of `sfFeedPeer::createFromObjects()` + * francois: Added the ability to define one method per feed property in `sfFeedPeer::convertObjectsToItems()` + * francois: `sfFeedPeer::convertObjectsToItems()` now populates the feed item content + * francois: `sfFeedPeer::createFromWeb()` can now use a custom `userAgent` option to be seen as a custom user agent from the outside + * francois: `sfFeedPeer::createFromWeb()` has a better detection of Atom feeds + * francois: Fixed a bug in generated Atom1 feeds (summary attribute) + * francois: Fixed a bug in `sfFeedPeer::aggregate()` when defining a feed format + +=== 2007-03-13 | 0.9.3 Beta === + + * francois: `sfFeedPeer::createFromWeb()` is smarter at determining the type of feed it reads + * francois: Added smart guessing of publication date for RSS and Atom feeds, based on URL scheme + * francois: `sfFeedPeer::aggregate()` now handles items with the same date without overriding one. + * francois: Fixed two bugs in `sfFeedPeer` preventing items creation from objects + * francois: Items aggregated in `sfFeedPeer::aggregate` now remember their original feed properties + * francois: `sfFeedPeer::aggregate` can now limit the total number of items returned + * francois: Added `sfFeed::keepOnlyItems($count)` method + * francois: `sfRssReed` now looks for a `dc:creator` of no regular author is found + +=== 2007-03-03 | 0.9.2 Beta === + + * francois: Added a way to get an item description based on a content when no description exists + * francois: Added `` handling in RSS 1 and 2 feeds (based on a patch from Jeff Merlet) + +=== 2007-02-22 | 0.9.1 Beta === + + * francois: Added the `sfRss10Feed` class and unit tests + * francois: Changed feed type detection technique to avoid building a simpleXML element twice + +=== 2007-02-21 | 0.9.0 Beta === + + * francois: Added more unit tests + * francois: Improved `sfRssFeed` conversions + * francois: Moved `getLatestPostDate()` method to `sfFeed` and unit tested it. + * francois: '''BC break''' Renamed specialized RSS classes to `sfRss201Feed` and `sfRss901Feed`. These classes are not really useful anyway, since all their code was refactored to `sfRssFeed`. + +=== 2007-02-19 | 0.8.1 Alpha === + + * francois: Added much more unit tests + * francois: Improved `sfAtom1Feed` conversions + * francois: Added `__toString()` and `initialize()` methods to `sfFeedEnclosure` + * francois: Added `content` property to `sfFeedItem` + * francois: '''BC break''' `fromXML()` methods now expect a string rather than a simpleXML object + * francois: '''BC break''' `sfFeedPeer::createFromObjects()` signature changed ($objects, $parameters = array()) + + +=== 2007-02-18 | 0.8.0 Alpha === + + * francois: Initial release \ No newline at end of file diff --git a/plugins/sfFeed2Plugin/lib/sfAtom1Feed.class.php b/plugins/sfFeed2Plugin/lib/sfAtom1Feed.class.php new file mode 100644 index 0000000..baf3a37 --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfAtom1Feed.class.php @@ -0,0 +1,331 @@ + + * (c) 2004-2007 Francois Zaninotto + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * Specification: http://www.ietf.org/rfc/rfc4287.txt + * + * @package sfFeed2 + * @author Fabien Potencier + * @author Francois Zaninotto + */ +class sfAtom1Feed extends sfFeed +{ + protected + $context; + + protected function initContext() + { + if(!$this->context) + { + $this->context = sfContext::getInstance(); + } + } + + /** + * Populate the feed object from a XML feed string. + * + * @param string A XML feed (Atom 1.0 format). + * + * @return sfAtom1Feed The current object. + * + * @throws Exception If the argument is not a well-formatted Atom feed. + */ + public function fromXml($feedXml) + { + preg_match('/^<\?xml\s*version="1\.0"\s*encoding="(.*?)\"\s*\?>$/mi', $feedXml, $matches); + if(isset($matches[1])) + { + $this->setEncoding($matches[1]); + } + $feedXml = simplexml_load_string($feedXml); + if(!$feedXml) + { + throw new Exception('Error creating feed from XML: string is not well-formatted XML'); + } + + $attributes = $feedXml->attributes('http://www.w3.org/XML/1998/namespace'); + + $this->setLanguage((string) $attributes['lang']); + $this->setTitle((string) $feedXml->title); + $feedXml->registerXPathNamespace('atom', 'http://www.w3.org/2005/Atom'); + if($titles = $feedXml->xpath('atom:link[@rel="alternate"]')) + { + $this->setLink((string) $titles[0]['href']); + } + if($titles = $feedXml->xpath('atom:link[@rel="self"]')) + { + $this->setFeedUrl((string) $titles[0]['href']); + } + $this->setSubtitle((string) $feedXml->subtitle); + $this->setAuthorName((string) $feedXml->author->name); + $this->setAuthorEmail((string) $feedXml->author->email); + $this->setAuthorLink((string) $feedXml->author->uri); + $categories = array(); + foreach($feedXml->category as $category) + { + $categories[] = (string) $category['term']; + } + $this->setCategories($categories); + + foreach($feedXml->entry as $itemXml) + { + $categories = array(); + foreach($itemXml->category as $category) + { + $categories[] = (string) $category['term']; + } + $url = (string) $itemXml->link['href']; + $pubdate = strtotime(str_replace(array('UT', 'Z'), '', (string) $itemXml->issued)); + if(!$pubdate) + { + if((string) $itemXml->updated) + { + $pubdate = strtotime(str_replace(array('UT', 'Z'), '', (string) $itemXml->updated)); + } + else if((string) $itemXml->modified) + { + $pubdate = strtotime(str_replace(array('UT', 'Z'), '', (string) $itemXml->modified)); + } + else if(preg_match('/\d{4}\/\d{2}\/\d{2}/', $url, $matches)) + { + $pubdate = strtotime($matches[0]); + } + else + { + $pubdate = 0; + } + } + $itemXml->registerXPathNamespace('atom', 'http://www.w3.org/2005/Atom'); + if($enclosures = $itemXml->xpath('atom:link[@rel="enclosure"]')) + { + $enclosure = new sfFeedEnclosure(); + $enclosure->setUrl((string) $enclosures[0]['href']); + $enclosure->setLength((string) $enclosures[0]['length']); + $enclosure->setMimeType((string) $enclosures[0]['type']); + } + else + { + $enclosure = null; + } + $this->addItemFromArray(array( + 'title' => (string) $itemXml->title, + 'link' => $url, + 'authorName' => (string) $itemXml->author->name, + 'authorEmail' => (string) $itemXml->author->email, + 'authorLink' => (string) $itemXml->author->uri, + 'pubDate' => $pubdate, + 'description' => (string) $itemXml->summary, + 'content' => (string) $itemXml->content, + 'uniqueId' => (string) $itemXml->id, + 'enclosure' => $enclosure, + 'categories' => $categories, + 'feed' => $this + )); + } + + return $this; + } + + /** + * Returns the the current object as a valid Atom 1.0 XML feed + * And sets the response content type accordingly. + * + * @return string An Atom 1.0 XML string. + */ + public function asXml() + { + $this->initContext(); + $this->context->getResponse()->setContentType('application/atom+xml'); + + return $this->toXml(); + } + + /** + * Returns the the current object as a valid Atom 1.0 XML feed. + * + * @return string An Atom 1.0 XML string. + */ + public function toXml() + { + $this->initContext(); + $controller = $this->context->getController(); + + $xml = array(); + $xml[] = 'getEncoding().'" ?>'; + + if ($this->getLanguage()) + { + $xml[] = sprintf('', 'http://www.w3.org/2005/Atom', $this->getLanguage()); + } + else + { + $xml[] = sprintf('', 'http://www.w3.org/2005/Atom'); + } + + $xml[] = ' '.$this->getTitle().''; + $xml[] = ' '; + if ($this->getFeedUrl()) + { + $xml[] = ' '; + } + if ($this->getLicense() && $this->getLicense()->getHref()) + { + $xml[] = ' '; + } + + $xml[] = ' '.$controller->genUrl($this->getLink(), true).''; + $xml[] = ' '.strftime('%Y-%m-%dT%H:%M:%SZ', $this->getLatestPostDate()).''; + + if ($this->getAuthorName()) + { + $xml[] = ' '; + $xml[] = ' '.$this->getAuthorName().''; + if ($this->getAuthorEmail()) + { + $xml[] = ' '.$this->getAuthorEmail().''; + } + if ($this->getAuthorLink()) + { + $xml[] = ' '.$controller->genUrl($this->getAuthorLink(), true).''; + } + $xml[] = ' '; + } + + if ($this->getSubtitle()) + { + $xml[] = ' '.$this->getSubtitle().''; + } + + if(is_array($this->getCategories())) + { + foreach ($this->getCategories() as $category) + { + $xml[] = ' '; + } + } + + $xml[] = $this->getFeedElements(); + + $xml[] = ''; + + return implode("\n", $xml); + } + + /** + * Returns an array of tags corresponding to the feed's items. + * + * @return string A list of elements. + */ + private function getFeedElements() + { + $controller = $this->context->getController(); + $xml = array(); + + foreach ($this->getItems() as $item) + { + $xml[] = ''; + $xml[] = ' '.htmlspecialchars($item->getTitle()).''; + $xml[] = ' '; + if ($item->getLicense() && $item->getLicense()->getHref()) + { + $xml[] = ' '; + } + + if ($item->getPubdate()) + { + $xml[] = ' '.strftime('%Y-%m-%dT%H:%M:%SZ', $item->getPubdate()).''; + } + + // author information + if ($item->getAuthorName()) + { + $xml[] = ' '; + $xml[] = ' '.$item->getAuthorName().''; + if ($item->getAuthorEmail()) + { + $xml[] = ' '.$item->getAuthorEmail().''; + } + if ($item->getAuthorLink()) + { + $xml[] = ' '.$controller->genUrl($item->getAuthorLink(), true).''; + } + $xml[] = ' '; + } + + // unique id + if ($item->getUniqueId()) + { + $uniqueId = $item->getUniqueId(); + } + else + { + $uniqueId = $this->getTagUri($item->getLink(), $item->getPubdate()); + } + $xml[] = ' '.$uniqueId.''; + + // summary + if ($item->getDescription()) + { + $xml[] = sprintf(' %s', htmlspecialchars($item->getDescription())); + } + + // content + if ($item->getContent()) + { + $xml[] = sprintf(' %s
    ]]>', $item->getContent()); + } + + // enclosure + if ($enclosure = $item->getEnclosure()) + { + $xml[] = sprintf(' ', $enclosure->getUrl(), $enclosure->getLength(), $enclosure->getMimeType()); + } + + // categories + if(is_array($item->getCategories())) + { + foreach ($item->getCategories() as $category) + { + $xml[] = ' '; + } + } + + $xml[] = ''; + } + + return implode("\n", $xml); + } + + /** + * Creates a TagURI. + * See http://diveintomark.org/archives/2004/05/28/howto-atom-id + * + * @param string An URI to the Feed Element + * @param datetime A publication date + * + * @return string A valid TagURI. + */ + private function getTagUri($url, $date) + { + $tag = preg_replace('#^http\://#', '', $url); + if ($date) + { + $tag = preg_replace('#/#', ','.strftime('%Y-%m-%d', $date).':/', $tag, 1); + } + $tag = preg_replace('/#/', '/', $tag); + + return 'tag:'.$tag; + } + +} + +?> diff --git a/plugins/sfFeed2Plugin/lib/sfFeed.class.php b/plugins/sfFeed2Plugin/lib/sfFeed.class.php new file mode 100644 index 0000000..a40101a --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfFeed.class.php @@ -0,0 +1,331 @@ + + * (c) 2004-2007 Francois Zaninotto + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfFeed. + * + * based on feedgenerator.py from django project + * + * @package sfFeed2 + * @author Fabien Potencier + * @author Francois Zaninotto + */ +class sfFeed +{ + protected + $items = array(), + $title, + $link, + $license, + $description, + $language = 'en', + $authorEmail, + $authorName, + $authorLink, + $subtitle, + $categories = array(), + $feedUrl, + $encoding = 'UTF-8'; + + public function construct($feed_array = array()) + { + if($feed_array) + { + $this->initialize($feed_array); + } + } + + /** + * Defines the feed properties, based on an associative array + * + * @param array an associative array of feed parameters + * + * @return sfFeed the current sfFeed object + */ + public function initialize($feed_array) + { + $this->setItems(isset($feed_array['items']) ? $feed_array['items'] : ''); + $this->setTitle(isset($feed_array['title']) ? $feed_array['title'] : ''); + $this->setLink(isset($feed_array['link']) ? $feed_array['link'] : ''); + $this->setLicense(isset($feed_array['license']) ? $feed_array['license'] : ''); + $this->setDescription(isset($feed_array['description']) ? $feed_array['description'] : ''); + $this->setLanguage(isset($feed_array['language']) ? $feed_array['language'] : $this->language); + $this->setAuthorEmail(isset($feed_array['authorEmail']) ? $feed_array['authorEmail'] : ''); + $this->setAuthorName(isset($feed_array['authorName']) ? $feed_array['authorName'] : ''); + $this->setAuthorLink(isset($feed_array['authorLink']) ? $feed_array['authorLink'] : ''); + $this->setSubtitle(isset($feed_array['subtitle']) ? $feed_array['subtitle'] : ''); + $this->setCategories(isset($feed_array['categories']) ? $feed_array['categories'] : ''); + $this->setFeedUrl(isset($feed_array['feedUrl']) ? $feed_array['feedUrl'] : ''); + $this->setEncoding(isset($feed_array['encoding']) ? $feed_array['encoding'] : $this->encoding); + + return $this; + } + + /** + * Retrieves the feed items + * + * @return array an array of sfFeedItem objects + */ + public function getItems() + { + return $this->items; + } + + /** + * Defines the items of the feed + * Caution: in previous versions, this method used to accept all kinds of objects. + * Now only objects of class sfFeedItem are allowed. + * + * @param array an array of sfFeedItem objects + * + * @return sfFeed the current sfFeed object + */ + public function setItems($items = array()) + { + $this->items = array(); + $this->addItems($items); + + return $this; + } + + /** + * Adds one item to the feed + * + * @param sfFeedItem an item object + * + * @return sfFeed the current sfFeed object + */ + public function addItem($item) + { + if (!($item instanceof sfFeedItem)) + { + // the object is of the wrong class + $error = 'Parameter of addItem() is not of class sfFeedItem'; + + throw new Exception($error); + } + $item->setFeed($this); + $this->items[] = $item; + + return $this; + } + + /** + * Adds several items to the feed + * + * @param array an array of sfFeedItem objects + * + * @return sfFeed the current sfFeed object + */ + public function addItems($items) + { + if(is_array($items)) + { + foreach($items as $item) + { + $this->addItem($item); + } + } + + return $this; + } + + /** + * Adds one item to the feed, based on an associative array + * + * @param array an associative array + * + * @return sfFeed the current sfFeed object + */ + public function addItemFromArray($item_array) + { + $this->items[] = new sfFeedItem($item_array); + + return $this; + } + + /** + * Removes the last items of the feed + * so that the total number doesn't bypass the limit defined as a parameter + * + * @param integer the maximum number of items + * + * @return sfFeed the current sfFeed object + */ + public function keepOnlyItems($count = 10) + { + if($count < count($this->items)) + { + $this->items = array_slice($this->items, 0, $count); + } + + return $this; + } + + public function setTitle ($title) + { + $this->title = $title; + } + + public function getTitle () + { + return $this->title; + } + + public function setLink ($link) + { + $this->link = $link; + } + + public function getLink () + { + return $this->link; + } + + public function setLicense($license) + { + if ($license && !($license instanceof sfFeedLicense)) + { + // the object is of the wrong class + $error = 'Parameter of setLicense() is not of class sfFeedLicense'; + + throw new Exception($error); + } + + $this->license = $license; + return $this; + } + + public function getLicense() + { + return $this->license; + } + + public function setDescription ($description) + { + $this->description = $description; + } + + public function getDescription () + { + return $this->description; + } + + public function setLanguage ($language) + { + $this->language = $language; + } + + public function getLanguage () + { + return $this->language; + } + + public function setAuthorEmail ($authorEmail) + { + $this->authorEmail = $authorEmail; + } + + public function getAuthorEmail () + { + return $this->authorEmail; + } + + public function setAuthorName ($authorName) + { + $this->authorName = $authorName; + } + + public function getAuthorName () + { + return $this->authorName; + } + + public function setAuthorLink ($authorLink) + { + $this->authorLink = $authorLink; + } + + public function getAuthorLink () + { + return $this->authorLink; + } + + public function setSubtitle ($subtitle) + { + $this->subtitle = $subtitle; + } + + public function getSubtitle () + { + return $this->subtitle; + } + + public function setCategories ($categories) + { + $this->categories = $categories; + } + + public function getCategories () + { + return $this->categories; + } + + public function setFeedUrl ($feedUrl) + { + $this->feedUrl = $feedUrl; + } + + public function getFeedUrl () + { + return $this->feedUrl; + } + + public function getEncoding() + { + return $this->encoding; + } + + public function setEncoding($encoding) + { + $this->encoding = $encoding; + } + + public function getLatestPostDate() + { + $updates = array(); + foreach ($this->getItems() as $item) + { + if ($item->getPubdate()) + { + $updates[] = $item->getPubdate(); + } + } + + if ($updates) + { + sort($updates); + return array_pop($updates); + } + else + { + return time(); + } + } + + public function asXml() + { + throw new sfException('You must use newInstance to get a real feed.'); + } + +} + +?> diff --git a/plugins/sfFeed2Plugin/lib/sfFeedEnclosure.class.php b/plugins/sfFeed2Plugin/lib/sfFeedEnclosure.class.php new file mode 100644 index 0000000..2827233 --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfFeedEnclosure.class.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package sfFeed2 + * @author Fabien Potencier + */ +class sfFeedEnclosure +{ + private + $url, + $length, + $mimeType; + + /** + * Defines the feed enclosure properties, based on an associative array + * + * @param array an associative array of feed parameters + * + * @return sfFeedEnclosure the current sfFeedEnclosure object + */ + public function initialize($feed_array) + { + $this->setUrl(isset($feed_array['url']) ? $feed_array['url'] : ''); + $this->setLength(isset($feed_array['length']) ? $feed_array['length'] : ''); + $this->setMimeType(isset($feed_array['mimeType']) ? $feed_array['mimeType'] : ''); + + return $this; + } + + public function __toString() + { + return sprintf("url=%s length=%s mimeType=%s", $this->getUrl(), $this->getLength(), $this->getMimeType()); + } + + public function setUrl ($url) + { + $this->url = $url; + } + + public function getUrl () + { + return $this->url; + } + + public function setLength ($length) + { + $this->length = $length; + } + + public function getLength () + { + return $this->length; + } + + public function setMimeType ($mimeType) + { + $this->mimeType = $mimeType; + } + + public function getMimeType () + { + return $this->mimeType; + } +} + +?> \ No newline at end of file diff --git a/plugins/sfFeed2Plugin/lib/sfFeedItem.class.php b/plugins/sfFeed2Plugin/lib/sfFeedItem.class.php new file mode 100644 index 0000000..c7d40dd --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfFeedItem.class.php @@ -0,0 +1,237 @@ + + * (c) 2004-2007 Francois Zaninotto + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package sfFeed2 + * @author Fabien Potencier + */ +class sfFeedItem +{ + private + $title, + $link, + $license, + $description, + $content, + $authorEmail, + $authorName, + $authorLink, + $pubdate, + $comments, + $uniqueId, + $enclosure, + $categories = array(), + $feed; + + public function __construct($item_array = array()) + { + if($item_array) + { + $this->initialize($item_array); + } + } + + /** + * Sets the feed item parameters, based on an associative array + * + * @param array an associative array + * + * @return sfFeedItem the current sfFeedItem object + */ + public function initialize($item_array) + { + $this->setTitle(isset($item_array['title']) ? $item_array['title'] : ''); + $this->setLink(isset($item_array['link']) ? $item_array['link'] : ''); + $this->setLicense(isset($item_array['license']) ? $item_array['license'] : ''); + $this->setDescription(isset($item_array['description']) ? $item_array['description'] : ''); + $this->setContent(isset($item_array['content']) ? $item_array['content'] : ''); + $this->setAuthorEmail(isset($item_array['authorEmail']) ? $item_array['authorEmail'] : ''); + $this->setAuthorName(isset($item_array['authorName']) ? $item_array['authorName'] : ''); + $this->setAuthorLink(isset($item_array['authorLink']) ? $item_array['authorLink'] : ''); + $this->setPubdate(isset($item_array['pubDate']) ? $item_array['pubDate'] : ''); + $this->setComments(isset($item_array['comments']) ? $item_array['comments'] : ''); + $this->setUniqueId(isset($item_array['uniqueId']) ? $item_array['uniqueId'] : ''); + $this->setEnclosure(isset($item_array['enclosure']) ? $item_array['enclosure'] : ''); + $this->setCategories(isset($item_array['categories']) ? $item_array['categories'] : ''); + $this->setFeed(isset($item_array['feed']) ? $item_array['feed'] : ''); + + return $this; + } + + public function setTitle ($title) + { + $this->title = $title; + } + + public function getTitle () + { + return $this->title; + } + + public function setLink ($link) + { + $this->link = $link; + } + + public function getLink () + { + return $this->link; + } + + public function getLicense () + { + return $this->license; + } + + public function setLicense ($license) + { + if ($license && !($license instanceof sfFeedLicense)) + { + // FIXME: This shouldn't cause an exception, lets just bail out gracefully + return $this; + + // the object is of the wrong class + $error = 'Parameter of setLicense() is not of class sfFeedLicense'; + + throw new Exception($error); + } + + $this->license = $license; + return $this; + } + + public function setDescription ($description) + { + $this->description = $description; + } + + public function getDescription () + { + if($this->description) + { + return $this->description; + } + else if($this->content) + { + $description = strip_tags($this->content); + $description_max_length = sfConfig::get('app_feed_item_max_length', 100); + if (strlen($description) > $description_max_length) + { + $description = substr($description, 0, $description_max_length - strlen($description)).'[...]'; + } + return $description; + } + } + + public function setContent ($content) + { + $this->content = $content; + } + + public function getContent () + { + return $this->content; + } + + public function setAuthorEmail ($authorEmail) + { + $this->authorEmail = $authorEmail; + } + + public function getAuthorEmail () + { + return $this->authorEmail; + } + + public function setAuthorName ($authorName) + { + $this->authorName = $authorName; + } + + public function getAuthorName () + { + return $this->authorName; + } + + public function setAuthorLink ($authorLink) + { + $this->authorLink = $authorLink; + } + + public function getAuthorLink () + { + return $this->authorLink; + } + + public function setPubdate ($pubdate) + { + $this->pubdate = $pubdate; + } + + public function getPubdate () + { + return $this->pubdate; + } + + public function setComments ($comments) + { + $this->comments = $comments; + } + + public function getComments () + { + return $this->comments; + } + + public function setUniqueId ($uniqueId) + { + $this->uniqueId = $uniqueId; + } + + public function getUniqueId () + { + return $this->uniqueId; + } + + public function setEnclosure ($enclosure) + { + $this->enclosure = $enclosure; + } + + public function getEnclosure () + { + return $this->enclosure; + } + + public function setCategories ($categories) + { + $this->categories = $categories; + } + + public function getCategories () + { + return $this->categories; + } + + public function setFeed ($feed) + { + $this->feed = $feed; + } + + public function getFeed () + { + return $this->feed; + } + +} + +?> diff --git a/plugins/sfFeed2Plugin/lib/sfFeedLicense.class.php b/plugins/sfFeed2Plugin/lib/sfFeedLicense.class.php new file mode 100644 index 0000000..86e6e91 --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfFeedLicense.class.php @@ -0,0 +1,53 @@ +initialize($item_array); + } + } + + /** + * Sets the feed image parameters, based on an associative array + * + * @param array an associative array + * + * @return sfFeedImage the current sfFeedImage object + */ + public function initialize($item_array) + { + $this->setType(isset($item_array['type']) ? $item_array['type'] : ''); + $this->setHref(isset($item_array['href']) ? $item_array['href'] : ''); + + return $this; + } + + public function setType($type) + { + $this->type = $type; + return $this; + } + public function getType() + { + return $this->type; + } + + public function setHref($href) + { + $this->href = $href; + return $this; + } + + public function getHref() + { + return $this->href; + } + +} + diff --git a/plugins/sfFeed2Plugin/lib/sfFeedPeer.class.php b/plugins/sfFeed2Plugin/lib/sfFeedPeer.class.php new file mode 100644 index 0000000..34fb39f --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfFeedPeer.class.php @@ -0,0 +1,544 @@ + + * (c) 2004-2007 Francois Zaninotto + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfFeedPeer + * + * + * @package sfFeed2 + * @author Fabien Potencier + * @author Francois Zaninotto + */ +class sfFeedPeer +{ + /** + * Retrieve a new sfFeed implementation instance. + * + * @param string A sfFeed implementation name. + * + * @return sfFeed A sfFeed implementation instance. + * + * @throws sfFactoryException If a new syndication feed implementation instance cannot be created. + */ + public static function newInstance($format = '') + { + try + { + $class = 'sf'.ucfirst($format).'Feed'; + + // the class exists + $object = new $class(); + + if (!($object instanceof sfFeed)) + { + // the class name is of the wrong type + $error = 'Class "%s" is not of the type sfFeed'; + $error = sprintf($error, $class); + + throw new sfFactoryException($error); + } + + return $object; + } + catch (sfException $e) + { + $e->printStackTrace(); + } + } + + /** + * Retrieve a new sfFeed implementation instance, populated from a web feed. + * The class of the returned instance depends on the nature of the web feed. + * This method uses the sfWebBrowser plugin. + * + * @param string A web feed URI + * + * @return sfFeed A sfFeed implementation instance. + */ + public static function createFromWeb($uri, $options = array()) + { + if(isset($options['adapter'])) + { + $browser = new sfWebBrowser(array(), $options['adapter'], isset($options['adapter_options']) ? $options['adapter_options'] : array()); + } + else + { + $browser = new sfWebBrowser(); + } + $browser->setUserAgent(isset($options['userAgent']) ? $options['userAgent'] : 'sfFeedReader/0.9'); + if($browser->get($uri)->responseIsError()) + { + $error = 'The given URL (%s) returns an error (%s: %s)'; + $error = sprintf($error, $uri, $browser->getResponseCode(), $browser->getResponseMessage()); + throw new Exception($error); + } + $feedString = $browser->getResponseText(); + + return self::createFromXml($feedString, $uri); + } + + /** + * Retrieve a new sfFeed implementation instance, populated from a xml feed. + * The class of the returned instance depends on the nature of the xml feed. + * + * @param string $feedString a feed as xml string + * @param string A web feed URI + * + * @return sfFeed A sfFeed implementation instance. + */ + public static function createFromXml($feedString, $uri) + { + $feedClass = ''; + if(preg_match('/xmlns=[\"\'](http:\/\/www\.w3\.org\/2005\/Atom|http:\/\/purl\.org\/atom)/', $feedString)) + { + $feedClass = 'sfAtom1Feed'; + } + if(strpos($feedString, 'setFeedUrl($uri); + $object->fromXml($feedString); + return $object; + } + else + { + throw new Exception('Impossible to decode feed format'); + } + } + + /** + * Merge the items from several feeds and retrieve a sfFeed instance + * Populated with all the items, and sorted. + * + * @param array an array of sfFeed objects + * @param array an associative array of feed parameters + * + * @return sfFeed A sfFeed implementation instance. + */ + public static function aggregate($feeds, $parameters = array()) + { + // merge all items + $feed_items = array(); + foreach($feeds as $feed) + { + foreach($feed->getItems() as $item) + { + $index = is_integer($item->getPubDate()) ? $item->getPubDate() : 0; + while(isset($feed_items[$index])) + { + $index++; + } + $feed_items[$index] = $item; + } + } + + // sort in reverse chronological order + krsort($feed_items); + + // limit the number of feed items to be added + if(isset($parameters['limit'])) + { + $feed_items = array_slice($feed_items, 0, $parameters['limit']); + } + + // create a feed with these items + $feed = self::newInstance(isset($parameters['format']) ? $parameters['format'] : ''); + $feed->initialize($parameters); + foreach($feed_items as $item) + { + $origin_feed = clone $item->getFeed(); + $origin_feed->setItems(); + $feed->addItem($item); + $item->setFeed($origin_feed); + } + + return $feed; + } + + /** + * Populates a feed with items based on objects + * Inspects the available methods of the objects to populate items properties. + * + * @param array an array of objects + * @param string A route name for building the URIs to the items + * @param array An associative array of options + * + * @return sfFeed the current sfFeed object + */ + public static function convertObjectsToItems($objects, $options = array()) + { + $items = array(); + foreach($objects as $object) + { + $item = new sfFeedItem(); + + // For each item property, check if an object method is provided, + // and if not, guess it. Here is what it does for the link property + if(isset($options['methods']['link'])) + { + if($options['methods']['link']) + { + $item->setLink(call_user_func(array($object, $options['methods']['link']))); + } + else + { + $item->setLink(''); + } + } + else + { + $routeName = (isset($options['routeName'])) ? $options['routeName'] : ''; + $fallbackUrl = (isset($options['fallbackUrl'])) ? $options['fallbackUrl'] : ''; + $item->setLink(self::getItemFeedLink($object, $routeName, $fallbackUrl)); + } + + // For the other properties, it can be automated + // Not as readable but definitely more concise + $details = array('title', 'description', 'content', 'authorEmail', 'authorName', 'authorLink', 'pubdate', 'comments', 'uniqueId', 'enclosure', 'categories', 'license'); + foreach($details as $detail) + { + $itemMethod = 'set'.ucfirst($detail); + if(isset($options['methods'][$detail])) + { + if($options['methods'][$detail]) + { + call_user_func(array($item, $itemMethod), call_user_func(array($object, $options['methods'][$detail]))); + } + else + { + call_user_func(array($item, $itemMethod), ''); + } + } + else + { + call_user_func(array($item, $itemMethod), call_user_func(array('sfFeedPeer', 'getItemFeed'.ucfirst($detail)), $object)); + } + } + + $items[] = $item; + } + + return $items; + } + + /** + * Creates and populates a feed with items based on objects + * This is a proxy method that combines calls to newInstance() and convertObjectsToItems() + * + * @param array an array of objects + * @param array an associative array of feed parameters + * + * @return sfFeed A sfFeed implementation instance, containing the parameters and populated with the objects + */ + public static function createFromObjects($objects, $options = array()) + { + $feed = self::newInstance(isset($options['format']) ? $options['format'] : ''); + $feed->initialize($options); + $options['fallbackUrl'] = $feed->getLink(); + $feed->addItems(self::convertObjectsToItems($objects, $options)); + + return $feed; + } + + private static function getItemFeedTitle($item) + { + foreach (array('getFeedTitle', 'getTitle', 'getName', '__toString') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + return ''; + } + + private static function getItemFeedLicense($item) + { + foreach(array('getFeedLicense', 'getLicense') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + return ''; + } + + private static function getItemFeedLink($item, $routeName = '', $fallback_url = '') + { + if ($routeName) + { + $routing = sfRouting::getInstance(); + $route = $routing->getRouteByName($routeName); + + $url = $route[0]; + $defaults = $route[4]; + + // we get all parameters + $params = array(); + if (preg_match_all('/\:([^\/]+)/', $url, $matches)) + { + foreach ($matches[1] as $paramName) + { + $value = null; + $name = ucfirst(sfInflector::camelize($paramName)); + + $found = false; + foreach (array('getFeed'.$name, 'get'.$name) as $methodName) + { + if (method_exists($item, $methodName)) + { + $value = $item->$methodName(); + $found = true; + break; + } + } + + if (!$found) + { + if (array_key_exists($paramName, $defaults)) + { + $value = $defaults[$paramName]; + } + else + { + $error = 'Cannot find a "getFeed%s()" or "get%s()" method for object "%s" to generate URL with the "%s" route'; + $error = sprintf($error, $name, $name, get_class($item), $routeName); + throw new sfException($error); + } + } + + $params[] = $paramName.'='.$value; + } + } + + return sfContext::getInstance()->getController()->genUrl($routeName.($params ? '?'.implode('&', $params) : ''), true); + } + + foreach (array('getFeedLink', 'getLink', 'getUrl') as $methodName) + { + if (method_exists($item, $methodName)) + { + return sfContext::getInstance()->getController()->genUrl($item->$methodName(), true); + } + } + + if ($fallback_url) + { + return sfContext::getInstance()->getController()->genUrl($fallback_url, true); + } + else + { + return sfContext::getInstance()->getController()->genUrl('/', true); + } + } + + private static function getItemFeedDescription($item) + { + foreach (array('getFeedDescription', 'getDescription', 'getBody') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + return ''; + } + + private static function getItemFeedContent($item) + { + foreach (array('getFeedContent', 'getContent', 'getHtmlBody', 'getBody') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + return ''; + } + + private static function getItemFeedUniqueId($item) + { + foreach (array('getFeedUniqueId', 'getUniqueId', 'getId') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + return ''; + } + + private static function getItemFeedAuthorEmail($item) + { + foreach (array('getFeedAuthorEmail', 'getAuthorEmail') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + // author as an object link + if ($author = self::getItemFeedAuthor($item)) + { + foreach (array('getEmail', 'getMail') as $methodName) + { + if (method_exists($author, $methodName)) + { + return $author->$methodName(); + } + } + } + + return ''; + } + + private static function getItemFeedAuthorName($item) + { + foreach (array('getFeedAuthorName', 'getAuthorName') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + // author as an object link + if ($author = self::getItemFeedAuthor($item)) + { + foreach (array('getName', '__toString') as $methodName) + { + if (method_exists($author, $methodName)) + { + return $author->$methodName(); + } + } + } + + return ''; + } + + private static function getItemFeedAuthorLink($item) + { + foreach (array('getFeedAuthorLink', 'getAuthorLink') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + // author as an object link + if ($author = self::getItemFeedAuthor($item)) + { + foreach (array('getLink') as $methodName) + { + if (method_exists($author, $methodName)) + { + return $author->$methodName(); + } + } + } + + return ''; + } + + private static function getItemFeedAuthor($item) + { + foreach (array('getAuthor', 'getUser', 'getPerson') as $methodName) + { + if (method_exists($item, $methodName) && is_object($item->$methodName())) + { + return $item->$methodName(); + } + } + + return null; + } + + private static function getItemFeedPubdate($item) + { + foreach (array('getFeedPubdate', 'getPubdate', 'getCreatedAt', 'getDate') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName('U'); + } + } + + return ''; + } + + private static function getItemFeedComments($item) + { + foreach (array('getFeedComments', 'getComments') as $methodName) + { + if (method_exists($item, $methodName)) + { + return $item->$methodName(); + } + } + + return ''; + } + + private static function getItemFeedCategories($item) + { + foreach (array('getFeedCategories', 'getCategories') as $methodName) + { + if (method_exists($item, $methodName) && is_object($item->$methodName())) + { + // categories as an object + $categories = $item->$methodName(); + if (is_array($categories)) + { + $cats = array(); + foreach ($categories as $category) + { + $cats[] = (string) $category; + } + + return $cats; + } + } + } + + return array(); + } + + private static function getItemFeedEnclosure($item) + { + if (method_exists($item, 'getFeedEnclosure')) + { + return $item->getFeedEnclosure(); + } + + return ''; + } + +} + +?> diff --git a/plugins/sfFeed2Plugin/lib/sfRss091Feed.class.php b/plugins/sfFeed2Plugin/lib/sfRss091Feed.class.php new file mode 100644 index 0000000..18f0c9e --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfRss091Feed.class.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package sfFeed2 + * @author Fabien Potencier + * @version SVN: $Id: sfRssUserland091Feed.class.php 460 2006-01-18 14:45:19Z fabien $ + */ +class sfRss091Feed extends sfRssFeed +{ + protected + $version = '0.91'; + +} + +?> \ No newline at end of file diff --git a/plugins/sfFeed2Plugin/lib/sfRss10Feed.class.php b/plugins/sfFeed2Plugin/lib/sfRss10Feed.class.php new file mode 100644 index 0000000..96f4e81 --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfRss10Feed.class.php @@ -0,0 +1,153 @@ + + * (c) 2004-2007 Francois Zaninotto + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Specification: http://web.resource.org/rss/1.0/spec + * http://web.resource.org/rss/1.0/modules/dc/ + * http://web.resource.org/rss/1.0/modules/syndication/ + * + * @package sfFeed2 + * @author Fabien Potencier + * @author Francois Zaninotto + */ +class sfRss10Feed extends sfRssFeed +{ + + /** + * Populate the feed object from a XML feed string. + * + * @param string A XML feed (RSS 1.0 format). + * + * @return sfRss10Feed The current object. + * + * @throws Exception If the argument is not a well-formatted RSS feed. + */ + public function fromXml($feedXml) + { + preg_match('/^<\?xml\s*version="1\.0"\s*encoding="(.*?)\"\s*\?>$/mi', $feedXml, $matches); + if(isset($matches[1])) + { + $this->setEncoding($matches[1]); + } + + // we get rid of namespaces to avoid simpleXML headaches + $feedXml = str_replace( + array('setTitle((string) $feedXml->channel->title); + $this->setLink((string) $feedXml->channel->link); + $this->setDescription((string) $feedXml->channel->description); + + foreach($feedXml->item as $itemXml) + { + $this->addItemFromArray(array( + 'title' => (string) $itemXml->title, + 'link' => (string) $itemXml->link, + 'description' => (string) $itemXml->description, + 'content' => (string) $itemXml->encoded, + 'authorName' => (string) $itemXml->creator, + 'pubDate' => strtotime(str_replace(array('UT', 'Z'), '', (string) $itemXml->date)), + 'feed' => $this + )); + } + + return $this; + } + + /** + * Returns the the current object as a valid RSS 1.0 XML feed. + * + * @return string A RSS 1.0 XML string. + */ + public function toXml() + { + $this->initContext(); + $xml = array(); + $xml[] = 'getEncoding().'" ?>'; + $xml[] = ''; + $xml[] = ' '; + $xml[] = ' '.htmlspecialchars($this->getTitle()).''; + $xml[] = ' '.htmlspecialchars($this->context->getController()->genUrl($this->getLink(), true)).''; + $xml[] = ' '.htmlspecialchars($this->getDescription()).''; + $xml[] = ' '; + $xml[] = ' '; + $xml[] = implode("\n", $this->getFeedItemSequence()); + $xml[] = ' '; + $xml[] = ' '; + $xml[] = ' '; + $xml[] = implode("\n", $this->getFeedElements()); + $xml[] = ''; + + return implode("\n", $xml); + } + + /** + * Returns an array of tags corresponding to the feed's items sequence. + * + * @return string A list of elements. + */ + protected function getFeedItemSequence() + { + $xml = array(); + foreach ($this->getItems() as $item) + { + $xml[] = ' '; + } + + return $xml; + } + + /** + * Returns an array of tags corresponding to the feed's items. + * + * @return string An list of elements. + */ + protected function getFeedElements() + { + $xml = array(); + foreach ($this->getItems() as $item) + { + $xml[] = ' '; + $xml[] = ' '.htmlspecialchars($item->getTitle()).''; + $xml[] = ' '.htmlspecialchars($this->context->getController()->genUrl($item->getLink(), true)).''; + if ($item->getDescription()) + { + $xml[] = ' '.htmlspecialchars($item->getDescription()).''; + } + if ($item->getContent()) + { + $xml[] = ' getContent().']]>'; + } + if ($item->getAuthorName()) + { + $xml[] = ' '.htmlspecialchars($item->getAuthorName()).''; + } + if ($item->getPubdate()) + { + $xml[] = ' '.strftime('%Y-%m-%dT%H:%M:%SZ', $item->getPubdate()).''; + } + $xml[] = ' '; + } + + return $xml; + } + +} + +?> \ No newline at end of file diff --git a/plugins/sfFeed2Plugin/lib/sfRss201Feed.class.php b/plugins/sfFeed2Plugin/lib/sfRss201Feed.class.php new file mode 100644 index 0000000..33fefbc --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfRss201Feed.class.php @@ -0,0 +1,25 @@ + + * (c) 2004-2007 Francois Zaninotto + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package sfFeed2 + * @author Fabien Potencier + * @author Francois Zaninotto + */ +class sfRss201Feed extends sfRssFeed +{ + protected + $version = "2.01"; + +} + +?> \ No newline at end of file diff --git a/plugins/sfFeed2Plugin/lib/sfRssFeed.class.php b/plugins/sfFeed2Plugin/lib/sfRssFeed.class.php new file mode 100644 index 0000000..6344d20 --- /dev/null +++ b/plugins/sfFeed2Plugin/lib/sfRssFeed.class.php @@ -0,0 +1,293 @@ + + * (c) 2004-2007 Francois Zaninotto + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Specification: 2.01 http://www.rssboard.org/rss-2-0-1-rv-6 + * 0.91 http://www.rssboard.org/rss-0-9-1 + * + * @package sfFeed2 + * @author Fabien Potencier + * @author Francois Zaninotto + */ +class sfRssFeed extends sfFeed +{ + protected + $context, + $version = '2.0'; + + protected function initContext() + { + if(!$this->context) + { + $this->context = sfContext::getInstance(); + } + } + + /** + * Populate the feed object from a XML feed string. + * + * @param string A XML feed (RSS 2.0 format). + * + * @return sfRss10Feed The current object. + * + * @throws Exception If the argument is not a well-formatted RSS feed. + */ + public function fromXml($feedXml) + { + preg_match('/^<\?xml\s*version="1\.0"\s*encoding="(.*?)\"\s*\?>$/mi', $feedXml, $matches); + if(isset($matches[1])) + { + $this->setEncoding($matches[1]); + } + $feedXml = simplexml_load_string($feedXml); + if(!$feedXml) + { + throw new Exception('Error creating feed from XML: string is not well-formatted XML'); + } + + $authorString = (string) $feedXml->channel[0]->managingEditor; + $pos = strpos($authorString, '('); + if($pos !== false) + { + $this->setAuthorEmail(trim(substr($authorString, 0, $pos))); + $this->setAuthorName(trim(substr($authorString, $pos+1, strlen($authorString)-$pos-2))); + } + else + { + $this->setAuthorEmail(trim($authorString)); + } + $this->setTitle((string) $feedXml->channel[0]->title); + $this->setLink((string) $feedXml->channel[0]->link); + $this->setDescription((string) $feedXml->channel[0]->description); + $this->setLanguage((string) $feedXml->channel[0]->language); + + $categories = array(); + foreach($feedXml->channel[0]->category as $category) + { + $categories[] = (string) $category; + } + $this->setCategories($categories); + + foreach($feedXml->channel[0]->item as $itemXml) + { + $url = (string) $itemXml->link; + $authorString = (string) $itemXml->author; + $pos = strpos($authorString, '('); + if($pos !== false) + { + $authorEmail = trim(substr($authorString, 0, $pos)); + $authorName = trim(substr($authorString, $pos+1, strlen($authorString)-$pos-2)); + } + else + { + $authorEmail = trim($authorString); + $authorName = ''; + } + $dc = $itemXml->children("http://purl.org/dc/elements/1.1/"); + if(!$authorName) + { + $authorName = (string) $dc->creator; + } + $pubdate = strtotime(str_replace(array('UT', 'Z'), '', (string) $itemXml->pubDate)); + if(!$pubdate) + { + if((string) $dc->date) + { + $pubdate = strtotime(str_replace(array('UT', 'Z'), '', (string) $dc->date)); + } + else if(preg_match('/\d{4}\/\d{2}\/\d{2}/', $url, $matches)) + { + $pubdate = strtotime($matches[0]); + } + else + { + $pubdate = 0; + } + } + $content = $itemXml->children("http://purl.org/rss/1.0/modules/content/"); + $categories = array(); + foreach($itemXml->category as $category) + { + $categories[] = (string) $category; + } + if($enclosureElement = $itemXml->enclosure) + { + $enclosure = new sfFeedEnclosure(); + $enclosure->setUrl((string) $enclosureElement['url']); + $enclosure->setLength((string) $enclosureElement['length']); + $enclosure->setMimeType((string) $enclosureElement['type']); + } + else + { + $enclosure = null; + } + $this->addItemFromArray(array( + 'title' => (string) $itemXml->title, + 'link' => $url, + 'description' => (string) $itemXml->description, + 'content' => (string) $content->encoded, + 'authorName' => $authorName, + 'authorEmail' => $authorEmail, + 'pubDate' => $pubdate, + 'comments' => (string) $itemXml->comments, + 'uniqueId' => (string) $itemXml->guid, + 'enclosure' => $enclosure, + 'categories' => $categories, + 'feed' => $this + )); + } + } + + /** + * Returns the the current object as a valid RSS 1.0 XML feed + * And sets the response content type accordingly. + * + * @return string A RSS 2.0 XML string. + */ + public function asXml() + { + $this->initContext(); + $this->context->getResponse()->setContentType('application/rss+xml'); + + return $this->toXml(); + } + + /** + * Returns the the current object as a valid RSS 1.0 XML feed. + * + * @return string A RSS 2.0 XML string. + */ + public function toXml() + { + $this->initContext(); + $xml = array(); + $xml[] = 'getEncoding().'" ?>'; + $xml[] = ''; + $xml[] = ' '; + $xml[] = ' '.$this->getTitle().''; + $xml[] = ' '.$this->context->getController()->genUrl($this->getLink(), true).''; + $xml[] = ' '.$this->getDescription().''; + $xml[] = ' '.strftime('%Y-%m-%dT%H:%M:%SZ', $this->getLatestPostDate()).''; + if ($this->getAuthorEmail()) + { + $xml[] = ' '.$this->getAuthorEmail().($this->getAuthorName() ? ' ('.$this->getAuthorName().')' : '').''; + } + if (!$this->getAuthorEmail() && $this->getAuthorName()) + { + $xml[] = ' '.$this->getAuthorName().''; + } if ($this->getLanguage()) + { + $xml[] = ' '.$this->getLanguage().''; + } + if(strpos($this->version, '2.') !== false) + { + if(is_array($this->getCategories())) + { + foreach ($this->getCategories() as $category) + { + $xml[] = ' '.$category.''; + } + } + } + $xml[] = implode("\n", $this->getFeedElements()); + $xml[] = ' '; + $xml[] = ''; + + return implode("\n", $xml); + } + + /** + * Returns an array of tags corresponding to the feed's items. + * + * @return string An list of elements. + */ + protected function getFeedElements() + { + $xml = array(); + foreach ($this->getItems() as $item) + { + $xml[] = ' '; + $xml[] = ' '.htmlspecialchars($item->getTitle()).''; + $xml[] = ' '.$this->context->getController()->genUrl($item->getLink(), true).''; + if ($item->getDescription()) + { + $xml[] = ' '.htmlspecialchars($item->getDescription()).''; + } + if ($item->getContent()) + { + $xml[] = ' getContent().']]>'; + } + if(strpos($this->version, '2.') !== false) + { + if ($item->getUniqueId()) + { + $xml[] = ' '.$item->getUniqueId().''; + } + + // author information + if ($item->getAuthorEmail()) + { + $xml[] = sprintf(' %s%s', $item->getAuthorEmail(), ($item->getAuthorName()) ? ' ('.$item->getAuthorName().')' : ''); + } + if ($item->getPubdate()) + { + $xml[] = ' '.strftime('%Y-%m-%dT%H:%M:%SZ', $item->getPubdate()).''; + } + if (is_string($item->getComments())) + { + $xml[] = ' '.htmlspecialchars($item->getComments()).''; + } + + // enclosure + if ($enclosure = $item->getEnclosure()) + { + $enclosure_attributes = sprintf('url="%s" length="%s" type="%s"', $enclosure->getUrl(), $enclosure->getLength(), $enclosure->getMimeType()); + $xml[] = ' '; + } + + // categories + if(is_array($item->getCategories())) + { + foreach ($item->getCategories() as $category) + { + $xml[] = ' '.$category.''; + } + } + } + $xml[] = ' '; + } + + return $xml; + } + + public function initialize($feed_array) + { + $this->setVersion(isset($feed_array['version']) ? $feed_array['version'] : ''); + parent::initialize($feed_array); + + return $this; + } + + public function setVersion($version) + { + if($version) + { + $this->version = $version; + } + } + + public function getVersion() + { + return $this->version; + } +} + +?> diff --git a/plugins/sfGoogleAnalyticsPlugin/LICENSE b/plugins/sfGoogleAnalyticsPlugin/LICENSE new file mode 100644 index 0000000..0384df3 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2007 Kris Wallsmith + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfGoogleAnalyticsPlugin/README b/plugins/sfGoogleAnalyticsPlugin/README new file mode 100644 index 0000000..4eed8bc --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/README @@ -0,0 +1,274 @@ += sfGoogleAnalyticsPlugin plugin = + +Easily add [http://www.google.com/analytics Google Analytics] tracking code to your presentation layer. + +''This documentation is a work in progress. Thank you for your patience.'' + +== Installation == + +=== 1. Install === + +You can install using the `plugin-install` task: + +{{{ +php symfony plugin-install sfGoogleAnalyticsPlugin +}}} + +You can also pull the code directly from the [http://svn.symfony-project.org/plugins/sfGoogleAnalyticsPlugin/trunk Subversion repository] using a `svn checkout` or the `svn:externals` property on your project's `/plugins` directory. + +Once the plugin code is accessible to your project, you need to add the `sfGoogleAnalyticsFilter` to your filter chain: + +{{{ +#!yaml +rendering: ~ +security: ~ + +# insert your own filters here +sf_google_analytics_plugin: + class: sfGoogleAnalyticsFilter + +cache: ~ +common: ~ +execution: ~ +}}} + +''NOTE: This is the symfony 1.1 `filters.yml` file. The equivalent symfony 1.0 file looks slightly different.'' + +=== 2. Configure === + +Basic configuration is done in your application's `app.yml` file: + +{{{ +#!yaml +all: + sf_google_analytics_plugin: + enabled: on + profile_id: XX-XXXXX-X + tracker: google +}}} + +You'll have to copy the `profile_id` value out of the tracking code Google supplies for your site profile. This value typically starts with the letter U and ends with a single digit. + +This plugin defaults to using the older `urchin` tracker. To take advantage of the latest featureset of Google Analytics, change the `tracker` value to `google`. This will insert the new `ga.js` tracking code into your project. + +== Advanced Usage == + +This plugin provides much more functionality than a simple insert of your tracking code. Here are some highlights: + +=== How do I customize the name a page is tracked as? === + +If you would like to track a certain page as something other than what appears in the browser address bar, you can do so by modifying the `page_name` parameter in `module.yml`: + +{{{ +#!yaml +all: + myAction: + sf_google_analytics_plugin: + params: + page_name: something_else +}}} + +For finer control over when the alternate page name is used, you can access the tracker object directly in your action. This also exposes additional funcionality. + +==== Option: `use_flash` ==== + +For example, if you want to track a successful form submission for a form that redirects to the same page on success and on error: + +{{{ +#!php +getTracker()->setPageName('/contact/success', array( + 'use_flash' => true, + )); + + $this->setFlash('feedback', 'Thank you!'); + + $this->redirect('main/contact'); + } + } +} +}}} + +In this example, the request after the successful form post will be tracked as `/contact/success`. + +==== Option: `is_route` ==== + +One more option available is the `is_route` option. When this flag is applied, the string provided for a page name will be passed through `sfRouting` before being added to the page. Using this option allows you to centralize all URLs, those real and for tracking purposes only, in your application's `routing.yml` file: + +{{{ +#!yaml +contact: + url: /contact + param: { module: main, action: contact } + +# be sure the tracking rule comes AFTER the real rule so the application +# doesn't use it for any url_for('main/contact') calls +track_contact: + url: /contact/success + param: { module: main, action: contact } +}}} + +{{{ +#!php +getTracker()->setPageName('@track_contact', array( + 'use_flash' => true, + 'is_route' => true, + )); + + $this->setFlash('feedback', 'Thank you!'); + + $this->redirect('@contact'); + } + } +} +}}} + +=== How do I selectively disable tracking? === + +You can easily configure the tracking code for a single module or even a single action by using the `module.yml` configuration file: + +{{{ +#!yaml +all: + # disable tracking for this module... + sf_google_analytics_plugin: + params: + enabled off + + # ...or for a single action + index: + sf_google_analytics_plugin: + params: + enabled off +}}} + +Alternatively, you can access the tracker object directly from inside your action: + +{{{ +#!php +getTracker()->setEnabled(false); + } +} +}}} + +=== Can I insert the tracking code at the top of my page? === + +You can configure this in `app.yml`: + +{{{ +#!yaml +all: + sf_google_analytics_plugin: + profile_id: XX-XXXXX-X + insertion: top +}}} + +=== Can I track demographic information? === + +You can expose whatever information you store on your users (that your privacy policy allows, of course) to Google Analytics. This is best done in your sign-in routine. For example, if you're using [wiki:sfGuardPlugin]: + +{{{ +#!php +getProfile()->getGender()) + { + $this->getTracker()->setVar('gender/'.$gender, array( + 'use_flash' => true, + )); + } + if ($this->hasCredential('moderator')) + { + $this->getTracker()->setVar('userType/moderator', array( + 'use_flash' => true, + )); + } + } +} +}}} + +== Changelog == + +=== Version 1.1.2 === + + * Fixed symfony 1.1 compatibility in `sfLogger` interactions. + +=== Version 1.1.1 === + + * Fixed Javascript case-sensitivity bug. + +=== Version 1.1.0 === + + * '''Added support for new Google Javascript library (`ga.js`).''' + * Updated API to include more human-readable method names. + * Added support for tracking e-commerce transactions. + * Added option to parse tracking argument with `sfRouting`. + * Added option to defer many tracker calls to the next response, similar to `sfFlash` storage (helpful for redirects). + +=== Version 1.0-RC1 === + + * Renamed plugin from sfUrchinPlugin to sfGoogleAnalyticsPlugin. + +=== Version 0.3.1-beta === + + * Bugfix to insertion top to accommodate `` tags with attributes. + +=== Version 0.3.0-beta === + + * Broke filter logic into protected methods for easy overloading. + * Added insertion configuration. + +=== Version 0.2.0-beta === + + * Added support for SSL requests. + * Added mixin methods to actions for easy modification of initialization variables and parameters. + * Added escaping of Javascript values. + +=== Version 0.1.0-beta === + + * Initial public release. + +== Maintainers == + +Kris Wallsmith + diff --git a/plugins/sfGoogleAnalyticsPlugin/config/app.yml b/plugins/sfGoogleAnalyticsPlugin/config/app.yml new file mode 100644 index 0000000..d682d4b --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/config/app.yml @@ -0,0 +1,33 @@ +# all: +# sf_google_analytics_plugin: +# enabled: off +# profile_id: XX-XXXXX-X +# insertion: bottom +# tracker: urchin +# classes: +# urchin: sfGoogleAnalyticsTrackerUrchin +# google: sfGoogleAnalyticsTrackerGoogle +# +# # tracker configuration, all optional +# params: +# page_name: ~ # this setting should be used in module.yml, not app.yml +# domain_name: ~ +# linker_policy: off +# organic_referers: [{ name: ~, param: ~ }] +# vars: [] # this setting also makes more sense to use in module.yml, not app.yml +# cookie_path: / +# client_info_policy: on +# hash_policy: on +# detect_flash_policy: on +# detect_title_policy: on +# session_timeout: 3600 # 30 minutes +# cookie_timeout: 31536000 # six months +# campaign_keys: { name: ~, source: ~, medium: ~, term: ~, content: ~, id: ~, no_override: ~ } +# anchor_policy: off +# ignored_organics: [] +# ignored_referers: [] +# sample_rate: 100 # 100% +# local_remote_server_policy: off +# +# # specific to "google" tracker +# tracker_var: pageTracker diff --git a/plugins/sfGoogleAnalyticsPlugin/config/config.php b/plugins/sfGoogleAnalyticsPlugin/config/config.php new file mode 100644 index 0000000..3099073 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/config/config.php @@ -0,0 +1,30 @@ +dispatcher->connect('request.method_not_found', $listener); + $this->dispatcher->connect('response.method_not_found', $listener); + $this->dispatcher->connect('component.method_not_found', $listener); + $this->dispatcher->connect('user.method_not_found', $listener); +} +else +{ + // symfony 1.0 + $getter = array('sfGoogleAnalyticsMixin', 'getTracker'); + $setter = array('sfGoogleAnalyticsMixin', 'setTracker'); + + sfMixer::register('sfRequest', $getter); + sfMixer::register('sfRequest', $setter); + + sfMixer::register('sfResponse', $getter); + sfMixer::register('sfResponse', $setter); + + sfMixer::register('sfComponent', $getter); + sfMixer::register('sfComponent', $setter); + + sfMixer::register('sfUser', $getter); + sfMixer::register('sfUser', $setter); +} diff --git a/plugins/sfGoogleAnalyticsPlugin/config/module.yml b/plugins/sfGoogleAnalyticsPlugin/config/module.yml new file mode 100644 index 0000000..be63ced --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/config/module.yml @@ -0,0 +1,9 @@ +# all: +# sf_google_analytics_plugin: +# # see params section of app.yml +# params: {} +# +# action_name: +# sf_google_analytics_plugin: +# # see params section of app.yml +# params: {} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/filter/sfGoogleAnalyticsFilter.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/filter/sfGoogleAnalyticsFilter.class.php new file mode 100644 index 0000000..9db87c9 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/filter/sfGoogleAnalyticsFilter.class.php @@ -0,0 +1,110 @@ + + * @version SVN: $Id: sfGoogleAnalyticsFilter.class.php 9604 2008-06-16 17:00:03Z Kris.Wallsmith $ + */ +class sfGoogleAnalyticsFilter extends sfFilter +{ + /** + * Insert tracking code for applicable web requests. + * + * @param sfFilterChain $filterChain + */ + public function execute($filterChain) + { + $prefix = 'app_sf_google_analytics_plugin_'; + $user = $this->context->getUser(); + $request = $this->context->getRequest(); + $response = $this->context->getResponse(); + + if ($this->isFirstCall()) + { + $classes = array_merge(array( + 'urchin' => 'sfGoogleAnalyticsTrackerUrchin', + 'google' => 'sfGoogleAnalyticsTrackerGoogle'), sfConfig::get($prefix.'classes', array())); + $class = $classes[sfConfig::get($prefix.'tracker', 'urchin')]; + + $tracker = new $class($this->context); + + // pull callables from session storage + $callables = $user->getAttribute('callables', array(), 'sf_google_analytics_plugin'); + foreach ($callables as $callable) + { + list($method, $arguments) = $callable; + call_user_func_array(array($tracker, $method), $arguments); + } + + $request->setTracker($tracker); + } + + $filterChain->execute(); + $tracker = $request->getTracker(); + + // apply module- and action-level configuration + $module = $this->context->getModuleName(); + $action = $this->context->getActionName(); + + $moduleParams = sfConfig::get('mod_'.$module.'_sf_google_analytics_plugin_params', array()); + $tracker->configure($moduleParams); + + $actionConfig = sfConfig::get('mod_'.$module.'_'.$action.'_sf_google_analytics_plugin', array()); + if (isset($actionConfig['params'])) + { + $tracker->configure($actionConfig['params']); + } + + // insert tracking code + if ($this->isTrackable() && $tracker->isEnabled()) + { + if (sfConfig::get('sf_logging_enabled')) + { + sfGoogleAnalyticsToolkit::logMessage($this, 'Inserting tracking code.'); + } + + $tracker->insert($response); + } + elseif (sfConfig::get('sf_logging_enabled')) + { + sfGoogleAnalyticsToolkit::logMessage($this, 'Tracking code not inserted.'); + } + + $user->getAttributeHolder()->removeNamespace('sf_google_analytics_plugin'); + $tracker->shutdown($user); + } + + /** + * Test whether the response is trackable. + * + * @return bool + */ + protected function isTrackable() + { + $request = $this->context->getRequest(); + $response = $this->context->getResponse(); + $controller = $this->context->getController(); + + // don't add analytics: + // * for XHR requests + // * if not HTML + // * if 304 + // * if not rendering to the client + // * if HTTP headers only + if ($request->isXmlHttpRequest() || + strpos($response->getContentType(), 'html') === false || + $response->getStatusCode() == 304 || + $controller->getRenderMode() != sfView::RENDER_CLIENT || + $response->isHeaderOnly()) + { + return false; + } + else + { + return true; + } + } +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/helper/GoogleAnalyticsHelper.php b/plugins/sfGoogleAnalyticsPlugin/lib/helper/GoogleAnalyticsHelper.php new file mode 100644 index 0000000..fa81833 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/helper/GoogleAnalyticsHelper.php @@ -0,0 +1,213 @@ + + * @version SVN: $Id: GoogleAnalyticsHelper.php 9604 2008-06-16 17:00:03Z Kris.Wallsmith $ + */ + +sfLoader::loadHelpers(array('Tag', 'Url')); + +/** + * Build a link that tracks a page view. + * + * Options can include: + * + * * track_as: an internal URI other than the link's href + * * is_route: whether to send the URI through sfRouting + * * is_event: track as an event rather than a page view + * * use_linker: use this if you're linking to another domain that tracks on + * the same website profile + * + * @param string $name + * @param string $internalUri + * @param array $options + * + * @return string + */ +function google_analytics_link_to($name = null, $internalUri = null, $options = array()) +{ + $tracker = sfContext::getInstance()->getRequest()->getTracker(); + + $options = _parse_attributes($options); + $trackerOptions = $tracker->extractViewOptions($options); + + if ($tracker->isEnabled()) + { + $trackAs = isset($trackerOptions['track_as']) ? $trackerOptions['track_as'] : $internalUri; + + if (isset($trackerOptions['use_linker']) && $trackerOptions['use_linker']) + { + $onclick = google_analytics_linker_function($trackAs, $trackerOptions); + } + else + { + $onclick = $tracker->forgePageViewFunction($trackAs, $trackerOptions); + } + + $options['onclick'] = isset($options['onclick']) ? ($onclick.$options['onclick']) : $onclick; + + if (isset($trackerOptions['use_linker']) && $trackerOptions['use_linker']) + { + $options['onclick'] .= 'return false'; + } + } + + return link_to($name, $internalUri, $options); +} + +/** + * Build a Javascript link that tracks a page view. + * + * Options can include: + * + * * track_as: an internal URI (required) + * * is_route: whether to send the URI through sfRouting + * * is_event: track as an event rather than a page view (for those trackers + * that support this option) + * + * @throws sfViewException if "track_as" option is absent + * + * @param string $name + * @param string $internalUri + * @param array $options + * + * @return string + */ +function google_analytics_link_to_function($name, $function, $options = array()) +{ + sfLoader::loadHelpers(array('Javascript')); + + $tracker = sfContext::getInstance()->getRequest()->getTracker(); + + $options = _parse_attributes($options); + $trackerOptions = $tracker->extractViewOptions($options); + + $link = link_to_function($name, $function, $options); + $link = _add_onclick_tracking($tracker, $link, $trackerOptions); + + return $link; +} + +/** + * Build a Javascript link that tracks a page view. + * + * Options (2nd parameter) can include: + * + * * track_as: an internal URI (required) + * * is_route: whether to send the URI through sfRouting + * * is_event: track as an event rather than a page view (for those trackers + * that support this option) + * + * @throws sfViewException if "track_as" option is absent + * + * @param string $name + * @param array $options + * @param array $html_options + * + * @return string + */ +function google_analytics_link_to_remote($name, $options = array(), $html_options = array()) +{ + sfLoader::loadHelpers(array('Javascript')); + + $tracker = sfContext::getInstance()->getRequest()->getTracker(); + + $options = _parse_attributes($options); + $trackerOptions = $tracker->extractViewOptions($options); + + $link = link_to_remote($name, $options, $html_options); + $link = _add_onclick_tracking($tracker, $link, $trackerOptions); + + return $link; +} + +/** + * Build a call to the Javascript linker function. + * + * @param string $url + * + * @return string + */ +function google_analytics_linker_function($url) +{ + $tracker = sfContext::getInstance()->getRequest()->getTracker(); + + _check_linker_settings($tracker); + + $linker = null; + if ($tracker->isEnabled()) + { + $linker = $tracker->forgeLinkerFunction($url); + } + + return $linker; +} + +/** + * Build a call to the Javascript POST linker function. + * + * @param string $formElement + * + * @return string + */ +function google_analytics_post_linker_function($formElement = 'this') +{ + $tracker = sfContext::getInstance()->getRequest()->getTracker(); + + _check_linker_settings($tracker); + + $linker = null; + if ($tracker->isEnabled()) + { + $linker = $tracker->forgePostLinkerFunction($formElement); + } + + return $linker; +} + +/** + * Inserts a page view into the supplied link's onclick attribute. + * + * @throws sfViewException if "track_as" option is absent + * + * @param sfGoogleAnalyticsTracker $tracker + * @param string $link + * @param array $options + * + * @return string + */ +function _add_onclick_tracking(sfGoogleAnalyticsTracker $tracker, $link, $options = array()) +{ + if (!isset($options['track_as'])) + { + throw new sfViewException(sprintf('{%s} The "track_as" parameter is required.', basename(__FILE__))); + } + + $tracker = sfContext::getInstance()->getRequest()->getTracker(); + if ($tracker->isEnabled()) + { + $onclick = $tracker->forgePageViewFunction($options['track_as'], $options); + $onclick = escape_once($onclick); + + $link = str_replace('onclick="', 'onclick="'.$onclick.' ', $link); + } + + return $link; +} + +/** + * Confirm the tracker is configured correctly to support a linker. + * + * @param sfGoogleAnalyticsTracker $tracker + */ +function _check_linker_settings(sfGoogleAnalyticsTracker $tracker) +{ + if ($tracker->getDomainName() !== 'none' || $tracker->getLinkerPolicy() !== true) + { + sfGoogleAnalyticsToolkit::logMessage(basename(__FILE__), 'If tracking multiple domain names on one profile, the app.yml "domain_name" setting should be "off" and the "linker_policy" setting should be "on".', 'notice'); + } +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/listener/sfGoogleAnalyticsListener.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/listener/sfGoogleAnalyticsListener.class.php new file mode 100644 index 0000000..1f7cb4f --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/listener/sfGoogleAnalyticsListener.class.php @@ -0,0 +1,36 @@ + + * @version SVN: $Id: sfGoogleAnalyticsListener.class.php 8635 2008-04-26 23:23:23Z Kris.Wallsmith $ + */ +class sfGoogleAnalyticsListener +{ + /** + * Get the current tracker object. + * + * @param sfEvent $event + * + * @return bool + */ + public static function observe(sfEvent $event) + { + $subject = $event->getSubject(); + + switch ($event['method']) + { + case 'getTracker': + $event->setReturnValue(sfGoogleAnalyticsMixin::getTracker($subject)); + return true; + + case 'setTracker': + sfGoogleAnalyticsMixin::setTracker($subject, $event['arguments'][0]); + return true; + } + } + +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/mixin/sfGoogleAnalyticsMixin.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/mixin/sfGoogleAnalyticsMixin.class.php new file mode 100644 index 0000000..7f54f1b --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/mixin/sfGoogleAnalyticsMixin.class.php @@ -0,0 +1,36 @@ + + * @version SVN: $Id: sfGoogleAnalyticsMixin.class.php 8635 2008-04-26 23:23:23Z Kris.Wallsmith $ + */ +class sfGoogleAnalyticsMixin +{ + /** + * Get the current request's tracker object. + * + * @param mixed $mixable + * + * @return sfGoogleAnalyticsTracker + */ + public static function getTracker($mixable) + { + return sfContext::getInstance()->getRequest()->getAttribute('tracker', null, 'sf_google_analytics_plugin'); + } + + /** + * Set the current request's tracker object. + * + * @param mixed $mixable + * @param sfGoogleAnalyticsTracker $tracker + */ + public static function setTracker($mixable, sfGoogleAnalyticsTracker $tracker) + { + sfContext::getInstance()->getRequest()->setAttribute('tracker', $tracker, 'sf_google_analytics_plugin'); + } + +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTracker.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTracker.class.php new file mode 100644 index 0000000..30e49a8 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTracker.class.php @@ -0,0 +1,945 @@ + + * @version SVN: $Id: sfGoogleAnalyticsTracker.class.php 9604 2008-06-16 17:00:03Z Kris.Wallsmith $ + */ +abstract class sfGoogleAnalyticsTracker +{ + const + POSITION_TOP = 'top', + POSITION_BOTTOM = 'bottom'; + + protected + $context = null, + $parameterHolder = null, + $beforeTrackerJS = null, + $afterTrackerJS = null, + + $enabled = false, + $profileId = null, + $insertion = null, + $domainName = null, + $pageName = null, + $linkerPolicy = false, + $localRemoteServerPolicy = false, + $anchorPolicy = false, + $clientInfoPolicy = true, + $hashPolicy = true, + $detectFlashPolicy = true, + $detectTitlePolicy = true, + $organicReferers = array(), + $ignoredOrganics = array(), + $ignoredReferers = array(), + $campaignNameKey = null, + $campaignSourceKey = null, + $campaignMediumKey = null, + $campaignTermKey = null, + $campaignContentKey = null, + $campaignIdKey = null, + $campaignNoOverrideKey = null, + $sampleRate = null, + $sessionTimeout = null, + $cookieTimeout = null, + $cookiePath = null, + $vars = array(), + $transaction = null; + + public function __construct($context, $parameters = array()) + { + $this->initialize($context, $parameters); + } + + public function initialize($context, $parameters = array()) + { + $this->context = $context; + + $this->parameterHolder = class_exists('sfNamespacedParameterHolder') ? new sfNamespacedParameterHolder : new sfParameterHolder; + $this->parameterHolder->add($parameters); + + // apply configuration from app.yml + $prefix = 'app_sf_google_analytics_plugin_'; + + $params = sfConfig::get($prefix.'params', array()); + $params['enabled'] = sfConfig::get($prefix.'enabled'); + $params['profile_id'] = sfConfig::get($prefix.'profile_id'); + $params['insertion'] = sfConfig::get($prefix.'insertion'); + + $this->configure($params); + + return true; + } + + /** + * Apply non-null configuration values. + * + * @param array $params + */ + public function configure($params) + { + $params = array_merge(array( + 'enabled' => null, + 'insertion' => null, + 'profile_id' => null, + 'page_name' => null, + 'domain_name' => null, + 'linker_policy' => null, + 'organic_referers' => null, + 'vars' => null, + 'cookie_path' => null, + 'client_info_policy' => null, + 'hash_policy' => null, + 'detect_flash_policy' => null, + 'detect_title_policy' => null, + 'session_timeout' => null, + 'cookie_timeout' => null, + 'campaign_keys' => null, + 'anchor_policy' => null, + 'ignored_organics' => null, + 'ignored_referers' => null, + 'sample_rate' => null, + 'local_remote_server_policy' => null), $params); + + if (!is_null($params['enabled'])) + { + $this->setEnabled($params['enabled']); + } + + if (!is_null($params['profile_id'])) + { + $this->setProfileId($params['profile_id']); + } + + if (!is_null($params['page_name'])) + { + $this->setPageName($params['page_name']); + } + + if (!is_null($params['insertion'])) + { + $this->setInsertion($params['insertion']); + } + + if (!is_null($params['domain_name'])) + { + $this->setDomainName($params['domain_name']); + } + + if (!is_null($params['linker_policy'])) + { + $this->setLinkerPolicy($params['linker_policy']); + } + + if (!is_null($params['local_remote_server_policy'])) + { + $this->setLocalRemoteServerPolicy($params['local_remote_server_policy']); + } + + if (!is_null($params['anchor_policy'])) + { + $this->setAnchorPolicy($params['anchor_policy']); + } + + if (!is_null($params['client_info_policy'])) + { + $this->setClientInfoPolicy($params['client_info_policy']); + } + + if (!is_null($params['hash_policy'])) + { + $this->setHashPolicy($params['hash_policy']); + } + + if (!is_null($params['detect_flash_policy'])) + { + $this->setDetectFlashPolicy($params['detect_flash_policy']); + } + + if (!is_null($params['detect_title_policy'])) + { + $this->setDetectTitlePolicy($params['detect_title_policy']); + } + + if (!is_null($params['organic_referers'])) + { + foreach ($params['organic_referers'] as $referer) + { + is_int(key($referer)) ? + $this->addOrganicReferer($referer[0], $referer[1]) : + $this->addOrganicReferer($referer['name'], $referer['param']); + } + } + + if (!is_null($params['ignored_organics'])) + { + foreach ($params['ignored_organics'] as $keyword) + { + $this->addIgnoredOrganic($keyword); + } + } + + if (!is_null($params['ignored_referers'])) + { + foreach ($params['ignored_referers'] as $referer) + { + $this->addIgnoredReferer($referer); + } + } + + if (!is_null($params['campaign_keys'])) + { + foreach ($params['campaign_keys'] as $key => $value) + { + $method = 'setCampaign'.sfInflector::camelize($key).'Key'; + $this->$method($value); + } + } + + if (!is_null($params['sample_rate'])) + { + $this->setSampleRate($params['sample_rate']); + } + + if (!is_null($params['session_timeout'])) + { + $this->setSessionTimeout($params['session_timeout']); + } + + if (!is_null($params['cookie_timeout'])) + { + $this->setCookieTimeout($params['cookie_timeout']); + } + + if (!is_null($params['cookie_path'])) + { + $this->setCookiePath($params['cookie_path']); + } + + if (!is_null($params['vars'])) + { + foreach ($params['vars'] as $var) + { + $this->setVar($var); + } + } + } + + public function getContext() + { + return $this->context; + } + + public function getParameterHolder() + { + return $this->parameterHolder; + } + + public function getParameter($name, $default = null, $ns = null) + { + return $this->parameterHolder->get($name, $default, $ns); + } + + public function hasParameter($name, $ns = null) + { + return $this->parameterHolder->has($name, $ns); + } + + public function setParameter($name, $value, $ns = null) + { + return $this->parameterHolder->set($name, $value, $ns); + } + + /** + * Add JS to include immediately before the tracker function is called. + * + * @param string $js + * @param array $options + */ + public function setBeforeTrackerJS($js, $options = array()) + { + if ($this->prepare($js, $options)) + { + $this->beforeTrackerJS = $js; + } + } + + public function getBeforeTrackerJS() + { + return $this->beforeTrackerJS; + } + + /** + * Add JS to include at the bottom of the tracker code. + * + * @param string $js + * @param array $options + */ + public function setAfterTrackerJS($js, $options = array()) + { + if ($this->prepare($js, $options)) + { + $this->afterTrackerJS = $js; + } + } + + public function getAfterTrackerJS() + { + return $this->afterTrackerJS; + } + + /** + * Toggle tracker's enabled state. + * + * @param bool $enabled + */ + public function setEnabled($enabled) + { + $this->enabled = (bool) $enabled; + } + + public function isEnabled() + { + return $this->enabled; + } + + /** + * Set the profile ID to use for this tracker. + * + * @param string $profileId + */ + public function setProfileId($profileId) + { + $this->profileId = $profileId; + } + + public function getProfileId() + { + return $this->profileId; + } + + /** + * Set where the tracking code should be inserted into the response. + * + * @param string $insertion + * @param array $options + */ + public function setInsertion($insertion, $options = array()) + { + if ($this->prepare($insertion, $options)) + { + $this->insertion = $insertion; + } + } + + public function getInsertion() + { + return $this->insertion; + } + + /** + * Define a page other than what's in the address bar. + * + * @param string $pageName + * @param array $options + */ + public function setPageName($pageName, $options = array()) + { + if ($this->prepare($pageName, $options)) + { + $this->pageName = $pageName; + } + } + + public function getPageName() + { + return $this->pageName; + } + + /** + * Set the domain to track this website as. + * + * @param string $domainName + */ + public function setDomainName($domainName) + { + if ($domainName === false) + { + $domainName = 'none'; + } + + $this->domainName = $domainName; + } + + public function getDomainName() + { + return $this->domainName; + } + + /** + * Define a linker policy. + * + * @param bool $enabled + */ + public function setLinkerPolicy($enabled) + { + $this->linkerPolicy = (bool) $enabled; + } + + public function getLinkerPolicy() + { + return $this->linkerPolicy; + } + + /** + * Set a transaction to track in the response. + * + * @param sfGoogleAnalyticsTransaction $transaction + * @param array $options + */ + public function setTransaction(sfGoogleAnalyticsTransaction $transaction, $options = array()) + { + if ($this->prepare($transaction, $options)) + { + $this->transaction = $transaction; + } + } + + public function getTransaction() + { + return $this->transaction; + } + + /** + * Add an organic referer. + * + * @param string $name + * @param string $param + */ + public function addOrganicReferer($name, $param) + { + $this->organicReferers[] = array($name, $param); + } + + public function getOrganicReferers() + { + return $this->organicReferers; + } + + /** + * Add a custom tracking variable to this cookie. + * + * @param string $var + * @param array $options + */ + public function setVar($var, $options = array()) + { + if ($this->prepare($var, $options)) + { + $this->vars[] = $var; + } + } + + public function getVars() + { + return $this->vars; + } + + /** + * Set a path to limit the tracking cookie to. + * + * @param string $path + * @param array $options + */ + public function setCookiePath($path, $options = array()) + { + if ($this->prepare($path, $options)) + { + $this->cookiePath = $path; + } + } + + public function getCookiePath() + { + return $this->cookiePath; + } + + /** + * Define a client info detection policy. + * + * @param bool $enabled + */ + public function setClientInfoPolicy($enabled) + { + $this->clientInfoPolicy = (bool) $enabled; + } + + public function getClientInfoPolicy() + { + return $this->clientInfoPolicy; + } + + /** + * Define a hash policy. + * + * @param bool $enabled + */ + public function setHashPolicy($enabled) + { + $this->hashPolicy = (bool) $enabled; + } + + public function getHashPolicy() + { + return $this->hashPolicy; + } + + /** + * Define a flash detection policy. + * + * @param bool $enabled + */ + public function setDetectFlashPolicy($enabled) + { + $this->detectFlashPolicy = (bool) $enabled; + } + + public function getDetectFlashPolicy() + { + return $this->detectFlashPolicy; + } + + /** + * Define a title detection policy. + * + * @param bool $enabled + */ + public function setDetectTitlePolicy($enabled) + { + $this->detectTitlePolicy = $enabled; + } + + public function getDetectTitlePolicy() + { + return $this->detectTitlePolicy; + } + + /** + * Set a session timeout. + * + * @param int $seconds + */ + public function setSessionTimeout($seconds) + { + $this->sessionTimeout = (int) $seconds; + } + + public function getSessionTimeout() + { + return $this->sessionTimeout; + } + + /** + * Set a cookie timeout. + * + * @param int $seconds + */ + public function setCookieTimeout($seconds) + { + $this->cookieTimeout = (int) $seconds; + } + + public function getCookieTimeout() + { + return $this->cookieTimeout; + } + + /** + * Set a campaign name parameter key. + * + * @param string $key + */ + public function setCampaignNameKey($key) + { + $this->campaignNameKey = $key; + } + + public function getCampaignNameKey() + { + return $this->campaignNameKey; + } + + /** + * Set a campaign source parameter key. + * + * @param string $key + */ + public function setCampaignSourceKey($key) + { + $this->campaignSourceKey = $key; + } + + public function getCampaignSourceKey() + { + return $this->campaignSourceKey; + } + + /** + * Set a campaign medium parameter key. + * + * @param string $key + */ + public function setCampaignMediumKey($key) + { + $this->campaignMediumKey = $key; + } + + public function getCampaignMediumKey() + { + return $this->campaignMediumKey; + } + + /** + * Set a campaign term parameter key. + * + * @param string $key + */ + public function setCampaignTermKey($key) + { + $this->campaignTermKey = $key; + } + + public function getCampaignTermKey() + { + return $this->campaignTermKey; + } + + /** + * Set a campaign content parameter key. + * + * @param string $key + */ + public function setCampaignContentKey($key) + { + $this->campaignContentKey = $key; + } + + public function getCampaignContentKey() + { + return $this->campaignContentKey; + } + + /** + * Set a campaign ID parameter key. + * + * @param string $key + */ + public function setCampaignIdKey($key) + { + $this->campaignIdKey = $key; + } + + public function getCampaignIdKey() + { + return $this->campaignIdKey; + } + + /** + * Set a campaign no override parameter key. + * + * @param string $key + */ + public function setCampaignNoOverrideKey($key) + { + $this->campaignNoOverrideKey = $key; + } + + public function getCampaignNoOverrideKey() + { + return $this->campaignNoOverrideKey; + } + + /** + * Define an anchor policy. + * + * @param bool $enabled + */ + public function setAnchorPolicy($enabled) + { + $this->anchorPolicy = (bool) $enabled; + } + + public function getAnchorPolicy() + { + return $this->anchorPolicy; + } + + /** + * Add an ignored orgnic keyword. + * + * @param string $keyword + */ + public function addIgnoredOrganic($keyword) + { + $this->ignoredOrganics[] = $keyword; + } + + public function getIgnoredOrganics() + { + return $this->ignoredOrganics; + } + + /** + * Add an ignored referer. + * + * @param string $referer + */ + public function addIgnoredReferer($referer) + { + $this->ignoredReferers[] = $referer; + } + + public function getIgnoredReferers() + { + return $this->ignoredReferers; + } + + /** + * Set a sample rate. + * + * @param int $rate + */ + public function setSampleRate($rate) + { + $this->sampleRate = (int) $rate; + } + + public function getSampleRate() + { + return $this->sampleRate; + } + + /** + * Define a local/remove server policy. + * + * @param bool $enabled + */ + public function setLocalRemoteServerPolicy($enabled) + { + $this->localRemoteServerPolicy = (bool) $enabled; + } + + public function getLocalRemoteServerPolicy() + { + return $this->localRemoteServerPolicy; + } + + /** + * Extract options used by tracker's helper functions. + * + * View options include: + * + * * track_as + * * is_route + * * is_event + * * use_linker + * + * @param array $options + * + * @return array + */ + public function extractViewOptions(& $options) + { + $viewOptions = array(); + + foreach (array('track_as', 'is_route', 'is_event', 'use_linker') as $option) + { + if (isset($options[$option])) + { + $viewOptions[$option] = $options[$option]; + unset($options[$option]); + } + } + + return $viewOptions; + } + + /** + * Forge a call to the Javascript page view function. + * + * @param string $path + * @param array $options + * + * @return string + */ + abstract public function forgePageViewFunction($path = null, $options = array()); + + /** + * Forge a call to the Javascript linker function. + * + * @param string $path + * + * @return string + */ + abstract public function forgeLinkerFunction($url); + + /** + * Forge a call to the Javascript POST linker function. + * + * @param string $formElement + * + * @return string + */ + abstract public function forgePostLinkerFunction($formElement = 'this'); + + /** + * Insert tracking code into a response. + * + * @param sfResponse $response + */ + abstract public function insert(sfResponse $response); + + /** + * Insert content into a response. + * + * @param sfResponse $response + * @param string $content + * @param string $position + */ + protected function doInsert(sfResponse $response, $content, $position = null) + { + if ($position == null) + { + $position = self::POSITION_BOTTOM; + } + + // check for overload + $method = 'doInsert'.$position; + + if (method_exists($this, $method)) + { + call_user_func(array($this, $method), $response, $content); + } + else + { + $old = $response->getContent(); + + switch ($position) + { + case self::POSITION_TOP: + $new = preg_replace('/]*>/i', "$0\n".$content."\n", $old, 1); + break; + + case self::POSITION_BOTTOM: + $new = str_ireplace('', "\n".$content."\n", $old); + break; + } + + if ($old == $new) + { + $new .= $content; + } + + $response->setContent($new); + } + } + + /** + * Apply common options to a value. + * + * @param mixed $value + * @param mixed $options + * + * @return bool whether to continue execution + */ + protected function prepare(& $value, & $options = array()) + { + if (is_string($options)) + { + $options = sfToolkit::stringToArray($options); + } + + if (isset($options['use_flash']) && $options['use_flash']) + { + unset($options['use_flash']); + + $trace = debug_backtrace(); + + $caller = $trace[1]; + $this->plant($caller['function'], array($value, $options)); + + return false; + } + else + { + if (is_string($value) && isset($options['is_route']) && $options['is_route']) + { + $value = $this->context->getController()->genUrl($value); + unset($options['is_route']); + } + + return true; + } + } + + /** + * Plant a callable to be executed against the next request's tracker. + * + * @param string $method + * @param array $arguments + */ + protected function plant($method, $arguments = array()) + { + if (sfConfig::get('sf_logging_enabled')) + { + sfGoogleAnalyticsToolkit::logMessage($this, 'Storing call to %s method for next response.'); + } + + $callables = $this->parameterHolder->getAll('flash', array()); + $callables[] = array($method, $arguments); + + $this->parameterHolder->removeNamespace('flash'); + $this->parameterHolder->add($callables, 'flash'); + } + + /** + * Escape the provided value for Javascript evaluation. + * + * @param string $value + * + * @return string + */ + protected function escape($value) + { + if (function_exists('json_encode')) + { + $escaped = json_encode($value); + } + else + { + sfLoader::loadHelpers(array('Escaping')); + $escaped = '"'.esc_js($value).'"'; + } + + return $escaped; + } + + /** + * Update storage with callables for the next tracker. + * + * @param sfUser $user + */ + public function shutdown($user) + { + if (sfConfig::get('sf_logging_enabled')) + { + sfGoogleAnalyticsToolkit::logMessage($this, 'Copying callables to session storage.'); + } + + $user->getAttributeHolder()->set('callables', $this->parameterHolder->getAll('flash', array()), 'sf_google_analytics_plugin'); + } + +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerGoogle.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerGoogle.class.php new file mode 100644 index 0000000..d6d73ae --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerGoogle.class.php @@ -0,0 +1,242 @@ + + * @version SVN: $Id: sfGoogleAnalyticsTrackerGoogle.class.php 9429 2008-06-05 03:58:31Z Kris.Wallsmith $ + */ +class sfGoogleAnalyticsTrackerGoogle extends sfGoogleAnalyticsTracker +{ + protected + $trackerVar = 'pageTracker'; + + public function configure($params) + { + parent::configure($params); + + $params = array_merge(array( + 'tracker_var' => null), $params); + + if (!is_null($params['tracker_var'])) + { + $this->setTrackerVar($params['tracker_var']); + } + } + + public function setTrackerVar($tracker) + { + $this->trackerVar = $tracker; + } + public function getTrackerVar() + { + return $this->trackerVar; + } + + /** + * @see sfGoogleAnalyticsTracker + */ + public function insert(sfResponse $response) + { + $tracker = $this->getTrackerVar(); + + $html = array(); + $html[] = ''; + $html[] = ''; + + $html = join("\n", $html); + $this->doInsert($response, $html, $this->insertion); + } + + /** + * @see sfGoogleAnalyticsTracker + */ + public function forgePageViewFunction($path = null, $options = array()) + { + $this->prepare($path, $options); + + if (isset($options['is_event']) && $options['is_event']) + { + $func = '%s._trackEvent(%s);'; + } + else + { + $func = '%s._trackPageview(%s);'; + } + + return sprintf($func, $this->getTrackerVar(), $this->escape($path)); + } + + /** + * @see sfGoogleAnalyticsTracker + */ + public function forgeLinkerFunction($url, $options = array()) + { + return sprintf('%s._link(%s);', $this->getTrackerVar(), $this->escape($url)); + } + + /** + * @see sfGoogleAnalyticsTracker + */ + public function forgePostLinkerFunction($formElement = 'this') + { + return sprintf('%s._linkByPost(%s);', $this->getTrackerVar(), $formElement); + } + +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerUrchin.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerUrchin.class.php new file mode 100644 index 0000000..999e120 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/tracker/sfGoogleAnalyticsTrackerUrchin.class.php @@ -0,0 +1,205 @@ + + * @version SVN: $Id: sfGoogleAnalyticsTrackerUrchin.class.php 8635 2008-04-26 23:23:23Z Kris.Wallsmith $ + */ +class sfGoogleAnalyticsTrackerUrchin extends sfGoogleAnalyticsTracker +{ + /** + * @see sfGoogleAnalyticsTracker + */ + public function insert(sfResponse $response) + { + $html = array(); + $html[] = $this->context->getRequest()->isSecure() ? + '' : + ''; + $html[] = ''; + + if ($transaction = $this->getTransaction()) + { + $html[] = ''; + $html[] = ''; + $html[] = ''; + $html[] = ''; + } + + $html = join("\n", $html); + $this->doInsert($response, $html, $this->insertion); + } + + /** + * @see sfGoogleAnalyticsTracker + */ + public function forgePageViewFunction($path = null, $options = array()) + { + $this->prepare($path, $options); + + return sprintf('urchinTracker(%s);', is_null($path) ? null : $this->escape($path)); + } + + /** + * @see sfGoogleAnalyticsTracker + */ + public function forgeLinkerFunction($url) + { + return sprintf('__utmLinker(%s);', $this->escape($url)); + } + + /** + * @see sfGoogleAnalyticsTracker + */ + public function forgePostLinkerFunction($formElement = 'this') + { + return sprintf('__utmLinkPost(%s);', $formElement); + } + +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsItem.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsItem.class.php new file mode 100644 index 0000000..3285c11 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsItem.class.php @@ -0,0 +1,95 @@ + + * @version SVN: $Id: sfGoogleAnalyticsItem.class.php 8635 2008-04-26 23:23:23Z Kris.Wallsmith $ + */ +class sfGoogleAnalyticsItem +{ + protected + $orderId = null, + $sku = null, + $productName = null, + $category = null, + $unitPrice = null, + $quantity = null; + + public function getValues() + { + $values = array( + $this->getOrderId(), + $this->getSku(), + $this->getProductName(), + $this->getCategory(), + $this->getUnitPrice(), + $this->getQuantity(), + ); + + return $values; + } + + public function setOrderId($orderId) + { + $this->orderId = $orderId; + } + + public function getOrderId() + { + return $this->orderId; + } + + public function setSku($sku) + { + $this->sku = $sku; + } + + public function getSku() + { + return $this->sku; + } + + public function setProductName($name) + { + $this->productName = $name; + } + + public function getProductName() + { + return $this->productName; + } + + public function setCategory($category) + { + $this->category = $category; + } + + public function getCategory() + { + return $this->category; + } + + public function setUnitPrice($price) + { + $this->unitPrice = $price; + } + + public function getUnitPrice() + { + return $this->unitPrice; + } + + public function setQuantity($quantity) + { + $this->quantity = $quantity; + } + + public function getQuantity() + { + return $this->quantity; + } + +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsTransaction.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsTransaction.class.php new file mode 100644 index 0000000..a28cf20 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/transaction/sfGoogleAnalyticsTransaction.class.php @@ -0,0 +1,130 @@ + + * @version SVN: $Id: sfGoogleAnalyticsTransaction.class.php 8635 2008-04-26 23:23:23Z Kris.Wallsmith $ + */ +class sfGoogleAnalyticsTransaction +{ + protected + $orderId = null, + $storeName = null, + $total = null, + $tax = null, + $shipping = null, + $city = null, + $state = null, + $country = null, + $items = array(); + + public function getValues() + { + $values = array( + $this->getOrderId(), + $this->getStoreName(), + $this->getTotal(), + $this->getTax(), + $this->getShipping(), + $this->getCity(), + $this->getState(), + $this->getCountry(), + ); + + return $values; + } + + public function addItem(sfGoogleAnalyticsItem $item) + { + $this->items[] = $item; + } + + public function getItems() + { + return $this->items; + } + + public function setOrderId($orderId) + { + $this->orderId = $orderId; + } + + public function getOrderId() + { + return $this->orderId; + } + + public function setStoreName($name) + { + $this->storeName = $name; + } + + public function getStoreName() + { + return $this->storeName; + } + + public function setTotal($total) + { + $this->total = $total; + } + + public function getTotal() + { + return $this->total; + } + + public function setTax($tax) + { + $this->tax = $tax; + } + + public function getTax() + { + return $this->tax; + } + + public function setShipping($shipping) + { + $this->shipping = $shipping; + } + + public function getShipping() + { + return $this->shipping; + } + + public function setCity($city) + { + $this->city = $city; + } + + public function getCity() + { + return $this->city; + } + + public function setState($state) + { + $this->state = $state; + } + + public function getState() + { + return $this->state; + } + + public function setCountry($country) + { + $this->country = $country; + } + + public function getCountry() + { + return $this->country; + } + +} diff --git a/plugins/sfGoogleAnalyticsPlugin/lib/util/sfGoogleAnalyticsToolkit.class.php b/plugins/sfGoogleAnalyticsPlugin/lib/util/sfGoogleAnalyticsToolkit.class.php new file mode 100644 index 0000000..bf87b72 --- /dev/null +++ b/plugins/sfGoogleAnalyticsPlugin/lib/util/sfGoogleAnalyticsToolkit.class.php @@ -0,0 +1,32 @@ + + * @version SVN: $Id: sfGoogleAnalyticsToolkit.class.php 10156 2008-07-07 05:26:29Z Kris.Wallsmith $ + */ +class sfGoogleAnalyticsToolkit +{ + /** + * Log a message. + * + * @param mixed $subject + * @param string $message + * @param string $priority + */ + static public function logMessage($subject, $message, $priority = 'info') + { + if (class_exists('ProjectConfiguration')) + { + ProjectConfiguration::getActive()->getEventDispatcher()->notify(new sfEvent($subject, 'application.log', array($message, 'priority' => $priority))); + } + else + { + $message = sprintf('{%s} %s', is_object($subject) ? get_class($subject) : $subject, $message); + sfContext::getInstance()->getLogger()->log($message, constant('SF_LOG_'.strtoupper($priority))); + } + } +} diff --git a/plugins/sfGuardPlugin/LICENSE b/plugins/sfGuardPlugin/LICENSE new file mode 100644 index 0000000..28956ad --- /dev/null +++ b/plugins/sfGuardPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2004-2006 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfGuardPlugin/README b/plugins/sfGuardPlugin/README new file mode 100644 index 0000000..ca5320d --- /dev/null +++ b/plugins/sfGuardPlugin/README @@ -0,0 +1,401 @@ += sfGuard plugin = + +The `sfGuardPlugin` is a symfony plugin that provides authentication and authorization features above the standard security feature of symfony. + +It gives you the model (user, group and permission objects) and the modules (backend and frontend) to secure your symfony application in a minute in +a configurable plugin. + +== Installation == + + * Install the plugin + + {{{ + symfony plugin-install http://plugins.symfony-project.com/sfGuardPlugin + }}} + + * Rebuild your model + + {{{ + symfony propel-build-model + symfony propel-build-sql + }}} + + * Update you database tables by starting from scratch (it will delete all the existing tables, then re-create them): + + {{{ + symfony propel-insert-sql + }}} + + or you can just create the new tables by using the generated SQL statements in `data/sql/plugins.sfGuardAuth.lib.model.schema.sql` + + * Load default fixtures (optional - it creates a superadmin user) + + {{{ + symfony propel-load-data + }}} + + * Enable one or more modules in your `settings.yml` (optional) + * For your backend application: sfGuardUser, sfGuardGroup, sfGuardPermission + * For your frontend application: sfGuardAuth + + {{{ + all: + .settings: + enabled_modules: [default, sfGuardGroup, sfGuardUser, sfGuardPermission] + }}} + + * Clear you cache + + {{{ + symfony cc + }}} + + * Optionally enable the "Remember Me" filter in `filters.yml` + + {{{ + security: + class: sfGuardBasicSecurityFilter + }}} + +=== Secure your application === + +To secure a symfony application: + + * Enable the module `sfGuardAuth` in `settings.yml` + + {{{ + all: + .settings: + enabled_modules: [..., sfGuardAuth] + }}} + + * Change the default login and secure modules in `settings.yml` + + {{{ + login_module: sfGuardAuth + login_action: signin + + secure_module: sfGuardAuth + secure_action: secure + }}} + + * Change the parent class in `myUser.class.php` + + {{{ + class myUser extends sfGuardSecurityUser + { + } + }}} + + * Optionally add the following routing rules to `routing.yml` + + {{{ + sf_guard_signin: + url: /login + param: { module: sfGuardAuth, action: signin } + + sf_guard_signout: + url: /logout + param: { module: sfGuardAuth, action: signout } + + sf_guard_password: + url: /request_password + param: { module: sfGuardAuth, action: password } + }}} + + You can customize the `url` parameter of each route. + N.B.: You must have a `@homepage` routing rule (used when a user sign out) + + These routes are automatically registered by the plugin if the module `sfGuardAuth` is enabled unless you defined `sfGuardPlugin_routes_register` to false + in the `app.yml` configuration file. + + * Secure some modules or your entire application in `security.yml` + + {{{ + default: + is_secure: on + }}} + + * You're done. Now, if you try to access a secure page, you will be redirected to the login page. + If you have loaded the default fixture file, try to login with `admin` as username and `admin` as password. + +== Manage your users, permissions and groups == + +To be able to manage your users, permissions and groups, `sfGuardPlugin` comes with 3 modules that can be integrated in your backend application. +These modules are auto-generated thanks to the symfony admin generator. + + * Enable the modules in `settings.yml` + + {{{ + all: + .settings: + enabled_modules: [..., sfGuardGroup, sfGuardPermission, sfGuardUser] + }}} + + * Access the modules with the default route: + + {{{ + http://www.example.com/backend.php/sfGuardUser + }}} + +== Customize sfGuardAuth module templates == + +By default, `sfGuardAuth` module comes with 2 very simple templates: + + * `signinSuccess.php` + * `secureSuccess.php` + +If you want to customize one of these templates: + + * Create a `sfGuardAuth` module in your application + + * Create a template with the name of the template you want to customize in your `templates` directory + + * Symfony now renders your template instead of the default one + +== Customize `sfGuardAuth` module actions == + +If you want to customize or add methods to the sfGuardAuth: + + * Create a `sfGuardAuth` module in your application + + * Create an `actions.class.php` file in your `actions` directory that inherit from `BasesfGuardAuthActions` + (don't forget to include the `BasesfGuardAuthActions` as it can't be autoloaded by symfony) + + {{{ + renderText('This is a new sfGuardAuth action.'); + } + } + }}} + +== `sfGuardSecurityUser` class == + +This class inherits from the `sfBasicSecurityUser` class from symfony and is used for the `user` object in your symfony application. +(because you changed the `myUser` base class earlier) + +So, to access it, you can use the standard `$this->getUser()` in your actions or `$sf_user` in your templates. + +`sfGuardSecurityUser` adds some methods: + + * `signIn()` and `signOut()` methods + * `getGuardUser()` that returns the `sfGuardUser` object + * a bunch of proxy methods to access directly the `sfGuardUser` object + +For example, to get the current username: + + {{{ + $this->getUser()->getGuardUser()->getUsername() + + // or via the proxy method + $this->getUser()->getUsername() + }}} + +== Super administrator flag == + +`sfGuardPlugin` has a notion of super administrator. A user that is a super administrator bypasses all credential checks. + +The super administrator flag cannot be set on the web, you must set the flag directly in the database or use the pake task: + + {{{ + symfony promote-super-admin admin + }}} + +== Validators == + +`sfGuardPlugin` comes with a validator that you can use in your modules: `sfGuardUserValidator`. + +This validator is used by the `sfGuardAuth` module to validate a user and password and automatically signin the user. + +== Customize the `sfAuthUser` model == + +The `sfAuthUser` model is quite simple. There is no `email` or `first_name` or `birthday` columns. +As you cannot add methods to the class, the `sfAuthPlugin` gives you the possibility to define a user profile class. + +By default, `sfAuthUser` looks for a `sfGuardUserProfile` class. + +Here is a simple example of a `sfGuardProfile` class that you can add to `schema.yml`: + + {{{ + sf_guard_user_profile: + _attributes: { phpName: sfGuardUserProfile } + id: + user_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true, onDelete: cascade } + first_name: varchar(20) + last_name: varchar(20) + birthday: date + }}} + +You can now access the user profile via the user object: + + {{{ + $this->getUser()->getGuardUser()->getProfile()->getFirstName() + + // or via the proxy method + $this->getUser()->getProfile()->getFirstName() + }}} + +The `getProfile()` method gets the associated user profile object or creates a new one if none already exists. + +When you delete a user, the associated profile is also deleted. + +You can change the name of the user profile class and the foreign key name in `app.yml`: + + {{{ + all: + sf_guard_plugin: + profile_class: sfGuardUserProfile + profile_field_name: user_id + }}} + +== Check the user password with an external method == + +If you don't want to store the password in the database because you already have a LDAP server, a .htaccess file or if you store +your passwords in another table, you can provide your own `checkPassword` callable (static method or function) in `app.yml`: + + {{{ + all: + sf_guard_plugin: + check_password_callable: [MyLDAPClass, checkPassword] + }}} + +When symfony will call the `$this->getUser()->checkPassword()` method, it will call your method or function. Your function must takes 2 parameters, +the first one is the username and the second one is the password. It must returns true or false. Here is a template for such a function: + + {{{ + function checkLDAPPassword($username, $password) + { + $user = LDAP::getUser($username); + if ($user->checkPassword($password)) + { + return true; + } + else + { + return false; + } + } + }}} + +== Change the algorithm used to store passwords == + +By default, passwords are stored as a `sha1()` hash. But you can change this with any callable in `app.yml`: + + {{{ + all: + sf_guard_plugin: + algorithm_callable: [MyCryptoClass, MyCryptoMethod] + }}} + +or + + {{{ + all: + sf_guard_plugin: + algorithm_callable: md5 + }}} + +As the algorithm is stored for each user, you can change your mind later without the need to regenerate all passwords +for the current users. + +== Change the name or expiration period of the "Remember Me" cookie == + +By default, the "Remember Me" feature creates a cookie named `sfRemember` that will last 15 days. You can change this behavior in `app.yml`: + + {{{ + all: + sf_guard_plugin: + remember_key_expiration_age: 2592000 # 30 days in seconds + remember_cookie_name: myAppRememberMe + }}} + + +== Customize `sfGuardAuth` redirect handling == + +If you want to redirect the user to his profile after a success login or define a logout site. +You can change the redirect values in `app.yml`: + + {{{ + all: + sf_guard_plugin: + success_signin_url: @my_route?param=value # the plugin use the referer as default + success_signout_url: module/action # the plugin use the referer as default + }}} + +== TODO == + + * finish the `promote_super_user` task + * finish the `getPassword` method + * add support for HTTP Basic authentication + +== Changelog == + +=== 1.1.14 PRE === + +=== 1.1.13 === + + * fabien: fixed isAnonymous() method (#2484) + * frederic: added PluginsfGuardUser::setPasswordHash() to be able to change the password hash directly (useful when loading fixtures) + * fabien: updated documentation about creating the new tables (#2476) + * fabien: added the BasesfGuardAuthActions inclusion when extending the sfGuardAuth class (#2296) + * francois: fixed indexes on unique columns were not unique + * francois: switched to YAML schema, to allow overriding by way of sfPropelAlternativeSchemaPlugin + * francois: added `lib/model/plugin/` classes to make the model truly extensible + +=== 1.1.12 === + + * fabien: fixed typo in secureSuccess template (closes #2260) + * fabien: fixed 'secure' action in sfGuardPlugin do not need to be secure (closes #2254) + * fabien: fixed typo in sfGuardUser::getProfile() + * fabien: added some check in sfGuardSecurityUser proxy methods + +=== 1.1.11 === + + * fabien: fixed array_merge_recursive causes recursion warnings in sfGuardUser.php (closes #1834) + * fabien: fixed groups, permissions, and profile saving when sfUser has no primary key (closes #1709) + * fabien: added connection parameters to all methods that interacts with the database (closes #2237) + * fabien: changed signout actions, so it doesn't require to be authenticated + * fabien: added a ->isSuperAdmin() method to the User class + * fabien: fixed connection should be used when saving model (closes #2152) + * fabien: fixed typo in modules /sfGuardAuth/config/security.yml (closes #1930) + * fabien: removed warning about foreign key and profile table + * davedash: when displaying the signin form, if no referer is set for the user we default to the last page + * davedash: updated documentation regarding remember me cookie settings (closes #2148) + * davedash: default algorithm is now sha1 not \asha1\a (closes Ticket #2189) + * davedash: made the default templates i18n compatible (closes #1662) + +=== 1.1.10 === + + * davedash: reordered the if/elseif structure so no loop starves + +=== 1.1.9 === + + * fabien: fixed a typo in sfGuardUser reloadGroupsAndPermissions() method (closes #1758) + * fabien: fixed "Remember Me" filter documentation (closes #1705) + +=== 1.1.8 === + + * gordon: add two new config params 'success_signin_url' and 'success_signin_url' + * gordon: split 'checkPassword()' to 'checkPassword()' and 'checkPasswordByGuard()' so it is callable by your own 'check_password()' + * gordon: better redirect + * gordon: 'login_module' and 'login_action' use for 'handleErrorSignin()' and after successe login + * gordon: Added extra logic to make sure remember me code is only executed if user is not authenticated. + * fabien: fixed is_super_admin has not default value (closes #1410) + * fabien: fixed sfGuardPlugin signin.yml validation configuration (closes #1440) + * fabien: fixed missing unique indexes in sf_guard_group and sf_guard_permission (closes #1454) + * fabien: fixed sfGuardAuth should clear the credentials (closes #1537) + * davedash: giving unique indexes unique names so that sfGuardPlugin works with postgres (closes ticket #1720) + * davedash: fixed the model so getting groupPermissions works (fixes #1729) + * davedash: the signin class would keep redirecting on itself if the user is logged in + +=== 1.1.7 === + + * fabien: fixed deleting sfGuardUser when no profile is defined (closes #1626) + * davedash: The setPassword() function of sfGuardSecurityUser() now saves the sfGuardUser object after setting the password diff --git a/plugins/sfGuardPlugin/config/config.php b/plugins/sfGuardPlugin/config/config.php new file mode 100644 index 0000000..7b61504 --- /dev/null +++ b/plugins/sfGuardPlugin/config/config.php @@ -0,0 +1,11 @@ +prependRoute('sf_guard_signin', '/login', array('module' => 'sfGuardAuth', 'action' => 'signin')); + $r->prependRoute('sf_guard_signout', '/logout', array('module' => 'sfGuardAuth', 'action' => 'signout')); + $r->prependRoute('sf_guard_password', '/request_password', array('module' => 'sfGuardAuth', 'action' => 'password')); +} diff --git a/plugins/sfGuardPlugin/config/schema.yml b/plugins/sfGuardPlugin/config/schema.yml new file mode 100644 index 0000000..12c9697 --- /dev/null +++ b/plugins/sfGuardPlugin/config/schema.yml @@ -0,0 +1,48 @@ +propel: + _attributes: { package: plugins.sfGuardPlugin.lib.model } + + sf_guard_group: + _attributes: { phpName: sfGuardGroup } + id: + name: { type: varchar, size: 255, required: true, index: unique } + description: { type: longvarchar } + + sf_guard_permission: + _attributes: { phpName: sfGuardPermission } + id: + name: { type: varchar, size: 255, required: true, index: unique } + #description: { type: longvarchar } + + sf_guard_group_permission: + _attributes: { phpName: sfGuardGroupPermission } + group_id: { type: integer, primaryKey: true, required: true, foreignTable: sf_guard_group, foreignReference: id, onDelete: cascade } + permission_id: { type: integer, primaryKey: true, required: true, foreignTable: sf_guard_permission, foreignReference: id, onDelete: cascade } + + sf_guard_user: + _attributes: { phpName: sfGuardUser } + id: + username: { type: varchar, size: 128, required: true, index: unique } + algorithm: { type: varchar, size: 128, required: true, default: sha1 } + salt: { type: varchar, size: 128, required: true } + password: { type: varchar, size: 128, required: true } + created_at: + last_login: { type: timestamp } + is_active: { type: boolean, required: true, default: 1 } + is_super_admin: { type: boolean, required: true, default: 0 } + + sf_guard_user_permission: + _attributes: { phpName: sfGuardUserPermission } + user_id: { type: integer, primaryKey: true, required: true, foreignTable: sf_guard_user, foreignReference: id, onDelete: cascade } + permission_id: { type: integer, primaryKey: true, required: true, foreignTable: sf_guard_permission, foreignReference: id, onDelete: cascade } + + sf_guard_user_group: + _attributes: { phpName: sfGuardUserGroup } + user_id: { type: integer, primaryKey: true, required: true, foreignTable: sf_guard_user, foreignReference: id, onDelete: cascade } + group_id: { type: integer, primaryKey: true, required: true, foreignTable: sf_guard_group, foreignReference: id, onDelete: cascade } + + sf_guard_remember_key: + _attributes: { phpName: sfGuardRememberKey } + user_id: { type: integer, primaryKey: true, required: true, foreignTable: sf_guard_user, foreignReference: id, onDelete: cascade } + remember_key: { type: varchar, size: 32 } + ip_address: { type: varchar, size: 15, primaryKey: true } + created_at: \ No newline at end of file diff --git a/plugins/sfGuardPlugin/data/fixtures/fixtures.yml b/plugins/sfGuardPlugin/data/fixtures/fixtures.yml new file mode 100644 index 0000000..e69de29 diff --git a/plugins/sfGuardPlugin/data/tasks/sfGuardSuperAdminTask.php b/plugins/sfGuardPlugin/data/tasks/sfGuardSuperAdminTask.php new file mode 100644 index 0000000..9d2a377 --- /dev/null +++ b/plugins/sfGuardPlugin/data/tasks/sfGuardSuperAdminTask.php @@ -0,0 +1,16 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_guard_group'); + $tMap->setPhpName('sfGuardGroup'); + + $tMap->setUseIdGenerator(true); + + $tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 255); + + $tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::LONGVARCHAR, false, null); + + $tMap->addColumn('IS_EDITORIAL_TEAM', 'IsEditorialTeam', 'boolean', CreoleTypes::BOOLEAN, false, null); + + $tMap->addColumn('IS_ENABLED', 'IsEnabled', 'boolean', CreoleTypes::BOOLEAN, false, null); + + } +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/map/sfGuardGroupPermissionMapBuilder.php b/plugins/sfGuardPlugin/lib/model/map/sfGuardGroupPermissionMapBuilder.php new file mode 100644 index 0000000..f6ed4cf --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/map/sfGuardGroupPermissionMapBuilder.php @@ -0,0 +1,40 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_guard_group_permission'); + $tMap->setPhpName('sfGuardGroupPermission'); + + $tMap->setUseIdGenerator(false); + + $tMap->addForeignPrimaryKey('GROUP_ID', 'GroupId', 'int' , CreoleTypes::INTEGER, 'sf_guard_group', 'ID', true, null); + + $tMap->addForeignPrimaryKey('PERMISSION_ID', 'PermissionId', 'int' , CreoleTypes::INTEGER, 'sf_guard_permission', 'ID', true, null); + + } +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionI18nMapBuilder.php b/plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionI18nMapBuilder.php new file mode 100644 index 0000000..78b0855 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionI18nMapBuilder.php @@ -0,0 +1,42 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_guard_permission_i18n'); + $tMap->setPhpName('sfGuardPermissionI18n'); + + $tMap->setUseIdGenerator(false); + + $tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::LONGVARCHAR, true, null); + + $tMap->addForeignPrimaryKey('ID', 'Id', 'int' , CreoleTypes::INTEGER, 'sf_guard_permission', 'ID', true, null); + + $tMap->addPrimaryKey('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, true, 7); + + } +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionMapBuilder.php b/plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionMapBuilder.php new file mode 100644 index 0000000..7627f95 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionMapBuilder.php @@ -0,0 +1,40 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_guard_permission'); + $tMap->setPhpName('sfGuardPermission'); + + $tMap->setUseIdGenerator(true); + + $tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, true, 255); + + } +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/map/sfGuardRememberKeyMapBuilder.php b/plugins/sfGuardPlugin/lib/model/map/sfGuardRememberKeyMapBuilder.php new file mode 100644 index 0000000..146deb3 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/map/sfGuardRememberKeyMapBuilder.php @@ -0,0 +1,44 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_guard_remember_key'); + $tMap->setPhpName('sfGuardRememberKey'); + + $tMap->setUseIdGenerator(false); + + $tMap->addForeignPrimaryKey('USER_ID', 'UserId', 'int' , CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null); + + $tMap->addColumn('REMEMBER_KEY', 'RememberKey', 'string', CreoleTypes::VARCHAR, false, 32); + + $tMap->addPrimaryKey('IP_ADDRESS', 'IpAddress', 'string', CreoleTypes::VARCHAR, true, 15); + + $tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null); + + } +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/map/sfGuardUserGroupMapBuilder.php b/plugins/sfGuardPlugin/lib/model/map/sfGuardUserGroupMapBuilder.php new file mode 100644 index 0000000..3cea961 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/map/sfGuardUserGroupMapBuilder.php @@ -0,0 +1,40 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_guard_user_group'); + $tMap->setPhpName('sfGuardUserGroup'); + + $tMap->setUseIdGenerator(false); + + $tMap->addForeignPrimaryKey('USER_ID', 'UserId', 'int' , CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null); + + $tMap->addForeignPrimaryKey('GROUP_ID', 'GroupId', 'int' , CreoleTypes::INTEGER, 'sf_guard_group', 'ID', true, null); + + } +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/map/sfGuardUserMapBuilder.php b/plugins/sfGuardPlugin/lib/model/map/sfGuardUserMapBuilder.php new file mode 100644 index 0000000..a395f0c --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/map/sfGuardUserMapBuilder.php @@ -0,0 +1,108 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_guard_user'); + $tMap->setPhpName('sfGuardUser'); + + $tMap->setUseIdGenerator(true); + + $tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('USERNAME', 'Username', 'string', CreoleTypes::VARCHAR, true, 128); + + $tMap->addColumn('ALGORITHM', 'Algorithm', 'string', CreoleTypes::VARCHAR, true, 128); + + $tMap->addColumn('SALT', 'Salt', 'string', CreoleTypes::VARCHAR, true, 128); + + $tMap->addColumn('PASSWORD', 'Password', 'string', CreoleTypes::VARCHAR, true, 128); + + $tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null); + + $tMap->addColumn('LAST_LOGIN', 'LastLogin', 'int', CreoleTypes::TIMESTAMP, false, null); + + $tMap->addColumn('IS_ACTIVE', 'IsActive', 'boolean', CreoleTypes::BOOLEAN, true, null); + + $tMap->addColumn('IS_SUPER_ADMIN', 'IsSuperAdmin', 'boolean', CreoleTypes::BOOLEAN, true, null); + + $tMap->addColumn('IS_VERIFIED', 'IsVerified', 'boolean', CreoleTypes::BOOLEAN, false, null); + + $tMap->addColumn('SHOW_CONTENT', 'ShowContent', 'boolean', CreoleTypes::BOOLEAN, false, null); + + $tMap->addColumn('CULTURE', 'Culture', 'string', CreoleTypes::VARCHAR, false, 10); + + $tMap->addColumn('EMAIL', 'Email', 'string', CreoleTypes::VARCHAR, true, 128); + + $tMap->addColumn('EMAIL_PRIVATE', 'EmailPrivate', 'boolean', CreoleTypes::BOOLEAN, false, null); + + $tMap->addColumn('NEW_EMAIL', 'NewEmail', 'string', CreoleTypes::VARCHAR, false, 128); + + $tMap->addColumn('NEW_EMAIL_KEY', 'NewEmailKey', 'string', CreoleTypes::VARCHAR, false, 128); + + $tMap->addColumn('NEW_PASSWORD_KEY', 'NewPasswordKey', 'string', CreoleTypes::VARCHAR, false, 128); + + $tMap->addColumn('KEY_EXPIRES', 'KeyExpires', 'int', CreoleTypes::TIMESTAMP, false, null); + + $tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, false, 128); + + $tMap->addColumn('NAME_PRIVATE', 'NamePrivate', 'boolean', CreoleTypes::BOOLEAN, false, null); + + $tMap->addColumn('DOB', 'Dob', 'string', CreoleTypes::VARCHAR, true, null); + + $tMap->addColumn('SEX', 'Sex', 'int', CreoleTypes::INTEGER, true, 1); + + $tMap->addColumn('DESCRIPTION', 'Description', 'string', CreoleTypes::LONGVARCHAR, false, null); + + $tMap->addForeignKey('RESIDENCE_ID', 'ResidenceId', 'int', CreoleTypes::INTEGER, 'residence', 'ID', true, null); + + $tMap->addColumn('AVATAR', 'Avatar', 'string', CreoleTypes::VARCHAR, false, 255); + + $tMap->addColumn('MSN', 'Msn', 'string', CreoleTypes::VARCHAR, false, 128); + + $tMap->addColumn('ICQ', 'Icq', 'int', CreoleTypes::INTEGER, false, null); + + $tMap->addColumn('HOMEPAGE', 'Homepage', 'string', CreoleTypes::VARCHAR, false, 256); + + $tMap->addColumn('PHONE', 'Phone', 'string', CreoleTypes::VARCHAR, false, 32); + + $tMap->addColumn('OPT_IN', 'OptIn', 'boolean', CreoleTypes::BOOLEAN, false, null); + + $tMap->addColumn('EDITORIAL_NOTIFICATION', 'EditorialNotification', 'int', CreoleTypes::INTEGER, false, null); + + $tMap->addColumn('SHOW_LOGIN_STATUS', 'ShowLoginStatus', 'int', CreoleTypes::INTEGER, false, null); + + $tMap->addColumn('LAST_ACTIVE', 'LastActive', 'int', CreoleTypes::TIMESTAMP, false, null); + + $tMap->addColumn('DOB_IS_DERIVED', 'DobIsDerived', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('NEED_PROFILE_CHECK', 'NeedProfileCheck', 'int', CreoleTypes::INTEGER, true, 1); + + $tMap->addColumn('FIRST_REAKTOR_LOGIN', 'FirstReaktorLogin', 'int', CreoleTypes::TIMESTAMP, false, null); + + } +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/map/sfGuardUserPermissionMapBuilder.php b/plugins/sfGuardPlugin/lib/model/map/sfGuardUserPermissionMapBuilder.php new file mode 100644 index 0000000..d3e5c43 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/map/sfGuardUserPermissionMapBuilder.php @@ -0,0 +1,42 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_guard_user_permission'); + $tMap->setPhpName('sfGuardUserPermission'); + + $tMap->setUseIdGenerator(false); + + $tMap->addForeignPrimaryKey('USER_ID', 'UserId', 'int' , CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null); + + $tMap->addForeignPrimaryKey('PERMISSION_ID', 'PermissionId', 'int' , CreoleTypes::INTEGER, 'sf_guard_permission', 'ID', true, null); + + $tMap->addColumn('EXCLUDE', 'Exclude', 'boolean', CreoleTypes::BOOLEAN, false, null); + + } +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroup.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroup.php new file mode 100644 index 0000000..13555e1 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroup.php @@ -0,0 +1,946 @@ +id; + } + + + public function getName() + { + + return $this->name; + } + + + public function getDescription() + { + + return $this->description; + } + + + public function getIsEditorialTeam() + { + + return $this->is_editorial_team; + } + + + public function getIsEnabled() + { + + return $this->is_enabled; + } + + + public function setId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = sfGuardGroupPeer::ID; + } + + } + + public function setName($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[] = sfGuardGroupPeer::NAME; + } + + } + + public function setDescription($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->description !== $v) { + $this->description = $v; + $this->modifiedColumns[] = sfGuardGroupPeer::DESCRIPTION; + } + + } + + public function setIsEditorialTeam($v) + { + + if ($this->is_editorial_team !== $v || $v === false) { + $this->is_editorial_team = $v; + $this->modifiedColumns[] = sfGuardGroupPeer::IS_EDITORIAL_TEAM; + } + + } + + public function setIsEnabled($v) + { + + if ($this->is_enabled !== $v || $v === false) { + $this->is_enabled = $v; + $this->modifiedColumns[] = sfGuardGroupPeer::IS_ENABLED; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->id = $rs->getInt($startcol + 0); + + $this->name = $rs->getString($startcol + 1); + + $this->description = $rs->getString($startcol + 2); + + $this->is_editorial_team = $rs->getBoolean($startcol + 3); + + $this->is_enabled = $rs->getBoolean($startcol + 4); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 5; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardGroup object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroup:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardGroupPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardGroup:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroup:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardGroup:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardGroupPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setId($pk); + $this->setNew(false); + } else { + $affectedRows += sfGuardGroupPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + if ($this->collsfGuardGroupPermissions !== null) { + foreach($this->collsfGuardGroupPermissions as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collsfGuardUserGroups !== null) { + foreach($this->collsfGuardUserGroups as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collReaktorArtworks !== null) { + foreach($this->collReaktorArtworks as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + if (($retval = sfGuardGroupPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + if ($this->collsfGuardGroupPermissions !== null) { + foreach($this->collsfGuardGroupPermissions as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collsfGuardUserGroups !== null) { + foreach($this->collsfGuardUserGroups as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collReaktorArtworks !== null) { + foreach($this->collReaktorArtworks as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardGroupPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getName(); + break; + case 2: + return $this->getDescription(); + break; + case 3: + return $this->getIsEditorialTeam(); + break; + case 4: + return $this->getIsEnabled(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardGroupPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getName(), + $keys[2] => $this->getDescription(), + $keys[3] => $this->getIsEditorialTeam(), + $keys[4] => $this->getIsEnabled(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardGroupPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setName($value); + break; + case 2: + $this->setDescription($value); + break; + case 3: + $this->setIsEditorialTeam($value); + break; + case 4: + $this->setIsEnabled($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardGroupPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setName($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setDescription($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setIsEditorialTeam($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setIsEnabled($arr[$keys[4]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardGroupPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardGroupPeer::ID)) $criteria->add(sfGuardGroupPeer::ID, $this->id); + if ($this->isColumnModified(sfGuardGroupPeer::NAME)) $criteria->add(sfGuardGroupPeer::NAME, $this->name); + if ($this->isColumnModified(sfGuardGroupPeer::DESCRIPTION)) $criteria->add(sfGuardGroupPeer::DESCRIPTION, $this->description); + if ($this->isColumnModified(sfGuardGroupPeer::IS_EDITORIAL_TEAM)) $criteria->add(sfGuardGroupPeer::IS_EDITORIAL_TEAM, $this->is_editorial_team); + if ($this->isColumnModified(sfGuardGroupPeer::IS_ENABLED)) $criteria->add(sfGuardGroupPeer::IS_ENABLED, $this->is_enabled); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardGroupPeer::DATABASE_NAME); + + $criteria->add(sfGuardGroupPeer::ID, $this->id); + + return $criteria; + } + + + public function getPrimaryKey() + { + return $this->getId(); + } + + + public function setPrimaryKey($key) + { + $this->setId($key); + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setName($this->name); + + $copyObj->setDescription($this->description); + + $copyObj->setIsEditorialTeam($this->is_editorial_team); + + $copyObj->setIsEnabled($this->is_enabled); + + + if ($deepCopy) { + $copyObj->setNew(false); + + foreach($this->getsfGuardGroupPermissions() as $relObj) { + $copyObj->addsfGuardGroupPermission($relObj->copy($deepCopy)); + } + + foreach($this->getsfGuardUserGroups() as $relObj) { + $copyObj->addsfGuardUserGroup($relObj->copy($deepCopy)); + } + + foreach($this->getReaktorArtworks() as $relObj) { + $copyObj->addReaktorArtwork($relObj->copy($deepCopy)); + } + + } + + $copyObj->setNew(true); + + $copyObj->setId(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardGroupPeer(); + } + return self::$peer; + } + + + public function initsfGuardGroupPermissions() + { + if ($this->collsfGuardGroupPermissions === null) { + $this->collsfGuardGroupPermissions = array(); + } + } + + + public function getsfGuardGroupPermissions($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardGroupPermissions === null) { + if ($this->isNew()) { + $this->collsfGuardGroupPermissions = array(); + } else { + + $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $this->getId()); + + sfGuardGroupPermissionPeer::addSelectColumns($criteria); + $this->collsfGuardGroupPermissions = sfGuardGroupPermissionPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $this->getId()); + + sfGuardGroupPermissionPeer::addSelectColumns($criteria); + if (!isset($this->lastsfGuardGroupPermissionCriteria) || !$this->lastsfGuardGroupPermissionCriteria->equals($criteria)) { + $this->collsfGuardGroupPermissions = sfGuardGroupPermissionPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfGuardGroupPermissionCriteria = $criteria; + return $this->collsfGuardGroupPermissions; + } + + + public function countsfGuardGroupPermissions($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $this->getId()); + + return sfGuardGroupPermissionPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfGuardGroupPermission(sfGuardGroupPermission $l) + { + $this->collsfGuardGroupPermissions[] = $l; + $l->setsfGuardGroup($this); + } + + + + public function getsfGuardGroupPermissionsJoinsfGuardPermission($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardGroupPermissions === null) { + if ($this->isNew()) { + $this->collsfGuardGroupPermissions = array(); + } else { + + $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $this->getId()); + + $this->collsfGuardGroupPermissions = sfGuardGroupPermissionPeer::doSelectJoinsfGuardPermission($criteria, $con); + } + } else { + + $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $this->getId()); + + if (!isset($this->lastsfGuardGroupPermissionCriteria) || !$this->lastsfGuardGroupPermissionCriteria->equals($criteria)) { + $this->collsfGuardGroupPermissions = sfGuardGroupPermissionPeer::doSelectJoinsfGuardPermission($criteria, $con); + } + } + $this->lastsfGuardGroupPermissionCriteria = $criteria; + + return $this->collsfGuardGroupPermissions; + } + + + public function initsfGuardUserGroups() + { + if ($this->collsfGuardUserGroups === null) { + $this->collsfGuardUserGroups = array(); + } + } + + + public function getsfGuardUserGroups($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardUserGroups === null) { + if ($this->isNew()) { + $this->collsfGuardUserGroups = array(); + } else { + + $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $this->getId()); + + sfGuardUserGroupPeer::addSelectColumns($criteria); + $this->collsfGuardUserGroups = sfGuardUserGroupPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $this->getId()); + + sfGuardUserGroupPeer::addSelectColumns($criteria); + if (!isset($this->lastsfGuardUserGroupCriteria) || !$this->lastsfGuardUserGroupCriteria->equals($criteria)) { + $this->collsfGuardUserGroups = sfGuardUserGroupPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfGuardUserGroupCriteria = $criteria; + return $this->collsfGuardUserGroups; + } + + + public function countsfGuardUserGroups($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $this->getId()); + + return sfGuardUserGroupPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfGuardUserGroup(sfGuardUserGroup $l) + { + $this->collsfGuardUserGroups[] = $l; + $l->setsfGuardGroup($this); + } + + + + public function getsfGuardUserGroupsJoinsfGuardUser($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardUserGroups === null) { + if ($this->isNew()) { + $this->collsfGuardUserGroups = array(); + } else { + + $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $this->getId()); + + $this->collsfGuardUserGroups = sfGuardUserGroupPeer::doSelectJoinsfGuardUser($criteria, $con); + } + } else { + + $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $this->getId()); + + if (!isset($this->lastsfGuardUserGroupCriteria) || !$this->lastsfGuardUserGroupCriteria->equals($criteria)) { + $this->collsfGuardUserGroups = sfGuardUserGroupPeer::doSelectJoinsfGuardUser($criteria, $con); + } + } + $this->lastsfGuardUserGroupCriteria = $criteria; + + return $this->collsfGuardUserGroups; + } + + + public function initReaktorArtworks() + { + if ($this->collReaktorArtworks === null) { + $this->collReaktorArtworks = array(); + } + } + + + public function getReaktorArtworks($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworks === null) { + if ($this->isNew()) { + $this->collReaktorArtworks = array(); + } else { + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + ReaktorArtworkPeer::addSelectColumns($criteria); + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + ReaktorArtworkPeer::addSelectColumns($criteria); + if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) { + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelect($criteria, $con); + } + } + } + $this->lastReaktorArtworkCriteria = $criteria; + return $this->collReaktorArtworks; + } + + + public function countReaktorArtworks($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + return ReaktorArtworkPeer::doCount($criteria, $distinct, $con); + } + + + public function addReaktorArtwork(ReaktorArtwork $l) + { + $this->collReaktorArtworks[] = $l; + $l->setsfGuardGroup($this); + } + + + + public function getReaktorArtworksJoinsfGuardUser($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworks === null) { + if ($this->isNew()) { + $this->collReaktorArtworks = array(); + } else { + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardUser($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) { + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardUser($criteria, $con); + } + } + $this->lastReaktorArtworkCriteria = $criteria; + + return $this->collReaktorArtworks; + } + + + + public function getReaktorArtworksJoinArtworkStatus($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworks === null) { + if ($this->isNew()) { + $this->collReaktorArtworks = array(); + } else { + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinArtworkStatus($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) { + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinArtworkStatus($criteria, $con); + } + } + $this->lastReaktorArtworkCriteria = $criteria; + + return $this->collReaktorArtworks; + } + + + + public function getReaktorArtworksJoinReaktorFile($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworks === null) { + if ($this->isNew()) { + $this->collReaktorArtworks = array(); + } else { + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinReaktorFile($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkPeer::TEAM_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) { + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinReaktorFile($criteria, $con); + } + } + $this->lastReaktorArtworkCriteria = $criteria; + + return $this->collReaktorArtworks; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardGroup:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardGroup::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPeer.php new file mode 100644 index 0000000..49644dc --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPeer.php @@ -0,0 +1,453 @@ + array ('Id', 'Name', 'Description', 'IsEditorialTeam', 'IsEnabled', ), + BasePeer::TYPE_COLNAME => array (sfGuardGroupPeer::ID, sfGuardGroupPeer::NAME, sfGuardGroupPeer::DESCRIPTION, sfGuardGroupPeer::IS_EDITORIAL_TEAM, sfGuardGroupPeer::IS_ENABLED, ), + BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'description', 'is_editorial_team', 'is_enabled', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Name' => 1, 'Description' => 2, 'IsEditorialTeam' => 3, 'IsEnabled' => 4, ), + BasePeer::TYPE_COLNAME => array (sfGuardGroupPeer::ID => 0, sfGuardGroupPeer::NAME => 1, sfGuardGroupPeer::DESCRIPTION => 2, sfGuardGroupPeer::IS_EDITORIAL_TEAM => 3, sfGuardGroupPeer::IS_ENABLED => 4, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'description' => 2, 'is_editorial_team' => 3, 'is_enabled' => 4, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardGroupMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardGroupMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardGroupPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardGroupPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardGroupPeer::ID); + + $criteria->addSelectColumn(sfGuardGroupPeer::NAME); + + $criteria->addSelectColumn(sfGuardGroupPeer::DESCRIPTION); + + $criteria->addSelectColumn(sfGuardGroupPeer::IS_EDITORIAL_TEAM); + + $criteria->addSelectColumn(sfGuardGroupPeer::IS_ENABLED); + + } + + const COUNT = 'COUNT(sf_guard_group.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_group.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardGroupPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardGroupPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardGroupPeer::populateObjects(sfGuardGroupPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardGroupPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardGroupPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardGroupPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardGroupPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + $criteria->remove(sfGuardGroupPeer::ID); + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardGroupPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardGroupPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardGroupPeer::ID); + $selectCriteria->add(sfGuardGroupPeer::ID, $criteria->remove(sfGuardGroupPeer::ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardGroupPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += sfGuardGroupPeer::doOnDeleteCascade(new Criteria(), $con); + $affectedRows += BasePeer::doDeleteAll(sfGuardGroupPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardGroup) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + $criteria->add(sfGuardGroupPeer::ID, (array) $values, Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + $affectedRows += sfGuardGroupPeer::doOnDeleteCascade($criteria, $con); + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected static function doOnDeleteCascade(Criteria $criteria, Connection $con) + { + $affectedRows = 0; + + $objects = sfGuardGroupPeer::doSelect($criteria, $con); + foreach($objects as $obj) { + + + include_once 'plugins/sfGuardPlugin/lib/model/sfGuardGroupPermission.php'; + + $c = new Criteria(); + + $c->add(sfGuardGroupPermissionPeer::GROUP_ID, $obj->getId()); + $affectedRows += sfGuardGroupPermissionPeer::doDelete($c, $con); + + include_once 'plugins/sfGuardPlugin/lib/model/sfGuardUserGroup.php'; + + $c = new Criteria(); + + $c->add(sfGuardUserGroupPeer::GROUP_ID, $obj->getId()); + $affectedRows += sfGuardUserGroupPeer::doDelete($c, $con); + } + return $affectedRows; + } + + + public static function doValidate(sfGuardGroup $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardGroupPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardGroupPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardGroupPeer::DATABASE_NAME, sfGuardGroupPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardGroupPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK($pk, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $criteria = new Criteria(sfGuardGroupPeer::DATABASE_NAME); + + $criteria->add(sfGuardGroupPeer::ID, $pk); + + + $v = sfGuardGroupPeer::doSelect($criteria, $con); + + return !empty($v) > 0 ? $v[0] : null; + } + + + public static function retrieveByPKs($pks, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $objs = null; + if (empty($pks)) { + $objs = array(); + } else { + $criteria = new Criteria(); + $criteria->add(sfGuardGroupPeer::ID, $pks, Criteria::IN); + $objs = sfGuardGroupPeer::doSelect($criteria, $con); + } + return $objs; + } + +} +if (Propel::isInit()) { + try { + BasesfGuardGroupPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardGroupMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardGroupMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermission.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermission.php new file mode 100644 index 0000000..59e6048 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermission.php @@ -0,0 +1,481 @@ +group_id; + } + + + public function getPermissionId() + { + + return $this->permission_id; + } + + + public function setGroupId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->group_id !== $v) { + $this->group_id = $v; + $this->modifiedColumns[] = sfGuardGroupPermissionPeer::GROUP_ID; + } + + if ($this->asfGuardGroup !== null && $this->asfGuardGroup->getId() !== $v) { + $this->asfGuardGroup = null; + } + + } + + public function setPermissionId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->permission_id !== $v) { + $this->permission_id = $v; + $this->modifiedColumns[] = sfGuardGroupPermissionPeer::PERMISSION_ID; + } + + if ($this->asfGuardPermission !== null && $this->asfGuardPermission->getId() !== $v) { + $this->asfGuardPermission = null; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->group_id = $rs->getInt($startcol + 0); + + $this->permission_id = $rs->getInt($startcol + 1); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 2; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardGroupPermission object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermission:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPermissionPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardGroupPermissionPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardGroupPermission:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermission:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPermissionPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardGroupPermission:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->asfGuardGroup !== null) { + if ($this->asfGuardGroup->isModified()) { + $affectedRows += $this->asfGuardGroup->save($con); + } + $this->setsfGuardGroup($this->asfGuardGroup); + } + + if ($this->asfGuardPermission !== null) { + if ($this->asfGuardPermission->isModified() || $this->asfGuardPermission->getCurrentsfGuardPermissionI18n()->isModified()) { + $affectedRows += $this->asfGuardPermission->save($con); + } + $this->setsfGuardPermission($this->asfGuardPermission); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardGroupPermissionPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setNew(false); + } else { + $affectedRows += sfGuardGroupPermissionPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->asfGuardGroup !== null) { + if (!$this->asfGuardGroup->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardGroup->getValidationFailures()); + } + } + + if ($this->asfGuardPermission !== null) { + if (!$this->asfGuardPermission->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardPermission->getValidationFailures()); + } + } + + + if (($retval = sfGuardGroupPermissionPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardGroupPermissionPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getGroupId(); + break; + case 1: + return $this->getPermissionId(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardGroupPermissionPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getGroupId(), + $keys[1] => $this->getPermissionId(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardGroupPermissionPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setGroupId($value); + break; + case 1: + $this->setPermissionId($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardGroupPermissionPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setGroupId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setPermissionId($arr[$keys[1]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardGroupPermissionPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardGroupPermissionPeer::GROUP_ID)) $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $this->group_id); + if ($this->isColumnModified(sfGuardGroupPermissionPeer::PERMISSION_ID)) $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $this->permission_id); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardGroupPermissionPeer::DATABASE_NAME); + + $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $this->group_id); + $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $this->permission_id); + + return $criteria; + } + + + public function getPrimaryKey() + { + $pks = array(); + + $pks[0] = $this->getGroupId(); + + $pks[1] = $this->getPermissionId(); + + return $pks; + } + + + public function setPrimaryKey($keys) + { + + $this->setGroupId($keys[0]); + + $this->setPermissionId($keys[1]); + + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + + $copyObj->setNew(true); + + $copyObj->setGroupId(NULL); + $copyObj->setPermissionId(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardGroupPermissionPeer(); + } + return self::$peer; + } + + + public function setsfGuardGroup($v) + { + + + if ($v === null) { + $this->setGroupId(NULL); + } else { + $this->setGroupId($v->getId()); + } + + + $this->asfGuardGroup = $v; + } + + + + public function getsfGuardGroup($con = null) + { + if ($this->asfGuardGroup === null && ($this->group_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPeer.php'; + + $this->asfGuardGroup = sfGuardGroupPeer::retrieveByPK($this->group_id, $con); + + + } + return $this->asfGuardGroup; + } + + + public function setsfGuardPermission($v) + { + + + if ($v === null) { + $this->setPermissionId(NULL); + } else { + $this->setPermissionId($v->getId()); + } + + + $this->asfGuardPermission = $v; + } + + + + public function getsfGuardPermission($con = null) + { + if ($this->asfGuardPermission === null && ($this->permission_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionPeer.php'; + + $this->asfGuardPermission = sfGuardPermissionPeer::retrieveByPK($this->permission_id, $con); + + + } + return $this->asfGuardPermission; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardGroupPermission:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardGroupPermission::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionI18n.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionI18n.php new file mode 100644 index 0000000..dd4a671 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionI18n.php @@ -0,0 +1,472 @@ +description; + } + + + public function getId() + { + + return $this->id; + } + + + public function getCulture() + { + + return $this->culture; + } + + + public function setDescription($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->description !== $v) { + $this->description = $v; + $this->modifiedColumns[] = sfGuardGroupPermissionI18nPeer::DESCRIPTION; + } + + } + + public function setId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = sfGuardGroupPermissionI18nPeer::ID; + } + + if ($this->asfGuardPermission !== null && $this->asfGuardPermission->getId() !== $v) { + $this->asfGuardPermission = null; + } + + } + + public function setCulture($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->culture !== $v) { + $this->culture = $v; + $this->modifiedColumns[] = sfGuardGroupPermissionI18nPeer::CULTURE; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->description = $rs->getString($startcol + 0); + + $this->id = $rs->getInt($startcol + 1); + + $this->culture = $rs->getString($startcol + 2); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 3; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardGroupPermissionI18n object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18n:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPermissionI18nPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardGroupPermissionI18nPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18n:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18n:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPermissionI18nPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18n:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->asfGuardPermission !== null) { + if ($this->asfGuardPermission->isModified() || $this->asfGuardPermission->getCurrentsfGuardGroupPermissionI18n()->isModified()) { + $affectedRows += $this->asfGuardPermission->save($con); + } + $this->setsfGuardPermission($this->asfGuardPermission); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardGroupPermissionI18nPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setNew(false); + } else { + $affectedRows += sfGuardGroupPermissionI18nPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->asfGuardPermission !== null) { + if (!$this->asfGuardPermission->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardPermission->getValidationFailures()); + } + } + + + if (($retval = sfGuardGroupPermissionI18nPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardGroupPermissionI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getDescription(); + break; + case 1: + return $this->getId(); + break; + case 2: + return $this->getCulture(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardGroupPermissionI18nPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getDescription(), + $keys[1] => $this->getId(), + $keys[2] => $this->getCulture(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardGroupPermissionI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setDescription($value); + break; + case 1: + $this->setId($value); + break; + case 2: + $this->setCulture($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardGroupPermissionI18nPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setDescription($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setId($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setCulture($arr[$keys[2]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardGroupPermissionI18nPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardGroupPermissionI18nPeer::DESCRIPTION)) $criteria->add(sfGuardGroupPermissionI18nPeer::DESCRIPTION, $this->description); + if ($this->isColumnModified(sfGuardGroupPermissionI18nPeer::ID)) $criteria->add(sfGuardGroupPermissionI18nPeer::ID, $this->id); + if ($this->isColumnModified(sfGuardGroupPermissionI18nPeer::CULTURE)) $criteria->add(sfGuardGroupPermissionI18nPeer::CULTURE, $this->culture); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardGroupPermissionI18nPeer::DATABASE_NAME); + + $criteria->add(sfGuardGroupPermissionI18nPeer::ID, $this->id); + $criteria->add(sfGuardGroupPermissionI18nPeer::CULTURE, $this->culture); + + return $criteria; + } + + + public function getPrimaryKey() + { + $pks = array(); + + $pks[0] = $this->getId(); + + $pks[1] = $this->getCulture(); + + return $pks; + } + + + public function setPrimaryKey($keys) + { + + $this->setId($keys[0]); + + $this->setCulture($keys[1]); + + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setDescription($this->description); + + + $copyObj->setNew(true); + + $copyObj->setId(NULL); + $copyObj->setCulture(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardGroupPermissionI18nPeer(); + } + return self::$peer; + } + + + public function setsfGuardPermission($v) + { + + + if ($v === null) { + $this->setId(NULL); + } else { + $this->setId($v->getId()); + } + + + $this->asfGuardPermission = $v; + } + + + + public function getsfGuardPermission($con = null) + { + if ($this->asfGuardPermission === null && ($this->id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionPeer.php'; + + $this->asfGuardPermission = sfGuardPermissionPeer::retrieveByPK($this->id, $con); + + + } + return $this->asfGuardPermission; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardGroupPermissionI18n:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardGroupPermissionI18n::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionI18nPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionI18nPeer.php new file mode 100644 index 0000000..e0e87dd --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionI18nPeer.php @@ -0,0 +1,569 @@ + array ('Description', 'Id', 'Culture', ), + BasePeer::TYPE_COLNAME => array (sfGuardGroupPermissionI18nPeer::DESCRIPTION, sfGuardGroupPermissionI18nPeer::ID, sfGuardGroupPermissionI18nPeer::CULTURE, ), + BasePeer::TYPE_FIELDNAME => array ('description', 'id', 'culture', ), + BasePeer::TYPE_NUM => array (0, 1, 2, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('Description' => 0, 'Id' => 1, 'Culture' => 2, ), + BasePeer::TYPE_COLNAME => array (sfGuardGroupPermissionI18nPeer::DESCRIPTION => 0, sfGuardGroupPermissionI18nPeer::ID => 1, sfGuardGroupPermissionI18nPeer::CULTURE => 2, ), + BasePeer::TYPE_FIELDNAME => array ('description' => 0, 'id' => 1, 'culture' => 2, ), + BasePeer::TYPE_NUM => array (0, 1, 2, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardGroupPermissionI18nMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardGroupPermissionI18nMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardGroupPermissionI18nPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardGroupPermissionI18nPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::DESCRIPTION); + + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::ID); + + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::CULTURE); + + } + + const COUNT = 'COUNT(sf_guard_permission_i18n.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_permission_i18n.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardGroupPermissionI18nPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardGroupPermissionI18nPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardGroupPermissionI18nPeer::populateObjects(sfGuardGroupPermissionI18nPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18nPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPermissionI18nPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardGroupPermissionI18nPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardGroupPermissionI18nPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinsfGuardPermission(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardGroupPermissionI18nPeer::ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardGroupPermissionI18nPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinsfGuardPermission(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardGroupPermissionI18nPeer::addSelectColumns($c); + $startcol = (sfGuardGroupPermissionI18nPeer::NUM_COLUMNS - sfGuardGroupPermissionI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardPermissionPeer::addSelectColumns($c); + + $c->addJoin(sfGuardGroupPermissionI18nPeer::ID, sfGuardPermissionPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardGroupPermissionI18nPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardPermission(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardGroupPermissionI18n($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardGroupPermissionI18ns(); + $obj2->addsfGuardGroupPermissionI18n($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionI18nPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardGroupPermissionI18nPeer::ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardGroupPermissionI18nPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardGroupPermissionI18nPeer::addSelectColumns($c); + $startcol2 = (sfGuardGroupPermissionI18nPeer::NUM_COLUMNS - sfGuardGroupPermissionI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardPermissionPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardPermissionPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardGroupPermissionI18nPeer::ID, sfGuardPermissionPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardGroupPermissionI18nPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = sfGuardPermissionPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardPermission(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardGroupPermissionI18n($obj1); break; + } + } + + if ($newObject) { + $obj2->initsfGuardGroupPermissionI18ns(); + $obj2->addsfGuardGroupPermissionI18n($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardGroupPermissionI18nPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18nPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardGroupPermissionI18nPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18nPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPermissionI18nPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18nPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardGroupPermissionI18nPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardGroupPermissionI18nPeer::ID); + $selectCriteria->add(sfGuardGroupPermissionI18nPeer::ID, $criteria->remove(sfGuardGroupPermissionI18nPeer::ID), $comparison); + + $comparison = $criteria->getComparison(sfGuardGroupPermissionI18nPeer::CULTURE); + $selectCriteria->add(sfGuardGroupPermissionI18nPeer::CULTURE, $criteria->remove(sfGuardGroupPermissionI18nPeer::CULTURE), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionI18nPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPermissionI18nPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(sfGuardGroupPermissionI18nPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPermissionI18nPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardGroupPermissionI18n) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + if(count($values) == count($values, COUNT_RECURSIVE)) + { + $values = array($values); + } + $vals = array(); + foreach($values as $value) + { + + $vals[0][] = $value[0]; + $vals[1][] = $value[1]; + } + + $criteria->add(sfGuardGroupPermissionI18nPeer::ID, $vals[0], Criteria::IN); + $criteria->add(sfGuardGroupPermissionI18nPeer::CULTURE, $vals[1], Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(sfGuardGroupPermissionI18n $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardGroupPermissionI18nPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardGroupPermissionI18nPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardGroupPermissionI18nPeer::DATABASE_NAME, sfGuardGroupPermissionI18nPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardGroupPermissionI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK( $id, $culture, $con = null) { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $criteria = new Criteria(); + $criteria->add(sfGuardGroupPermissionI18nPeer::ID, $id); + $criteria->add(sfGuardGroupPermissionI18nPeer::CULTURE, $culture); + $v = sfGuardGroupPermissionI18nPeer::doSelect($criteria, $con); + + return !empty($v) ? $v[0] : null; + } +} +if (Propel::isInit()) { + try { + BasesfGuardGroupPermissionI18nPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardGroupPermissionI18nMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardGroupPermissionI18nMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php new file mode 100644 index 0000000..e5f180a --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php @@ -0,0 +1,839 @@ + array ('GroupId', 'PermissionId', ), + BasePeer::TYPE_COLNAME => array (sfGuardGroupPermissionPeer::GROUP_ID, sfGuardGroupPermissionPeer::PERMISSION_ID, ), + BasePeer::TYPE_FIELDNAME => array ('group_id', 'permission_id', ), + BasePeer::TYPE_NUM => array (0, 1, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('GroupId' => 0, 'PermissionId' => 1, ), + BasePeer::TYPE_COLNAME => array (sfGuardGroupPermissionPeer::GROUP_ID => 0, sfGuardGroupPermissionPeer::PERMISSION_ID => 1, ), + BasePeer::TYPE_FIELDNAME => array ('group_id' => 0, 'permission_id' => 1, ), + BasePeer::TYPE_NUM => array (0, 1, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardGroupPermissionMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardGroupPermissionMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardGroupPermissionPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardGroupPermissionPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::GROUP_ID); + + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::PERMISSION_ID); + + } + + const COUNT = 'COUNT(sf_guard_group_permission.GROUP_ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_group_permission.GROUP_ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardGroupPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardGroupPermissionPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardGroupPermissionPeer::populateObjects(sfGuardGroupPermissionPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPermissionPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardGroupPermissionPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardGroupPermissionPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinsfGuardGroup(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardGroupPermissionPeer::GROUP_ID, sfGuardGroupPeer::ID); + + $rs = sfGuardGroupPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doCountJoinsfGuardPermission(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardGroupPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardGroupPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinsfGuardGroup(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardGroupPermissionPeer::addSelectColumns($c); + $startcol = (sfGuardGroupPermissionPeer::NUM_COLUMNS - sfGuardGroupPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardGroupPeer::addSelectColumns($c); + + $c->addJoin(sfGuardGroupPermissionPeer::GROUP_ID, sfGuardGroupPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardGroupPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardGroupPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardGroup(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardGroupPermission($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardGroupPermissions(); + $obj2->addsfGuardGroupPermission($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doSelectJoinsfGuardPermission(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardGroupPermissionPeer::addSelectColumns($c); + $startcol = (sfGuardGroupPermissionPeer::NUM_COLUMNS - sfGuardGroupPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardPermissionPeer::addSelectColumns($c); + + $c->addJoin(sfGuardGroupPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardGroupPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardPermission(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardGroupPermission($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardGroupPermissions(); + $obj2->addsfGuardGroupPermission($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardGroupPermissionPeer::GROUP_ID, sfGuardGroupPeer::ID); + + $criteria->addJoin(sfGuardGroupPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardGroupPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardGroupPermissionPeer::addSelectColumns($c); + $startcol2 = (sfGuardGroupPermissionPeer::NUM_COLUMNS - sfGuardGroupPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardGroupPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardGroupPeer::NUM_COLUMNS; + + sfGuardPermissionPeer::addSelectColumns($c); + $startcol4 = $startcol3 + sfGuardPermissionPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardGroupPermissionPeer::GROUP_ID, sfGuardGroupPeer::ID); + + $c->addJoin(sfGuardGroupPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardGroupPermissionPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = sfGuardGroupPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardGroup(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardGroupPermission($obj1); break; + } + } + + if ($newObject) { + $obj2->initsfGuardGroupPermissions(); + $obj2->addsfGuardGroupPermission($obj1); + } + + + + $omClass = sfGuardPermissionPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj3 = new $cls(); + $obj3->hydrate($rs, $startcol3); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj3 = $temp_obj1->getsfGuardPermission(); if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) { + $newObject = false; + $temp_obj3->addsfGuardGroupPermission($obj1); break; + } + } + + if ($newObject) { + $obj3->initsfGuardGroupPermissions(); + $obj3->addsfGuardGroupPermission($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAllExceptsfGuardGroup(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardGroupPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardGroupPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doCountJoinAllExceptsfGuardPermission(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardGroupPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardGroupPermissionPeer::GROUP_ID, sfGuardGroupPeer::ID); + + $rs = sfGuardGroupPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAllExceptsfGuardGroup(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardGroupPermissionPeer::addSelectColumns($c); + $startcol2 = (sfGuardGroupPermissionPeer::NUM_COLUMNS - sfGuardGroupPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardPermissionPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardPermissionPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardGroupPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardGroupPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardPermissionPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardPermission(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardGroupPermission($obj1); + break; + } + } + + if ($newObject) { + $obj2->initsfGuardGroupPermissions(); + $obj2->addsfGuardGroupPermission($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + + public static function doSelectJoinAllExceptsfGuardPermission(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardGroupPermissionPeer::addSelectColumns($c); + $startcol2 = (sfGuardGroupPermissionPeer::NUM_COLUMNS - sfGuardGroupPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardGroupPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardGroupPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardGroupPermissionPeer::GROUP_ID, sfGuardGroupPeer::ID); + + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardGroupPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardGroupPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardGroup(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardGroupPermission($obj1); + break; + } + } + + if ($newObject) { + $obj2->initsfGuardGroupPermissions(); + $obj2->addsfGuardGroupPermission($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardGroupPermissionPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardGroupPermissionPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPermissionPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardGroupPermissionPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardGroupPermissionPeer::GROUP_ID); + $selectCriteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $criteria->remove(sfGuardGroupPermissionPeer::GROUP_ID), $comparison); + + $comparison = $criteria->getComparison(sfGuardGroupPermissionPeer::PERMISSION_ID); + $selectCriteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $criteria->remove(sfGuardGroupPermissionPeer::PERMISSION_ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardGroupPermissionPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardGroupPermissionPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(sfGuardGroupPermissionPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardGroupPermissionPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardGroupPermission) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + if(count($values) == count($values, COUNT_RECURSIVE)) + { + $values = array($values); + } + $vals = array(); + foreach($values as $value) + { + + $vals[0][] = $value[0]; + $vals[1][] = $value[1]; + } + + $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $vals[0], Criteria::IN); + $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $vals[1], Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(sfGuardGroupPermission $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardGroupPermissionPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardGroupPermissionPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardGroupPermissionPeer::DATABASE_NAME, sfGuardGroupPermissionPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardGroupPermissionPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK( $group_id, $permission_id, $con = null) { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $criteria = new Criteria(); + $criteria->add(sfGuardGroupPermissionPeer::GROUP_ID, $group_id); + $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $permission_id); + $v = sfGuardGroupPermissionPeer::doSelect($criteria, $con); + + return !empty($v) ? $v[0] : null; + } +} +if (Propel::isInit()) { + try { + BasesfGuardGroupPermissionPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardGroupPermissionMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardGroupPermissionMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermission.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermission.php new file mode 100644 index 0000000..7784bbd --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermission.php @@ -0,0 +1,785 @@ +id; + } + + + public function getName() + { + + return $this->name; + } + + + public function setId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = sfGuardPermissionPeer::ID; + } + + } + + public function setName($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[] = sfGuardPermissionPeer::NAME; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->id = $rs->getInt($startcol + 0); + + $this->name = $rs->getString($startcol + 1); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 2; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardPermission object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermission:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardPermissionPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardPermissionPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardPermission:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermission:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardPermissionPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardPermission:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardPermissionPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setId($pk); + $this->setNew(false); + } else { + $affectedRows += sfGuardPermissionPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + if ($this->collsfGuardGroupPermissions !== null) { + foreach($this->collsfGuardGroupPermissions as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collsfGuardUserPermissions !== null) { + foreach($this->collsfGuardUserPermissions as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collsfGuardPermissionI18ns !== null) { + foreach($this->collsfGuardPermissionI18ns as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + if (($retval = sfGuardPermissionPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + if ($this->collsfGuardGroupPermissions !== null) { + foreach($this->collsfGuardGroupPermissions as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collsfGuardUserPermissions !== null) { + foreach($this->collsfGuardUserPermissions as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collsfGuardPermissionI18ns !== null) { + foreach($this->collsfGuardPermissionI18ns as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardPermissionPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getName(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardPermissionPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getName(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardPermissionPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setName($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardPermissionPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setName($arr[$keys[1]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardPermissionPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardPermissionPeer::ID)) $criteria->add(sfGuardPermissionPeer::ID, $this->id); + if ($this->isColumnModified(sfGuardPermissionPeer::NAME)) $criteria->add(sfGuardPermissionPeer::NAME, $this->name); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardPermissionPeer::DATABASE_NAME); + + $criteria->add(sfGuardPermissionPeer::ID, $this->id); + + return $criteria; + } + + + public function getPrimaryKey() + { + return $this->getId(); + } + + + public function setPrimaryKey($key) + { + $this->setId($key); + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setName($this->name); + + + if ($deepCopy) { + $copyObj->setNew(false); + + foreach($this->getsfGuardGroupPermissions() as $relObj) { + $copyObj->addsfGuardGroupPermission($relObj->copy($deepCopy)); + } + + foreach($this->getsfGuardUserPermissions() as $relObj) { + $copyObj->addsfGuardUserPermission($relObj->copy($deepCopy)); + } + + foreach($this->getsfGuardPermissionI18ns() as $relObj) { + $copyObj->addsfGuardPermissionI18n($relObj->copy($deepCopy)); + } + + } + + $copyObj->setNew(true); + + $copyObj->setId(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardPermissionPeer(); + } + return self::$peer; + } + + + public function initsfGuardGroupPermissions() + { + if ($this->collsfGuardGroupPermissions === null) { + $this->collsfGuardGroupPermissions = array(); + } + } + + + public function getsfGuardGroupPermissions($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardGroupPermissions === null) { + if ($this->isNew()) { + $this->collsfGuardGroupPermissions = array(); + } else { + + $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $this->getId()); + + sfGuardGroupPermissionPeer::addSelectColumns($criteria); + $this->collsfGuardGroupPermissions = sfGuardGroupPermissionPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $this->getId()); + + sfGuardGroupPermissionPeer::addSelectColumns($criteria); + if (!isset($this->lastsfGuardGroupPermissionCriteria) || !$this->lastsfGuardGroupPermissionCriteria->equals($criteria)) { + $this->collsfGuardGroupPermissions = sfGuardGroupPermissionPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfGuardGroupPermissionCriteria = $criteria; + return $this->collsfGuardGroupPermissions; + } + + + public function countsfGuardGroupPermissions($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $this->getId()); + + return sfGuardGroupPermissionPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfGuardGroupPermission(sfGuardGroupPermission $l) + { + $this->collsfGuardGroupPermissions[] = $l; + $l->setsfGuardPermission($this); + } + + + + public function getsfGuardGroupPermissionsJoinsfGuardGroup($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardGroupPermissions === null) { + if ($this->isNew()) { + $this->collsfGuardGroupPermissions = array(); + } else { + + $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $this->getId()); + + $this->collsfGuardGroupPermissions = sfGuardGroupPermissionPeer::doSelectJoinsfGuardGroup($criteria, $con); + } + } else { + + $criteria->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $this->getId()); + + if (!isset($this->lastsfGuardGroupPermissionCriteria) || !$this->lastsfGuardGroupPermissionCriteria->equals($criteria)) { + $this->collsfGuardGroupPermissions = sfGuardGroupPermissionPeer::doSelectJoinsfGuardGroup($criteria, $con); + } + } + $this->lastsfGuardGroupPermissionCriteria = $criteria; + + return $this->collsfGuardGroupPermissions; + } + + + public function initsfGuardUserPermissions() + { + if ($this->collsfGuardUserPermissions === null) { + $this->collsfGuardUserPermissions = array(); + } + } + + + public function getsfGuardUserPermissions($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardUserPermissions === null) { + if ($this->isNew()) { + $this->collsfGuardUserPermissions = array(); + } else { + + $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $this->getId()); + + sfGuardUserPermissionPeer::addSelectColumns($criteria); + $this->collsfGuardUserPermissions = sfGuardUserPermissionPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $this->getId()); + + sfGuardUserPermissionPeer::addSelectColumns($criteria); + if (!isset($this->lastsfGuardUserPermissionCriteria) || !$this->lastsfGuardUserPermissionCriteria->equals($criteria)) { + $this->collsfGuardUserPermissions = sfGuardUserPermissionPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfGuardUserPermissionCriteria = $criteria; + return $this->collsfGuardUserPermissions; + } + + + public function countsfGuardUserPermissions($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $this->getId()); + + return sfGuardUserPermissionPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfGuardUserPermission(sfGuardUserPermission $l) + { + $this->collsfGuardUserPermissions[] = $l; + $l->setsfGuardPermission($this); + } + + + + public function getsfGuardUserPermissionsJoinsfGuardUser($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardUserPermissions === null) { + if ($this->isNew()) { + $this->collsfGuardUserPermissions = array(); + } else { + + $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $this->getId()); + + $this->collsfGuardUserPermissions = sfGuardUserPermissionPeer::doSelectJoinsfGuardUser($criteria, $con); + } + } else { + + $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $this->getId()); + + if (!isset($this->lastsfGuardUserPermissionCriteria) || !$this->lastsfGuardUserPermissionCriteria->equals($criteria)) { + $this->collsfGuardUserPermissions = sfGuardUserPermissionPeer::doSelectJoinsfGuardUser($criteria, $con); + } + } + $this->lastsfGuardUserPermissionCriteria = $criteria; + + return $this->collsfGuardUserPermissions; + } + + + public function initsfGuardPermissionI18ns() + { + if ($this->collsfGuardPermissionI18ns === null) { + $this->collsfGuardPermissionI18ns = array(); + } + } + + + public function getsfGuardPermissionI18ns($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18nPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardPermissionI18ns === null) { + if ($this->isNew()) { + $this->collsfGuardPermissionI18ns = array(); + } else { + + $criteria->add(sfGuardPermissionI18nPeer::ID, $this->getId()); + + sfGuardPermissionI18nPeer::addSelectColumns($criteria); + $this->collsfGuardPermissionI18ns = sfGuardPermissionI18nPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfGuardPermissionI18nPeer::ID, $this->getId()); + + sfGuardPermissionI18nPeer::addSelectColumns($criteria); + if (!isset($this->lastsfGuardPermissionI18nCriteria) || !$this->lastsfGuardPermissionI18nCriteria->equals($criteria)) { + $this->collsfGuardPermissionI18ns = sfGuardPermissionI18nPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfGuardPermissionI18nCriteria = $criteria; + return $this->collsfGuardPermissionI18ns; + } + + + public function countsfGuardPermissionI18ns($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18nPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfGuardPermissionI18nPeer::ID, $this->getId()); + + return sfGuardPermissionI18nPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfGuardPermissionI18n(sfGuardPermissionI18n $l) + { + $this->collsfGuardPermissionI18ns[] = $l; + $l->setsfGuardPermission($this); + } + + public function getCulture() + { + return $this->culture; + } + + public function setCulture($culture) + { + $this->culture = $culture; + } + + public function getDescription() + { + $obj = $this->getCurrentsfGuardPermissionI18n(); + + return ($obj ? $obj->getDescription() : null); + } + + public function setDescription($value) + { + $this->getCurrentsfGuardPermissionI18n()->setDescription($value); + } + + protected $current_i18n = array(); + + public function getCurrentsfGuardPermissionI18n() + { + if (!isset($this->current_i18n[$this->culture])) + { + $obj = sfGuardPermissionI18nPeer::retrieveByPK($this->getId(), $this->culture); + if ($obj) + { + $this->setsfGuardPermissionI18nForCulture($obj, $this->culture); + } + else + { + $this->setsfGuardPermissionI18nForCulture(new sfGuardPermissionI18n(), $this->culture); + $this->current_i18n[$this->culture]->setCulture($this->culture); + } + } + + return $this->current_i18n[$this->culture]; + } + + public function setsfGuardPermissionI18nForCulture($object, $culture) + { + $this->current_i18n[$culture] = $object; + $this->addsfGuardPermissionI18n($object); + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardPermission:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardPermission::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18n.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18n.php new file mode 100644 index 0000000..085104e --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18n.php @@ -0,0 +1,472 @@ +description; + } + + + public function getId() + { + + return $this->id; + } + + + public function getCulture() + { + + return $this->culture; + } + + + public function setDescription($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->description !== $v) { + $this->description = $v; + $this->modifiedColumns[] = sfGuardPermissionI18nPeer::DESCRIPTION; + } + + } + + public function setId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = sfGuardPermissionI18nPeer::ID; + } + + if ($this->asfGuardPermission !== null && $this->asfGuardPermission->getId() !== $v) { + $this->asfGuardPermission = null; + } + + } + + public function setCulture($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->culture !== $v) { + $this->culture = $v; + $this->modifiedColumns[] = sfGuardPermissionI18nPeer::CULTURE; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->description = $rs->getString($startcol + 0); + + $this->id = $rs->getInt($startcol + 1); + + $this->culture = $rs->getString($startcol + 2); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 3; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardPermissionI18n object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermissionI18n:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardPermissionI18nPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardPermissionI18nPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardPermissionI18n:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermissionI18n:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardPermissionI18nPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardPermissionI18n:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->asfGuardPermission !== null) { + if ($this->asfGuardPermission->isModified() || $this->asfGuardPermission->getCurrentsfGuardPermissionI18n()->isModified()) { + $affectedRows += $this->asfGuardPermission->save($con); + } + $this->setsfGuardPermission($this->asfGuardPermission); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardPermissionI18nPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setNew(false); + } else { + $affectedRows += sfGuardPermissionI18nPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->asfGuardPermission !== null) { + if (!$this->asfGuardPermission->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardPermission->getValidationFailures()); + } + } + + + if (($retval = sfGuardPermissionI18nPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardPermissionI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getDescription(); + break; + case 1: + return $this->getId(); + break; + case 2: + return $this->getCulture(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardPermissionI18nPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getDescription(), + $keys[1] => $this->getId(), + $keys[2] => $this->getCulture(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardPermissionI18nPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setDescription($value); + break; + case 1: + $this->setId($value); + break; + case 2: + $this->setCulture($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardPermissionI18nPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setDescription($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setId($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setCulture($arr[$keys[2]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardPermissionI18nPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardPermissionI18nPeer::DESCRIPTION)) $criteria->add(sfGuardPermissionI18nPeer::DESCRIPTION, $this->description); + if ($this->isColumnModified(sfGuardPermissionI18nPeer::ID)) $criteria->add(sfGuardPermissionI18nPeer::ID, $this->id); + if ($this->isColumnModified(sfGuardPermissionI18nPeer::CULTURE)) $criteria->add(sfGuardPermissionI18nPeer::CULTURE, $this->culture); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardPermissionI18nPeer::DATABASE_NAME); + + $criteria->add(sfGuardPermissionI18nPeer::ID, $this->id); + $criteria->add(sfGuardPermissionI18nPeer::CULTURE, $this->culture); + + return $criteria; + } + + + public function getPrimaryKey() + { + $pks = array(); + + $pks[0] = $this->getId(); + + $pks[1] = $this->getCulture(); + + return $pks; + } + + + public function setPrimaryKey($keys) + { + + $this->setId($keys[0]); + + $this->setCulture($keys[1]); + + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setDescription($this->description); + + + $copyObj->setNew(true); + + $copyObj->setId(NULL); + $copyObj->setCulture(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardPermissionI18nPeer(); + } + return self::$peer; + } + + + public function setsfGuardPermission($v) + { + + + if ($v === null) { + $this->setId(NULL); + } else { + $this->setId($v->getId()); + } + + + $this->asfGuardPermission = $v; + } + + + + public function getsfGuardPermission($con = null) + { + if ($this->asfGuardPermission === null && ($this->id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionPeer.php'; + + $this->asfGuardPermission = sfGuardPermissionPeer::retrieveByPK($this->id, $con); + + + } + return $this->asfGuardPermission; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardPermissionI18n:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardPermissionI18n::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18nPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18nPeer.php new file mode 100644 index 0000000..e4a533a --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionI18nPeer.php @@ -0,0 +1,569 @@ + array ('Description', 'Id', 'Culture', ), + BasePeer::TYPE_COLNAME => array (sfGuardPermissionI18nPeer::DESCRIPTION, sfGuardPermissionI18nPeer::ID, sfGuardPermissionI18nPeer::CULTURE, ), + BasePeer::TYPE_FIELDNAME => array ('description', 'id', 'culture', ), + BasePeer::TYPE_NUM => array (0, 1, 2, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('Description' => 0, 'Id' => 1, 'Culture' => 2, ), + BasePeer::TYPE_COLNAME => array (sfGuardPermissionI18nPeer::DESCRIPTION => 0, sfGuardPermissionI18nPeer::ID => 1, sfGuardPermissionI18nPeer::CULTURE => 2, ), + BasePeer::TYPE_FIELDNAME => array ('description' => 0, 'id' => 1, 'culture' => 2, ), + BasePeer::TYPE_NUM => array (0, 1, 2, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionI18nMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardPermissionI18nMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardPermissionI18nPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardPermissionI18nPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::DESCRIPTION); + + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::ID); + + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::CULTURE); + + } + + const COUNT = 'COUNT(sf_guard_permission_i18n.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_permission_i18n.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardPermissionI18nPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardPermissionI18nPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardPermissionI18nPeer::populateObjects(sfGuardPermissionI18nPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermissionI18nPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardPermissionI18nPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardPermissionI18nPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardPermissionI18nPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinsfGuardPermission(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardPermissionI18nPeer::ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardPermissionI18nPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinsfGuardPermission(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardPermissionI18nPeer::addSelectColumns($c); + $startcol = (sfGuardPermissionI18nPeer::NUM_COLUMNS - sfGuardPermissionI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardPermissionPeer::addSelectColumns($c); + + $c->addJoin(sfGuardPermissionI18nPeer::ID, sfGuardPermissionPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardPermissionI18nPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardPermission(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardPermissionI18n($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardPermissionI18ns(); + $obj2->addsfGuardPermissionI18n($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardPermissionI18nPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardPermissionI18nPeer::ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardPermissionI18nPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardPermissionI18nPeer::addSelectColumns($c); + $startcol2 = (sfGuardPermissionI18nPeer::NUM_COLUMNS - sfGuardPermissionI18nPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardPermissionPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardPermissionPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardPermissionI18nPeer::ID, sfGuardPermissionPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardPermissionI18nPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = sfGuardPermissionPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardPermission(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardPermissionI18n($obj1); break; + } + } + + if ($newObject) { + $obj2->initsfGuardPermissionI18ns(); + $obj2->addsfGuardPermissionI18n($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardPermissionI18nPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermissionI18nPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardPermissionI18nPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardPermissionI18nPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardPermissionI18nPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermissionI18nPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardPermissionI18nPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardPermissionI18nPeer::ID); + $selectCriteria->add(sfGuardPermissionI18nPeer::ID, $criteria->remove(sfGuardPermissionI18nPeer::ID), $comparison); + + $comparison = $criteria->getComparison(sfGuardPermissionI18nPeer::CULTURE); + $selectCriteria->add(sfGuardPermissionI18nPeer::CULTURE, $criteria->remove(sfGuardPermissionI18nPeer::CULTURE), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardPermissionI18nPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardPermissionI18nPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(sfGuardPermissionI18nPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardPermissionI18nPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardPermissionI18n) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + if(count($values) == count($values, COUNT_RECURSIVE)) + { + $values = array($values); + } + $vals = array(); + foreach($values as $value) + { + + $vals[0][] = $value[0]; + $vals[1][] = $value[1]; + } + + $criteria->add(sfGuardPermissionI18nPeer::ID, $vals[0], Criteria::IN); + $criteria->add(sfGuardPermissionI18nPeer::CULTURE, $vals[1], Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(sfGuardPermissionI18n $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardPermissionI18nPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardPermissionI18nPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardPermissionI18nPeer::DATABASE_NAME, sfGuardPermissionI18nPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardPermissionI18nPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK( $id, $culture, $con = null) { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $criteria = new Criteria(); + $criteria->add(sfGuardPermissionI18nPeer::ID, $id); + $criteria->add(sfGuardPermissionI18nPeer::CULTURE, $culture); + $v = sfGuardPermissionI18nPeer::doSelect($criteria, $con); + + return !empty($v) ? $v[0] : null; + } +} +if (Propel::isInit()) { + try { + BasesfGuardPermissionI18nPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionI18nMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardPermissionI18nMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionPeer.php new file mode 100644 index 0000000..8dcdda6 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionPeer.php @@ -0,0 +1,493 @@ + array ('Id', 'Name', ), + BasePeer::TYPE_COLNAME => array (sfGuardPermissionPeer::ID, sfGuardPermissionPeer::NAME, ), + BasePeer::TYPE_FIELDNAME => array ('id', 'name', ), + BasePeer::TYPE_NUM => array (0, 1, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Name' => 1, ), + BasePeer::TYPE_COLNAME => array (sfGuardPermissionPeer::ID => 0, sfGuardPermissionPeer::NAME => 1, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, ), + BasePeer::TYPE_NUM => array (0, 1, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardPermissionMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardPermissionPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardPermissionPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardPermissionPeer::ID); + + $criteria->addSelectColumn(sfGuardPermissionPeer::NAME); + + } + + const COUNT = 'COUNT(sf_guard_permission.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_permission.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardPermissionPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardPermissionPeer::populateObjects(sfGuardPermissionPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermissionPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardPermissionPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardPermissionPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardPermissionPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doSelectWithI18n(Criteria $c, $culture = null, $con = null) + { + if ($culture === null) + { + $culture = sfContext::getInstance()->getUser()->getCulture(); + } + + if ($c->getDbName() == Propel::getDefaultDB()) + { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardPermissionPeer::addSelectColumns($c); + $startcol = (sfGuardPermissionPeer::NUM_COLUMNS - sfGuardPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardPermissionI18nPeer::addSelectColumns($c); + + $c->addJoin(sfGuardPermissionPeer::ID, sfGuardPermissionI18nPeer::ID); + $c->add(sfGuardPermissionI18nPeer::CULTURE, $culture); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + $obj1->setCulture($culture); + + $omClass = sfGuardPermissionI18nPeer::getOMClass($rs, $startcol); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $obj1->setsfGuardPermissionI18nForCulture($obj2, $culture); + $obj2->setsfGuardPermission($obj1); + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardPermissionPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermissionPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardPermissionPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + $criteria->remove(sfGuardPermissionPeer::ID); + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardPermissionPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardPermissionPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardPermissionPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardPermissionPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardPermissionPeer::ID); + $selectCriteria->add(sfGuardPermissionPeer::ID, $criteria->remove(sfGuardPermissionPeer::ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardPermissionPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardPermissionPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += sfGuardPermissionPeer::doOnDeleteCascade(new Criteria(), $con); + $affectedRows += BasePeer::doDeleteAll(sfGuardPermissionPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardPermissionPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardPermission) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + $criteria->add(sfGuardPermissionPeer::ID, (array) $values, Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + $affectedRows += sfGuardPermissionPeer::doOnDeleteCascade($criteria, $con); + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected static function doOnDeleteCascade(Criteria $criteria, Connection $con) + { + $affectedRows = 0; + + $objects = sfGuardPermissionPeer::doSelect($criteria, $con); + foreach($objects as $obj) { + + + include_once 'plugins/sfGuardPlugin/lib/model/sfGuardGroupPermission.php'; + + $c = new Criteria(); + + $c->add(sfGuardGroupPermissionPeer::PERMISSION_ID, $obj->getId()); + $affectedRows += sfGuardGroupPermissionPeer::doDelete($c, $con); + + include_once 'plugins/sfGuardPlugin/lib/model/sfGuardUserPermission.php'; + + $c = new Criteria(); + + $c->add(sfGuardUserPermissionPeer::PERMISSION_ID, $obj->getId()); + $affectedRows += sfGuardUserPermissionPeer::doDelete($c, $con); + + include_once 'plugins/sfGuardPlugin/lib/model/sfGuardPermissionI18n.php'; + + $c = new Criteria(); + + $c->add(sfGuardPermissionI18nPeer::ID, $obj->getId()); + $affectedRows += sfGuardPermissionI18nPeer::doDelete($c, $con); + } + return $affectedRows; + } + + + public static function doValidate(sfGuardPermission $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardPermissionPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardPermissionPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardPermissionPeer::DATABASE_NAME, sfGuardPermissionPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardPermissionPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK($pk, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $criteria = new Criteria(sfGuardPermissionPeer::DATABASE_NAME); + + $criteria->add(sfGuardPermissionPeer::ID, $pk); + + + $v = sfGuardPermissionPeer::doSelect($criteria, $con); + + return !empty($v) > 0 ? $v[0] : null; + } + + + public static function retrieveByPKs($pks, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $objs = null; + if (empty($pks)) { + $objs = array(); + } else { + $criteria = new Criteria(); + $criteria->add(sfGuardPermissionPeer::ID, $pks, Criteria::IN); + $objs = sfGuardPermissionPeer::doSelect($criteria, $con); + } + return $objs; + } + +} +if (Propel::isInit()) { + try { + BasesfGuardPermissionPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardPermissionMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardPermissionMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKey.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKey.php new file mode 100644 index 0000000..6973251 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKey.php @@ -0,0 +1,533 @@ +user_id; + } + + + public function getRememberKey() + { + + return $this->remember_key; + } + + + public function getIpAddress() + { + + return $this->ip_address; + } + + + public function getCreatedAt($format = 'Y-m-d H:i:s') + { + + if ($this->created_at === null || $this->created_at === '') { + return null; + } elseif (!is_int($this->created_at)) { + $ts = strtotime($this->created_at); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true)); + } + } else { + $ts = $this->created_at; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function setUserId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->user_id !== $v) { + $this->user_id = $v; + $this->modifiedColumns[] = sfGuardRememberKeyPeer::USER_ID; + } + + if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) { + $this->asfGuardUser = null; + } + + } + + public function setRememberKey($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->remember_key !== $v) { + $this->remember_key = $v; + $this->modifiedColumns[] = sfGuardRememberKeyPeer::REMEMBER_KEY; + } + + } + + public function setIpAddress($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->ip_address !== $v) { + $this->ip_address = $v; + $this->modifiedColumns[] = sfGuardRememberKeyPeer::IP_ADDRESS; + } + + } + + public function setCreatedAt($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->created_at !== $ts) { + $this->created_at = $ts; + $this->modifiedColumns[] = sfGuardRememberKeyPeer::CREATED_AT; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->user_id = $rs->getInt($startcol + 0); + + $this->remember_key = $rs->getString($startcol + 1); + + $this->ip_address = $rs->getString($startcol + 2); + + $this->created_at = $rs->getTimestamp($startcol + 3, null); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 4; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardRememberKey object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardRememberKey:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardRememberKeyPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardRememberKeyPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardRememberKey:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardRememberKey:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isNew() && !$this->isColumnModified(sfGuardRememberKeyPeer::CREATED_AT)) + { + $this->setCreatedAt(time()); + } + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardRememberKeyPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardRememberKey:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->asfGuardUser !== null) { + if ($this->asfGuardUser->isModified()) { + $affectedRows += $this->asfGuardUser->save($con); + } + $this->setsfGuardUser($this->asfGuardUser); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardRememberKeyPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setNew(false); + } else { + $affectedRows += sfGuardRememberKeyPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->asfGuardUser !== null) { + if (!$this->asfGuardUser->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures()); + } + } + + + if (($retval = sfGuardRememberKeyPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardRememberKeyPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getUserId(); + break; + case 1: + return $this->getRememberKey(); + break; + case 2: + return $this->getIpAddress(); + break; + case 3: + return $this->getCreatedAt(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardRememberKeyPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getUserId(), + $keys[1] => $this->getRememberKey(), + $keys[2] => $this->getIpAddress(), + $keys[3] => $this->getCreatedAt(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardRememberKeyPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setUserId($value); + break; + case 1: + $this->setRememberKey($value); + break; + case 2: + $this->setIpAddress($value); + break; + case 3: + $this->setCreatedAt($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardRememberKeyPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setUserId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setRememberKey($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setIpAddress($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setCreatedAt($arr[$keys[3]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardRememberKeyPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardRememberKeyPeer::USER_ID)) $criteria->add(sfGuardRememberKeyPeer::USER_ID, $this->user_id); + if ($this->isColumnModified(sfGuardRememberKeyPeer::REMEMBER_KEY)) $criteria->add(sfGuardRememberKeyPeer::REMEMBER_KEY, $this->remember_key); + if ($this->isColumnModified(sfGuardRememberKeyPeer::IP_ADDRESS)) $criteria->add(sfGuardRememberKeyPeer::IP_ADDRESS, $this->ip_address); + if ($this->isColumnModified(sfGuardRememberKeyPeer::CREATED_AT)) $criteria->add(sfGuardRememberKeyPeer::CREATED_AT, $this->created_at); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardRememberKeyPeer::DATABASE_NAME); + + $criteria->add(sfGuardRememberKeyPeer::USER_ID, $this->user_id); + $criteria->add(sfGuardRememberKeyPeer::IP_ADDRESS, $this->ip_address); + + return $criteria; + } + + + public function getPrimaryKey() + { + $pks = array(); + + $pks[0] = $this->getUserId(); + + $pks[1] = $this->getIpAddress(); + + return $pks; + } + + + public function setPrimaryKey($keys) + { + + $this->setUserId($keys[0]); + + $this->setIpAddress($keys[1]); + + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setRememberKey($this->remember_key); + + $copyObj->setCreatedAt($this->created_at); + + + $copyObj->setNew(true); + + $copyObj->setUserId(NULL); + $copyObj->setIpAddress(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardRememberKeyPeer(); + } + return self::$peer; + } + + + public function setsfGuardUser($v) + { + + + if ($v === null) { + $this->setUserId(NULL); + } else { + $this->setUserId($v->getId()); + } + + + $this->asfGuardUser = $v; + } + + + + public function getsfGuardUser($con = null) + { + if ($this->asfGuardUser === null && ($this->user_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php'; + + $this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con); + + + } + return $this->asfGuardUser; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardRememberKey:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardRememberKey::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKeyPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKeyPeer.php new file mode 100644 index 0000000..087e846 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKeyPeer.php @@ -0,0 +1,574 @@ + array ('UserId', 'RememberKey', 'IpAddress', 'CreatedAt', ), + BasePeer::TYPE_COLNAME => array (sfGuardRememberKeyPeer::USER_ID, sfGuardRememberKeyPeer::REMEMBER_KEY, sfGuardRememberKeyPeer::IP_ADDRESS, sfGuardRememberKeyPeer::CREATED_AT, ), + BasePeer::TYPE_FIELDNAME => array ('user_id', 'remember_key', 'ip_address', 'created_at', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('UserId' => 0, 'RememberKey' => 1, 'IpAddress' => 2, 'CreatedAt' => 3, ), + BasePeer::TYPE_COLNAME => array (sfGuardRememberKeyPeer::USER_ID => 0, sfGuardRememberKeyPeer::REMEMBER_KEY => 1, sfGuardRememberKeyPeer::IP_ADDRESS => 2, sfGuardRememberKeyPeer::CREATED_AT => 3, ), + BasePeer::TYPE_FIELDNAME => array ('user_id' => 0, 'remember_key' => 1, 'ip_address' => 2, 'created_at' => 3, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardRememberKeyMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardRememberKeyMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardRememberKeyPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardRememberKeyPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardRememberKeyPeer::USER_ID); + + $criteria->addSelectColumn(sfGuardRememberKeyPeer::REMEMBER_KEY); + + $criteria->addSelectColumn(sfGuardRememberKeyPeer::IP_ADDRESS); + + $criteria->addSelectColumn(sfGuardRememberKeyPeer::CREATED_AT); + + } + + const COUNT = 'COUNT(sf_guard_remember_key.USER_ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_remember_key.USER_ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardRememberKeyPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardRememberKeyPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardRememberKeyPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardRememberKeyPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardRememberKeyPeer::populateObjects(sfGuardRememberKeyPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardRememberKeyPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardRememberKeyPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardRememberKeyPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardRememberKeyPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardRememberKeyPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardRememberKeyPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardRememberKeyPeer::USER_ID, sfGuardUserPeer::ID); + + $rs = sfGuardRememberKeyPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardRememberKeyPeer::addSelectColumns($c); + $startcol = (sfGuardRememberKeyPeer::NUM_COLUMNS - sfGuardRememberKeyPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardUserPeer::addSelectColumns($c); + + $c->addJoin(sfGuardRememberKeyPeer::USER_ID, sfGuardUserPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardRememberKeyPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardRememberKey($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardRememberKeys(); + $obj2->addsfGuardRememberKey($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardRememberKeyPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardRememberKeyPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardRememberKeyPeer::USER_ID, sfGuardUserPeer::ID); + + $rs = sfGuardRememberKeyPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardRememberKeyPeer::addSelectColumns($c); + $startcol2 = (sfGuardRememberKeyPeer::NUM_COLUMNS - sfGuardRememberKeyPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardUserPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardRememberKeyPeer::USER_ID, sfGuardUserPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardRememberKeyPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardRememberKey($obj1); break; + } + } + + if ($newObject) { + $obj2->initsfGuardRememberKeys(); + $obj2->addsfGuardRememberKey($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardRememberKeyPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardRememberKeyPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardRememberKeyPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardRememberKeyPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardRememberKeyPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardRememberKeyPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardRememberKeyPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardRememberKeyPeer::USER_ID); + $selectCriteria->add(sfGuardRememberKeyPeer::USER_ID, $criteria->remove(sfGuardRememberKeyPeer::USER_ID), $comparison); + + $comparison = $criteria->getComparison(sfGuardRememberKeyPeer::IP_ADDRESS); + $selectCriteria->add(sfGuardRememberKeyPeer::IP_ADDRESS, $criteria->remove(sfGuardRememberKeyPeer::IP_ADDRESS), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardRememberKeyPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardRememberKeyPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(sfGuardRememberKeyPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardRememberKeyPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardRememberKey) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + if(count($values) == count($values, COUNT_RECURSIVE)) + { + $values = array($values); + } + $vals = array(); + foreach($values as $value) + { + + $vals[0][] = $value[0]; + $vals[1][] = $value[1]; + } + + $criteria->add(sfGuardRememberKeyPeer::USER_ID, $vals[0], Criteria::IN); + $criteria->add(sfGuardRememberKeyPeer::IP_ADDRESS, $vals[1], Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(sfGuardRememberKey $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardRememberKeyPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardRememberKeyPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardRememberKeyPeer::DATABASE_NAME, sfGuardRememberKeyPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardRememberKeyPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK( $user_id, $ip_address, $con = null) { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $criteria = new Criteria(); + $criteria->add(sfGuardRememberKeyPeer::USER_ID, $user_id); + $criteria->add(sfGuardRememberKeyPeer::IP_ADDRESS, $ip_address); + $v = sfGuardRememberKeyPeer::doSelect($criteria, $con); + + return !empty($v) ? $v[0] : null; + } +} +if (Propel::isInit()) { + try { + BasesfGuardRememberKeyPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardRememberKeyMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardRememberKeyMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUser.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUser.php new file mode 100644 index 0000000..1bfa0e2 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUser.php @@ -0,0 +1,5307 @@ +id; + } + + + public function getUsername() + { + + return $this->username; + } + + + public function getAlgorithm() + { + + return $this->algorithm; + } + + + public function getSalt() + { + + return $this->salt; + } + + + public function getPassword() + { + + return $this->password; + } + + + public function getCreatedAt($format = 'Y-m-d H:i:s') + { + + if ($this->created_at === null || $this->created_at === '') { + return null; + } elseif (!is_int($this->created_at)) { + $ts = strtotime($this->created_at); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true)); + } + } else { + $ts = $this->created_at; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function getLastLogin($format = 'Y-m-d H:i:s') + { + + if ($this->last_login === null || $this->last_login === '') { + return null; + } elseif (!is_int($this->last_login)) { + $ts = strtotime($this->last_login); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [last_login] as date/time value: " . var_export($this->last_login, true)); + } + } else { + $ts = $this->last_login; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function getIsActive() + { + + return $this->is_active; + } + + + public function getIsSuperAdmin() + { + + return $this->is_super_admin; + } + + + public function getIsVerified() + { + + return $this->is_verified; + } + + + public function getShowContent() + { + + return $this->show_content; + } + + + public function getCulture() + { + + return $this->culture; + } + + + public function getEmail() + { + + return $this->email; + } + + + public function getEmailPrivate() + { + + return $this->email_private; + } + + + public function getNewEmail() + { + + return $this->new_email; + } + + + public function getNewEmailKey() + { + + return $this->new_email_key; + } + + + public function getNewPasswordKey() + { + + return $this->new_password_key; + } + + + public function getKeyExpires($format = 'Y-m-d H:i:s') + { + + if ($this->key_expires === null || $this->key_expires === '') { + return null; + } elseif (!is_int($this->key_expires)) { + $ts = strtotime($this->key_expires); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [key_expires] as date/time value: " . var_export($this->key_expires, true)); + } + } else { + $ts = $this->key_expires; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function getName() + { + + return $this->name; + } + + + public function getNamePrivate() + { + + return $this->name_private; + } + + + public function getDob() + { + + return $this->dob; + } + + + public function getSex() + { + + return $this->sex; + } + + + public function getDescription() + { + + return $this->description; + } + + + public function getResidenceId() + { + + return $this->residence_id; + } + + + public function getAvatar() + { + + return $this->avatar; + } + + + public function getMsn() + { + + return $this->msn; + } + + + public function getIcq() + { + + return $this->icq; + } + + + public function getHomepage() + { + + return $this->homepage; + } + + + public function getPhone() + { + + return $this->phone; + } + + + public function getOptIn() + { + + return $this->opt_in; + } + + + public function getEditorialNotification() + { + + return $this->editorial_notification; + } + + + public function getShowLoginStatus() + { + + return $this->show_login_status; + } + + + public function getLastActive($format = 'Y-m-d H:i:s') + { + + if ($this->last_active === null || $this->last_active === '') { + return null; + } elseif (!is_int($this->last_active)) { + $ts = strtotime($this->last_active); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [last_active] as date/time value: " . var_export($this->last_active, true)); + } + } else { + $ts = $this->last_active; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function getDobIsDerived() + { + + return $this->dob_is_derived; + } + + + public function getNeedProfileCheck() + { + + return $this->need_profile_check; + } + + + public function getFirstReaktorLogin($format = 'Y-m-d H:i:s') + { + + if ($this->first_reaktor_login === null || $this->first_reaktor_login === '') { + return null; + } elseif (!is_int($this->first_reaktor_login)) { + $ts = strtotime($this->first_reaktor_login); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [first_reaktor_login] as date/time value: " . var_export($this->first_reaktor_login, true)); + } + } else { + $ts = $this->first_reaktor_login; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function setId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = sfGuardUserPeer::ID; + } + + } + + public function setUsername($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->username !== $v) { + $this->username = $v; + $this->modifiedColumns[] = sfGuardUserPeer::USERNAME; + } + + } + + public function setAlgorithm($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->algorithm !== $v || $v === 'sha1') { + $this->algorithm = $v; + $this->modifiedColumns[] = sfGuardUserPeer::ALGORITHM; + } + + } + + public function setSalt($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->salt !== $v) { + $this->salt = $v; + $this->modifiedColumns[] = sfGuardUserPeer::SALT; + } + + } + + public function setPassword($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->password !== $v) { + $this->password = $v; + $this->modifiedColumns[] = sfGuardUserPeer::PASSWORD; + } + + } + + public function setCreatedAt($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->created_at !== $ts) { + $this->created_at = $ts; + $this->modifiedColumns[] = sfGuardUserPeer::CREATED_AT; + } + + } + + public function setLastLogin($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [last_login] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->last_login !== $ts) { + $this->last_login = $ts; + $this->modifiedColumns[] = sfGuardUserPeer::LAST_LOGIN; + } + + } + + public function setIsActive($v) + { + + if ($this->is_active !== $v || $v === true) { + $this->is_active = $v; + $this->modifiedColumns[] = sfGuardUserPeer::IS_ACTIVE; + } + + } + + public function setIsSuperAdmin($v) + { + + if ($this->is_super_admin !== $v || $v === false) { + $this->is_super_admin = $v; + $this->modifiedColumns[] = sfGuardUserPeer::IS_SUPER_ADMIN; + } + + } + + public function setIsVerified($v) + { + + if ($this->is_verified !== $v || $v === false) { + $this->is_verified = $v; + $this->modifiedColumns[] = sfGuardUserPeer::IS_VERIFIED; + } + + } + + public function setShowContent($v) + { + + if ($this->show_content !== $v || $v === false) { + $this->show_content = $v; + $this->modifiedColumns[] = sfGuardUserPeer::SHOW_CONTENT; + } + + } + + public function setCulture($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->culture !== $v || $v === 'no') { + $this->culture = $v; + $this->modifiedColumns[] = sfGuardUserPeer::CULTURE; + } + + } + + public function setEmail($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->email !== $v) { + $this->email = $v; + $this->modifiedColumns[] = sfGuardUserPeer::EMAIL; + } + + } + + public function setEmailPrivate($v) + { + + if ($this->email_private !== $v || $v === true) { + $this->email_private = $v; + $this->modifiedColumns[] = sfGuardUserPeer::EMAIL_PRIVATE; + } + + } + + public function setNewEmail($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->new_email !== $v) { + $this->new_email = $v; + $this->modifiedColumns[] = sfGuardUserPeer::NEW_EMAIL; + } + + } + + public function setNewEmailKey($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->new_email_key !== $v) { + $this->new_email_key = $v; + $this->modifiedColumns[] = sfGuardUserPeer::NEW_EMAIL_KEY; + } + + } + + public function setNewPasswordKey($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->new_password_key !== $v) { + $this->new_password_key = $v; + $this->modifiedColumns[] = sfGuardUserPeer::NEW_PASSWORD_KEY; + } + + } + + public function setKeyExpires($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [key_expires] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->key_expires !== $ts) { + $this->key_expires = $ts; + $this->modifiedColumns[] = sfGuardUserPeer::KEY_EXPIRES; + } + + } + + public function setName($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[] = sfGuardUserPeer::NAME; + } + + } + + public function setNamePrivate($v) + { + + if ($this->name_private !== $v || $v === false) { + $this->name_private = $v; + $this->modifiedColumns[] = sfGuardUserPeer::NAME_PRIVATE; + } + + } + + public function setDob($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->dob !== $v) { + $this->dob = $v; + $this->modifiedColumns[] = sfGuardUserPeer::DOB; + } + + } + + public function setSex($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->sex !== $v) { + $this->sex = $v; + $this->modifiedColumns[] = sfGuardUserPeer::SEX; + } + + } + + public function setDescription($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->description !== $v) { + $this->description = $v; + $this->modifiedColumns[] = sfGuardUserPeer::DESCRIPTION; + } + + } + + public function setResidenceId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->residence_id !== $v) { + $this->residence_id = $v; + $this->modifiedColumns[] = sfGuardUserPeer::RESIDENCE_ID; + } + + if ($this->aResidence !== null && $this->aResidence->getId() !== $v) { + $this->aResidence = null; + } + + } + + public function setAvatar($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->avatar !== $v) { + $this->avatar = $v; + $this->modifiedColumns[] = sfGuardUserPeer::AVATAR; + } + + } + + public function setMsn($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->msn !== $v) { + $this->msn = $v; + $this->modifiedColumns[] = sfGuardUserPeer::MSN; + } + + } + + public function setIcq($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->icq !== $v) { + $this->icq = $v; + $this->modifiedColumns[] = sfGuardUserPeer::ICQ; + } + + } + + public function setHomepage($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->homepage !== $v) { + $this->homepage = $v; + $this->modifiedColumns[] = sfGuardUserPeer::HOMEPAGE; + } + + } + + public function setPhone($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->phone !== $v) { + $this->phone = $v; + $this->modifiedColumns[] = sfGuardUserPeer::PHONE; + } + + } + + public function setOptIn($v) + { + + if ($this->opt_in !== $v || $v === false) { + $this->opt_in = $v; + $this->modifiedColumns[] = sfGuardUserPeer::OPT_IN; + } + + } + + public function setEditorialNotification($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->editorial_notification !== $v || $v === 0) { + $this->editorial_notification = $v; + $this->modifiedColumns[] = sfGuardUserPeer::EDITORIAL_NOTIFICATION; + } + + } + + public function setShowLoginStatus($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->show_login_status !== $v || $v === 1) { + $this->show_login_status = $v; + $this->modifiedColumns[] = sfGuardUserPeer::SHOW_LOGIN_STATUS; + } + + } + + public function setLastActive($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [last_active] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->last_active !== $ts) { + $this->last_active = $ts; + $this->modifiedColumns[] = sfGuardUserPeer::LAST_ACTIVE; + } + + } + + public function setDobIsDerived($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->dob_is_derived !== $v || $v === 0) { + $this->dob_is_derived = $v; + $this->modifiedColumns[] = sfGuardUserPeer::DOB_IS_DERIVED; + } + + } + + public function setNeedProfileCheck($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->need_profile_check !== $v || $v === 0) { + $this->need_profile_check = $v; + $this->modifiedColumns[] = sfGuardUserPeer::NEED_PROFILE_CHECK; + } + + } + + public function setFirstReaktorLogin($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [first_reaktor_login] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->first_reaktor_login !== $ts) { + $this->first_reaktor_login = $ts; + $this->modifiedColumns[] = sfGuardUserPeer::FIRST_REAKTOR_LOGIN; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->id = $rs->getInt($startcol + 0); + + $this->username = $rs->getString($startcol + 1); + + $this->algorithm = $rs->getString($startcol + 2); + + $this->salt = $rs->getString($startcol + 3); + + $this->password = $rs->getString($startcol + 4); + + $this->created_at = $rs->getTimestamp($startcol + 5, null); + + $this->last_login = $rs->getTimestamp($startcol + 6, null); + + $this->is_active = $rs->getBoolean($startcol + 7); + + $this->is_super_admin = $rs->getBoolean($startcol + 8); + + $this->is_verified = $rs->getBoolean($startcol + 9); + + $this->show_content = $rs->getBoolean($startcol + 10); + + $this->culture = $rs->getString($startcol + 11); + + $this->email = $rs->getString($startcol + 12); + + $this->email_private = $rs->getBoolean($startcol + 13); + + $this->new_email = $rs->getString($startcol + 14); + + $this->new_email_key = $rs->getString($startcol + 15); + + $this->new_password_key = $rs->getString($startcol + 16); + + $this->key_expires = $rs->getTimestamp($startcol + 17, null); + + $this->name = $rs->getString($startcol + 18); + + $this->name_private = $rs->getBoolean($startcol + 19); + + $this->dob = $rs->getString($startcol + 20); + + $this->sex = $rs->getInt($startcol + 21); + + $this->description = $rs->getString($startcol + 22); + + $this->residence_id = $rs->getInt($startcol + 23); + + $this->avatar = $rs->getString($startcol + 24); + + $this->msn = $rs->getString($startcol + 25); + + $this->icq = $rs->getInt($startcol + 26); + + $this->homepage = $rs->getString($startcol + 27); + + $this->phone = $rs->getString($startcol + 28); + + $this->opt_in = $rs->getBoolean($startcol + 29); + + $this->editorial_notification = $rs->getInt($startcol + 30); + + $this->show_login_status = $rs->getInt($startcol + 31); + + $this->last_active = $rs->getTimestamp($startcol + 32, null); + + $this->dob_is_derived = $rs->getInt($startcol + 33); + + $this->need_profile_check = $rs->getInt($startcol + 34); + + $this->first_reaktor_login = $rs->getTimestamp($startcol + 35, null); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 36; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardUser object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUser:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardUserPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardUserPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardUser:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUser:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isNew() && !$this->isColumnModified(sfGuardUserPeer::CREATED_AT)) + { + $this->setCreatedAt(time()); + } + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardUserPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardUser:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->aResidence !== null) { + if ($this->aResidence->isModified()) { + $affectedRows += $this->aResidence->save($con); + } + $this->setResidence($this->aResidence); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardUserPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setId($pk); + $this->setNew(false); + } else { + $affectedRows += sfGuardUserPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + if ($this->collMessagessRelatedByToUserId !== null) { + foreach($this->collMessagessRelatedByToUserId as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collMessagessRelatedByFromUserId !== null) { + foreach($this->collMessagessRelatedByFromUserId as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collMessagesIgnoredUsersRelatedByUserId !== null) { + foreach($this->collMessagesIgnoredUsersRelatedByUserId as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collMessagesIgnoredUsersRelatedByIgnoresUserId !== null) { + foreach($this->collMessagesIgnoredUsersRelatedByIgnoresUserId as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collAdminMessages !== null) { + foreach($this->collAdminMessages as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collRecommendedArtworks !== null) { + foreach($this->collRecommendedArtworks as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collsfGuardUserPermissions !== null) { + foreach($this->collsfGuardUserPermissions as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collsfGuardUserGroups !== null) { + foreach($this->collsfGuardUserGroups as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collsfGuardRememberKeys !== null) { + foreach($this->collsfGuardRememberKeys as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collsfComments !== null) { + foreach($this->collsfComments as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collReaktorArtworks !== null) { + foreach($this->collReaktorArtworks as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collUserInterests !== null) { + foreach($this->collUserInterests as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collTags !== null) { + foreach($this->collTags as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collTaggings !== null) { + foreach($this->collTaggings as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collUserResources !== null) { + foreach($this->collUserResources as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collReaktorFiles !== null) { + foreach($this->collReaktorFiles as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collRelatedArtworks !== null) { + foreach($this->collRelatedArtworks as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collReaktorArtworkHistorys !== null) { + foreach($this->collReaktorArtworkHistorys as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collCategoryArtworks !== null) { + foreach($this->collCategoryArtworks as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collArticles !== null) { + foreach($this->collArticles as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collArticleArticleRelations !== null) { + foreach($this->collArticleArticleRelations as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collArticleArtworkRelations !== null) { + foreach($this->collArticleArtworkRelations as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collArticleFiles !== null) { + foreach($this->collArticleFiles as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collFavouritesRelatedByUserId !== null) { + foreach($this->collFavouritesRelatedByUserId as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collFavouritesRelatedByFriendId !== null) { + foreach($this->collFavouritesRelatedByFriendId as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + if ($this->collHistorys !== null) { + foreach($this->collHistorys as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->aResidence !== null) { + if (!$this->aResidence->validate($columns)) { + $failureMap = array_merge($failureMap, $this->aResidence->getValidationFailures()); + } + } + + + if (($retval = sfGuardUserPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + if ($this->collMessagessRelatedByToUserId !== null) { + foreach($this->collMessagessRelatedByToUserId as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collMessagessRelatedByFromUserId !== null) { + foreach($this->collMessagessRelatedByFromUserId as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collMessagesIgnoredUsersRelatedByUserId !== null) { + foreach($this->collMessagesIgnoredUsersRelatedByUserId as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collMessagesIgnoredUsersRelatedByIgnoresUserId !== null) { + foreach($this->collMessagesIgnoredUsersRelatedByIgnoresUserId as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collAdminMessages !== null) { + foreach($this->collAdminMessages as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collRecommendedArtworks !== null) { + foreach($this->collRecommendedArtworks as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collsfGuardUserPermissions !== null) { + foreach($this->collsfGuardUserPermissions as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collsfGuardUserGroups !== null) { + foreach($this->collsfGuardUserGroups as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collsfGuardRememberKeys !== null) { + foreach($this->collsfGuardRememberKeys as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collsfComments !== null) { + foreach($this->collsfComments as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collReaktorArtworks !== null) { + foreach($this->collReaktorArtworks as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collUserInterests !== null) { + foreach($this->collUserInterests as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collTags !== null) { + foreach($this->collTags as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collTaggings !== null) { + foreach($this->collTaggings as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collUserResources !== null) { + foreach($this->collUserResources as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collReaktorFiles !== null) { + foreach($this->collReaktorFiles as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collRelatedArtworks !== null) { + foreach($this->collRelatedArtworks as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collReaktorArtworkHistorys !== null) { + foreach($this->collReaktorArtworkHistorys as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collCategoryArtworks !== null) { + foreach($this->collCategoryArtworks as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collArticles !== null) { + foreach($this->collArticles as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collArticleArticleRelations !== null) { + foreach($this->collArticleArticleRelations as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collArticleArtworkRelations !== null) { + foreach($this->collArticleArtworkRelations as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collArticleFiles !== null) { + foreach($this->collArticleFiles as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collFavouritesRelatedByUserId !== null) { + foreach($this->collFavouritesRelatedByUserId as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collFavouritesRelatedByFriendId !== null) { + foreach($this->collFavouritesRelatedByFriendId as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + if ($this->collHistorys !== null) { + foreach($this->collHistorys as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardUserPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getUsername(); + break; + case 2: + return $this->getAlgorithm(); + break; + case 3: + return $this->getSalt(); + break; + case 4: + return $this->getPassword(); + break; + case 5: + return $this->getCreatedAt(); + break; + case 6: + return $this->getLastLogin(); + break; + case 7: + return $this->getIsActive(); + break; + case 8: + return $this->getIsSuperAdmin(); + break; + case 9: + return $this->getIsVerified(); + break; + case 10: + return $this->getShowContent(); + break; + case 11: + return $this->getCulture(); + break; + case 12: + return $this->getEmail(); + break; + case 13: + return $this->getEmailPrivate(); + break; + case 14: + return $this->getNewEmail(); + break; + case 15: + return $this->getNewEmailKey(); + break; + case 16: + return $this->getNewPasswordKey(); + break; + case 17: + return $this->getKeyExpires(); + break; + case 18: + return $this->getName(); + break; + case 19: + return $this->getNamePrivate(); + break; + case 20: + return $this->getDob(); + break; + case 21: + return $this->getSex(); + break; + case 22: + return $this->getDescription(); + break; + case 23: + return $this->getResidenceId(); + break; + case 24: + return $this->getAvatar(); + break; + case 25: + return $this->getMsn(); + break; + case 26: + return $this->getIcq(); + break; + case 27: + return $this->getHomepage(); + break; + case 28: + return $this->getPhone(); + break; + case 29: + return $this->getOptIn(); + break; + case 30: + return $this->getEditorialNotification(); + break; + case 31: + return $this->getShowLoginStatus(); + break; + case 32: + return $this->getLastActive(); + break; + case 33: + return $this->getDobIsDerived(); + break; + case 34: + return $this->getNeedProfileCheck(); + break; + case 35: + return $this->getFirstReaktorLogin(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardUserPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getUsername(), + $keys[2] => $this->getAlgorithm(), + $keys[3] => $this->getSalt(), + $keys[4] => $this->getPassword(), + $keys[5] => $this->getCreatedAt(), + $keys[6] => $this->getLastLogin(), + $keys[7] => $this->getIsActive(), + $keys[8] => $this->getIsSuperAdmin(), + $keys[9] => $this->getIsVerified(), + $keys[10] => $this->getShowContent(), + $keys[11] => $this->getCulture(), + $keys[12] => $this->getEmail(), + $keys[13] => $this->getEmailPrivate(), + $keys[14] => $this->getNewEmail(), + $keys[15] => $this->getNewEmailKey(), + $keys[16] => $this->getNewPasswordKey(), + $keys[17] => $this->getKeyExpires(), + $keys[18] => $this->getName(), + $keys[19] => $this->getNamePrivate(), + $keys[20] => $this->getDob(), + $keys[21] => $this->getSex(), + $keys[22] => $this->getDescription(), + $keys[23] => $this->getResidenceId(), + $keys[24] => $this->getAvatar(), + $keys[25] => $this->getMsn(), + $keys[26] => $this->getIcq(), + $keys[27] => $this->getHomepage(), + $keys[28] => $this->getPhone(), + $keys[29] => $this->getOptIn(), + $keys[30] => $this->getEditorialNotification(), + $keys[31] => $this->getShowLoginStatus(), + $keys[32] => $this->getLastActive(), + $keys[33] => $this->getDobIsDerived(), + $keys[34] => $this->getNeedProfileCheck(), + $keys[35] => $this->getFirstReaktorLogin(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardUserPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setUsername($value); + break; + case 2: + $this->setAlgorithm($value); + break; + case 3: + $this->setSalt($value); + break; + case 4: + $this->setPassword($value); + break; + case 5: + $this->setCreatedAt($value); + break; + case 6: + $this->setLastLogin($value); + break; + case 7: + $this->setIsActive($value); + break; + case 8: + $this->setIsSuperAdmin($value); + break; + case 9: + $this->setIsVerified($value); + break; + case 10: + $this->setShowContent($value); + break; + case 11: + $this->setCulture($value); + break; + case 12: + $this->setEmail($value); + break; + case 13: + $this->setEmailPrivate($value); + break; + case 14: + $this->setNewEmail($value); + break; + case 15: + $this->setNewEmailKey($value); + break; + case 16: + $this->setNewPasswordKey($value); + break; + case 17: + $this->setKeyExpires($value); + break; + case 18: + $this->setName($value); + break; + case 19: + $this->setNamePrivate($value); + break; + case 20: + $this->setDob($value); + break; + case 21: + $this->setSex($value); + break; + case 22: + $this->setDescription($value); + break; + case 23: + $this->setResidenceId($value); + break; + case 24: + $this->setAvatar($value); + break; + case 25: + $this->setMsn($value); + break; + case 26: + $this->setIcq($value); + break; + case 27: + $this->setHomepage($value); + break; + case 28: + $this->setPhone($value); + break; + case 29: + $this->setOptIn($value); + break; + case 30: + $this->setEditorialNotification($value); + break; + case 31: + $this->setShowLoginStatus($value); + break; + case 32: + $this->setLastActive($value); + break; + case 33: + $this->setDobIsDerived($value); + break; + case 34: + $this->setNeedProfileCheck($value); + break; + case 35: + $this->setFirstReaktorLogin($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardUserPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setUsername($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setAlgorithm($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setSalt($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setPassword($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setCreatedAt($arr[$keys[5]]); + if (array_key_exists($keys[6], $arr)) $this->setLastLogin($arr[$keys[6]]); + if (array_key_exists($keys[7], $arr)) $this->setIsActive($arr[$keys[7]]); + if (array_key_exists($keys[8], $arr)) $this->setIsSuperAdmin($arr[$keys[8]]); + if (array_key_exists($keys[9], $arr)) $this->setIsVerified($arr[$keys[9]]); + if (array_key_exists($keys[10], $arr)) $this->setShowContent($arr[$keys[10]]); + if (array_key_exists($keys[11], $arr)) $this->setCulture($arr[$keys[11]]); + if (array_key_exists($keys[12], $arr)) $this->setEmail($arr[$keys[12]]); + if (array_key_exists($keys[13], $arr)) $this->setEmailPrivate($arr[$keys[13]]); + if (array_key_exists($keys[14], $arr)) $this->setNewEmail($arr[$keys[14]]); + if (array_key_exists($keys[15], $arr)) $this->setNewEmailKey($arr[$keys[15]]); + if (array_key_exists($keys[16], $arr)) $this->setNewPasswordKey($arr[$keys[16]]); + if (array_key_exists($keys[17], $arr)) $this->setKeyExpires($arr[$keys[17]]); + if (array_key_exists($keys[18], $arr)) $this->setName($arr[$keys[18]]); + if (array_key_exists($keys[19], $arr)) $this->setNamePrivate($arr[$keys[19]]); + if (array_key_exists($keys[20], $arr)) $this->setDob($arr[$keys[20]]); + if (array_key_exists($keys[21], $arr)) $this->setSex($arr[$keys[21]]); + if (array_key_exists($keys[22], $arr)) $this->setDescription($arr[$keys[22]]); + if (array_key_exists($keys[23], $arr)) $this->setResidenceId($arr[$keys[23]]); + if (array_key_exists($keys[24], $arr)) $this->setAvatar($arr[$keys[24]]); + if (array_key_exists($keys[25], $arr)) $this->setMsn($arr[$keys[25]]); + if (array_key_exists($keys[26], $arr)) $this->setIcq($arr[$keys[26]]); + if (array_key_exists($keys[27], $arr)) $this->setHomepage($arr[$keys[27]]); + if (array_key_exists($keys[28], $arr)) $this->setPhone($arr[$keys[28]]); + if (array_key_exists($keys[29], $arr)) $this->setOptIn($arr[$keys[29]]); + if (array_key_exists($keys[30], $arr)) $this->setEditorialNotification($arr[$keys[30]]); + if (array_key_exists($keys[31], $arr)) $this->setShowLoginStatus($arr[$keys[31]]); + if (array_key_exists($keys[32], $arr)) $this->setLastActive($arr[$keys[32]]); + if (array_key_exists($keys[33], $arr)) $this->setDobIsDerived($arr[$keys[33]]); + if (array_key_exists($keys[34], $arr)) $this->setNeedProfileCheck($arr[$keys[34]]); + if (array_key_exists($keys[35], $arr)) $this->setFirstReaktorLogin($arr[$keys[35]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardUserPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardUserPeer::ID)) $criteria->add(sfGuardUserPeer::ID, $this->id); + if ($this->isColumnModified(sfGuardUserPeer::USERNAME)) $criteria->add(sfGuardUserPeer::USERNAME, $this->username); + if ($this->isColumnModified(sfGuardUserPeer::ALGORITHM)) $criteria->add(sfGuardUserPeer::ALGORITHM, $this->algorithm); + if ($this->isColumnModified(sfGuardUserPeer::SALT)) $criteria->add(sfGuardUserPeer::SALT, $this->salt); + if ($this->isColumnModified(sfGuardUserPeer::PASSWORD)) $criteria->add(sfGuardUserPeer::PASSWORD, $this->password); + if ($this->isColumnModified(sfGuardUserPeer::CREATED_AT)) $criteria->add(sfGuardUserPeer::CREATED_AT, $this->created_at); + if ($this->isColumnModified(sfGuardUserPeer::LAST_LOGIN)) $criteria->add(sfGuardUserPeer::LAST_LOGIN, $this->last_login); + if ($this->isColumnModified(sfGuardUserPeer::IS_ACTIVE)) $criteria->add(sfGuardUserPeer::IS_ACTIVE, $this->is_active); + if ($this->isColumnModified(sfGuardUserPeer::IS_SUPER_ADMIN)) $criteria->add(sfGuardUserPeer::IS_SUPER_ADMIN, $this->is_super_admin); + if ($this->isColumnModified(sfGuardUserPeer::IS_VERIFIED)) $criteria->add(sfGuardUserPeer::IS_VERIFIED, $this->is_verified); + if ($this->isColumnModified(sfGuardUserPeer::SHOW_CONTENT)) $criteria->add(sfGuardUserPeer::SHOW_CONTENT, $this->show_content); + if ($this->isColumnModified(sfGuardUserPeer::CULTURE)) $criteria->add(sfGuardUserPeer::CULTURE, $this->culture); + if ($this->isColumnModified(sfGuardUserPeer::EMAIL)) $criteria->add(sfGuardUserPeer::EMAIL, $this->email); + if ($this->isColumnModified(sfGuardUserPeer::EMAIL_PRIVATE)) $criteria->add(sfGuardUserPeer::EMAIL_PRIVATE, $this->email_private); + if ($this->isColumnModified(sfGuardUserPeer::NEW_EMAIL)) $criteria->add(sfGuardUserPeer::NEW_EMAIL, $this->new_email); + if ($this->isColumnModified(sfGuardUserPeer::NEW_EMAIL_KEY)) $criteria->add(sfGuardUserPeer::NEW_EMAIL_KEY, $this->new_email_key); + if ($this->isColumnModified(sfGuardUserPeer::NEW_PASSWORD_KEY)) $criteria->add(sfGuardUserPeer::NEW_PASSWORD_KEY, $this->new_password_key); + if ($this->isColumnModified(sfGuardUserPeer::KEY_EXPIRES)) $criteria->add(sfGuardUserPeer::KEY_EXPIRES, $this->key_expires); + if ($this->isColumnModified(sfGuardUserPeer::NAME)) $criteria->add(sfGuardUserPeer::NAME, $this->name); + if ($this->isColumnModified(sfGuardUserPeer::NAME_PRIVATE)) $criteria->add(sfGuardUserPeer::NAME_PRIVATE, $this->name_private); + if ($this->isColumnModified(sfGuardUserPeer::DOB)) $criteria->add(sfGuardUserPeer::DOB, $this->dob); + if ($this->isColumnModified(sfGuardUserPeer::SEX)) $criteria->add(sfGuardUserPeer::SEX, $this->sex); + if ($this->isColumnModified(sfGuardUserPeer::DESCRIPTION)) $criteria->add(sfGuardUserPeer::DESCRIPTION, $this->description); + if ($this->isColumnModified(sfGuardUserPeer::RESIDENCE_ID)) $criteria->add(sfGuardUserPeer::RESIDENCE_ID, $this->residence_id); + if ($this->isColumnModified(sfGuardUserPeer::AVATAR)) $criteria->add(sfGuardUserPeer::AVATAR, $this->avatar); + if ($this->isColumnModified(sfGuardUserPeer::MSN)) $criteria->add(sfGuardUserPeer::MSN, $this->msn); + if ($this->isColumnModified(sfGuardUserPeer::ICQ)) $criteria->add(sfGuardUserPeer::ICQ, $this->icq); + if ($this->isColumnModified(sfGuardUserPeer::HOMEPAGE)) $criteria->add(sfGuardUserPeer::HOMEPAGE, $this->homepage); + if ($this->isColumnModified(sfGuardUserPeer::PHONE)) $criteria->add(sfGuardUserPeer::PHONE, $this->phone); + if ($this->isColumnModified(sfGuardUserPeer::OPT_IN)) $criteria->add(sfGuardUserPeer::OPT_IN, $this->opt_in); + if ($this->isColumnModified(sfGuardUserPeer::EDITORIAL_NOTIFICATION)) $criteria->add(sfGuardUserPeer::EDITORIAL_NOTIFICATION, $this->editorial_notification); + if ($this->isColumnModified(sfGuardUserPeer::SHOW_LOGIN_STATUS)) $criteria->add(sfGuardUserPeer::SHOW_LOGIN_STATUS, $this->show_login_status); + if ($this->isColumnModified(sfGuardUserPeer::LAST_ACTIVE)) $criteria->add(sfGuardUserPeer::LAST_ACTIVE, $this->last_active); + if ($this->isColumnModified(sfGuardUserPeer::DOB_IS_DERIVED)) $criteria->add(sfGuardUserPeer::DOB_IS_DERIVED, $this->dob_is_derived); + if ($this->isColumnModified(sfGuardUserPeer::NEED_PROFILE_CHECK)) $criteria->add(sfGuardUserPeer::NEED_PROFILE_CHECK, $this->need_profile_check); + if ($this->isColumnModified(sfGuardUserPeer::FIRST_REAKTOR_LOGIN)) $criteria->add(sfGuardUserPeer::FIRST_REAKTOR_LOGIN, $this->first_reaktor_login); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardUserPeer::DATABASE_NAME); + + $criteria->add(sfGuardUserPeer::ID, $this->id); + + return $criteria; + } + + + public function getPrimaryKey() + { + return $this->getId(); + } + + + public function setPrimaryKey($key) + { + $this->setId($key); + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setUsername($this->username); + + $copyObj->setAlgorithm($this->algorithm); + + $copyObj->setSalt($this->salt); + + $copyObj->setPassword($this->password); + + $copyObj->setCreatedAt($this->created_at); + + $copyObj->setLastLogin($this->last_login); + + $copyObj->setIsActive($this->is_active); + + $copyObj->setIsSuperAdmin($this->is_super_admin); + + $copyObj->setIsVerified($this->is_verified); + + $copyObj->setShowContent($this->show_content); + + $copyObj->setCulture($this->culture); + + $copyObj->setEmail($this->email); + + $copyObj->setEmailPrivate($this->email_private); + + $copyObj->setNewEmail($this->new_email); + + $copyObj->setNewEmailKey($this->new_email_key); + + $copyObj->setNewPasswordKey($this->new_password_key); + + $copyObj->setKeyExpires($this->key_expires); + + $copyObj->setName($this->name); + + $copyObj->setNamePrivate($this->name_private); + + $copyObj->setDob($this->dob); + + $copyObj->setSex($this->sex); + + $copyObj->setDescription($this->description); + + $copyObj->setResidenceId($this->residence_id); + + $copyObj->setAvatar($this->avatar); + + $copyObj->setMsn($this->msn); + + $copyObj->setIcq($this->icq); + + $copyObj->setHomepage($this->homepage); + + $copyObj->setPhone($this->phone); + + $copyObj->setOptIn($this->opt_in); + + $copyObj->setEditorialNotification($this->editorial_notification); + + $copyObj->setShowLoginStatus($this->show_login_status); + + $copyObj->setLastActive($this->last_active); + + $copyObj->setDobIsDerived($this->dob_is_derived); + + $copyObj->setNeedProfileCheck($this->need_profile_check); + + $copyObj->setFirstReaktorLogin($this->first_reaktor_login); + + + if ($deepCopy) { + $copyObj->setNew(false); + + foreach($this->getMessagessRelatedByToUserId() as $relObj) { + $copyObj->addMessagesRelatedByToUserId($relObj->copy($deepCopy)); + } + + foreach($this->getMessagessRelatedByFromUserId() as $relObj) { + $copyObj->addMessagesRelatedByFromUserId($relObj->copy($deepCopy)); + } + + foreach($this->getMessagesIgnoredUsersRelatedByUserId() as $relObj) { + $copyObj->addMessagesIgnoredUserRelatedByUserId($relObj->copy($deepCopy)); + } + + foreach($this->getMessagesIgnoredUsersRelatedByIgnoresUserId() as $relObj) { + $copyObj->addMessagesIgnoredUserRelatedByIgnoresUserId($relObj->copy($deepCopy)); + } + + foreach($this->getAdminMessages() as $relObj) { + $copyObj->addAdminMessage($relObj->copy($deepCopy)); + } + + foreach($this->getRecommendedArtworks() as $relObj) { + $copyObj->addRecommendedArtwork($relObj->copy($deepCopy)); + } + + foreach($this->getsfGuardUserPermissions() as $relObj) { + $copyObj->addsfGuardUserPermission($relObj->copy($deepCopy)); + } + + foreach($this->getsfGuardUserGroups() as $relObj) { + $copyObj->addsfGuardUserGroup($relObj->copy($deepCopy)); + } + + foreach($this->getsfGuardRememberKeys() as $relObj) { + $copyObj->addsfGuardRememberKey($relObj->copy($deepCopy)); + } + + foreach($this->getsfComments() as $relObj) { + $copyObj->addsfComment($relObj->copy($deepCopy)); + } + + foreach($this->getReaktorArtworks() as $relObj) { + $copyObj->addReaktorArtwork($relObj->copy($deepCopy)); + } + + foreach($this->getUserInterests() as $relObj) { + $copyObj->addUserInterest($relObj->copy($deepCopy)); + } + + foreach($this->getTags() as $relObj) { + $copyObj->addTag($relObj->copy($deepCopy)); + } + + foreach($this->getTaggings() as $relObj) { + $copyObj->addTagging($relObj->copy($deepCopy)); + } + + foreach($this->getUserResources() as $relObj) { + $copyObj->addUserResource($relObj->copy($deepCopy)); + } + + foreach($this->getReaktorFiles() as $relObj) { + $copyObj->addReaktorFile($relObj->copy($deepCopy)); + } + + foreach($this->getRelatedArtworks() as $relObj) { + $copyObj->addRelatedArtwork($relObj->copy($deepCopy)); + } + + foreach($this->getReaktorArtworkHistorys() as $relObj) { + $copyObj->addReaktorArtworkHistory($relObj->copy($deepCopy)); + } + + foreach($this->getCategoryArtworks() as $relObj) { + $copyObj->addCategoryArtwork($relObj->copy($deepCopy)); + } + + foreach($this->getArticles() as $relObj) { + $copyObj->addArticle($relObj->copy($deepCopy)); + } + + foreach($this->getArticleArticleRelations() as $relObj) { + $copyObj->addArticleArticleRelation($relObj->copy($deepCopy)); + } + + foreach($this->getArticleArtworkRelations() as $relObj) { + $copyObj->addArticleArtworkRelation($relObj->copy($deepCopy)); + } + + foreach($this->getArticleFiles() as $relObj) { + $copyObj->addArticleFile($relObj->copy($deepCopy)); + } + + foreach($this->getFavouritesRelatedByUserId() as $relObj) { + $copyObj->addFavouriteRelatedByUserId($relObj->copy($deepCopy)); + } + + foreach($this->getFavouritesRelatedByFriendId() as $relObj) { + $copyObj->addFavouriteRelatedByFriendId($relObj->copy($deepCopy)); + } + + foreach($this->getHistorys() as $relObj) { + $copyObj->addHistory($relObj->copy($deepCopy)); + } + + } + + $copyObj->setNew(true); + + $copyObj->setId(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardUserPeer(); + } + return self::$peer; + } + + + public function setResidence($v) + { + + + if ($v === null) { + $this->setResidenceId(NULL); + } else { + $this->setResidenceId($v->getId()); + } + + + $this->aResidence = $v; + } + + + + public function getResidence($con = null) + { + if ($this->aResidence === null && ($this->residence_id !== null)) { + include_once 'lib/model/om/BaseResidencePeer.php'; + + $this->aResidence = ResidencePeer::retrieveByPK($this->residence_id, $con); + + + } + return $this->aResidence; + } + + + public function initMessagessRelatedByToUserId() + { + if ($this->collMessagessRelatedByToUserId === null) { + $this->collMessagessRelatedByToUserId = array(); + } + } + + + public function getMessagessRelatedByToUserId($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseMessagesPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collMessagessRelatedByToUserId === null) { + if ($this->isNew()) { + $this->collMessagessRelatedByToUserId = array(); + } else { + + $criteria->add(MessagesPeer::TO_USER_ID, $this->getId()); + + MessagesPeer::addSelectColumns($criteria); + $this->collMessagessRelatedByToUserId = MessagesPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(MessagesPeer::TO_USER_ID, $this->getId()); + + MessagesPeer::addSelectColumns($criteria); + if (!isset($this->lastMessagesRelatedByToUserIdCriteria) || !$this->lastMessagesRelatedByToUserIdCriteria->equals($criteria)) { + $this->collMessagessRelatedByToUserId = MessagesPeer::doSelect($criteria, $con); + } + } + } + $this->lastMessagesRelatedByToUserIdCriteria = $criteria; + return $this->collMessagessRelatedByToUserId; + } + + + public function countMessagessRelatedByToUserId($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseMessagesPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(MessagesPeer::TO_USER_ID, $this->getId()); + + return MessagesPeer::doCount($criteria, $distinct, $con); + } + + + public function addMessagesRelatedByToUserId(Messages $l) + { + $this->collMessagessRelatedByToUserId[] = $l; + $l->setsfGuardUserRelatedByToUserId($this); + } + + + public function initMessagessRelatedByFromUserId() + { + if ($this->collMessagessRelatedByFromUserId === null) { + $this->collMessagessRelatedByFromUserId = array(); + } + } + + + public function getMessagessRelatedByFromUserId($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseMessagesPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collMessagessRelatedByFromUserId === null) { + if ($this->isNew()) { + $this->collMessagessRelatedByFromUserId = array(); + } else { + + $criteria->add(MessagesPeer::FROM_USER_ID, $this->getId()); + + MessagesPeer::addSelectColumns($criteria); + $this->collMessagessRelatedByFromUserId = MessagesPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(MessagesPeer::FROM_USER_ID, $this->getId()); + + MessagesPeer::addSelectColumns($criteria); + if (!isset($this->lastMessagesRelatedByFromUserIdCriteria) || !$this->lastMessagesRelatedByFromUserIdCriteria->equals($criteria)) { + $this->collMessagessRelatedByFromUserId = MessagesPeer::doSelect($criteria, $con); + } + } + } + $this->lastMessagesRelatedByFromUserIdCriteria = $criteria; + return $this->collMessagessRelatedByFromUserId; + } + + + public function countMessagessRelatedByFromUserId($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseMessagesPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(MessagesPeer::FROM_USER_ID, $this->getId()); + + return MessagesPeer::doCount($criteria, $distinct, $con); + } + + + public function addMessagesRelatedByFromUserId(Messages $l) + { + $this->collMessagessRelatedByFromUserId[] = $l; + $l->setsfGuardUserRelatedByFromUserId($this); + } + + + public function initMessagesIgnoredUsersRelatedByUserId() + { + if ($this->collMessagesIgnoredUsersRelatedByUserId === null) { + $this->collMessagesIgnoredUsersRelatedByUserId = array(); + } + } + + + public function getMessagesIgnoredUsersRelatedByUserId($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseMessagesIgnoredUserPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collMessagesIgnoredUsersRelatedByUserId === null) { + if ($this->isNew()) { + $this->collMessagesIgnoredUsersRelatedByUserId = array(); + } else { + + $criteria->add(MessagesIgnoredUserPeer::USER_ID, $this->getId()); + + MessagesIgnoredUserPeer::addSelectColumns($criteria); + $this->collMessagesIgnoredUsersRelatedByUserId = MessagesIgnoredUserPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(MessagesIgnoredUserPeer::USER_ID, $this->getId()); + + MessagesIgnoredUserPeer::addSelectColumns($criteria); + if (!isset($this->lastMessagesIgnoredUserRelatedByUserIdCriteria) || !$this->lastMessagesIgnoredUserRelatedByUserIdCriteria->equals($criteria)) { + $this->collMessagesIgnoredUsersRelatedByUserId = MessagesIgnoredUserPeer::doSelect($criteria, $con); + } + } + } + $this->lastMessagesIgnoredUserRelatedByUserIdCriteria = $criteria; + return $this->collMessagesIgnoredUsersRelatedByUserId; + } + + + public function countMessagesIgnoredUsersRelatedByUserId($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseMessagesIgnoredUserPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(MessagesIgnoredUserPeer::USER_ID, $this->getId()); + + return MessagesIgnoredUserPeer::doCount($criteria, $distinct, $con); + } + + + public function addMessagesIgnoredUserRelatedByUserId(MessagesIgnoredUser $l) + { + $this->collMessagesIgnoredUsersRelatedByUserId[] = $l; + $l->setsfGuardUserRelatedByUserId($this); + } + + + public function initMessagesIgnoredUsersRelatedByIgnoresUserId() + { + if ($this->collMessagesIgnoredUsersRelatedByIgnoresUserId === null) { + $this->collMessagesIgnoredUsersRelatedByIgnoresUserId = array(); + } + } + + + public function getMessagesIgnoredUsersRelatedByIgnoresUserId($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseMessagesIgnoredUserPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collMessagesIgnoredUsersRelatedByIgnoresUserId === null) { + if ($this->isNew()) { + $this->collMessagesIgnoredUsersRelatedByIgnoresUserId = array(); + } else { + + $criteria->add(MessagesIgnoredUserPeer::IGNORES_USER_ID, $this->getId()); + + MessagesIgnoredUserPeer::addSelectColumns($criteria); + $this->collMessagesIgnoredUsersRelatedByIgnoresUserId = MessagesIgnoredUserPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(MessagesIgnoredUserPeer::IGNORES_USER_ID, $this->getId()); + + MessagesIgnoredUserPeer::addSelectColumns($criteria); + if (!isset($this->lastMessagesIgnoredUserRelatedByIgnoresUserIdCriteria) || !$this->lastMessagesIgnoredUserRelatedByIgnoresUserIdCriteria->equals($criteria)) { + $this->collMessagesIgnoredUsersRelatedByIgnoresUserId = MessagesIgnoredUserPeer::doSelect($criteria, $con); + } + } + } + $this->lastMessagesIgnoredUserRelatedByIgnoresUserIdCriteria = $criteria; + return $this->collMessagesIgnoredUsersRelatedByIgnoresUserId; + } + + + public function countMessagesIgnoredUsersRelatedByIgnoresUserId($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseMessagesIgnoredUserPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(MessagesIgnoredUserPeer::IGNORES_USER_ID, $this->getId()); + + return MessagesIgnoredUserPeer::doCount($criteria, $distinct, $con); + } + + + public function addMessagesIgnoredUserRelatedByIgnoresUserId(MessagesIgnoredUser $l) + { + $this->collMessagesIgnoredUsersRelatedByIgnoresUserId[] = $l; + $l->setsfGuardUserRelatedByIgnoresUserId($this); + } + + + public function initAdminMessages() + { + if ($this->collAdminMessages === null) { + $this->collAdminMessages = array(); + } + } + + + public function getAdminMessages($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseAdminMessagePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collAdminMessages === null) { + if ($this->isNew()) { + $this->collAdminMessages = array(); + } else { + + $criteria->add(AdminMessagePeer::AUTHOR, $this->getId()); + + AdminMessagePeer::addSelectColumns($criteria); + $this->collAdminMessages = AdminMessagePeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(AdminMessagePeer::AUTHOR, $this->getId()); + + AdminMessagePeer::addSelectColumns($criteria); + if (!isset($this->lastAdminMessageCriteria) || !$this->lastAdminMessageCriteria->equals($criteria)) { + $this->collAdminMessages = AdminMessagePeer::doSelect($criteria, $con); + } + } + } + $this->lastAdminMessageCriteria = $criteria; + return $this->collAdminMessages; + } + + + public function countAdminMessages($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseAdminMessagePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(AdminMessagePeer::AUTHOR, $this->getId()); + + return AdminMessagePeer::doCount($criteria, $distinct, $con); + } + + + public function addAdminMessage(AdminMessage $l) + { + $this->collAdminMessages[] = $l; + $l->setsfGuardUser($this); + } + + + public function initRecommendedArtworks() + { + if ($this->collRecommendedArtworks === null) { + $this->collRecommendedArtworks = array(); + } + } + + + public function getRecommendedArtworks($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseRecommendedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collRecommendedArtworks === null) { + if ($this->isNew()) { + $this->collRecommendedArtworks = array(); + } else { + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + RecommendedArtworkPeer::addSelectColumns($criteria); + $this->collRecommendedArtworks = RecommendedArtworkPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + RecommendedArtworkPeer::addSelectColumns($criteria); + if (!isset($this->lastRecommendedArtworkCriteria) || !$this->lastRecommendedArtworkCriteria->equals($criteria)) { + $this->collRecommendedArtworks = RecommendedArtworkPeer::doSelect($criteria, $con); + } + } + } + $this->lastRecommendedArtworkCriteria = $criteria; + return $this->collRecommendedArtworks; + } + + + public function countRecommendedArtworks($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseRecommendedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + return RecommendedArtworkPeer::doCount($criteria, $distinct, $con); + } + + + public function addRecommendedArtwork(RecommendedArtwork $l) + { + $this->collRecommendedArtworks[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getRecommendedArtworksJoinReaktorArtwork($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseRecommendedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collRecommendedArtworks === null) { + if ($this->isNew()) { + $this->collRecommendedArtworks = array(); + } else { + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + $this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } else { + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + if (!isset($this->lastRecommendedArtworkCriteria) || !$this->lastRecommendedArtworkCriteria->equals($criteria)) { + $this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } + $this->lastRecommendedArtworkCriteria = $criteria; + + return $this->collRecommendedArtworks; + } + + + + public function getRecommendedArtworksJoinSubreaktorRelatedBySubreaktor($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseRecommendedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collRecommendedArtworks === null) { + if ($this->isNew()) { + $this->collRecommendedArtworks = array(); + } else { + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + $this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinSubreaktorRelatedBySubreaktor($criteria, $con); + } + } else { + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + if (!isset($this->lastRecommendedArtworkCriteria) || !$this->lastRecommendedArtworkCriteria->equals($criteria)) { + $this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinSubreaktorRelatedBySubreaktor($criteria, $con); + } + } + $this->lastRecommendedArtworkCriteria = $criteria; + + return $this->collRecommendedArtworks; + } + + + + public function getRecommendedArtworksJoinSubreaktorRelatedByLocalsubreaktor($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseRecommendedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collRecommendedArtworks === null) { + if ($this->isNew()) { + $this->collRecommendedArtworks = array(); + } else { + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + $this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinSubreaktorRelatedByLocalsubreaktor($criteria, $con); + } + } else { + + $criteria->add(RecommendedArtworkPeer::UPDATED_BY, $this->getId()); + + if (!isset($this->lastRecommendedArtworkCriteria) || !$this->lastRecommendedArtworkCriteria->equals($criteria)) { + $this->collRecommendedArtworks = RecommendedArtworkPeer::doSelectJoinSubreaktorRelatedByLocalsubreaktor($criteria, $con); + } + } + $this->lastRecommendedArtworkCriteria = $criteria; + + return $this->collRecommendedArtworks; + } + + + public function initsfGuardUserPermissions() + { + if ($this->collsfGuardUserPermissions === null) { + $this->collsfGuardUserPermissions = array(); + } + } + + + public function getsfGuardUserPermissions($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardUserPermissions === null) { + if ($this->isNew()) { + $this->collsfGuardUserPermissions = array(); + } else { + + $criteria->add(sfGuardUserPermissionPeer::USER_ID, $this->getId()); + + sfGuardUserPermissionPeer::addSelectColumns($criteria); + $this->collsfGuardUserPermissions = sfGuardUserPermissionPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfGuardUserPermissionPeer::USER_ID, $this->getId()); + + sfGuardUserPermissionPeer::addSelectColumns($criteria); + if (!isset($this->lastsfGuardUserPermissionCriteria) || !$this->lastsfGuardUserPermissionCriteria->equals($criteria)) { + $this->collsfGuardUserPermissions = sfGuardUserPermissionPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfGuardUserPermissionCriteria = $criteria; + return $this->collsfGuardUserPermissions; + } + + + public function countsfGuardUserPermissions($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfGuardUserPermissionPeer::USER_ID, $this->getId()); + + return sfGuardUserPermissionPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfGuardUserPermission(sfGuardUserPermission $l) + { + $this->collsfGuardUserPermissions[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getsfGuardUserPermissionsJoinsfGuardPermission($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardUserPermissions === null) { + if ($this->isNew()) { + $this->collsfGuardUserPermissions = array(); + } else { + + $criteria->add(sfGuardUserPermissionPeer::USER_ID, $this->getId()); + + $this->collsfGuardUserPermissions = sfGuardUserPermissionPeer::doSelectJoinsfGuardPermission($criteria, $con); + } + } else { + + $criteria->add(sfGuardUserPermissionPeer::USER_ID, $this->getId()); + + if (!isset($this->lastsfGuardUserPermissionCriteria) || !$this->lastsfGuardUserPermissionCriteria->equals($criteria)) { + $this->collsfGuardUserPermissions = sfGuardUserPermissionPeer::doSelectJoinsfGuardPermission($criteria, $con); + } + } + $this->lastsfGuardUserPermissionCriteria = $criteria; + + return $this->collsfGuardUserPermissions; + } + + + public function initsfGuardUserGroups() + { + if ($this->collsfGuardUserGroups === null) { + $this->collsfGuardUserGroups = array(); + } + } + + + public function getsfGuardUserGroups($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardUserGroups === null) { + if ($this->isNew()) { + $this->collsfGuardUserGroups = array(); + } else { + + $criteria->add(sfGuardUserGroupPeer::USER_ID, $this->getId()); + + sfGuardUserGroupPeer::addSelectColumns($criteria); + $this->collsfGuardUserGroups = sfGuardUserGroupPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfGuardUserGroupPeer::USER_ID, $this->getId()); + + sfGuardUserGroupPeer::addSelectColumns($criteria); + if (!isset($this->lastsfGuardUserGroupCriteria) || !$this->lastsfGuardUserGroupCriteria->equals($criteria)) { + $this->collsfGuardUserGroups = sfGuardUserGroupPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfGuardUserGroupCriteria = $criteria; + return $this->collsfGuardUserGroups; + } + + + public function countsfGuardUserGroups($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfGuardUserGroupPeer::USER_ID, $this->getId()); + + return sfGuardUserGroupPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfGuardUserGroup(sfGuardUserGroup $l) + { + $this->collsfGuardUserGroups[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getsfGuardUserGroupsJoinsfGuardGroup($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardUserGroups === null) { + if ($this->isNew()) { + $this->collsfGuardUserGroups = array(); + } else { + + $criteria->add(sfGuardUserGroupPeer::USER_ID, $this->getId()); + + $this->collsfGuardUserGroups = sfGuardUserGroupPeer::doSelectJoinsfGuardGroup($criteria, $con); + } + } else { + + $criteria->add(sfGuardUserGroupPeer::USER_ID, $this->getId()); + + if (!isset($this->lastsfGuardUserGroupCriteria) || !$this->lastsfGuardUserGroupCriteria->equals($criteria)) { + $this->collsfGuardUserGroups = sfGuardUserGroupPeer::doSelectJoinsfGuardGroup($criteria, $con); + } + } + $this->lastsfGuardUserGroupCriteria = $criteria; + + return $this->collsfGuardUserGroups; + } + + + public function initsfGuardRememberKeys() + { + if ($this->collsfGuardRememberKeys === null) { + $this->collsfGuardRememberKeys = array(); + } + } + + + public function getsfGuardRememberKeys($criteria = null, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKeyPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfGuardRememberKeys === null) { + if ($this->isNew()) { + $this->collsfGuardRememberKeys = array(); + } else { + + $criteria->add(sfGuardRememberKeyPeer::USER_ID, $this->getId()); + + sfGuardRememberKeyPeer::addSelectColumns($criteria); + $this->collsfGuardRememberKeys = sfGuardRememberKeyPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfGuardRememberKeyPeer::USER_ID, $this->getId()); + + sfGuardRememberKeyPeer::addSelectColumns($criteria); + if (!isset($this->lastsfGuardRememberKeyCriteria) || !$this->lastsfGuardRememberKeyCriteria->equals($criteria)) { + $this->collsfGuardRememberKeys = sfGuardRememberKeyPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfGuardRememberKeyCriteria = $criteria; + return $this->collsfGuardRememberKeys; + } + + + public function countsfGuardRememberKeys($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardRememberKeyPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfGuardRememberKeyPeer::USER_ID, $this->getId()); + + return sfGuardRememberKeyPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfGuardRememberKey(sfGuardRememberKey $l) + { + $this->collsfGuardRememberKeys[] = $l; + $l->setsfGuardUser($this); + } + + + public function initsfComments() + { + if ($this->collsfComments === null) { + $this->collsfComments = array(); + } + } + + + public function getsfComments($criteria = null, $con = null) + { + include_once 'plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfCommentPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collsfComments === null) { + if ($this->isNew()) { + $this->collsfComments = array(); + } else { + + $criteria->add(sfCommentPeer::AUTHOR_ID, $this->getId()); + + sfCommentPeer::addSelectColumns($criteria); + $this->collsfComments = sfCommentPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(sfCommentPeer::AUTHOR_ID, $this->getId()); + + sfCommentPeer::addSelectColumns($criteria); + if (!isset($this->lastsfCommentCriteria) || !$this->lastsfCommentCriteria->equals($criteria)) { + $this->collsfComments = sfCommentPeer::doSelect($criteria, $con); + } + } + } + $this->lastsfCommentCriteria = $criteria; + return $this->collsfComments; + } + + + public function countsfComments($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfCommentPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(sfCommentPeer::AUTHOR_ID, $this->getId()); + + return sfCommentPeer::doCount($criteria, $distinct, $con); + } + + + public function addsfComment(sfComment $l) + { + $this->collsfComments[] = $l; + $l->setsfGuardUser($this); + } + + + public function initReaktorArtworks() + { + if ($this->collReaktorArtworks === null) { + $this->collReaktorArtworks = array(); + } + } + + + public function getReaktorArtworks($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworks === null) { + if ($this->isNew()) { + $this->collReaktorArtworks = array(); + } else { + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + ReaktorArtworkPeer::addSelectColumns($criteria); + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + ReaktorArtworkPeer::addSelectColumns($criteria); + if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) { + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelect($criteria, $con); + } + } + } + $this->lastReaktorArtworkCriteria = $criteria; + return $this->collReaktorArtworks; + } + + + public function countReaktorArtworks($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + return ReaktorArtworkPeer::doCount($criteria, $distinct, $con); + } + + + public function addReaktorArtwork(ReaktorArtwork $l) + { + $this->collReaktorArtworks[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getReaktorArtworksJoinArtworkStatus($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworks === null) { + if ($this->isNew()) { + $this->collReaktorArtworks = array(); + } else { + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinArtworkStatus($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) { + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinArtworkStatus($criteria, $con); + } + } + $this->lastReaktorArtworkCriteria = $criteria; + + return $this->collReaktorArtworks; + } + + + + public function getReaktorArtworksJoinsfGuardGroup($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworks === null) { + if ($this->isNew()) { + $this->collReaktorArtworks = array(); + } else { + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardGroup($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) { + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinsfGuardGroup($criteria, $con); + } + } + $this->lastReaktorArtworkCriteria = $criteria; + + return $this->collReaktorArtworks; + } + + + + public function getReaktorArtworksJoinReaktorFile($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworks === null) { + if ($this->isNew()) { + $this->collReaktorArtworks = array(); + } else { + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinReaktorFile($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkPeer::USER_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkCriteria) || !$this->lastReaktorArtworkCriteria->equals($criteria)) { + $this->collReaktorArtworks = ReaktorArtworkPeer::doSelectJoinReaktorFile($criteria, $con); + } + } + $this->lastReaktorArtworkCriteria = $criteria; + + return $this->collReaktorArtworks; + } + + + public function initUserInterests() + { + if ($this->collUserInterests === null) { + $this->collUserInterests = array(); + } + } + + + public function getUserInterests($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseUserInterestPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collUserInterests === null) { + if ($this->isNew()) { + $this->collUserInterests = array(); + } else { + + $criteria->add(UserInterestPeer::USER_ID, $this->getId()); + + UserInterestPeer::addSelectColumns($criteria); + $this->collUserInterests = UserInterestPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(UserInterestPeer::USER_ID, $this->getId()); + + UserInterestPeer::addSelectColumns($criteria); + if (!isset($this->lastUserInterestCriteria) || !$this->lastUserInterestCriteria->equals($criteria)) { + $this->collUserInterests = UserInterestPeer::doSelect($criteria, $con); + } + } + } + $this->lastUserInterestCriteria = $criteria; + return $this->collUserInterests; + } + + + public function countUserInterests($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseUserInterestPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(UserInterestPeer::USER_ID, $this->getId()); + + return UserInterestPeer::doCount($criteria, $distinct, $con); + } + + + public function addUserInterest(UserInterest $l) + { + $this->collUserInterests[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getUserInterestsJoinSubreaktor($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseUserInterestPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collUserInterests === null) { + if ($this->isNew()) { + $this->collUserInterests = array(); + } else { + + $criteria->add(UserInterestPeer::USER_ID, $this->getId()); + + $this->collUserInterests = UserInterestPeer::doSelectJoinSubreaktor($criteria, $con); + } + } else { + + $criteria->add(UserInterestPeer::USER_ID, $this->getId()); + + if (!isset($this->lastUserInterestCriteria) || !$this->lastUserInterestCriteria->equals($criteria)) { + $this->collUserInterests = UserInterestPeer::doSelectJoinSubreaktor($criteria, $con); + } + } + $this->lastUserInterestCriteria = $criteria; + + return $this->collUserInterests; + } + + + public function initTags() + { + if ($this->collTags === null) { + $this->collTags = array(); + } + } + + + public function getTags($criteria = null, $con = null) + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collTags === null) { + if ($this->isNew()) { + $this->collTags = array(); + } else { + + $criteria->add(TagPeer::APPROVED_BY, $this->getId()); + + TagPeer::addSelectColumns($criteria); + $this->collTags = TagPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(TagPeer::APPROVED_BY, $this->getId()); + + TagPeer::addSelectColumns($criteria); + if (!isset($this->lastTagCriteria) || !$this->lastTagCriteria->equals($criteria)) { + $this->collTags = TagPeer::doSelect($criteria, $con); + } + } + } + $this->lastTagCriteria = $criteria; + return $this->collTags; + } + + + public function countTags($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(TagPeer::APPROVED_BY, $this->getId()); + + return TagPeer::doCount($criteria, $distinct, $con); + } + + + public function addTag(Tag $l) + { + $this->collTags[] = $l; + $l->setsfGuardUser($this); + } + + + public function initTaggings() + { + if ($this->collTaggings === null) { + $this->collTaggings = array(); + } + } + + + public function getTaggings($criteria = null, $con = null) + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collTaggings === null) { + if ($this->isNew()) { + $this->collTaggings = array(); + } else { + + $criteria->add(TaggingPeer::PARENT_USER_ID, $this->getId()); + + TaggingPeer::addSelectColumns($criteria); + $this->collTaggings = TaggingPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(TaggingPeer::PARENT_USER_ID, $this->getId()); + + TaggingPeer::addSelectColumns($criteria); + if (!isset($this->lastTaggingCriteria) || !$this->lastTaggingCriteria->equals($criteria)) { + $this->collTaggings = TaggingPeer::doSelect($criteria, $con); + } + } + } + $this->lastTaggingCriteria = $criteria; + return $this->collTaggings; + } + + + public function countTaggings($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(TaggingPeer::PARENT_USER_ID, $this->getId()); + + return TaggingPeer::doCount($criteria, $distinct, $con); + } + + + public function addTagging(Tagging $l) + { + $this->collTaggings[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getTaggingsJoinTag($criteria = null, $con = null) + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collTaggings === null) { + if ($this->isNew()) { + $this->collTaggings = array(); + } else { + + $criteria->add(TaggingPeer::PARENT_USER_ID, $this->getId()); + + $this->collTaggings = TaggingPeer::doSelectJoinTag($criteria, $con); + } + } else { + + $criteria->add(TaggingPeer::PARENT_USER_ID, $this->getId()); + + if (!isset($this->lastTaggingCriteria) || !$this->lastTaggingCriteria->equals($criteria)) { + $this->collTaggings = TaggingPeer::doSelectJoinTag($criteria, $con); + } + } + $this->lastTaggingCriteria = $criteria; + + return $this->collTaggings; + } + + + public function initUserResources() + { + if ($this->collUserResources === null) { + $this->collUserResources = array(); + } + } + + + public function getUserResources($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseUserResourcePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collUserResources === null) { + if ($this->isNew()) { + $this->collUserResources = array(); + } else { + + $criteria->add(UserResourcePeer::USER_ID, $this->getId()); + + UserResourcePeer::addSelectColumns($criteria); + $this->collUserResources = UserResourcePeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(UserResourcePeer::USER_ID, $this->getId()); + + UserResourcePeer::addSelectColumns($criteria); + if (!isset($this->lastUserResourceCriteria) || !$this->lastUserResourceCriteria->equals($criteria)) { + $this->collUserResources = UserResourcePeer::doSelect($criteria, $con); + } + } + } + $this->lastUserResourceCriteria = $criteria; + return $this->collUserResources; + } + + + public function countUserResources($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseUserResourcePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(UserResourcePeer::USER_ID, $this->getId()); + + return UserResourcePeer::doCount($criteria, $distinct, $con); + } + + + public function addUserResource(UserResource $l) + { + $this->collUserResources[] = $l; + $l->setsfGuardUser($this); + } + + + public function initReaktorFiles() + { + if ($this->collReaktorFiles === null) { + $this->collReaktorFiles = array(); + } + } + + + public function getReaktorFiles($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorFilePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorFiles === null) { + if ($this->isNew()) { + $this->collReaktorFiles = array(); + } else { + + $criteria->add(ReaktorFilePeer::USER_ID, $this->getId()); + + ReaktorFilePeer::addSelectColumns($criteria); + $this->collReaktorFiles = ReaktorFilePeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(ReaktorFilePeer::USER_ID, $this->getId()); + + ReaktorFilePeer::addSelectColumns($criteria); + if (!isset($this->lastReaktorFileCriteria) || !$this->lastReaktorFileCriteria->equals($criteria)) { + $this->collReaktorFiles = ReaktorFilePeer::doSelect($criteria, $con); + } + } + } + $this->lastReaktorFileCriteria = $criteria; + return $this->collReaktorFiles; + } + + + public function countReaktorFiles($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseReaktorFilePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(ReaktorFilePeer::USER_ID, $this->getId()); + + return ReaktorFilePeer::doCount($criteria, $distinct, $con); + } + + + public function addReaktorFile(ReaktorFile $l) + { + $this->collReaktorFiles[] = $l; + $l->setsfGuardUser($this); + } + + + public function initRelatedArtworks() + { + if ($this->collRelatedArtworks === null) { + $this->collRelatedArtworks = array(); + } + } + + + public function getRelatedArtworks($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseRelatedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collRelatedArtworks === null) { + if ($this->isNew()) { + $this->collRelatedArtworks = array(); + } else { + + $criteria->add(RelatedArtworkPeer::CREATED_BY, $this->getId()); + + RelatedArtworkPeer::addSelectColumns($criteria); + $this->collRelatedArtworks = RelatedArtworkPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(RelatedArtworkPeer::CREATED_BY, $this->getId()); + + RelatedArtworkPeer::addSelectColumns($criteria); + if (!isset($this->lastRelatedArtworkCriteria) || !$this->lastRelatedArtworkCriteria->equals($criteria)) { + $this->collRelatedArtworks = RelatedArtworkPeer::doSelect($criteria, $con); + } + } + } + $this->lastRelatedArtworkCriteria = $criteria; + return $this->collRelatedArtworks; + } + + + public function countRelatedArtworks($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseRelatedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(RelatedArtworkPeer::CREATED_BY, $this->getId()); + + return RelatedArtworkPeer::doCount($criteria, $distinct, $con); + } + + + public function addRelatedArtwork(RelatedArtwork $l) + { + $this->collRelatedArtworks[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getRelatedArtworksJoinReaktorArtworkRelatedByFirstArtwork($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseRelatedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collRelatedArtworks === null) { + if ($this->isNew()) { + $this->collRelatedArtworks = array(); + } else { + + $criteria->add(RelatedArtworkPeer::CREATED_BY, $this->getId()); + + $this->collRelatedArtworks = RelatedArtworkPeer::doSelectJoinReaktorArtworkRelatedByFirstArtwork($criteria, $con); + } + } else { + + $criteria->add(RelatedArtworkPeer::CREATED_BY, $this->getId()); + + if (!isset($this->lastRelatedArtworkCriteria) || !$this->lastRelatedArtworkCriteria->equals($criteria)) { + $this->collRelatedArtworks = RelatedArtworkPeer::doSelectJoinReaktorArtworkRelatedByFirstArtwork($criteria, $con); + } + } + $this->lastRelatedArtworkCriteria = $criteria; + + return $this->collRelatedArtworks; + } + + + + public function getRelatedArtworksJoinReaktorArtworkRelatedBySecondArtwork($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseRelatedArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collRelatedArtworks === null) { + if ($this->isNew()) { + $this->collRelatedArtworks = array(); + } else { + + $criteria->add(RelatedArtworkPeer::CREATED_BY, $this->getId()); + + $this->collRelatedArtworks = RelatedArtworkPeer::doSelectJoinReaktorArtworkRelatedBySecondArtwork($criteria, $con); + } + } else { + + $criteria->add(RelatedArtworkPeer::CREATED_BY, $this->getId()); + + if (!isset($this->lastRelatedArtworkCriteria) || !$this->lastRelatedArtworkCriteria->equals($criteria)) { + $this->collRelatedArtworks = RelatedArtworkPeer::doSelectJoinReaktorArtworkRelatedBySecondArtwork($criteria, $con); + } + } + $this->lastRelatedArtworkCriteria = $criteria; + + return $this->collRelatedArtworks; + } + + + public function initReaktorArtworkHistorys() + { + if ($this->collReaktorArtworkHistorys === null) { + $this->collReaktorArtworkHistorys = array(); + } + } + + + public function getReaktorArtworkHistorys($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworkHistorys === null) { + if ($this->isNew()) { + $this->collReaktorArtworkHistorys = array(); + } else { + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + ReaktorArtworkHistoryPeer::addSelectColumns($criteria); + $this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + ReaktorArtworkHistoryPeer::addSelectColumns($criteria); + if (!isset($this->lastReaktorArtworkHistoryCriteria) || !$this->lastReaktorArtworkHistoryCriteria->equals($criteria)) { + $this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelect($criteria, $con); + } + } + } + $this->lastReaktorArtworkHistoryCriteria = $criteria; + return $this->collReaktorArtworkHistorys; + } + + + public function countReaktorArtworkHistorys($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + return ReaktorArtworkHistoryPeer::doCount($criteria, $distinct, $con); + } + + + public function addReaktorArtworkHistory(ReaktorArtworkHistory $l) + { + $this->collReaktorArtworkHistorys[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getReaktorArtworkHistorysJoinReaktorArtworkRelatedByArtworkId($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworkHistorys === null) { + if ($this->isNew()) { + $this->collReaktorArtworkHistorys = array(); + } else { + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + $this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinReaktorArtworkRelatedByArtworkId($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkHistoryCriteria) || !$this->lastReaktorArtworkHistoryCriteria->equals($criteria)) { + $this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinReaktorArtworkRelatedByArtworkId($criteria, $con); + } + } + $this->lastReaktorArtworkHistoryCriteria = $criteria; + + return $this->collReaktorArtworkHistorys; + } + + + + public function getReaktorArtworkHistorysJoinReaktorArtworkRelatedByFileId($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworkHistorys === null) { + if ($this->isNew()) { + $this->collReaktorArtworkHistorys = array(); + } else { + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + $this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinReaktorArtworkRelatedByFileId($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkHistoryCriteria) || !$this->lastReaktorArtworkHistoryCriteria->equals($criteria)) { + $this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinReaktorArtworkRelatedByFileId($criteria, $con); + } + } + $this->lastReaktorArtworkHistoryCriteria = $criteria; + + return $this->collReaktorArtworkHistorys; + } + + + + public function getReaktorArtworkHistorysJoinArtworkStatus($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseReaktorArtworkHistoryPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collReaktorArtworkHistorys === null) { + if ($this->isNew()) { + $this->collReaktorArtworkHistorys = array(); + } else { + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + $this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinArtworkStatus($criteria, $con); + } + } else { + + $criteria->add(ReaktorArtworkHistoryPeer::USER_ID, $this->getId()); + + if (!isset($this->lastReaktorArtworkHistoryCriteria) || !$this->lastReaktorArtworkHistoryCriteria->equals($criteria)) { + $this->collReaktorArtworkHistorys = ReaktorArtworkHistoryPeer::doSelectJoinArtworkStatus($criteria, $con); + } + } + $this->lastReaktorArtworkHistoryCriteria = $criteria; + + return $this->collReaktorArtworkHistorys; + } + + + public function initCategoryArtworks() + { + if ($this->collCategoryArtworks === null) { + $this->collCategoryArtworks = array(); + } + } + + + public function getCategoryArtworks($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseCategoryArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collCategoryArtworks === null) { + if ($this->isNew()) { + $this->collCategoryArtworks = array(); + } else { + + $criteria->add(CategoryArtworkPeer::ADDED_BY, $this->getId()); + + CategoryArtworkPeer::addSelectColumns($criteria); + $this->collCategoryArtworks = CategoryArtworkPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(CategoryArtworkPeer::ADDED_BY, $this->getId()); + + CategoryArtworkPeer::addSelectColumns($criteria); + if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) { + $this->collCategoryArtworks = CategoryArtworkPeer::doSelect($criteria, $con); + } + } + } + $this->lastCategoryArtworkCriteria = $criteria; + return $this->collCategoryArtworks; + } + + + public function countCategoryArtworks($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseCategoryArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(CategoryArtworkPeer::ADDED_BY, $this->getId()); + + return CategoryArtworkPeer::doCount($criteria, $distinct, $con); + } + + + public function addCategoryArtwork(CategoryArtwork $l) + { + $this->collCategoryArtworks[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getCategoryArtworksJoinCategory($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseCategoryArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collCategoryArtworks === null) { + if ($this->isNew()) { + $this->collCategoryArtworks = array(); + } else { + + $criteria->add(CategoryArtworkPeer::ADDED_BY, $this->getId()); + + $this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinCategory($criteria, $con); + } + } else { + + $criteria->add(CategoryArtworkPeer::ADDED_BY, $this->getId()); + + if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) { + $this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinCategory($criteria, $con); + } + } + $this->lastCategoryArtworkCriteria = $criteria; + + return $this->collCategoryArtworks; + } + + + + public function getCategoryArtworksJoinReaktorArtwork($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseCategoryArtworkPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collCategoryArtworks === null) { + if ($this->isNew()) { + $this->collCategoryArtworks = array(); + } else { + + $criteria->add(CategoryArtworkPeer::ADDED_BY, $this->getId()); + + $this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } else { + + $criteria->add(CategoryArtworkPeer::ADDED_BY, $this->getId()); + + if (!isset($this->lastCategoryArtworkCriteria) || !$this->lastCategoryArtworkCriteria->equals($criteria)) { + $this->collCategoryArtworks = CategoryArtworkPeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } + $this->lastCategoryArtworkCriteria = $criteria; + + return $this->collCategoryArtworks; + } + + + public function initArticles() + { + if ($this->collArticles === null) { + $this->collArticles = array(); + } + } + + + public function getArticles($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticlePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticles === null) { + if ($this->isNew()) { + $this->collArticles = array(); + } else { + + $criteria->add(ArticlePeer::AUTHOR_ID, $this->getId()); + + ArticlePeer::addSelectColumns($criteria); + $this->collArticles = ArticlePeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(ArticlePeer::AUTHOR_ID, $this->getId()); + + ArticlePeer::addSelectColumns($criteria); + if (!isset($this->lastArticleCriteria) || !$this->lastArticleCriteria->equals($criteria)) { + $this->collArticles = ArticlePeer::doSelect($criteria, $con); + } + } + } + $this->lastArticleCriteria = $criteria; + return $this->collArticles; + } + + + public function countArticles($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseArticlePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(ArticlePeer::AUTHOR_ID, $this->getId()); + + return ArticlePeer::doCount($criteria, $distinct, $con); + } + + + public function addArticle(Article $l) + { + $this->collArticles[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getArticlesJoinArticleFile($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticlePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticles === null) { + if ($this->isNew()) { + $this->collArticles = array(); + } else { + + $criteria->add(ArticlePeer::AUTHOR_ID, $this->getId()); + + $this->collArticles = ArticlePeer::doSelectJoinArticleFile($criteria, $con); + } + } else { + + $criteria->add(ArticlePeer::AUTHOR_ID, $this->getId()); + + if (!isset($this->lastArticleCriteria) || !$this->lastArticleCriteria->equals($criteria)) { + $this->collArticles = ArticlePeer::doSelectJoinArticleFile($criteria, $con); + } + } + $this->lastArticleCriteria = $criteria; + + return $this->collArticles; + } + + + public function initArticleArticleRelations() + { + if ($this->collArticleArticleRelations === null) { + $this->collArticleArticleRelations = array(); + } + } + + + public function getArticleArticleRelations($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticleArticleRelationPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticleArticleRelations === null) { + if ($this->isNew()) { + $this->collArticleArticleRelations = array(); + } else { + + $criteria->add(ArticleArticleRelationPeer::CREATED_BY, $this->getId()); + + ArticleArticleRelationPeer::addSelectColumns($criteria); + $this->collArticleArticleRelations = ArticleArticleRelationPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(ArticleArticleRelationPeer::CREATED_BY, $this->getId()); + + ArticleArticleRelationPeer::addSelectColumns($criteria); + if (!isset($this->lastArticleArticleRelationCriteria) || !$this->lastArticleArticleRelationCriteria->equals($criteria)) { + $this->collArticleArticleRelations = ArticleArticleRelationPeer::doSelect($criteria, $con); + } + } + } + $this->lastArticleArticleRelationCriteria = $criteria; + return $this->collArticleArticleRelations; + } + + + public function countArticleArticleRelations($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseArticleArticleRelationPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(ArticleArticleRelationPeer::CREATED_BY, $this->getId()); + + return ArticleArticleRelationPeer::doCount($criteria, $distinct, $con); + } + + + public function addArticleArticleRelation(ArticleArticleRelation $l) + { + $this->collArticleArticleRelations[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getArticleArticleRelationsJoinArticleRelatedByFirstArticle($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticleArticleRelationPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticleArticleRelations === null) { + if ($this->isNew()) { + $this->collArticleArticleRelations = array(); + } else { + + $criteria->add(ArticleArticleRelationPeer::CREATED_BY, $this->getId()); + + $this->collArticleArticleRelations = ArticleArticleRelationPeer::doSelectJoinArticleRelatedByFirstArticle($criteria, $con); + } + } else { + + $criteria->add(ArticleArticleRelationPeer::CREATED_BY, $this->getId()); + + if (!isset($this->lastArticleArticleRelationCriteria) || !$this->lastArticleArticleRelationCriteria->equals($criteria)) { + $this->collArticleArticleRelations = ArticleArticleRelationPeer::doSelectJoinArticleRelatedByFirstArticle($criteria, $con); + } + } + $this->lastArticleArticleRelationCriteria = $criteria; + + return $this->collArticleArticleRelations; + } + + + + public function getArticleArticleRelationsJoinArticleRelatedBySecondArticle($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticleArticleRelationPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticleArticleRelations === null) { + if ($this->isNew()) { + $this->collArticleArticleRelations = array(); + } else { + + $criteria->add(ArticleArticleRelationPeer::CREATED_BY, $this->getId()); + + $this->collArticleArticleRelations = ArticleArticleRelationPeer::doSelectJoinArticleRelatedBySecondArticle($criteria, $con); + } + } else { + + $criteria->add(ArticleArticleRelationPeer::CREATED_BY, $this->getId()); + + if (!isset($this->lastArticleArticleRelationCriteria) || !$this->lastArticleArticleRelationCriteria->equals($criteria)) { + $this->collArticleArticleRelations = ArticleArticleRelationPeer::doSelectJoinArticleRelatedBySecondArticle($criteria, $con); + } + } + $this->lastArticleArticleRelationCriteria = $criteria; + + return $this->collArticleArticleRelations; + } + + + public function initArticleArtworkRelations() + { + if ($this->collArticleArtworkRelations === null) { + $this->collArticleArtworkRelations = array(); + } + } + + + public function getArticleArtworkRelations($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticleArtworkRelations === null) { + if ($this->isNew()) { + $this->collArticleArtworkRelations = array(); + } else { + + $criteria->add(ArticleArtworkRelationPeer::CREATED_BY, $this->getId()); + + ArticleArtworkRelationPeer::addSelectColumns($criteria); + $this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(ArticleArtworkRelationPeer::CREATED_BY, $this->getId()); + + ArticleArtworkRelationPeer::addSelectColumns($criteria); + if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) { + $this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelect($criteria, $con); + } + } + } + $this->lastArticleArtworkRelationCriteria = $criteria; + return $this->collArticleArtworkRelations; + } + + + public function countArticleArtworkRelations($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(ArticleArtworkRelationPeer::CREATED_BY, $this->getId()); + + return ArticleArtworkRelationPeer::doCount($criteria, $distinct, $con); + } + + + public function addArticleArtworkRelation(ArticleArtworkRelation $l) + { + $this->collArticleArtworkRelations[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getArticleArtworkRelationsJoinArticle($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticleArtworkRelations === null) { + if ($this->isNew()) { + $this->collArticleArtworkRelations = array(); + } else { + + $criteria->add(ArticleArtworkRelationPeer::CREATED_BY, $this->getId()); + + $this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinArticle($criteria, $con); + } + } else { + + $criteria->add(ArticleArtworkRelationPeer::CREATED_BY, $this->getId()); + + if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) { + $this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinArticle($criteria, $con); + } + } + $this->lastArticleArtworkRelationCriteria = $criteria; + + return $this->collArticleArtworkRelations; + } + + + + public function getArticleArtworkRelationsJoinReaktorArtwork($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticleArtworkRelationPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticleArtworkRelations === null) { + if ($this->isNew()) { + $this->collArticleArtworkRelations = array(); + } else { + + $criteria->add(ArticleArtworkRelationPeer::CREATED_BY, $this->getId()); + + $this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } else { + + $criteria->add(ArticleArtworkRelationPeer::CREATED_BY, $this->getId()); + + if (!isset($this->lastArticleArtworkRelationCriteria) || !$this->lastArticleArtworkRelationCriteria->equals($criteria)) { + $this->collArticleArtworkRelations = ArticleArtworkRelationPeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } + $this->lastArticleArtworkRelationCriteria = $criteria; + + return $this->collArticleArtworkRelations; + } + + + public function initArticleFiles() + { + if ($this->collArticleFiles === null) { + $this->collArticleFiles = array(); + } + } + + + public function getArticleFiles($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticleFilePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticleFiles === null) { + if ($this->isNew()) { + $this->collArticleFiles = array(); + } else { + + $criteria->add(ArticleFilePeer::UPLOADED_BY, $this->getId()); + + ArticleFilePeer::addSelectColumns($criteria); + $this->collArticleFiles = ArticleFilePeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(ArticleFilePeer::UPLOADED_BY, $this->getId()); + + ArticleFilePeer::addSelectColumns($criteria); + if (!isset($this->lastArticleFileCriteria) || !$this->lastArticleFileCriteria->equals($criteria)) { + $this->collArticleFiles = ArticleFilePeer::doSelect($criteria, $con); + } + } + } + $this->lastArticleFileCriteria = $criteria; + return $this->collArticleFiles; + } + + + public function countArticleFiles($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseArticleFilePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(ArticleFilePeer::UPLOADED_BY, $this->getId()); + + return ArticleFilePeer::doCount($criteria, $distinct, $con); + } + + + public function addArticleFile(ArticleFile $l) + { + $this->collArticleFiles[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getArticleFilesJoinFileMimetype($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseArticleFilePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collArticleFiles === null) { + if ($this->isNew()) { + $this->collArticleFiles = array(); + } else { + + $criteria->add(ArticleFilePeer::UPLOADED_BY, $this->getId()); + + $this->collArticleFiles = ArticleFilePeer::doSelectJoinFileMimetype($criteria, $con); + } + } else { + + $criteria->add(ArticleFilePeer::UPLOADED_BY, $this->getId()); + + if (!isset($this->lastArticleFileCriteria) || !$this->lastArticleFileCriteria->equals($criteria)) { + $this->collArticleFiles = ArticleFilePeer::doSelectJoinFileMimetype($criteria, $con); + } + } + $this->lastArticleFileCriteria = $criteria; + + return $this->collArticleFiles; + } + + + public function initFavouritesRelatedByUserId() + { + if ($this->collFavouritesRelatedByUserId === null) { + $this->collFavouritesRelatedByUserId = array(); + } + } + + + public function getFavouritesRelatedByUserId($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseFavouritePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collFavouritesRelatedByUserId === null) { + if ($this->isNew()) { + $this->collFavouritesRelatedByUserId = array(); + } else { + + $criteria->add(FavouritePeer::USER_ID, $this->getId()); + + FavouritePeer::addSelectColumns($criteria); + $this->collFavouritesRelatedByUserId = FavouritePeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(FavouritePeer::USER_ID, $this->getId()); + + FavouritePeer::addSelectColumns($criteria); + if (!isset($this->lastFavouriteRelatedByUserIdCriteria) || !$this->lastFavouriteRelatedByUserIdCriteria->equals($criteria)) { + $this->collFavouritesRelatedByUserId = FavouritePeer::doSelect($criteria, $con); + } + } + } + $this->lastFavouriteRelatedByUserIdCriteria = $criteria; + return $this->collFavouritesRelatedByUserId; + } + + + public function countFavouritesRelatedByUserId($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseFavouritePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(FavouritePeer::USER_ID, $this->getId()); + + return FavouritePeer::doCount($criteria, $distinct, $con); + } + + + public function addFavouriteRelatedByUserId(Favourite $l) + { + $this->collFavouritesRelatedByUserId[] = $l; + $l->setsfGuardUserRelatedByUserId($this); + } + + + + public function getFavouritesRelatedByUserIdJoinReaktorArtwork($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseFavouritePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collFavouritesRelatedByUserId === null) { + if ($this->isNew()) { + $this->collFavouritesRelatedByUserId = array(); + } else { + + $criteria->add(FavouritePeer::USER_ID, $this->getId()); + + $this->collFavouritesRelatedByUserId = FavouritePeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } else { + + $criteria->add(FavouritePeer::USER_ID, $this->getId()); + + if (!isset($this->lastFavouriteRelatedByUserIdCriteria) || !$this->lastFavouriteRelatedByUserIdCriteria->equals($criteria)) { + $this->collFavouritesRelatedByUserId = FavouritePeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } + $this->lastFavouriteRelatedByUserIdCriteria = $criteria; + + return $this->collFavouritesRelatedByUserId; + } + + + + public function getFavouritesRelatedByUserIdJoinArticle($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseFavouritePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collFavouritesRelatedByUserId === null) { + if ($this->isNew()) { + $this->collFavouritesRelatedByUserId = array(); + } else { + + $criteria->add(FavouritePeer::USER_ID, $this->getId()); + + $this->collFavouritesRelatedByUserId = FavouritePeer::doSelectJoinArticle($criteria, $con); + } + } else { + + $criteria->add(FavouritePeer::USER_ID, $this->getId()); + + if (!isset($this->lastFavouriteRelatedByUserIdCriteria) || !$this->lastFavouriteRelatedByUserIdCriteria->equals($criteria)) { + $this->collFavouritesRelatedByUserId = FavouritePeer::doSelectJoinArticle($criteria, $con); + } + } + $this->lastFavouriteRelatedByUserIdCriteria = $criteria; + + return $this->collFavouritesRelatedByUserId; + } + + + public function initFavouritesRelatedByFriendId() + { + if ($this->collFavouritesRelatedByFriendId === null) { + $this->collFavouritesRelatedByFriendId = array(); + } + } + + + public function getFavouritesRelatedByFriendId($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseFavouritePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collFavouritesRelatedByFriendId === null) { + if ($this->isNew()) { + $this->collFavouritesRelatedByFriendId = array(); + } else { + + $criteria->add(FavouritePeer::FRIEND_ID, $this->getId()); + + FavouritePeer::addSelectColumns($criteria); + $this->collFavouritesRelatedByFriendId = FavouritePeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(FavouritePeer::FRIEND_ID, $this->getId()); + + FavouritePeer::addSelectColumns($criteria); + if (!isset($this->lastFavouriteRelatedByFriendIdCriteria) || !$this->lastFavouriteRelatedByFriendIdCriteria->equals($criteria)) { + $this->collFavouritesRelatedByFriendId = FavouritePeer::doSelect($criteria, $con); + } + } + } + $this->lastFavouriteRelatedByFriendIdCriteria = $criteria; + return $this->collFavouritesRelatedByFriendId; + } + + + public function countFavouritesRelatedByFriendId($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseFavouritePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(FavouritePeer::FRIEND_ID, $this->getId()); + + return FavouritePeer::doCount($criteria, $distinct, $con); + } + + + public function addFavouriteRelatedByFriendId(Favourite $l) + { + $this->collFavouritesRelatedByFriendId[] = $l; + $l->setsfGuardUserRelatedByFriendId($this); + } + + + + public function getFavouritesRelatedByFriendIdJoinReaktorArtwork($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseFavouritePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collFavouritesRelatedByFriendId === null) { + if ($this->isNew()) { + $this->collFavouritesRelatedByFriendId = array(); + } else { + + $criteria->add(FavouritePeer::FRIEND_ID, $this->getId()); + + $this->collFavouritesRelatedByFriendId = FavouritePeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } else { + + $criteria->add(FavouritePeer::FRIEND_ID, $this->getId()); + + if (!isset($this->lastFavouriteRelatedByFriendIdCriteria) || !$this->lastFavouriteRelatedByFriendIdCriteria->equals($criteria)) { + $this->collFavouritesRelatedByFriendId = FavouritePeer::doSelectJoinReaktorArtwork($criteria, $con); + } + } + $this->lastFavouriteRelatedByFriendIdCriteria = $criteria; + + return $this->collFavouritesRelatedByFriendId; + } + + + + public function getFavouritesRelatedByFriendIdJoinArticle($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseFavouritePeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collFavouritesRelatedByFriendId === null) { + if ($this->isNew()) { + $this->collFavouritesRelatedByFriendId = array(); + } else { + + $criteria->add(FavouritePeer::FRIEND_ID, $this->getId()); + + $this->collFavouritesRelatedByFriendId = FavouritePeer::doSelectJoinArticle($criteria, $con); + } + } else { + + $criteria->add(FavouritePeer::FRIEND_ID, $this->getId()); + + if (!isset($this->lastFavouriteRelatedByFriendIdCriteria) || !$this->lastFavouriteRelatedByFriendIdCriteria->equals($criteria)) { + $this->collFavouritesRelatedByFriendId = FavouritePeer::doSelectJoinArticle($criteria, $con); + } + } + $this->lastFavouriteRelatedByFriendIdCriteria = $criteria; + + return $this->collFavouritesRelatedByFriendId; + } + + + public function initHistorys() + { + if ($this->collHistorys === null) { + $this->collHistorys = array(); + } + } + + + public function getHistorys($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseHistoryPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collHistorys === null) { + if ($this->isNew()) { + $this->collHistorys = array(); + } else { + + $criteria->add(HistoryPeer::USER_ID, $this->getId()); + + HistoryPeer::addSelectColumns($criteria); + $this->collHistorys = HistoryPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(HistoryPeer::USER_ID, $this->getId()); + + HistoryPeer::addSelectColumns($criteria); + if (!isset($this->lastHistoryCriteria) || !$this->lastHistoryCriteria->equals($criteria)) { + $this->collHistorys = HistoryPeer::doSelect($criteria, $con); + } + } + } + $this->lastHistoryCriteria = $criteria; + return $this->collHistorys; + } + + + public function countHistorys($criteria = null, $distinct = false, $con = null) + { + include_once 'lib/model/om/BaseHistoryPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(HistoryPeer::USER_ID, $this->getId()); + + return HistoryPeer::doCount($criteria, $distinct, $con); + } + + + public function addHistory(History $l) + { + $this->collHistorys[] = $l; + $l->setsfGuardUser($this); + } + + + + public function getHistorysJoinHistoryAction($criteria = null, $con = null) + { + include_once 'lib/model/om/BaseHistoryPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collHistorys === null) { + if ($this->isNew()) { + $this->collHistorys = array(); + } else { + + $criteria->add(HistoryPeer::USER_ID, $this->getId()); + + $this->collHistorys = HistoryPeer::doSelectJoinHistoryAction($criteria, $con); + } + } else { + + $criteria->add(HistoryPeer::USER_ID, $this->getId()); + + if (!isset($this->lastHistoryCriteria) || !$this->lastHistoryCriteria->equals($criteria)) { + $this->collHistorys = HistoryPeer::doSelectJoinHistoryAction($criteria, $con); + } + } + $this->lastHistoryCriteria = $criteria; + + return $this->collHistorys; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardUser:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardUser::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroup.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroup.php new file mode 100644 index 0000000..4ebf6c9 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroup.php @@ -0,0 +1,481 @@ +user_id; + } + + + public function getGroupId() + { + + return $this->group_id; + } + + + public function setUserId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->user_id !== $v) { + $this->user_id = $v; + $this->modifiedColumns[] = sfGuardUserGroupPeer::USER_ID; + } + + if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) { + $this->asfGuardUser = null; + } + + } + + public function setGroupId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->group_id !== $v) { + $this->group_id = $v; + $this->modifiedColumns[] = sfGuardUserGroupPeer::GROUP_ID; + } + + if ($this->asfGuardGroup !== null && $this->asfGuardGroup->getId() !== $v) { + $this->asfGuardGroup = null; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->user_id = $rs->getInt($startcol + 0); + + $this->group_id = $rs->getInt($startcol + 1); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 2; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardUserGroup object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserGroup:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardUserGroupPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardUserGroupPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardUserGroup:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserGroup:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardUserGroupPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardUserGroup:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->asfGuardUser !== null) { + if ($this->asfGuardUser->isModified()) { + $affectedRows += $this->asfGuardUser->save($con); + } + $this->setsfGuardUser($this->asfGuardUser); + } + + if ($this->asfGuardGroup !== null) { + if ($this->asfGuardGroup->isModified()) { + $affectedRows += $this->asfGuardGroup->save($con); + } + $this->setsfGuardGroup($this->asfGuardGroup); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardUserGroupPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setNew(false); + } else { + $affectedRows += sfGuardUserGroupPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->asfGuardUser !== null) { + if (!$this->asfGuardUser->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures()); + } + } + + if ($this->asfGuardGroup !== null) { + if (!$this->asfGuardGroup->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardGroup->getValidationFailures()); + } + } + + + if (($retval = sfGuardUserGroupPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardUserGroupPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getUserId(); + break; + case 1: + return $this->getGroupId(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardUserGroupPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getUserId(), + $keys[1] => $this->getGroupId(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardUserGroupPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setUserId($value); + break; + case 1: + $this->setGroupId($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardUserGroupPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setUserId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setGroupId($arr[$keys[1]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardUserGroupPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardUserGroupPeer::USER_ID)) $criteria->add(sfGuardUserGroupPeer::USER_ID, $this->user_id); + if ($this->isColumnModified(sfGuardUserGroupPeer::GROUP_ID)) $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $this->group_id); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardUserGroupPeer::DATABASE_NAME); + + $criteria->add(sfGuardUserGroupPeer::USER_ID, $this->user_id); + $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $this->group_id); + + return $criteria; + } + + + public function getPrimaryKey() + { + $pks = array(); + + $pks[0] = $this->getUserId(); + + $pks[1] = $this->getGroupId(); + + return $pks; + } + + + public function setPrimaryKey($keys) + { + + $this->setUserId($keys[0]); + + $this->setGroupId($keys[1]); + + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + + $copyObj->setNew(true); + + $copyObj->setUserId(NULL); + $copyObj->setGroupId(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardUserGroupPeer(); + } + return self::$peer; + } + + + public function setsfGuardUser($v) + { + + + if ($v === null) { + $this->setUserId(NULL); + } else { + $this->setUserId($v->getId()); + } + + + $this->asfGuardUser = $v; + } + + + + public function getsfGuardUser($con = null) + { + if ($this->asfGuardUser === null && ($this->user_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php'; + + $this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con); + + + } + return $this->asfGuardUser; + } + + + public function setsfGuardGroup($v) + { + + + if ($v === null) { + $this->setGroupId(NULL); + } else { + $this->setGroupId($v->getId()); + } + + + $this->asfGuardGroup = $v; + } + + + + public function getsfGuardGroup($con = null) + { + if ($this->asfGuardGroup === null && ($this->group_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardGroupPeer.php'; + + $this->asfGuardGroup = sfGuardGroupPeer::retrieveByPK($this->group_id, $con); + + + } + return $this->asfGuardGroup; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardUserGroup:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardUserGroup::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php new file mode 100644 index 0000000..5e75c4d --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserGroupPeer.php @@ -0,0 +1,839 @@ + array ('UserId', 'GroupId', ), + BasePeer::TYPE_COLNAME => array (sfGuardUserGroupPeer::USER_ID, sfGuardUserGroupPeer::GROUP_ID, ), + BasePeer::TYPE_FIELDNAME => array ('user_id', 'group_id', ), + BasePeer::TYPE_NUM => array (0, 1, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('UserId' => 0, 'GroupId' => 1, ), + BasePeer::TYPE_COLNAME => array (sfGuardUserGroupPeer::USER_ID => 0, sfGuardUserGroupPeer::GROUP_ID => 1, ), + BasePeer::TYPE_FIELDNAME => array ('user_id' => 0, 'group_id' => 1, ), + BasePeer::TYPE_NUM => array (0, 1, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardUserGroupMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardUserGroupMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardUserGroupPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardUserGroupPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardUserGroupPeer::USER_ID); + + $criteria->addSelectColumn(sfGuardUserGroupPeer::GROUP_ID); + + } + + const COUNT = 'COUNT(sf_guard_user_group.USER_ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_user_group.USER_ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardUserGroupPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardUserGroupPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardUserGroupPeer::populateObjects(sfGuardUserGroupPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserGroupPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardUserGroupPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardUserGroupPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardUserGroupPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserGroupPeer::USER_ID, sfGuardUserPeer::ID); + + $rs = sfGuardUserGroupPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doCountJoinsfGuardGroup(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserGroupPeer::GROUP_ID, sfGuardGroupPeer::ID); + + $rs = sfGuardUserGroupPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserGroupPeer::addSelectColumns($c); + $startcol = (sfGuardUserGroupPeer::NUM_COLUMNS - sfGuardUserGroupPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardUserPeer::addSelectColumns($c); + + $c->addJoin(sfGuardUserGroupPeer::USER_ID, sfGuardUserPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserGroupPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserGroup($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardUserGroups(); + $obj2->addsfGuardUserGroup($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doSelectJoinsfGuardGroup(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserGroupPeer::addSelectColumns($c); + $startcol = (sfGuardUserGroupPeer::NUM_COLUMNS - sfGuardUserGroupPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardGroupPeer::addSelectColumns($c); + + $c->addJoin(sfGuardUserGroupPeer::GROUP_ID, sfGuardGroupPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserGroupPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardGroupPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardGroup(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserGroup($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardUserGroups(); + $obj2->addsfGuardUserGroup($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserGroupPeer::USER_ID, sfGuardUserPeer::ID); + + $criteria->addJoin(sfGuardUserGroupPeer::GROUP_ID, sfGuardGroupPeer::ID); + + $rs = sfGuardUserGroupPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserGroupPeer::addSelectColumns($c); + $startcol2 = (sfGuardUserGroupPeer::NUM_COLUMNS - sfGuardUserGroupPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardUserPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS; + + sfGuardGroupPeer::addSelectColumns($c); + $startcol4 = $startcol3 + sfGuardGroupPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardUserGroupPeer::USER_ID, sfGuardUserPeer::ID); + + $c->addJoin(sfGuardUserGroupPeer::GROUP_ID, sfGuardGroupPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserGroupPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserGroup($obj1); break; + } + } + + if ($newObject) { + $obj2->initsfGuardUserGroups(); + $obj2->addsfGuardUserGroup($obj1); + } + + + + $omClass = sfGuardGroupPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj3 = new $cls(); + $obj3->hydrate($rs, $startcol3); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj3 = $temp_obj1->getsfGuardGroup(); if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) { + $newObject = false; + $temp_obj3->addsfGuardUserGroup($obj1); break; + } + } + + if ($newObject) { + $obj3->initsfGuardUserGroups(); + $obj3->addsfGuardUserGroup($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserGroupPeer::GROUP_ID, sfGuardGroupPeer::ID); + + $rs = sfGuardUserGroupPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doCountJoinAllExceptsfGuardGroup(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserGroupPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserGroupPeer::USER_ID, sfGuardUserPeer::ID); + + $rs = sfGuardUserGroupPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserGroupPeer::addSelectColumns($c); + $startcol2 = (sfGuardUserGroupPeer::NUM_COLUMNS - sfGuardUserGroupPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardGroupPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardGroupPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardUserGroupPeer::GROUP_ID, sfGuardGroupPeer::ID); + + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserGroupPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardGroupPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardGroup(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserGroup($obj1); + break; + } + } + + if ($newObject) { + $obj2->initsfGuardUserGroups(); + $obj2->addsfGuardUserGroup($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + + public static function doSelectJoinAllExceptsfGuardGroup(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserGroupPeer::addSelectColumns($c); + $startcol2 = (sfGuardUserGroupPeer::NUM_COLUMNS - sfGuardUserGroupPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardUserPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardUserGroupPeer::USER_ID, sfGuardUserPeer::ID); + + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserGroupPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserGroup($obj1); + break; + } + } + + if ($newObject) { + $obj2->initsfGuardUserGroups(); + $obj2->addsfGuardUserGroup($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardUserGroupPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserGroupPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardUserGroupPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardUserGroupPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardUserGroupPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserGroupPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardUserGroupPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardUserGroupPeer::USER_ID); + $selectCriteria->add(sfGuardUserGroupPeer::USER_ID, $criteria->remove(sfGuardUserGroupPeer::USER_ID), $comparison); + + $comparison = $criteria->getComparison(sfGuardUserGroupPeer::GROUP_ID); + $selectCriteria->add(sfGuardUserGroupPeer::GROUP_ID, $criteria->remove(sfGuardUserGroupPeer::GROUP_ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardUserGroupPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardUserGroupPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(sfGuardUserGroupPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardUserGroupPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardUserGroup) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + if(count($values) == count($values, COUNT_RECURSIVE)) + { + $values = array($values); + } + $vals = array(); + foreach($values as $value) + { + + $vals[0][] = $value[0]; + $vals[1][] = $value[1]; + } + + $criteria->add(sfGuardUserGroupPeer::USER_ID, $vals[0], Criteria::IN); + $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $vals[1], Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(sfGuardUserGroup $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardUserGroupPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardUserGroupPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardUserGroupPeer::DATABASE_NAME, sfGuardUserGroupPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardUserGroupPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK( $user_id, $group_id, $con = null) { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $criteria = new Criteria(); + $criteria->add(sfGuardUserGroupPeer::USER_ID, $user_id); + $criteria->add(sfGuardUserGroupPeer::GROUP_ID, $group_id); + $v = sfGuardUserGroupPeer::doSelect($criteria, $con); + + return !empty($v) ? $v[0] : null; + } +} +if (Propel::isInit()) { + try { + BasesfGuardUserGroupPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardUserGroupMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardUserGroupMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php new file mode 100644 index 0000000..e018467 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php @@ -0,0 +1,790 @@ + array ('Id', 'Username', 'Algorithm', 'Salt', 'Password', 'CreatedAt', 'LastLogin', 'IsActive', 'IsSuperAdmin', 'IsVerified', 'ShowContent', 'Culture', 'Email', 'EmailPrivate', 'NewEmail', 'NewEmailKey', 'NewPasswordKey', 'KeyExpires', 'Name', 'NamePrivate', 'Dob', 'Sex', 'Description', 'ResidenceId', 'Avatar', 'Msn', 'Icq', 'Homepage', 'Phone', 'OptIn', 'EditorialNotification', 'ShowLoginStatus', 'LastActive', 'DobIsDerived', 'NeedProfileCheck', 'FirstReaktorLogin', ), + BasePeer::TYPE_COLNAME => array (sfGuardUserPeer::ID, sfGuardUserPeer::USERNAME, sfGuardUserPeer::ALGORITHM, sfGuardUserPeer::SALT, sfGuardUserPeer::PASSWORD, sfGuardUserPeer::CREATED_AT, sfGuardUserPeer::LAST_LOGIN, sfGuardUserPeer::IS_ACTIVE, sfGuardUserPeer::IS_SUPER_ADMIN, sfGuardUserPeer::IS_VERIFIED, sfGuardUserPeer::SHOW_CONTENT, sfGuardUserPeer::CULTURE, sfGuardUserPeer::EMAIL, sfGuardUserPeer::EMAIL_PRIVATE, sfGuardUserPeer::NEW_EMAIL, sfGuardUserPeer::NEW_EMAIL_KEY, sfGuardUserPeer::NEW_PASSWORD_KEY, sfGuardUserPeer::KEY_EXPIRES, sfGuardUserPeer::NAME, sfGuardUserPeer::NAME_PRIVATE, sfGuardUserPeer::DOB, sfGuardUserPeer::SEX, sfGuardUserPeer::DESCRIPTION, sfGuardUserPeer::RESIDENCE_ID, sfGuardUserPeer::AVATAR, sfGuardUserPeer::MSN, sfGuardUserPeer::ICQ, sfGuardUserPeer::HOMEPAGE, sfGuardUserPeer::PHONE, sfGuardUserPeer::OPT_IN, sfGuardUserPeer::EDITORIAL_NOTIFICATION, sfGuardUserPeer::SHOW_LOGIN_STATUS, sfGuardUserPeer::LAST_ACTIVE, sfGuardUserPeer::DOB_IS_DERIVED, sfGuardUserPeer::NEED_PROFILE_CHECK, sfGuardUserPeer::FIRST_REAKTOR_LOGIN, ), + BasePeer::TYPE_FIELDNAME => array ('id', 'username', 'algorithm', 'salt', 'password', 'created_at', 'last_login', 'is_active', 'is_super_admin', 'is_verified', 'show_content', 'culture', 'email', 'email_private', 'new_email', 'new_email_key', 'new_password_key', 'key_expires', 'name', 'name_private', 'dob', 'sex', 'description', 'residence_id', 'avatar', 'msn', 'icq', 'homepage', 'phone', 'opt_in', 'editorial_notification', 'show_login_status', 'last_active', 'dob_is_derived', 'need_profile_check', 'first_reaktor_login', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'Username' => 1, 'Algorithm' => 2, 'Salt' => 3, 'Password' => 4, 'CreatedAt' => 5, 'LastLogin' => 6, 'IsActive' => 7, 'IsSuperAdmin' => 8, 'IsVerified' => 9, 'ShowContent' => 10, 'Culture' => 11, 'Email' => 12, 'EmailPrivate' => 13, 'NewEmail' => 14, 'NewEmailKey' => 15, 'NewPasswordKey' => 16, 'KeyExpires' => 17, 'Name' => 18, 'NamePrivate' => 19, 'Dob' => 20, 'Sex' => 21, 'Description' => 22, 'ResidenceId' => 23, 'Avatar' => 24, 'Msn' => 25, 'Icq' => 26, 'Homepage' => 27, 'Phone' => 28, 'OptIn' => 29, 'EditorialNotification' => 30, 'ShowLoginStatus' => 31, 'LastActive' => 32, 'DobIsDerived' => 33, 'NeedProfileCheck' => 34, 'FirstReaktorLogin' => 35, ), + BasePeer::TYPE_COLNAME => array (sfGuardUserPeer::ID => 0, sfGuardUserPeer::USERNAME => 1, sfGuardUserPeer::ALGORITHM => 2, sfGuardUserPeer::SALT => 3, sfGuardUserPeer::PASSWORD => 4, sfGuardUserPeer::CREATED_AT => 5, sfGuardUserPeer::LAST_LOGIN => 6, sfGuardUserPeer::IS_ACTIVE => 7, sfGuardUserPeer::IS_SUPER_ADMIN => 8, sfGuardUserPeer::IS_VERIFIED => 9, sfGuardUserPeer::SHOW_CONTENT => 10, sfGuardUserPeer::CULTURE => 11, sfGuardUserPeer::EMAIL => 12, sfGuardUserPeer::EMAIL_PRIVATE => 13, sfGuardUserPeer::NEW_EMAIL => 14, sfGuardUserPeer::NEW_EMAIL_KEY => 15, sfGuardUserPeer::NEW_PASSWORD_KEY => 16, sfGuardUserPeer::KEY_EXPIRES => 17, sfGuardUserPeer::NAME => 18, sfGuardUserPeer::NAME_PRIVATE => 19, sfGuardUserPeer::DOB => 20, sfGuardUserPeer::SEX => 21, sfGuardUserPeer::DESCRIPTION => 22, sfGuardUserPeer::RESIDENCE_ID => 23, sfGuardUserPeer::AVATAR => 24, sfGuardUserPeer::MSN => 25, sfGuardUserPeer::ICQ => 26, sfGuardUserPeer::HOMEPAGE => 27, sfGuardUserPeer::PHONE => 28, sfGuardUserPeer::OPT_IN => 29, sfGuardUserPeer::EDITORIAL_NOTIFICATION => 30, sfGuardUserPeer::SHOW_LOGIN_STATUS => 31, sfGuardUserPeer::LAST_ACTIVE => 32, sfGuardUserPeer::DOB_IS_DERIVED => 33, sfGuardUserPeer::NEED_PROFILE_CHECK => 34, sfGuardUserPeer::FIRST_REAKTOR_LOGIN => 35, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'username' => 1, 'algorithm' => 2, 'salt' => 3, 'password' => 4, 'created_at' => 5, 'last_login' => 6, 'is_active' => 7, 'is_super_admin' => 8, 'is_verified' => 9, 'show_content' => 10, 'culture' => 11, 'email' => 12, 'email_private' => 13, 'new_email' => 14, 'new_email_key' => 15, 'new_password_key' => 16, 'key_expires' => 17, 'name' => 18, 'name_private' => 19, 'dob' => 20, 'sex' => 21, 'description' => 22, 'residence_id' => 23, 'avatar' => 24, 'msn' => 25, 'icq' => 26, 'homepage' => 27, 'phone' => 28, 'opt_in' => 29, 'editorial_notification' => 30, 'show_login_status' => 31, 'last_active' => 32, 'dob_is_derived' => 33, 'need_profile_check' => 34, 'first_reaktor_login' => 35, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardUserMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardUserMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardUserPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardUserPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardUserPeer::ID); + + $criteria->addSelectColumn(sfGuardUserPeer::USERNAME); + + $criteria->addSelectColumn(sfGuardUserPeer::ALGORITHM); + + $criteria->addSelectColumn(sfGuardUserPeer::SALT); + + $criteria->addSelectColumn(sfGuardUserPeer::PASSWORD); + + $criteria->addSelectColumn(sfGuardUserPeer::CREATED_AT); + + $criteria->addSelectColumn(sfGuardUserPeer::LAST_LOGIN); + + $criteria->addSelectColumn(sfGuardUserPeer::IS_ACTIVE); + + $criteria->addSelectColumn(sfGuardUserPeer::IS_SUPER_ADMIN); + + $criteria->addSelectColumn(sfGuardUserPeer::IS_VERIFIED); + + $criteria->addSelectColumn(sfGuardUserPeer::SHOW_CONTENT); + + $criteria->addSelectColumn(sfGuardUserPeer::CULTURE); + + $criteria->addSelectColumn(sfGuardUserPeer::EMAIL); + + $criteria->addSelectColumn(sfGuardUserPeer::EMAIL_PRIVATE); + + $criteria->addSelectColumn(sfGuardUserPeer::NEW_EMAIL); + + $criteria->addSelectColumn(sfGuardUserPeer::NEW_EMAIL_KEY); + + $criteria->addSelectColumn(sfGuardUserPeer::NEW_PASSWORD_KEY); + + $criteria->addSelectColumn(sfGuardUserPeer::KEY_EXPIRES); + + $criteria->addSelectColumn(sfGuardUserPeer::NAME); + + $criteria->addSelectColumn(sfGuardUserPeer::NAME_PRIVATE); + + $criteria->addSelectColumn(sfGuardUserPeer::DOB); + + $criteria->addSelectColumn(sfGuardUserPeer::SEX); + + $criteria->addSelectColumn(sfGuardUserPeer::DESCRIPTION); + + $criteria->addSelectColumn(sfGuardUserPeer::RESIDENCE_ID); + + $criteria->addSelectColumn(sfGuardUserPeer::AVATAR); + + $criteria->addSelectColumn(sfGuardUserPeer::MSN); + + $criteria->addSelectColumn(sfGuardUserPeer::ICQ); + + $criteria->addSelectColumn(sfGuardUserPeer::HOMEPAGE); + + $criteria->addSelectColumn(sfGuardUserPeer::PHONE); + + $criteria->addSelectColumn(sfGuardUserPeer::OPT_IN); + + $criteria->addSelectColumn(sfGuardUserPeer::EDITORIAL_NOTIFICATION); + + $criteria->addSelectColumn(sfGuardUserPeer::SHOW_LOGIN_STATUS); + + $criteria->addSelectColumn(sfGuardUserPeer::LAST_ACTIVE); + + $criteria->addSelectColumn(sfGuardUserPeer::DOB_IS_DERIVED); + + $criteria->addSelectColumn(sfGuardUserPeer::NEED_PROFILE_CHECK); + + $criteria->addSelectColumn(sfGuardUserPeer::FIRST_REAKTOR_LOGIN); + + } + + const COUNT = 'COUNT(sf_guard_user.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_user.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardUserPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardUserPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardUserPeer::populateObjects(sfGuardUserPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardUserPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardUserPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardUserPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinResidence(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserPeer::RESIDENCE_ID, ResidencePeer::ID); + + $rs = sfGuardUserPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinResidence(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserPeer::addSelectColumns($c); + $startcol = (sfGuardUserPeer::NUM_COLUMNS - sfGuardUserPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + ResidencePeer::addSelectColumns($c); + + $c->addJoin(sfGuardUserPeer::RESIDENCE_ID, ResidencePeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = ResidencePeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getResidence(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUser($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardUsers(); + $obj2->addsfGuardUser($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserPeer::RESIDENCE_ID, ResidencePeer::ID); + + $rs = sfGuardUserPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserPeer::addSelectColumns($c); + $startcol2 = (sfGuardUserPeer::NUM_COLUMNS - sfGuardUserPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + ResidencePeer::addSelectColumns($c); + $startcol3 = $startcol2 + ResidencePeer::NUM_COLUMNS; + + $c->addJoin(sfGuardUserPeer::RESIDENCE_ID, ResidencePeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = ResidencePeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getResidence(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUser($obj1); break; + } + } + + if ($newObject) { + $obj2->initsfGuardUsers(); + $obj2->addsfGuardUser($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardUserPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardUserPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + $criteria->remove(sfGuardUserPeer::ID); + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardUserPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardUserPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardUserPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardUserPeer::ID); + $selectCriteria->add(sfGuardUserPeer::ID, $criteria->remove(sfGuardUserPeer::ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardUserPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardUserPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += sfGuardUserPeer::doOnDeleteCascade(new Criteria(), $con); + $affectedRows += BasePeer::doDeleteAll(sfGuardUserPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardUserPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardUser) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + $criteria->add(sfGuardUserPeer::ID, (array) $values, Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + $affectedRows += sfGuardUserPeer::doOnDeleteCascade($criteria, $con); + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected static function doOnDeleteCascade(Criteria $criteria, Connection $con) + { + $affectedRows = 0; + + $objects = sfGuardUserPeer::doSelect($criteria, $con); + foreach($objects as $obj) { + + + include_once 'plugins/sfGuardPlugin/lib/model/sfGuardUserPermission.php'; + + $c = new Criteria(); + + $c->add(sfGuardUserPermissionPeer::USER_ID, $obj->getId()); + $affectedRows += sfGuardUserPermissionPeer::doDelete($c, $con); + + include_once 'plugins/sfGuardPlugin/lib/model/sfGuardUserGroup.php'; + + $c = new Criteria(); + + $c->add(sfGuardUserGroupPeer::USER_ID, $obj->getId()); + $affectedRows += sfGuardUserGroupPeer::doDelete($c, $con); + + include_once 'plugins/sfGuardPlugin/lib/model/sfGuardRememberKey.php'; + + $c = new Criteria(); + + $c->add(sfGuardRememberKeyPeer::USER_ID, $obj->getId()); + $affectedRows += sfGuardRememberKeyPeer::doDelete($c, $con); + + include_once 'lib/model/UserInterest.php'; + + $c = new Criteria(); + + $c->add(UserInterestPeer::USER_ID, $obj->getId()); + $affectedRows += UserInterestPeer::doDelete($c, $con); + + include_once 'lib/model/UserResource.php'; + + $c = new Criteria(); + + $c->add(UserResourcePeer::USER_ID, $obj->getId()); + $affectedRows += UserResourcePeer::doDelete($c, $con); + } + return $affectedRows; + } + + + public static function doValidate(sfGuardUser $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardUserPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardUserPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardUserPeer::DATABASE_NAME, sfGuardUserPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardUserPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK($pk, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $criteria = new Criteria(sfGuardUserPeer::DATABASE_NAME); + + $criteria->add(sfGuardUserPeer::ID, $pk); + + + $v = sfGuardUserPeer::doSelect($criteria, $con); + + return !empty($v) > 0 ? $v[0] : null; + } + + + public static function retrieveByPKs($pks, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $objs = null; + if (empty($pks)) { + $objs = array(); + } else { + $criteria = new Criteria(); + $criteria->add(sfGuardUserPeer::ID, $pks, Criteria::IN); + $objs = sfGuardUserPeer::doSelect($criteria, $con); + } + return $objs; + } + +} +if (Propel::isInit()) { + try { + BasesfGuardUserPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardUserMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardUserMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermission.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermission.php new file mode 100644 index 0000000..b97cf80 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermission.php @@ -0,0 +1,515 @@ +user_id; + } + + + public function getPermissionId() + { + + return $this->permission_id; + } + + + public function getExclude() + { + + return $this->exclude; + } + + + public function setUserId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->user_id !== $v) { + $this->user_id = $v; + $this->modifiedColumns[] = sfGuardUserPermissionPeer::USER_ID; + } + + if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) { + $this->asfGuardUser = null; + } + + } + + public function setPermissionId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->permission_id !== $v) { + $this->permission_id = $v; + $this->modifiedColumns[] = sfGuardUserPermissionPeer::PERMISSION_ID; + } + + if ($this->asfGuardPermission !== null && $this->asfGuardPermission->getId() !== $v) { + $this->asfGuardPermission = null; + } + + } + + public function setExclude($v) + { + + if ($this->exclude !== $v || $v === false) { + $this->exclude = $v; + $this->modifiedColumns[] = sfGuardUserPermissionPeer::EXCLUDE; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->user_id = $rs->getInt($startcol + 0); + + $this->permission_id = $rs->getInt($startcol + 1); + + $this->exclude = $rs->getBoolean($startcol + 2); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 3; + } catch (Exception $e) { + throw new PropelException("Error populating sfGuardUserPermission object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserPermission:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardUserPermissionPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfGuardUserPermissionPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardUserPermission:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserPermission:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfGuardUserPermissionPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfGuardUserPermission:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->asfGuardUser !== null) { + if ($this->asfGuardUser->isModified()) { + $affectedRows += $this->asfGuardUser->save($con); + } + $this->setsfGuardUser($this->asfGuardUser); + } + + if ($this->asfGuardPermission !== null) { + if ($this->asfGuardPermission->isModified() || $this->asfGuardPermission->getCurrentsfGuardPermissionI18n()->isModified()) { + $affectedRows += $this->asfGuardPermission->save($con); + } + $this->setsfGuardPermission($this->asfGuardPermission); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfGuardUserPermissionPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setNew(false); + } else { + $affectedRows += sfGuardUserPermissionPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->asfGuardUser !== null) { + if (!$this->asfGuardUser->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures()); + } + } + + if ($this->asfGuardPermission !== null) { + if (!$this->asfGuardPermission->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardPermission->getValidationFailures()); + } + } + + + if (($retval = sfGuardUserPermissionPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardUserPermissionPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getUserId(); + break; + case 1: + return $this->getPermissionId(); + break; + case 2: + return $this->getExclude(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardUserPermissionPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getUserId(), + $keys[1] => $this->getPermissionId(), + $keys[2] => $this->getExclude(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfGuardUserPermissionPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setUserId($value); + break; + case 1: + $this->setPermissionId($value); + break; + case 2: + $this->setExclude($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfGuardUserPermissionPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setUserId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setPermissionId($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setExclude($arr[$keys[2]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfGuardUserPermissionPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfGuardUserPermissionPeer::USER_ID)) $criteria->add(sfGuardUserPermissionPeer::USER_ID, $this->user_id); + if ($this->isColumnModified(sfGuardUserPermissionPeer::PERMISSION_ID)) $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $this->permission_id); + if ($this->isColumnModified(sfGuardUserPermissionPeer::EXCLUDE)) $criteria->add(sfGuardUserPermissionPeer::EXCLUDE, $this->exclude); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfGuardUserPermissionPeer::DATABASE_NAME); + + $criteria->add(sfGuardUserPermissionPeer::USER_ID, $this->user_id); + $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $this->permission_id); + + return $criteria; + } + + + public function getPrimaryKey() + { + $pks = array(); + + $pks[0] = $this->getUserId(); + + $pks[1] = $this->getPermissionId(); + + return $pks; + } + + + public function setPrimaryKey($keys) + { + + $this->setUserId($keys[0]); + + $this->setPermissionId($keys[1]); + + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setExclude($this->exclude); + + + $copyObj->setNew(true); + + $copyObj->setUserId(NULL); + $copyObj->setPermissionId(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfGuardUserPermissionPeer(); + } + return self::$peer; + } + + + public function setsfGuardUser($v) + { + + + if ($v === null) { + $this->setUserId(NULL); + } else { + $this->setUserId($v->getId()); + } + + + $this->asfGuardUser = $v; + } + + + + public function getsfGuardUser($con = null) + { + if ($this->asfGuardUser === null && ($this->user_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php'; + + $this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->user_id, $con); + + + } + return $this->asfGuardUser; + } + + + public function setsfGuardPermission($v) + { + + + if ($v === null) { + $this->setPermissionId(NULL); + } else { + $this->setPermissionId($v->getId()); + } + + + $this->asfGuardPermission = $v; + } + + + + public function getsfGuardPermission($con = null) + { + if ($this->asfGuardPermission === null && ($this->permission_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardPermissionPeer.php'; + + $this->asfGuardPermission = sfGuardPermissionPeer::retrieveByPK($this->permission_id, $con); + + + } + return $this->asfGuardPermission; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfGuardUserPermission:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfGuardUserPermission::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php new file mode 100644 index 0000000..d8a6e9e --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPermissionPeer.php @@ -0,0 +1,844 @@ + array ('UserId', 'PermissionId', 'Exclude', ), + BasePeer::TYPE_COLNAME => array (sfGuardUserPermissionPeer::USER_ID, sfGuardUserPermissionPeer::PERMISSION_ID, sfGuardUserPermissionPeer::EXCLUDE, ), + BasePeer::TYPE_FIELDNAME => array ('user_id', 'permission_id', 'exclude', ), + BasePeer::TYPE_NUM => array (0, 1, 2, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('UserId' => 0, 'PermissionId' => 1, 'Exclude' => 2, ), + BasePeer::TYPE_COLNAME => array (sfGuardUserPermissionPeer::USER_ID => 0, sfGuardUserPermissionPeer::PERMISSION_ID => 1, sfGuardUserPermissionPeer::EXCLUDE => 2, ), + BasePeer::TYPE_FIELDNAME => array ('user_id' => 0, 'permission_id' => 1, 'exclude' => 2, ), + BasePeer::TYPE_NUM => array (0, 1, 2, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardUserPermissionMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardUserPermissionMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfGuardUserPermissionPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfGuardUserPermissionPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfGuardUserPermissionPeer::USER_ID); + + $criteria->addSelectColumn(sfGuardUserPermissionPeer::PERMISSION_ID); + + $criteria->addSelectColumn(sfGuardUserPermissionPeer::EXCLUDE); + + } + + const COUNT = 'COUNT(sf_guard_user_permission.USER_ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_guard_user_permission.USER_ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfGuardUserPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfGuardUserPermissionPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfGuardUserPermissionPeer::populateObjects(sfGuardUserPermissionPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserPermissionPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfGuardUserPermissionPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfGuardUserPermissionPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfGuardUserPermissionPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserPermissionPeer::USER_ID, sfGuardUserPeer::ID); + + $rs = sfGuardUserPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doCountJoinsfGuardPermission(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardUserPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserPermissionPeer::addSelectColumns($c); + $startcol = (sfGuardUserPermissionPeer::NUM_COLUMNS - sfGuardUserPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardUserPeer::addSelectColumns($c); + + $c->addJoin(sfGuardUserPermissionPeer::USER_ID, sfGuardUserPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserPermission($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardUserPermissions(); + $obj2->addsfGuardUserPermission($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doSelectJoinsfGuardPermission(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserPermissionPeer::addSelectColumns($c); + $startcol = (sfGuardUserPermissionPeer::NUM_COLUMNS - sfGuardUserPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardPermissionPeer::addSelectColumns($c); + + $c->addJoin(sfGuardUserPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardPermission(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserPermission($obj1); break; + } + } + if ($newObject) { + $obj2->initsfGuardUserPermissions(); + $obj2->addsfGuardUserPermission($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserPermissionPeer::USER_ID, sfGuardUserPeer::ID); + + $criteria->addJoin(sfGuardUserPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardUserPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserPermissionPeer::addSelectColumns($c); + $startcol2 = (sfGuardUserPermissionPeer::NUM_COLUMNS - sfGuardUserPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardUserPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS; + + sfGuardPermissionPeer::addSelectColumns($c); + $startcol4 = $startcol3 + sfGuardPermissionPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardUserPermissionPeer::USER_ID, sfGuardUserPeer::ID); + + $c->addJoin(sfGuardUserPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserPermissionPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserPermission($obj1); break; + } + } + + if ($newObject) { + $obj2->initsfGuardUserPermissions(); + $obj2->addsfGuardUserPermission($obj1); + } + + + + $omClass = sfGuardPermissionPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj3 = new $cls(); + $obj3->hydrate($rs, $startcol3); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj3 = $temp_obj1->getsfGuardPermission(); if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) { + $newObject = false; + $temp_obj3->addsfGuardUserPermission($obj1); break; + } + } + + if ($newObject) { + $obj3->initsfGuardUserPermissions(); + $obj3->addsfGuardUserPermission($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + $rs = sfGuardUserPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doCountJoinAllExceptsfGuardPermission(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfGuardUserPermissionPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfGuardUserPermissionPeer::USER_ID, sfGuardUserPeer::ID); + + $rs = sfGuardUserPermissionPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserPermissionPeer::addSelectColumns($c); + $startcol2 = (sfGuardUserPermissionPeer::NUM_COLUMNS - sfGuardUserPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardPermissionPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardPermissionPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardUserPermissionPeer::PERMISSION_ID, sfGuardPermissionPeer::ID); + + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardPermissionPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardPermission(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserPermission($obj1); + break; + } + } + + if ($newObject) { + $obj2->initsfGuardUserPermissions(); + $obj2->addsfGuardUserPermission($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + + public static function doSelectJoinAllExceptsfGuardPermission(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfGuardUserPermissionPeer::addSelectColumns($c); + $startcol2 = (sfGuardUserPermissionPeer::NUM_COLUMNS - sfGuardUserPermissionPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardUserPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS; + + $c->addJoin(sfGuardUserPermissionPeer::USER_ID, sfGuardUserPeer::ID); + + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfGuardUserPermissionPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfGuardUserPermission($obj1); + break; + } + } + + if ($newObject) { + $obj2->initsfGuardUserPermissions(); + $obj2->addsfGuardUserPermission($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfGuardUserPermissionPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserPermissionPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardUserPermissionPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfGuardUserPermissionPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfGuardUserPermissionPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfGuardUserPermissionPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfGuardUserPermissionPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfGuardUserPermissionPeer::USER_ID); + $selectCriteria->add(sfGuardUserPermissionPeer::USER_ID, $criteria->remove(sfGuardUserPermissionPeer::USER_ID), $comparison); + + $comparison = $criteria->getComparison(sfGuardUserPermissionPeer::PERMISSION_ID); + $selectCriteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $criteria->remove(sfGuardUserPermissionPeer::PERMISSION_ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfGuardUserPermissionPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfGuardUserPermissionPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(sfGuardUserPermissionPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfGuardUserPermissionPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfGuardUserPermission) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + if(count($values) == count($values, COUNT_RECURSIVE)) + { + $values = array($values); + } + $vals = array(); + foreach($values as $value) + { + + $vals[0][] = $value[0]; + $vals[1][] = $value[1]; + } + + $criteria->add(sfGuardUserPermissionPeer::USER_ID, $vals[0], Criteria::IN); + $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $vals[1], Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(sfGuardUserPermission $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfGuardUserPermissionPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfGuardUserPermissionPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfGuardUserPermissionPeer::DATABASE_NAME, sfGuardUserPermissionPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfGuardUserPermissionPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK( $user_id, $permission_id, $con = null) { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $criteria = new Criteria(); + $criteria->add(sfGuardUserPermissionPeer::USER_ID, $user_id); + $criteria->add(sfGuardUserPermissionPeer::PERMISSION_ID, $permission_id); + $v = sfGuardUserPermissionPeer::doSelect($criteria, $con); + + return !empty($v) ? $v[0] : null; + } +} +if (Propel::isInit()) { + try { + BasesfGuardUserPermissionPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfGuardPlugin/lib/model/map/sfGuardUserPermissionMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfGuardPlugin.lib.model.map.sfGuardUserPermissionMapBuilder'); +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroup.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroup.php new file mode 100644 index 0000000..5825068 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroup.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardGroup.php 1949 2006-09-05 14:40:20Z fabien $ + */ +class PluginsfGuardGroup extends BasesfGuardGroup +{ + public function __toString() + { + return $this->getName(); + } +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPeer.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPeer.php new file mode 100644 index 0000000..5e4540e --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPeer.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardGroupPeer.php 3109 2006-12-23 07:52:31Z fabien $ + */ +class PluginsfGuardGroupPeer extends BasesfGuardGroupPeer +{ + public static function retrieveByName($name) + { + $c = new Criteria(); + $c->add(self::NAME, $name); + + return self::doSelectOne($c); + } +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermission.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermission.php new file mode 100644 index 0000000..533d88c --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermission.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardGroupPermission.php 1949 2006-09-05 14:40:20Z fabien $ + */ +class PluginsfGuardGroupPermission extends BasesfGuardGroupPermission +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermissionPeer.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermissionPeer.php new file mode 100644 index 0000000..233d7b3 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardGroupPermissionPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardGroupPermissionPeer.php 1949 2006-09-05 14:40:20Z fabien $ + */ +class PluginsfGuardGroupPermissionPeer extends BasesfGuardGroupPermissionPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermission.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermission.php new file mode 100644 index 0000000..66ad2f9 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermission.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardPermission.php 1949 2006-09-05 14:40:20Z fabien $ + */ +class PluginsfGuardPermission extends BasesfGuardPermission +{ + public function __toString() + { + return $this->getName(); + } +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermissionPeer.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermissionPeer.php new file mode 100644 index 0000000..68565ca --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardPermissionPeer.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardPermissionPeer.php 3187 2007-01-08 10:51:03Z fabien $ + */ +class PluginsfGuardPermissionPeer extends BasesfGuardPermissionPeer +{ + public static function retrieveByName($name) + { + $c = new Criteria(); + $c->add(self::NAME, $name); + + return self::doSelectOne($c); + } +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKey.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKey.php new file mode 100644 index 0000000..5b9796f --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKey.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardPermissionPeer.php 2344 2006-10-06 17:06:58Z davedash $ + */ +class PluginsfGuardRememberKey extends BasesfGuardRememberKey +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKeyPeer.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKeyPeer.php new file mode 100644 index 0000000..33d6dea --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardRememberKeyPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardPermissionPeer.php 2344 2006-10-06 17:06:58Z davedash $ + */ +class PluginsfGuardRememberKeyPeer extends BasesfGuardRememberKeyPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUser.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUser.php new file mode 100644 index 0000000..d957fbe --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUser.php @@ -0,0 +1,296 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUser.php 5193 2007-09-19 18:26:45Z fabien $ + */ +class PluginsfGuardUser extends BasesfGuardUser +{ + protected + $profile = null, + $groups = null, + $permissions = null, + $allPermissions = null; + + public function __toString() + { + return $this->getUsername(); + } + + public function setPassword($password) + { + if (!$password) + { + return; + } + + if (!$salt = $this->getSalt()) + { + $salt = md5(rand(100000, 999999).$this->getUsername()); + $this->setSalt($salt); + } + $algorithm = sfConfig::get('app_sf_guard_plugin_algorithm_callable', 'sha1'); + $algorithmAsStr = is_array($algorithm) ? $algorithm[0].'::'.$algorithm[1] : $algorithm; + if (!is_callable($algorithm)) + { + throw new sfException(sprintf('The algorithm callable "%s" is not callable.', $algorithmAsStr)); + } + $this->setAlgorithm($algorithmAsStr); + + parent::setPassword(call_user_func_array($algorithm, array($salt.$password))); + } + + public function setPasswordBis($password) + { + } + + public function checkPassword($password) + { + if ($callable = sfConfig::get('app_sf_guard_plugin_check_password_callable')) + { + return call_user_func_array($callable, array($this->getUsername(), $password)); + } + else + { + return $this->checkPasswordByGuard($password); + } + } + + public function checkPasswordByGuard($password) + { + $algorithm = $this->getAlgorithm(); + if (false !== $pos = strpos($algorithm, '::')) + { + $algorithm = array(substr($algorithm, 0, $pos), substr($algorithm, $pos + 2)); + } + if (!is_callable($algorithm)) + { + throw new sfException(sprintf('The algorithm callable "%s" is not callable.', $algorithm)); + } + + return $this->getPassword() == call_user_func_array($algorithm, array($this->getSalt().$password)); + } + + public function getProfile() + { + if (!is_null($this->profile)) + { + return $this->profile; + } + + $profileClass = sfConfig::get('app_sf_guard_plugin_profile_class', 'sfGuardUserProfile'); + if (!class_exists($profileClass)) + { + throw new sfException(sprintf('The user profile class "%s" does not exist.', $profileClass)); + } + + $fieldName = sfConfig::get('app_sf_guard_plugin_profile_field_name', 'user_id'); + $profilePeerClass = $profileClass.'Peer'; + + // to avoid php segmentation fault + class_exists($profilePeerClass); + + $foreignKeyColumn = call_user_func_array(array($profilePeerClass, 'translateFieldName'), array($fieldName, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_COLNAME)); + + if (!$foreignKeyColumn) + { + throw new sfException(sprintf('The user profile class "%s" does not contain a "%s" column.', $profileClass, $fieldName)); + } + + $c = new Criteria(); + $c->add($foreignKeyColumn, $this->getId()); + + $this->profile = call_user_func_array(array($profileClass.'Peer', 'doSelectOne'), array($c)); + + if (!$this->profile) + { + $this->profile = new $profileClass(); + if (method_exists($this->profile, 'setsfGuardUser')) + { + $this->profile->setsfGuardUser($this); + } + else + { + $method = 'set'.call_user_func_array(array($profilePeerClass, 'translateFieldName'), array($fieldName, BasePeer::TYPE_FIELDNAME, BasePeer::TYPE_PHPNAME)); + $this->profile->$method($this->getId()); + } + } + + return $this->profile; + } + + public function addGroupByName($name, $con = null) + { + $group = sfGuardGroupPeer::retrieveByName($name); + if (!$group) + { + throw new Exception(sprintf('The group "%s" does not exist.', $name)); + } + + $ug = new sfGuardUserGroup(); + $ug->setsfGuardUser($this); + $ug->setGroupId($group->getId()); + + $ug->save($con); + } + + public function addPermissionByName($name, $con = null) + { + $permission = sfGuardPermissionPeer::retrieveByName($name); + if (!$permission) + { + throw new Exception(sprintf('The permission "%s" does not exist.', $name)); + } + + $up = new sfGuardUserPermission(); + $up->setsfGuardUser($this); + $up->setPermissionId($permission->getId()); + + $up->save($con); + } + + public function hasGroup($name) + { + if (!$this->groups) + { + $this->getGroups(); + } + + return isset($this->groups[$name]); + } + + public function getGroups() + { + if (!$this->groups) + { + $this->groups = array(); + + $c = new Criteria(); + $c->add(sfGuardUserGroupPeer::USER_ID, $this->getId()); + $ugs = sfGuardUserGroupPeer::doSelectJoinsfGuardGroup($c); + + foreach ($ugs as $ug) + { + $group = $ug->getsfGuardGroup(); + $this->groups[$group->getName()] = $group; + } + } + + return $this->groups; + } + + public function getGroupNames() + { + return array_keys($this->getGroups()); + } + + public function hasPermission($name) + { + if (!$this->permissions) + { + $this->getPermissions(); + } + + return isset($this->permissions[$name]); + } + + public function getPermissions() + { + if (!$this->permissions) + { + $this->permissions = array(); + + $c = new Criteria(); + $c->add(sfGuardUserPermissionPeer::USER_ID, $this->getId()); + $ups = sfGuardUserPermissionPeer::doSelectJoinsfGuardPermission($c); + + foreach ($ups as $up) + { + $permission = $up->getsfGuardPermission(); + $this->permissions[$permission->getName()] = $permission; + } + } + + return $this->permissions; + } + + public function getPermissionNames() + { + return array_keys($this->getPermissions()); + } + + // merge of permission in a group + permissions + public function getAllPermissions() + { + if (!$this->allPermissions) + { + $this->allPermissions = $this->getPermissions(); + + foreach ($this->getGroups() as $group) + { + foreach ($group->getsfGuardGroupPermissions() as $gp) + { + $permission = $gp->getsfGuardPermission(); + + $this->allPermissions[$permission->getName()] = $permission; + } + } + } + + return $this->allPermissions; + } + + public function getAllPermissionNames() + { + return array_keys($this->getAllPermissions()); + } + + public function reloadGroupsAndPermissions() + { + $this->groups = null; + $this->permissions = null; + $this->allPermissions = null; + } + + public function delete($con = null) + { + // delete profile if available + try + { + if ($profile = $this->getProfile()) + { + $profile->delete(); + } + } + catch (sfException $e) + { + } + + return parent::delete(); + } + + public function setPasswordHash($v) + { + if (!is_null($v) && !is_string($v)) + { + $v = (string) $v; + } + + if ($this->password !== $v) + { + $this->password = $v; + $this->modifiedColumns[] = sfGuardUserPeer::PASSWORD; + } + } +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroup.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroup.php new file mode 100644 index 0000000..64eb13b --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroup.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserGroup.php 4939 2007-08-30 14:00:49Z fabien $ + */ +class PluginsfGuardUserGroup extends BasesfGuardUserGroup +{ + public function save($con = null) + { + parent::save($con); + + $this->getsfGuardUser($con)->reloadGroupsAndPermissions(); + } +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroupPeer.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroupPeer.php new file mode 100644 index 0000000..3175310 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserGroupPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserGroupPeer.php 3109 2006-12-23 07:52:31Z fabien $ + */ +class PluginsfGuardUserGroupPeer extends BasesfGuardUserGroupPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPeer.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPeer.php new file mode 100644 index 0000000..b3a3ee2 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPeer.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserPeer.php 3810 2007-04-17 19:37:51Z davedash $ + */ +class PluginsfGuardUserPeer extends BasesfGuardUserPeer +{ + public static function retrieveByUsername($username, $isActive = true) + { + $c = new Criteria(); + $c->add(self::USERNAME, $username); + $c->add(self::IS_ACTIVE, $isActive); + + return self::doSelectOne($c); + } + +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermission.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermission.php new file mode 100644 index 0000000..035ba32 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermission.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserPermission.php 4939 2007-08-30 14:00:49Z fabien $ + */ +class PluginsfGuardUserPermission extends BasesfGuardUserPermission +{ + public function save($con = null) + { + parent::save($con); + + $this->getsfGuardUser($con)->reloadGroupsAndPermissions(); + } +} diff --git a/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermissionPeer.php b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermissionPeer.php new file mode 100644 index 0000000..e25b624 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/plugin/PluginsfGuardUserPermissionPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserPermissionPeer.php 3109 2006-12-23 07:52:31Z fabien $ + */ +class PluginsfGuardUserPermissionPeer extends BasesfGuardUserPermissionPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardGroup.php b/plugins/sfGuardPlugin/lib/model/sfGuardGroup.php new file mode 100644 index 0000000..15546fd --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardGroup.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardGroup.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardGroup extends PluginsfGuardGroup +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardGroupPeer.php b/plugins/sfGuardPlugin/lib/model/sfGuardGroupPeer.php new file mode 100644 index 0000000..796322e --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardGroupPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardGroupPeer.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardGroupPeer extends PluginsfGuardGroupPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermission.php b/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermission.php new file mode 100644 index 0000000..b718120 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermission.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardGroupPermission.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardGroupPermission extends PluginsfGuardGroupPermission +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermissionPeer.php b/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermissionPeer.php new file mode 100644 index 0000000..39b1a0b --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardGroupPermissionPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardGroupPermissionPeer.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardGroupPermissionPeer extends PluginsfGuardGroupPermissionPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardPermission.php b/plugins/sfGuardPlugin/lib/model/sfGuardPermission.php new file mode 100644 index 0000000..d536573 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardPermission.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardPermission.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardPermission extends PluginsfGuardPermission +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardPermissionI18n.php b/plugins/sfGuardPlugin/lib/model/sfGuardPermissionI18n.php new file mode 100644 index 0000000..4fbac19 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardPermissionI18n.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardPermissionPeer.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardPermissionPeer extends PluginsfGuardPermissionPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardRememberKey.php b/plugins/sfGuardPlugin/lib/model/sfGuardRememberKey.php new file mode 100644 index 0000000..0c07205 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardRememberKey.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardPermissionPeer.php 2344 2006-10-06 17:06:58Z davedash $ + */ +class sfGuardRememberKey extends PluginsfGuardRememberKey +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardRememberKeyPeer.php b/plugins/sfGuardPlugin/lib/model/sfGuardRememberKeyPeer.php new file mode 100644 index 0000000..d82c4aa --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardRememberKeyPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardPermissionPeer.php 2344 2006-10-06 17:06:58Z davedash $ + */ +class sfGuardRememberKeyPeer extends PluginsfGuardRememberKeyPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardUser.php b/plugins/sfGuardPlugin/lib/model/sfGuardUser.php new file mode 100644 index 0000000..cb6f7d9 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardUser.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUser.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardUser extends PluginsfGuardUser +{ +} \ No newline at end of file diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardUserGroup.php b/plugins/sfGuardPlugin/lib/model/sfGuardUserGroup.php new file mode 100644 index 0000000..cfd0217 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardUserGroup.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserGroup.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardUserGroup extends PluginsfGuardUserGroup +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardUserGroupPeer.php b/plugins/sfGuardPlugin/lib/model/sfGuardUserGroupPeer.php new file mode 100644 index 0000000..2c5945f --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardUserGroupPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserGroupPeer.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardUserGroupPeer extends PluginsfGuardUserGroupPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardUserPeer.php b/plugins/sfGuardPlugin/lib/model/sfGuardUserPeer.php new file mode 100644 index 0000000..996eeb6 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardUserPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserPeer.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardUserPeer extends PluginsfGuardUserPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardUserPermission.php b/plugins/sfGuardPlugin/lib/model/sfGuardUserPermission.php new file mode 100644 index 0000000..e78f472 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardUserPermission.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserPermission.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardUserPermission extends PluginsfGuardUserPermission +{ +} diff --git a/plugins/sfGuardPlugin/lib/model/sfGuardUserPermissionPeer.php b/plugins/sfGuardPlugin/lib/model/sfGuardUserPermissionPeer.php new file mode 100644 index 0000000..afd37de --- /dev/null +++ b/plugins/sfGuardPlugin/lib/model/sfGuardUserPermissionPeer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserPermissionPeer.php 5760 2007-10-30 07:51:16Z francois $ + */ +class sfGuardUserPermissionPeer extends PluginsfGuardUserPermissionPeer +{ +} diff --git a/plugins/sfGuardPlugin/lib/sfGuardBasicSecurityFilter.class.php b/plugins/sfGuardPlugin/lib/sfGuardBasicSecurityFilter.class.php new file mode 100644 index 0000000..264a171 --- /dev/null +++ b/plugins/sfGuardPlugin/lib/sfGuardBasicSecurityFilter.class.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardBasicSecurityFilter.class.php 135 2008-02-08 21:33:02Z kjellm $ + */ +class sfGuardBasicSecurityFilter extends sfBasicSecurityFilter +{ + public function execute ($filterChain) + { + if ($this->isFirstCall() and !$this->getContext()->getUser()->isAuthenticated()) + { + if ($cookie = $this->getContext()->getRequest()->getCookie(sfConfig::get('app_sf_guard_plugin_remember_cookie_name', 'sfRemember'))) + { + $c = new Criteria(); + $c->add(sfGuardRememberKeyPeer::REMEMBER_KEY, $cookie); + $rk = sfGuardRememberKeyPeer::doSelectOne($c); + if ($rk && $rk->getSfGuardUser()) + { + $this->getContext()->getUser()->signIn($rk->getSfGuardUser()); + } + } + } + + parent::execute($filterChain); + } +} diff --git a/plugins/sfGuardPlugin/lib/user/sfGuardSecurityUser.class.php b/plugins/sfGuardPlugin/lib/user/sfGuardSecurityUser.class.php new file mode 100644 index 0000000..822a3ee --- /dev/null +++ b/plugins/sfGuardPlugin/lib/user/sfGuardSecurityUser.class.php @@ -0,0 +1,212 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardSecurityUser.class.php 6016 2007-11-14 11:09:59Z fabien $ + */ +class sfGuardSecurityUser extends sfBasicSecurityUser +{ + private $user = null; + + public function hasCredential($credential, $useAnd = true) + { + if (!$this->getGuardUser()) + { + return false; + } + + if ($this->getGuardUser()->getIsSuperAdmin()) + { + return true; + } + + return parent::hasCredential($credential, $useAnd); + } + + public function isSuperAdmin() + { + return $this->getGuardUser()->getIsSuperAdmin(); + } + + public function isAnonymous() + { + return !$this->isAuthenticated(); + } + + public function signIn($user, $remember = false, $con = null) + { + // signin + $this->setAttribute('user_id', $user->getId(), 'sfGuardSecurityUser'); + $this->setAuthenticated(true); + $this->clearCredentials(); + $this->addCredentials($user->getAllPermissionNames()); + + // save last login + $user->setLastLogin(time()); + $user->save($con); + + // remember? + if ($remember) + { + // remove old keys + $c = new Criteria(); + $expiration_age = sfConfig::get('app_sf_guard_plugin_remember_key_expiration_age', 15 * 24 * 3600); + $c->add(sfGuardRememberKeyPeer::CREATED_AT, time() - $expiration_age, Criteria::LESS_THAN); + sfGuardRememberKeyPeer::doDelete($c); + + // remove other keys from this user + $c = new Criteria(); + $c->add(sfGuardRememberKeyPeer::USER_ID, $user->getId()); + sfGuardRememberKeyPeer::doDelete($c); + + // generate new keys + $key = $this->generateRandomKey(); + + // save key + $rk = new sfGuardRememberKey(); + $rk->setRememberKey($key); + $rk->setSfGuardUser($user); + $rk->setIpAddress($_SERVER['REMOTE_ADDR']); + $rk->save($con); + + // make key as a cookie + $remember_cookie = sfConfig::get('app_sf_guard_plugin_remember_cookie_name', 'sfRemember'); + sfContext::getInstance()->getResponse()->setCookie($remember_cookie, $key, time() + $expiration_age); + } + } + + protected function generateRandomKey($len = 20) + { + $string = ''; + $pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + for ($i = 1; $i <= $len; $i++) + { + $string .= substr($pool, rand(0, 61), 1); + } + + return md5($string); + } + + public function signOut() + { + $this->getAttributeHolder()->removeNamespace('sfGuardSecurityUser'); + $this->user = null; + $this->clearCredentials(); + $this->setAuthenticated(false); + $expiration_age = sfConfig::get('app_sf_guard_plugin_remember_key_expiration_age', 15 * 24 * 3600); + $remember_cookie = sfConfig::get('app_sf_guard_plugin_remember_cookie_name', 'sfRemember'); + sfContext::getInstance()->getResponse()->setCookie($remember_cookie, '', time() - $expiration_age); + } + + public function getGuardUser() + { + if (!$this->user && $id = $this->getAttribute('user_id', null, 'sfGuardSecurityUser')) + { + $this->user = sfGuardUserPeer::retrieveByPk($id); + + if (!$this->user) + { + // the user does not exist anymore in the database + $this->signOut(); + + throw new sfException('The user does exist anymore in the database.'); + } + } + + return $this->user; + } + + // add some proxy method to the sfGuardUser instance + + public function __toString() + { + return $this->getGuardUser()->__toString(); + } + + public function getUsername() + { + return $this->getGuardUser()->getUsername(); + } + + public function getEmail() + { + return $this->getGuardUser()->getEmail(); + } + + public function setPassword($password, $con = null) + { + $this->getGuardUser()->setPassword($password); + $this->getGuardUser()->save($con); + } + + public function checkPassword($password) + { + return $this->getGuardUser()->checkPassword($password); + } + + public function hasGroup($name) + { + return $this->getGuardUser() ? $this->getGuardUser()->hasGroup($name) : false; + } + + public function getGroups() + { + return $this->getGuardUser() ? $this->getGuardUser()->getGroups() : array(); + } + + public function getGroupNames() + { + return $this->getGuardUser() ? $this->getGuardUser()->getGroupNames() : array(); + } + + public function hasPermission($name) + { + return $this->getGuardUser() ? $this->getGuardUser()->hasPermission($name) : false; + } + + public function getPermissions() + { + return $this->getGuardUser()->getPermissions(); + } + + public function getPermissionNames() + { + return $this->getGuardUser() ? $this->getGuardUser()->getPermissionNames() : array(); + } + + public function getAllPermissions() + { + return $this->getGuardUser() ? $this->getGuardUser()->getAllPermissions() : array(); + } + + public function getAllPermissionNames() + { + return $this->getGuardUser() ? $this->getGuardUser()->getAllPermissionNames() : array(); + } + + public function getProfile() + { + return $this->getGuardUser() ? $this->getGuardUser()->getProfile() : null; + } + + public function addGroupByName($name, $con = null) + { + return $this->getGuardUser()->addGroupByName($name, $con); + } + + public function addPermissionByName($name, $con = null) + { + return $this->getGuardUser()->addPermissionByName($name, $con); + } +} diff --git a/plugins/sfGuardPlugin/lib/validator/sfGuardUserValidator.class.php b/plugins/sfGuardPlugin/lib/validator/sfGuardUserValidator.class.php new file mode 100644 index 0000000..367b04a --- /dev/null +++ b/plugins/sfGuardPlugin/lib/validator/sfGuardUserValidator.class.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: sfGuardUserValidator.class.php 3109 2006-12-23 07:52:31Z fabien $ + */ +class sfGuardUserValidator extends sfValidator +{ + public function initialize($context, $parameters = null) + { + // initialize parent + parent::initialize($context); + + // set defaults + $this->getParameterHolder()->set('username_error', 'Username or password is not valid.'); + $this->getParameterHolder()->set('password_field', 'password'); + $this->getParameterHolder()->set('remember_field', 'remember'); + + $this->getParameterHolder()->add($parameters); + + return true; + } + + public function execute(&$value, &$error) + { + $password_field = $this->getParameterHolder()->get('password_field'); + $password = $this->getContext()->getRequest()->getParameter($password_field); + + $remember = false; + $remember_field = $this->getParameterHolder()->get('remember_field'); + $remember = $this->getContext()->getRequest()->getParameter($remember_field); + + $username = $value; + + $user = sfGuardUserPeer::retrieveByUsername($username); + + // user exists? + if ($user) + { + // password is ok? + if ($user->checkPassword($password)) + { + $this->getContext()->getUser()->signIn($user, $remember); + + return true; + } + } + + $error = $this->getParameterHolder()->get('username_error'); + + return false; + } +} diff --git a/plugins/sfGuardPlugin/modules/sfGuardAuth/actions/actions.class.php b/plugins/sfGuardPlugin/modules/sfGuardAuth/actions/actions.class.php new file mode 100644 index 0000000..c66d91c --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardAuth/actions/actions.class.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once(dirname(__FILE__).'/../lib/BasesfGuardAuthActions.class.php'); + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: actions.class.php 2278 2006-10-01 13:30:31Z fabien $ + */ +class sfGuardAuthActions extends BasesfGuardAuthActions +{ +} diff --git a/plugins/sfGuardPlugin/modules/sfGuardAuth/config/security.yml b/plugins/sfGuardPlugin/modules/sfGuardAuth/config/security.yml new file mode 100644 index 0000000..b097bc1 --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardAuth/config/security.yml @@ -0,0 +1,8 @@ +secure: + is_secure: off + +signin: + is_secure: off + +signout: + is_secure: off diff --git a/plugins/sfGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php b/plugins/sfGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php new file mode 100644 index 0000000..318c495 --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: BasesfGuardAuthActions.class.php 5003 2007-09-08 08:42:27Z fabien $ + */ +class BasesfGuardAuthActions extends sfActions +{ + public function executeSignin() + { + $user = $this->getUser(); + if ($this->getRequest()->getMethod() == sfRequest::POST) + { + //Changed by Russ Flynn - possible fix to redirect error? + //$referer = $user->getAttribute('referer', $this->getRequest()->getReferer()); + // $referer = $user->getAttribute('referer') ? $user->getAttribute('referer') : $this->getRequest()->getReferer(); + $referer = $this->getRequestParameter('referer') ? $this->getRequestParameter('referer') : "/fred"; + + $user->getAttributeHolder()->remove('referer'); + + $signin_url = sfConfig::get('app_sf_guard_plugin_success_signin_url', $referer); + + $this->redirect('' != $signin_url ? $signin_url : '@home'); + } + elseif ($user->isAuthenticated()) + { + $this->redirect('@home'); + } + else + { + if (!$user->hasAttribute('referer')) + { + $user->setAttribute('referer', $this->getRequest()->getReferer()); + } + + $module = sfConfig::get('sf_login_module'); + if ($this->getModuleName() != $module) + { + $this->redirect($module.'/'.sfConfig::get('sf_login_action')); + } + } + } + + public function executeSignout() + { + $this->getUser()->signOut(); + + $signout_url = sfConfig::get('app_sf_guard_plugin_success_signout_url', $this->getRequest()->getReferer()); + + } + + public function executeSecure() + { + } + + public function executePassword() + { + throw new sfException('This method is not yet implemented.'); + } + + public function handleErrorSignin() + { + $user = $this->getUser(); + if (!$user->hasAttribute('referer')) + { + $user->setAttribute('referer', $this->getRequest()->getReferer()); + } + + $module = sfConfig::get('sf_login_module'); + if ($this->getModuleName() != $module) + { + $this->forward(sfConfig::get('sf_login_module'), sfConfig::get('sf_login_action')); + } + + return sfView::SUCCESS; + } +} diff --git a/plugins/sfGuardPlugin/modules/sfGuardAuth/templates/secureSuccess.php b/plugins/sfGuardPlugin/modules/sfGuardAuth/templates/secureSuccess.php new file mode 100644 index 0000000..5fbbbe5 --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardAuth/templates/secureSuccess.php @@ -0,0 +1 @@ +

    \ No newline at end of file diff --git a/plugins/sfGuardPlugin/modules/sfGuardAuth/templates/signinSuccess.php b/plugins/sfGuardPlugin/modules/sfGuardAuth/templates/signinSuccess.php new file mode 100644 index 0000000..1709fa5 --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardAuth/templates/signinSuccess.php @@ -0,0 +1,34 @@ +
    + + +
    + +
    + get('sf_params')->get('username')); + ?> +
    + +
    + +
    +
    + +
    +
    + + 'sf_guard_auth_forgot_password')) + ?> + +
    diff --git a/plugins/sfGuardPlugin/modules/sfGuardAuth/validate/signin.yml b/plugins/sfGuardPlugin/modules/sfGuardAuth/validate/signin.yml new file mode 100644 index 0000000..10ce04e --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardAuth/validate/signin.yml @@ -0,0 +1,18 @@ +methods: + post: [username, password] + +names: + username: + required: true + required_msg: Your username is required + validators: [userValidator] + + password: + required: true + required_msg: Your password is required + +userValidator: + class: sfGuardUserValidator + param: + password_field: password + remember_field: remember diff --git a/plugins/sfGuardPlugin/modules/sfGuardGroup/actions/actions.class.php b/plugins/sfGuardPlugin/modules/sfGuardGroup/actions/actions.class.php new file mode 100644 index 0000000..d529422 --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardGroup/actions/actions.class.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Group management. + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: actions.class.php 1949 2006-09-05 14:40:20Z fabien $ + */ +class sfGuardGroupActions extends autosfGuardGroupActions +{ + function handleErrorEdit() + { + $ret = parent::handleErrorEdit(); + $this->labels['associated_permissions'] = 'Permissions:'; + return $ret; + } +} diff --git a/plugins/sfGuardPlugin/modules/sfGuardGroup/config/generator.yml b/plugins/sfGuardPlugin/modules/sfGuardGroup/config/generator.yml new file mode 100644 index 0000000..4d156b1 --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardGroup/config/generator.yml @@ -0,0 +1,12 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: sfGuardGroup + theme: default + + list: + title: Group list + display: [=name, description] + + edit: + title: Edit "%%name%%" group \ No newline at end of file diff --git a/plugins/sfGuardPlugin/modules/sfGuardPermission/actions/actions.class.php b/plugins/sfGuardPlugin/modules/sfGuardPermission/actions/actions.class.php new file mode 100644 index 0000000..faa32bf --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardPermission/actions/actions.class.php @@ -0,0 +1,42 @@ + +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +/** +* Permission management. +* +* @package symfony +* @subpackage plugin +* @author Fabien Potencier +* @version SVN: $Id: actions.class.php 3109 2006-12-23 07:52:31Z fabien $ +*/ +class sfGuardPermissionActions extends autosfGuardPermissionActions +{ + protected function updatesfGuardPermissionFromRequest() + { + $sf_guard_permission = $this->getRequestParameter('sf_guard_permission'); + + if (isset($sf_guard_permission['name'])) + { + $this->sf_guard_permission->setName($sf_guard_permission['name']); + } + if (isset($sf_guard_permission['description'])) + { + $this->sf_guard_permission->setDescription($sf_guard_permission['description']); + } + if (!empty($sf_guard_permission['module_name'])) + { + $this->sf_guard_permission->setModuleName($sf_guard_permission['module_name']); + } + if (!empty($sf_guard_permission['action_name'])) + { + $this->sf_guard_permission->setActionName($sf_guard_permission['action_name']); + } + } +} diff --git a/plugins/sfGuardPlugin/modules/sfGuardPermission/config/generator.yml b/plugins/sfGuardPlugin/modules/sfGuardPermission/config/generator.yml new file mode 100644 index 0000000..9ebbd1e --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardPermission/config/generator.yml @@ -0,0 +1,12 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: sfGuardPermission + theme: default + + list: + title: Permission list + display: [=name, description] + + edit: + title: Edit "%%name%%" permission diff --git a/plugins/sfGuardPlugin/modules/sfGuardPermission/validate/edit.yml b/plugins/sfGuardPlugin/modules/sfGuardPermission/validate/edit.yml new file mode 100644 index 0000000..f90f04e --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardPermission/validate/edit.yml @@ -0,0 +1,16 @@ +methods: + post: + - "sf_guard_permission{name}" + +names: + sf_guard_permission{name}: + required: yes + required_msg: Please, enter a name + validators: nameUniqueValidator + +nameUniqueValidator: + class: sfPropelUniqueValidator + param: + class: sfGuardPermission + column: name + unique_error: This permission name already exists diff --git a/plugins/sfGuardPlugin/modules/sfGuardUser/actions/actions.class.php b/plugins/sfGuardPlugin/modules/sfGuardUser/actions/actions.class.php new file mode 100644 index 0000000..604c43d --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardUser/actions/actions.class.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once(dirname(__FILE__).'/../lib/BasesfGuardUserActions.class.php'); + +/** + * User management. + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: actions.class.php 3422 2007-02-07 11:57:05Z fabien $ + */ +class sfGuardUserActions extends BasesfGuardUserActions +{ +} diff --git a/plugins/sfGuardPlugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php b/plugins/sfGuardPlugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php new file mode 100644 index 0000000..0f137b6 --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Fabien Potencier + * @version SVN: $Id: BasesfGuardUserActions.class.php 3384 2007-02-01 09:05:19Z fabien $ + */ +class BasesfGuardUserActions extends autosfGuardUserActions +{ + public function validateEdit() + { + if ($this->getRequest()->getMethod() == sfRequest::POST && !$this->getRequestParameter('id')) + { + if ($this->getRequestParameter('sf_guard_user[password]') == '') + { + $this->getRequest()->setError('sf_guard_user{password}', 'Password is mandatory'); + + return false; + } + } + + return true; + } +} diff --git a/plugins/sfGuardPlugin/modules/sfGuardUser/templates/_password.php b/plugins/sfGuardPlugin/modules/sfGuardUser/templates/_password.php new file mode 100644 index 0000000..4d3ed8b --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardUser/templates/_password.php @@ -0,0 +1 @@ + 'sf_guard_user[password]')) ?> diff --git a/plugins/sfGuardPlugin/modules/sfGuardUser/templates/_password_bis.php b/plugins/sfGuardPlugin/modules/sfGuardUser/templates/_password_bis.php new file mode 100644 index 0000000..2095380 --- /dev/null +++ b/plugins/sfGuardPlugin/modules/sfGuardUser/templates/_password_bis.php @@ -0,0 +1 @@ + 'sf_guard_user[password_bis]')) ?> diff --git a/plugins/sfI18nDbTranslationPlugin/LICENSE b/plugins/sfI18nDbTranslationPlugin/LICENSE new file mode 100644 index 0000000..c5e0f13 --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2008 Gareth James + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfI18nDbTranslationPlugin/README b/plugins/sfI18nDbTranslationPlugin/README new file mode 100644 index 0000000..5763a22 --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/README @@ -0,0 +1,38 @@ += sfI18nDbTranslation plugin = + +== Overview == + +This plugin provides an admin interface to update translations stored in a database + +== Installation == + +To install sfI18nDbTranslation: + +{{{ +symfony plugin-install local|global http://bemused.org/symfony/sfI18nDbTranslation +}}} + +Enable the plugin in apps/backend/config/settings.yml: + +{{{ + enabled_modules: [default, sfTransUnit, sfCatalogue] +}}} + +== Usage == + +Create an entry for each language in the catalogue table. Edit the plugins/sfI18nDbTranslation/data/fixtures/fixtures.yml, then update the data using + +{{{ +symfony propel-load-data frontend plugins/sfI18nDbTranslationPlugin/data/fixtures +}}} + +== Known limitations/TODO == + - 'Use comment for all translations' checkbox doesn't work + - html pages are ugly + - delete button doesn't delete all translations on trans_unit page (should it?) + - lots of other stuff probably + +== License == + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. diff --git a/plugins/sfI18nDbTranslationPlugin/modules/sfCatalogue/actions/actions.class.php b/plugins/sfI18nDbTranslationPlugin/modules/sfCatalogue/actions/actions.class.php new file mode 100644 index 0000000..f761507 --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/modules/sfCatalogue/actions/actions.class.php @@ -0,0 +1,13 @@ + + * @version SVN: $Id$ + */ +require_once(dirname(__FILE__).'/../lib/BasesfTransUnitActions.class.php'); + +class sfTransUnitActions extends BasesfTransUnitActions +{ +} diff --git a/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/config/generator.yml b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/config/generator.yml new file mode 100644 index 0000000..1e79f9f --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/config/generator.yml @@ -0,0 +1,47 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: TransUnit + theme: default + + list: + title: Translation list + max_per_page: 50 + display: [_lang, =source, target, comments, translated] + filters: [source, _translated, _catfilter, filename, module] + object_actions: + _edit: ~ + _delete: ~ + # sort: source + fields: + source: { params: disabled=false } + translated: { params: disabled=false, type: boolean } + _lang: { params: lang } + catfilter: { name: language } + actions: + # _search: { name: Search for new untranslated text, action: ~ } + _create: { name: Create new , action: ~ } + + create: + title: create Translation + display: [source, comments] + fields: + source: { params: disabled=false size=80, type: input_tag } + comments: { params: disabled=false size=80×5, type: textarea_tag } + actions: + _list: ~ + _save: ~ + _delete: ~ + + edit: + title: “Edit Translation” + display: [source, _target] + fields: + source: { params: disabled=false size=80, type: input_tag, name: Opprinnelig tekst } + # comments: { params: disabled=false size=80x5, type: textarea_tag } + actions: + previous: { name: Previous string, action: previousString, icon: backend/next.png } + _list: ~ + _save: ~ + next: { name: Next string, action: nextString, icon: backend/next.png } + _delete: ~ \ No newline at end of file diff --git a/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/lib/BasesfTransUnitActions.class.php b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/lib/BasesfTransUnitActions.class.php new file mode 100644 index 0000000..3626365 --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/lib/BasesfTransUnitActions.class.php @@ -0,0 +1,154 @@ + + * (c) 2008 Gareth James + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage plugin + * @author Gareth James + * @version SVN: $Id$ + */ + +class BasesfTransUnitActions extends autoSfTransUnitActions +{ + public function executeEdit() + { + $this->trans_unit = $this->getTransUnitOrCreate(); + $catalogues = CataloguePeer::getCatalogues(); + foreach ($catalogues as $catalogue) { + $c = new Criteria(); + $c->add(TransUnitPeer::CAT_ID, $catalogue->getCatId()); + $c->add(TransUnitPeer::SOURCE, $this->trans_unit->getSource()); + $trans_unit_cat = TransUnitPeer::doSelectOne($c); + $trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + if ($trans_unit_cat) { + $this->$trans_unit_string = $this->getTransUnitByMsgIdOrCreate($trans_unit_cat->getMsgId()); + } else { + $this->$trans_unit_string = $this->getTransUnitOrCreate(); + } + } + + if ($this->getRequest()->getMethod() == sfRequest::POST) + { + foreach ($catalogues as $catalogue) { + $this->updateTransUnitCatIdFromRequest($catalogue->getCatId()); + $trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + $this->saveTransUnit($this->$trans_unit_string); + } + + $this->setFlash('notice', 'Your modifications have been saved'); + + if ($this->getRequestParameter('save_and_add')) + { + return $this->redirect('sfTransUnit/create'); + } + else if ($this->getRequestParameter('save_and_list')) + { + return $this->redirect('sfTransUnit/list'); + } + else + { + return $this->redirect('sfTransUnit/edit?msg_id='.$this->trans_unit->getMsgId()); + } + } + else + { + $this->labels = $this->getLabels(); + } + } + + protected function updateTransUnitCatIdFromRequest($cat_id) + { + $trans_unit_string = 'trans_unit_' . $cat_id; + ${$trans_unit_string} = $this->getRequestParameter("trans_unit_$cat_id"); + + if (isset(${$trans_unit_string}['source'])) + { + $this->$trans_unit_string->setSource(${$trans_unit_string}['source']); + } + if (isset(${$trans_unit_string}['target']) && (${$trans_unit_string}['target'] != $this->$trans_unit_string->getTarget())) { + $this->$trans_unit_string->setTranslated(1); + } else if (! isset(${$trans_unit_string}['translated'])) + { + $this->$trans_unit_string->setTranslated(0); + } + if (isset(${$trans_unit_string}['default']) ) { + $this->$trans_unit_string->setTarget($this->$trans_unit_string->getSource()); + } else if (isset(${$trans_unit_string}['target'])) + { + $this->$trans_unit_string->setTarget(${$trans_unit_string}['target']); + } + if (isset(${$trans_unit_string}['comments'])) + { + $this->$trans_unit_string->setComments(${$trans_unit_string}['comments']); + } + } + + protected function addFiltersCriteria($c) + { + if (isset($this->filters['source_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::SOURCE, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::SOURCE, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['source']) && $this->filters['source'] !== '') + { + $c->add(TransUnitPeer::SOURCE, '%' . $this->filters['source']. '%', Criteria::LIKE); + } + if (isset($this->filters['module_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::MODULE, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::MODULE, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['module']) && $this->filters['module'] !== '') + { + $c->add(TransUnitPeer::MODULE, '%' . $this->filters['module']. '%', Criteria::LIKE); + } + if (isset($this->filters['translated_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::TRANSLATED, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::TRANSLATED, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['translated']) && $this->filters['translated'] !== '') + { + $c->add(TransUnitPeer::TRANSLATED, $this->filters['translated']); + } + if (isset($this->filters['cat_is_empty'])) + { + $criterion = $c->getNewCriterion(TransUnitPeer::CAT_ID, ''); + $criterion->addOr($c->getNewCriterion(TransUnitPeer::CAT_ID, null, Criteria::ISNULL)); + $c->add($criterion); + } + else if (isset($this->filters['cat_id']) && $this->filters['cat_id'] !== '') + { + $c->add(TransUnitPeer::CAT_ID, $this->filters['cat_id']); + } + } + + protected function getTransUnitByMsgIdOrCreate($msg_id = NULL) + { + if (is_null($msg_id)) + { + $trans_unit = new TransUnit(); + } + else + { + $trans_unit = TransUnitPeer::retrieveByPk($msg_id); + + $this->forward404Unless($trans_unit); + } + return $trans_unit; + } + +} diff --git a/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_catfilter.php b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_catfilter.php new file mode 100644 index 0000000..603bb0a --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_catfilter.php @@ -0,0 +1,2 @@ + + true) )) ?> diff --git a/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_lang.php b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_lang.php new file mode 100644 index 0000000..35cbcda --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_lang.php @@ -0,0 +1 @@ +getTargetLang() ?> diff --git a/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_target.php b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_target.php new file mode 100644 index 0000000..0e75f14 --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_target.php @@ -0,0 +1,34 @@ + +getMsgId()); +foreach ($catalogues as $catalogue) { + $c = new Criteria(); + $c->add(TransUnitPeer::CAT_ID, $catalogue->getCatId()); + $c->add(TransUnitPeer::SOURCE, $trans_unit->getSource()); + $trans_unit_string = 'trans_unit_' . $catalogue->getCatId(); + $cat_id = $catalogue->getCatId(); + $$trans_unit_string = TransUnitPeer::doSelectOne($c); + if ($$trans_unit_string) { + $msg_id_string = 'msg_id_' . $catalogue->getCatId(); + echo input_hidden_tag("${trans_unit_string}[msg_id]", ${$trans_unit_string}->getMsgId()); + } else { + $$trans_unit_string = new TransUnit(); + } + + echo ''.$catalogue->getTargetLang().''; + echo '
    '; + echo checkbox_tag("${trans_unit_string}[default]", 1, ''); + echo " Set translation to source string"; + echo '
    '; + echo input_tag("${trans_unit_string}[target]", $$trans_unit_string->getTarget(), array('style' => 'width: 480px')); + echo '
    '; + echo checkbox_tag("${trans_unit_string}[translated]", 1, ($$trans_unit_string->getTranslated() == 1) ? 1 : 0); + echo " Translated"; + echo '
    '; + echo textarea_tag("${trans_unit_string}[comments]", $$trans_unit_string->getComments()); + echo '
    '; + echo checkbox_tag("${trans_unit_string}[global]", 1, ''); + echo " Use this comment for all translations"; + echo '
    '; + echo "
    \n"; +} diff --git a/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_translated.php b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_translated.php new file mode 100644 index 0000000..6c1c9b8 --- /dev/null +++ b/plugins/sfI18nDbTranslationPlugin/modules/sfTransUnit/templates/_translated.php @@ -0,0 +1,5 @@ + 'all', + '0' => 'untranslated', + '1' => 'translated', + ), isset($filters['translated']) ? $filters['translated'] : '' )) ?> diff --git a/plugins/sfI18nExtractPlugin/LICENSE b/plugins/sfI18nExtractPlugin/LICENSE new file mode 100644 index 0000000..28956ad --- /dev/null +++ b/plugins/sfI18nExtractPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2004-2006 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfI18nExtractPlugin/README b/plugins/sfI18nExtractPlugin/README new file mode 100644 index 0000000..6da9ee4 --- /dev/null +++ b/plugins/sfI18nExtractPlugin/README @@ -0,0 +1,55 @@ += sfI18nExtract plugin = + +The `sfI18nExtract` is a symfony plugin that provides i18n strings extraction. + +This plugin is a backport of a symfony 1.1 native feature. + +== Installation == + + * Install the plugin + + {{{ + symfony plugin-install http://plugins.symfony-project.com/sfI18nExtractPlugin + }}} + + * Clear you cache + + {{{ + symfony cc + }}} + +=== Usage === + +The `i18n-extract` task parses a symfony application to extract all the strings that need to be translated. + +It takes an application and a culture as its arguments: + + {{{ + php symfony i18n-extract frontend en + }}} + +By default, the task does not modify your dictionaries, it just outputs the number of new and old i18n strings. To append the new strings to your dictionary, you can pass the `--auto-save` option: + + {{{ + php symfony i18n-extract --auto-save frontend en + }}} + +You can also delete old strings automatically by passing the `--auto-delete` option: + + {{{ + php symfony i18n-extract --auto-save --auto-delete frontend en + }}} + +=== Known limitations === + + * Can only works with the default "messages" catalogue + * For file backends (XLIFF and gettext), it only saves/deletes strings in the `apps/myapp/i18n/messages.XX.xml` file + +=== Patch === + +The patches needed to convert the symfony 1.1 implementation to the one used in this plugin can be obtained with the 2 following commands: + + {{{ + svn diff http://svn.symfony-project.com/trunk/lib/i18n/extract/ http://svn.symfony-project.com/plugins/sfI18nExtractPlugin/lib + svn diff http://svn.symfony-project.com/trunk/data/tasks/sfPakeI18N.php http://svn.symfony-project.com/plugins/sfI18nExtractPlugin/data/tasks/sfPakeI18N.php + }}} diff --git a/plugins/sfI18nExtractPlugin/data/tasks/sfPakeI18N.php b/plugins/sfI18nExtractPlugin/data/tasks/sfPakeI18N.php new file mode 100644 index 0000000..d702905 --- /dev/null +++ b/plugins/sfI18nExtractPlugin/data/tasks/sfPakeI18N.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +pake_desc('extract i18n strings from an application'); +pake_task('i18n-extract'); + +pake_desc('find non "i18n ready" strings in an application'); +pake_task('i18n-find'); + +function run_i18n_find($task, $args) +{ + if (!count($args)) + { + throw new Exception('You must provide the application.'); + } + + $app = $args[0]; + + if (!is_dir(sfConfig::get('sf_app_dir').DIRECTORY_SEPARATOR.$app)) + { + throw new Exception(sprintf('The app "%s" does not exist.', $app)); + } + + pake_echo_action('i18n', sprintf('find non "i18n ready" strings in the "%s" application', $app)); + + sfConfig::set('sf_app', $app); + sfConfig::set('sf_environment', 'dev'); + include(sfConfig::get('sf_symfony_data_dir').'/config/constants.php'); + + // Look in templates + $moduleNames = sfFinder::type('dir')->maxdepth(0)->ignore_version_control()->relative()->in(sfConfig::get('sf_app_dir').'/modules'); + $strings = array(); + foreach ($moduleNames as $moduleName) + { + $dir = sfConfig::get('sf_app_dir').'/modules/'.$moduleName.'/templates'; + $templates = pakeFinder::type('file')->name('*.php')->relative()->in($dir); + foreach ($templates as $template) + { + $dom = new DomDocument('1.0', sfConfig::get('sf_charset', 'UTF-8')); + @$dom->loadXML(''.file_get_contents($dir.'/'.$template).''); + + $nodes = array($dom); + while ($nodes) + { + $node = array_shift($nodes); + + if (XML_TEXT_NODE === $node->nodeType) + { + if (!$node->isWhitespaceInElementContent()) + { + if (!isset($strings[$moduleName][$template])) + { + if (!isset($strings[$moduleName])) + { + $strings[$moduleName] = array(); + } + + $strings[$moduleName][$template] = array(); + } + + $strings[$moduleName][$template][] = $node->nodeValue; + } + } + else if ($node->childNodes) + { + for ($i = 0, $max = $node->childNodes->length; $i < $max; $i++) + { + $nodes[] = $node->childNodes->item($i); + } + } + } + } + } + + foreach ($strings as $moduleName => $templateStrings) + { + foreach ($templateStrings as $template => $messages) + { + pake_echo_action('i18n', sprintf('strings in "%s:%s"', $moduleName, $template)); + foreach ($messages as $message) + { + echo " $message\n"; + } + } + } +} + +function run_i18n_extract($task, $args, $options) +{ + $args = array_values($args); + + if (!count($args)) + { + throw new Exception('You must provide the application.'); + } + + $app = $args[0]; + + if (!is_dir(sfConfig::get('sf_app_dir').DIRECTORY_SEPARATOR.$app)) + { + throw new Exception(sprintf('The app "%s" does not exist.', $app)); + } + + if (!isset($args[1])) + { + throw new Exception('You must provide a culture.'); + } + + $culture = $args[1]; + + define('SF_ROOT_DIR', sfConfig::get('sf_root_dir')); + define('SF_APP', $app); + define('SF_ENVIRONMENT', 'dev'); + define('SF_DEBUG', true); + + require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'); + + sfContext::getInstance(); + + pake_echo_action('i18n', sprintf('extracting i18n strings for the "%s" application', $app)); + + $extract = new sfI18nApplicationExtract(); + $extract->initialize($culture); + $extract->extract(); + + pake_echo_action('i18n', sprintf('found "%d" new i18n strings', count($extract->getNewMessages()))); + pake_echo_action('i18n', sprintf('found "%d" old i18n strings', count($extract->getOldMessages()))); + + if (isset($options['display-new'])) + { + pake_echo_action('i18n', sprintf('display new i18n strings', count($extract->getOldMessages()))); + foreach ($extract->getNewMessages() as $message) + { + echo ' '.$message."\n"; + } + } + + if (isset($options['auto-save'])) + { + pake_echo_action('i18n', 'saving new i18n strings'); + + $extract->saveNewMessages(); + } + + if (isset($options['display-old'])) + { + pake_echo_action('i18n', sprintf('display old i18n strings', count($extract->getOldMessages()))); + foreach ($extract->getOldMessages() as $message) + { + echo ' '.$message."\n"; + } + } + + if (isset($options['auto-delete'])) + { + //$extract->deleteOldMessages(); + pake_echo_action('i18n', 'deleting old i18n strings is disabled in symfony 1.0'); + } +} diff --git a/plugins/sfI18nExtractPlugin/lib/sfI18nApplicationExtract.class.php b/plugins/sfI18nExtractPlugin/lib/sfI18nApplicationExtract.class.php new file mode 100644 index 0000000..595d616 --- /dev/null +++ b/plugins/sfI18nExtractPlugin/lib/sfI18nApplicationExtract.class.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage i18n + * @author Fabien Potencier + * @version SVN: $Id: sfI18nApplicationExtract.class.php 4378 2007-06-25 14:33:47Z fabien $ + */ +class sfI18nApplicationExtract extends sfI18nExtract +{ + protected $extractObjects = array(); + + /** + * Configures the current extract object. + */ + public function configure() + { + $this->extractObjects = array(); + + // Modules + $moduleNames = sfFinder::type('dir')->maxdepth(0)->ignore_version_control()->relative()->in(sfConfig::get('sf_app_dir').'/modules'); + foreach ($moduleNames as $moduleName) + { + $moduleExtract = new sfI18nModuleExtract(); + $moduleExtract->initialize($this->culture, array('module' => $moduleName)); + + $this->extractObjects[] = $moduleExtract; + } + } + + /** + * Extracts i18n strings. + * + * This class must be implemented by subclasses. + */ + public function extract() + { + foreach ($this->extractObjects as $extractObject) + { + $extractObject->extract(); + } + + // Add global templates + $this->extractFromPhpFiles(sfConfig::get('sf_app_template_dir')); + + // Add global librairies + $this->extractFromPhpFiles(sfConfig::get('sf_app_lib_dir')); + } + + /** + * Gets the current i18n strings. + * + * @param array An array of i18n strings + */ + public function getCurrentMessages() + { + return array_unique(array_merge($this->currentMessages, $this->aggregateMessages('getCurrentMessages'))); + } + + /** + * Gets all i18n strings seen during the extraction process. + * + * @param array An array of i18n strings + */ + public function getAllSeenMessages() + { + return array_unique(array_merge($this->allSeenMessages, $this->aggregateMessages('getAllSeenMessages'))); + } + + protected function aggregateMessages($method) + { + $messages = array(); + foreach ($this->extractObjects as $extractObject) + { + $messages = array_merge($messages, $extractObject->$method()); + } + + return array_unique($messages); + } +} diff --git a/plugins/sfI18nExtractPlugin/lib/sfI18nExtract.class.php b/plugins/sfI18nExtractPlugin/lib/sfI18nExtract.class.php new file mode 100644 index 0000000..4fd49e0 --- /dev/null +++ b/plugins/sfI18nExtractPlugin/lib/sfI18nExtract.class.php @@ -0,0 +1,218 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage i18n + * @author Fabien Potencier + * @version SVN: $Id: sfI18nExtract.class.php 4371 2007-06-25 14:00:40Z fabien $ + */ +abstract class sfI18nExtract +{ + protected + $currentMessages = array(), + $newMessages = array(), + $allSeenMessages = array(), + $culture = null, + $parameters = array(), + $i18n = null; + + /** + * Initializes the current extract object. + * + * @param string The culture + * @param array An array of parameters + */ + function initialize($culture, $parameters = array()) + { + if (!sfConfig::get('sf_i18n')) + { + throw new sfConfigurationException('You must enable "i18n" in your settings.yml configuration file.'); + } + + $this->allSeenMessages = array(); + $this->newMessages = array(); + $this->currentMessages = array(); + + $this->culture = $culture; + $this->parameters = $parameters; + + $this->i18n = sfContext::getInstance()->getI18N(); + + $this->configure(); + + $this->loadMessageSources(); + $this->loadCurrentMessages(); + } + + /** + * Configures the current extract object. + */ + public function configure() + { + } + + /** + * Extracts i18n strings. + * + * This class must be implemented by subclasses. + */ + abstract public function extract(); + + /** + * Saves the new messages. + * + * Current limitations: + * - For file backends (XLIFF and gettext), it only saves in the "most global" file + */ + public function saveNewMessages() + { + $messageSource = $this->i18n->getGlobalMessageSource(); + foreach ($this->getNewMessages() as $message) + { + $messageSource->append($message); + } + + $messageSource->save('messages', $_SESSION['messageLocations']); + } + + /** + * Deletes old messages. + * + * Current limitations: + * - For file backends (XLIFF and gettext), it only deletes in the "most global" file + */ + public function deleteOldMessages() + { + $messageSource = $this->i18n->getGlobalMessageSource(); + foreach ($this->getOldMessages() as $message) + { + $messageSource->delete($message); + } + } + + /** + * Gets the new i18n strings. + * + * @param array An array of i18n strings + */ + final public function getNewMessages() + { + return array_diff($this->getAllSeenMessages(), $this->getCurrentMessages()); + } + + /** + * Gets the current i18n strings. + * + * @param array An array of i18n strings + */ + public function getCurrentMessages() + { + return $this->currentMessages; + } + + /** + * Gets all i18n strings seen during the extraction process. + * + * @param array An array of i18n strings + */ + public function getAllSeenMessages() + { + return $this->allSeenMessages; + } + + /** + * Gets old i18n strings. + * + * This returns all strings that weren't seen during the extraction process + * and are in the current messages. + * + * @param array An array of i18n strings + */ + final public function getOldMessages() + { + return array_diff($this->getCurrentMessages(), $this->getAllSeenMessages()); + } + + /** + * Loads message sources objects and sets the culture. + */ + protected function loadMessageSources() + { + foreach (array($this->i18n->getMessageSource(), $this->i18n->getGlobalMessageSource()) as $messageSource) + { + if (!$messageSource) + { + continue; + } + + $messageSource->setCulture($this->culture); + $messageSource->load(); + } + } + + /** + * Loads messages already saved in the message sources. + */ + protected function loadCurrentMessages() + { + $this->currentMessages = array(); + foreach (array($this->i18n->getMessageSource(), $this->i18n->getGlobalMessageSource()) as $messageSource) + { + if (!$messageSource) + { + continue; + } + + foreach ($messageSource->read() as $catalogue => $translations) + { + foreach ($translations as $key => $values) + { + $this->currentMessages[] = $key; + } + } + } + } + + /** + * Extracts i18n strings from PHP files. + * + * @param string The PHP full path name + */ + protected function extractFromPhpFiles($dir) + { + $phpExtractor = new sfI18nPhpExtractor(); + + $files = sfFinder::type('file')->name('*.php'); + $messages = array(); + foreach ($files->in($dir) as $file) + { + $message = $phpExtractor->extract(file_get_contents($file)); + $messages = array_merge($messages, $message); + + foreach ($message as $amessage) + { + $_SESSION['messageLocations'][] = array('message' => $amessage, 'file' => $file); + } + } + + $this->updateMessages($messages); + } + + /** + * Updates the internal arrays with new messages. + * + * @param array An array of new i18n strings + */ + protected function updateMessages($messages) + { + $this->allSeenMessages = array_unique(array_merge($this->allSeenMessages, $messages)); + } +} diff --git a/plugins/sfI18nExtractPlugin/lib/sfI18nExtractorInterface.class.php b/plugins/sfI18nExtractPlugin/lib/sfI18nExtractorInterface.class.php new file mode 100644 index 0000000..37736ad --- /dev/null +++ b/plugins/sfI18nExtractPlugin/lib/sfI18nExtractorInterface.class.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage i18n + * @author Fabien Potencier + * @version SVN: $Id: sfI18nExtractorInterface.class.php 4362 2007-06-25 13:01:55Z fabien $ + */ +interface sfI18nExtractorInterface +{ + /** + * Extract i18n strings for the given content. + * + * @param string The content + * + * @return array An array of i18n strings + */ + public function extract($content); +} diff --git a/plugins/sfI18nExtractPlugin/lib/sfI18nModuleExtract.class.php b/plugins/sfI18nExtractPlugin/lib/sfI18nModuleExtract.class.php new file mode 100644 index 0000000..f640d12 --- /dev/null +++ b/plugins/sfI18nExtractPlugin/lib/sfI18nModuleExtract.class.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage i18n + * @author Fabien Potencier + * @version SVN: $Id: sfI18nModuleExtract.class.php 4362 2007-06-25 13:01:55Z fabien $ + */ +class sfI18nModuleExtract extends sfI18nExtract +{ + protected $module = ''; + + /** + * Configures the current extract object. + */ + public function configure() + { + if (!isset($this->parameters['module'])) + { + throw new sfException('You must give a "module" parameter when extracting for a module.'); + } + + $this->module = $this->parameters['module']; + + $this->i18n->setMessageSourceDir(sfLoader::getI18NDir($this->module), $this->culture); + } + + /** + * Extracts i18n strings. + * + * This class must be implemented by subclasses. + */ + public function extract() + { + // Extract from PHP files to find __() calls in actions/ lib/ and templates/ directories + $moduleDir = sfConfig::get('sf_app_module_dir').'/'.$this->module; + $this->extractFromPhpFiles(array( + $moduleDir.'/'.sfConfig::get('sf_app_module_action_dir_name'), + $moduleDir.'/'.sfConfig::get('sf_app_module_lib_dir_name'), + $moduleDir.'/'.sfConfig::get('sf_app_module_template_dir_name'), + )); + + // Extract from generator.yml files + $generator = $moduleDir.'/'.sfConfig::get('sf_app_module_config_dir_name').'/generator.yml'; + if (file_exists($generator)) + { + $yamlExtractor = new sfI18nYamlGeneratorExtractor(); + $message = $yamlExtractor->extract(file_get_contents($generator)); + foreach ($message as $amessage) + { + $_SESSION['messageLocations'][] = array('message' => $amessage, 'file' => $generator); + } + $this->updateMessages($message); + } + + // Extract from validate/*.yml files + $validateFiles = glob($moduleDir.'/'.sfConfig::get('sf_app_module_validate_dir_name').'/*.yml'); + if (is_array($validateFiles)) + { + foreach ($validateFiles as $validateFile) + { + $yamlExtractor = new sfI18nYamlValidateExtractor(); + $message = $yamlExtractor->extract(file_get_contents($validateFile)); + foreach ($message as $amessage) + { + $_SESSION['messageLocations'][] = array('message' => $amessage, 'file' => $validateFile); + } + $this->updateMessages($message); + } + } + } +} diff --git a/plugins/sfI18nExtractPlugin/lib/sfI18nPhpExtractor.class.php b/plugins/sfI18nExtractPlugin/lib/sfI18nPhpExtractor.class.php new file mode 100644 index 0000000..00868cc --- /dev/null +++ b/plugins/sfI18nExtractPlugin/lib/sfI18nPhpExtractor.class.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage i18n + * @author Fabien Potencier + * @version SVN: $Id: sfI18nPhpExtractor.class.php 4442 2007-06-27 14:47:31Z fabien $ + */ +class sfI18nPhpExtractor implements sfI18nExtractorInterface +{ + /** + * Extract i18n strings for the given content. + * + * @param string The content + * + * @return array An array of i18n strings + */ + public function extract($content) + { + $tokens = token_get_all($content); + + $strings = array(); + $i18n_function = 0; + $line = 0; + $heredoc = false; + $buffer = ''; + foreach ($tokens as $token) + { + if (is_string($token)) + { + switch ($token) + { + case '(': + if (1 == $i18n_function) + { + $i18n_function = 2; + } + + break; + default: + $i18n_function = 0; + } + } + else + { + list($id, $text) = $token; + + switch ($id) + { + case T_STRING: + if ($heredoc && 2 == $i18n_function) + { + $buffer .= $text; + } + else + { + $i18n_function = ('__' == $text || 'format_number_choice' == $text) ? 1 : 0; + } + break; + case T_WHITESPACE: + break; + case T_START_HEREDOC: + $heredoc = true; + break; + case T_END_HEREDOC: + $heredoc = false; + if ($buffer) + { + $strings[] = $buffer; + } + $i18n_function = 0; + break; + case T_CONSTANT_ENCAPSED_STRING: + if (2 == $i18n_function) + { + $delimiter = $text[0]; + $strings[] = str_replace('\\'.$delimiter, $delimiter, substr($text, 1, -1)); + } + $i18n_function = 0; + break; + default: + if ($heredoc && 2 == $i18n_function) + { + $buffer .= $text; + } + else + { + $i18n_function = 0; + } + } + } + } + + return $strings; + } +} diff --git a/plugins/sfI18nExtractPlugin/lib/sfI18nYamlExtractor.class.php b/plugins/sfI18nExtractPlugin/lib/sfI18nYamlExtractor.class.php new file mode 100644 index 0000000..69fe867 --- /dev/null +++ b/plugins/sfI18nExtractPlugin/lib/sfI18nYamlExtractor.class.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage i18n + * @author Fabien Potencier + * @version SVN: $Id: sfI18nYamlExtractor.class.php 4362 2007-06-25 13:01:55Z fabien $ + */ +abstract class sfI18nYamlExtractor implements sfI18nExtractorInterface +{ +} diff --git a/plugins/sfI18nExtractPlugin/lib/sfI18nYamlGeneratorExtractor.class.php b/plugins/sfI18nExtractPlugin/lib/sfI18nYamlGeneratorExtractor.class.php new file mode 100644 index 0000000..97b6671 --- /dev/null +++ b/plugins/sfI18nExtractPlugin/lib/sfI18nYamlGeneratorExtractor.class.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage i18n + * @author Fabien Potencier + * @version SVN: $Id: sfI18nYamlGeneratorExtractor.class.php 4362 2007-06-25 13:01:55Z fabien $ + */ +class sfI18nYamlGeneratorExtractor extends sfI18nYamlExtractor +{ + protected $strings = array(); + + /** + * Extract i18n strings for the given content. + * + * @param string The content + * + * @return array An array of i18n strings + */ + public function extract($content) + { + $this->strings = array(); + + $config = sfYaml::load($content); + + if (!isset($config['generator']['param'])) + { + return array(); + } + + $params = $config['generator']['param']; + + // titles + if (isset($params['list']['title'])) + { + $this->strings[] = $params['list']['title']; + } + + if (isset($params['edit']['title'])) + { + $this->strings[] = $params['edit']['title']; + } + + // names and help messages + if (isset($params['fields'])) + { + $this->getFromFields($params['fields']); + } + + if (isset($params['list']['fields'])) + { + $this->getFromFields($params['list']['fields']); + } + + if (isset($params['edit']['fields'])) + { + $this->getFromFields($params['edit']['fields']); + } + + // edit categories + if (isset($params['edit']['display']) && !isset($params['edit']['display'][0])) + { + foreach (array_keys($params['edit']['display']) as $string) + { + if ('NONE' == $string) + { + continue; + } + + $this->strings[] = $string; + } + } + + return $this->strings; + } + + protected function getFromFields($fields) + { + foreach ($fields as $field => $options) + { + if (isset($options['name'])) + { + $this->strings[] = $options['name']; + } + + if (isset($options['help'])) + { + $this->strings[] = $options['help']; + } + } + } +} diff --git a/plugins/sfI18nExtractPlugin/lib/sfI18nYamlValidateExtractor.class.php b/plugins/sfI18nExtractPlugin/lib/sfI18nYamlValidateExtractor.class.php new file mode 100644 index 0000000..a0fdeea --- /dev/null +++ b/plugins/sfI18nExtractPlugin/lib/sfI18nYamlValidateExtractor.class.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage i18n + * @author Fabien Potencier + * @version SVN: $Id: sfI18nYamlValidateExtractor.class.php 4374 2007-06-25 14:23:37Z fabien $ + */ +class sfI18nYamlValidateExtractor extends sfI18nYamlExtractor +{ + /** + * Extract i18n strings for the given content. + * + * @param string The content + * + * @return array An array of i18n strings + */ + public function extract($content) + { + $strings = array(); + + $config = sfYaml::load($content); + + // New validate.yml format + + // fields + if (isset($config['fields'])) + { + foreach ($config['fields'] as $field => $validation) + { + foreach ($validation as $type => $parameters) + { + if (!is_array($parameters)) + { + continue; + } + + foreach ($parameters as $key => $value) + { + if (preg_match('/(msg|error)$/', $key)) + { + $strings[] = $value; + } + } + } + } + } + + // validators + if (isset($config['validators'])) + { + foreach (array_keys($config['validators']) as $name) + { + if (!isset($config['validators'][$name]['param'])) + { + continue; + } + + foreach ($config['validators'][$name]['param'] as $key => $value) + { + if (preg_match('/(msg|error)$/', $key)) + { + $strings[] = $value; + } + } + } + } + + // Old validate.yml format + + // required messages + if (isset($config['names'])) + { + foreach ($config['names'] as $key => $value) + { + if (isset($value['required_msg'])) + { + $strings[] = $value['required_msg']; + } + } + } + + // validators + foreach ($config as $key => $value) + { + if (isset($value['param']) && isset($value['class'])) + { + foreach ($value['param'] as $key => $value) + { + if (preg_match('/(msg|error)$/', $key)) + { + $strings[] = $value; + } + } + } + } + + return $strings; + } +} diff --git a/plugins/sfModelTestPlugin/LICENSE b/plugins/sfModelTestPlugin/LICENSE new file mode 100644 index 0000000..7d7885e --- /dev/null +++ b/plugins/sfModelTestPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2007 Rob Rosenbaum + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfModelTestPlugin/README b/plugins/sfModelTestPlugin/README new file mode 100644 index 0000000..c7a0dfc --- /dev/null +++ b/plugins/sfModelTestPlugin/README @@ -0,0 +1,100 @@ += sfModelTestPlugin plugin = + +[[PageOutline]] + +The `sfModelTestPlugin` is a symfony plugin for quickly creating unit tests that require database interaction. Was "sfModelTestPlugin." + +== Features == + + * Uses a separate test database + * Automatically reloads test data before each group of tests + * Easy to install and use + * Support for Propel 1.2, Propel 1.3, and Doctrine + +== Installation == + + * Uncompress the archive + + {{{ + #!sh + cd /path/to/your/symfony/project/plugins/ + tar -xzf /path/to/sfModelTestPlugin-1.0.0.tgz + }}} + + * Create a database for testing. To load the schema, just use your existing sql + + {{{ + #!sh + mysql -u username -p myApp_test < data/sql/lib.model.schema.sql + }}} + + * Add the test database to databases.yml + + {{{ + #!yml + all: + propel: + class: sfPropelDatabase + param: + phptype: mysql + host: localhost + database: myApp + username: myUser + password: myPasswd + test: + propel: + class: sfPropelDatabase + param: + phptype: mysql + host: localhost + database: myApp_test + username: myUser + password: myPasswd + }}} + + * Create one or more YAML data files for testing, and put them in tests/fixtures (or wherever). These files are just like the test data files you might put in data/fixtures, except they will be reloaded into the test database at the beginning of every test method. (see "Usage") + + * Create your unit tests! You will need to include the following two lines at the top of your unit tests, (replacing 'myApp' with, of course, the name of your app): + + {{{ + #!php + define('SF_APP', 'myApp'); + include(dirname(__FILE__).'/../../plugins/sfModelTestPlugin/bootstrap/model-unit.php'); + }}} + +== Usage == + +Unit tests that use this plugin are almost identical in form and function to those in Ruby on Rails. A unit test file will look like this: + {{{ + #!php + define('SF_APP', 'myApp'); + include(dirname(__FILE__).'/../../plugins/sfModelTestPlugin/bootstrap/model-unit.php'); + + class myUnitTest extends sfPropelTest + { + public function test_user() + { + $user = new User(); + $user->setFirstName('Joe'); + $user->setLastName('Smith'); + $user->setUsername('bobbyjoe'); + $user->save(); + + $joe = UserPeer::getBy(UserPeer::USERNAME, 'bobbyjoe'); + $this->ok($joe, 'Joe exists!'); + } + + public function test_dataDelete() + { + $joe = UserPeer::getBy(UserPeer::USERNAME, 'bobbyjoe'); + $this->ok(!$joe, 'Joe no longer exists.'); + } + } + + $test = new myUnitTest('/path/to/data.yml'); + $test->execute(); + }}} + +Above, sfPropelTest extends an abstract class called sfModelTest, which itself extends lime_test. sfDoctrineTest and sfPropel13Test are also bundled with the plugin. Each unit test is a class that extends one of these. If you are familiar with Rails, the above should look familiar. If not, here is the quick summary: +For every test case, you write a class; every class method that begins with "test_" gets called in turn; before each test method is called, the data is reloaded and the setup() method is called (if you defined one); after each test method is called, the teardown() method is called (if you defined one). +All the test functions available from lime are methods of your class, so call them with $this. The argument to the constructor tells the test where to find the test data. It can be a file, a directory (all YAML files in the directory will be loaded) or nothing (all YAML files in "test/fixtures" will be loaded.) diff --git a/plugins/sfModelTestPlugin/bootstrap/model-unit.php b/plugins/sfModelTestPlugin/bootstrap/model-unit.php new file mode 100644 index 0000000..c5d1147 --- /dev/null +++ b/plugins/sfModelTestPlugin/bootstrap/model-unit.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!@constant('SF_APP')) { + die ('Constant "SF_APP" must be defined in your test script.'."\n"); +} + +if (!@constant('SF_ENVIRONMENT')) { // Only load constants in not done before (group tests) + define('SF_ENVIRONMENT', 'test'); + define('SF_DEBUG', TRUE); + define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/../../..')); + + // symfony directories + require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'); + + $databaseManager = new sfDatabaseManager(); + $databaseManager->initialize(); + + require_once($sf_symfony_lib_dir.'/vendor/lime/lime.php'); + require_once(dirname(__FILE__).'/../lib/sfModelTest.php'); +} diff --git a/plugins/sfModelTestPlugin/lib/sfModelTest.php b/plugins/sfModelTestPlugin/lib/sfModelTest.php new file mode 100644 index 0000000..2bae470 --- /dev/null +++ b/plugins/sfModelTestPlugin/lib/sfModelTest.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +abstract class sfModelTest extends lime_test +{ + protected $testDataDir; + + public function __construct($fixturesFileOrDir = null) + { + if ($fixturesFileOrDir === null) { + $this->testDataDir = SF_ROOT_DIR . '/test/fixtures'; + } else if (file_exists($fixturesFileOrDir)) { + $this->testDataDir = $fixturesFileOrDir; + } else { + throw new RuntimeException($fixturesFileOrDir.': No such file or directory'); + } + + if (!is_readable($this->testDataDir)) { + throw new RuntimeException($this->testDataDir.': Could not read file or directory'); + } + + parent::__construct(null, new lime_output_color()); + } + + public function execute() + { + $reflection = new ReflectionClass(get_class($this)); + + $this->diag($reflection); + foreach ($reflection->getMethods() as $method) { + if ($method->isPublic() && 0 === strpos($method->getName(), 'test_')) { + $this->loadData(); + $this->setup(); + + try { + $method->invoke($this); + } catch (Exception $e) { + $this->output->red_bar('Uncaught exception: '.$e->getMessage()); + return false; + } + + $this->teardown(); + } + } + } + + public function loadData() + { + $ormDataClass = $this->getORMDataClass(); + + $sfData = new $ormDataClass(); + $sfData->setDeleteCurrentData(true); + $sfData->loadData($this->testDataDir); + } + + abstract public function getORMDataClass(); + + /* + * These are for child classes to override + */ + public function setup() + { + } + + public function teardown() + { + } +} + +class sfPropelTest extends sfModelTest +{ + public function getORMDataClass() + { + return 'sfPropelData'; + } +} + +class sfDoctrineTest extends sfModelTest +{ + public function getORMDataClass() + { + return 'sfDoctrineData'; + } +} + +class sfPropel13Test extends sfModelTest +{ + public function getORMDataClass() + { + return 'sfPropel13Data'; + } +} + diff --git a/plugins/sfPagerNavigationPlugin-1.2.0/LICENSE b/plugins/sfPagerNavigationPlugin-1.2.0/LICENSE new file mode 100644 index 0000000..3d5945e --- /dev/null +++ b/plugins/sfPagerNavigationPlugin-1.2.0/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2004-2007 Francois Zaninotto + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfPagerNavigationPlugin-1.2.0/README b/plugins/sfPagerNavigationPlugin-1.2.0/README new file mode 100644 index 0000000..6a85cab --- /dev/null +++ b/plugins/sfPagerNavigationPlugin-1.2.0/README @@ -0,0 +1,43 @@ += sfPagerNavigation plugin = + +== Overview == + +This plugin adds a new helper group, `PagerNavigation`, with three new helpers. They add interface controls for paginated lists, either with links to pages or with AJAX ([http://www.symfony-project.com/demo/pager.html online demo]) + +== Installation == + +To install sfPagerNavigationPlugin, type: + +{{{ +$ symfony plugin-install http://plugins.symfony-project.com/sfPagerNavigationPlugin +}}} + +== Usage == + +=== Regular pager === + +{{{ + + + +}}} + +=== Ajax pager === + +{{{ + + + 'pager/ajaxPager', + 'update' => 'ajax_pager', +), $pager) ?> + + +}}} + +== License == + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. diff --git a/plugins/sfPagerNavigationPlugin-1.2.0/lib/helper/PagerNavigationHelper.php b/plugins/sfPagerNavigationPlugin-1.2.0/lib/helper/PagerNavigationHelper.php new file mode 100644 index 0000000..8502ab6 --- /dev/null +++ b/plugins/sfPagerNavigationPlugin-1.2.0/lib/helper/PagerNavigationHelper.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package sfPagerNavigation + * @author Francois Zaninotto + * @version SVN: $Id$ + */ + + +/** + * Includes an AJAX navigation. + * If you provide a sfPager object, the helper automatically stops the periodical call + * wen reaching the last page + * + * Options: + * - url - 'module/action' or '@rule' of the AJAX action + * - update - id of the paginated list + * - page_name - name of the page request parameter, defaults to 'name' + * - frequency - number of seconds between each position check, defaults to 1 second + * - trigger - height in pixels, calculated from the bottom of the page, which triggers the AJAX call + * ...as well as the usual remote_ helpers options + * + * @param array Ajax options + * @param object optional sfPager object of the current pager + * @return string XHTML code containing links + */ +function remote_pager($options = array(), $pager = null) +{ + if($pager && ($pager->getNextPage() == $pager->getPage() || $pager->getPage()!= 1)) + { + return; + } + + // name of the page request parameter (default 'page') + $options['page_name'] = isset($options['page_name']) ? $options['page_name'] : 'page'; + + // frequency of the scroll check (default 1 second) + $options['frequency'] = isset($options['frequency']) ? $options['frequency'] : 1; + + // scroll offset (in pixels, from the bottom) triggering the remote call (default 30px) + $options['trigger'] = isset($options['trigger']) ? $options['trigger'] : '30'; + + $options['position'] = isset($options['position']) ? $options['position'] : 'before'; + + use_helper('Javascript'); + + sfContext::getInstance()->getResponse()->addJavascript('/sf/js/prototype/prototype'); + + $javascript_callback = 'ajax_pager_semaphore = 0; ajax_pager_page++;'; + if($pager) + { + // build in the stop of the PeriodicalExecuter when the pager reaches the last page + $javascript_callback .= 'if(ajax_pager_page>'.$pager->getLastPage().') { pager_watch.callback = function () {}; };'; + } + $options['success'] = isset($options['success']) ? $options['success'].$javascript_callback : $javascript_callback; + + return javascript_tag(" + var ajax_pager_semaphore = 0; + var ajax_pager_page = 2; + + function sf_ajax_next_page() + { + if (ajax_pager_semaphore == 0) + { + ajax_pager_semaphore = 1; + new Ajax.Updater( + '".$options['update']."', + '".url_for($options['url']).'?'.$options['page_name']."='+ajax_pager_page, + "._options_for_ajax($options)." + ); + } + } + + pager_watch = new PeriodicalExecuter(function() + { + var scrollpos = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop; + var windowsize = window.innerHeight || document.documentElement.clientHeight; + var testend = document.body.clientHeight - (windowsize + scrollpos); + + if ( (testend < ".$options['trigger'].") ) + { + sf_ajax_next_page(); + } + }, ".$options['frequency'].");"); + +} + +function stop_remote_pager() +{ + use_helper('Javascript'); + + // until prototype implements a stop() method for the PeriodicalExecuter, + // the following (almost a hack) is the only simple way to stop it + + return javascript_tag("pager_watch.callback = function () {};"); +} + +/** + * Outputs a regular navigation navigation. + * It outputs a series of links to the first, previous, next and last page + * as well as to the 5 pages surrounding the current page. + * + * @param object sfPager object of the current pager + * @param string 'module/action' or '@rule' of the paginated action + * @return string XHTML code containing links + */ +function pager_navigation($pager, $uri) +{ + $navigation = ''; + + if ($pager->haveToPaginate()) + { + $uri .= (preg_match('/\?/', $uri) ? '&' : '?').'page='; + + // First and previous page + if ($pager->getPage() != 1) + { + $navigation .= link_to(image_tag('/sf/images/sf_admin/first.png', 'align=absmiddle'), $uri.'1'); + $navigation .= link_to(image_tag('/sf/images/sf_admin/previous.png', 'align=absmiddle'), $uri.$pager->getPreviousPage()).' '; + } + + // Pages one by one + $links = array(); + foreach ($pager->getLinks() as $page) + { + $links[] = link_to_unless($page == $pager->getPage(), $page, $uri.$page); + } + $navigation .= join('  ', $links); + + // Next and last page + if ($pager->getPage() != $pager->getLastPage()) + { + $navigation .= ' '.link_to(image_tag('/sf/images/sf_admin/next.png', 'align=absmiddle'), $uri.$pager->getNextPage()); + $navigation .= link_to(image_tag('/sf/images/sf_admin/last.png', 'align=absmiddle'), $uri.$pager->getLastPage()); + } + + } + + return $navigation; +} + + ?> \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/LICENSE b/plugins/sfPropelActAsCommentableBehaviorPlugin/LICENSE new file mode 100644 index 0000000..7dbcbb9 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2007 Xavier Lacot + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/README b/plugins/sfPropelActAsCommentableBehaviorPlugin/README new file mode 100644 index 0000000..b6fc5e8 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/README @@ -0,0 +1,413 @@ += sfPropelActAsCommentableBehaviorPlugin = + +== Introduction == +This behavior permits to attach comments to Propel objects. It provides a +module for enabling comments in your application in less than 3 minutes. + +== Features == + + * add/remove comment(s) on an object + * unit-tested + * comment module, with ajax support and layout customization + * comment namespaces (separate comments for the front-office and the + back-office, for instance) + * comment admin-module + +== Screenshots == +[[Image(sfPropelActAsCommentableBehaviorPlugin_comment_1.png, 25%)]] +[[Image(sfPropelActAsCommentableBehaviorPlugin_comment_2.png, 25%)]] +[[Image(sfPropelActAsCommentableBehaviorPlugin_comment_3.png, 25%)]] + + +== Philosophy of the stuff == + + * commentable objects must have a primary key + * comments can only be attached on objects that have already been saved + * comments are saved when applied + +== Get it installed == + + * go to your project's root + + * Install the plugin: + {{{ + ./symfony plugin-install http://plugins.symfony-project.com/sfPropelActAsCommentableBehaviorPlugin + }}} + + * if not already done, enabled behaviors in config/propel.ini: + {{{ + propel.builder.addBehaviors = true + }}} + + * edit the classes that you want to make taggable. For instance, for lib/model/Post.php: + {{{ + #!php + getTitle(); ?> + +

    getText(); ?>

    + +

    Comments

    + $post)); +include_component('sfComment', 'commentForm', array('object' => $post)); +?> +}}} + +By default, the comment list displays all the comments that do not belong to +one namespace. If you want to display comments for the namespace "gerard", then +simply pass this optionnal parameter to the component: + +{{{ +#!php + $post, 'namespace' => 'gerard')); +?> +}}} + +This also works for the comment-form component. This way, the following form +will add the comment to the namespace "gerard": +{{{ +#!php + $post, 'namespace' => 'gerard')); +?> +}}} + +You can protect namespaces from being accessed when the current user does not +have some credentials ; have a look at [#Optionalsettings the configuration file] +for further informations. + +=== Attaching comments to a commentable object === +Consider a Propel "Post" class: + +{{{ +#!php +save(); +$post->addComment('This is a cool comment.'); +$post->addComment(array('title' => 'this is a cool title', 'text' => 'this is a cool comment', 'author_id' => sfContext::getInstance()->getUser()->getUserId())); +$post->addComment(array('This is a cool comment.', 'this is one other comment')); +}}} + +=== Retrieving one object's comments === +It is possible to retrieve comments from a commentable object: +{{{ +#!php +getComments(); + +foreach ($comments as $comment) +{ + echo '

    '.$comment->getText().'

    '; +} +}}} + +=== Removing one object's comment === +Of course, comments can also be removed: +{{{ +#!php +removeComment(12); +$post->clearComments(); +}}} + +== API == +The behavior implement the following methods: + * '''addComment($comment)''' - Adds a comment to the object. The "comment" + param can be an associative array (in which each element represents one of the + comment properties), or an array of associative arrays. In this case, it adds + all the comments to the object. + * '''clearComments()''' - Deletes all the comments attached to the object + * '''getComments($options = array())''' - Returns the list of the comments + attached to the object. The options array can contain several options + * '''getNbComments()''' - Returns the number of the comments attached to the + object. + * '''removeComment($comment_id)''' - Removes one comment from the object. + +== Unit testing == +The plugin has been deeply unit-tested. The tests are located in test/unit/sfPropelActAsCommentableBehaviorTest.php. If you want to run them: + * install the plugin + * configure a model for using it, for instance "Post" + * edit this file and, if required, modify the application name and the TEST_CLASS constant, line 3: + {{{ + define('TEST_CLASS', 'Post'); + }}} + * run the tests: + {{{ + php plugins/sfPropelActAsCommentableBehaviorPlugin/test/unit/sfPropelActAsCommentableBehaviorTest.php + }}} + +== In-depth usage tutorial == +This part is a complete tutorial for using the plugin both in front and +back-office. + +=== Install the plugin === + * go to your project's root + + * Install the plugin: + {{{ + ./symfony plugin-install http://plugins.symfony-project.com/sfPropelActAsCommentableBehaviorPlugin + }}} + + * if not already done, enabled behaviors in config/propel.ini: + {{{ + propel.builder.addBehaviors = true + }}} + + * edit the classes that you want to make taggable. For instance, for lib/model/Post.php: + {{{ + #!php + getTitle(); ?> + +

    getText(); ?>

    + +

    Comments

    + $post, 'namespace' => 'frontend')); +include_component('sfComment', 'commentForm', array('object' => $post, 'namespace' => 'frontend')); +?> +}}} +The use of a "namespace" is not required in this case; but it is advised, as it +makes it easier to find the comments back. + +=== Add comments in back-office === +Include the sfComment components where the comments and the commentform shoumd appear: +{{{ +#!php + $post, 'namespace' => 'backend')); +include_component('sfComment', 'commentForm', array('object' => $post, 'namespace' => 'backend')); +?> +}}} + + * you're done! Only users with "administrator" credential are able to add + comments to objects in the back-office, while everyone can add comments in the + front-office. You can tweak the required credentials by modifying the app.yml + file. + +=== Comments administration === + * optionnaly, have a look at the sfCommentAdmin module, that uses the + admin-generator for providing a view of all comments. + +== License and credits == +This plugin is licensed under the MIT license. You can contact the maintainer +at [http://lacot.org/ xavier@lacot.org] + +== Changelog == + +=== Version 0.4 - 2007-12-10 === + * compatibility with escaping=both mode + * Added unique DOM id for each comment, in the form {{{sf_comment_$id}}} + (Nicolas Perriault) + * use a session token instead of passing the object id and model in the request + (Nicolas Perriault) + * bugfixes, based on a patch from Michael Nolan (closes #2595): + * fix anonymous posting (use the token) + * pre and post addition hooks + +=== version 0.3 - 2007-10-08 === + * added namespaces support + * fixed bad index names (thanks to francois) + * made getComments() more flexible (closes #2312, thanks to FrankStelzer) + +=== version 0.2 - 2007-09-26 === + * added a Symfony module for posting and displaying comments + * ajax support + * authenticated users support + * form customization + * added an administration module + +=== version 0.1 - 2007-09-13 === +Initial public release. Features comments attachment to heterogene Propel +objects. + +== Roadmap / Wishlist == + * have custom configurations for specific comment-forms (and not only app-wide + configurations) + * make use of a captcha plugin, when a clean one will be available. + * handle other custom fields in comments. \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/config/app.yml.sample b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/app.yml.sample new file mode 100644 index 0000000..26fceaa --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/app.yml.sample @@ -0,0 +1,25 @@ +all: + sfPropelActAsCommentableBehaviorPlugin: + anonymous: + enabled: true + layout: + name: required + email: required + title: optional + comment: required + name: Anonymous User + user: + enabled: true + layout: + title: optional + comment: required + table: sf_guard_user + id: id + class: sfGuardUser + id_method: getId + toString: __toString + save_name: false + namespaces: + frontend: - + backend: administrator + use_ajax: true \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/config/config.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/config.php new file mode 100644 index 0000000..bb88307 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/config.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +if (in_array('sfComment', sfConfig::get('sf_enabled_modules', array()))) +{ + $r = sfRouting::getInstance(); + $r->prependRoute('sf_comment_authenticated', '/sfComment/authenticated_comment', array('module' => 'sfComment', 'action' => 'authenticatedComment')); + $r->prependRoute('sf_comment_anonymous', '/sfComment/anonymous_comment', array('module' => 'sfComment', 'action' => 'anonymousComment')); +} + +sfPropelBehavior::registerMethods('sfPropelActAsCommentableBehavior', array ( + array ( + 'sfPropelActAsCommentableBehavior', + 'addComment' + ), + array ( + 'sfPropelActAsCommentableBehavior', + 'clearComments' + ), + array ( + 'sfPropelActAsCommentableBehavior', + 'getComments' + ), + array ( + 'sfPropelActAsCommentableBehavior', + 'getNbComments' + ), + array ( + 'sfPropelActAsCommentableBehavior', + 'removeComment' + ) +)); \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/config/schema.yml b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/schema.yml new file mode 100644 index 0000000..d2fd57c --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/schema.yml @@ -0,0 +1,27 @@ + +: + _attributes: { package: plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model } + + # a comment applies to one Propel object + # a comment is defined by : + # - a title + # - a text + # - an author (set the related user model in app.yml) + # - a creation date + sf_comment: + _attributes: { phpName: sfComment, package: plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model } + id: { phpName: Id, type: integer, required: true, primaryKey: true, autoincrement: true } + parent_id: integer + commentable_model: varchar(30) + commentable_id: integer + namespace: varchar(50) + title: varchar(100) + text: longvarchar + author_id: integer + author_name: varchar(50) + author_email: varchar(100) + created_at: + _indexes: + comments_index: [namespace, commentable_model, commentable_id] + object_index: [commentable_model, commentable_id] + author_index: [author_id] \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/config/schemaConfig.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/schemaConfig.php new file mode 100644 index 0000000..c7a6e5b --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/schemaConfig.php @@ -0,0 +1,16 @@ + 'propel' +); + +// Check custom project values in my_project/config/sfCommentPlugin.yml +if(is_readable($config_file = sfConfig::get('sf_config_dir').'/sfPropelActAsCommentableBehaviorPlugin.yml')) +{ + $user_config = sfYaml::load($config_file); + if(isset($user_config['schema'])) + { + $config = array_merge($config, $user_config['schema']); + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/config/sfPropelActAsCommentableBehaviorPlugin.yml.sample b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/sfPropelActAsCommentableBehaviorPlugin.yml.sample new file mode 100644 index 0000000..9e4f054 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/config/sfPropelActAsCommentableBehaviorPlugin.yml.sample @@ -0,0 +1,6 @@ +schema: + connection: propel + user_table: sf_guard_user + user_id: id + user_class: sfGuardUser + comment_table: sf_comment \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/map/sfCommentMapBuilder.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/map/sfCommentMapBuilder.php new file mode 100644 index 0000000..ff5da74 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/map/sfCommentMapBuilder.php @@ -0,0 +1,62 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_comment'); + $tMap->setPhpName('sfComment'); + + $tMap->setUseIdGenerator(true); + + $tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('PARENT_ID', 'ParentId', 'int', CreoleTypes::INTEGER, false, null); + + $tMap->addColumn('COMMENTABLE_MODEL', 'CommentableModel', 'string', CreoleTypes::VARCHAR, false, 30); + + $tMap->addColumn('COMMENTABLE_ID', 'CommentableId', 'int', CreoleTypes::INTEGER, false, null); + + $tMap->addColumn('NAMESPACE', 'Namespace', 'string', CreoleTypes::VARCHAR, false, 50); + + $tMap->addColumn('TITLE', 'Title', 'string', CreoleTypes::LONGVARCHAR, false, null); + + $tMap->addColumn('TEXT', 'Text', 'string', CreoleTypes::LONGVARCHAR, false, null); + + $tMap->addForeignKey('AUTHOR_ID', 'AuthorId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null); + + $tMap->addColumn('AUTHOR_NAME', 'AuthorName', 'string', CreoleTypes::VARCHAR, false, 50); + + $tMap->addColumn('AUTHOR_EMAIL', 'AuthorEmail', 'string', CreoleTypes::VARCHAR, false, 100); + + $tMap->addColumn('CREATED_AT', 'CreatedAt', 'int', CreoleTypes::TIMESTAMP, false, null); + + $tMap->addColumn('UNSUITABLE', 'Unsuitable', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('EMAIL_NOTIFY', 'EmailNotify', 'int', CreoleTypes::INTEGER, true, null); + + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfComment.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfComment.php new file mode 100644 index 0000000..76df346 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfComment.php @@ -0,0 +1,884 @@ +id; + } + + + public function getParentId() + { + + return $this->parent_id; + } + + + public function getCommentableModel() + { + + return $this->commentable_model; + } + + + public function getCommentableId() + { + + return $this->commentable_id; + } + + + public function getNamespace() + { + + return $this->namespace; + } + + + public function getTitle() + { + + return $this->title; + } + + + public function getText() + { + + return $this->text; + } + + + public function getAuthorId() + { + + return $this->author_id; + } + + + public function getAuthorName() + { + + return $this->author_name; + } + + + public function getAuthorEmail() + { + + return $this->author_email; + } + + + public function getCreatedAt($format = 'Y-m-d H:i:s') + { + + if ($this->created_at === null || $this->created_at === '') { + return null; + } elseif (!is_int($this->created_at)) { + $ts = strtotime($this->created_at); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [created_at] as date/time value: " . var_export($this->created_at, true)); + } + } else { + $ts = $this->created_at; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function getUnsuitable() + { + + return $this->unsuitable; + } + + + public function getEmailNotify() + { + + return $this->email_notify; + } + + + public function setId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = sfCommentPeer::ID; + } + + } + + public function setParentId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->parent_id !== $v) { + $this->parent_id = $v; + $this->modifiedColumns[] = sfCommentPeer::PARENT_ID; + } + + } + + public function setCommentableModel($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->commentable_model !== $v) { + $this->commentable_model = $v; + $this->modifiedColumns[] = sfCommentPeer::COMMENTABLE_MODEL; + } + + } + + public function setCommentableId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->commentable_id !== $v) { + $this->commentable_id = $v; + $this->modifiedColumns[] = sfCommentPeer::COMMENTABLE_ID; + } + + } + + public function setNamespace($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->namespace !== $v) { + $this->namespace = $v; + $this->modifiedColumns[] = sfCommentPeer::NAMESPACE; + } + + } + + public function setTitle($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->title !== $v) { + $this->title = $v; + $this->modifiedColumns[] = sfCommentPeer::TITLE; + } + + } + + public function setText($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->text !== $v) { + $this->text = $v; + $this->modifiedColumns[] = sfCommentPeer::TEXT; + } + + } + + public function setAuthorId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->author_id !== $v) { + $this->author_id = $v; + $this->modifiedColumns[] = sfCommentPeer::AUTHOR_ID; + } + + if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) { + $this->asfGuardUser = null; + } + + } + + public function setAuthorName($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->author_name !== $v) { + $this->author_name = $v; + $this->modifiedColumns[] = sfCommentPeer::AUTHOR_NAME; + } + + } + + public function setAuthorEmail($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->author_email !== $v) { + $this->author_email = $v; + $this->modifiedColumns[] = sfCommentPeer::AUTHOR_EMAIL; + } + + } + + public function setCreatedAt($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [created_at] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->created_at !== $ts) { + $this->created_at = $ts; + $this->modifiedColumns[] = sfCommentPeer::CREATED_AT; + } + + } + + public function setUnsuitable($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->unsuitable !== $v || $v === 0) { + $this->unsuitable = $v; + $this->modifiedColumns[] = sfCommentPeer::UNSUITABLE; + } + + } + + public function setEmailNotify($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->email_notify !== $v || $v === 0) { + $this->email_notify = $v; + $this->modifiedColumns[] = sfCommentPeer::EMAIL_NOTIFY; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->id = $rs->getInt($startcol + 0); + + $this->parent_id = $rs->getInt($startcol + 1); + + $this->commentable_model = $rs->getString($startcol + 2); + + $this->commentable_id = $rs->getInt($startcol + 3); + + $this->namespace = $rs->getString($startcol + 4); + + $this->title = $rs->getString($startcol + 5); + + $this->text = $rs->getString($startcol + 6); + + $this->author_id = $rs->getInt($startcol + 7); + + $this->author_name = $rs->getString($startcol + 8); + + $this->author_email = $rs->getString($startcol + 9); + + $this->created_at = $rs->getTimestamp($startcol + 10, null); + + $this->unsuitable = $rs->getInt($startcol + 11); + + $this->email_notify = $rs->getInt($startcol + 12); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 13; + } catch (Exception $e) { + throw new PropelException("Error populating sfComment object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfComment:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfCommentPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfCommentPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfComment:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfComment:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isNew() && !$this->isColumnModified(sfCommentPeer::CREATED_AT)) + { + $this->setCreatedAt(time()); + } + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfCommentPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfComment:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->asfGuardUser !== null) { + if ($this->asfGuardUser->isModified()) { + $affectedRows += $this->asfGuardUser->save($con); + } + $this->setsfGuardUser($this->asfGuardUser); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfCommentPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setId($pk); + $this->setNew(false); + } else { + $affectedRows += sfCommentPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->asfGuardUser !== null) { + if (!$this->asfGuardUser->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures()); + } + } + + + if (($retval = sfCommentPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfCommentPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getParentId(); + break; + case 2: + return $this->getCommentableModel(); + break; + case 3: + return $this->getCommentableId(); + break; + case 4: + return $this->getNamespace(); + break; + case 5: + return $this->getTitle(); + break; + case 6: + return $this->getText(); + break; + case 7: + return $this->getAuthorId(); + break; + case 8: + return $this->getAuthorName(); + break; + case 9: + return $this->getAuthorEmail(); + break; + case 10: + return $this->getCreatedAt(); + break; + case 11: + return $this->getUnsuitable(); + break; + case 12: + return $this->getEmailNotify(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfCommentPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getParentId(), + $keys[2] => $this->getCommentableModel(), + $keys[3] => $this->getCommentableId(), + $keys[4] => $this->getNamespace(), + $keys[5] => $this->getTitle(), + $keys[6] => $this->getText(), + $keys[7] => $this->getAuthorId(), + $keys[8] => $this->getAuthorName(), + $keys[9] => $this->getAuthorEmail(), + $keys[10] => $this->getCreatedAt(), + $keys[11] => $this->getUnsuitable(), + $keys[12] => $this->getEmailNotify(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfCommentPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setParentId($value); + break; + case 2: + $this->setCommentableModel($value); + break; + case 3: + $this->setCommentableId($value); + break; + case 4: + $this->setNamespace($value); + break; + case 5: + $this->setTitle($value); + break; + case 6: + $this->setText($value); + break; + case 7: + $this->setAuthorId($value); + break; + case 8: + $this->setAuthorName($value); + break; + case 9: + $this->setAuthorEmail($value); + break; + case 10: + $this->setCreatedAt($value); + break; + case 11: + $this->setUnsuitable($value); + break; + case 12: + $this->setEmailNotify($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfCommentPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setParentId($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setCommentableModel($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setCommentableId($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setNamespace($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setTitle($arr[$keys[5]]); + if (array_key_exists($keys[6], $arr)) $this->setText($arr[$keys[6]]); + if (array_key_exists($keys[7], $arr)) $this->setAuthorId($arr[$keys[7]]); + if (array_key_exists($keys[8], $arr)) $this->setAuthorName($arr[$keys[8]]); + if (array_key_exists($keys[9], $arr)) $this->setAuthorEmail($arr[$keys[9]]); + if (array_key_exists($keys[10], $arr)) $this->setCreatedAt($arr[$keys[10]]); + if (array_key_exists($keys[11], $arr)) $this->setUnsuitable($arr[$keys[11]]); + if (array_key_exists($keys[12], $arr)) $this->setEmailNotify($arr[$keys[12]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfCommentPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfCommentPeer::ID)) $criteria->add(sfCommentPeer::ID, $this->id); + if ($this->isColumnModified(sfCommentPeer::PARENT_ID)) $criteria->add(sfCommentPeer::PARENT_ID, $this->parent_id); + if ($this->isColumnModified(sfCommentPeer::COMMENTABLE_MODEL)) $criteria->add(sfCommentPeer::COMMENTABLE_MODEL, $this->commentable_model); + if ($this->isColumnModified(sfCommentPeer::COMMENTABLE_ID)) $criteria->add(sfCommentPeer::COMMENTABLE_ID, $this->commentable_id); + if ($this->isColumnModified(sfCommentPeer::NAMESPACE)) $criteria->add(sfCommentPeer::NAMESPACE, $this->namespace); + if ($this->isColumnModified(sfCommentPeer::TITLE)) $criteria->add(sfCommentPeer::TITLE, $this->title); + if ($this->isColumnModified(sfCommentPeer::TEXT)) $criteria->add(sfCommentPeer::TEXT, $this->text); + if ($this->isColumnModified(sfCommentPeer::AUTHOR_ID)) $criteria->add(sfCommentPeer::AUTHOR_ID, $this->author_id); + if ($this->isColumnModified(sfCommentPeer::AUTHOR_NAME)) $criteria->add(sfCommentPeer::AUTHOR_NAME, $this->author_name); + if ($this->isColumnModified(sfCommentPeer::AUTHOR_EMAIL)) $criteria->add(sfCommentPeer::AUTHOR_EMAIL, $this->author_email); + if ($this->isColumnModified(sfCommentPeer::CREATED_AT)) $criteria->add(sfCommentPeer::CREATED_AT, $this->created_at); + if ($this->isColumnModified(sfCommentPeer::UNSUITABLE)) $criteria->add(sfCommentPeer::UNSUITABLE, $this->unsuitable); + if ($this->isColumnModified(sfCommentPeer::EMAIL_NOTIFY)) $criteria->add(sfCommentPeer::EMAIL_NOTIFY, $this->email_notify); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfCommentPeer::DATABASE_NAME); + + $criteria->add(sfCommentPeer::ID, $this->id); + + return $criteria; + } + + + public function getPrimaryKey() + { + return $this->getId(); + } + + + public function setPrimaryKey($key) + { + $this->setId($key); + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setParentId($this->parent_id); + + $copyObj->setCommentableModel($this->commentable_model); + + $copyObj->setCommentableId($this->commentable_id); + + $copyObj->setNamespace($this->namespace); + + $copyObj->setTitle($this->title); + + $copyObj->setText($this->text); + + $copyObj->setAuthorId($this->author_id); + + $copyObj->setAuthorName($this->author_name); + + $copyObj->setAuthorEmail($this->author_email); + + $copyObj->setCreatedAt($this->created_at); + + $copyObj->setUnsuitable($this->unsuitable); + + $copyObj->setEmailNotify($this->email_notify); + + + $copyObj->setNew(true); + + $copyObj->setId(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfCommentPeer(); + } + return self::$peer; + } + + + public function setsfGuardUser($v) + { + + + if ($v === null) { + $this->setAuthorId(NULL); + } else { + $this->setAuthorId($v->getId()); + } + + + $this->asfGuardUser = $v; + } + + + + public function getsfGuardUser($con = null) + { + if ($this->asfGuardUser === null && ($this->author_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php'; + + $this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->author_id, $con); + + + } + return $this->asfGuardUser; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfComment:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfComment::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfCommentPeer.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfCommentPeer.php new file mode 100644 index 0000000..47f6956 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/om/BasesfCommentPeer.php @@ -0,0 +1,627 @@ + array ('Id', 'ParentId', 'CommentableModel', 'CommentableId', 'Namespace', 'Title', 'Text', 'AuthorId', 'AuthorName', 'AuthorEmail', 'CreatedAt', 'Unsuitable', 'EmailNotify', ), + BasePeer::TYPE_COLNAME => array (sfCommentPeer::ID, sfCommentPeer::PARENT_ID, sfCommentPeer::COMMENTABLE_MODEL, sfCommentPeer::COMMENTABLE_ID, sfCommentPeer::NAMESPACE, sfCommentPeer::TITLE, sfCommentPeer::TEXT, sfCommentPeer::AUTHOR_ID, sfCommentPeer::AUTHOR_NAME, sfCommentPeer::AUTHOR_EMAIL, sfCommentPeer::CREATED_AT, sfCommentPeer::UNSUITABLE, sfCommentPeer::EMAIL_NOTIFY, ), + BasePeer::TYPE_FIELDNAME => array ('id', 'parent_id', 'commentable_model', 'commentable_id', 'namespace', 'title', 'text', 'author_id', 'author_name', 'author_email', 'created_at', 'unsuitable', 'email_notify', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'ParentId' => 1, 'CommentableModel' => 2, 'CommentableId' => 3, 'Namespace' => 4, 'Title' => 5, 'Text' => 6, 'AuthorId' => 7, 'AuthorName' => 8, 'AuthorEmail' => 9, 'CreatedAt' => 10, 'Unsuitable' => 11, 'EmailNotify' => 12, ), + BasePeer::TYPE_COLNAME => array (sfCommentPeer::ID => 0, sfCommentPeer::PARENT_ID => 1, sfCommentPeer::COMMENTABLE_MODEL => 2, sfCommentPeer::COMMENTABLE_ID => 3, sfCommentPeer::NAMESPACE => 4, sfCommentPeer::TITLE => 5, sfCommentPeer::TEXT => 6, sfCommentPeer::AUTHOR_ID => 7, sfCommentPeer::AUTHOR_NAME => 8, sfCommentPeer::AUTHOR_EMAIL => 9, sfCommentPeer::CREATED_AT => 10, sfCommentPeer::UNSUITABLE => 11, sfCommentPeer::EMAIL_NOTIFY => 12, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'parent_id' => 1, 'commentable_model' => 2, 'commentable_id' => 3, 'namespace' => 4, 'title' => 5, 'text' => 6, 'author_id' => 7, 'author_name' => 8, 'author_email' => 9, 'created_at' => 10, 'unsuitable' => 11, 'email_notify' => 12, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/map/sfCommentMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model.map.sfCommentMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfCommentPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfCommentPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfCommentPeer::ID); + + $criteria->addSelectColumn(sfCommentPeer::PARENT_ID); + + $criteria->addSelectColumn(sfCommentPeer::COMMENTABLE_MODEL); + + $criteria->addSelectColumn(sfCommentPeer::COMMENTABLE_ID); + + $criteria->addSelectColumn(sfCommentPeer::NAMESPACE); + + $criteria->addSelectColumn(sfCommentPeer::TITLE); + + $criteria->addSelectColumn(sfCommentPeer::TEXT); + + $criteria->addSelectColumn(sfCommentPeer::AUTHOR_ID); + + $criteria->addSelectColumn(sfCommentPeer::AUTHOR_NAME); + + $criteria->addSelectColumn(sfCommentPeer::AUTHOR_EMAIL); + + $criteria->addSelectColumn(sfCommentPeer::CREATED_AT); + + $criteria->addSelectColumn(sfCommentPeer::UNSUITABLE); + + $criteria->addSelectColumn(sfCommentPeer::EMAIL_NOTIFY); + + } + + const COUNT = 'COUNT(sf_comment.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_comment.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfCommentPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfCommentPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfCommentPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfCommentPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfCommentPeer::populateObjects(sfCommentPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfCommentPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfCommentPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfCommentPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfCommentPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfCommentPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfCommentPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfCommentPeer::AUTHOR_ID, sfGuardUserPeer::ID); + + $rs = sfCommentPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfCommentPeer::addSelectColumns($c); + $startcol = (sfCommentPeer::NUM_COLUMNS - sfCommentPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardUserPeer::addSelectColumns($c); + + $c->addJoin(sfCommentPeer::AUTHOR_ID, sfGuardUserPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfCommentPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfComment($obj1); break; + } + } + if ($newObject) { + $obj2->initsfComments(); + $obj2->addsfComment($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfCommentPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfCommentPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(sfCommentPeer::AUTHOR_ID, sfGuardUserPeer::ID); + + $rs = sfCommentPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + sfCommentPeer::addSelectColumns($c); + $startcol2 = (sfCommentPeer::NUM_COLUMNS - sfCommentPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardUserPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS; + + $c->addJoin(sfCommentPeer::AUTHOR_ID, sfGuardUserPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = sfCommentPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addsfComment($obj1); break; + } + } + + if ($newObject) { + $obj2->initsfComments(); + $obj2->addsfComment($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfCommentPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfCommentPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfCommentPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + $criteria->remove(sfCommentPeer::ID); + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfCommentPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfCommentPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfCommentPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfCommentPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfCommentPeer::ID); + $selectCriteria->add(sfCommentPeer::ID, $criteria->remove(sfCommentPeer::ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfCommentPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfCommentPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(sfCommentPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfCommentPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfComment) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + $criteria->add(sfCommentPeer::ID, (array) $values, Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(sfComment $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfCommentPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfCommentPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfCommentPeer::DATABASE_NAME, sfCommentPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfCommentPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK($pk, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $criteria = new Criteria(sfCommentPeer::DATABASE_NAME); + + $criteria->add(sfCommentPeer::ID, $pk); + + + $v = sfCommentPeer::doSelect($criteria, $con); + + return !empty($v) > 0 ? $v[0] : null; + } + + + public static function retrieveByPKs($pks, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $objs = null; + if (empty($pks)) { + $objs = array(); + } else { + $criteria = new Criteria(); + $criteria->add(sfCommentPeer::ID, $pks, Criteria::IN); + $objs = sfCommentPeer::doSelect($criteria, $con); + } + return $objs; + } + +} +if (Propel::isInit()) { + try { + BasesfCommentPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/map/sfCommentMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfPropelActAsCommentableBehaviorPlugin.lib.model.map.sfCommentMapBuilder'); +} diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/sfComment.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/sfComment.php new file mode 100644 index 0000000..4217893 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/sfComment.php @@ -0,0 +1,16 @@ +username; + } +} diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/sfCommentPeer.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/sfCommentPeer.php new file mode 100644 index 0000000..89f11dd --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/model/sfCommentPeer.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* + * This behavior permits to attach comments to Propel objects. Some more bits + * about the philosophy of the stuff: + * + * - commentable objects must have a primary key + * - comments can only be attached on objects that have already been saved + * - comments are saved when applied + * + * @author Xavier Lacot + * @see http://www.symfony-project.com/trac/wiki/sfPropelActAsCommentableBehaviorPlugin + */ + +class sfPropelActAsCommentableBehavior +{ + /** + * Adds a comment to the object. The "comment" param can be an associative + * array (in which each element represents one of the comment properties), or + * an array of associative arrays. In this case, it adds all the comments to + * the object. + * + * @param BaseObject $object + * @param array $comment + */ + public function addComment(BaseObject $object, $comment) + { + if ($object->isNew() === true) + { + throw new Exception('Comments can only be attached to already saved objects'); + } + + if (is_array($comment)) + { + if (!isset($comment['text'])) + { + foreach ($comment as $onecomment) + { + $this->addComment($object, $onecomment); + } + } + else + { + if (strlen($comment['text']) > 0) + { + $comment['text'] = strip_tags($comment['text']); + $comment['created_at'] = time(); + + if (!isset($comment['namespace'])) + { + $comment['namespace'] = ''; + } + + $comment_object = new sfComment(); + $comment_object->fromArray($comment, BasePeer::TYPE_FIELDNAME); + $comment_object->setCommentableId($object->getPrimaryKey()); + $comment_object->setCommentableModel(get_class($object)); + $comment_object->save(); + return $comment_object; + } + } + } + elseif (is_string($comment)) + { + $this->addComment($object, array('text' => $comment)); + } + else + { + new Exception('A comment must be represented as string or an associative array with a "text" key'); + } + } + + /** + * Deletes all the comments attached to the object + * + * @param BaseObject $object + * @return boolean + */ + public function clearComments(BaseObject $object, $namespace = null) + { + $c = new Criteria(); + $c->add(sfCommentPeer::COMMENTABLE_ID, $object->getPrimaryKey()); + $c->add(sfCommentPeer::COMMENTABLE_MODEL, get_class($object)); + + if ($namespace != null) + { + $c->add(sfCommentPeer::NAMESPACE, $namespace); + } + + return sfCommentPeer::doDelete($c); + } + + /** + * Returns the list of the comments attached to the object. The options array + * can contain several options : + * - order : order of the comments + * + * @param BaseObject $object + * @param Array $options + * @param Criteria $criteria + * + * @return Array + */ + public function getComments(BaseObject $object, $options = array(), Criteria $criteria = null) + { + $c = $this->getCommentsCriteria($object, $options, $criteria); + $comment_objects = sfCommentPeer::doSelect($c); + $comments = array(); + + foreach ($comment_objects as $comment_object) + { + $comment = $comment_object->toArray(); + $comments[] = $comment; + } + + return $comments; + } + + /** + * Returns a criteria for comments selection. The options array + * can contain several options : + * - order : order of the comments + * + * @param BaseObject $object + * @param Array $options + * @param Criteria $criteria + * + * @return Array + */ + protected function getCommentsCriteria(BaseObject $object, $options = array(), Criteria $criteria = null) + { + if ($criteria != null) + { + $c = clone $criteria; + } + else + { + $c = new Criteria(); + } + + $c->add(sfCommentPeer::COMMENTABLE_ID, $object->getPrimaryKey()); + $c->add(sfCommentPeer::COMMENTABLE_MODEL, get_class($object)); + + if (isset($options['namespace'])) + { + $c->add(sfCommentPeer::NAMESPACE, $options['namespace']); + } + else + { + $c->add(sfCommentPeer::NAMESPACE, ''); + } + + if (isset($options['order']) && ($options['order'] == 'desc')) + { + $c->addDescendingOrderByColumn(sfCommentPeer::CREATED_AT); + $c->addDescendingOrderByColumn(sfCommentPeer::ID); + } + else + { + $c->addAscendingOrderByColumn(sfCommentPeer::CREATED_AT); + $c->addAscendingOrderByColumn(sfCommentPeer::ID); + } + + return $c; + } + + /** + * Returns the number of the comments attached to the object. + * + * @param BaseObject $object + * @param Array $options + * @param Criteria $criteria + * + * @return integer + */ + public function getNbComments(BaseObject $object, $options = array(), Criteria $criteria = null) + { + $c = $this->getCommentsCriteria($object, $options, $criteria); + return sfCommentPeer::doCount($c); + } + + /** + * Removes one comment from the object. + * + * @param BaseObject $object + */ + public function removeComment(BaseObject $object, $comment_id) + { + $c = new Criteria(); + $c->add(sfCommentPeer::COMMENTABLE_ID, $object->getPrimaryKey()); + $c->add(sfCommentPeer::COMMENTABLE_MODEL, get_class($object)); + $c->add(sfCommentPeer::ID, $comment_id); + return sfCommentPeer::doDelete($c); + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/sfPropelActAsCommentableToolkit.class.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/sfPropelActAsCommentableToolkit.class.php new file mode 100644 index 0000000..fb79efa --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/lib/sfPropelActAsCommentableToolkit.class.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfPropelActAsCommentableBehavior toolkit class + * + * @author Xavier Lacot + * @author Nicolas Perriault + */ +class sfPropelActAsCommentableToolkit +{ + + /** + * Add a token to available ones in the user session + * and return generated token + * + * @author Nicolas Perriault + * @param string $object_model + * @param int $object_id + * @return string + */ + public static function addTokenToSession($object_model, $object_id) + { + $session = sfContext::getInstance()->getUser(); + $token = self::generateToken($object_model, $object_id); + $tokens = $session->getAttribute('tokens', array(), 'sf_commentables'); + $tokens = array($token => array($object_model, $object_id)) + $tokens; + $tokens = array_slice($tokens, 0, sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_max_tokens', 10)); + $session->setAttribute('tokens', $tokens, 'sf_commentables'); + return $token; + } + + /** + * Generates token representing a commentable object from its model and its id + * + * @author Nicolas Perriault + * @param string $object_model + * @param int $object_id + * @return string + */ + public static function generateToken($object_model, $object_id) + { + return md5(sprintf('%s-%s-%s', $object_model, $object_id, sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_salt', 'c0mm3nt4bl3'))); + } + + /** + * Returns true if the passed model name is commentable + * + * @author Xavier Lacot + * @param string $object_name + * @return boolean + */ + public static function isCommentable($model) + { + if (is_object($model)) + { + $model = get_class($model); + } + + if (!is_string($model)) + { + throw new Exception('The param passed to the metod isTaggable must be a string.'); + } + + if (!class_exists($model)) + { + throw new Exception(sprintf('Unknown class %s', $model)); + } + + $base_class = sprintf('Base%s', $model); + return !is_null(sfMixer::getCallable($base_class.':addComment')); + } + + /** + * Retrieve a commentable object + * + * @param string $object_model + * @param int $object_id + */ + public static function retrieveCommentableObject($object_model, $object_id) + { + try + { + $peer = sprintf('%sPeer', $object_model); + + if (!class_exists($peer)) + { + throw new Exception(sprintf('Unable to load class %s', $peer)); + } + + $object = call_user_func(array($peer, 'retrieveByPk'), $object_id); + + if (is_null($object)) + { + throw new Exception(sprintf('Unable to retrieve %s with primary key %s', $object_model, $object_id)); + } + + if (!sfPropelActAsCommentableToolkit::isCommentable($object)) + { + throw new Exception(sprintf('Class %s does not have the commentable behavior', $object_model)); + } + + return $object; + } + catch (Exception $e) + { + return sfContext::getInstance()->getLogger()->log($e->getMessage()); + } + } + + /** + * Retrieve commentable object instance from token + * + * @author Nicolas Perriault + * @param string $token + * @return BaseObject + */ + public static function retrieveFromToken($token) + { + $session = sfContext::getInstance()->getUser(); + $tokens = $session->getAttribute('tokens', array(), 'sf_commentables'); + if (array_key_exists($token, $tokens) && is_array($tokens[$token]) && class_exists($tokens[$token][0])) + { + $object_model = $tokens[$token][0]; + $object_id = $tokens[$token][1]; + return self::retrieveCommentableObject($object_model, $object_id); + } else return null; + } + +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/actions/actions.class.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/actions/actions.class.php new file mode 100644 index 0000000..b63b0d5 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/actions/actions.class.php @@ -0,0 +1,14 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsCommentableBehaviorPlugin + */ +class sfCommentActions extends BasesfCommentActions +{ +} diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/actions/components.class.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/actions/components.class.php new file mode 100644 index 0000000..9fc1c85 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/actions/components.class.php @@ -0,0 +1,14 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsCommentableBehaviorPlugin + */ +class sfCommentComponents extends BasesfCommentComponents +{ +} diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentActions.class.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentActions.class.php new file mode 100644 index 0000000..a997798 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentActions.class.php @@ -0,0 +1,187 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsCommentableBehaviorPlugin + */ +class BasesfCommentActions extends sfActions +{ + private + $config, + $config_user, + $config_anonymous; + + /** + * Saves a comment, for an authentified user + */ + public function executeAuthenticatedComment() + { + $this->getConfig(); + + if ((sfContext::getInstance()->getUser()->isAuthenticated() + && $this->config_user['enabled']) + && $this->getRequest()->getMethod() == sfRequest::POST) + { + $token = $this->getRequestParameter('sf_comment_object_token'); + $object = sfPropelActAsCommentableToolkit::retrieveFromToken($token); + $comment = array('text' => $this->getRequestParameter('sf_comment')); + $id_method = $this->config_user['id_method']; + $namespace = $this->getRequestParameter('sf_comment_namespace', null); + $this->namespace = $namespace; + + $this->validateNamespace($namespace); + + $comment['author_id'] = sfContext::getInstance()->getUser()->$id_method(); + $comment['namespace'] = $namespace; + + foreach (sfMixer::getCallables('sfCommentActions:addComment:pre') as $callable) + { + call_user_func($callable, $comment, $object); + } + + $comment_object = $object->addComment($comment); + + foreach (sfMixer::getCallables('sfCommentActions:addComment:post') as $callable) + { + call_user_func($callable, $comment_object, $object); + } + + $this->object = $object; + + if (!$this->getContext()->getRequest()->isXmlHttpRequest()) + { + $this->redirect($this->getRequestParameter('sf_comment_referer')); + } + } + + $this->setTemplate('comment'); + } + + /** + * Saves a comment, for a non authentified user + */ + public function executeAnonymousComment() + { + $this->getConfig(); + + if ($this->config_anonymous['enabled'] && $this->getRequest()->getMethod() == sfRequest::POST) + { + $token = $this->getRequestParameter('sf_comment_object_token'); + $object = sfPropelActAsCommentableToolkit::retrieveFromToken($token); + $namespace = $this->getRequestParameter('sf_comment_namespace', null); + $this->namespace = $namespace; + + $this->validateNamespace($namespace); + + $comment = array('text' => $this->getRequestParameter('sf_comment'), + 'author_name' => $this->getRequestParameter('sf_comment_name'), + 'author_email' => $this->getRequestParameter('sf_comment_email'), + 'namespace' => $namespace); + + foreach (sfMixer::getCallables('sfCommentActions:addComment:pre') as $callable) + { + call_user_func($callable, $comment, $object); + } + + $comment_object = $object->addComment($comment); + + foreach (sfMixer::getCallables('sfCommentActions:addComment:post') as $callable) + { + call_user_func($callable, $comment_object, $object); + } + + $this->object = $object; + + if (!$this->getContext()->getRequest()->isXmlHttpRequest()) + { + $this->redirect($this->getRequestParameter('sf_comment_referer')); + } + } + + $this->setTemplate('comment'); + } + + /** + * Displays the comment form + */ + public function executeCommentForm() + { + $token = $this->getRequestParameter('sf_comment_object_token'); + $this->object = sfPropelActAsCommentableToolkit::retrieveFromToken($token); + $this->namespace = $this->getRequestParameter('sf_comment_namespace', null); + } + + protected function getConfig() + { + $config_anonymous = array('enabled' => true, + 'layout' => array('name' => 'required', + 'email' => 'required', + 'title' => 'optional', + 'comment' => 'required'), + 'name' => 'Anonymous User'); + $config_user = array('enabled' => true, + 'layout' => array('title' => 'optional', + 'comment' => 'required'), + 'table' => 'sf_guard_user', + 'id' => 'id', + 'class' => 'sfGuardUser', + 'id_method' => 'getUserId', + 'toString' => 'toString', + 'save_name' => false); + + $this->config_anonymous = sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_anonymous', $config_anonymous); + $this->config_user = sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_user', $config_user); + + $config = array('user' => $this->config_user, + 'anonymous' => $this->config_anonymous, + 'use_ajax' => sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_use_ajax', false), + 'namespaces' => sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_namespaces', false)); + $this->config = $config; + } + + public function handleErrorAnonymousComment() + { + $this->handleErrorComment(); + } + + public function handleErrorAuthenticatedComment() + { + $this->handleErrorComment(); + } + + private function handleErrorComment() + { + $params = $this->getContext()->getController()->convertUrlStringToParameters($this->getRequestParameter('sf_comment_referer')); + + foreach ($params[1] as $param => $value) + { + $this->getRequest()->setParameter($param, $value); + } + + if ($this->getContext()->getRequest()->isXmlHttpRequest()) + { + $this->getResponse()->setStatusCode(500); + $this->forward('sfComment', 'commentForm'); + } + else + { + $this->forward($params[1]['module'], $params[1]['action']); + } + } + + public function validateNamespace($namespace) + { + $this->getConfig(); + $namespaces = $this->config['namespaces']; + + if (isset($namespaces[$namespace]) && !$this->getUser()->hasCredential($namespaces[$namespace])) + { + $this->getRequest()->setError('unauthorized', + 'You do not have the right to add comments in this namespace.'); + $this->handleErrorComment(); + } + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentComponents.class.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentComponents.class.php new file mode 100644 index 0000000..f5940b3 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/lib/BasesfCommentComponents.class.php @@ -0,0 +1,98 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsCommentableBehaviorPlugin + */ +class BasesfCommentComponents extends sfComponents +{ + public function executeCommentForm() + { + sfContext::getInstance()->getResponse()->addStylesheet('/sfPropelActAsCommentableBehaviorPlugin/css/sf_comment'); + $this->getConfig(); + + if ($this->object instanceof sfOutputEscaperObjectDecorator) + { + $object = $this->object->getRawValue(); + } + else + { + $object = $this->object; + } + + $this->object_model = get_class($object); + $this->object_id = $object->getPrimaryKey(); + $this->token = sfPropelActAsCommentableToolkit::addTokenToSession($this->object_model, $this->object_id); + + if ($this->getUser()->isAuthenticated() && $this->config_user['enabled']) + { + $this->action = 'authenticated_comment'; + $this->config_used = $this->config_user; + } + else + { + $this->action = 'anonymous_comment'; + $this->config_used = $this->config_anonymous; + } + } + + public function executeCommentList() + { + $object = $this->object; + $order = $this->order; + $namespace = $this->namespace; + $limit = $this->limit; + + if (!$order) + { + $order = 'asc'; + } + + if (!$namespace) + { + $namespace = null; + } + + if (!$limit) + { + $criteria = null; + } + else + { + $criteria = new Criteria(); + $criteria->setLimit($limit); + } + + $this->comments = $object->getComments(array('order' => $order, 'namespace' => $namespace), $criteria); + } + + protected function getConfig() + { + $config_anonymous = array('enabled' => true, + 'layout' => array('name' => 'required', + 'email' => 'required', + 'title' => 'optional', + 'comment' => 'required'), + 'name' => 'Anonymous User'); + $config_user = array('enabled' => true, + 'layout' => array('title' => 'optional', + 'comment' => 'required'), + 'table' => 'sf_guard_user', + 'id' => 'id', + 'class' => 'sfGuardUser', + 'id_method' => 'getUserId', + 'toString' => 'toString', + 'save_name' => false); + $config = array('user' => $config_user, + 'anonymous' => $config_anonymous, + 'use_ajax' => sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_use_ajax', false), + 'namespaces' => array()); + + $this->config = $config; + $this->config_anonymous = sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_anonymous', $config_anonymous); + $this->config_user = sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_user', $config_user); + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentForm.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentForm.php new file mode 100644 index 0000000..b9821a8 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentForm.php @@ -0,0 +1,97 @@ + + + + + + +isAuthenticated() && $config_user['enabled']) + || $config_anonymous['enabled']): ?> + 'sf_comment_form', + 'id' => 'sf_comment_form', + 'name' => 'sf_comment_form')); + ?> +
    + hasError('unauthorized')): ?> +
    + getError('unauthorized') ?> +
    + + + +
    + + + +
    + + + +
    + + + +
    + + + +
    + + + +
    + + +
    + + + +
    +
    + + getCurrentInternalUri(); + + if ($pathInfoArray['QUERY_STRING'] != '') + { + $referer .= '?'.$pathInfoArray['QUERY_STRING']; + } + ?> + getRequest()->getParameter('sf_comment_referer', $referer)) ?> + + + + + + + + + array('success' => 'sf_comment_list', 'failure' => 'sf_comment_form'), + 'url' => 'sfComment/'.$action, + 'loading' => "Element.show('sf_comment_ajax_indicator')", + 'complete' => "Element.hide('sf_comment_ajax_indicator');Element.scrollTo('sf_comment_list')", + 'script' => true), + array('class' => 'submit')); + ?> + + + 'submit')) ?> + + + \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentList.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentList.php new file mode 100644 index 0000000..8a5b8be --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentList.php @@ -0,0 +1,9 @@ +
    + 0): ?> + + $comment)) ?> + + +

    + +
    \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentView.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentView.php new file mode 100644 index 0000000..70acb22 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/_commentView.php @@ -0,0 +1,19 @@ + +
    +

    + + + $toString(); + ?>, + distance_of_time_in_words(strtotime($comment['CreatedAt'])))) ?> +

    +

    + +

    +
    \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/commentFormSuccess.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/commentFormSuccess.php new file mode 100644 index 0000000..2fc03f0 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/commentFormSuccess.php @@ -0,0 +1,3 @@ + $object, 'namespace' => $namespace)); +?> \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/commentSuccess.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/commentSuccess.php new file mode 100644 index 0000000..35ddf52 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/templates/commentSuccess.php @@ -0,0 +1,3 @@ + + + $object, 'namespace' => $namespace)) ?> diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/validate/anonymousComment.yml b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/validate/anonymousComment.yml new file mode 100644 index 0000000..fc3a32d --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/validate/anonymousComment.yml @@ -0,0 +1,41 @@ + true, + 'layout' => array('name' => 'required', + 'email' => 'required', + 'title' => 'optionnal', + 'comment' => 'required'), + 'name' => 'Anonymous User'); + +$config_anonymous = sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_anonymous', $config_anonymous); +?> + +fields: + + sf_comment_name: + required: + msg: Your name is required + + + + sf_comment_email: + required: + msg: Your email is required + sfEmailValidator: + strict: true + email_error: This email address is invalid + + + + sf_comment_title: + required: + msg: A title is required + + + sf_comment: + required: + msg: The message is required + +fillin: + enabled: true + param: + name: sf_comment_form \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/validate/authenticatedComment.yml b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/validate/authenticatedComment.yml new file mode 100644 index 0000000..81db1b2 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfComment/validate/authenticatedComment.yml @@ -0,0 +1,44 @@ + true, + 'layout' => array('title' => 'optionnal', + 'comment' => 'required'), + 'table' => 'sf_guard_user', + 'id' => 'id', + 'class' => 'sfGuardUser', + 'id_method' => 'getUserId', + 'toString' => '__toString', + 'save_name' => false); + +$config_user = sfConfig::get('app_sfPropelActAsCommentableBehaviorPlugin_user', $config_user); +?> + +fields: + + sf_comment_name: + required: + msg: Your name is required + + + + sf_comment_email: + required: + msg: Your email is required + sfEmailValidator: + strict: true + email_error: This email address is invalid + + + + sf_comment_title: + required: + msg: A title is required + + + sf_comment: + required: + msg: The message is required + +fillin: + enabled: true + param: + name: sf_comment_form \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfCommentAdmin/actions/actions.class.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfCommentAdmin/actions/actions.class.php new file mode 100644 index 0000000..7f775a6 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfCommentAdmin/actions/actions.class.php @@ -0,0 +1,13 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsCommentableBehaviorPlugin + */ +class sfCommentAdminActions extends autoSfCommentAdminActions +{ +} diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfCommentAdmin/config/generator.yml b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfCommentAdmin/config/generator.yml new file mode 100644 index 0000000..91abcd1 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/modules/sfCommentAdmin/config/generator.yml @@ -0,0 +1,26 @@ +generator: + class: sfPropelAdminGenerator + param: + model_class: sfComment + theme: default + + fields: + commentable_model: { name: Model } + commentable_id: { name: Id } + author: { name: Author } + created_at: { name: Date } + + list: + title: List of the comments + filters: [commentable_model, commentable_id, author_id, namespace] + sort: [created_at, desc] + display: [=id, namespace, commentable_model, commentable_id, author_id, created_at] + object_actions: + _edit: - + _delete: confirm: Are you sur you want to delete this comment ? + + edit: + title: Edit a comment + display: + "Commented object": [commentable_model, commentable_id] + "Comment": [author_id, author_name, author_email, namespace, created_at, title, text] \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/test/unit/sfPropelActAsCommentableBehaviorTest.php b/plugins/sfPropelActAsCommentableBehaviorPlugin/test/unit/sfPropelActAsCommentableBehaviorTest.php new file mode 100644 index 0000000..08d9506 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/test/unit/sfPropelActAsCommentableBehaviorTest.php @@ -0,0 +1,114 @@ +initialize(); +$con = Propel::getConnection(); + +// clean the database +sfCommentPeer::doDeleteAll(); +call_user_func(array(_create_object()->getPeer(), 'doDeleteAll')); + +// create a new test browser +$browser = new sfTestBrowser(); +$browser->initialize(); + +// start tests +$t = new lime_test(11, new lime_output_color()); + + +// these tests check for the comments attachement consistency +$t->diag('comments attachment consistency'); + +$object1 = _create_object(); +$t->ok($object1->getComments() == array(), 'a new object has no comment.'); +$object1->save(); + +$object1->addComment('One first comment.'); +$object_comments = $object1->getComments(); +$t->ok((count($object_comments) == 1) && ($object_comments[0]['Text'] == 'One first comment.'), 'a saved object can get commented.'); + +$object1->addComment('One second comment.'); +$t->ok($object1->getNbComments() == 2, 'one object can have several comments.'); + +$object2 = _create_object(); +$object2->save(); + +$object2->addComment('One first comment on object2.'); +$object1_comments = $object1->getComments(); +$object2_comments = $object2->getComments(); +$t->ok((count($object1_comments) == 2) && (count($object2_comments) == 1), 'one comment is only attached to one Propel object.'); +$t->ok(count($object1_comments) == $object1->getNbComments(), 'getNbComment() permùits to retrieve one object\'s comments number.'); + +$object3 = _create_object(); +$object3->save(); +$comment1 = array('text' => 'One first comment', + 'author_name' => 'Gérard', + 'author_email' => 'gerard@lambert.com'); +$object3->addComment($comment1); +$t->ok($object3->getNbComments() == 1, 'comments can also be attached using arrays.'); +$comment2 = array('text' => 'My Back-office comment', + 'author_name' => 'Gérard', + 'author_email' => 'gerard@lambert.com', + 'namespace' => 'backend'); +$object3->addComment($comment2); +$object3->addComment($comment2); +$t->ok(($object3->getNbComments() == 1) && ($object3->getNbComments(array('namespace' => 'backend')) == 2), 'comments are separated into namespaces, and can be retrieved separately.'); + + +// these tests check for other methods +$t->diag('comments manipulation methods'); +sfCommentPeer::doDeleteAll(); + +$object1 = _create_object(); +$object1->save(); +$object1->addComment('One first comment.'); +$object1->addComment('One second comment.'); +$object_comments = $object1->getComments(); +$nb_object_comments = $object1->getNbComments(); +$t->ok(($nb_object_comments == count($object_comments)) && ($nb_object_comments == 2), 'getNbComments() returns the number of comments attached to the object when it has still not been saved.'); + +$object1->addComment('One third comment.'); +$object_comments = $object1->getComments(); +$nb_object_comments = $object1->getNbComments(); +$t->ok(($nb_object_comments == count($object_comments)) && ($nb_object_comments == 3), 'getNbComments() returns the number of comments attached to the object, when it has been saved also.'); + +$object1->clearComments(); +$t->ok($object1->getNbComments() === 0, 'comments on an object can be cleared using clearComments().'); + + +// these tests check for comments retrieval methods +$t->diag('comments retrieval methods'); +sfCommentPeer::doDeleteAll(); + +$object1 = _create_object(); +$object1->save(); +$object1->addComment('One first comment.'); +$object1->addComment('One second comment.'); +$asc_comments = $object1->getComments(array('order' => 'asc')); +$desc_comments = $object1->getComments(array('order' => 'desc')); +$t->ok(($asc_comments[0]['Text'] == 'One first comment.') + && ($asc_comments[1]['Text'] == 'One second comment.') + && ($desc_comments[1]['Text'] == 'One first comment.') + && ($desc_comments[0]['Text'] == 'One second comment.'), 'comments can be retrieved in a specific order.'); + + +// test object creation +function _create_object() +{ + $classname = TEST_CLASS; + + if (!class_exists($classname)) + { + throw new Exception(sprintf('Unknow class "%s"', $classname)); + } + + + return new $classname; +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/web/css/sf_comment.css b/plugins/sfPropelActAsCommentableBehaviorPlugin/web/css/sf_comment.css new file mode 100644 index 0000000..5059ee1 --- /dev/null +++ b/plugins/sfPropelActAsCommentableBehaviorPlugin/web/css/sf_comment.css @@ -0,0 +1,64 @@ +.sf_comment_form div { +margin: 0 0 10px 0; +} + +.sf_comment_form fieldset { +padding: 0; +} + +.sf_comment_form label { +margin: 0; +padding: 0; +display: block; +} + +.sf_comment_form input, .sf_comment_form textarea { +padding: 1px 0 1px 10px; +min-width: 30em; +background: #fff url(../images/input-shadow.gif) top left repeat-x; +} + +.sf_comment_form textarea { +height: 10em; +} + +.sf_comment_form .form_error { +color: red; +font-weight: bold; +} + +.sf_comment_form input.submit { +color: #666; +width: auto; +border: 1px #666 solid; +height: 2.2em; +margin: 0 0 2em 0; +padding: 0 5px; +font-size: 1em; +min-width: 0; +background: none; +background-color: #ececec; +} + +.sf_comment_form input.submit:hover { +color: #ececec; +border: 1px #ececec solid; +background-color: #666; +} + +.sf_comment_form .required input, .sf_comment_form .required textarea { +background: #fff url(../images/input-shadow-required.gif) top left no-repeat; +} + +.sf_comment_form_error { +color: red; +font-weight: bold; +} + +#sf_comment_ajax_indicator { +width: 20px; +height: 20px; +margin: 0; +padding: 0; +background: transparent url(../images/indicator.gif) top left no-repeat; +} \ No newline at end of file diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/indicator.gif b/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/indicator.gif new file mode 100644 index 0000000..1560b64 Binary files /dev/null and b/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/indicator.gif differ diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/input-shadow-required.gif b/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/input-shadow-required.gif new file mode 100644 index 0000000..9ff6992 Binary files /dev/null and b/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/input-shadow-required.gif differ diff --git a/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/input-shadow.gif b/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/input-shadow.gif new file mode 100644 index 0000000..ffe4cc3 Binary files /dev/null and b/plugins/sfPropelActAsCommentableBehaviorPlugin/web/images/input-shadow.gif differ diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/LICENSE b/plugins/sfPropelActAsRatableBehaviorPlugin/LICENSE new file mode 100644 index 0000000..59a4b0f --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2007 Nicolas Perriault + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/README b/plugins/sfPropelActAsRatableBehaviorPlugin/README new file mode 100644 index 0000000..992018a --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/README @@ -0,0 +1,370 @@ += sfPropelActAsRatableBehaviorPlugin = + +This plugin aims at providing rating capabilities to any Propel object with the +help of a dedicated Propel behavior. + +[[Image(rating_capture.png, right)]] + +== Installation == + +To install the plugin, run this command within your symfony project : + +{{{ +symfony plugin-install http://plugins.symfony-project.com/sfPropelActAsRatableBehaviorPlugin +}}} + +The source code is also available: + * [source:plugins/sfPropelActAsRatableBehaviorPlugin from the code browser] + * [http://svn.symfony-project.com/plugins/sfPropelActAsRatableBehaviorPlugin/ from the SVN repository] + (please always use a tagged version in production) + +=== SVN repository === + +The plugin is also available through the Symfony SVN repository. + +Stable versions are available in the +[http://svn.symfony-project.com/plugins/sfPropelActAsRatableBehaviorPlugin/tags tags] +folder, experimental ones in the +[http://svn.symfony-project.com/plugins/sfPropelActAsRatableBehaviorPlugin/branches branches] +one and the current alpha in the +[http://svn.symfony-project.com/plugins/sfPropelActAsRatableBehaviorPlugin/trunk trunk]. + +'''Caution: Never use the trunk version in a production environment.''' + +== Configuration == + +To activate this Propel behavior in Symfony, you must first activate behaviors +in your propel.ini file : + +{{{ +propel.builder.addBehaviors = true +}}} + +In one (or more) of your existing model object classes, apply the behavior. Eg. +for an {{{Article}}} Propel model class: + +{{{ + + array('max_rating' => 10, // Max rating value for an Article + 'rating_field' => 'AverageRating', // refers to ArticlePeer::AVERAGE_RATING + 'reference_field' => 'Reference'))); // refers to ArticlePeer::REFERENCE +}}} + + * The {{{max_rating}}} parameter sets the maximum rating available for an object + (this must be an integer greater than 0 - default is 5) + * The {{{rating_field}}} parameter, which refer to a {{{float}}} + column in phpName format of your ratable object table which will store cached + value of actual rating for the object. Useful for queries performances and + sorting ;) + * The {{{reference_field}}} parameter sets the name of the field where you + store the identifier of the object to rate. By default, the plugin will use + the primary key of the object. You must return an integer fo referencing a + custom identifier. + +=== Ensure rating consistency === + +A clean way to ensure rating consistency is to associate a rating to a unique +identified user reference stored server side, typically the primary key of a +user record in your database. + +If no user reference can be retrieved, the plugin will rely on cookies, but you +should consider this alternative solution with caution, as cookies are easily +deletable by the user. + +=== User reference retrieval configuration === + +By default, the plugin will search for an [wiki:sfGuardPlugin sfGuardPlugin] +installation to retrieve authenticated user primary key. If you are using sfGuard, +you have nothing more to configure. + +If you don't use sfGuard, you can specify the way a unique user reference (eg. +primary key) will be retrieved, using these available plugin settings in your +{{{app.yml}}} file: + + * You can specify a PHP function, eg. {{{get_connected_user_id()}}}: + +{{{ + rating: + user_id_getter: get_connected_user_id +}}} + + * Or a static method of a PHP class, eg. + {{{MyCustomUtilsClass::getConnectedUserId()}}}: + +{{{ + rating: + user_id_getter: [MyCustomUtilsClass, getConnectedUserId] +}}} + +The return value of these calls should always be the primary key of your +connected user. + +== Using the Ajax rating system == + +This plugin provides an Ajax-based rating system, with pretty stars to click on. +You must note that this web module is provided for illustration purpose, it has +weak chances to fit exactly your project needs. + +[[Image(rating_capture.png)]] + +To activate this feature, you must enable the {{{sfRating}}} module in the +{{{config/settings.yml}}} file of the app you want to use the helper in : + +{{{ +all: + .settings: + enabled_modules: [default, sfRating] +}}} + +If you are under Microsoft Windows, you also have to manually copy the {{{./web}}} +directory of the plugin in the {{{%SF_ROOT_DIR%/web}}} directory of your project +and rename it to {{{sfPropelActAsRatableBehaviorPlugin}}}. Then you will have +this on the filesytem : + +{{{ +project_root + [...] + web + sfPropelActAsRatableBehaviorPlugin + css + sf_rating.css + images + alt_star.gif +}}} + +Then, you can use the {{{sf_rater}}} helper in any of your templates: + +{{{ + + +}}} + +== Using the rating details display component == + +[[Image(RatingDetails.png, right)]] + +Just call the component from any of your templates: + +{{{ + $article) ?> +}}} + +== API Usage == + +Note: In below examples, {{{$user_id}}} is a string representing a +unique reference to a user, eg. if you're using the sfGuardPlugin, +{{{sfContext::getInstance()->getUser()->getGuardUser()->getId()}}}. + +If you don't provide this parameter, the +[#Userreferenceretrievalconfiguration configured user reference retrieval configuration] +will apply. + +To set a rating for a given user: + +{{{ +$article->setRating(10, $user_id); +}}} + +To test if the object has already been rated : + +{{{ +$article->hasBeenRated(); +}}} + +To test if the object has already been rated by a particular user: + +{{{ +$article->hasBeenRatedByUser($user_id); +}}} + +To retrieve user rating for this object : + +{{{ +$article->getUserRating($user_id); +}}} + +To get the average rating of the object : + +{{{ +$article->getRating([$precision]); +}}} + +Note: If you have concerns about performances, you will better use the cached +value of rating stored in the {{{rating_column}}} you configured previously. + +To retrieve the maximum possible rating for an object (which you have defined in +the {{{max_rating}}} behavior optional parameter - default is 5) : + +{{{ +$article->getMaxRating(); +}}} + +To clear user rating : + +{{{ +$article->clearUserRating($user_id); +}}} + +To retrieve rating details : + +{{{ +$details = $article->getRatingDetails(); +}}} + +Results will be this form: + +{{{ +array( + 2 => 12, // 12 people has rated the object 2 + 5 => 7 // 7 people has rated the object 5 +) +}}} + +You can also retrieve details for all available ratings: + +{{{ +$full_details = $article->getRatingDetails(true); +}}} + +Results will be this form: + +{{{ +array( + 1 => 0, // Nobody has rated the object 1 + 2 => 12, // 12 people has rated the object 2 + 3 => 0, // Nobody has rated the object 3 + 4 => 0, // Nobody has rated the object 4 + 5 => 7, // 7 people has rated the object 5 +) +}}} + +To clear all ratings for the object : + +{{{ +$article->clearRatings(); +}}} + +== Unit testing == + +The plugin is provided with a test suite located in the {{{./test}}} directory. +To run the tests, type this line from the root of your project : + +{{{ +$ php plugins/sfPropelActAsRatableBehaviorPlugin/test/unit/sfPropelActAsRatableBehaviorTest.php +}}} + +Note that you have to provide a Propel test object class name to run the test in the test file: + +{{{ +define('TEST_CLASS', 'Article'); +}}} + +== Uninstallation == + +{{{ +symfony plugin-uninstall symfony/sfPropelActAsRatableBehaviorPlugin +}}} + +You will need to remove the behavior to all your model, then rebuild your model +and purge your cache. + +== TODO == + + * Add functional tests + +== Changelog == + +=== 2007-10-29 | v0.7.1 === + + * Ratable model objects instances references are now tokenized in the session + and are no more passed as request parameters + +=== 2007-09-23 | v0.7 === + + * big behavior refactoring, with model and API BC (sorry for that, but it is + *much* better now) + * removed ugly reference field configuration and behavior methods, now we use + object {{{getPrimaryKey()}}} method: fast, portable and reliable + * removed sfPropelActAsRatableBehavior::isRatable() buggy method + * added Fabian Lange patch to allow ratings details retrieval (thanks!) + * added a component to display rating details graphically + * removed all IP address handling related stuff (unsecure when passed as parameters) + * ratings storing in dedicated column in ratable object table (submitted by Vojtech + Rysanek - thanks!) + * added i18n strings management + +=== 2007-09-12 | v0.6.2 === + + * Reference keys are now stored as a md5 hash + * Corrected custom reference keys handling bug in Ajax rater widget + * Added a {{{isRatable}}} static method in behavior class + * Some bugs corrected + +=== 2007-09-09 | v0.6.1 === + + * Added a way to specify a custom reference field to identify a ratable Propel object + * Added ability to set the maximum rating for an object when the behavior is added + * Key length as also been decreased to avoid a strange MySQL bug on KEY length + * Added unit tests + +=== 2007-09-07 | v0.6.0 === + + * Added an AJAX rating system as a helper + * Added constant MAX_RATING management for consistency control in ratable model class + * Moved int fields to varchar for storing unique user reference descriptor + (eg. storing the IP address, an email, a md5 hash, etc.) + * {{{sfRatings}}} table has been renamed to {{{sf_ratings}}}: you have to + rebuild your SQL files and insert them in your DB if you upgrade from + 0.5.0. Hopefully, one day we'll have a migration system in Symfony core... + * Removed configuration file to set up Propel object to unit test in the test + suite + +=== 2007-09-05 | v0.5.0 === + + * Initial release + +== Maintener == + +This plugin is maintened by [http://prendreuncafe.com Nicolas Perriault] +({{{nperriault}}} -> {{{gmail.com}}}) + +Feel free to send feture request, enhancement suggestion or idealy a patch. + +== Credits == + + * The eye-candy star-based Ajax system is based on the great work of + Komodomedia: + http://komodomedia.com/blog/samples/star_rating/example2.htm diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/config/config.php b/plugins/sfPropelActAsRatableBehaviorPlugin/config/config.php new file mode 100644 index 0000000..84f3992 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/config/config.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +sfPropelBehavior::registerHooks('sfPropelActAsRatableBehavior', array ( + ':delete:pre' => array ('sfPropelActAsRatableBehavior', 'preDelete'), +)); + +sfPropelBehavior::registerMethods('sfPropelActAsRatableBehavior', array ( + array('sfPropelActAsRatableBehavior', 'countRatings'), + array('sfPropelActAsRatableBehavior', 'setRating'), + array('sfPropelActAsRatableBehavior', 'getMaxRating'), + array('sfPropelActAsRatableBehavior', 'getRating'), + array('sfPropelActAsRatableBehavior', 'getRatingDetails'), + array('sfPropelActAsRatableBehavior', 'getReferenceKey'), + array('sfPropelActAsRatableBehavior', 'getUserRating'), + array('sfPropelActAsRatableBehavior', 'hasBeenRated'), + array('sfPropelActAsRatableBehavior', 'hasBeenRatedByUser'), + array('sfPropelActAsRatableBehavior', 'clearRatings'), + array('sfPropelActAsRatableBehavior', 'clearUserRating'), +)); diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/config/schema.yml b/plugins/sfPropelActAsRatableBehaviorPlugin/config/schema.yml new file mode 100644 index 0000000..db36c21 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/config/schema.yml @@ -0,0 +1,14 @@ +propel: + _attributes: { package: plugins.sfPropelActAsRatableBehaviorPlugin.lib.model } + + sf_ratings: + _attributes: { phpName: sfRating, package: plugins.sfPropelActAsRatableBehaviorPlugin.lib.model } + id: + ratable_model: { type: varchar, size: 50, required: true } + ratable_id: { type: integer, required: true } + user_id: { type: integer } + rating: { type: integer, required: true, default: 1 } + _indexes: + ratable_index: [ratable_model, ratable_id, user_id] + + \ No newline at end of file diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/lib/helper/sfRatingHelper.php b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/helper/sfRatingHelper.php new file mode 100644 index 0000000..a659cb7 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/helper/sfRatingHelper.php @@ -0,0 +1,102 @@ + + */ +sfLoader::loadHelpers(array('Javascript', 'Tag', 'I18N')); + +$response = sfContext::getInstance()->getResponse(); + +$css = '/sfPropelActAsRatableBehaviorPlugin/css/sf_rating'; +$response->addStylesheet($css); + +$js = '/sf/prototype/js/prototype.js'; +$response->addJavascript($js); + +/** + * Return the HTML code for a unordered list showing rating stars + * + * @param BaseObject $object Propel object instance + * @param array $options Array of HTML options to apply on the HTML list + * @throws sfPropelActAsRatableException + * @return string + **/ +function sf_rater($object, $options = array()) +{ + if (is_null($object)) + { + sfLogger::getInstance()->debug('A NULL object cannot be rated'); + } + + if (!isset($options['star-width'])) + { + $star_width = sfConfig::get('app_rating_star_width', 25); + } + else + { + $star_width = $options['star-width']; + unset($options['star-width']); + } + + try + { + $max_rating = $object->getMaxRating(); + $actual_rating = $object->getRating(); + $bar_width = $actual_rating * $star_width; + + $options = _parse_attributes($options); + if (!isset($options['class'])) + { + $options = array_merge($options, array('class' => 'star-rating')); + } + if (!isset($options['style']) or !preg_match('/width:/i', $options['style'])) + { + $full_bar_width = $max_rating * $star_width; + $options = array_merge($options, + array('style' => 'width:'.$full_bar_width.'px')); + } + + if ($object instanceof sfOutputEscaperObjectDecorator) + { + $object_class = get_class($object->getRawValue()); + } + else + { + $object_class = get_class($object); + } + $object_id = $object->getReferenceKey(); + $token = sfPropelActAsRatableBehaviorToolkit::addTokenToSession($object_class, $object_id); + + $msg_domid = sprintf('rating_message_%s', $token) ; + $bar_domid = sprintf('current_rating_%s', $token) ; + + $list_content = '
  • '; + $list_content .= __('Currently rated %rating% star(s) on %max_rating%', array('%rating%' => $object->getRating(), '%max_rating%' => $max_rating)); + $list_content .= '
  • '; + + for ($i=1; $i <= $max_rating; $i++) + { + $label = __('Rate it %number_of_stars% stars', array('%number_of_stars%' => $i)); + $list_content .= + '
  • '.link_to_remote($label, + array('url' => sprintf('sfRating/rate?token=%s&rating=%d&star_width=%d', + $token, + $i, + $star_width), + 'update' => $msg_domid, + 'script' => true, + 'complete' => visual_effect('appear', $msg_domid). + visual_effect('highlight', $msg_domid)), + array('class' => 'r'.$i.'stars', + 'title' => $label)).'
  • '; + } + + return content_tag('ul', $list_content, $options). + content_tag('div', null, array('id' => $msg_domid)); + } + catch (Exception $e) + { + sfLogger::getInstance()->err('Exception catched from sf_rater helper: '.$e->getMessage()); + } +} diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/map/sfRatingMapBuilder.php b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/map/sfRatingMapBuilder.php new file mode 100644 index 0000000..b2c25dd --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/map/sfRatingMapBuilder.php @@ -0,0 +1,48 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('sf_ratings'); + $tMap->setPhpName('sfRating'); + + $tMap->setUseIdGenerator(true); + + $tMap->addPrimaryKey('ID', 'Id', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('RATABLE_MODEL', 'RatableModel', 'string', CreoleTypes::VARCHAR, true, 50); + + $tMap->addColumn('RATABLE_ID', 'RatableId', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('USER_ID', 'UserId', 'int', CreoleTypes::INTEGER, false, null); + + $tMap->addColumn('RATING', 'Rating', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('RATED_AT', 'RatedAt', 'int', CreoleTypes::TIMESTAMP, true, null); + + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRating.php b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRating.php new file mode 100644 index 0000000..e54c503 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRating.php @@ -0,0 +1,546 @@ +id; + } + + + public function getRatableModel() + { + + return $this->ratable_model; + } + + + public function getRatableId() + { + + return $this->ratable_id; + } + + + public function getUserId() + { + + return $this->user_id; + } + + + public function getRating() + { + + return $this->rating; + } + + + public function getRatedAt($format = 'Y-m-d H:i:s') + { + + if ($this->rated_at === null || $this->rated_at === '') { + return null; + } elseif (!is_int($this->rated_at)) { + $ts = strtotime($this->rated_at); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [rated_at] as date/time value: " . var_export($this->rated_at, true)); + } + } else { + $ts = $this->rated_at; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function setId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = sfRatingPeer::ID; + } + + } + + public function setRatableModel($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->ratable_model !== $v) { + $this->ratable_model = $v; + $this->modifiedColumns[] = sfRatingPeer::RATABLE_MODEL; + } + + } + + public function setRatableId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->ratable_id !== $v) { + $this->ratable_id = $v; + $this->modifiedColumns[] = sfRatingPeer::RATABLE_ID; + } + + } + + public function setUserId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->user_id !== $v) { + $this->user_id = $v; + $this->modifiedColumns[] = sfRatingPeer::USER_ID; + } + + } + + public function setRating($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->rating !== $v || $v === 1) { + $this->rating = $v; + $this->modifiedColumns[] = sfRatingPeer::RATING; + } + + } + + public function setRatedAt($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [rated_at] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->rated_at !== $ts) { + $this->rated_at = $ts; + $this->modifiedColumns[] = sfRatingPeer::RATED_AT; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->id = $rs->getInt($startcol + 0); + + $this->ratable_model = $rs->getString($startcol + 1); + + $this->ratable_id = $rs->getInt($startcol + 2); + + $this->user_id = $rs->getInt($startcol + 3); + + $this->rating = $rs->getInt($startcol + 4); + + $this->rated_at = $rs->getTimestamp($startcol + 5, null); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 6; + } catch (Exception $e) { + throw new PropelException("Error populating sfRating object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BasesfRating:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfRatingPeer::DATABASE_NAME); + } + + try { + $con->begin(); + sfRatingPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfRating:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BasesfRating:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(sfRatingPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BasesfRating:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = sfRatingPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setId($pk); + $this->setNew(false); + } else { + $affectedRows += sfRatingPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + if (($retval = sfRatingPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfRatingPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getId(); + break; + case 1: + return $this->getRatableModel(); + break; + case 2: + return $this->getRatableId(); + break; + case 3: + return $this->getUserId(); + break; + case 4: + return $this->getRating(); + break; + case 5: + return $this->getRatedAt(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfRatingPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getId(), + $keys[1] => $this->getRatableModel(), + $keys[2] => $this->getRatableId(), + $keys[3] => $this->getUserId(), + $keys[4] => $this->getRating(), + $keys[5] => $this->getRatedAt(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = sfRatingPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setId($value); + break; + case 1: + $this->setRatableModel($value); + break; + case 2: + $this->setRatableId($value); + break; + case 3: + $this->setUserId($value); + break; + case 4: + $this->setRating($value); + break; + case 5: + $this->setRatedAt($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = sfRatingPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setRatableModel($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setRatableId($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setUserId($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setRating($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setRatedAt($arr[$keys[5]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(sfRatingPeer::DATABASE_NAME); + + if ($this->isColumnModified(sfRatingPeer::ID)) $criteria->add(sfRatingPeer::ID, $this->id); + if ($this->isColumnModified(sfRatingPeer::RATABLE_MODEL)) $criteria->add(sfRatingPeer::RATABLE_MODEL, $this->ratable_model); + if ($this->isColumnModified(sfRatingPeer::RATABLE_ID)) $criteria->add(sfRatingPeer::RATABLE_ID, $this->ratable_id); + if ($this->isColumnModified(sfRatingPeer::USER_ID)) $criteria->add(sfRatingPeer::USER_ID, $this->user_id); + if ($this->isColumnModified(sfRatingPeer::RATING)) $criteria->add(sfRatingPeer::RATING, $this->rating); + if ($this->isColumnModified(sfRatingPeer::RATED_AT)) $criteria->add(sfRatingPeer::RATED_AT, $this->rated_at); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(sfRatingPeer::DATABASE_NAME); + + $criteria->add(sfRatingPeer::ID, $this->id); + + return $criteria; + } + + + public function getPrimaryKey() + { + return $this->getId(); + } + + + public function setPrimaryKey($key) + { + $this->setId($key); + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setRatableModel($this->ratable_model); + + $copyObj->setRatableId($this->ratable_id); + + $copyObj->setUserId($this->user_id); + + $copyObj->setRating($this->rating); + + $copyObj->setRatedAt($this->rated_at); + + + $copyObj->setNew(true); + + $copyObj->setId(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new sfRatingPeer(); + } + return self::$peer; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BasesfRating:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BasesfRating::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRatingPeer.php b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRatingPeer.php new file mode 100644 index 0000000..b69c9bf --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/om/BasesfRatingPeer.php @@ -0,0 +1,431 @@ + array ('Id', 'RatableModel', 'RatableId', 'UserId', 'Rating', 'RatedAt', ), + BasePeer::TYPE_COLNAME => array (sfRatingPeer::ID, sfRatingPeer::RATABLE_MODEL, sfRatingPeer::RATABLE_ID, sfRatingPeer::USER_ID, sfRatingPeer::RATING, sfRatingPeer::RATED_AT, ), + BasePeer::TYPE_FIELDNAME => array ('id', 'ratable_model', 'ratable_id', 'user_id', 'rating', 'rated_at', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('Id' => 0, 'RatableModel' => 1, 'RatableId' => 2, 'UserId' => 3, 'Rating' => 4, 'RatedAt' => 5, ), + BasePeer::TYPE_COLNAME => array (sfRatingPeer::ID => 0, sfRatingPeer::RATABLE_MODEL => 1, sfRatingPeer::RATABLE_ID => 2, sfRatingPeer::USER_ID => 3, sfRatingPeer::RATING => 4, sfRatingPeer::RATED_AT => 5, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'ratable_model' => 1, 'ratable_id' => 2, 'user_id' => 3, 'rating' => 4, 'rated_at' => 5, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/map/sfRatingMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfPropelActAsRatableBehaviorPlugin.lib.model.map.sfRatingMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = sfRatingPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(sfRatingPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(sfRatingPeer::ID); + + $criteria->addSelectColumn(sfRatingPeer::RATABLE_MODEL); + + $criteria->addSelectColumn(sfRatingPeer::RATABLE_ID); + + $criteria->addSelectColumn(sfRatingPeer::USER_ID); + + $criteria->addSelectColumn(sfRatingPeer::RATING); + + $criteria->addSelectColumn(sfRatingPeer::RATED_AT); + + } + + const COUNT = 'COUNT(sf_ratings.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT sf_ratings.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(sfRatingPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(sfRatingPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = sfRatingPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = sfRatingPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return sfRatingPeer::populateObjects(sfRatingPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BasesfRatingPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BasesfRatingPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + sfRatingPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = sfRatingPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return sfRatingPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfRatingPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfRatingPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + $criteria->remove(sfRatingPeer::ID); + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BasesfRatingPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BasesfRatingPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BasesfRatingPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BasesfRatingPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(sfRatingPeer::ID); + $selectCriteria->add(sfRatingPeer::ID, $criteria->remove(sfRatingPeer::ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BasesfRatingPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BasesfRatingPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(sfRatingPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(sfRatingPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof sfRating) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + $criteria->add(sfRatingPeer::ID, (array) $values, Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(sfRating $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(sfRatingPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(sfRatingPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(sfRatingPeer::DATABASE_NAME, sfRatingPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = sfRatingPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK($pk, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $criteria = new Criteria(sfRatingPeer::DATABASE_NAME); + + $criteria->add(sfRatingPeer::ID, $pk); + + + $v = sfRatingPeer::doSelect($criteria, $con); + + return !empty($v) > 0 ? $v[0] : null; + } + + + public static function retrieveByPKs($pks, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $objs = null; + if (empty($pks)) { + $objs = array(); + } else { + $criteria = new Criteria(); + $criteria->add(sfRatingPeer::ID, $pks, Criteria::IN); + $objs = sfRatingPeer::doSelect($criteria, $con); + } + return $objs; + } + +} +if (Propel::isInit()) { + try { + BasesfRatingPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/map/sfRatingMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfPropelActAsRatableBehaviorPlugin.lib.model.map.sfRatingMapBuilder'); +} diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/sfRating.php b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/sfRating.php new file mode 100644 index 0000000..8948884 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/model/sfRating.php @@ -0,0 +1,9 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * This Propel behavior aims at providing rating capabilities on any Propel + * object + * + * @package plugins + * @subpackage rating + * @author Nicolas Perriault + * @author Fabian Lange + * @author Vojtech Rysanek + */ +class sfPropelActAsRatableBehavior +{ + + /** + * Default default max rating + */ + const DEFAULT_MAX_RATING = 5; + + /** + * Default float precision + */ + const DEFAULT_PRECISION = 2; + + /** + * Counts ratings made on given ratable object. + * + * @param BaseObject $object + * @return int + */ + public function countRatings(BaseObject $object) + { + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + return sfRatingPeer::doCount($c); + } + + /** + * Retrieves configured float precision for ratings + * + * @param int $default_precision + * @return int + */ + protected static function getPrecision($default_precision = null) + { + if (is_null($default_precision)) + { + $default_precision = self::DEFAULT_PRECISION; + } + return sfConfig::get('app_rating_precision', $default_precision); + } + + /** + * Retrieves an existing rating object, or return a new empty one + * + * @param BaseObject $object + * @param mixed $user_id Unique user primary key + * @return sfRating + * @throws sfPropelActAsRatableException + **/ + protected static function getOrCreate(BaseObject $object, $user_id = null) + { + if ($object->isNew()) + { + throw new sfPropelActAsRatableException('Unsaved objects are not ratable'); + } + + if (is_null($user_id)) + { + return new sfRating(); + } + + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + $c->add(sfRatingPeer::USER_ID, $user_id); + $user_rating = sfRatingPeer::doSelectOne($c); + return is_null($user_rating) ? new sfRating() : $user_rating; + } + + /** + * Clear all ratings for an object + * + * @param BaseObject $object + **/ + public function clearRatings(BaseObject $object) + { + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + $ret = sfRatingPeer::doDelete($c); + self::setRatingToObject($object, 0); + return $ret; + } + + /** + * Clear user rating for an object + * + * @param BaseObject $object + * @param mixed $user_id User primary key + **/ + public function clearUserRating(BaseObject $object, $user_id) + { + if (is_null($user_id) or trim((string)$user_id) === '') + { + throw new sfPropelActAsRatableException('Impossible to clear a user rating with no user primary key provided'); + } + + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + $c->add(sfRatingPeer::USER_ID, $user_id); + $ret = sfRatingPeer::doDelete($c); + self::setRatingToObject($object, $this->getRating($object, self::getPrecision(), true)); + return $ret; + } + + /** + * Checks if an Object has been rated + * + * @param BaseObject $object + **/ + public function hasBeenRated(BaseObject $object) + { + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + return sfRatingPeer::doCount($c) > 0; + } + + /** + * Checks if an Object has been rated by a user + * + * @param BaseObject $object + * @param mixed $user_id Unique reference to a user + **/ + public function hasBeenRatedByUser(BaseObject $object, $user_id) + { + if (is_null($user_id) or trim((string)$user_id) === '') + { + throw new sfPropelActAsRatableException( + 'Impossible to check a user rating with no user primary key provided'); + } + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + $c->add(sfRatingPeer::USER_ID, $user_id); + return (sfRatingPeer::doCount($c) > 0); + } + + /** + * Old method to set maximum rating in a class constant + * This stays here for compability purpose + * + * @param BaseObject $object + * @return int + */ + protected static function getDefaultMaxRating(BaseObject $object) + { + $max_rating = @constant(get_class($object).'::MAX_RATING'); + if (!is_int($max_rating)) + { + $max_rating = self::DEFAULT_MAX_RATING; + } + return $max_rating; + } + + /** + * Retrieves maximum rating for given object + * + * @param BaseObject $object Propel object instance + * @return int + * @throws sfPropelActAsRatableException + */ + public function getMaxRating(BaseObject $object) + { + $max_rating = sfConfig::get( + sprintf('propel_behavior_sfPropelActAsRatableBehavior_%s_max_rating', + get_class($object))); + + if (is_null($max_rating)) + { + $max_rating = self::getDefaultMaxRating($object); + } + + if (!is_int($max_rating)) + { + throw new sfPropelActAsRatableException( + 'The max_rating parameter must be an integer'); + } + + if (is_float($max_rating) && floor($max_rating) != $max_rating) // yeah, php typing sucks... + { + throw new sfPropelActAsRatableException( + sprintf('You cannot type %s::MAX_RATING as float (you provided "%s")', + get_class($object), + $max_rating)); + } + + if ($max_rating < 2) + { + throw new sfPropelActAsRatableException( + 'The max_rating parameter must be an integer greater than 1'); + } + + return $max_rating; + } + + /** + * Retrieves reference_field phpName from configuration + * + * @param BaseObject $object + * @return mixed + */ + protected static function getObjectReferenceField(BaseObject $object) + { + return sfConfig::get( + sprintf('propel_behavior_sfPropelActAsRatableBehavior_%s_reference_field', + get_class($object))); + } + + /** + * Retrieves reference key for current ratable object (default returns + * primary key) + * + * @param BaseObject $object + * @return int + */ + public function getReferenceKey(BaseObject $object) + { + $reference_field = self::getObjectReferenceField($object); + if (is_null($reference_field)) + { + return $object->getPrimaryKey(); + } + + $getter = 'get'.$reference_field; + if (method_exists($object, $getter)) + { + $ret = $object->$getter(); + if (!is_int($ret)) + { + throw new sfPropelActAsRatableException( + 'A reference field must be typed as integer'); + } + return $ret; + } + } + + /** + * Retrieves the object rating + * + * @param BaseObject $object + * @param int $precision Result float precision + * @return float + **/ + public function getRating(BaseObject $object, $precision=2, $docount=false) + { + if ($docount === false && !is_null(self::getObjectRatingField($object))) + { + return round(self::getRatingToObject($object), self::getPrecision()); + } + + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + $c->clearSelectColumns(); + $c->addAsColumn('nb_ratings', 'COUNT('.sfRatingPeer::ID.')'); + $c->addAsColumn('total', 'SUM('.sfRatingPeer::RATING.')'); + $c->addGroupByColumn(sfRatingPeer::RATABLE_MODEL); + $rs = sfRatingPeer::doSelectRS($c); + $rs->setFetchmode(ResultSet::FETCHMODE_ASSOC); + while ($rs->next()) + { + $nb_ratings = $rs->getInt('nb_ratings'); + $total = $rs->getInt('total'); + if (!$nb_ratings or $nb_ratings === 0) + { + return NULL; // Object has not been rated yet + } + return round($total / $nb_ratings, self::getPrecision($precision)); + } + } + + /** + * Gets the object rating details + * + * @author Fabian Lange + * @author Nicolas Perriault + * @param BaseObject $object + * @param boolean $include_all Shall we include all available ratings? + * @return associative array containing (rating => count) + **/ + public function getRatingDetails(BaseObject $object, $include_all = false) + { + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + $c->clearSelectColumns(); + $c->addAsColumn('nb_ratings', 'COUNT('.sfRatingPeer::ID.')'); + $c->addAsColumn('rating', sfRatingPeer::RATING); + $c->addGroupByColumn(sfRatingPeer::RATING); + $rs = sfRatingPeer::doSelectRS($c); + $rs->setFetchmode(ResultSet::FETCHMODE_ASSOC); + $details = array(); + while ($rs->next()) + { + $details = $details + array ($rs->getInt('rating') => (int)$rs->getString('nb_ratings')); + } + if ($include_all === true) + { + for ($i=1; $i<=$object->getMaxRating(); $i++) + { + if (!array_key_exists($i, $details)) + { + $details[$i] = 0; + } + } + } + ksort($details); + return $details; + } + + /** + * Gets the object rating for given user pk + * + * @param BaseObject $object + * @param mixed $user_id User primary key + * @return int or false + **/ + public function getUserRating(BaseObject $object, $user_id) + { + if (is_null($user_id) or trim((string)$user_id) === '') + { + throw new sfPropelActAsRatableException( + 'Impossible to get a user rating with no user primary key provided'); + } + + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + $c->add(sfRatingPeer::RATABLE_MODEL, get_class($object)); + $c->add(sfRatingPeer::USER_ID, $user_id); + $rating_object = sfRatingPeer::doSelectOne($c); + if (!is_null($rating_object)) + { + return $rating_object->getRating(); + } + } + + /** + * Retrieves ratable object instance from class name and key + * + * @param string $class_name + * @param int $key + * @return BaseObject + */ + public static function retrieveByKey($object_name, $key) + { + if (!class_exists($object_name)) + { + throw new sfPropelActAsRatableException('Class %s does not exist', + $object_name); + } + $object = new $object_name; + $peer = $object->getPeer(); + $field = self::getObjectReferenceField($object); + if (is_null($field)) + { + return call_user_func(array($peer, 'retrieveByPK'), $key); + } + else + { + $column = call_user_func(array($peer, 'translateFieldName'), + self::getObjectReferenceField($object), + BasePeer::TYPE_PHPNAME, + BasePeer::TYPE_COLNAME); + $c = new Criteria(); + $c->add($column, $key); + return call_user_func(array($peer, 'doSelectOne'), $c); + } + } + + /** + * Rates the Object + * + * @param BaseObject $object + * @param int $rating + * @param mixed $user_id Optionnal unique reference to user + * @throws sfPropelActAsRatableException + **/ + public function setRating(BaseObject $object, $rating, $user_id = null) + { + if (is_float($rating) && floor($rating) != $rating) + { + throw new sfPropelActAsRatableException( + sprintf('You cannot rate an object with a float (you provided "%s")', + $rating)); + } + + $rating = (int)$rating; + + if ($rating > $object->getMaxRating()) + { + throw new sfPropelActAsRatableException( + sprintf('Maximum rating is %d', $object->getMaxRating())); + } + + if ($rating < 1) + { + throw new sfPropelActAsRatableException('Minimum rating is 1'); + } + + $rating_object = self::getOrCreate($object, $user_id); + $rating_object->setRatableModel(get_class($object)); + $rating_object->setRatableId($object->getReferenceKey()); + $rating_object->setUserId($user_id); + $rating_object->setRating($rating); + $rating_object->setRatedAt(time()); + $ret = $rating_object->save(); + self::setRatingToObject($object, $this->getRating($object, self::getPrecision(), true)); + return $ret; + } + + /** + * Deletes all rating for a ratable object (delete cascade emulation) + * + * @param BaseObject $object + */ + public function preDelete(BaseObject $object) + { + try + { + $c = new Criteria(); + $c->add(sfRatingPeer::RATABLE_ID, $object->getReferenceKey()); + sfRatingPeer::doDelete($c); + } + catch (Exception $e) + { + throw new sfPropelActAsRatableException( + 'Unable to delete ratable object related ratings records'); + } + } + + /* + * Contributed by Vojtech Rysanek + */ + + /** + * Retrieves rating_field phpName from configuration + * + * @param BaseObject $object + * @return mixed + */ + protected static function getObjectRatingField(BaseObject $object) + { + return sfConfig::get( + sprintf('propel_behavior_sfPropelActAsRatableBehavior_%s_rating_field', + get_class($object))); + } + + /** + * Sets cached rating + * + * @param BaseObject $object + * @param float $value + */ + protected static function setRatingToObject(BaseObject $object, $value) + { + $field = self::getObjectRatingField($object); + if (!is_null($field)) + { + $setter = 'set'.$field; + if (method_exists($object, $setter)) + { + $ret = $object->$setter($value); + return $object->save(); + } + } + } + + /** + * Return cached rating from object + * + * @param BaseObject $object + * @return float + */ + protected static function getRatingToObject(BaseObject $object) + { + $field = self::getObjectRatingField($object); + if (!is_null($field)) + { + $getter = 'get'.$field; + if (method_exists($object, $getter)) + { + return $object->$getter(); + } + } + return null; + } + +} \ No newline at end of file diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableBehaviorToolkit.class.php b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableBehaviorToolkit.class.php new file mode 100644 index 0000000..fc98a8e --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableBehaviorToolkit.class.php @@ -0,0 +1,168 @@ +getUser(); + if (class_exists('sfGuardSecurityUser') + && $session instanceof sfGuardSecurityUser + && is_callable(array($session, 'getGuardUser'))) + { + $guard_user = $session->getGuardUser(); + if (!is_null($guard_user)) + { + $guard_user_id = $guard_user->getId(); + if (!is_null($guard_user_id)) + { + return $guard_user_id; + } + } + } + + $getter = sfConfig::get('app_rating_user_id_getter'); + if (is_array($getter) && class_exists($getter[0])) + { + return call_user_func($getter); + } + elseif (is_string($getter) && function_exists($getter)) + { + return $getter(); + } + else + { + return null; + } + } + + /** + * Add a token to available ones in the user session and return generated + * token + * + * @author Nicolas Perriault + * @param string $object_model + * @param int $object_id + * @return string + */ + public static function addTokenToSession($object_model, $object_id) + { + $session = sfContext::getInstance()->getUser(); + $token = self::generateToken($object_model, $object_id); + $tokens = $session->getAttribute('tokens', array(), 'sf_ratables'); + $tokens = array($token => array($object_model, $object_id)) + $tokens; + $tokens = array_slice($tokens, 0, sfConfig::get('app_rating_max_tokens', 10)); + $session->setAttribute('tokens', $tokens, 'sf_ratables'); + return $token; + } + + /** + * Generates token representing a ratable object from its model and its id + * + * @author Nicolas Perriault + * @param string $object_model + * @param int $object_id + * @return string + */ + public static function generateToken($object_model, $object_id) + { + return md5(sprintf('%s-%s-%s', $object_model, $object_id, sfConfig::get('app_rating_salt', 'r4t4bl3'))); + } + + /** + * Returns true if the passed model name is ratable + * + * @author Xavier Lacot + * @param string $object_name + * @return boolean + */ + public static function isRatable($model) + { + if (is_object($model)) + { + $model = get_class($model); + } + + if (!is_string($model)) + { + throw new Exception('The param passed to the metod isRatable must be a string.'); + } + + if (!class_exists($model)) + { + throw new Exception(sprintf('Unknown class %s', $model)); + } + + $base_class = sprintf('Base%s', $model); + return !is_null(sfMixer::getCallable($base_class.':setRating')); + } + + /** + * Retrieve a ratable object + * + * @param string $object_model + * @param int $object_id + */ + public static function retrieveRatableObject($object_model, $object_id) + { + try + { + $peer = sprintf('%sPeer', $object_model); + + if (!class_exists($peer)) + { + throw new Exception(sprintf('Unable to load class %s', $peer)); + } + + $object = call_user_func(array($peer, 'retrieveByPk'), $object_id); + + if (is_null($object)) + { + throw new Exception(sprintf('Unable to retrieve %s with primary key %s', $object_model, $object_id)); + } + + if (!sfPropelActAsRatableBehaviorToolkit::isRatable($object)) + { + throw new Exception(sprintf('Class %s does not have the ratable behavior', $object_model)); + } + + return $object; + } + catch (Exception $e) + { + return sfContext::getInstance()->getLogger()->log($e->getMessage()); + } + } + + /** + * Retrieve ratable object instance from token + * + * @author Nicolas Perriault + * @param string $token + * @return BaseObject + */ + public static function retrieveFromToken($token) + { + $session = sfContext::getInstance()->getUser(); + $tokens = $session->getAttribute('tokens', array(), 'sf_ratables'); + if (array_key_exists($token, $tokens) && is_array($tokens[$token]) && class_exists($tokens[$token][0])) + { + $object_model = $tokens[$token][0]; + $object_id = $tokens[$token][1]; + return self::retrieveRatableObject($object_model, $object_id); + } else return null; + } + +} diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableException.class.php b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableException.class.php new file mode 100644 index 0000000..93f0780 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/lib/sfPropelActAsRatableException.class.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + + +/** + * sfPropelActAsRatableBehaviorPlugin exception + * + * @package plugins + * @subpackage rating + * @author Nicolas Perriault + */ +class sfPropelActAsRatableException extends sfException +{ + + /** + * Class constructor. + * + * @param string The error message + * @param int The error code + */ + public function __construct($message = null, $code = 0) + { + if ($this->getName() === null) + { + $this->setName('sfPropelActAsRatableException'); + } + + parent::__construct($message, $code); + } + +} diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/actions/actions.class.php b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/actions/actions.class.php new file mode 100644 index 0000000..f3321f7 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/actions/actions.class.php @@ -0,0 +1,14 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsRatableBehaviorPlugin + */ +class sfRatingActions extends BasesfRatingActions +{ +} diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/actions/components.class.php b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/actions/components.class.php new file mode 100644 index 0000000..f546177 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/actions/components.class.php @@ -0,0 +1,34 @@ +object) + { + $total_ratings = $this->object->countRatings(); + $details = $this->object->getRatingDetails(true); + $full_details = array(); + foreach ($details as $rating => $nb_ratings) + { + if ($total_ratings > 0) + { + $percent = $nb_ratings / $total_ratings * 100; + } else $percent = 0; + $full_details[$rating] = array('count' => $nb_ratings, + 'percent' => $percent); + } + $this->rating_details = $full_details; + $this->object_type = get_class($this->object); + } + } + +} diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/lib/BasesfRatingActions.class.php b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/lib/BasesfRatingActions.class.php new file mode 100644 index 0000000..5b9ef5e --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/lib/BasesfRatingActions.class.php @@ -0,0 +1,123 @@ + + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsRatableBehaviorPlugin + */ +class BasesfRatingActions extends sfActions +{ + + /** + * Here we will initiate system messages translatable strings + * + */ + public function preExecute() + { + parent::preExecute(); + sfLoader::loadHelpers('I18N'); + $this->messages = array( + 'already_voted' => __('You have already voted'), + 'missing_params' => __('Parameters are missing to retrieve ratable object'), + 'post_only' => __('POST requests only'), + 'ratable_error' => __('Unable to retrieve ratable object: %s'), + 'thank_you' => __('Thank you for your vote'), + 'thank_you_update' => __('Thanks for updating your vote'), + 'user_error' => __('A problem has occured, sorry for the inconvenience'), + ); + } + + /** + *

    Rate a propel object. This action is typically executed from an AJAX + * request.

    + * + *

    You should override this method in your own exteends actions class if + * you need to associate current rating with a user.

    + * + * @see sfPropelActAsRatableBehavior API + * @link http://trac.symfony-project.com/trac/wiki/sfPropelActAsRatableBehaviorPlugin + */ + public function executeRate() + { + try + { + if ($this->getRequest()->getMethod() !== sfRequest::POST) + { + return $this->renderText($this->messages['post_only']); + } + + // Retrieve parameters from request + $token = $this->getRequestParameter('token'); + $rating = $this->getRequestParameter('rating'); + $star_width = $this->getRequestParameter('star_width', sfConfig::get('app_rating_star_width', 25)); + + // Retrieve ratable propel object + if (is_null($token) or is_null($rating)) + { + return $this->renderFatalError($this->messages['missing_params']); + } + + $object = sfPropelActAsRatableBehaviorToolkit::retrieveFromToken($token); + + if (is_null($object)) + { + return $this->renderFatalError($this->message['ratable_error']); + } + + // User retrieval + $user_id = sfPropelActAsRatableBehaviorToolkit::getUserId(); + if (is_null($user_id)) + { + // Votes are cookie based + $cookie_name = sprintf('%s_%s', sfConfig::get('app_rating_cookie_prefix', 'rating'), $token); + if (!is_null($this->getRequest()->getCookie($cookie_name))) + { + $message = $this->messages['already_voted']; + } + else + { + $object->setRating((int) $rating); + $cookie_ttl = sfConfig::get('app_rating_cookie_ttl', (86400*365*10)); + $cookie_expires = date('Y-m-d H:m:i', time() + $cookie_ttl); + $this->getResponse()->setCookie($cookie_name, (int)$rating, $cookie_expires); + $message = $this->messages['thank_you']; + } + } + else + { + $already_rated = $object->hasBeenRatedByUser($user_id); + $object->setRating((int) $rating, $user_id); + $message = $already_rated === true ? + $this->messages['thank_you_update'] : + $this->messages['thank_you']; + } + + $this->token = $token; + $this->rating = $object->getRating(); + $this->star_width = $star_width; + $this->message = $message; + } + catch (Exception $e) + { + return $this->renderFatalError($e->getMessage()); + } + } + + /** + * This methods will returns a basic user error message while logging a + * complete one if provided in the debug log file + * + * @param string $log_info Log information message + */ + protected function renderFatalError($log_info = null) + { + if (!is_null($log_info)) + { + sfLogger::getInstance()->warning('Rating error: '.$log_info); + } + return $this->renderText($this->messages['user_error']); + } + +} diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/templates/_ratingDetails.php b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/templates/_ratingDetails.php new file mode 100644 index 0000000..0be91f9 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/templates/_ratingDetails.php @@ -0,0 +1,18 @@ + + +getId() ?> + + $details): ?> + + + + + + +
    $rating)) ?> +
    +   +
    +
    ()
    + \ No newline at end of file diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/templates/rateSuccess.php b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/templates/rateSuccess.php new file mode 100644 index 0000000..2c38c25 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/modules/sfRating/templates/rateSuccess.php @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/test/unit/sfPropelActAsRatableBehaviorTest.php b/plugins/sfPropelActAsRatableBehaviorPlugin/test/unit/sfPropelActAsRatableBehaviorTest.php new file mode 100644 index 0000000..dd681d4 --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/test/unit/sfPropelActAsRatableBehaviorTest.php @@ -0,0 +1,217 @@ +initialize(); + $con = Propel::getConnection(); +} +catch (PropelException $e) +{ + $t->fail($e->getMessage()); + return 0; +} + +try +{ + $class = TEST_CLASS; + $method = TEST_METHOD; + $obj = new $class; + if (!method_exists($obj, TEST_METHOD)) + { + // Don't run tests at all + return; + } + $obj->$method('A test object'); + $obj->save(); + $obj2 = new $class; + $obj2->$method('Another test object'); + $obj2->save(); +} +catch (Exception $e) +{ + $t->fail($e->getMessage()); +} + +$obj_pk = $obj->getPrimaryKey(); +$t->ok(!is_null($obj_pk), 'getPrimaryKey() Test Object saved'); +$obj2_pk = $obj2->getPrimaryKey(); +$t->ok(!is_null($obj2_pk), 'getPrimaryKey() Other test Object saved'); + +// Override any existing max_rating parameter +sfConfig::set( + sprintf('propel_behavior_sfPropelActAsRatableBehavior_%s_max_rating', + get_class($obj)), 5); +$t->is($obj->getMaxRating(), 5, 'getMaxRating() retrieve correct value'); +sfConfig::set( + sprintf('propel_behavior_sfPropelActAsRatableBehavior_%s_max_rating', + get_class($obj)), 10); +$t->is($obj->getMaxRating(), 10, 'getMaxRating() retrieve correct value, even when changed'); + +$max_rating = $obj->getMaxRating(); +$t->isa_ok($max_rating, 'integer', 'getMaxRating() MAX_RATING is an integer'); + +$t->is($obj->getTitle(), 'A test object', 'getTitle() Object has been created'); +$t->is($obj->hasBeenRated(), false, 'hasBeenRated() Object has not been rated yet'); + +// Tests will be IP address based +$user_1_id = 1; +$user_2_id = 2; +$user_3_id = 3; + +$t->ok(!$obj->hasBeenRatedByUser($user_1_id), + 'hasBeenRatedByUser() Object has not been rated by user 1 yet'); + +# User 1 overrate object 1 +try +{ + $obj->setRating(11, $user_1_id); + $t->fail('setRating() It is possible to overrate an object :('); +} +catch (Exception $e) +{ + $t->pass('setRating() It is impossible to overrate an object'); +} + +# User 1 rate with a negative value +try +{ + $obj->setRating(-1, $user_1_id); + $t->fail('setRating() It is possible to underrate an object :('); +} +catch (Exception $e) +{ + $t->pass('setRating() It is impossible to underrate an object'); +} + +# User 1 rate with a string +try +{ + $obj->setRating('rototo', $user_1_id); + $t->fail('setRating() It is possible to misrate an object :('); +} +catch (Exception $e) +{ + $t->pass('setRating() It is impossible to misrate an object'); +} + +# User 1 rate object 1 correctly +$u1_rating = 10; +$t->ok($obj->setRating($u1_rating, $user_1_id), 'setRating() Object rated OK by user 1 to '.$u1_rating); +$t->ok($obj->hasBeenRated(), 'hasBeenRated() Object has been rated'); +$t->is($obj->hasBeenRatedByUser($user_1_id), true, 'hasBeenRatedByUser() Object has been rated by user 1'); +$t->is($obj->hasBeenRatedByUser($user_2_id), false, 'hasBeenRatedByUser() Object has not been rated by user 2 yet'); + +$t->is($obj->getRating(), $u1_rating, 'getRating() rating retrieval OK'); +$t->is($obj->getUserRating($user_1_id), $u1_rating, 'getUserRating() user rating retrieval OK'); + +# User 2 rate object 1 +$u2_rating = 5; +$t->ok($obj->setRating($u2_rating, $user_2_id), 'setRating() Object rated by user 2 to '.$u2_rating); +$t->ok($obj->hasBeenRated(), 'hasBeenRated() Object has been rated'); +$t->ok($obj->hasBeenRatedByUser($user_2_id), 'hasBeenRatedByUser() Object has been rated by user 2'); + +$t->is($obj->getRating(), 7.5, 'getRating() rating retrieval OK'); +$t->is($obj->getUserRating($user_2_id), $u2_rating, 'getUserRating() user rating retrieval OK'); + +# User 1 rates object 2 +$obj2->setRating(5, $user_1_id); +$t->is($obj2->getUserRating($user_1_id), 5, 'getUserRating() user rating retrieval OK'); +$t->is($obj2->getRating(), 5, 'getRating() rating ok'); +$obj2->clearRatings(); +$t->is($obj2->getRating(), null, 'clearRatings() clear rating ok'); + +# User 2 changes his rating for object 1 +$u2_rating = 8; +$t->ok($obj->setRating($u2_rating, $user_2_id), 'setRating() User 2 changes his rating to '.$u2_rating); +$t->ok($obj->hasBeenRatedByUser($user_2_id), 'hasBeenRatedByUser() Object is still rated by user 2'); + +$t->is($obj->getRating(), 9, 'getRating() rating retrieval = 9'); +$t->is($obj->getUserRating($user_2_id), $u2_rating, 'getUserRating() user rating retrieval OK'); + +# User 1 changes his rating +$u1_rating = 2; +$t->ok($obj->setRating($u1_rating, $user_1_id), 'setRating() User 1 changes his rating to '.$u1_rating); +$t->ok($obj->hasBeenRatedByUser($user_1_id), 'hasBeenRatedByUser() Object is still rated by user 1'); + +$t->is($obj->getRating(), 5, 'getRating() rating retrieval OK'); +$t->is($obj->getUserRating($user_1_id), $u1_rating, 'getUserRating() user rating retrieval OK'); + +# User 1 cancel his rating +$t->ok($obj->clearUserRating($user_2_id), 'cleanUserRating() User 2 cleans his rating'); +$t->ok(!$obj->hasBeenRatedByUser($user_2_id), 'hasBeenRatedByUser() Object has now not been rated by user 2'); +$t->is($obj->getRating(), $u1_rating, 'getRating() Object rating has been updated'); + +$t->ok($obj->clearRatings(), 'cleanRatings() All ratings are cleared'); +$t->is($obj->getRating(), NULL, 'getRating() Rating is now NULL for this object'); + +// Rating based on a 12 max rating +$obj->clearRatings(); +$obj2->clearRatings(); +sfConfig::set( + sprintf('propel_behavior_sfPropelActAsRatableBehavior_%s_max_rating', + get_class($obj)), 12); + +$obj->setRating(6, $user_1_id); +$obj->setRating(6, $user_2_id); +$t->is($obj->getRating(), 6, 'getRating() base12 ok'); +$obj->setRating(12, $user_2_id); +$t->is($obj->getRating(), 9, 'getRating() base12 ok'); +$obj->setRating(3, $user_1_id); +$t->is($obj->getRating(), 7.5, 'getRating() base12 ok'); + +// Testing ratings details retrieval +$obj->setRating(6, $user_1_id); +$obj->setRating(6, $user_2_id); +$obj->setRating(7, $user_3_id); +$details = $obj->getRatingDetails(); +$t->is(count($details), 2, 'getRatingDetails() count ok'); +$t->is_deeply($details, array(6 => 2, 7 => 1), 'getRatingDetails() results are conform'); + +$full_details = $obj->getRatingDetails(true); +$t->is(count($full_details), 12, 'getRatingDetails(true) count ok'); +$expected = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>2, 7=>1, 8=>0, 9=>0, 10=>0, 11=>0, 12=>0); +$t->is_deeply($full_details, $expected, 'getRatingDetails(true) results are conform'); + +// Testing cascade deletion +$obj_key = $obj->getPrimaryKey(); +$obj->delete(); +$c = new Criteria(); +$c->add(sfRatingPeer::RATABLE_ID, $obj_key); +$count = sfRatingPeer::doCount($c); +$t->is($count, 0, 'doCount() No more rating records for deleted object'); + +// Delete remaining object +$obj2->delete(); + +$t->diag('Tests are now terminated'); \ No newline at end of file diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/web/css/sf_rating.css b/plugins/sfPropelActAsRatableBehaviorPlugin/web/css/sf_rating.css new file mode 100644 index 0000000..2e1b00c --- /dev/null +++ b/plugins/sfPropelActAsRatableBehaviorPlugin/web/css/sf_rating.css @@ -0,0 +1,122 @@ +/** + * Based on http://komodomedia.com/blog/samples/star_rating/example2.htm + * Styles for the star rater + */ +table.rating_details_table td.sf_rating_bar_bg { + background: lightblue; +} + +table.rating_details_table div { + background: blue; +} + +.star-rating{ + list-style: none; + margin: 0; + padding: 0; + height: 25px; + position:relative; + overflow:hidden; + background: url(../images/alt_star.gif) top left repeat-x; +} +.star-rating li{ + padding: 0; + margin: 0; + width: 25px; + height: 25px; + /*\*/ + float: left; + /* */ +} +.star-rating li a{ + display: block; + width: 25px; + height: 25px; + line-height: 25px; + text-decoration: none; + text-indent: -9000px; + z-index: 20; + position: absolute; + padding: 0; + overflow: hidden; +} +.star-rating li a:hover{ + background: url(../images/alt_star.gif) left bottom; + z-index: 2; + left: 0; + border:none; +} +.star-rating a.r1star{ + left: 0; +} +.star-rating a.r1star:hover{ + width:25px; +} +.star-rating a.r2stars{ + left:25px; +} +.star-rating a.r2stars:hover{ + width: 50px; +} +.star-rating a.r3stars{ + left: 50px; +} +.star-rating a.r3stars:hover{ + width: 75px; +} +.star-rating a.r4stars{ + left: 75px; +} +.star-rating a.r4stars:hover{ + width: 100px; +} +.star-rating a.r5stars{ + left: 100px; +} +.star-rating a.r5stars:hover{ + width: 125px; +} +.star-rating a.r6stars{ + left: 125px; +} +.star-rating a.r6stars:hover{ + width: 150px; +} +.star-rating a.r7stars{ + left: 150px; +} +.star-rating a.r7stars:hover{ + width: 175px; +} +.star-rating a.r8stars{ + left: 175px; +} +.star-rating a.r8stars:hover{ + width: 200px; +} +.star-rating a.r9stars{ + left: 200px; +} +.star-rating a.r9stars:hover{ + width: 225px; +} +.star-rating a.r10stars{ + left: 225px; +} +.star-rating a.r10stars:hover{ + width: 250px; +} +.star-rating li.current-rating{ + background: url(/images/alt_star.gif) left center; + position: absolute; + height: 25px; + display: block; + text-indent: -9000px; + z-index: 1; + left:0px; +} + +/* remove halo effect in firefox */ +a:active{ + outline: none; +} diff --git a/plugins/sfPropelActAsRatableBehaviorPlugin/web/images/alt_star.gif b/plugins/sfPropelActAsRatableBehaviorPlugin/web/images/alt_star.gif new file mode 100644 index 0000000..068fa7f Binary files /dev/null and b/plugins/sfPropelActAsRatableBehaviorPlugin/web/images/alt_star.gif differ diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/LICENSE b/plugins/sfPropelActAsTaggableBehaviorPlugin/LICENSE new file mode 100644 index 0000000..d03e0bf --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2007 Xavier Lacot + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/README b/plugins/sfPropelActAsTaggableBehaviorPlugin/README new file mode 100644 index 0000000..48ff05b --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/README @@ -0,0 +1,281 @@ += sfPropelActAsTaggableBehaviorPlugin = + +== Introduction == +This behavior permits to attach tags to Propel objects. It includes tag-clouds generation and helpers to display these clouds. + +== Features == + + * add/remove tag(s) on an object + * multi-tags object search + * multi-models selection + * tag cloud generation + * related tags handling + * unit-tested + * [http://www.flickr.com/groups/api/discuss/72157594497877875/ machine tags] support (also called "triple tags") + +== Philosophy of the stuff == + + * taggable objects must have a primary key + * tags are saved when the object is saved, not before + * one object cannot be tagged twice with the same tag. When trying to use twice the same tag on one object, the second tagging will be ignored + * the tags associated to one taggable object are only loaded when necessary. Then they are cached. + * once created, tags never change in the Tag table. When using replaceTag(), a new tag is created id necessary, but the old one is not deleted. + +== Get it installed == + + * go to your project's root + + * Install the plugin: + {{{ + ./symfony plugin-install http://plugins.symfony-project.com/sfPropelActAsTaggableBehaviorPlugin + }}} + + * if not already done, enabled behaviors in config/propel.ini: + {{{ + propel.builder.addBehaviors = true + }}} + + * edit the classes that you want to make taggable. For instance, for lib/model/Post.php: + {{{ + #!php + addTag('toto'); +$post->addTag('tata, tutu'); +$post->addTag(array('Titi', 'Gros Minet')); +$post->save(); +}}} + +Since the version 0.4, the plugin supports [http://www.flickr.com/groups/api/discuss/72157594497877875/ machine tags]: +{{{ +#!php +addTag('iso:isbn=123456789'); + +// assume City is a taggable class +$city = new City(); +$city->addTag('geo:lat=47.3456'); +}}} + +=== Retrieving one object's tags === +It is possible to retrieve tags from a taggable object: +{{{ +#!php +getTags(); + +foreach ($tags as $tag) +{ + echo $tag.'
    '; +} +}}} + +=== Removing one object's tags === +Of course, tags can also be removed: +{{{ +#!php +removeTag('toto'); +$post->removeTag('toto, tutu'); +$post->removeAllTags(); +}}} + +=== Tags cloud generation === +The plugin also proposes methods and helpers for generating tags cloud: +{{{ +#!php + 'Post')); + +// displays the related tags cloud, using the route "@post_tags" with the +// request parameter "tags" +echo related_tag_cloud($tags, '@post_tags?tags=', 'toto,tutu'); +}}} + +=== Specialize your tag clouds === +The tag retrieval mecanism is fully based on Criterias, so it is easy to pass +several restrictions. For instance, for retrieving popular tags over posts +created in March 2007: +{{{ +#!php +addJoin(PostPeer::ID, TaggingPeer::TAGGABLE_ID); +$c->add(PostPeer::CREATED_AT, '2007-03%', Criteria::LIKE); +$tags = TagPeer::getPopulars($c, array('model' => 'Post')); +echo tag_cloud($tags, '@tag?tags='); +}}} + +The methods TagPeer::getPopulars, TagPeer::getAll, etc., accept as last +parameter an array with several keys: + * max number of returned tags: +{{{ +#!php + 200)); +}}} + * tag name restriction: +{{{ +#!php + 'to%')); +}}} + * whether the returned tags should be machine tags, or not: +{{{ +#!php + true)); +}}} + * for triple tags, it is possible to restrict the returned tags from their namespace, key, and value: +{{{ +#!php + true, 'namespace' => 'geo')); + +// returns only triple tags with teh key "lat" +$lat_tags = TagPeer::getAll(null, array('triple' => true, 'key' => 'lat')); + +// returns only triple tags with teh value "12" +$value_tags = TagPeer::getAll(null, array('triple' => true, 'value' => '12')); +}}} + +=== Avoid performance problems === +In case you want to display a long list of taggable objects with their associated tags, you might want first to preload these objects's tags: it avoids to load tags per object, and gets all tags in a few requests. +{{{ +#!php + 'Post')); +sfPropelActAsTaggableBehavior::preloadTags($posts); + +foreach ($posts as $post) +{ + echo $post-getTitle(); + + // won't require one request at each loop, as tags have been preloaded. + var_dump($post-getTags()); +} +}}} + +== Plugin internals == +The plugin associates a parameterHolder to Propel objects, with 3 disjoin namespaces: + * '''tags''': tags that have been attached to the object, but not yet saved. Contract: tags are disjoin of (saved_tags union removed_tags) + * '''saved_tags''': tags that are presently saved in the database. Contract: removed_tags are disjoin of (tags union saved_tags) + * '''removed_tags''': tags that are presently saved in the database, but which will be removed at the next save(). Contract: removed_tags are disjoin of (tags union saved_tags) + +When required, the saved_tags namespace is filled with the tags previously present in the database. The tagging methods have an action on these three namespaces, which are serialized in the database after the Propel object gets saved. + +=== What is done when adding a tag ? === + * if the tag is present in the "removed_tags" namespace, the tagging request is interpreted as a tag-removal revert. The tag is then deleted front the "removed_tags" request, and brought back into "saved_tags". + * else, if the tag is not present in the "saved_tags" namespace, add it to the "tags" one. + +=== What is done when removing a tag ? === + * if the tag has not yet been saved, simply remove it from the "tags" namespace. + * if he has been saved, remove it from the "saved_tags" namespace, and add it to the "removed_tags" one. + +== API == +The behavior implement the following methods: + * '''addTag($tagname)''' - Adds one or several tags to an object + * '''getTags()''' - Returns the list of the tags attached to the object + * '''hasTag($tag = null)''' - Returns true if the object has a tag. If a tag ar an array of tags is passed in second parameter, checks if these tags are attached to the object + * '''removeTag($tagname)''' - Removes a tag or a set of tags from the object. + * '''replaceTag($tagname, $replacement = null)''' - Replaces a tag with an other one. + +The behavior class also implement the following method, which is a facility for preloading all the tags for a set of taggable objects + * '''preloadTags($objects)''' - Preload tags for a set of objects + +== Unit testing == +The plugin has been deeply unit-tested, if not fully. The tests are located in test/unit/sfPropelActAsTaggableBehaviorTest.php. If you want to run them: + * install the plugin + * configure a model for using it, for instance "Post" + * copy the test file to /path/to/your/project/test/unit/sfPropelActAsTaggableBehaviorTest.php + * edit this file and modify line 3: + {{{ + define('TEST_CLASS', 'Post'); + }}} + * run the tests: + {{{ + ./symfony test-unit sfPropelActAsTaggableBehavior + }}} + +== License and credits == +This plugin has been developed by [http://lacot.org/blog Xavier Lacot] and is licensed under the MIT license. Thanks to Tristan Rivoallan for the help provided. + +== Changelog == + +=== version 0.4 - 2007-12-11 === + * added machine tags support (also called "triple tags") (thanks to Michael Nolan) + +=== version 0.3 - 2007-07-02 === + * fixed bug in tags removal (thanks Alexander Alexandrov) + +=== version 0.2 - 2007-06-27 === + * indexes on tags model + * bugfixes + * thanks to Nicolas Perriault for his useful comments + +=== version 0.1 - 2007-05-22 === +Initial public release. Features tags attachment to heterogene Propel objects, and includes tag-clouds generation. \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/config/config.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/config/config.php new file mode 100644 index 0000000..2c8b85c --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/config/config.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +sfPropelBehavior::registerHooks('sfPropelActAsTaggableBehavior', array ( + ':save:post' => array ('sfPropelActAsTaggableBehavior', 'postSave'), +)); + + +sfPropelBehavior::registerMethods('sfPropelActAsTaggableBehavior', array ( + array ( + 'sfPropelActAsTaggableBehavior', + 'addTag' + ), + array ( + 'sfPropelActAsTaggableBehavior', + 'getTags' + ), + array ( + 'sfPropelActAsTaggableBehavior', + 'hasTag' + ), + array ( + 'sfPropelActAsTaggableBehavior', + 'removeAllTags' + ), + array ( + 'sfPropelActAsTaggableBehavior', + 'removeTag' + ), + array ( + 'sfPropelActAsTaggableBehavior', + 'replaceTag' + ), +)); \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/config/schema.yml b/plugins/sfPropelActAsTaggableBehaviorPlugin/config/schema.yml new file mode 100644 index 0000000..5497c03 --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/config/schema.yml @@ -0,0 +1,18 @@ +propel: + _attributes: { package: plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model } + + tag: + _attributes: { phpName: Tag, package: plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model } + id: { phpName: ID, type: integer, required: true, primaryKey: true, autoincrement: true } + name: varchar(100) + _indexes: + name: [name] + tagging: + _attributes: { phpName: Tagging, package: plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model } + id: { phpName: ID, type: integer, required: true, primaryKey: true, autoincrement: true } + tag_id: varchar(100) + taggable_model: varchar(30) + taggable_id: integer + _indexes: + tag: [tag_id] + taggable: [taggable_model, taggable_id] \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/helper/TagsHelper.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/helper/TagsHelper.php new file mode 100644 index 0000000..4c25508 --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/helper/TagsHelper.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +function tag_cloud($tags, $route, $options = array(), $title = '') +{ + $result = ''; + if ($title != '') + { + $result .= '

    ' . $title . '

    '; + } + + if(count($tags) > 0) + { + $emphasizers_begin = array(-2 => '', + -1 => '', + 0 => '', + 1 => '', + 2 => ''); + $emphasizers_end = array(-2 => '', + -1 => '', + 0 => '', + 1 => '', + 2 => ''); + + $class = isset($options['class']) ? $options['class'] : 'tag-cloud'; + $result .= '
      '; + + foreach ($tags as $name => $count) + { + $link = reaktor_link_to($name, + $route.$name, + array('rel' => 'tag')); + + $result .= ' +
    • '.$emphasizers_begin[$count].$link.$emphasizers_end[$count].'
    • '; + } + + $result .= '
    '; + } + + return $result; +} + +function tag_list($tags, $route, $options = array()) +{ + $result = ''; + + if (count($tags) > 0) + { + $class = isset($options['class']) ? $options['class'] : 'tags-list'; + $result = '
      '; + + foreach ($tags as $tag) + { + $link = link_to($tag, + $route.$tag, + array('rel' => 'tag')); + + $result .= ' +
    • '.$link.'
    • '; + } + + $result .= '
    '; + } + + return $result; +} + +function related_tag_cloud($tags, $route, $tag, $options = array()) +{ + $result = ''; + + if(count($tags) > 0) + { + if (is_array($tag)) + { + $tag = implode(',', $tag); + } + + $emphasizers_begin = array(-2 => '', + -1 => '', + 0 => '', + 1 => '', + 2 => ''); + $emphasizers_end = array(-2 => '', + -1 => '', + 0 => '', + 1 => '', + 2 => ''); + + $add = isset($options['add']) ? $options['add'] : '(+)'; + $class = isset($options['class']) ? $options['class'] : 'tag-cloud'; + $result = '
      '; + + foreach ($tags as $name => $count) + { + $link = link_to($name, + $route.$name, + array('rel' => 'tag')); + $related_link = link_to($add, + $route.$tag.','.$name); + + $result .= ' +
    • '.$emphasizers_begin[$count] + .$link.' ' + .$related_link.$emphasizers_end[$count] + .'
    • '; + } + + $result .= '
    '; + } + + return $result; +} \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tag.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tag.php new file mode 100644 index 0000000..a21a58c --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tag.php @@ -0,0 +1,30 @@ +getName(); + } +} diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TagPeer.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TagPeer.php new file mode 100644 index 0000000..f4f3157 --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/TagPeer.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Subclass for performing query and update operations on the 'tag' table. + * + * @package plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model + */ +class TagPeer extends BaseTagPeer +{ + // All this ovverriden in lib/model/TagPeer.php +} \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tagging.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tagging.php new file mode 100644 index 0000000..d646444 --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/Tagging.php @@ -0,0 +1,12 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('tag'); + $tMap->setPhpName('Tag'); + + $tMap->setUseIdGenerator(true); + + $tMap->addPrimaryKey('ID', 'ID', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addColumn('NAME', 'Name', 'string', CreoleTypes::VARCHAR, false, 100); + + $tMap->addColumn('APPROVED', 'Approved', 'int', CreoleTypes::TINYINT, true, null); + + $tMap->addForeignKey('APPROVED_BY', 'ApprovedBy', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', false, null); + + $tMap->addColumn('APPROVED_AT', 'ApprovedAt', 'int', CreoleTypes::TIMESTAMP, false, null); + + $tMap->addColumn('WIDTH', 'Width', 'int', CreoleTypes::INTEGER, false, null); + + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TaggingMapBuilder.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TaggingMapBuilder.php new file mode 100644 index 0000000..5c5c8d5 --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TaggingMapBuilder.php @@ -0,0 +1,48 @@ +dbMap !== null); + } + + + public function getDatabaseMap() + { + return $this->dbMap; + } + + + public function doBuild() + { + $this->dbMap = Propel::getDatabaseMap('propel'); + + $tMap = $this->dbMap->addTable('tagging'); + $tMap->setPhpName('Tagging'); + + $tMap->setUseIdGenerator(true); + + $tMap->addPrimaryKey('ID', 'ID', 'int', CreoleTypes::INTEGER, true, null); + + $tMap->addForeignKey('TAG_ID', 'TagId', 'int', CreoleTypes::INTEGER, 'tag', 'ID', true, null); + + $tMap->addColumn('TAGGABLE_MODEL', 'TaggableModel', 'string', CreoleTypes::VARCHAR, false, 30); + + $tMap->addColumn('TAGGABLE_ID', 'TaggableId', 'int', CreoleTypes::INTEGER, false, null); + + $tMap->addColumn('PARENT_APPROVED', 'ParentApproved', 'int', CreoleTypes::TINYINT, true, null); + + $tMap->addForeignKey('PARENT_USER_ID', 'ParentUserId', 'int', CreoleTypes::INTEGER, 'sf_guard_user', 'ID', true, null); + + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTag.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTag.php new file mode 100644 index 0000000..c973b6f --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTag.php @@ -0,0 +1,735 @@ +id; + } + + + public function getName() + { + + return $this->name; + } + + + public function getApproved() + { + + return $this->approved; + } + + + public function getApprovedBy() + { + + return $this->approved_by; + } + + + public function getApprovedAt($format = 'Y-m-d H:i:s') + { + + if ($this->approved_at === null || $this->approved_at === '') { + return null; + } elseif (!is_int($this->approved_at)) { + $ts = strtotime($this->approved_at); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse value of [approved_at] as date/time value: " . var_export($this->approved_at, true)); + } + } else { + $ts = $this->approved_at; + } + if ($format === null) { + return $ts; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $ts); + } else { + return date($format, $ts); + } + } + + + public function getWidth() + { + + return $this->width; + } + + + public function setID($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = TagPeer::ID; + } + + } + + public function setName($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->name !== $v) { + $this->name = $v; + $this->modifiedColumns[] = TagPeer::NAME; + } + + } + + public function setApproved($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->approved !== $v || $v === 0) { + $this->approved = $v; + $this->modifiedColumns[] = TagPeer::APPROVED; + } + + } + + public function setApprovedBy($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->approved_by !== $v) { + $this->approved_by = $v; + $this->modifiedColumns[] = TagPeer::APPROVED_BY; + } + + if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) { + $this->asfGuardUser = null; + } + + } + + public function setApprovedAt($v) + { + + if ($v !== null && !is_int($v)) { + $ts = strtotime($v); + if ($ts === -1 || $ts === false) { throw new PropelException("Unable to parse date/time value for [approved_at] from input: " . var_export($v, true)); + } + } else { + $ts = $v; + } + if ($this->approved_at !== $ts) { + $this->approved_at = $ts; + $this->modifiedColumns[] = TagPeer::APPROVED_AT; + } + + } + + public function setWidth($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->width !== $v) { + $this->width = $v; + $this->modifiedColumns[] = TagPeer::WIDTH; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->id = $rs->getInt($startcol + 0); + + $this->name = $rs->getString($startcol + 1); + + $this->approved = $rs->getInt($startcol + 2); + + $this->approved_by = $rs->getInt($startcol + 3); + + $this->approved_at = $rs->getTimestamp($startcol + 4, null); + + $this->width = $rs->getInt($startcol + 5); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 6; + } catch (Exception $e) { + throw new PropelException("Error populating Tag object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BaseTag:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(TagPeer::DATABASE_NAME); + } + + try { + $con->begin(); + TagPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BaseTag:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BaseTag:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(TagPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BaseTag:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->asfGuardUser !== null) { + if ($this->asfGuardUser->isModified()) { + $affectedRows += $this->asfGuardUser->save($con); + } + $this->setsfGuardUser($this->asfGuardUser); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = TagPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setID($pk); + $this->setNew(false); + } else { + $affectedRows += TagPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + if ($this->collTaggings !== null) { + foreach($this->collTaggings as $referrerFK) { + if (!$referrerFK->isDeleted()) { + $affectedRows += $referrerFK->save($con); + } + } + } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->asfGuardUser !== null) { + if (!$this->asfGuardUser->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures()); + } + } + + + if (($retval = TagPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + if ($this->collTaggings !== null) { + foreach($this->collTaggings as $referrerFK) { + if (!$referrerFK->validate($columns)) { + $failureMap = array_merge($failureMap, $referrerFK->getValidationFailures()); + } + } + } + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = TagPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getID(); + break; + case 1: + return $this->getName(); + break; + case 2: + return $this->getApproved(); + break; + case 3: + return $this->getApprovedBy(); + break; + case 4: + return $this->getApprovedAt(); + break; + case 5: + return $this->getWidth(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = TagPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getID(), + $keys[1] => $this->getName(), + $keys[2] => $this->getApproved(), + $keys[3] => $this->getApprovedBy(), + $keys[4] => $this->getApprovedAt(), + $keys[5] => $this->getWidth(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = TagPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setID($value); + break; + case 1: + $this->setName($value); + break; + case 2: + $this->setApproved($value); + break; + case 3: + $this->setApprovedBy($value); + break; + case 4: + $this->setApprovedAt($value); + break; + case 5: + $this->setWidth($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = TagPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setID($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setName($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setApproved($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setApprovedBy($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setApprovedAt($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setWidth($arr[$keys[5]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(TagPeer::DATABASE_NAME); + + if ($this->isColumnModified(TagPeer::ID)) $criteria->add(TagPeer::ID, $this->id); + if ($this->isColumnModified(TagPeer::NAME)) $criteria->add(TagPeer::NAME, $this->name); + if ($this->isColumnModified(TagPeer::APPROVED)) $criteria->add(TagPeer::APPROVED, $this->approved); + if ($this->isColumnModified(TagPeer::APPROVED_BY)) $criteria->add(TagPeer::APPROVED_BY, $this->approved_by); + if ($this->isColumnModified(TagPeer::APPROVED_AT)) $criteria->add(TagPeer::APPROVED_AT, $this->approved_at); + if ($this->isColumnModified(TagPeer::WIDTH)) $criteria->add(TagPeer::WIDTH, $this->width); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(TagPeer::DATABASE_NAME); + + $criteria->add(TagPeer::ID, $this->id); + + return $criteria; + } + + + public function getPrimaryKey() + { + return $this->getID(); + } + + + public function setPrimaryKey($key) + { + $this->setID($key); + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setName($this->name); + + $copyObj->setApproved($this->approved); + + $copyObj->setApprovedBy($this->approved_by); + + $copyObj->setApprovedAt($this->approved_at); + + $copyObj->setWidth($this->width); + + + if ($deepCopy) { + $copyObj->setNew(false); + + foreach($this->getTaggings() as $relObj) { + $copyObj->addTagging($relObj->copy($deepCopy)); + } + + } + + $copyObj->setNew(true); + + $copyObj->setID(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new TagPeer(); + } + return self::$peer; + } + + + public function setsfGuardUser($v) + { + + + if ($v === null) { + $this->setApprovedBy(NULL); + } else { + $this->setApprovedBy($v->getId()); + } + + + $this->asfGuardUser = $v; + } + + + + public function getsfGuardUser($con = null) + { + if ($this->asfGuardUser === null && ($this->approved_by !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php'; + + $this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->approved_by, $con); + + + } + return $this->asfGuardUser; + } + + + public function initTaggings() + { + if ($this->collTaggings === null) { + $this->collTaggings = array(); + } + } + + + public function getTaggings($criteria = null, $con = null) + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collTaggings === null) { + if ($this->isNew()) { + $this->collTaggings = array(); + } else { + + $criteria->add(TaggingPeer::TAG_ID, $this->getID()); + + TaggingPeer::addSelectColumns($criteria); + $this->collTaggings = TaggingPeer::doSelect($criteria, $con); + } + } else { + if (!$this->isNew()) { + + + $criteria->add(TaggingPeer::TAG_ID, $this->getID()); + + TaggingPeer::addSelectColumns($criteria); + if (!isset($this->lastTaggingCriteria) || !$this->lastTaggingCriteria->equals($criteria)) { + $this->collTaggings = TaggingPeer::doSelect($criteria, $con); + } + } + } + $this->lastTaggingCriteria = $criteria; + return $this->collTaggings; + } + + + public function countTaggings($criteria = null, $distinct = false, $con = null) + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + $criteria->add(TaggingPeer::TAG_ID, $this->getID()); + + return TaggingPeer::doCount($criteria, $distinct, $con); + } + + + public function addTagging(Tagging $l) + { + $this->collTaggings[] = $l; + $l->setTag($this); + } + + + + public function getTaggingsJoinsfGuardUser($criteria = null, $con = null) + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php'; + if ($criteria === null) { + $criteria = new Criteria(); + } + elseif ($criteria instanceof Criteria) + { + $criteria = clone $criteria; + } + + if ($this->collTaggings === null) { + if ($this->isNew()) { + $this->collTaggings = array(); + } else { + + $criteria->add(TaggingPeer::TAG_ID, $this->getID()); + + $this->collTaggings = TaggingPeer::doSelectJoinsfGuardUser($criteria, $con); + } + } else { + + $criteria->add(TaggingPeer::TAG_ID, $this->getID()); + + if (!isset($this->lastTaggingCriteria) || !$this->lastTaggingCriteria->equals($criteria)) { + $this->collTaggings = TaggingPeer::doSelectJoinsfGuardUser($criteria, $con); + } + } + $this->lastTaggingCriteria = $criteria; + + return $this->collTaggings; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BaseTag:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BaseTag::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagPeer.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagPeer.php new file mode 100644 index 0000000..b84a00c --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagPeer.php @@ -0,0 +1,592 @@ + array ('ID', 'Name', 'Approved', 'ApprovedBy', 'ApprovedAt', 'Width', ), + BasePeer::TYPE_COLNAME => array (TagPeer::ID, TagPeer::NAME, TagPeer::APPROVED, TagPeer::APPROVED_BY, TagPeer::APPROVED_AT, TagPeer::WIDTH, ), + BasePeer::TYPE_FIELDNAME => array ('id', 'name', 'approved', 'approved_by', 'approved_at', 'width', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('ID' => 0, 'Name' => 1, 'Approved' => 2, 'ApprovedBy' => 3, 'ApprovedAt' => 4, 'Width' => 5, ), + BasePeer::TYPE_COLNAME => array (TagPeer::ID => 0, TagPeer::NAME => 1, TagPeer::APPROVED => 2, TagPeer::APPROVED_BY => 3, TagPeer::APPROVED_AT => 4, TagPeer::WIDTH => 5, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'name' => 1, 'approved' => 2, 'approved_by' => 3, 'approved_at' => 4, 'width' => 5, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TagMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model.map.TagMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = TagPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(TagPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(TagPeer::ID); + + $criteria->addSelectColumn(TagPeer::NAME); + + $criteria->addSelectColumn(TagPeer::APPROVED); + + $criteria->addSelectColumn(TagPeer::APPROVED_BY); + + $criteria->addSelectColumn(TagPeer::APPROVED_AT); + + $criteria->addSelectColumn(TagPeer::WIDTH); + + } + + const COUNT = 'COUNT(tag.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT tag.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TagPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TagPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = TagPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = TagPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return TagPeer::populateObjects(TagPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BaseTagPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BaseTagPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + TagPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = TagPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TagPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TagPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(TagPeer::APPROVED_BY, sfGuardUserPeer::ID); + + $rs = TagPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + TagPeer::addSelectColumns($c); + $startcol = (TagPeer::NUM_COLUMNS - TagPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardUserPeer::addSelectColumns($c); + + $c->addJoin(TagPeer::APPROVED_BY, sfGuardUserPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = TagPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addTag($obj1); break; + } + } + if ($newObject) { + $obj2->initTags(); + $obj2->addTag($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TagPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TagPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(TagPeer::APPROVED_BY, sfGuardUserPeer::ID); + + $rs = TagPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + TagPeer::addSelectColumns($c); + $startcol2 = (TagPeer::NUM_COLUMNS - TagPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardUserPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS; + + $c->addJoin(TagPeer::APPROVED_BY, sfGuardUserPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = TagPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addTag($obj1); break; + } + } + + if ($newObject) { + $obj2->initTags(); + $obj2->addTag($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return TagPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BaseTagPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BaseTagPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + $criteria->remove(TagPeer::ID); + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BaseTagPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BaseTagPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BaseTagPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BaseTagPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(TagPeer::ID); + $selectCriteria->add(TagPeer::ID, $criteria->remove(TagPeer::ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BaseTagPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BaseTagPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(TagPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(TagPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof Tag) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + $criteria->add(TagPeer::ID, (array) $values, Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(Tag $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(TagPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(TagPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(TagPeer::DATABASE_NAME, TagPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = TagPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK($pk, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $criteria = new Criteria(TagPeer::DATABASE_NAME); + + $criteria->add(TagPeer::ID, $pk); + + + $v = TagPeer::doSelect($criteria, $con); + + return !empty($v) > 0 ? $v[0] : null; + } + + + public static function retrieveByPKs($pks, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $objs = null; + if (empty($pks)) { + $objs = array(); + } else { + $criteria = new Criteria(); + $criteria->add(TagPeer::ID, $pks, Criteria::IN); + $objs = TagPeer::doSelect($criteria, $con); + } + return $objs; + } + +} +if (Propel::isInit()) { + try { + BaseTagPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TagMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model.map.TagMapBuilder'); +} diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagging.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagging.php new file mode 100644 index 0000000..a12c610 --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagging.php @@ -0,0 +1,632 @@ +id; + } + + + public function getTagId() + { + + return $this->tag_id; + } + + + public function getTaggableModel() + { + + return $this->taggable_model; + } + + + public function getTaggableId() + { + + return $this->taggable_id; + } + + + public function getParentApproved() + { + + return $this->parent_approved; + } + + + public function getParentUserId() + { + + return $this->parent_user_id; + } + + + public function setID($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->id !== $v) { + $this->id = $v; + $this->modifiedColumns[] = TaggingPeer::ID; + } + + } + + public function setTagId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->tag_id !== $v) { + $this->tag_id = $v; + $this->modifiedColumns[] = TaggingPeer::TAG_ID; + } + + if ($this->aTag !== null && $this->aTag->getID() !== $v) { + $this->aTag = null; + } + + } + + public function setTaggableModel($v) + { + + + + if ($v !== null && !is_string($v)) { + $v = (string) $v; + } + + if ($this->taggable_model !== $v) { + $this->taggable_model = $v; + $this->modifiedColumns[] = TaggingPeer::TAGGABLE_MODEL; + } + + } + + public function setTaggableId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->taggable_id !== $v) { + $this->taggable_id = $v; + $this->modifiedColumns[] = TaggingPeer::TAGGABLE_ID; + } + + } + + public function setParentApproved($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->parent_approved !== $v || $v === 0) { + $this->parent_approved = $v; + $this->modifiedColumns[] = TaggingPeer::PARENT_APPROVED; + } + + } + + public function setParentUserId($v) + { + + + + if ($v !== null && !is_int($v) && is_numeric($v)) { + $v = (int) $v; + } + + if ($this->parent_user_id !== $v) { + $this->parent_user_id = $v; + $this->modifiedColumns[] = TaggingPeer::PARENT_USER_ID; + } + + if ($this->asfGuardUser !== null && $this->asfGuardUser->getId() !== $v) { + $this->asfGuardUser = null; + } + + } + + public function hydrate(ResultSet $rs, $startcol = 1) + { + try { + + $this->id = $rs->getInt($startcol + 0); + + $this->tag_id = $rs->getInt($startcol + 1); + + $this->taggable_model = $rs->getString($startcol + 2); + + $this->taggable_id = $rs->getInt($startcol + 3); + + $this->parent_approved = $rs->getInt($startcol + 4); + + $this->parent_user_id = $rs->getInt($startcol + 5); + + $this->resetModified(); + + $this->setNew(false); + + return $startcol + 6; + } catch (Exception $e) { + throw new PropelException("Error populating Tagging object", $e); + } + } + + + public function delete($con = null) + { + + foreach (sfMixer::getCallables('BaseTagging:delete:pre') as $callable) + { + $ret = call_user_func($callable, $this, $con); + if ($ret) + { + return; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("This object has already been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(TaggingPeer::DATABASE_NAME); + } + + try { + $con->begin(); + TaggingPeer::doDelete($this, $con); + $this->setDeleted(true); + $con->commit(); + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BaseTagging:delete:post') as $callable) + { + call_user_func($callable, $this, $con); + } + + } + + public function save($con = null) + { + + foreach (sfMixer::getCallables('BaseTagging:save:pre') as $callable) + { + $affectedRows = call_user_func($callable, $this, $con); + if (is_int($affectedRows)) + { + return $affectedRows; + } + } + + + if ($this->isDeleted()) { + throw new PropelException("You cannot save an object that has been deleted."); + } + + if ($con === null) { + $con = Propel::getConnection(TaggingPeer::DATABASE_NAME); + } + + try { + $con->begin(); + $affectedRows = $this->doSave($con); + $con->commit(); + foreach (sfMixer::getCallables('BaseTagging:save:post') as $callable) + { + call_user_func($callable, $this, $con, $affectedRows); + } + + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + protected function doSave($con) + { + $affectedRows = 0; if (!$this->alreadyInSave) { + $this->alreadyInSave = true; + + + + if ($this->aTag !== null) { + if ($this->aTag->isModified()) { + $affectedRows += $this->aTag->save($con); + } + $this->setTag($this->aTag); + } + + if ($this->asfGuardUser !== null) { + if ($this->asfGuardUser->isModified()) { + $affectedRows += $this->asfGuardUser->save($con); + } + $this->setsfGuardUser($this->asfGuardUser); + } + + + if ($this->isModified()) { + if ($this->isNew()) { + $pk = TaggingPeer::doInsert($this, $con); + $affectedRows += 1; + $this->setID($pk); + $this->setNew(false); + } else { + $affectedRows += TaggingPeer::doUpdate($this, $con); + } + $this->resetModified(); } + + $this->alreadyInSave = false; + } + return $affectedRows; + } + + protected $validationFailures = array(); + + + public function getValidationFailures() + { + return $this->validationFailures; + } + + + public function validate($columns = null) + { + $res = $this->doValidate($columns); + if ($res === true) { + $this->validationFailures = array(); + return true; + } else { + $this->validationFailures = $res; + return false; + } + } + + + protected function doValidate($columns = null) + { + if (!$this->alreadyInValidation) { + $this->alreadyInValidation = true; + $retval = null; + + $failureMap = array(); + + + + if ($this->aTag !== null) { + if (!$this->aTag->validate($columns)) { + $failureMap = array_merge($failureMap, $this->aTag->getValidationFailures()); + } + } + + if ($this->asfGuardUser !== null) { + if (!$this->asfGuardUser->validate($columns)) { + $failureMap = array_merge($failureMap, $this->asfGuardUser->getValidationFailures()); + } + } + + + if (($retval = TaggingPeer::doValidate($this, $columns)) !== true) { + $failureMap = array_merge($failureMap, $retval); + } + + + + $this->alreadyInValidation = false; + } + + return (!empty($failureMap) ? $failureMap : true); + } + + + public function getByName($name, $type = BasePeer::TYPE_PHPNAME) + { + $pos = TaggingPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->getByPosition($pos); + } + + + public function getByPosition($pos) + { + switch($pos) { + case 0: + return $this->getID(); + break; + case 1: + return $this->getTagId(); + break; + case 2: + return $this->getTaggableModel(); + break; + case 3: + return $this->getTaggableId(); + break; + case 4: + return $this->getParentApproved(); + break; + case 5: + return $this->getParentUserId(); + break; + default: + return null; + break; + } } + + + public function toArray($keyType = BasePeer::TYPE_PHPNAME) + { + $keys = TaggingPeer::getFieldNames($keyType); + $result = array( + $keys[0] => $this->getID(), + $keys[1] => $this->getTagId(), + $keys[2] => $this->getTaggableModel(), + $keys[3] => $this->getTaggableId(), + $keys[4] => $this->getParentApproved(), + $keys[5] => $this->getParentUserId(), + ); + return $result; + } + + + public function setByName($name, $value, $type = BasePeer::TYPE_PHPNAME) + { + $pos = TaggingPeer::translateFieldName($name, $type, BasePeer::TYPE_NUM); + return $this->setByPosition($pos, $value); + } + + + public function setByPosition($pos, $value) + { + switch($pos) { + case 0: + $this->setID($value); + break; + case 1: + $this->setTagId($value); + break; + case 2: + $this->setTaggableModel($value); + break; + case 3: + $this->setTaggableId($value); + break; + case 4: + $this->setParentApproved($value); + break; + case 5: + $this->setParentUserId($value); + break; + } } + + + public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME) + { + $keys = TaggingPeer::getFieldNames($keyType); + + if (array_key_exists($keys[0], $arr)) $this->setID($arr[$keys[0]]); + if (array_key_exists($keys[1], $arr)) $this->setTagId($arr[$keys[1]]); + if (array_key_exists($keys[2], $arr)) $this->setTaggableModel($arr[$keys[2]]); + if (array_key_exists($keys[3], $arr)) $this->setTaggableId($arr[$keys[3]]); + if (array_key_exists($keys[4], $arr)) $this->setParentApproved($arr[$keys[4]]); + if (array_key_exists($keys[5], $arr)) $this->setParentUserId($arr[$keys[5]]); + } + + + public function buildCriteria() + { + $criteria = new Criteria(TaggingPeer::DATABASE_NAME); + + if ($this->isColumnModified(TaggingPeer::ID)) $criteria->add(TaggingPeer::ID, $this->id); + if ($this->isColumnModified(TaggingPeer::TAG_ID)) $criteria->add(TaggingPeer::TAG_ID, $this->tag_id); + if ($this->isColumnModified(TaggingPeer::TAGGABLE_MODEL)) $criteria->add(TaggingPeer::TAGGABLE_MODEL, $this->taggable_model); + if ($this->isColumnModified(TaggingPeer::TAGGABLE_ID)) $criteria->add(TaggingPeer::TAGGABLE_ID, $this->taggable_id); + if ($this->isColumnModified(TaggingPeer::PARENT_APPROVED)) $criteria->add(TaggingPeer::PARENT_APPROVED, $this->parent_approved); + if ($this->isColumnModified(TaggingPeer::PARENT_USER_ID)) $criteria->add(TaggingPeer::PARENT_USER_ID, $this->parent_user_id); + + return $criteria; + } + + + public function buildPkeyCriteria() + { + $criteria = new Criteria(TaggingPeer::DATABASE_NAME); + + $criteria->add(TaggingPeer::ID, $this->id); + + return $criteria; + } + + + public function getPrimaryKey() + { + return $this->getID(); + } + + + public function setPrimaryKey($key) + { + $this->setID($key); + } + + + public function copyInto($copyObj, $deepCopy = false) + { + + $copyObj->setTagId($this->tag_id); + + $copyObj->setTaggableModel($this->taggable_model); + + $copyObj->setTaggableId($this->taggable_id); + + $copyObj->setParentApproved($this->parent_approved); + + $copyObj->setParentUserId($this->parent_user_id); + + + $copyObj->setNew(true); + + $copyObj->setID(NULL); + } + + + public function copy($deepCopy = false) + { + $clazz = get_class($this); + $copyObj = new $clazz(); + $this->copyInto($copyObj, $deepCopy); + return $copyObj; + } + + + public function getPeer() + { + if (self::$peer === null) { + self::$peer = new TaggingPeer(); + } + return self::$peer; + } + + + public function setTag($v) + { + + + if ($v === null) { + $this->setTagId(NULL); + } else { + $this->setTagId($v->getID()); + } + + + $this->aTag = $v; + } + + + + public function getTag($con = null) + { + if ($this->aTag === null && ($this->tag_id !== null)) { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTagPeer.php'; + + $this->aTag = TagPeer::retrieveByPK($this->tag_id, $con); + + + } + return $this->aTag; + } + + + public function setsfGuardUser($v) + { + + + if ($v === null) { + $this->setParentUserId(NULL); + } else { + $this->setParentUserId($v->getId()); + } + + + $this->asfGuardUser = $v; + } + + + + public function getsfGuardUser($con = null) + { + if ($this->asfGuardUser === null && ($this->parent_user_id !== null)) { + include_once 'plugins/sfGuardPlugin/lib/model/om/BasesfGuardUserPeer.php'; + + $this->asfGuardUser = sfGuardUserPeer::retrieveByPK($this->parent_user_id, $con); + + + } + return $this->asfGuardUser; + } + + + public function __call($method, $arguments) + { + if (!$callable = sfMixer::getCallable('BaseTagging:'.$method)) + { + throw new sfException(sprintf('Call to undefined method BaseTagging::%s', $method)); + } + + array_unshift($arguments, $this); + + return call_user_func_array($callable, $arguments); + } + + +} \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php new file mode 100644 index 0000000..afae640 --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/om/BaseTaggingPeer.php @@ -0,0 +1,867 @@ + array ('ID', 'TagId', 'TaggableModel', 'TaggableId', 'ParentApproved', 'ParentUserId', ), + BasePeer::TYPE_COLNAME => array (TaggingPeer::ID, TaggingPeer::TAG_ID, TaggingPeer::TAGGABLE_MODEL, TaggingPeer::TAGGABLE_ID, TaggingPeer::PARENT_APPROVED, TaggingPeer::PARENT_USER_ID, ), + BasePeer::TYPE_FIELDNAME => array ('id', 'tag_id', 'taggable_model', 'taggable_id', 'parent_approved', 'parent_user_id', ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, ) + ); + + + private static $fieldKeys = array ( + BasePeer::TYPE_PHPNAME => array ('ID' => 0, 'TagId' => 1, 'TaggableModel' => 2, 'TaggableId' => 3, 'ParentApproved' => 4, 'ParentUserId' => 5, ), + BasePeer::TYPE_COLNAME => array (TaggingPeer::ID => 0, TaggingPeer::TAG_ID => 1, TaggingPeer::TAGGABLE_MODEL => 2, TaggingPeer::TAGGABLE_ID => 3, TaggingPeer::PARENT_APPROVED => 4, TaggingPeer::PARENT_USER_ID => 5, ), + BasePeer::TYPE_FIELDNAME => array ('id' => 0, 'tag_id' => 1, 'taggable_model' => 2, 'taggable_id' => 3, 'parent_approved' => 4, 'parent_user_id' => 5, ), + BasePeer::TYPE_NUM => array (0, 1, 2, 3, 4, 5, ) + ); + + + public static function getMapBuilder() + { + include_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TaggingMapBuilder.php'; + return BasePeer::getMapBuilder('plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model.map.TaggingMapBuilder'); + } + + public static function getPhpNameMap() + { + if (self::$phpNameMap === null) { + $map = TaggingPeer::getTableMap(); + $columns = $map->getColumns(); + $nameMap = array(); + foreach ($columns as $column) { + $nameMap[$column->getPhpName()] = $column->getColumnName(); + } + self::$phpNameMap = $nameMap; + } + return self::$phpNameMap; + } + + static public function translateFieldName($name, $fromType, $toType) + { + $toNames = self::getFieldNames($toType); + $key = isset(self::$fieldKeys[$fromType][$name]) ? self::$fieldKeys[$fromType][$name] : null; + if ($key === null) { + throw new PropelException("'$name' could not be found in the field names of type '$fromType'. These are: " . print_r(self::$fieldKeys[$fromType], true)); + } + return $toNames[$key]; + } + + + + static public function getFieldNames($type = BasePeer::TYPE_PHPNAME) + { + if (!array_key_exists($type, self::$fieldNames)) { + throw new PropelException('Method getFieldNames() expects the parameter $type to be one of the class constants TYPE_PHPNAME, TYPE_COLNAME, TYPE_FIELDNAME, TYPE_NUM. ' . $type . ' was given.'); + } + return self::$fieldNames[$type]; + } + + + public static function alias($alias, $column) + { + return str_replace(TaggingPeer::TABLE_NAME.'.', $alias.'.', $column); + } + + + public static function addSelectColumns(Criteria $criteria) + { + + $criteria->addSelectColumn(TaggingPeer::ID); + + $criteria->addSelectColumn(TaggingPeer::TAG_ID); + + $criteria->addSelectColumn(TaggingPeer::TAGGABLE_MODEL); + + $criteria->addSelectColumn(TaggingPeer::TAGGABLE_ID); + + $criteria->addSelectColumn(TaggingPeer::PARENT_APPROVED); + + $criteria->addSelectColumn(TaggingPeer::PARENT_USER_ID); + + } + + const COUNT = 'COUNT(tagging.ID)'; + const COUNT_DISTINCT = 'COUNT(DISTINCT tagging.ID)'; + + + public static function doCount(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TaggingPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TaggingPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $rs = TaggingPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + public static function doSelectOne(Criteria $criteria, $con = null) + { + $critcopy = clone $criteria; + $critcopy->setLimit(1); + $objects = TaggingPeer::doSelect($critcopy, $con); + if ($objects) { + return $objects[0]; + } + return null; + } + + public static function doSelect(Criteria $criteria, $con = null) + { + return TaggingPeer::populateObjects(TaggingPeer::doSelectRS($criteria, $con)); + } + + public static function doSelectRS(Criteria $criteria, $con = null) + { + + foreach (sfMixer::getCallables('BaseTaggingPeer:addDoSelectRS:addDoSelectRS') as $callable) + { + call_user_func($callable, 'BaseTaggingPeer', $criteria, $con); + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if (!$criteria->getSelectColumns()) { + $criteria = clone $criteria; + TaggingPeer::addSelectColumns($criteria); + } + + $criteria->setDbName(self::DATABASE_NAME); + + return BasePeer::doSelect($criteria, $con); + } + + public static function populateObjects(ResultSet $rs) + { + $results = array(); + + $cls = TaggingPeer::getOMClass(); + $cls = Propel::import($cls); + while($rs->next()) { + + $obj = new $cls(); + $obj->hydrate($rs); + $results[] = $obj; + + } + return $results; + } + + + public static function doCountJoinTag(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TaggingPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TaggingPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(TaggingPeer::TAG_ID, TagPeer::ID); + + $rs = TaggingPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doCountJoinsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TaggingPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TaggingPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(TaggingPeer::PARENT_USER_ID, sfGuardUserPeer::ID); + + $rs = TaggingPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinTag(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + TaggingPeer::addSelectColumns($c); + $startcol = (TaggingPeer::NUM_COLUMNS - TaggingPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + TagPeer::addSelectColumns($c); + + $c->addJoin(TaggingPeer::TAG_ID, TagPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = TaggingPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = TagPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getTag(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addTagging($obj1); break; + } + } + if ($newObject) { + $obj2->initTaggings(); + $obj2->addTagging($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doSelectJoinsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + TaggingPeer::addSelectColumns($c); + $startcol = (TaggingPeer::NUM_COLUMNS - TaggingPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + sfGuardUserPeer::addSelectColumns($c); + + $c->addJoin(TaggingPeer::PARENT_USER_ID, sfGuardUserPeer::ID); + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = TaggingPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol); + + $newObject = true; + foreach($results as $temp_obj1) { + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addTagging($obj1); break; + } + } + if ($newObject) { + $obj2->initTaggings(); + $obj2->addTagging($obj1); } + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAll(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TaggingPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TaggingPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(TaggingPeer::TAG_ID, TagPeer::ID); + + $criteria->addJoin(TaggingPeer::PARENT_USER_ID, sfGuardUserPeer::ID); + + $rs = TaggingPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAll(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + TaggingPeer::addSelectColumns($c); + $startcol2 = (TaggingPeer::NUM_COLUMNS - TaggingPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + TagPeer::addSelectColumns($c); + $startcol3 = $startcol2 + TagPeer::NUM_COLUMNS; + + sfGuardUserPeer::addSelectColumns($c); + $startcol4 = $startcol3 + sfGuardUserPeer::NUM_COLUMNS; + + $c->addJoin(TaggingPeer::TAG_ID, TagPeer::ID); + + $c->addJoin(TaggingPeer::PARENT_USER_ID, sfGuardUserPeer::ID); + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = TaggingPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + + + $omClass = TagPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getTag(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addTagging($obj1); break; + } + } + + if ($newObject) { + $obj2->initTaggings(); + $obj2->addTagging($obj1); + } + + + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj3 = new $cls(); + $obj3->hydrate($rs, $startcol3); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj3 = $temp_obj1->getsfGuardUser(); if ($temp_obj3->getPrimaryKey() === $obj3->getPrimaryKey()) { + $newObject = false; + $temp_obj3->addTagging($obj1); break; + } + } + + if ($newObject) { + $obj3->initTaggings(); + $obj3->addTagging($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + + public static function doCountJoinAllExceptTag(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TaggingPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TaggingPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(TaggingPeer::PARENT_USER_ID, sfGuardUserPeer::ID); + + $rs = TaggingPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doCountJoinAllExceptsfGuardUser(Criteria $criteria, $distinct = false, $con = null) + { + $criteria = clone $criteria; + + $criteria->clearSelectColumns()->clearOrderByColumns(); + if ($distinct || in_array(Criteria::DISTINCT, $criteria->getSelectModifiers())) { + $criteria->addSelectColumn(TaggingPeer::COUNT_DISTINCT); + } else { + $criteria->addSelectColumn(TaggingPeer::COUNT); + } + + foreach($criteria->getGroupByColumns() as $column) + { + $criteria->addSelectColumn($column); + } + + $criteria->addJoin(TaggingPeer::TAG_ID, TagPeer::ID); + + $rs = TaggingPeer::doSelectRS($criteria, $con); + if ($rs->next()) { + return $rs->getInt(1); + } else { + return 0; + } + } + + + + public static function doSelectJoinAllExceptTag(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + TaggingPeer::addSelectColumns($c); + $startcol2 = (TaggingPeer::NUM_COLUMNS - TaggingPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + sfGuardUserPeer::addSelectColumns($c); + $startcol3 = $startcol2 + sfGuardUserPeer::NUM_COLUMNS; + + $c->addJoin(TaggingPeer::PARENT_USER_ID, sfGuardUserPeer::ID); + + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = TaggingPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = sfGuardUserPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getsfGuardUser(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addTagging($obj1); + break; + } + } + + if ($newObject) { + $obj2->initTaggings(); + $obj2->addTagging($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + + public static function doSelectJoinAllExceptsfGuardUser(Criteria $c, $con = null) + { + $c = clone $c; + + if ($c->getDbName() == Propel::getDefaultDB()) { + $c->setDbName(self::DATABASE_NAME); + } + + TaggingPeer::addSelectColumns($c); + $startcol2 = (TaggingPeer::NUM_COLUMNS - TaggingPeer::NUM_LAZY_LOAD_COLUMNS) + 1; + + TagPeer::addSelectColumns($c); + $startcol3 = $startcol2 + TagPeer::NUM_COLUMNS; + + $c->addJoin(TaggingPeer::TAG_ID, TagPeer::ID); + + + $rs = BasePeer::doSelect($c, $con); + $results = array(); + + while($rs->next()) { + + $omClass = TaggingPeer::getOMClass(); + + $cls = Propel::import($omClass); + $obj1 = new $cls(); + $obj1->hydrate($rs); + + $omClass = TagPeer::getOMClass(); + + + $cls = Propel::import($omClass); + $obj2 = new $cls(); + $obj2->hydrate($rs, $startcol2); + + $newObject = true; + for ($j=0, $resCount=count($results); $j < $resCount; $j++) { + $temp_obj1 = $results[$j]; + $temp_obj2 = $temp_obj1->getTag(); if ($temp_obj2->getPrimaryKey() === $obj2->getPrimaryKey()) { + $newObject = false; + $temp_obj2->addTagging($obj1); + break; + } + } + + if ($newObject) { + $obj2->initTaggings(); + $obj2->addTagging($obj1); + } + + $results[] = $obj1; + } + return $results; + } + + + public static function getTableMap() + { + return Propel::getDatabaseMap(self::DATABASE_NAME)->getTable(self::TABLE_NAME); + } + + + public static function getOMClass() + { + return TaggingPeer::CLASS_DEFAULT; + } + + + public static function doInsert($values, $con = null) + { + + foreach (sfMixer::getCallables('BaseTaggingPeer:doInsert:pre') as $callable) + { + $ret = call_user_func($callable, 'BaseTaggingPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } else { + $criteria = $values->buildCriteria(); } + + $criteria->remove(TaggingPeer::ID); + + $criteria->setDbName(self::DATABASE_NAME); + + try { + $con->begin(); + $pk = BasePeer::doInsert($criteria, $con); + $con->commit(); + } catch(PropelException $e) { + $con->rollback(); + throw $e; + } + + + foreach (sfMixer::getCallables('BaseTaggingPeer:doInsert:post') as $callable) + { + call_user_func($callable, 'BaseTaggingPeer', $values, $con, $pk); + } + + return $pk; + } + + + public static function doUpdate($values, $con = null) + { + + foreach (sfMixer::getCallables('BaseTaggingPeer:doUpdate:pre') as $callable) + { + $ret = call_user_func($callable, 'BaseTaggingPeer', $values, $con); + if (false !== $ret) + { + return $ret; + } + } + + + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $selectCriteria = new Criteria(self::DATABASE_NAME); + + if ($values instanceof Criteria) { + $criteria = clone $values; + $comparison = $criteria->getComparison(TaggingPeer::ID); + $selectCriteria->add(TaggingPeer::ID, $criteria->remove(TaggingPeer::ID), $comparison); + + } else { $criteria = $values->buildCriteria(); $selectCriteria = $values->buildPkeyCriteria(); } + + $criteria->setDbName(self::DATABASE_NAME); + + $ret = BasePeer::doUpdate($selectCriteria, $criteria, $con); + + + foreach (sfMixer::getCallables('BaseTaggingPeer:doUpdate:post') as $callable) + { + call_user_func($callable, 'BaseTaggingPeer', $values, $con, $ret); + } + + return $ret; + } + + + public static function doDeleteAll($con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + $affectedRows = 0; try { + $con->begin(); + $affectedRows += BasePeer::doDeleteAll(TaggingPeer::TABLE_NAME, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doDelete($values, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(TaggingPeer::DATABASE_NAME); + } + + if ($values instanceof Criteria) { + $criteria = clone $values; } elseif ($values instanceof Tagging) { + + $criteria = $values->buildPkeyCriteria(); + } else { + $criteria = new Criteria(self::DATABASE_NAME); + $criteria->add(TaggingPeer::ID, (array) $values, Criteria::IN); + } + + $criteria->setDbName(self::DATABASE_NAME); + + $affectedRows = 0; + try { + $con->begin(); + + $affectedRows += BasePeer::doDelete($criteria, $con); + $con->commit(); + return $affectedRows; + } catch (PropelException $e) { + $con->rollback(); + throw $e; + } + } + + + public static function doValidate(Tagging $obj, $cols = null) + { + $columns = array(); + + if ($cols) { + $dbMap = Propel::getDatabaseMap(TaggingPeer::DATABASE_NAME); + $tableMap = $dbMap->getTable(TaggingPeer::TABLE_NAME); + + if (! is_array($cols)) { + $cols = array($cols); + } + + foreach($cols as $colName) { + if ($tableMap->containsColumn($colName)) { + $get = 'get' . $tableMap->getColumn($colName)->getPhpName(); + $columns[$colName] = $obj->$get(); + } + } + } else { + + } + + $res = BasePeer::doValidate(TaggingPeer::DATABASE_NAME, TaggingPeer::TABLE_NAME, $columns); + if ($res !== true) { + $request = sfContext::getInstance()->getRequest(); + foreach ($res as $failed) { + $col = TaggingPeer::translateFieldname($failed->getColumn(), BasePeer::TYPE_COLNAME, BasePeer::TYPE_PHPNAME); + $request->setError($col, $failed->getMessage()); + } + } + + return $res; + } + + + public static function retrieveByPK($pk, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $criteria = new Criteria(TaggingPeer::DATABASE_NAME); + + $criteria->add(TaggingPeer::ID, $pk); + + + $v = TaggingPeer::doSelect($criteria, $con); + + return !empty($v) > 0 ? $v[0] : null; + } + + + public static function retrieveByPKs($pks, $con = null) + { + if ($con === null) { + $con = Propel::getConnection(self::DATABASE_NAME); + } + + $objs = null; + if (empty($pks)) { + $objs = array(); + } else { + $criteria = new Criteria(); + $criteria->add(TaggingPeer::ID, $pks, Criteria::IN); + $objs = TaggingPeer::doSelect($criteria, $con); + } + return $objs; + } + +} +if (Propel::isInit()) { + try { + BaseTaggingPeer::getMapBuilder(); + } catch (Exception $e) { + Propel::log('Could not initialize Peer: ' . $e->getMessage(), Propel::LOG_ERR); + } +} else { + require_once 'plugins/sfPropelActAsTaggableBehaviorPlugin/lib/model/map/TaggingMapBuilder.php'; + Propel::registerMapBuilder('plugins.sfPropelActAsTaggableBehaviorPlugin.lib.model.map.TaggingMapBuilder'); +} diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableBehavior.class.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableBehavior.class.php new file mode 100644 index 0000000..fb15e5b --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableBehavior.class.php @@ -0,0 +1,482 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* + * This behavior permits to attach tags to Propel objects. Some more bits about + * the philosophy of the stuff: + * + * - taggable objects must have a primary key + * + * - tags are saved when the object is saved, not before + * + * - one object cannot be tagged twice with the same tag. When trying to use + * twice the same tag on one object, the second tagging will be ignored + * + * - the tags associated to one taggable object are only loaded when necessary. + * Then they are cached. + * + * - once created, tags never change in the Tag table. When using replaceTag(), + * a new tag is created id necessary, but the old one is not deleted. + * + * + * The plugin associates a parameterHolder to Propel objects, with 3 namespaces: + * + * - tags: + * Tags that have been attached to the object, but not yet saved. + * Contract: tags are disjoin of (saved_tags union removed_tags) + * + * - saved_tags: + * Tags that are presently saved in the database + * + * - removed_tags: + * Tags that are presently saved in the database, but which will be removed + * at the next save() + * Contract: removed_tags are disjoin of (tags union saved_tags) + * + * + * @author Xavier Lacot + * @see http://www.symfony-project.com/trac/wiki/sfPropelActAsTaggableBehaviorPlugin + */ + +class sfPropelActAsTaggableBehavior +{ + /** + * parameterHolder access methods + */ + private static function getTagsHolder(BaseObject $object) + { + if ((!isset($object->_tags)) || ($object->_tags == null)) + { + $object->_tags = new sfParameterHolder(); + } + + return $object->_tags; + } + + private static function add_tag(BaseObject $object, $tag) + { + $tag = sfPropelActAsTaggableToolkit::cleanTagName($tag); + + if (strlen($tag) > 0) + { + self::getTagsHolder($object)->set($tag, $tag, 'tags'); + } + } + + private static function clear_tags(BaseObject $object) + { + return self::getTagsHolder($object)->removeNamespace('tags'); + } + + private static function get_tags(BaseObject $object) + { + return self::getTagsHolder($object)->getAll('tags'); + } + + private static function set_tags(BaseObject $object, $tags) + { + self::clear_tags($object); + self::getTagsHolder($object)->add($tags, 'tags'); + } + + private static function add_saved_tag(BaseObject $object, $tag) + { + self::getTagsHolder($object)->set($tag, $tag, 'saved_tags'); + } + + private static function clear_saved_tags(BaseObject $object) + { + return self::getTagsHolder($object)->removeNamespace('saved_tags'); + } + + private static function get_saved_tags(BaseObject $object) + { + return self::getTagsHolder($object)->getAll('saved_tags'); + } + + private static function set_saved_tags(BaseObject $object, $tags) + { + self::clear_saved_tags($object); + self::getTagsHolder($object)->add($tags, 'saved_tags'); + } + + private static function add_removed_tag(BaseObject $object, $tag) + { + self::getTagsHolder($object)->set($tag, $tag, 'removed_tags'); + } + + private static function clear_removed_tags(BaseObject $object) + { + return self::getTagsHolder($object)->removeNamespace('removed_tags'); + } + + private static function get_removed_tags(BaseObject $object) + { + return self::getTagsHolder($object)->getAll('removed_tags'); + } + + private static function set_removed_tags(BaseObject $object, $tags) + { + self::clear_removed_tags($object); + self::getTagsHolder($object)->add($tags, 'removed_tags'); + } + + + /** + * Adds a tag to the object. The "tagname" param can be a string or an array + * of strings. These 3 code sequences produce an equivalent result : + * + * 1- $object->addTag('tag1,tag2,tag3'); + * 2- $object->addTag('tag1'); + * $object->addTag('tag2'); + * $object->addTag('tag3'); + * 3- $object->addTag(array('tag1','tag2','tag3')); + * + * @param BaseObject $object + * @param mixed $tagname + */ + public function addTag(BaseObject $object, $tagname) + { + $tagname = sfPropelActAsTaggableToolkit::explodeTagString($tagname); + + if (is_array($tagname)) + { + foreach ($tagname as $tag) + { + $this->addTag($object, $tag); + } + } + else + { + $removed_tags = self::get_removed_tags($object); + + if (isset($removed_tags[$tagname])) + { + unset($removed_tags[$tagname]); + self::set_removed_tags($object, $removed_tags); + self::add_saved_tag($object, $tagname); + } + else + { + $saved_tags = $this->getSavedTags($object); + + if (!isset($saved_tags[$tagname])) + { + self::add_tag($object, $tagname); + } + } + } + } + + /** + * Retrieves from the database tags that have been atached to the object. + * Once loaded, this saved tags list is cached and updated in memory. + * + * @param BaseObject $object + */ + private function getSavedTags(BaseObject $object) + { + if (!isset($object->_tags) || !$object->_tags->hasNamespace('saved_tags')) + { + $c = new Criteria(); + $c->add(TaggingPeer::TAGGABLE_ID, $object->getPrimaryKey()); + $c->add(TaggingPeer::TAGGABLE_MODEL, get_class($object)); + $c->addJoin(TaggingPeer::TAG_ID, TagPeer::ID); + $saved_tags = TagPeer::doSelect($c); + $tags = array(); + + foreach ($saved_tags as $tag) + { + $tags[$tag->getName()] = $tag->getName(); + } + + self::set_saved_tags($object, $tags); + return $tags; + } + else + { + return self::get_saved_tags($object); + } + } + + /** + * Returns the list of the tags attached to the object, whatever they have + * already been saved or not. + * + * @param BaseObject $object + */ + public function getTags(BaseObject $object, $options = array()) + { + $tags = array_merge(self::get_tags($object), $this->getSavedTags($object)); + ksort($tags); + + if (isset($options['serialized']) && (true === $options['serialized'])) + { + $tags = implode(', ', $tags); + } + + return $tags; + } + + /** + * Returns true if the object has a tag. If a tag ar an array of tags is + * passed in second parameter, checks if these tags are attached to the object + * + * These 3 calls are equivalent : + * 1- $object->hasTag('tag1') + * && $object->hasTag('tag2') + * && $object->hasTag('tag3'); + * 2- $object->hasTag('tag1,tag2,tag3'); + * 3- $object->hasTag(array('tag1', 'tag2', 'tag3')); + * + * @param BaseObject $object + * @param mixed $tag + */ + public function hasTag(BaseObject $object, $tag = null) + { + $tag = sfPropelActAsTaggableToolkit::explodeTagString($tag); + + if (is_array($tag)) + { + $result = true; + + foreach ($tag as $tagname) + { + $result = $result && $this->hasTag($object, $tagname); + } + + return $result; + } + else + { + $tags = self::get_tags($object); + + if ($tag === null) + { + return (count($tags) > 0) || (count($this->getSavedTags($object)) > 0); + } + elseif (is_string($tag)) + { + $tag = sfPropelActAsTaggableToolkit::cleanTagName($tag); + + if (isset($tags[$tag])) + { + return true; + } + else + { + $saved_tags = $this->getSavedTags($object); + $removed_tags = self::get_removed_tags($object); + return isset($saved_tags[$tag]) && !isset($removed_tags[$tag]); + } + } + else + { + $msg = sprintf('hasTag() does not support this type of argument : %s.', get_class($tag)); + throw new Exception($msg); + } + } + } + + /** + * Preload tags for a set of objects. It might be usefull in case you want to + * display a long list of taggable objects with their associated tags: it + * avoids to load tags per object, and gets all tags in a few requests. + * + * @param array $objects + */ + public static function preloadTags(&$objects) + { + $searched = array(); + + foreach ($objects as $object) + { + $class = get_class($object); + + if (!isset($searched[$class])) + { + $searched[$class] = array(); + } + + $searched[$class][$object->getPrimaryKey()] = $object; + } + + if (count($searched) > 0) + { + $con = Propel::getConnection(); + + foreach ($searched as $model => $instances) + { + $keys = array_keys($instances); + $query = 'SELECT %s as id, + GROUP_CONCAT(%s) as tags + FROM %s, %s + WHERE %s IN (%s) + AND %s=? + AND %s=%s + GROUP BY %s'; + + $query = sprintf($query, + TaggingPeer::TAGGABLE_ID, + TagPeer::NAME, + TaggingPeer::TABLE_NAME, + TagPeer::TABLE_NAME, + TaggingPeer::TAGGABLE_ID, + implode($keys, ','), + TaggingPeer::TAGGABLE_MODEL, + TaggingPeer::TAG_ID, + TagPeer::ID, + TaggingPeer::TAGGABLE_ID); + $stmt = $con->prepareStatement($query); + $stmt->setString(1, $model); + $rs = $stmt->executeQuery(); + + while ($rs->next()) + { + $object = $instances[$rs->getInt('id')]; + $object_tags = explode(',', $rs->getString('tags')); + $tags = array(); + + foreach ($object_tags as $tag) + { + $tags[$tag] = $tag; + } + + self::set_saved_tags($object, $tags); + } + } + } + } + + /** + * Tags saving logic, runned after the object himself has been saved + * + * @param BaseObject $object + */ + public function postSave(BaseObject $object) + { + $tags = self::get_tags($object); + $removed_tags = self::get_removed_tags($object); + + // save new tags + foreach ($tags as $tagname) + { + $tag = TagPeer::retrieveOrCreateByTagName($tagname); + $tag->save(); + $tagging = new Tagging(); + $tagging->setTagId($tag->getId()); + $tagging->setTaggableId($object->getPrimaryKey()); + $tagging->setTaggableModel(get_class($object)); + $tagging->save(); + } + + // remove removed tags + if (!empty($removed_tags)) + { + $c = new Criteria(); + $c->add(TagPeer::NAME, $removed_tags, Criteria::IN); + $rs = TagPeer::doSelectRS($c); + $removed_tag_ids = array(); + + while ($rs->next()) + { + $removed_tag_ids[] = $rs->getInt(1); + } + + if (!empty($removed_tag_ids)) + { + $c = new Criteria(); + $c->add(TaggingPeer::TAG_ID, $removed_tag_ids, Criteria::IN); + $c->add(TaggingPeer::TAGGABLE_ID, $object->getPrimaryKey()); + $c->add(TaggingPeer::TAGGABLE_MODEL, get_class($object)); + TaggingPeer::doDelete($c); + } + } + + $tags = array_merge(self::get_tags($object), $this->getSavedTags($object)); + self::set_saved_tags($object, $tags); + self::clear_tags($object); + self::clear_removed_tags($object); + } + + /** + * Removes all the tags associated to the object. + * + * @param BaseObject $object + */ + public function removeAllTags(BaseObject $object) + { + $saved_tags = self::getSavedTags($object); + + self::set_saved_tags($object, array()); + self::set_tags($object, array()); + self::set_removed_tags($object, $saved_tags); + } + + /** + * Removes a tag or a set of tags from the object. As usual, the second + * parameter might be an array of tags or a comma-separated string. + * + * @param BaseObject $object + * @param mixed $tagname + */ + public function removeTag(BaseObject $object, $tagname) + { + $tagname = sfPropelActAsTaggableToolkit::explodeTagString($tagname); + + if (is_array($tagname)) + { + foreach ($tagname as $tag) + { + $this->removeTag($object, $tag); + } + } + else + { + $tagname = sfPropelActAsTaggableToolkit::cleanTagName($tagname); + $tags = self::get_tags($object); + $saved_tags = $this->getSavedTags($object); + + if (isset($tags[$tagname])) + { + unset($tags[$tagname]); + self::set_tags($object, $tags); + } + + if (isset($saved_tags[$tagname])) + { + unset($saved_tags[$tagname]); + self::set_saved_tags($object, $saved_tags); + self::add_removed_tag($object, $tagname); + } + } + } + + /** + * Replaces a tag with an other one. If the third optionnal parameter is not + * passed, the second tag will simply be removed + * + * @param BaseObject $object + * @param String $tagname + * @param String $replacement + */ + public function replaceTag(BaseObject $object, $tagname, $replacement = null) + { + if (($replacement != $tagname) && ($tagname != null)) + { + $this->removeTag($object, $tagname); + + if ($replacement != null) + { + $this->addTag($object, $replacement); + } + } + } +} \ No newline at end of file diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableToolkit.class.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableToolkit.class.php new file mode 100644 index 0000000..60387be --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/lib/sfPropelActAsTaggableToolkit.class.php @@ -0,0 +1,153 @@ + + * (c) 2007 Michael Nolan + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class sfPropelActAsTaggableToolkit +{ + /** + * "Cleans" a string in order it to be used as a tag. Intended for strings + * representing a single tag + * + * @param String $tag + * @return bool + */ + public static function cleanTagName($tag) + { + return trim(rtrim(str_replace(',', ' ', $tag))); + } + + /** + * "Cleans" a string in order it to be used as a tag + * Intended for strings representing a single tag + * + * @param mixed $tag + * @return mixed + */ + public static function explodeTagString($tag) + { + if (is_string($tag) && false !== strpos($tag, ',')) + { + $tag = explode(',', $tag); + $tag = array_map('trim', $tag); + $tag = array_map('rtrim', $tag); + } + + return $tag; + } + + /** + * Formats a tag string/array in a pretty string. For instance, will convert + * tag3,tag1,tag2 into the following string : "tag1", "tag2" and "tag3" + * + * @param array $tags + * @return String + */ + public static function formatTagString($tags) + { + $result = ''; + $sf_i18n = sfContext::getInstance()->getI18n(); + + if (is_string($tags)) + { + $tags = explode(',', $tags); + } + + $nb_tags = count($tags); + + if ($nb_tags > 0) + { + sort($tags, SORT_LOCALE_STRING); + $i = 0; + + foreach ( $tags as $tag ) + { + $result .= '"'.$tag.'"'; + $i++; + + if ($i == $nb_tags - 1) + { + $result .= ' '.$sf_i18n->__('and').' '; + } + elseif ($i < $nb_tags) + { + $result .= ', '; + } + } + } + + return $result; + } + + /** + * Returns true if the passed model name is taggable + * + * @param mixed $model + * @return boolean + */ + public static function isTaggable($model) + { + if (is_object($model)) + { + $model = get_class($model); + } + + if (!is_string($model)) + { + throw new Exception('The param passed to the metod isTaggable must be a string.'); + } + + $base_class = sprintf('Base%s', ucfirst($model)); + $callables = sfMixer::getCallables($base_class.':save:post'); + $callables_count = count($callables); + $i = 0; + $is_taggable = false; + + while (!$is_taggable && ($i < $callables_count)) + { + $callable = $callables[$i][0]; + $is_taggable = (is_object($callable) + && (get_class($callable) == 'sfPropelActAsTaggableBehavior')); + $i++; + } + + return $is_taggable; + } + + /** + * Normalizes a tag cloud, ie. changes a (tag => weight) array into a + * (tag => normalized_weight) one. Normalized weights range from -2 to 2. + * + * @param array $tag_cloud + * @return array + */ + public static function normalize($tag_cloud) + { + $tags = array(); + $levels = 5; + $power = 0.7; + + if ( count($tag_cloud) > 0 ) + { + $max_count = max($tag_cloud); + $min_count = min($tag_cloud); + $max = intval($levels / 2); + + if ($max_count != 0) + { + foreach ($tag_cloud as $tag => $count) + { + $tags[$tag] = round(.9999 * $levels * (pow($count/$max_count, $power) - .5), 0); + } + } + } + + return $tags; + } +} diff --git a/plugins/sfPropelActAsTaggableBehaviorPlugin/test/unit/sfPropelActAsTaggableBehaviorTest.php b/plugins/sfPropelActAsTaggableBehaviorPlugin/test/unit/sfPropelActAsTaggableBehaviorTest.php new file mode 100644 index 0000000..cc5331a --- /dev/null +++ b/plugins/sfPropelActAsTaggableBehaviorPlugin/test/unit/sfPropelActAsTaggableBehaviorTest.php @@ -0,0 +1,309 @@ +initialize(); +$con = Propel::getConnection(); + +// clean the database +TagPeer::doDeleteAll(); +TaggingPeer::doDeleteAll(); +call_user_func(array(_create_object()->getPeer(), 'doDeleteAll')); + +// create a new test browser +$browser = new sfTestBrowser(); +$browser->initialize(); + +// start tests +$t = new lime_test(36, new lime_output_color()); + + +// these tests check for the tags attachement consistency +$t->diag('tagging consistency'); + +$object = _create_object(); +$t->ok($object->getTags() == array(), 'a new object has no tag.'); + +$object->addTag('toto'); +$object_tags = $object->getTags(); +$t->ok((count($object_tags) == 1) && ($object_tags['toto'] == 'toto'), 'a non-saved object can get tagged.'); + +$object->addTag('toto'); +$object_tags = $object->getTags(); +$t->ok(count($object_tags) == 1, 'a tag is only applied once to non-saved objects.'); +$object->save(); + +$object->addTag('toto'); +$object_tags = $object->getTags(); +$t->ok(count($object_tags) == 1, 'a tag is also only applied once to saved objects.'); +$object->save(); + +$object->addTag('tutu'); +$object_tags = $object->getTags(); +$t->ok($object->hasTag('tutu'), 'a saved object can get tagged.'); +$object->save(); + +// get the key of this object +$id1 = $object->getPrimaryKey(); + +$object->removeTag('tutu'); +$t->ok(!$object->hasTag('tutu'), 'a previously saved tag can be removed.'); + +$object->addTag('tata'); +$object->removeTag('tata'); +$t->ok(!$object->hasTag('tata'), 'a non-saved tag can also be removed.'); + +$object2 = _create_object(); +$object_tags = $object2->getTags(); +$t->ok(count($object_tags) == 0, 'a new object has no tag, even if other tagged objects exist.'); +$object2->save(); + +$object2->addTag('titi'); +$t->ok($object2->hasTag('titi'), 'a new object can get tagged, even if other tagged objects exist.'); +$t->ok(!$object->hasTag('titi'), 'tags applied to new objects do not affect old ones.'); +$object2->save(); +$id2 = $object2->getPrimaryKey(); + +$object2_copy = call_user_func(array(_create_object()->getPeer(), 'retrieveByPk'), $id2); +$object2_copy->addTag('clever'); +$t->ok($object2_copy->hasTag('clever') && !$object2->hasTag('clever'), 'tags are applied to the object instances independently.'); + +$object = _create_object(); +$object->addTag('tutu'); +$object->addTag('titi'); +$object->save(); +$object->addTag('tata'); +$object->removeAllTags(); +$t->ok(!$object->hasTag(), 'tags can all be removed at once.'); + +$object = _create_object(); +$object->addTag('toto,tutu,tata'); +$object->save(); +$id = $object->getPrimaryKey(); +$object = call_user_func(array(_create_object()->getPeer(), 'retrieveByPk'), $id); +$object->removeTag('tata'); +$object->addTag('tata'); +$object->save(); +$object = call_user_func(array(_create_object()->getPeer(), 'retrieveByPk'), $id); +$object_tags = $object->getTags(); +$t->ok(count($object_tags) == 3, 'when removing one previously saved tags, then restoring it, and then saving it again, tags are not duplicated.'); + +$object = _create_object(); +$object->addTag('toto,tutu,tata'); +$object->save(); +$object->removeAllTags(); +$object->addTag('toto,tutu,tata'); +$object->save(); +$id = $object->getPrimaryKey(); +$object = call_user_func(array(_create_object()->getPeer(), 'retrieveByPk'), $id); +$object_tags = $object->getTags(); +$t->ok(count($object_tags) == 3, 'when removing all previously saved tags, then restoring it, and then saving it again, tags are not duplicated.'); + +$object = _create_object(); +$object->addTag('toto,tutu,tata'); +$object->save(); +$previous_count = count($object->getTags()); +$object->removeAllTags(); +$object->save(); +$id = $object->getPrimaryKey(); +$object = call_user_func(array(_create_object()->getPeer(), 'retrieveByPk'), $id); +$t->ok(($previous_count == 3) && !$object->hasTag(), 'previously in-database tags can be deleted.'); + +$object = _create_object(); +$object->addTag('toto, tutu, test'); +$object->save(); +$id = $object->getPrimaryKey(); +$object = call_user_func(array(_create_object()->getPeer(), 'retrieveByPk'), $id); + +$object2 = _create_object(); +$object2->addTag('clever age, symfony, test'); +$object2->save(); +$object2->removeTag('test'); +$object2->save(); + +$object_tags = $object->getTags(); +$object2_tags = $object2->getTags(); +$t->ok((count($object2_tags) == 2) && (count($object_tags) == 3), 'removing one tag as no effect on the other tags of the object, neither on the other objects.'); + +$object2_tags = $object2->getTags(array('serialized' => true)); +$t->ok($object2_tags == 'clever age, symfony', 'tags can be retrieved in a serialized form.'); + +unset($object, $object2, $object2_copy); + + +// these tests check the various methods for applying tags to an object +$t->diag('various methods for applying tags'); +$object = _create_object(); +$object->addTag('toto'); +$object_tags = $object->getTags(); +$t->ok((count($object_tags) == 1) && ($object_tags['toto'] == 'toto'), 'one tag can be added alone.'); + +$object->addTag('titi,tutu'); +$object_tags = $object->getTags(); +$t->ok((count($object_tags) == 3) && $object->hasTag('tutu') && $object->hasTag('titi'), 'tags can be added with a comma-separated string.'); +$t->ok($object->hasTag('titi, tutu'), 'comma-separated strings are divided into several tags.'); + +$object = _create_object(); +$object->addTag(array('titi', 'tutu')); +$object_tags = $object->getTags(); +$t->ok((count($object_tags) == 2) && $object->hasTag('tutu') && $object->hasTag('titi'), 'tags can be added with an array.'); + +unset($object); + + +// these tests check for TagPeer methods (tag clouds generation) + +// clean the database +TagPeer::doDeleteAll(); +TaggingPeer::doDeleteAll(); +call_user_func(array(_create_object()->getPeer(), 'doDeleteAll')); + +$t->diag('tag clouds'); +$object1 = _create_object(); +$object1->addTag('tag2,tag3,tag1,tag4,tag5,tag6'); +$object1->save(); + +$object2 = _create_object(); +$object2->addTag('tag1,tag3,tag4,tag7'); +$object2->save(); + +$object3 = _create_object(); +$object3->addTag('tag2,tag3,tag7,tag8'); +$object3->save(); + +$object4 = _create_object(); +$object4->addTag('tag3'); +$object4->save(); + +$object5 = _create_object(); +$object5->addTag('tag1,tag3,tag7'); +$object5->save(); + +// getAll() test +$tags = TagPeer::getAll(); +$result = array(); + +foreach ($tags as $tag) +{ + $result[] = $tag->getName(); +} + +$t->ok($result == array('tag2', 'tag3', 'tag1', 'tag4', 'tag5', 'tag6', 'tag7', 'tag8'), 'all tags can be retrieved with getAll().'); + +// getAllWithCount() test +$tags = TagPeer::getAllWithCount(); +$t->ok($tags == array('tag1' => 3, 'tag2' => 2, 'tag3' => 5, 'tag4' => 2, 'tag5' => 1, 'tag6' => 1, 'tag7' => 3, 'tag8' => 1), 'all tags can be retrieved with getAll().'); + +// getPopulars() test +$c = new Criteria(); +$c->setLimit(3); +$tags = TagPeer::getPopulars($c); +$t->ok(array_keys($tags) == array('tag1', 'tag3', 'tag7'), 'most popular tags can be retrieved with getPopulars().'); +$t->ok($tags['tag3'] >= $tags['tag1'], 'getPopulars() preserves tag importance.'); + +// getRelatedTags() test +$tags = TagPeer::getRelatedTags('tag8'); +$t->ok(array_keys($tags) == array('tag2', 'tag3', 'tag7'), 'related tags can be retrieved with getRelatedTags().'); + +$c = new Criteria(); +$tags = TagPeer::getRelatedTags('tag2', array('limit' => 1)); +$t->ok(array_keys($tags) == array('tag3'), 'when a limit is set, only most popular related tags are returned by getRelatedTags().'); + +// getRelatedTags() test +$tags = TagPeer::getRelatedTags('tag7'); +$t->ok(array_keys($tags) == array('tag1', 'tag2', 'tag3', 'tag4', 'tag8'), 'getRelatedTags() aggregates tags from different objects.'); + +// getRelatedTags() test +$tags = TagPeer::getRelatedTags(array('tag2', 'tag7')); +$t->ok(array_keys($tags) == array('tag3', 'tag8'), 'getRelatedTags() can retrieve tags related to an array of tags.'); + +// getRelatedTags() test +$tags = TagPeer::getRelatedTags('tag2,tag7'); +$t->ok(array_keys($tags) == array('tag3', 'tag8'), 'getRelatedTags() also accepts a coma-separated string.'); + +// getTaggedWith() tests +$object_2_1 = _create_object_2(); +$object_2_1->addTag('tag1,tag3,tag7'); +$object_2_1->save(); + +$object_2_2 = _create_object_2(); +$object_2_2->addTag('tag2,tag7'); +$object_2_2->save(); + +$tagged_with_tag4 = TagPeer::getTaggedWith('tag4'); +$t->ok(count($tagged_with_tag4) == 2, 'getTaggedWith() returns objects tagged with one specific tag.'); + +$tagged_with_tag7 = TagPeer::getTaggedWith('tag7'); +$t->ok(count($tagged_with_tag7) == 5, 'getTaggedWith() can return several object types.'); + +$tagged_with_tag17 = TagPeer::getTaggedWith(array('tag1', 'tag7')); +$t->ok(count($tagged_with_tag17) == 3, 'getTaggedWith() returns objects tagged with several specific tags.'); + +// these tests check the isTaggable() method +$t->diag('detecting if a model is taggable or not'); + +$t->ok(sfPropelActAsTaggableToolkit::isTaggable(TEST_CLASS) === true, 'it is possible to tell if a model is taggable from its name.'); + +$object = _create_object(); +$t->ok(sfPropelActAsTaggableToolkit::isTaggable($object) === true, 'it is possible to tell if a model is taggable from one of its instances.'); +$t->ok(sfPropelActAsTaggableToolkit::isTaggable('Tristan\'s cat') === false, 'Tristan\'s cat is not taggable, and that is fine.'); + + +TagPeer::doDeleteAll(); +TaggingPeer::doDeleteAll(); +call_user_func(array(_create_object()->getPeer(), 'doDeleteAll')); + + +$object = _create_object(); +$object->addTag('tutu'); +$object->save(); + +// test object creation +function _create_object() +{ + $classname = TEST_CLASS; + + if (!class_exists($classname)) + { + throw new Exception(sprintf('Unknow class "%s"', $classname)); + } + + return new $classname(); +} + +// second type of test object creation +function _create_object_2() +{ + $classname = TEST_CLASS_2; + + if (!class_exists($classname)) + { + throw new Exception(sprintf('Unknow class "%s"', $classname)); + } + + return new $classname(); +} diff --git a/plugins/sfPropelAlternativeSchemaPlugin/LICENSE b/plugins/sfPropelAlternativeSchemaPlugin/LICENSE new file mode 100644 index 0000000..e7a51e3 --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2007 François Zaninotto + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfPropelAlternativeSchemaPlugin/README b/plugins/sfPropelAlternativeSchemaPlugin/README new file mode 100644 index 0000000..22ba659 --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/README @@ -0,0 +1,407 @@ += sfPropelAlternativeSchemaPlugin - Extension to the Propel schema syntax = + +== Overview == + +This plugin extends the symfony model generator, based on Propel, to allow a schema to override another one. Using this plugin, you can add columns, change table names, or the database connection without modifying existing schemas. + +It also provides a new optional YAML syntax for defining database schemas, more explicit and more readable than the current one. Finally, this alternative schema syntax adds a few new features to schemas, such as the ability to define a behavior from a schema. + +== Installation == + +To install the plugin for a symfony project, the usual process is to use the symfony command line: +{{{ +$ php symfony plugin-install http://plugins.symfony-project.com/sfPropelAlternativeSchemaPlugin +}}} + +Alternatively, if you don't have PEAR installed, you can download the latest package attached to this plugin's wiki page and extract it under your project's `plugins/` directory. + +Clear the cache to enable the autoloading to find the new classes: +{{{ +$ php symfony cc +}}} + +That's it, you are ready to override existing schemas and write schemas with the new syntax. + +== Customizing an existing schema == + +Once the plugin is installed, schemas can be customized by other schemas. This is great for plugin schemas, for instance, to allow users to override some of the plugin's schema settings (such as the connection, the table names, etc), or to allow one plugin to extend another plugin. + +When building the model, the plugin will look for custom YAML files for each schema, following this rule: + + Original schema name | Custom schema name + -----------------------------------------|------------------------ + config/schema.yml | schema.custom.yml + config/foobar_schema.yml | foobar_schema.custom.yml + plugins/myPlugin/config/schema.yml | myPlugin_schema.custom.yml + plugins/myPlugin/config/foo_schema.yml | myPlugin_foo_schema.custom.yml + +Custom schemas will be looked for in the application's and plugins' `config/` directories, so a plugin can override another plugin's schema, and there can be more than one customization per schema. + +The plugin will merge the two schemas in a smart way, as follows: + +{{{ +# Original schema +################# +propel: + cd_user: + _attributes: { phpName: User } + first_name: { type: varchar, size: 255, default: "Anonymous" } + last_name: varchar(50) + age: { type: integer, required: true, index: true } + created_at: + + ij_article: + _attributes: { phpName: Article } + title: varchar(50) + user_id: { type: integer } + created_at: + _foreignKeys: + - + foreignTable: cd_user + onDelete: cascade + references: + - { local: user_id, foreign: id } + +# Custom schema +############### +myConnection: + ab_group: + _attributes: { phpName: Group, package: foo.bar.lib.model } + id: + name: varchar(50) + + ef_user: + _attributes: { phpName: User, isI18N: true, i18nTable: cd_user_i18n } + ab_group_id: + + ij_article: + updated_at: + +# Resulting schema +################## +myConnection: + ef_user: + _attributes: { phpName: User, isI18N: true, i18nTable: cd_user_i18n } + first_name: { type: varchar, size: 255, default: "Anonymous" } + last_name: varchar(50) + age: { type: integer, required: true, index: true } + created_at: + ab_group_id: + + ij_article: + _attributes: { phpName: Article } + title: varchar(50) + user_id: { type: integer } + created_at: + updated_at: + _foreignKeys: + - + foreignTable: cd_user + onDelete: cascade + references: + - { local: user_id, foreign: id } + + ab_group: + _attributes: { phpName: Group, package: foo.bar.lib.model } + id: + name: varchar(50) +}}} + +When merging two tables, the plugin will consider the table's `phpName` as a key, and therefore you can change the name of a table in the database, provided that you keep the same `phpName` in the schema. + +== New schema syntax == + +As an alternative to the current `schema.yml` syntax (which still works), this plugin proposes a new way to define a database schema. + +Consider the following schema, using the current syntax: + +{{{ +propel: + _attributes: { noXsd: false, defaultIdMethod: none, package: lib.model } + ab_group: + _attributes: { phpName: Group, package: foo.bar.lib.model } + id: + name: varchar(50) + + cd_user: + _attributes: { phpName: User, isI18N: true, i18nTable: cd_user_i18n } + first_name: { type: varchar, size: 255, default: "Anonymous" } + last_name: varchar(50) + age: { type: integer, required: true, index: true } + ab_group_id: + created_at: + + cd_user_i18n: + description: longvarchar + + ef_article: + title: { type: longvarchar, required: true, index: unique } + stripped_title: { type: longvarchar, required: true, primaryKey: true, sequence: my_custom_sequence_name } + user_id: + my_group: { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } + created_at: timestamp + updated_at: + + ij_article: + _attributes: { phpName: Article } + title: varchar(50) + user_id: { type: integer } + _foreignKeys: + - + foreignTable: cd_user + onDelete: cascade + references: + - { local: user_id, foreign: id } + created_at: + _indexes: + my_index: [title, user_id] + _uniques: + my_other_index: [created_at] + + ab_group_i18n: + motto: longvarchar +}}} + +With the alternative syntax, you can write it as follows: + +{{{ +connection: propel +noXsd: false +defaultIdMethod: none +package: lib.model + +classes: + Group: + tableName: ab_group + package: foo.bar.lib.model + columns: + id: + name: varchar(50) + + User: + tableName: cd_user + isI18N: true + i18nTable: cd_user_i18n + columns: + first_name: { type: varchar, size: 255, default: "Anonymous" } + last_name: varchar(50) + age: { type: integer, required: true, index: true } + ab_group_id: + created_at: + + CdUserI18n: + columns: + description: longvarchar + + EfArticle: + columns: + title: { type: longvarchar, required: true, index: unique } + stripped_title: { type: longvarchar, required: true, primaryKey: true, sequence: my_custom_sequence_name } + user_id: + my_group: { type: integer, foreignClass: Group, foreignReference: id, onDelete: setnull } + created_at: timestamp + updated_at: + + Article: + tableName: ij_article + columns: + title: varchar(50) + user_id: { type: integer } + created_at: + foreignKeys: + - + foreignTable: cd_user + onDelete: cascade + references: + - { local: user_id, foreign: id } + indexes: + my_index: [title, user_id] + uniques: + my_other_index: [created_at] + + AbGroupI18n: + columns: + motto: longvarchar +}}} + +The main difference is that you declare classes, not tables, using the table `phpName` as a key. If you don't define a `tableName`, the plugin will determine one automatically based on the `phpName` using `sfInflector::underscore()`. + +This alternative syntax is also more explicit, since you must create entries for `classes` and `columns`. But it gets rid of the ugly `_attributes` hack of the current syntax. + +The `connection` parameter is optional. If it is not set, it will take `propel` as a default value. + +Note that you can define foreign keys either with the usual `foreignTable` attribute, which expects a table name, or via the new `foreignClass` attribute, which expects a class name. + +Last but not least, all the 'magic' of the current syntax is still there (auto definition of primary keys, foreign keys, i18n tables, etc.). + +Once you have defined such a schema, rebuild the model as usual: + +{{{ +$ php symfony propel-build-model +}}} + +The plugin will recognize the alternative syntax automatically. Note that you can have, in a project, schemas with mixed current and alternative syntax. + +== Behaviors == + +The alternative schema syntax allows you to define behaviors directly from the schema itself. To allow the support for these schema behaviors, you must change two lines in the 'Builder Settings' section of your project's `propel.ini`: + +{{{ +// In config/propel.ini +; builder settings +propel.builder.peer.class = plugins.sfPropelAlternativeSchemaPlugin.lib.SfAlternativePeerBuilder +propel.builder.object.class = plugins.sfPropelAlternativeSchemaPlugin.lib.SfAlternativeObjectBuilder +}}} + +Now you can add a `behaviors` section for each class that you define in a schema, as follows: + +{{{ +classes: + Article: + columns: + title: varchar(50) + behaviors: + paranoid: { column: deleted_at } +}}} + +Of course, don't forget to rebuild the model after you modify your schema. + +It is also possible to define behaviors in the current syntax if you enabled the custom builder in the `propel.ini`. Just add a leading underscore before the `behaviors` key and define behaviors the same a above: + +{{{ +propel: + ij_article: + _attributes: { phpName: Article } + title: varchar(50) + _behaviors: + paranoid: { column: deleted_at } +}}} + + +Note: Incidentally, behaviors entered this way are registered both in the model and peer classes, which seems to solve some problems with behaviors (like #1229). + +== Mixed schemas == + +The schema customization works whatever the original schema syntax and whatever the custom schemas syntax. This means that you can customize an existing schema with the old syntax using a custom schema with the new syntax, and vice-versa. The plugin will do the conversion internally so that the merge is always possible. + +Note that the schema merge is easier to understand when considering the alternative syntax for both the original and the custom schema. In fact, this is the internal format used by the plugin for the merge. The following listing is the same example as the one in the "Customizing an existing schema" section, except it uses the alternative schema syntax... and behaviors. + +{{{ +# Original schema +################# +classes: + User: + tableName: cd_user + columns: + first_name: { type: varchar, size: 255, default: "Anonymous" } + last_name: varchar(50) + age: { type: integer, required: true, index: true } + created_at: + + Article: + tableName: ij_article + columns: + title: varchar(50) + user_id: { type: integer } + created_at: + foreignKeys: + - + foreignTable: cd_user + onDelete: cascade + references: + - { local: user_id, foreign: id } + +# Custom schema +############### +connection: myConnection +classes: + Group: + tableName: ab_group + package: foo.bar.lib.model + behaviors: [paranoid] + columns: + id: + name: varchar(50) + + User: + tableName: ef_user + isI18N: true + i18nTable: cd_user_i18n + columns: + ab_group_id: + + Article: + columns: + updated_at: + +# Resulting schema +################## +connection: myConnection +classes: + Group: + tableName: ab_group + package: foo.bar.lib.model + behaviors: [paranoid] + columns: + id: + name: varchar(50) + + User: + tableName: cd_user + isI18N: true + i18nTable: cd_user_i18n + columns: + first_name: { type: varchar, size: 255, default: "Anonymous" } + last_name: varchar(50) + age: { type: integer, required: true, index: true } + ab_group_id: + created_at: + + Article: + tableName: ij_article + columns: + title: varchar(50) + user_id: { type: integer } + created_at: + updated_at: + foreignKeys: + - + foreignTable: cd_user + onDelete: cascade + references: + - { local: user_id, foreign: id } +}}} + +For clarity, it is recommended to use the alternative schema syntax as much as possible. + +== Checking that the plugin is installed == + +Alternative schemas can sometimes look like normal YAML schemas. If this plugin is not installed, the usual schema interpreter may try to transform a schema with the alternative syntax into an XML schema, but based on the usual syntax. This will most probably cause problems. + +To avoid this, you should check that the plugin is installed before trying to interpret an alternative YAML schema. To do so, a good trick is to take advantage of the fact that YAML files are executed as PHP files before being converted to arrays. So add the following line on top of every alternative YAML schema: + +{{{ + +}}} + +== Todo == + + * Refactor `sfPropelDatabaseSchema` to use the new schema syntax internally + +== Changelog == + +=== Trunk === + +=== 2007-10-18 | 1.0.0 Stable === + + * francois: Added support for behaviors in the old syntax, too + * francois: Added new/old YAML syntax conversion. It is now possible to customize an old schema even if it doesn't use the alternative syntax. + * francois: Added a fix for the too late initialization of behaviors in symfony when adding hooks to custom class + * francois: Added a way to define behaviors from the schema + * francois: Added a new `foreignClass` column attribute to define a foreign key from a phpName rather than from a tableName + * francois: Added section about plugin check in README + * francois: Fixed a problem with model class names beginning with a lowercase character + +=== 2007-10-05 | 0.9.0 Beta === + + * francois: initial release \ No newline at end of file diff --git a/plugins/sfPropelAlternativeSchemaPlugin/lib/SfAlternativeObjectBuilder.php b/plugins/sfPropelAlternativeSchemaPlugin/lib/SfAlternativeObjectBuilder.php new file mode 100644 index 0000000..b19596e --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/lib/SfAlternativeObjectBuilder.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage addon + * @author Fabien Potencier + * @version SVN: $Id: SfObjectBuilder.php 3493 2007-02-18 09:23:10Z fabien $ + */ +class SfAlternativeObjectBuilder extends SfObjectBuilder +{ + protected function addClassClose(&$script) + { + parent::addClassClose($script); + + $behavior_file_name = 'Base'.$this->getTable()->getPhpName().'Behaviors'; + $behavior_file_path = $this->getFilePath($this->getStubObjectBuilder()->getPackage().'.om.'.$behavior_file_name); + + $behaviors = $this->getTable()->getAttribute('behaviors'); + if($behaviors) + { + $script .= sprintf("\n\ninclude_once '%s';\n", $behavior_file_path); + } + } +} diff --git a/plugins/sfPropelAlternativeSchemaPlugin/lib/SfAlternativePeerBuilder.php b/plugins/sfPropelAlternativeSchemaPlugin/lib/SfAlternativePeerBuilder.php new file mode 100644 index 0000000..e8020f7 --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/lib/SfAlternativePeerBuilder.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * @package symfony + * @subpackage addon + * @author Fabien Potencier + * @version SVN: $Id: SfPeerBuilder.php 3663 2007-03-23 13:43:19Z fabien $ + */ +class SfAlternativePeerBuilder extends sfPeerBuilder +{ + + protected function addClassClose(&$script) + { + parent::addClassClose($script); + + $behavior_file_name = 'Base'.$this->getTable()->getPhpName().'Behaviors'; + $behavior_file_path = $this->getFilePath($this->getStubObjectBuilder()->getPackage().'.om.'.$behavior_file_name); + $absolute_behavior_file_path = sfConfig::get('sf_root_dir').'/'.$behavior_file_path; + + if(file_exists($absolute_behavior_file_path)) + { + unlink($absolute_behavior_file_path); + } + + $behaviors = $this->getTable()->getAttribute('behaviors'); + if($behaviors) + { + file_put_contents($absolute_behavior_file_path, sprintf("getTable()->getPhpName(), var_export(unserialize($behaviors), true))); + $script .= sprintf("\n\ninclude_once '%s';\n", $behavior_file_path); + } + } + +// TEMPORARY : remove these when bug #1585 and #2310 are solved + protected function addDoSelectJoin(&$script) + { + $tmp = ''; + parent::addDoSelectJoin($tmp); + + if (DataModelBuilder::getBuildProperty('builderAddBehaviors')) + { + $mixer_script = " + + foreach (sfMixer::getCallables('{$this->getClassname()}:doSelectJoin:doSelectJoin') as \$callable) + { + call_user_func(\$callable, '{$this->getClassname()}', \$c, \$con); + } + +"; + $tmp = preg_replace('/public static function doSelectJoin.*\(Criteria \$c, \$con = null\)\n\s*{/', '\0'.$mixer_script, $tmp); + } + + $script .= $tmp; + } + + protected function addDoSelectJoinAllExcept(&$script) + { + $tmp = ''; + parent::addDoSelectJoinAllExcept($tmp); + + if (DataModelBuilder::getBuildProperty('builderAddBehaviors')) + { + $mixer_script = " + + foreach (sfMixer::getCallables('{$this->getClassname()}:doSelectJoinAllExcept:doSelectJoinAllExcept') as \$callable) + { + call_user_func(\$callable, '{$this->getClassname()}', \$c, \$con); + } + +"; + $tmp = preg_replace('/public static function doSelectJoinAllExcept.*\(Criteria \$c, \$con = null\)\n\s*{/', '\0'.$mixer_script, $tmp); + } + + $script .= $tmp; + } + + protected function addDoSelectJoinAll(&$script) + { + $tmp = ''; + parent::addDoSelectJoinAll($tmp); + + if (DataModelBuilder::getBuildProperty('builderAddBehaviors')) + { + $mixer_script = " + + foreach (sfMixer::getCallables('{$this->getClassname()}:doSelectJoinAll:doSelectJoinAll') as \$callable) + { + call_user_func(\$callable, '{$this->getClassname()}', \$c, \$con); + } + +"; + $tmp = preg_replace('/{/', '{'.$mixer_script, $tmp, 1); + } + + $script .= $tmp; + } + + protected function addDoSelectRS(&$script) + { + $tmp = ''; + parent::addDoSelectRS($tmp); + + if (DataModelBuilder::getBuildProperty('builderAddBehaviors')) + { + $mixer_script = " + + foreach (sfMixer::getCallables('{$this->getClassname()}:doSelectRS:doSelectRS') as \$callable) + { + call_user_func(\$callable, '{$this->getClassname()}', \$criteria, \$con); + } + +"; + $tmp = preg_replace('/{/', '{'.$mixer_script, $tmp, 1); + } + + $script .= $tmp; + } +// TEMPORARY + +} diff --git a/plugins/sfPropelAlternativeSchemaPlugin/lib/sfPropelDatabaseSchema.class.php b/plugins/sfPropelAlternativeSchemaPlugin/lib/sfPropelDatabaseSchema.class.php new file mode 100644 index 0000000..3afdb95 --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/lib/sfPropelDatabaseSchema.class.php @@ -0,0 +1,962 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * + * @package symfony + * @subpackage addon + * @author Fabien Potencier + * @author François Zaninotto + * @version SVN: $Id$ + */ +class sfPropelDatabaseSchema +{ + protected $connection_name = ''; + protected $database = array(); + + public function asArray() + { + return array($this->connection_name => $this->database); + } + + public function loadArray($schema_array) + { + $database = array(); + $connection_name = ''; + + if(isset($schema_array['classes'])) + { + // New schema syntax + $schema_array = $this->convertNewToOldYaml($schema_array); + } + + if (count($schema_array) > 1) + { + throw new sfException('A schema.yml must only contain 1 database entry.'); + } + + $tmp = array_keys($schema_array); + $connection_name = array_shift($tmp); + + if ($connection_name) + { + $database = $schema_array[$connection_name]; + } + + $this->connection_name = $connection_name; + $this->database = $database; + + $this->fixYAMLDatabase(); + $this->fixYAMLI18n(); + $this->fixYAMLColumns(); + } + + public function loadYAML($file) + { + $schema_array = sfYaml::load($file); + + if(!isset($schema_array['classes'])) + { + // Old schema syntax: we convert it + $schema_array = $this->convertOldToNewYaml($schema_array); + } + + // the following should be in the pake task, but unfortunately it can't be overridden... + // so we do it only if in the pake context + if(class_exists('pakeFinder')) + { + // New schema syntax, we should look for custom schemas + $custom_schema_filename = str_replace(array(getcwd().DIRECTORY_SEPARATOR, 'plugins'.DIRECTORY_SEPARATOR, 'config'.DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, 'schema.yml'), array('', '', '', '_', 'schema.custom.yml'), $file); + $dirs = array('config'); + if ($pluginDirs = glob(sfConfig::get('sf_root_dir').'/plugins/*/config')) + { + $dirs = array_merge($dirs, $pluginDirs); + } + $custom_schemas = pakeFinder::type('file')->name($custom_schema_filename)->in($dirs); + + foreach($custom_schemas as $custom_schema) + { + if(function_exists('pake_echo_action')) + { + pake_echo_action('schema', sprintf('found custom schema %s', $custom_schema)); + } + $custom_schema_array = sfYaml::load($custom_schema); + if(!isset($custom_schema_array['classes'])) + { + // Old schema syntax: we convert it + $custom_schema_array = $this->convertOldToNewYaml($custom_schema_array); + } + $schema_array = sfToolkit::arrayDeepMerge($schema_array, $custom_schema_array); + } + } + + $this->loadArray($schema_array); + } + + public function convertOldToNewYaml($schema) + { + $new_schema = array(); + + $tmp = array_keys($schema); + $connection_name = array_shift($tmp); + $new_schema['connection'] = $connection_name; + + $classes = array(); + if (!is_array($schema[$connection_name])) { + trigger_error($schema[$connection_name], E_USER_WARNING); + $schema[$connection_name] = (array)$schema[$connection_name]; + } + foreach($schema[$connection_name] as $table => $table_params) + { + if($table == '_attributes') + { + // Database attributes + $new_schema = array_merge($new_schema, $table_params); + } + else + { + // Table + $phpName = sfInflector::camelize($table); + if(isset($table_params['_attributes'])) + { + $table_attributes = $table_params['_attributes']; + unset($table_params['_attributes']); + if(isset($table_attributes['phpName'])) + { + $phpName = $table_attributes['phpName']; + unset($table_attributes['phpName']); + } + } + else + { + $table_attributes = array(); + } + $classes[$phpName] = $table_attributes; + $classes[$phpName]['tableName'] = $table; + $classes[$phpName]['columns'] = array(); + foreach($table_params as $column => $column_params) + { + switch($column) + { + case '_behaviors': + $classes[$phpName]['behaviors'] = $column_params; + break; + case '_foreignKeys': + $classes[$phpName]['foreignKeys'] = $column_params; + break; + case '_indexes': + $classes[$phpName]['indexes'] = $column_params; + break; + case '_uniques': + $classes[$phpName]['uniques'] = $column_params; + break; + default: + $classes[$phpName]['columns'][$column] = $column_params; + } + } + } + } + + $new_schema['classes'] = $classes; + + return $new_schema; + } + + public function convertNewToOldYaml($schema) + { + + if(isset($schema['connection'])) + { + $connection_name = $schema['connection']; + unset($schema['connection']); + } + else + { + $connection_name = 'propel'; + } + + $database = array(); + + // Tables + if(isset($schema['classes'])) + { + $tables = array(); + foreach ($schema['classes'] as $className => $classParams) + { + $tableParams = array(); + + // Columns + if(isset($classParams['columns'])) + { + $tableParams = array_merge($classParams['columns'], $tableParams); + unset($classParams['columns']); + } + + // Indexes and foreign keys + if(isset($classParams['indexes'])) + { + $tableParams['_indexes'] = $classParams['indexes']; + unset($classParams['indexes']); + } + if(isset($classParams['uniques'])) + { + $tableParams['_uniques'] = $classParams['uniques']; + unset($classParams['uniques']); + } + if(isset($classParams['foreignKeys'])) + { + $tableParams['_foreignKeys'] = $classParams['foreignKeys']; + unset($classParams['foreignKeys']); + } + + // Behaviors + if(isset($classParams['behaviors'])) + { + $tableParams['_behaviors'] = $classParams['behaviors']; + unset($classParams['behaviors']); + } + + // Table attributes + $tableAttributes = array(); + if(isset($classParams['tableName'])) + { + $tableName = $classParams['tableName']; + unset($classParams['tableName']); + } + else + { + $tableName = sfInflector::underscore($className); + } + + if(sfInflector::camelize($tableName) != $className) + { + $tableAttributes['phpName'] = $className; + } + + if($tableAttributes || $classParams) + { + $tableParams['_attributes'] = array_merge($tableAttributes, $classParams); + } + + $tables[$tableName] = $tableParams; + } + $database = array_merge($database, $tables); + unset($schema['classes']); + } + + // Database attributes + if($schema) + { + $database['_attributes'] = $schema; + } + + return array($connection_name => $database); + } + + public function asXML() + { + $xml = "\n"; + + $xml .= "connection_name\"".$this->getAttributesFor($this->database).">\n"; + + // tables + foreach ($this->getChildren($this->database) as $tb_name => $table) + { + $xml .= "\n getAttributesFor($table); + if (isset($table['_behaviors'])) + { + $xml .= sprintf(" behaviors=\"%s\"", htmlspecialchars(serialize($table['_behaviors']))); + } + $xml .= ">\n"; + + // columns + foreach ($this->getChildren($table) as $col_name => $column) + { + $xml .= " getAttributesForColumn($tb_name, $col_name, $column); + } + + // indexes + if (isset($table['_indexes'])) + { + foreach ($table['_indexes'] as $index_name => $index) + { + $xml .= " \n"; + foreach ($index as $index_column) + { + $xml .= " \n"; + } + $xml .= " \n"; + } + } + + // uniques + if (isset($table['_uniques'])) + { + foreach ($table['_uniques'] as $unique_name => $index) + { + $xml .= " \n"; + foreach ($index as $unique_column) + { + $xml .= " \n"; + } + $xml .= " \n"; + } + } + + // foreign-keys + if (isset($table['_foreignKeys'])) + { + foreach ($table['_foreignKeys'] as $fkey_name => $fkey) + { + $xml .= " \n"; + } + } + $xml .= " \n"; + } + } + + $xml .= "
    \n"; + } + $xml .= "\n
    \n"; + + return $xml; + } + + protected function fixYAMLDatabase() + { + if (!isset($this->database['_attributes'])) + { + $this->database['_attributes'] = array(); + } + + // conventions for database attributes + $this->setIfNotSet($this->database['_attributes'], 'defaultIdMethod', 'native'); + $this->setIfNotSet($this->database['_attributes'], 'noXsd', true); + $this->setIfNotSet($this->database['_attributes'], 'package', 'lib.model'); + } + + protected function fixYAMLI18n() + { + foreach ($this->getTables() as $i18n_table => $columns) + { + $pos = strpos($i18n_table, '_i18n'); + + $has_primary_key = false; + foreach ($columns as $column => $attributes) + { + if (is_array($attributes) && array_key_exists('primaryKey', $attributes)) + { + $has_primary_key = true; + } + } + + if ($pos > 0 && $pos == strlen($i18n_table) - 5 && !$has_primary_key) + { + // i18n table without primary key + $main_table = $this->findTable(substr($i18n_table, 0, $pos)); + + if ($main_table) + { + // set i18n attributes for main table + $this->setIfNotSet($this->database[$main_table]['_attributes'], 'isI18N', 1); + $this->setIfNotSet($this->database[$main_table]['_attributes'], 'i18nTable', $i18n_table); + + // set id and culture columns for i18n table + $this->setIfNotSet($this->database[$i18n_table], 'id', array( + 'type' => 'integer', + 'required' => true, + 'primaryKey' => true, + 'foreignTable' => $main_table, + 'foreignReference' => 'id', + 'onDelete' => 'cascade' + )); + $this->setIfNotSet($this->database[$i18n_table], 'culture', array( + 'isCulture' => true, + 'type' => 'varchar', + 'size' => '7', + 'required' => true, + 'primaryKey' => true + )); + } + else + { + throw new sfException(sprintf('Missing main table for internationalized table "%s".', $i18n_table)); + } + } + } + } + + protected function fixYAMLColumns() + { + foreach ($this->getTables() as $table => $columns) + { + $has_primary_key = false; + + foreach ($columns as $column => $attributes) + { + if ($attributes == null) + { + // conventions for null attributes + if ($column == 'created_at' || $column == 'updated_at') + { + // timestamp convention + $this->database[$table][$column]['type']= 'timestamp'; + } + + if ($column == 'id') + { + // primary key convention + $this->database[$table]['id'] = array( + 'type' => 'integer', + 'required' => true, + 'primaryKey' => true, + 'autoIncrement' => true + ); + $has_primary_key = true; + } + + $pos = strpos($column, '_id'); + if ($pos > 0 && $pos == strlen($column) - 3) + { + // foreign key convention + $foreign_table = $this->findTable(substr($column, 0, $pos)); + if ($foreign_table) + { + $this->database[$table][$column] = array( + 'type' => 'integer', + 'foreignTable' => $foreign_table, + 'foreignReference' => 'id' + ); + } + else + { + throw new sfException(sprintf('Unable to resolve foreign table for column "%s"', $column)); + } + } + + } + else + { + if (!is_array($attributes)) + { + // compact type given as single attribute + $this->database[$table][$column] = $this->getAttributesFromCompactType($attributes); + } + else + { + if (isset($attributes['type'])) + { + // compact type given as value of the type attribute + $this->database[$table][$column] = array_merge($this->database[$table][$column], $this->getAttributesFromCompactType($attributes['type'])); + } + if (isset($attributes['primaryKey'])) + { + $has_primary_key = true; + } + } + } + } + + if (!$has_primary_key) + { + // convention for tables without primary key + $this->database[$table]['id'] = array( + 'type' => 'integer', + 'required' => true, + 'primaryKey' => true, + 'autoIncrement' => true + ); + } + } + } + + protected function getAttributesFromCompactType($type) + { + preg_match('/varchar\(([\d]+)\)/', $type, $matches); + if (isset($matches[1])) + { + return array('type' => 'varchar', 'size' => $matches[1]); + } + else + { + return array('type' => $type); + } + } + + protected function setIfNotSet(&$entry, $key, $value) + { + if (!isset($entry[$key])) + { + $entry[$key] = $value; + } + } + + protected function findTable($table_name) + { + // find a table from a phpName or a name + $table_match = false; + foreach ($this->getTables() as $tb_name => $table) + { + if ( + ($tb_name == $table_name) + || (isset($table['_attributes']['phpName']) && + ( + $table['_attributes']['phpName'] == sfInflector::camelize($table_name) + || $table['_attributes']['phpName'] == $table_name + ) + || (sfInflector::underscore($table_name) == $tb_name)) + ) + { + $table_match = $tb_name; + break; + } + } + + return $table_match; + } + + protected function getAttributesForColumn($tb_name, $col_name, $column) + { + $attributes_string = ''; + if (is_array($column)) + { + foreach ($column as $key => $value) + { + if (!in_array($key, array('foreignClass', 'foreignTable', 'foreignReference', 'onDelete', 'onUpdate', 'index', 'unique', 'sequence'))) + { + $attributes_string .= " $key=\"".htmlspecialchars($this->getCorrectValueFor($key, $value))."\""; + } + } + $attributes_string .= " />\n"; + } + else + { + throw new sfException('Incorrect settings for column '.$col_name); + } + + // conventions for foreign key attributes + if (is_array($column) && (isset($column['foreignTable']) || isset($column['foreignClass']))) + { + if (isset($column['foreignTable'])) + { + $attributes_string .= " findTable($column['foreignClass']); + if(!$foreignTable) + { + // Let's assume that the class given is from another schema + // We have no access to the other schema's phpNames + // So our last guess is to try to underscore the class name + $foreignTable = sfInflector::underscore($column['foreignClass']); + } + $attributes_string .= " \n"; + $attributes_string .= " \n"; + } + + // conventions for index and unique index attributes + if (is_array($column) && isset($column['index'])) + { + if ($column['index'] === 'unique') + { + $attributes_string .= " \n"; + $attributes_string .= " \n"; + $attributes_string .= " \n"; + } + else + { + $attributes_string .= " \n"; + $attributes_string .= " \n"; + $attributes_string .= " \n"; + } + } + + // conventions for sequence name attributes + // required for databases using sequences for auto-increment columns (e.g. PostgreSQL or Oracle) + if (is_array($column) && isset($column['sequence'])) + { + $attributes_string .= " \n"; + } + + return $attributes_string; + } + + protected function getAttributesFor($tag) + { + if (!isset($tag['_attributes'])) + { + return ''; + } + $attributes = $tag['_attributes']; + $attributes_string = ''; + foreach ($attributes as $key => $value) + { + $attributes_string .= ' '.$key.'="'.htmlspecialchars($this->getCorrectValueFor($key, $value)).'"'; + } + + return $attributes_string; + } + + protected function getCorrectValueFor($key, $value) + { + $booleans = array('required', 'primaryKey', 'autoincrement', 'autoIncrement', 'noXsd', 'isI18N', 'isCulture'); + if (in_array($key, $booleans)) + { + return $value == 1 ? 'true' : 'false'; + } + else + { + return is_null($value) ? 'null' : $value; + } + } + + public function getTables() + { + return $this->getChildren($this->database); + } + + public function getChildren($hash) + { + foreach ($hash as $key => $value) + { + // ignore special children (starting with _) + if ($key[0] == '_') + { + unset($hash[$key]); + } + } + + return $hash; + } + + public function loadXML($file) + { + $schema = simplexml_load_file($file); + $database = array(); + + // database + list($database_name, $database_attributes) = $this->getNameAndAttributes($schema->attributes()); + if ($database_name) + { + $this->connection_name = $database_name; + } + else + { + throw new sfException('The database tag misses a name attribute'); + } + if ($database_attributes) + { + $database['_attributes'] = $database_attributes; + } + + // tables + foreach ($schema as $table) + { + list($table_name, $table_attributes) = $this->getNameAndAttributes($table->attributes()); + if ($table_name) + { + $database[$table_name] = array(); + } + else + { + throw new sfException('A table tag misses the name attribute'); + } + if ($table_attributes) + { + $database[$table_name]['_attributes'] = $table_attributes; + } + + // columns + foreach ($table->xpath('column') as $column) + { + list($column_name, $column_attributes) = $this->getNameAndAttributes($column->attributes()); + if ($column_name) + { + $database[$table_name][$column_name] = $column_attributes; + } + else + { + throw new sfException('A column tag misses the name attribute'); + } + } + + // foreign-keys + $database[$table_name]['_foreign_keys'] = array(); + foreach ($table->xpath('foreign-key') as $foreign_key) + { + $foreign_key_table = array(); + + // foreign key attributes + if (isset($foreign_key['foreignTable'])) + { + $foreign_key_table['foreign_table'] = (string) $foreign_key['foreignTable']; + } + else + { + throw new sfException('A foreign key misses the foreignTable attribute'); + } + if (isset($foreign_key['onDelete'])) + { + $foreign_key_table['on_delete'] = (string) $foreign_key['onDelete']; + } + if (isset($foreign_key['onUpdate'])) + { + $foreign_key_table['on_update'] = (string) $foreign_key['onUpdate']; + } + + // foreign key references + $foreign_key_table['references'] = array(); + foreach ($foreign_key->xpath('reference') as $reference) + { + $reference_attributes = array(); + foreach ($reference->attributes() as $reference_attribute_name => $reference_attribute_value) + { + $reference_attributes[$reference_attribute_name] = strval($reference_attribute_value); + } + $foreign_key_table['references'][] = $reference_attributes; + } + + if (isset($foreign_key['name'])) + { + $database[$table_name]['_foreign_keys'][(string)$foreign_key['name']] = $foreign_key_table; + } + else + { + $database[$table_name]['_foreign_keys'][] = $foreign_key_table; + } + + } + $this->removeEmptyKey($database[$table_name], '_foreign_keys'); + + // indexes + $database[$table_name]['_indexes'] = array(); + foreach ($table->xpath('index') as $index) + { + $index_keys = array(); + foreach ($index->xpath('index-column') as $index_key) + { + $index_keys[] = strval($index_key['name']); + } + $database[$table_name]['_indexes'][strval($index['name'])] = $index_keys; + } + $this->removeEmptyKey($database[$table_name], '_indexes'); + + // unique indexes + $database[$table_name]['_uniques'] = array(); + foreach ($table->xpath('unique') as $index) + { + $unique_keys = array(); + foreach ($index->xpath('unique-column') as $unique_key) + { + $unique_keys[] = strval($unique_key['name']); + } + $database[$table_name]['_uniques'][strval($index['name'])] = $unique_keys; + } + $this->removeEmptyKey($database[$table_name], '_uniques'); + } + $this->database = $database; + + $this->fixXML(); + } + + public function fixXML() + { + $this->fixXMLForeignKeys(); + $this->fixXMLIndexes(); + // $this->fixXMLColumns(); + } + + protected function fixXMLForeignKeys() + { + foreach ($this->getTables() as $table => $columns) + { + if (isset($this->database[$table]['_foreign_keys'])) + { + $foreign_keys = $this->database[$table]['_foreign_keys']; + foreach ($foreign_keys as $foreign_key_name => $foreign_key_attributes) + { + // Only single foreign keys can be simplified + if (count($foreign_key_attributes['references']) == 1) + { + $reference = $foreign_key_attributes['references'][0]; + + // set simple foreign key + $this->database[$table][$reference['local']]['foreignTable'] = $foreign_key_attributes['foreign_table']; + $this->database[$table][$reference['local']]['foreignReference'] = $reference['foreign']; + if (isset($foreign_key_attributes['on_delete'])) + { + $this->database[$table][$reference['local']]['onDelete'] = $foreign_key_attributes['on_delete']; + } + if (isset($foreign_key_attributes['on_update'])) + { + $this->database[$table][$reference['local']]['onUpdate'] = $foreign_key_attributes['on_update']; + } + + // remove complex foreign key + unset($this->database[$table]['_foreign_keys'][$foreign_key_name]); + } + + $this->removeEmptyKey($this->database[$table], '_foreign_keys'); + } + } + } + } + + protected function fixXMLIndexes() + { + foreach ($this->getTables() as $table => $columns) + { + if (isset($this->database[$table]['_indexes'])) + { + $indexes = $this->database[$table]['_indexes']; + foreach ($indexes as $index => $references) + { + // Only single indexes can be simplified + if (count($references) == 1 && array_key_exists(substr($index, 0, strlen($index) - 6), $columns)) + { + $reference = $references[0]; + + // set simple index + $this->database[$table][$reference]['index'] = 'true'; + + // remove complex index + unset($this->database[$table]['_indexes'][$index]); + } + + $this->removeEmptyKey($this->database[$table], '_indexes'); + } + } + if (isset($this->database[$table]['_uniques'])) + { + $uniques = $this->database[$table]['_uniques']; + foreach ($uniques as $index => $references) + { + // Only single unique indexes can be simplified + if (count($references) == 1 && array_key_exists(substr($index, 0, strlen($index) - 7), $columns)) + { + $reference = $references[0]; + + // set simple index + $this->database[$table][$reference]['index'] = 'unique'; + + // remove complex unique index + unset($this->database[$table]['_uniques'][$index]); + } + + $this->removeEmptyKey($this->database[$table], '_uniques'); + } + } + } + } + + protected function fixXMLColumns() + { + foreach ($this->getTables() as $table => $columns) + { + foreach ($columns as $column => $attributes) + { + if ($column == 'id' && !array_diff($attributes, array('type' => 'integer', 'required' => 'true', 'primaryKey' => 'true', 'autoIncrement' => 'true'))) + { + // simplify primary keys + $this->database[$table]['id'] = null; + } + + if (($column == 'created_at') || ($column == 'updated_at') && !array_diff($attributes, array('type' => 'timestamp'))) + { + // simplify timestamps + $this->database[$table][$column] = null; + } + + $pos = strpos($column, '_id'); + $has_fk_name = $pos > 0 && $pos == strlen($column) - 3; + $is_foreign_key = isset($attributes['type']) && $attributes['type'] == 'integer' && isset($attributes['foreignReference']) && $attributes['foreignReference'] == 'id'; + $has_foreign_table = isset($attributes['foreignTable']) && array_key_exists($attributes['foreignTable'], $this->getTables()); + $has_other_attribute = isset($attributes['onDelete']); + if ($has_fk_name && $has_foreign_table && $is_foreign_key && !$has_other_attribute) + { + // simplify foreign key + $this->database[$table][$column] = null; + } + } + } + } + + public function asYAML() + { + return sfYaml::dump(array($this->connection_name => $this->database)); + } + + protected function getNameAndAttributes($hash, $name_attribute = 'name') + { + // tag name + $name = ''; + if (isset($hash[$name_attribute])) + { + $name = strval($hash[$name_attribute]); + unset($hash[$name_attribute]); + } + + // tag attributes + $attributes = array(); + foreach ($hash as $attribute => $value) + { + $attributes[$attribute] = (string) $value; + } + + return array($name, $attributes); + } + + protected function removeEmptyKey(&$hash, $key) + { + if (isset($hash[$key]) && !$hash[$key]) + { + unset($hash[$key]); + } + } +} diff --git a/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/new_schema.yml b/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/new_schema.yml new file mode 100644 index 0000000..593b67a --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/new_schema.yml @@ -0,0 +1,65 @@ +connection: propel +noXsd: false +defaultIdMethod: none +package: lib.model + +classes: + Group: + tableName: ab_group + package: foo.bar.lib.model + columns: + id: + name: varchar(50) + + User: + tableName: cd_user + isI18N: true + i18nTable: cd_user_i18n + columns: + first_name: { type: varchar, size: 255, default: "Anonymous" } + last_name: varchar(50) + age: { type: integer, required: true, index: true } + ab_group_id: + created_at: + + CdUserI18n: + tableName: cd_user_i18n + columns: + description: longvarchar + + EfArticle: + tableName: ef_article + columns: + title: { type: longvarchar, required: true, index: unique } + stripped_title: { type: longvarchar, required: true, primaryKey: true, sequence: my_custom_sequence_name } + user_id: + my_group: { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } + my_other_group: { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } + created_at: timestamp + updated_at: + + Article: + tableName: ij_article + columns: + title: varchar(50) + user_id: { type: integer } + created_at: + foreignKeys: + - + foreignTable: cd_user + onDelete: cascade + references: + - { local: user_id, foreign: id } + indexes: + my_index: [title, user_id] + uniques: + my_other_index: [created_at] + behaviors: + paranoid: { column: deleted_at } + act_as_nested_set: + + + AbGroupI18n: + tableName: ab_group_i18n + columns: + motto: longvarchar \ No newline at end of file diff --git a/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/schema.xml b/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/schema.xml new file mode 100644 index 0000000..cccc59c --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/schema.xml @@ -0,0 +1,82 @@ + + + + + + +
    + + + + + + + + + + + + + + +
    + + + + + + + + +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + + + + + + +
    + + + + + + + + +
    + +
    diff --git a/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/schema.yml b/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/schema.yml new file mode 100644 index 0000000..294dab2 --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/test/unit/fixtures/schema.yml @@ -0,0 +1,48 @@ +propel: + _attributes: { noXsd: false, defaultIdMethod: none, package: lib.model } + ab_group: + _attributes: { phpName: Group, package: foo.bar.lib.model } + id: + name: varchar(50) + + cd_user: + _attributes: { phpName: User, isI18N: true, i18nTable: cd_user_i18n } + first_name: { type: varchar, size: 255, default: "Anonymous" } + last_name: varchar(50) + age: { type: integer, required: true, index: true } + ab_group_id: + created_at: + + cd_user_i18n: + description: longvarchar + + ef_article: + title: { type: longvarchar, required: true, index: unique } + stripped_title: { type: longvarchar, required: true, primaryKey: true, sequence: my_custom_sequence_name } + user_id: + my_group: { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } + my_other_group: { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } + created_at: timestamp + updated_at: + + ij_article: + _attributes: { phpName: Article } + title: varchar(50) + user_id: { type: integer } + _foreignKeys: + - + foreignTable: cd_user + onDelete: cascade + references: + - { local: user_id, foreign: id } + created_at: + _indexes: + my_index: [title, user_id] + _uniques: + my_other_index: [created_at] + _behaviors: + paranoid: { column: deleted_at } + act_as_nested_set: + + ab_group_i18n: + motto: longvarchar \ No newline at end of file diff --git a/plugins/sfPropelAlternativeSchemaPlugin/test/unit/sfPropelDatabaseSchemaTest.php b/plugins/sfPropelAlternativeSchemaPlugin/test/unit/sfPropelDatabaseSchemaTest.php new file mode 100644 index 0000000..673290d --- /dev/null +++ b/plugins/sfPropelAlternativeSchemaPlugin/test/unit/sfPropelDatabaseSchemaTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +include(dirname(__FILE__).'/../../../../test/bootstrap/unit.php'); + +class sfPropelAlternativeSchema +{ + static function cleanBehaviorsOnce() + { + + } +} + +class my_lime_test extends lime_test +{ + public function is_array_explicit($test, $target, $prefix = '') + { + foreach ($test as $key => $value) + { + if (is_array($value)) + { + $this->is_array_explicit($value, $target[$key], $prefix.' '.$key); + } + else + { + $this->is($value, $target[$key], sprintf('%s %s is %s', $prefix, $key, $value)); + } + } + } + + public function is_line_by_line($exp1, $exp2) + { + $array_exp1 = explode("\n", $exp1); + $array_exp2 = explode("\n", $exp2); + $nb_lines = count($array_exp1); + for ($i=0; $i < $nb_lines; $i++) + { + if(!$array_exp1[$i]) continue; // Skip blank lines to avoid testing nothing + $this->is(trim($array_exp1[$i]), trim($array_exp2[$i]), sprintf('Line %d matches %s', $i, $array_exp1[$i])); + } + } +} + +$t = new my_lime_test(261, new lime_output_color()); + +require_once(dirname(__FILE__).'/../../lib/sfPropelDatabaseSchema.class.php'); +require_once($sf_symfony_lib_dir.'/util/sfInflector.class.php'); +require_once($sf_symfony_lib_dir.'/util/sfToolkit.class.php'); +require_once($sf_symfony_lib_dir.'/util/sfYaml.class.php'); + +$t->diag('Classical YAML to XML conversion'); +$p = new sfPropelDatabaseSchema(); +$p->loadYAML(dirname(__FILE__).'/fixtures/schema.yml'); +$target = file_get_contents(dirname(__FILE__).'/fixtures/schema.xml'); +$t->is_line_by_line($p->asXML(), $target); + +$t->diag('New YAML to XML conversion'); +$p = new sfPropelDatabaseSchema(); +$p->loadYAML(dirname(__FILE__).'/fixtures/new_schema.yml'); +$target = file_get_contents(dirname(__FILE__).'/fixtures/schema.xml'); +$t->is_line_by_line($p->asXML(), $target); + +$t->diag('New YAML to Old YAML conversion'); +$old_yml_target = sfYaml::load(dirname(__FILE__).'/fixtures/schema.yml'); +$p = new sfPropelDatabaseSchema(); +$new_yml_transformed = $p->convertNewToOldYaml(sfYaml::load(dirname(__FILE__).'/fixtures/new_schema.yml')); +$t->is_array_explicit($new_yml_transformed, $old_yml_target); + +$t->diag('Old YAML to New YAML conversion'); +$new_yml_target = sfYaml::load(dirname(__FILE__).'/fixtures/new_schema.yml'); +$p = new sfPropelDatabaseSchema(); +$old_yml_transformed = $p->convertOldToNewYaml(sfYaml::load(dirname(__FILE__).'/fixtures/schema.yml')); +$t->is_array_explicit($old_yml_transformed, $new_yml_target); + + +$t->todo('XML and classical YAML internal representation'); +$p1 = new sfPropelDatabaseSchema(); +$p1->loadXML(dirname(__FILE__).'/fixtures/schema.xml'); +$p2 = new sfPropelDatabaseSchema(); +$p2->loadYAML(dirname(__FILE__).'/fixtures/schema.yml'); +//$t->is_array_explicit($p1->asArray(), $p2->asArray()); + +$t->todo('XML and classical YAML compared as XML'); +//$t->is_line_by_line($p1->asXML(), $p2->asXML()); + +$t->todo('XML and classical YAML compared as YAML'); +//$t->is_line_by_line($p1->asYAML(), $p2->asYAML()); \ No newline at end of file diff --git a/plugins/sfReCaptchaPlugin/LICENSE b/plugins/sfReCaptchaPlugin/LICENSE new file mode 100644 index 0000000..43f6da2 --- /dev/null +++ b/plugins/sfReCaptchaPlugin/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2008 Arthur Koziel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/plugins/sfReCaptchaPlugin/README b/plugins/sfReCaptchaPlugin/README new file mode 100644 index 0000000..7d04f7c --- /dev/null +++ b/plugins/sfReCaptchaPlugin/README @@ -0,0 +1 @@ +For more information about the reCaptchaPlugin, navigate to http://trac.symfony-project.com/wiki/sfReCaptchaPlugin \ No newline at end of file diff --git a/plugins/sfReCaptchaPlugin/lib/helper/recaptchaHelper.php b/plugins/sfReCaptchaPlugin/lib/helper/recaptchaHelper.php new file mode 100644 index 0000000..ec18078 --- /dev/null +++ b/plugins/sfReCaptchaPlugin/lib/helper/recaptchaHelper.php @@ -0,0 +1,3 @@ + $value ) + $req .= $key . '=' . urlencode( stripslashes($value) ) . '&'; + + // Cut the last '&' + $req=substr($req,0,strlen($req)-1); + return $req; +} + + + +/** + * Submits an HTTP POST to a reCAPTCHA server + * @param string $host + * @param string $path + * @param array $data + * @param int port + * @return array response + */ +function _recaptcha_http_post($host, $path, $data, $port = 80) { + + $req = _recaptcha_qsencode ($data); + + $http_request = "POST $path HTTP/1.0\r\n"; + $http_request .= "Host: $host\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: " . strlen($req) . "\r\n"; + $http_request .= "User-Agent: reCAPTCHA/PHP\r\n"; + $http_request .= "\r\n"; + $http_request .= $req; + + $response = ''; + if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) { + die ('Could not open socket'); + } + + fwrite($fs, $http_request); + + while ( !feof($fs) ) + $response .= fgets($fs, 1160); // One TCP-IP packet + fclose($fs); + $response = explode("\r\n\r\n", $response, 2); + + return $response; +} + + + +/** + * Gets the challenge HTML (javascript and non-javascript version). + * This is called from the browser, and the resulting reCAPTCHA HTML widget + * is embedded within the HTML form it was called from. + * @param string $pubkey A public key for reCAPTCHA + * @param string $error The error given by reCAPTCHA (optional, default is null) + * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false) + + * @return string - The HTML to be embedded in the user's form. + */ +function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false) +{ + if ($pubkey == null || $pubkey == '') { + die ("To use reCAPTCHA you must get an API key from http://recaptcha.net/api/getkey"); + } + + if ($use_ssl) { + $server = RECAPTCHA_API_SECURE_SERVER; + } else { + $server = RECAPTCHA_API_SERVER; + } + + $errorpart = ""; + if ($error) { + $errorpart = "&error=" . $error; + } + return ' + + '; +} + + + + +/** + * A ReCaptchaResponse is returned from recaptcha_check_answer() + */ +class ReCaptchaResponse { + var $is_valid; + var $error; +} + + +/** + * Calls an HTTP POST function to verify if the user's guess was correct + * @param string $privkey + * @param string $remoteip + * @param string $challenge + * @param string $response + * @param array $extra_params an array of extra variables to post to the server + * @return ReCaptchaResponse + */ +function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array()) +{ + if ($privkey == null || $privkey == '') { + die ("To use reCAPTCHA you must get an API key from http://recaptcha.net/api/getkey"); + } + + if ($remoteip == null || $remoteip == '') { + die ("For security reasons, you must pass the remote ip to reCAPTCHA"); + } + + + + //discard spam submissions + if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) { + $recaptcha_response = new ReCaptchaResponse(); + $recaptcha_response->is_valid = false; + $recaptcha_response->error = 'incorrect-captcha-sol'; + return $recaptcha_response; + } + + $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/verify", + array ( + 'privatekey' => $privkey, + 'remoteip' => $remoteip, + 'challenge' => $challenge, + 'response' => $response + ) + $extra_params + ); + + $answers = explode ("\n", $response [1]); + $recaptcha_response = new ReCaptchaResponse(); + + if (trim ($answers [0]) == 'true') { + $recaptcha_response->is_valid = true; + } + else { + $recaptcha_response->is_valid = false; + $recaptcha_response->error = $answers [1]; + } + return $recaptcha_response; + +} + +/** + * gets a URL where the user can sign up for reCAPTCHA. If your application + * has a configuration page where you enter a key, you should provide a link + * using this function. + * @param string $domain The domain where the page is hosted + * @param string $appname The name of your application + */ +function recaptcha_get_signup_url ($domain = null, $appname = null) { + return "http://recaptcha.net/api/getkey?" . _recaptcha_qsencode (array ('domain' => $domain, 'app' => $appname)); +} + +function _recaptcha_aes_pad($val) { + $block_size = 16; + $numpad = $block_size - (strlen ($val) % $block_size); + return str_pad($val, strlen ($val) + $numpad, chr($numpad)); +} + +/* Mailhide related code */ + +function _recaptcha_aes_encrypt($val,$ky) { + if (! function_exists ("mcrypt_encrypt")) { + die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed."); + } + $mode=MCRYPT_MODE_CBC; + $enc=MCRYPT_RIJNDAEL_128; + $val=_recaptcha_aes_pad($val); + return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); +} + + +function _recaptcha_mailhide_urlbase64 ($x) { + return strtr(base64_encode ($x), '+/', '-_'); +} + +/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */ +function recaptcha_mailhide_url($pubkey, $privkey, $email) { + if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) { + die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " . + "you can do so at http://mailhide.recaptcha.net/apikey"); + } + + + $ky = pack('H*', $privkey); + $cryptmail = _recaptcha_aes_encrypt ($email, $ky); + + return "http://mailhide.recaptcha.net/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail); +} + +/** + * gets the parts of the email to expose to the user. + * eg, given johndoe@example,com return ["john", "example.com"]. + * the email is then displayed as john...@example.com + */ +function _recaptcha_mailhide_email_parts ($email) { + $arr = preg_split("/@/", $email ); + + if (strlen ($arr[0]) <= 4) { + $arr[0] = substr ($arr[0], 0, 1); + } else if (strlen ($arr[0]) <= 6) { + $arr[0] = substr ($arr[0], 0, 3); + } else { + $arr[0] = substr ($arr[0], 0, 4); + } + return $arr; +} + +/** + * Gets html to display an email address given a public an private key. + * to get a key, go to: + * + * http://mailhide.recaptcha.net/apikey + */ +function recaptcha_mailhide_html($pubkey, $privkey, $email) { + $emailparts = _recaptcha_mailhide_email_parts ($email); + $url = recaptcha_mailhide_url ($pubkey, $privkey, $email); + + return htmlentities($emailparts[0]) . "...@" . htmlentities ($emailparts [1]); + +} + + +?> diff --git a/plugins/sfReCaptchaPlugin/lib/sfReCaptchaValidator.class.php b/plugins/sfReCaptchaPlugin/lib/sfReCaptchaValidator.class.php new file mode 100644 index 0000000..237fd38 --- /dev/null +++ b/plugins/sfReCaptchaPlugin/lib/sfReCaptchaValidator.class.php @@ -0,0 +1,64 @@ + + * @version SVN: $Id$ + */ +class sfReCaptchaValidator extends sfValidator +{ + /** + * Execute this validator. + * + * @param mixed A file or parameter value/array + * @param error An error message reference + * + * @return bool true, if this validator executes successfully, otherwise false + */ + public function execute(&$value, &$error) + { + if (sfConfig::get('sf_environment') === 'test') { + return true; + } + + // get values of challange and response fields + $challenge = $this->getContext()->getRequest()->getParameter('recaptcha_challenge_field'); + $response = $this->getContext()->getRequest()->getParameter('recaptcha_response_field'); + + // validate the given response against the challenge + $resp = recaptcha_check_answer (sfConfig::get('app_recaptcha_privatekey'), + $_SERVER["REMOTE_ADDR"], + $challenge, + $response); + + // if invalid, return error + if (!$resp->is_valid) + { + $error = $resp->error; + + return false; + } + + return true; + } + + /** + * Initializes the validator. + * + * @param sfContext The current application context + * @param array An associative array of initialization parameters + * + * @return bool true, if initialization completes successfully, otherwise false + */ + public function initialize($context, $parameters = null) + { + require_once ('recaptchalib.php'); + + parent::initialize($context); + + return true; + } +} diff --git a/plugins/sfReCaptchaPlugin/modules/recaptcha/actions/actions.class.php b/plugins/sfReCaptchaPlugin/modules/recaptcha/actions/actions.class.php new file mode 100644 index 0000000..1b19a96 --- /dev/null +++ b/plugins/sfReCaptchaPlugin/modules/recaptcha/actions/actions.class.php @@ -0,0 +1,28 @@ + + * @version SVN: $Id$ + */ +class recaptchaActions extends sfActions +{ + public function executeIndex() + { + if ($this->getRequest()->getMethod() == sfRequest::POST) { + // captcha correct; do whatever you want here + } + } + + public function handleErrorIndex() + { + return sfView::SUCCESS; + } + + public function executeMailhide() + { + } +} diff --git a/plugins/sfReCaptchaPlugin/modules/recaptcha/templates/indexSuccess.php b/plugins/sfReCaptchaPlugin/modules/recaptcha/templates/indexSuccess.php new file mode 100644 index 0000000..4517ba5 --- /dev/null +++ b/plugins/sfReCaptchaPlugin/modules/recaptcha/templates/indexSuccess.php @@ -0,0 +1,7 @@ + + + + getError('recaptcha_response_field')); ?> + + \ No newline at end of file diff --git a/plugins/sfReCaptchaPlugin/modules/recaptcha/templates/mailhideSuccess.php b/plugins/sfReCaptchaPlugin/modules/recaptcha/templates/mailhideSuccess.php new file mode 100644 index 0000000..d058eab --- /dev/null +++ b/plugins/sfReCaptchaPlugin/modules/recaptcha/templates/mailhideSuccess.php @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/plugins/sfReCaptchaPlugin/modules/recaptcha/validate/index.yml b/plugins/sfReCaptchaPlugin/modules/recaptcha/validate/index.yml new file mode 100644 index 0000000..95bd00e --- /dev/null +++ b/plugins/sfReCaptchaPlugin/modules/recaptcha/validate/index.yml @@ -0,0 +1,3 @@ +fields: + recaptcha_response_field: + sfReCaptchaValidator: diff --git a/plugins/sfThumbnailPlugin/LICENSE b/plugins/sfThumbnailPlugin/LICENSE new file mode 100644 index 0000000..28956ad --- /dev/null +++ b/plugins/sfThumbnailPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2004-2006 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfThumbnailPlugin/README b/plugins/sfThumbnailPlugin/README new file mode 100644 index 0000000..dd853e1 --- /dev/null +++ b/plugins/sfThumbnailPlugin/README @@ -0,0 +1,162 @@ += sfThumbnailPlugin plugin = + +The `sfThumbnailPlugin` creates thumbnails from images. It relies on your choice of the [http://php.net/gd/ GD] or [http://www.imagemagick.org ImageMagick] libraries. + +== Installation == + +To install the plugin for a symfony project, the usual process is to use the symfony command line: +{{{ +$ symfony plugin-install http://plugins.symfony-project.com/sfThumbnailPlugin +}}} + +Alternatively, if you don't have PEAR installed, you can download the latest package attached to this plugin's wiki page and extract it under your project's `plugins/` directory. + +Clear the cache to enable the autoloading to find the new classes: +{{{ +$ php symfony cc +}}} + +You're done. + +'''Note''': If the [http://php.net/gd GD library] is not activated, you might have to uncomment the related line in your `php.ini` and restart your web server to enable PHP image handling functions. + +'''Note''': To use !ImageMagick, you'll need to download and install the binaries from http://www.imagemagick.org. + +== Contents == + +The plugin contains three classes, `sfThumbnail`, `sfGDAdapter` and `sfImageMagickAdapter`. Available methods are: + +{{{ +// Initialize the thumbnail attributes +__construct($maxWidth = null, $maxHeight = null, $scale = true, $inflate = true, $quality = 75, $adapterClass = null, $adapterOptions = array()) + +// Load image file from a file system +loadFile($imageFile) + +// Load image file from a string (GD adapter only, currently) +loadData($imageString, $mimeType) + +// Save the thumbnail to a file +save($thumbFile, $targetMime = null) +}}} + +Supported GD image types are 'image/jpeg', 'image/png' and 'image/gif'. + +!ImageMagick supports over [http://www.imagemagick.org/script/formats.php 100 types]. + +Note that the $quality setting only applies to JPEG images. + +== Usage == + +=== Creating a thumbnail from an existing image file === + +The process of creating a thumbnail from an existing image file is pretty straightforward. + +First, you must initialize a new `sfThumbnail` object with two parameters: the maximum width and height of the desired thumbnail. + +{{{ +// Initialize the object for 150x150 thumbnails +$thumbnail = new sfThumbnail(150, 150); +}}} + +Then, specify a file path to the image to reduce to the `loadFile()` method. + +{{{ +// Load the image to reduce +$thumbnail->loadFile('/path/to/image/file.png'); +}}} + +Finally, ask the thumbnail object to save the thumbnail. You must provide a file path. Optionally, if you don't want the thumbnail to use the same mime type as the source image, you can specify a mime type as the second parameter. + +{{{ +// Save the thumbnail +$thumbnail->save('/path/to/thumbnail/file.jpg', 'image/jpg'); +}}} + +Both the source and destination file paths must be absolute paths in your filesystem. To store files under a symfony project directory, make sure you use the [http://www.symfony-project.com/book/trunk/19-Mastering-Symfony-s-Configuration-Files#The%20Basic%20File%20Structure directory constants], accessed by `sfConfig::get()`. + +=== Creating a thumbnail for an uploaded file === + +If you upload images, you might need to create thumbnails of each uploaded file. For instance, to save a thumbnail of maximum size 150x150px at the same time as the uploaded image, the form handling action can look like: + +{{{ +public function executeUpload() +{ + // Retrieve the name of the uploaded file + $fileName = $this->getRequest()->getFileName('file'); + + // Create the thumbnail + $thumbnail = new sfThumbnail(150, 150); + $thumbnail->loadFile($this->getRequest()->getFilePath('file')); + $thumbnail->save(sfConfig::get('sf_upload_dir').'/thumbnail/'.$fileName, 'image/png'); + + // Move the uploaded file to the 'uploads' directory + $this->getRequest()->moveFile('file', sfConfig::get('sf_upload_dir').'/'.$fileName); + + // Do whatever is next + $this->redirect('media/show?filename='.$fileName); +} +}}} + +Don't forget to create the `uploads/thumbnail/` directory before calling the action. + +== !ImageMagick-Specific Usage == + +Usage is the same as above except you need to explicitly call the sfImageMagickAdapter class. + +{{{ +$thumbnail = new sfThumbnail(150, 150, true, true, 75, 'sfImageMagickAdapter'); +}}} + +=== Custom Options === + +The last option in the constructor is an array that you can use to pass custom options to !ImageMagick. Below are some examples of this functionality. + +Extract the first page from a PDF document: + +{{{ +$thumbnail = new sfThumbnail(150, 150, true, true, 75, 'sfImageMagickAdapter', array('extract' => 1)); +}}} + +"1" stands for the first page, "2" for the second page, etc. + +If for some reason you use a non-standard name for your !ImageMagick binary, you can specify it like so: + +{{{ +$thumbnail = new sfThumbnail(150, 150, true, true, 75, 'sfImageMagickAdapter', array('convert' => 'my_imagemagick_binary')); +}}} + +By default sfThumbnail resizes the image in order to get to the desired width and height of the thumbnail. But what if you want to force the thumbnail to be a certain width and height but without distorting the image of the source size scale is different than the thumbnail size scale +Now you can use a custom option "method" to achieve just that but "shaving" the source image in order to get it to be the same scale as the thumbnail and them resize it to the required dimentions. +When "shave_bottom" is used and the image’s width is greater than the height then sfThumbnail shaves from both left side and right side until the desired scale. +There is one requirement for the "method" option to work as expected and it is to turn off scaling (set the third parameter of sfThumbnail to FALSE) + +{{{ +$thumbnail = new sfThumbnail(150, 150, false, true, 75, 'sfImageMagickAdapter', array('method' => 'shave_all')); + +$thumbnail->loadFile('http://www.walkerbooks.co.uk/assets_walker/dynamic/1172005677146.png'); +$thumbnail->save('/tmp/shave.png', 'image/png'); +}}} + +== Changelog == + +=== Trunk === + +=== 2007-09-15 | 1.5.0 Stable === + + * kupokomapa: toString($mime) method now works for both adapters + * kupokomapa: loadFile() method can now accept a URI if sfWebBrowserPluging is available + * kupokomapa: Implemented "method" option for sfImageMagickAdapter where "method" for now can be "shave_all" or "shave_bottom" + +=== 2007-09-12 | 1.4.0 Stable === + + * davedash: Added toString($mime) function to save file to a string + +=== 2007-05-18 | 1.3.0 Stable === + + * bmeynell: Updated README + * bmeynell: Fixed ticket (#1710) + * bmeynell: Added adapter support + * francois: Updated README + +=== 2006-11-29 | 1.2.0 Stable === diff --git a/plugins/sfThumbnailPlugin/lib/sfGDAdapter.class.php b/plugins/sfThumbnailPlugin/lib/sfGDAdapter.class.php new file mode 100644 index 0000000..a6d3417 --- /dev/null +++ b/plugins/sfThumbnailPlugin/lib/sfGDAdapter.class.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfGDAdapter provides a mechanism for creating thumbnail images. + * @see http://www.php.net/gd + * + * @package sfThumbnailPlugin + * @author Fabien Potencier + * @author Benjamin Meynell + */ + +class sfGDAdapter +{ + + protected + $sourceWidth, + $sourceHeight, + $sourceMime, + $maxWidth, + $maxHeight, + $scale, + $inflate, + $quality, + $source, + $thumb; + + /** + * List of accepted image types based on MIME + * descriptions that this adapter supports + */ + protected $imgTypes = array( + 'image/jpeg', + 'image/pjpeg', + 'image/png', + 'image/gif', + ); + + /** + * Stores function names for each image type + */ + protected $imgLoaders = array( + 'image/jpeg' => 'imagecreatefromjpeg', + 'image/pjpeg' => 'imagecreatefromjpeg', + 'image/png' => 'imagecreatefrompng', + 'image/gif' => 'imagecreatefromgif', + ); + + /** + * Stores function names for each image type + */ + protected $imgCreators = array( + 'image/jpeg' => 'imagejpeg', + 'image/pjpeg' => 'imagejpeg', + 'image/png' => 'imagepng', + 'image/gif' => 'imagegif', + ); + + public function __construct($maxWidth, $maxHeight, $scale, $inflate, $quality, $options) + { + if (!extension_loaded('gd')) + { + throw new Exception ('GD not enabled. Check your php.ini file.'); + } + $this->maxWidth = $maxWidth; + $this->maxHeight = $maxHeight; + $this->scale = $scale; + $this->inflate = $inflate; + $this->quality = $quality; + $this->options = $options; + } + + public function loadFile($thumbnail, $image) + { + $imgData = @GetImageSize($image); + + if (!$imgData) + { + throw new Exception(sprintf('Could not load image %s', $image)); + } + + if (in_array($imgData['mime'], $this->imgTypes)) + { + $loader = $this->imgLoaders[$imgData['mime']]; + if(!function_exists($loader)) + { + throw new Exception(sprintf('Function %s not available. Please enable the GD extension.', $loader)); + } + + $this->source = $loader($image); + $this->sourceWidth = $imgData[0]; + $this->sourceHeight = $imgData[1]; + $this->sourceMime = $imgData['mime']; + $thumbnail->initThumb($this->sourceWidth, $this->sourceHeight, $this->maxWidth, $this->maxHeight, $this->scale, $this->inflate); + + $this->thumb = imagecreatetruecolor($thumbnail->getThumbWidth(), $thumbnail->getThumbHeight()); + if ($imgData[0] == $this->maxWidth && $imgData[1] == $this->maxHeight) + { + $this->thumb = $this->source; + } + else + { + imagecopyresampled($this->thumb, $this->source, 0, 0, 0, 0, $thumbnail->getThumbWidth(), $thumbnail->getThumbHeight(), $imgData[0], $imgData[1]); + } + + return true; + } + else + { + throw new Exception(sprintf('Image MIME type %s not supported', $imgData['mime'])); + } + } + + public function loadData($thumbnail, $image, $mime) + { + if (in_array($mime,$this->imgTypes)) + { + $this->source = imagecreatefromstring($image); + $this->sourceWidth = imagesx($this->source); + $this->sourceHeight = imagesy($this->source); + $this->sourceMime = $mime; + $thumbnail->initThumb($this->sourceWidth, $this->sourceHeight, $this->maxWidth, $this->maxHeight, $this->scale, $this->inflate); + + $this->thumb = imagecreatetruecolor($thumbnail->getThumbWidth(), $thumbnail->getThumbHeight()); + if ($this->sourceWidth == $this->maxWidth && $this->sourceHeight == $this->maxHeight) + { + $this->thumb = $this->source; + } + else + { + imagecopyresampled($this->thumb, $this->source, 0, 0, 0, 0, $thumbnail->getThumbWidth(), $thumbnail->getThumbHeight(), $this->sourceWidth, $this->sourceHeight); + } + + return true; + } + else + { + throw new Exception(sprintf('Image MIME type %s not supported', $mime)); + } + } + + public function save($thumbnail, $thumbDest, $targetMime = null) + { + if($targetMime !== null) + { + $creator = $this->imgCreators[$targetMime]; + } + else + { + $creator = $this->imgCreators[$thumbnail->getMime()]; + } + + if ($creator == 'imagejpeg') + { + imagejpeg($this->thumb, $thumbDest, $this->quality); + } + else + { + $creator($this->thumb, $thumbDest); + } + } + + public function toString($thumbnail, $targetMime = null) + { + if ($targetMime !== null) + { + $creator = $this->imgCreators[$targetMime]; + } + else + { + $creator = $this->imgCreators[$thumbnail->getMime()]; + } + + ob_start(); + $creator($this->thumb); + + return ob_get_clean(); + } + + public function freeSource() + { + if (is_resource($this->source)) + { + imagedestroy($this->source); + } + } + + public function freeThumb() + { + if (is_resource($this->thumb)) + { + imagedestroy($this->thumb); + } + } + + public function getSourceMime() + { + return $this->sourceMime; + } + +} diff --git a/plugins/sfThumbnailPlugin/lib/sfImageMagickAdapter.class.php b/plugins/sfThumbnailPlugin/lib/sfImageMagickAdapter.class.php new file mode 100644 index 0000000..1c778d4 --- /dev/null +++ b/plugins/sfThumbnailPlugin/lib/sfImageMagickAdapter.class.php @@ -0,0 +1,344 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfImageMagickAdapter provides a mechanism for creating thumbnail images. + * @see http://www.imagemagick.org + * + * @package sfThumbnailPlugin + * @author Fabien Potencier + * @author Benjamin Meynell + */ + +class sfImageMagickAdapter +{ + + protected + $sourceWidth, + $sourceHeight, + $sourceMime, + $maxWidth, + $maxHeight, + $scale, + $inflate, + $quality, + $source, + $magickCommands; + + /** + * Mime types this adapter supports + */ + protected $imgTypes = array( + 'application/pdf', + 'application/postscript', + 'application/vnd.palm', + 'application/x-icb', + 'application/x-mif', + 'image/dcx', + 'image/g3fax', + 'image/gif', + 'image/jng', + 'image/jpeg', + 'image/pbm', + 'image/pcd', + 'image/pict', + 'image/pjpeg', + 'image/png', + 'image/ras', + 'image/sgi', + 'image/svg', + 'image/tga', + 'image/tiff', + 'image/vda', + 'image/vnd.wap.wbmp', + 'image/vst', + 'image/x-fits', + 'image/x-ms-bmp', + 'image/x-otb', + 'image/x-palm', + 'image/x-pcx', + 'image/x-pgm', + 'image/x-photoshop', + 'image/x-ppm', + 'image/x-ptiff', + 'image/x-viff', + 'image/x-win-bitmap', + 'image/x-xbitmap', + 'image/x-xv', + 'image/xpm', + 'image/xwd', + 'text/plain', + 'video/mng', + 'video/mpeg', + 'video/mpeg2', + ); + + /** + * Imagemagick-specific Type to Mime type map + */ + protected $mimeMap = array( + 'bmp' => 'image/bmp', + 'bmp2' => 'image/bmp', + 'bmp3' => 'image/bmp', + 'cur' => 'image/x-win-bitmap', + 'dcx' => 'image/dcx', + 'epdf' => 'application/pdf', + 'epi' => 'application/postscript', + 'eps' => 'application/postscript', + 'eps2' => 'application/postscript', + 'eps3' => 'application/postscript', + 'epsf' => 'application/postscript', + 'epsi' => 'application/postscript', + 'ept' => 'application/postscript', + 'ept2' => 'application/postscript', + 'ept3' => 'application/postscript', + 'fax' => 'image/g3fax', + 'fits' => 'image/x-fits', + 'g3' => 'image/g3fax', + 'gif' => 'image/gif', + 'gif87' => 'image/gif', + 'icb' => 'application/x-icb', + 'ico' => 'image/x-win-bitmap', + 'icon' => 'image/x-win-bitmap', + 'jng' => 'image/jng', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'm2v' => 'video/mpeg2', + 'miff' => 'application/x-mif', + 'mng' => 'video/mng', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'otb' => 'image/x-otb', + 'p7' => 'image/x-xv', + 'palm' => 'image/x-palm', + 'pbm' => 'image/pbm', + 'pcd' => 'image/pcd', + 'pcds' => 'image/pcd', + 'pcl' => 'application/pcl', + 'pct' => 'image/pict', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/vnd.palm', + 'pdf' => 'application/pdf', + 'pgm' => 'image/x-pgm', + 'picon' => 'image/xpm', + 'pict' => 'image/pict', + 'pjpeg' => 'image/pjpeg', + 'png' => 'image/png', + 'png24' => 'image/png', + 'png32' => 'image/png', + ); + + public function __construct($maxWidth, $maxHeight, $scale, $inflate, $quality, $options) + { + $this->magickCommands = array(); + $this->magickCommands['convert'] = isset($options['convert']) ? escapeshellcmd($options['convert']) : 'convert'; + $this->magickCommands['identify'] = isset($options['identify']) ? escapeshellcmd($options['identify']) : 'identify'; + + exec($this->magickCommands['convert'], $stdout); + if (strpos($stdout[0], 'ImageMagick') === false) + { + throw new Exception(sprintf("ImageMagick convert command not found")); + } + + exec($this->magickCommands['identify'], $stdout); + if (strpos($stdout[0], 'ImageMagick') === false) + { + throw new Exception(sprintf("ImageMagick identify command not found")); + } + + $this->maxWidth = $maxWidth; + $this->maxHeight = $maxHeight; + $this->scale = $scale; + $this->inflate = $inflate; + $this->quality = $quality; + $this->options = $options; + } + + public function toString($thumbnail, $targetMime = null) + { + ob_start(); + $this->save($thumbnail, null, $targetMime); + + return ob_get_clean(); + } + + public function loadFile($thumbnail, $image) + { + // try and use getimagesize() + // on failure, use identify instead + $imgData = @getimagesize($image); + if (!$imgData) + { + exec($this->magickCommands['identify'].' '.escapeshellarg($image), $stdout, $retval); + if ($retval === 1) + { + throw new Exception('Image could not be identified.'); + } + else + { + // get image data via identify + list($img, $type, $dimen) = explode(' ', $stdout[0]); + list($width, $height) = explode('x', $dimen); + + $this->sourceWidth = $width; + $this->sourceHeight = $height; + $this->sourceMime = $this->mimeMap[strtolower($type)]; + } + } + else + { + // use image data from getimagesize() + $this->sourceWidth = $imgData[0]; + $this->sourceHeight = $imgData[1]; + $this->sourceMime = $imgData['mime']; + } + $this->image = $image; + + // open file resource + $source = fopen($image, 'r'); + + $this->source = $source; + + $thumbnail->initThumb($this->sourceWidth, $this->sourceHeight, $this->maxWidth, $this->maxHeight, $this->scale, $this->inflate); + + return true; + } + + public function loadData($thumbnail, $image, $mime) + { + throw new Exception('This function is not yet implemented. Try a different adapter.'); + } + + public function save($thumbnail, $thumbDest, $targetMime = null) + { + $command = ''; + + $width = $this->sourceWidth; + $height = $this->sourceHeight; + $x = $y = 0; + switch (@$this->options['method']) { + case "shave_all": + if ($width > $height) + { + $x = ceil(($width - $height) / 2 ); + $width = $height; + } + elseif ($height > $width) + { + $y = ceil(($height - $width) / 2); + $height = $width; + } + + $command = sprintf(" -shave %dx%d", $x, $y); + break; + case "shave_bottom": + if ($width > $height) + { + $x = ceil(($width - $height) / 2 ); + $width = $height; + } + elseif ($height > $width) + { + $y = 0; + $height = $width; + } + + if (is_null($thumbDest)) + { + $command = sprintf( + " -crop %dx%d+%d+%d %s '-' | %s", + $width, $height, + $x, $y, + escapeshellarg($this->image), + $this->magickCommands['convert'] + ); + + $this->image = '-'; + } + else + { + $command = sprintf( + " -crop %dx%d+%d+%d %s %s && %s", + $width, $height, + $x, $y, + escapeshellarg($this->image), escapeshellarg($thumbDest), + $this->magickCommands['convert'] + ); + + $this->image = $thumbDest; + } + + break; + } // end switch + + /* + * This is a solution to the RT#21554 bug: Gif-animation does not play + * @author Robert Strind + * + * Aditional parameters for animated gif files + * Fully define the look of each frame of an GIF animation sequence, to form + * a 'film strip' animation. + */ + if ($thumbnail->getMime() == 'image/gif') { + $command .= ' -coalesce'; + } + + $command .= ' -thumbnail '; + $command .= $thumbnail->getThumbWidth().'x'.$thumbnail->getThumbHeight(); + + // absolute sizing + if (!$this->scale) + { + $command .= '!'; + } + + if ($this->quality && $thumbnail->getMime() == 'image/jpeg') + { + $command .= ' -quality '.$this->quality.'% '; + } + + // extract images such as pages from a pdf doc + $extract = ''; + if (isset($this->options['extract']) && is_int($this->options['extract'])) + { + if ($this->options['extract'] > 0) + { + $this->options['extract']--; + } + $extract = '['.escapeshellarg($this->options['extract']).'] '; + } + + $output = (is_null($thumbDest))?'-':$thumbDest; + $output = (($mime = array_search($targetMime, $this->mimeMap))?$mime.':':'').$output; + + $cmd = $this->magickCommands['convert'].' '.escapeshellarg($this->image).' '.$command.' '.$extract.' '.escapeshellarg($output); + + (is_null($thumbDest))?passthru($cmd):exec($cmd); + } + + public function freeSource() + { + if (is_resource($this->source)) + { + fclose($this->source); + } + } + + public function freeThumb() + { + return true; + } + + public function getSourceMime() + { + return $this->sourceMime; + } + +} diff --git a/plugins/sfThumbnailPlugin/lib/sfThumbnail.class.php b/plugins/sfThumbnailPlugin/lib/sfThumbnail.class.php new file mode 100644 index 0000000..ffd2a44 --- /dev/null +++ b/plugins/sfThumbnailPlugin/lib/sfThumbnail.class.php @@ -0,0 +1,251 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfThumbnail provides a mechanism for creating thumbnail images. + * + * This is taken from Harry Fueck's Thumbnail class and + * converted for PHP5 strict compliance for use with symfony. + * + * @package sfThumbnailPlugin + * @author Fabien Potencier + * @author Benjamin Meynell + */ +class sfThumbnail +{ + /** + * Width of thumbnail in pixels + */ + protected $thumbWidth; + + /** + * Height of thumbnail in pixels + */ + protected $thumbHeight; + + /** + * Temporary file if the source is not local + */ + protected $tempFile = null; + + /** + * Thumbnail constructor + * + * @param int (optional) max width of thumbnail + * @param int (optional) max height of thumbnail + * @param boolean (optional) if true image scales + * @param boolean (optional) if true inflate small images + * @param string (optional) adapter class name + * @param array (optional) adapter options + */ + public function __construct($maxWidth = null, $maxHeight = null, $scale = true, $inflate = true, $quality = 75, $adapterClass = null, $adapterOptions = array()) + { + if (!$adapterClass) + { + if (extension_loaded('gd')) + { + $adapterClass = 'sfGDAdapter'; + } + else + { + $adapterClass = 'sfImageMagickAdapter'; + } + } + $this->adapter = new $adapterClass($maxWidth, $maxHeight, $scale, $inflate, $quality, $adapterOptions); + } + + /** + * Loads an image from a file and creates an internal thumbnail out of it + * + * @param string filename (with absolute path) of the image to load + * + * @return boolean True if the image was properly loaded + * @throws Exception If the image cannot be loaded, or if its mime type is not supported + */ + public function loadFile($image) + { + if (eregi('http(s)?://', $image)) + { + if (class_exists('sfWebBrowser')) + { + if (!is_null($this->tempFile)) { + unlink($this->tempFile); + } + $this->tempFile = tempnam('/tmp', 'sfThumbnailPlugin'); + + $b = new sfWebBrowser(); + try + { + $b->get($image); + if ($b->getResponseCode() != 200) { + throw new Exception(sprintf('%s returned error code %s', $image, $b->getResponseCode())); + } + file_put_contents($this->tempFile, $b->getResponseText()); + if (!filesize($this->tempFile)) { + throw new Exception('downloaded file is empty'); + } else { + $image = $this->tempFile; + } + } + catch (Exception $e) + { + throw new Exception("Source image is a URL but it cannot be used because ". $e->getMessage()); + } + } + else + { + throw new Exception("Source image is a URL but sfWebBrowserPlugin is not installed"); + } + } + + $this->adapter->loadFile($this, $image); + } + + /** + * Loads an image from a string (e.g. database) and creates an internal thumbnail out of it + * + * @param string the image string (must be a format accepted by imagecreatefromstring()) + * @param string mime type of the image + * + * @return boolean True if the image was properly loaded + * @access public + * @throws Exception If image mime type is not supported + */ + public function loadData($image, $mime) + { + $this->adapter->loadData($this, $image, $mime); + } + + /** + * Saves the thumbnail to the filesystem + * If no target mime type is specified, the thumbnail is created with the same mime type as the source file. + * + * @param string the image thumbnail file destination (with absolute path) + * @param string The mime-type of the thumbnail (possible values are 'image/jpeg', 'image/png', and 'image/gif') + * + * @access public + * @return void + */ + public function save($thumbDest, $targetMime = null) + { + $this->adapter->save($this, $thumbDest, $targetMime); + } + + /** + * Returns the thumbnail as a string + * If no target mime type is specified, the thumbnail is created with the same mime type as the source file. + * + * + * @param string The mime-type of the thumbnail (possible values are adapter dependent) + * + * @access public + * @return string + */ + public function toString($targetMime = null) + { + return $this->adapter->toString($this, $targetMime); + } + + public function freeSource() + { + if (!is_null($this->tempFile)) { + unlink($this->tempFile); + } + $this->adapter->freeSource(); + } + + public function freeThumb() + { + $this->adapter->freeThumb(); + } + + public function freeAll() + { + $this->adapter->freeSource(); + $this->adapter->freeThumb(); + } + + /** + * Returns the width of the thumbnail + */ + public function getThumbWidth() + { + return $this->thumbWidth; + } + + /** + * Returns the height of the thumbnail + */ + public function getThumbHeight() + { + return $this->thumbHeight; + } + + /** + * Returns the mime type of the source image + */ + public function getMime() + { + return $this->adapter->getSourceMime(); + } + + /** + * Computes the thumbnail width and height + * Used by adapter + */ + public function initThumb($sourceWidth, $sourceHeight, $maxWidth, $maxHeight, $scale, $inflate) + { + if ($maxWidth > 0) + { + $ratioWidth = $maxWidth / $sourceWidth; + } + if ($maxHeight > 0) + { + $ratioHeight = $maxHeight / $sourceHeight; + } + + if ($scale) + { + if ($maxWidth && $maxHeight) + { + $ratio = ($ratioWidth < $ratioHeight) ? $ratioWidth : $ratioHeight; + } + if ($maxWidth xor $maxHeight) + { + $ratio = (isset($ratioWidth)) ? $ratioWidth : $ratioHeight; + } + if ((!$maxWidth && !$maxHeight) || (!$inflate && $ratio > 1)) + { + $ratio = 1; + } + + $this->thumbWidth = floor($ratio * $sourceWidth); + $this->thumbHeight = ceil($ratio * $sourceHeight); + } + else + { + if (!isset($ratioWidth) || (!$inflate && $ratioWidth > 1)) + { + $ratioWidth = 1; + } + if (!isset($ratioHeight) || (!$inflate && $ratioHeight > 1)) + { + $ratioHeight = 1; + } + $this->thumbWidth = floor($ratioWidth * $sourceWidth); + $this->thumbHeight = ceil($ratioHeight * $sourceHeight); + } + } + + public function __destruct() + { + $this->freeAll(); + } +} diff --git a/plugins/sfWebBrowserPlugin/LICENSE b/plugins/sfWebBrowserPlugin/LICENSE new file mode 100644 index 0000000..4dd8b67 --- /dev/null +++ b/plugins/sfWebBrowserPlugin/LICENSE @@ -0,0 +1,7 @@ +Copyright (c) 2004-2006 Francois Zaninotto + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/plugins/sfWebBrowserPlugin/README b/plugins/sfWebBrowserPlugin/README new file mode 100644 index 0000000..7713cf4 --- /dev/null +++ b/plugins/sfWebBrowserPlugin/README @@ -0,0 +1,224 @@ += sfWebBrowser plugin = + +The `sfWebBrowserPlugin` proposes an HTTP client capable of making web requests. The interface is similar to that of `sfTestBrowser`. + +=== Possible uses === + + * Querying a Web service + * Monitoring a Website + * Mashup of content from several websites + * Aggregation of RSS feeds + * Proxy to another server + * Cross-domain AJAX interactions + * API to foreign websites + * ... + +== Contents == + +This plugin contains four classes: `sfWebBrowser`, `sfFopenAdapter`, `sfCurlAdapter`, and `sfSocketsAdapter`. Unit tests are available in the SVN repository, to be placed in a symfony application's `test/` directory. + +== Features == + +The `sfWebBrowser` class makes web requests based on a URI: +{{{ +$b = new sfWebBrowser(); +$b->get('http://www.example.com/'); +$res = $b->getResponseText(); +}}} + +The usual methods of the `sfTestBrowser` also work there, with the fluid interface. +{{{ +// Inline +$b->get('http://www.example.com/')->get('http://www.google.com/')->back()->reload(); +// More readable +$b->get('http://www.example.com/') + ->get('http://www.google.com/') + ->back() + ->reload(); +}}} + +The browser accepts absolute and relative URIs +{{{ +$b->get('http://www.example.com/test.html'); +$b->get('test.html'); +}}} + +The `get()` method accepts parameters either as a query string, or as an array. +{{{ +$b->get('http://www.example.com/test.php?foo=bar'); +$b->get('http://www.example.com/test.php', array('foo', 'bar')); +}}} + +POST, PUT and DELETE requests are also supported. +{{{ +$b->post('http://www.example.com/test.php', array('foo', 'bar')); +$b->put('http://www.example.com/test.php', array('foo', 'bar')); +$b->delete('http://www.example.com/test.php', array('foo', 'bar')); +}}} + +You can access the response in various formats, at your convenience: +{{{ +$myString = $b->getResponseText(); +$myString = $b->getResponseBody(); // drop the part +$myDomDocument = $b->getResponseDom(); +$myDomCssSelector = $b->getResponseDomCssSelector(); +$mySimpleXml = $b->getResponseXml(); +}}} + +You can also interact with the response with the `setFields()` and `click()` methods. + +{{{ +$b->get('http://www.example.com/login') + ->setField('user', 'foobar') + ->setField('password', 'barbaz') + ->click('submit'); +}}} + +The browser supports HTTP and HTTPS requests, proxies, redirects, and timeouts. + +Gzip and deflate content-encoded response bodies are also supported, provided that you have the [http://php.net/zlib zlib extention] enabled. + +== Adapters == + +The browser can use various adapters to perform the requests: + + * `sfFopenAdapter` (default): Uses [http://php.net/fopen `fopen()`] to fetch pages. `fopen()` can take an URL as a parameter provided that PHP is compiled with sockets support, and `allow_url_fopen` is defined to `true` in `php.ini`. This is the case in most PHP distributions, so the default adapter should work in almost every platform. On the other hand, the compatibility has a cost: this adapter is slow. + + * `sfCurlAdapter`: Uses [http://php.net/curl Curl] to fetch pages. This adapter is a lot faster than `sfFopenAdapter`, however PHP must be compiled with the `with-curl` option, and the `curl` extension must be enabled in `php.ini` (which is rarely the case by default) for it to work. + + * `sfSocketsAdapter`: Uses [http://php.net/fsockopen `fsockopen()`] to fetch pages. + +You can specify an adapter when you create a new browser object, as follows: + +{{{ +// use default adapter, i.e. sfFopenAdapter +$b = new sfWebBrowser(array()); +// use sfCurlAdapter +$b = new sfWebBrowser(array(), 'sfCurlAdapter'); +}}} + +== Usage == + +`sfWebBrowser` distiguishes to types of error: adapter errors and response errors. Thus, `sfWebBrowser` calls should be run this way : + +{{{ +$b = new sfWebBrowser(); +try +{ + if (!$b->get($url)->responseIsError()) + { + // Successful response (eg. 200, 201, etc) + } + else + { + // Error response (eg. 404, 500, etc) + } +} +catch (Exception $e) +{ + // Adapter error (eg. Host not found) +} +}}} + +Besides, you should always remember that the response contents may contain incorrect code. Consider it as 'tainted', and therefore always use the [http://www.symfony-project.com/book/trunk/07-Inside-the-View-Layer#Output%20Escaping escaping] when outputting it to a template. + +{{{ +// In the action +$this->title = (string) $b->getResponseXml()->body->h1 + +// In the template + +get('title') // correct ?> +}}} + +== Installation == + + * Install the plugin +{{{ +$ symfony plugin-install http://plugins.symfony-project.com/sfWebBrowserPlugin +}}} + + * Clear the cache to enable the autoloading to find the new class +{{{ +$ symfony cc +}}} + +== Known limitations == + +If `allow_url_fopen` is not defined to `true` and if the curl extension cannot be activated in the `php.ini` file, the browser can't fetch pages. Workaround (todo): use a sockets adapter. + +Cookies are not handled yet. + +Caching is not supported yet. + +== Changelog == + +=== trunk === + +=== 2007-03-27 | 1.0.1 stable === + + * bmeynell: Fixed a bug with `sfCurlAdapter` causing 'Bad Request' error responses + * francois: Fixed a bug with `get()` when `arg_separator.output` is not set to '&' in `php.ini` (patch from river.bright) + * francois: Fixed a bug with `get()` when query string is already present in the url (based on a patch from Jeff Merlet) + * francois: Fixed auto-adapter decision in `sfWebBrowser::__construct()` + +=== 2007-03-08 | 1.0.0 stable === + + * francois: Added auto-adapter decision in `sfWebBrowser::__construct()` + * francois: Changed tested URLs a bit to avoid redirection issues with google + * bmeynell: Added `sfSocketsAdapter` + * bmeynell: `sfCurlAdapter`: more detailed error messages & leaner request setup + +=== 2007-02-22 | 0.9.6 Beta === + + * bmeynell, tristan: Allowed for requests with any method in `sfCurlAdapter` + * tristan: Added `sfWebBrowser::responseIsError()` + * tristan: Added `sfWebBrowser::getResponseMessage()` + * tristan: Refactored error management in `sfFopenAdapter` + +=== 2007-02-21 | 0.9.5 Beta === + + * bmeynell: Fixed bug with relative uri's attempting to use a port other than 80 (sfWebBrowser, 132 - 146) + * bmeynell: Fixed small bug not printing hostname on exception (sfFopenAdapter, 61-62) + * bmeynell: Created sfCurlAdapter and passes all unit tests + * bmeynell: Removed '$changeStack = true' from call() prototype in sfCurlAdapter, sfFopenAdapter, and moved changestack check to sfWebBrowser + * bmeynell: Added $askeet_url to sfWebBrowserTest + * bmeynell: Added easy toggling between adapters in sfWebBrowserTest + * tristan: Added put() and delete() public methods + * tristan: Added unit tests to validate request HTTP method + +=== 2007-02-16 | 0.9.4 Beta === + + * francois: Refactored the browser to make it multi-adapter + * francois: '''BC break''' constructor signature changed : `new sfWebBrowser(array $headers, string $adapter_class, array $adapter_options)` + * francois: Fixed notice when trying to retrieve inexistent header + * francois: Fixed header case normalization + * francois: Transformed setResponseXXX() methods to public + * francois: Fixed caps in `initializeRequestHeaders()` + * francois: Fixed unit test #40 + +=== 2007-02-16 | 0.9.3 Beta === + + * tristan: Added support for gzip and deflate. + * tristan: Possibility to pass default request headers to sfWebBrowser's constructor + * tristan: "Accept-Encoding" header is automatically set depending on PHP capabilities + * tristan: Fixed problems with request and response headers case + * tristan: Renamed "browser options" to "adapter options" (http://www.symfony-project.com/forum/index.php/m/21635/) + * tristan: '''BC break''' constructor signature changed : `new sfWebBrowser(array $headers, array $adapter_options)` + * tristan: Unit tested POST requests + * tristan: Changed way httpd headers are stored internally + * tristan: Fixed small bug in `getResponseBody()` + * francois: Fixed unit test for malformed headers + +=== 2007-02-09 | 0.9.2 Beta === + + * francois: Fixed notice with `getResponseXML()` + +=== 2007-02-08 | 0.9.1 Beta === + + * francois: Fixed notice with some headers + * francois: Added license and copyright + +=== 2007-02-08 | 0.9.0 Beta === + + * francois: Initial release diff --git a/plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php b/plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php new file mode 100644 index 0000000..fc8cb5b --- /dev/null +++ b/plugins/sfWebBrowserPlugin/lib/sfCurlAdapter.class.php @@ -0,0 +1,102 @@ + + * (c) 2004-2006 Fabien Potencier for the click-related functions + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWebBrowser provides a basic HTTP client. + * + * @package sfWebBrowserPlugin + * @author Francois Zaninotto + * @author Ben Meynell + * @version 0.9 + */ + +class sfCurlAdapter +{ + + protected + $options = array(), + $headers = array(); + + public function __construct($options = array()) + { + if (!function_exists('curl_init')) + { + throw new Exception('Curl not enabled'); + } + + $this->options = $options; + } + + /** + * Submits a request + * + * @param string The request uri + * @param string The request method + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * + * @return sfWebBrowser The current browser object + */ + public function call($browser, $uri, $method = 'GET', $parameters = array(), $headers = array()) + { + $curl = curl_init(); + + // default settings + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_AUTOREFERER, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + + // uri + curl_setopt($curl, CURLOPT_URL, $uri); + + // request headers + $m_headers = array_merge($browser->getDefaultRequestHeaders(), $browser->initializeRequestHeaders($headers)); + $request_headers = explode("\r\n", $browser->prepareHeaders($m_headers)); + curl_setopt($curl, CURLOPT_HTTPHEADER, $request_headers); + + // encoding support + isset($headers['Accept-Encoding']) ? curl_setopt($curl, CURLOPT_ENCODING, $headers['Accept-Encoding']) : null; + + // store response headers, uses callback function + curl_setopt($curl, CURLOPT_HEADERFUNCTION, array($this, 'read_header')); + + // handle any request method + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($parameters)); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); + + $response = curl_exec($curl); + + if (curl_errno($curl)) + { + throw new Exception(curl_error($curl)); + } + + $requestInfo = curl_getinfo($curl); + + $browser->setResponseCode($requestInfo['http_code']); + $browser->setResponseHeaders($this->headers); + $browser->setResponseText($response); + + // clear response headers + $this->headers = array(); + + curl_close($curl); + + return $browser; + } + + private function read_header($curl, $headers) + { + $this->headers[] = $headers; + return strlen($headers); + } + +} diff --git a/plugins/sfWebBrowserPlugin/lib/sfFopenAdapter.class.php b/plugins/sfWebBrowserPlugin/lib/sfFopenAdapter.class.php new file mode 100644 index 0000000..e45a7ef --- /dev/null +++ b/plugins/sfWebBrowserPlugin/lib/sfFopenAdapter.class.php @@ -0,0 +1,130 @@ + + * (c) 2004-2006 Fabien Potencier for the click-related functions + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWebBrowser provides a basic HTTP client. + * + * @package sfWebBrowserPlugin + * @author Francois Zaninotto + * @version 0.9 + */ +class sfFopenAdapter +{ + protected + $options = array(), + $adapterErrorMessage = null, + $browser = null; + + public function __construct($options = array()) + { + $this->options = $options; + } + + /** + * Submits a request + * + * @param string The request uri + * @param string The request method + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * @param boolean To specify is the request changes the browser history + * + * @return sfWebBrowser The current browser object + */ + public function call($browser, $uri, $method = 'GET', $parameters = array(), $headers = array()) + { + $m_headers = array_merge($browser->getDefaultRequestHeaders(), $browser->initializeRequestHeaders($headers)); + $request_headers = $browser->prepareHeaders($m_headers); + + // Read the response from the server + // FIXME: use sockets to avoid depending on allow_url_fopen + $context = stream_context_create(array('http' => array_merge( + $this->options, + array('method' => $method), + array('content' => http_build_query($parameters)), + array('header' => $request_headers) + ))); + + // Custom error handler + // -- browser instance must be accessible from handleRuntimeError() + $this->browser = $browser; + set_error_handler(array($this, 'handleRuntimeError'), E_WARNING); + if($handle = fopen($uri, 'r', false, $context)) + { + $response_headers = stream_get_meta_data($handle); + $browser->setResponseCode(array_shift($response_headers['wrapper_data'])); + $browser->setResponseHeaders($response_headers['wrapper_data']); + $browser->setResponseText(stream_get_contents($handle)); + fclose($handle); + } + + restore_error_handler(); + + if ($this->adapterErrorMessage == true) + { + $msg = $this->adapterErrorMessage; + $this->adapterErrorMessage = null; + throw new Exception($msg); + } + + return $browser; + } + + /** + * Handles PHP runtime error. + * + * This handler is used to catch any warnigns sent by fopen($url) and reformat them to something + * usable. + * + * @see http://php.net/set_error_handler + */ + function handleRuntimeError($errno, $errstr, $errfile = null, $errline = null, $errcontext = array() ) + { + static $error_types = null; + + if ($error_types === null) + { + $error_types = array( + E_NOTICE => "Notice", + E_WARNING => "Warning", + E_STRICT => "Strict notice", + ); + + // Forward compatibility with PHP5.3 + if (defined("E_DEPRECATED")) + { + $error_types[E_DEPRECATED] = "Deprecated"; + $error_types[E_RECOVERABLE_ERROR] = "Error"; + } + // Forward compatibility with PHP5.2 + elseif (defined("E_RECOVERABLE_ERROR")) + { + $error_types[E_RECOVERABLE_ERROR] = "Error"; + } + } + + $msg = sprintf('%s : "%s" occured in %s on line %d', + $error_types[$errno], $errstr, $errfile, $errline); + + $matches = array(); + if (preg_match('/HTTP\/\d\.\d (\d{3}) (.*)$/', $errstr, $matches)) + { + $this->browser->setResponseCode($matches[1]); + $this->browser->setResponseMessage($matches[2]); + $body = sprintf('The %s adapter cannot handle error responses body. Try using another adapter.', __CLASS__); + $this->browser->setResponseText($body); + } + else + { + $this->adapterErrorMessage = $msg; + } + } +} diff --git a/plugins/sfWebBrowserPlugin/lib/sfSocketsAdapter.class.php b/plugins/sfWebBrowserPlugin/lib/sfSocketsAdapter.class.php new file mode 100644 index 0000000..02de52b --- /dev/null +++ b/plugins/sfWebBrowserPlugin/lib/sfSocketsAdapter.class.php @@ -0,0 +1,133 @@ + + * (c) 2004-2006 Fabien Potencier for the click-related functions + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWebBrowser provides a basic HTTP client. + * + * @package sfWebBrowserPlugin + * @author Francois Zaninotto + * @author Benjamin Meynell + * @version 0.9 + */ +class sfSocketsAdapter +{ + protected + $options = array(), + $adapterErrorMessage = null, + $browser = null; + + public function __construct($options = array()) + { + $this->options = $options; + } + + /** + * Submits a request + * + * @param string The request uri + * @param string The request method + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * + * @return sfWebBrowser The current browser object + */ + public function call($browser, $uri, $method = 'GET', $parameters = array(), $headers = array()) + { + $m_headers = array_merge($browser->getDefaultRequestHeaders(), $browser->initializeRequestHeaders($headers)); + $request_headers = $browser->prepareHeaders($m_headers); + + $url_info = $browser->getUrlInfo(); + + // initialize default values + isset($url_info['path']) ? $path = $url_info['path'] : $path = '/'; + isset($url_info['query']) ? $qstring = '?'.$url_info['query'] : $qstring = null; + isset($url_info['port']) ? null : $url_info['port'] = 80; + $body = http_build_query($parameters); + + if (!$socket = @fsockopen($url_info['host'], $url_info['port'], $errno, $errstr, 15)) + { + throw new Exception("Could not connect ($errno): $errstr"); + } + + // build request + $request = "$method $path$qstring HTTP/1.1\r\n"; + $request .= 'Host: '.$url_info['host']."\r\n"; + $request .= $request_headers; + $request .= 'Content-Length: '.strlen($body)."\r\n"; + $request .= "Connection: Close\r\n"; + + if ($method == 'POST') + { + $request .= "Content-type: application/x-www-form-urlencoded\r\n"; + } + + if ($body) + { + $request .= "\r\n"; + $request .= $body; + } + $request .= "\r\n"; + + fwrite($socket, $request); + + while (!feof($socket)) + { + $response .= fgets($socket, 1024); + } + fclose($socket); + + // parse response components: status line, headers and body + $response_lines = explode("\n", $response); + + // http status line (ie "HTTP 1.1 200 OK") + $status_line = array_shift($response_lines); + + $start_body = false; + for($i=0; $isetResponseHeaders($response_headers); + $browser->setResponseCode($status_code[1]); + $browser->setResponseText($response_body); + + // handle redirects + if($browser->getResponseCode() == 302 || $browser->getResponseCode() == 303) + { + preg_match('@(https?://[^/]+)(.*)@', $browser->getResponseHeader('Location'), $uri); + $browser->call($uri[1].':'.$url_info['port'].$uri[2], 'GET', array(), $headers); + } + + return $browser; + + } + +} diff --git a/plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php b/plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php new file mode 100644 index 0000000..86c9b77 --- /dev/null +++ b/plugins/sfWebBrowserPlugin/lib/sfWebBrowser.class.php @@ -0,0 +1,819 @@ + + * (c) 2004-2006 Fabien Potencier for the click-related functions + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWebBrowser provides a basic HTTP client. + * + * @package sfWebBrowserPlugin + * @author Francois Zaninotto + * @author Tristan Rivoallan + * @version 0.9 + */ +class sfWebBrowser +{ + protected + $defaultHeaders = array(), + $stack = array(), + $stackPosition = -1, + $responseHeaders = array(), + $responseCode = '', + $responseMessage = '', + $responseText = '', + $responseDom = null, + $responseDomCssSelector = null, + $responseXml = null, + $fields = array(), + $urlInfo = array(); + + public function __construct($defaultHeaders = array(), $adapterClass = null, $adapterOptions = array()) + { + if(!$adapterClass) + { + if (function_exists('curl_init')) + { + $adapterClass = 'sfCurlAdapter'; + } + else if(ini_get('allow_url_fopen') == 1) + { + $adapterClass = 'sfFopenAdapter'; + } + else + { + $adapterClass = 'sfSocketsAdapter'; + } + } + $this->defaultHeaders = $this->fixHeaders($defaultHeaders); + $this->adapter = new $adapterClass($adapterOptions); + } + + // Browser methods + + /** + * Restarts the browser + * + * @param array default browser options + * + * @return sfWebBrowser The current browser object + */ + public function restart($defaultHeaders = array()) + { + $this->defaultHeaders = $this->fixHeaders($defaultHeaders); + $this->stack = array(); + $this->stackPosition = -1; + $this->urlInfo = array(); + $this->initializeResponse(); + + return $this; + } + + /** + * Sets the browser user agent name + * + * @param string agent name + * + * @return sfWebBrowser The current browser object + */ + public function setUserAgent($agent) + { + $this->defaultHeaders['User-Agent'] = $agent; + + return $this; + } + + /** + * Gets the browser user agent name + * + * @return string agent name + */ + public function getUserAgent() + { + return isset($this->defaultHeaders['User-Agent']) ? $this->defaultHeaders['User-Agent'] : ''; + } + + /** + * Submits a GET request + * + * @param string The request uri + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * + * @return sfWebBrowser The current browser object + */ + public function get($uri, $parameters = array(), $headers = array()) + { + if ($parameters) + { + $uri .= ((false !== strpos($uri, '?')) ? '&' : '?') . http_build_query($parameters, '', '&'); + } + return $this->call($uri, 'GET', array(), $headers); + } + + /** + * Submits a POST request + * + * @param string The request uri + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * + * @return sfWebBrowser The current browser object + */ + public function post($uri, $parameters = array(), $headers = array()) + { + return $this->call($uri, 'POST', $parameters, $headers); + } + + /** + * Submits a PUT request. + * + * @param string The request uri + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * + * @return sfWebBrowser The current browser object + */ + public function put($uri, $parameters = array(), $headers = array()) + { + return $this->call($uri, 'PUT', $parameters, $headers); + } + + /** + * Submits a DELETE request. + * + * @param string The request uri + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * + * @return sfWebBrowser The current browser object + */ + public function delete($uri, $parameters = array(), $headers = array()) + { + return $this->call($uri, 'DELETE', $parameters, $headers); + } + + /** + * Submits a request + * + * @param string The request uri + * @param string The request method + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * @param boolean To specify is the request changes the browser history + * + * @return sfWebBrowser The current browser object + */ + public function call($uri, $method = 'GET', $parameters = array(), $headers = array(), $changeStack = true) + { + $urlInfo = parse_url($uri); + + // Check headers + $headers = $this->fixHeaders($headers); + + // check port + if (isset($urlInfo['port'])) + { + $this->urlInfo['port'] = $urlInfo['port']; + } + else if (!isset($this->urlInfo['port'])) + { + $this->urlInfo['port'] = 80; + } + + if(!isset($urlInfo['host']) && isset($this->urlInfo['scheme']) && isset($this->urlInfo['host'])) + { + // relative link + $uri = $this->urlInfo['scheme'].'://'.$this->urlInfo['host'].':'.$this->urlInfo['port'].'/'.$uri; + } + else if(isset($urlInfo['scheme']) && $urlInfo['scheme'] != 'http' && $urlInfo['scheme'] != 'https') + { + throw new Exception('sfWebBrowser handles only http and https requests'); + } + + $this->urlInfo = parse_url($uri); + + $this->initializeResponse(); + + if ($changeStack) + { + $this->addToStack($uri, $method, $parameters, $headers); + } + + return $this->adapter->call($this, $uri, $method, $parameters, $headers); + } + + /** + * Gives a value to a form field in the response + * + * @param string field name + * @param string field value + * + * @return sfWebBrowser The current browser object + */ + public function setField($name, $value) + { + // as we don't know yet the form, just store name/value pairs + $this->parseArgumentAsArray($name, $value, $this->fields); + + return $this; + } + + /** + * Looks for a link or a button in the response and submits the related request + * + * @param string The link/button value/href/alt + * @param array request parameters (associative array) + * + * @return sfWebBrowser The current browser object + */ + public function click($name, $arguments = array()) + { + if (!$dom = $this->getResponseDom()) + { + throw new Exception('Cannot click because there is no current page in the browser'); + } + + $xpath = new DomXpath($dom); + + // text link, the name being in an attribute + if ($link = $xpath->query(sprintf('//a[@*="%s"]', $name))->item(0)) + { + return $this->get($link->getAttribute('href')); + } + + // text link, the name being the text value + if ($links = $xpath->query('//a[@href]')) + { + foreach($links as $link) + { + if(preg_replace(array('/\s{2,}/', '/\\r\\n|\\n|\\r/'), array(' ', ''), $link->nodeValue) == $name) + { + return $this->get($link->getAttribute('href')); + } + } + } + + // image link, the name being the alt attribute value + if ($link = $xpath->query(sprintf('//a/img[@alt="%s"]/ancestor::a', $name))->item(0)) + { + return $this->get($link->getAttribute('href')); + } + + // form, the name being the button or input value + if (!$form = $xpath->query(sprintf('//input[((@type="submit" or @type="button") and @value="%s") or (@type="image" and @alt="%s")]/ancestor::form', $name, $name))->item(0)) + { + throw new Exception(sprintf('Cannot find the "%s" link or button.', $name)); + } + + // form attributes + $url = $form->getAttribute('action'); + $method = $form->getAttribute('method') ? strtolower($form->getAttribute('method')) : 'get'; + + // merge form default values and arguments + $defaults = array(); + foreach ($xpath->query('descendant::input | descendant::textarea | descendant::select', $form) as $element) + { + $elementName = $element->getAttribute('name'); + $nodeName = $element->nodeName; + $value = null; + if ($nodeName == 'input' && ($element->getAttribute('type') == 'checkbox' || $element->getAttribute('type') == 'radio')) + { + if ($element->getAttribute('checked')) + { + $value = $element->getAttribute('value'); + } + } + else if ( + $nodeName == 'input' + && + (($element->getAttribute('type') != 'submit' && $element->getAttribute('type') != 'button') || $element->getAttribute('value') == $name) + && + ($element->getAttribute('type') != 'image' || $element->getAttribute('alt') == $name) + ) + { + $value = $element->getAttribute('value'); + } + else if ($nodeName == 'textarea') + { + $value = ''; + foreach ($element->childNodes as $el) + { + $value .= $dom->saveXML($el); + } + } + else if ($nodeName == 'select') + { + if ($multiple = $element->hasAttribute('multiple')) + { + $elementName = str_replace('[]', '', $elementName); + $value = array(); + } + else + { + $value = null; + } + + $found = false; + foreach ($xpath->query('descendant::option', $element) as $option) + { + if ($option->getAttribute('selected')) + { + $found = true; + if ($multiple) + { + $value[] = $option->getAttribute('value'); + } + else + { + $value = $option->getAttribute('value'); + } + } + } + + // if no option is selected and if it is a simple select box, take the first option as the value + if (!$found && !$multiple) + { + $value = $xpath->query('descendant::option', $element)->item(0)->getAttribute('value'); + } + } + + if (null !== $value) + { + $this->parseArgumentAsArray($elementName, $value, $defaults); + } + } + + // create request parameters + $arguments = sfToolkit::arrayDeepMerge($defaults, $this->fields, $arguments); + if ('post' == $method) + { + return $this->post($url, $arguments); + } + else + { + return $this->get($url, $arguments); + } + } + + protected function parseArgumentAsArray($name, $value, &$vars) + { + if (false !== $pos = strpos($name, '[')) + { + $var = &$vars; + $tmps = array_filter(preg_split('/(\[ | \[\] | \])/x', $name)); + foreach ($tmps as $tmp) + { + $var = &$var[$tmp]; + } + if ($var) + { + if (!is_array($var)) + { + $var = array($var); + } + $var[] = $value; + } + else + { + $var = $value; + } + } + else + { + $vars[$name] = $value; + } + } + + /** + * Adds the current request to the history stack + * + * @param string The request uri + * @param string The request method + * @param array The request parameters (associative array) + * @param array The request headers (associative array) + * + * @return sfWebBrowser The current browser object + */ + public function addToStack($uri, $method, $parameters, $headers) + { + $this->stack = array_slice($this->stack, 0, $this->stackPosition + 1); + $this->stack[] = array( + 'uri' => $uri, + 'method' => $method, + 'parameters' => $parameters, + 'headers' => $headers + ); + $this->stackPosition = count($this->stack) - 1; + + return $this; + } + + /** + * Submits the previous request in history again + * + * @return sfWebBrowser The current browser object + */ + public function back() + { + if ($this->stackPosition < 1) + { + throw new Exception('You are already on the first page.'); + } + + --$this->stackPosition; + return $this->call($this->stack[$this->stackPosition]['uri'], + $this->stack[$this->stackPosition]['method'], + $this->stack[$this->stackPosition]['parameters'], + $this->stack[$this->stackPosition]['headers'], + false); + } + + /** + * Submits the next request in history again + * + * @return sfWebBrowser The current browser object + */ + public function forward() + { + if ($this->stackPosition > count($this->stack) - 2) + { + throw new Exception('You are already on the last page.'); + } + + ++$this->stackPosition; + return $this->call($this->stack[$this->stackPosition]['uri'], + $this->stack[$this->stackPosition]['method'], + $this->stack[$this->stackPosition]['parameters'], + $this->stack[$this->stackPosition]['headers'], + false); + } + + /** + * Submits the current request again + * + * @return sfWebBrowser The current browser object + */ + public function reload() + { + if (-1 == $this->stackPosition) + { + throw new Exception('No page to reload.'); + } + + return $this->call($this->stack[$this->stackPosition]['uri'], + $this->stack[$this->stackPosition]['method'], + $this->stack[$this->stackPosition]['parameters'], + $this->stack[$this->stackPosition]['headers'], + false); + } + + /** + * Transforms an associative array of header names => header values to its HTTP equivalent. + * + * @param array $headers + * @return string + */ + public function prepareHeaders($headers = array()) + { + $prepared_headers = array(); + foreach ($headers as $name => $value) + { + $prepared_headers[] = sprintf("%s: %s\r\n", ucfirst($name), $value); + } + + return implode('', $prepared_headers); + } + + // Response methods + + /** + * Initializes the response and erases all content from prior requests + */ + public function initializeResponse() + { + $this->responseHeaders = array(); + $this->responseCode = ''; + $this->responseText = ''; + $this->responseDom = null; + $this->responseDomCssSelector = null; + $this->responseXml = null; + $this->fields = array(); + } + + /** + * Set the response headers + * + * @param array The response headers as an array of strings shaped like "key: value" + * + * @return sfWebBrowser The current browser object + */ + public function setResponseHeaders($headers = array()) + { + $header_array = array(); + foreach($headers as $header) + { + $arr = explode(': ', $header); + if(isset($arr[1])) + { + $header_array[$this->normalizeHeaderName($arr[0])] = trim($arr[1]); + } + } + + $this->responseHeaders = $header_array; + + return $this; + } + + /** + * Set the response code + * + * @param string The first line of the response + * + * @return sfWebBrowser The current browser object + */ + public function setResponseCode($firstLine) + { + preg_match('/\d{3}/', $firstLine, $matches); + $this->responseCode = $matches[0]; + + return $this; + } + + /** + * Set the response contents + * + * @param string The response contents + * + * @return sfWebBrowser The current browser object + */ + public function setResponseText($res) + { + $this->responseText = $res; + + return $this; + } + + /** + * Get a text version of the response + * + * @return string The response contents + */ + public function getResponseText() + { + $text = $this->responseText; + + // Decode any content-encoding (gzip or deflate) if needed + switch (strtolower($this->getResponseHeader('content-encoding'))) { + + // Handle gzip encoding + case 'gzip': + $text = $this->decodeGzip($text); + break; + + // Handle deflate encoding + case 'deflate': + $text = $this->decodeDeflate($text); + break; + + default: + break; + } + + return $text; + } + + /** + * Get a text version of the body part of the response (without and ) + * + * @return string The body part of the response contents + */ + public function getResponseBody() + { + preg_match('/(.*)<\/body>/si', $this->getResponseText(), $matches); + + return $matches[1]; + } + + /** + * Get a DOMDocument version of the response + * + * @return DOMDocument The reponse contents + */ + public function getResponseDom() + { + if(!$this->responseDom) + { + // for HTML/XML content, create a DOM object for the response content + if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type'))) + { + $this->responseDom = new DomDocument('1.0', 'utf8'); + $this->responseDom->validateOnParse = true; + @$this->responseDom->loadHTML($this->getResponseText()); + } + } + + return $this->responseDom; + } + + /** + * Get a sfDomCssSelector version of the response + * + * @return sfDomCssSelector The response contents + */ + public function getResponseDomCssSelector() + { + if(!$this->responseDomCssSelector) + { + // for HTML/XML content, create a DOM object for the response content + if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type'))) + { + $this->responseDomCssSelector = new sfDomCssSelector($this->getResponseDom()); + } + } + + return $this->responseDomCssSelector; + } + + /** + * Get a SimpleXML version of the response + * + * @return SimpleXMLElement The reponse contents + */ + public function getResponseXML() + { + if(!$this->responseXml) + { + // for HTML/XML content, create a DOM object for the response content + if (preg_match('/(x|ht)ml/i', $this->getResponseHeader('Content-Type'))) + { + $this->responseXml = @simplexml_load_string($this->getResponseText()); + } + } + + return $this->responseXml; + } + + /** + * Returns true if server response is an error. + * + * @return bool + */ + public function responseIsError() + { + return in_array((int)($this->getResponseCode() / 100), array(4, 5)); + } + + /** + * Get the response headers + * + * @return array The response headers + */ + public function getResponseHeaders() + { + return $this->responseHeaders; + } + + /** + * Get a response header + * + * @param string The response header name + * + * @return string The response header value + */ + public function getResponseHeader($key) + { + $normalized_key = $this->normalizeHeaderName($key); + return (isset($this->responseHeaders[$normalized_key])) ? $this->responseHeaders[$normalized_key] : ''; + } + + /** + * Decodes gzip-encoded content ("content-encoding: gzip" response header). + * + * @param stream $gzip_text + * @return string + */ + protected function decodeGzip($gzip_text) + { + return gzinflate(substr($gzip_text, 10)); + } + + /** + * Decodes deflate-encoded content ("content-encoding: deflate" response header). + * + * @param stream $deflate_text + * @return string + */ + protected function decodeDeflate($deflate_text) + { + return gzuncompress($deflate_text); + } + + /** + * Get the response code + * + * @return string The response code + */ + public function getResponseCode() + { + return $this->responseCode; + } + + /** + * Returns the response message (the 'Not Found' part in 'HTTP/1.1 404 Not Found') + * + * @return string + */ + public function getResponseMessage() + { + return $this->responseMessage; + } + + /** + * Sets response message. + * + * @param string $message + */ + public function setResponseMessage($msg) + { + $this->responseMessage = $msg; + } + + public function getUrlInfo() + { + return $this->urlInfo; + } + + public function getDefaultRequestHeaders() + { + return $this->defaultHeaders; + } + + /** + * Adds default headers to the supplied headers array. + * + * @param array $headers + * @return array + */ + public function initializeRequestHeaders($headers = array()) + { + // Supported encodings + $encodings = array(); + if (isset($headers['Accept-Encoding'])) + { + $encodings = explode(',', $headers['Accept-Encoding']); + } + if (function_exists('gzinflate')) + { + $encodings[] = 'gzip'; + } + if (function_exists('gzuncompress')) + { + $encodings[] = 'deflate'; + } + + $headers['Accept-Encoding'] = implode(',', array_unique($encodings)); + + return $headers; + } + + /** + * Validates supplied headers and turns all names to lowercase. + * + * @param array $headers + * @return array + */ + private function fixHeaders($headers) + { + $fixed_headers = array(); + foreach ($headers as $name => $value) + { + if (!preg_match('/[a-z][A-Z]*/', $name)) + { + $msg = sprintf('Invalid header "%s"', $name); + throw new Exception($msg); + } + $fixed_headers[$this->normalizeHeaderName($name)] = trim($value); + } + + return $fixed_headers; + } + + /** + * Retrieves a normalized Header. + * + * @param string Header name + * + * @return string Normalized header + */ + protected function normalizeHeaderName($name) + { + return preg_replace('/\-(.)/e', "'-'.strtoupper('\\1')", strtr(ucfirst(strtolower($name)), '_', '-')); + } + +} diff --git a/prototype/README b/prototype/README new file mode 100644 index 0000000..147653c --- /dev/null +++ b/prototype/README @@ -0,0 +1,92 @@ +THE PROGRAM +----------- + +./run-import +./run-import-debug +./run-import-test-regression + + +The current state of the implementation is that it is heavily +connected to the Reaktor project. However it should be easy to adopt +and generalize the code to handle other database migration scenarios. + + + +THE DATABASES +------------- + +- The prototype's database is a PostgreSQL database. + + sudo createuser + createdb reaktor + psql < reaktor-fulldump-2008-03-03.sql + + The datamodel is documented in reaktor-datamodell.pdf + +- The reaktor database is defined in reaktor.sql + + mysqladmin -uroot create reaktor_imp + mysql -uroot -e 'grant all on reaktor_imp.* to @localhost' + mysql reaktor_imp < reaktor.sql + + Remember to update reaktor.sql when ever the schema changes. + + + +THE SCHEMA MAPPING +------------------ + +The data is imported row by row from one database A to another +database B. + +Each table in A has a defined mapping handled by the PrototypeTableMap +class. + +For each row and column in A we examine a mapping that defines how +these data relates to the schema in B. Based on this mapping INSERT +statements are generated and executed. + +A column in A might map in several different ways: + + - Directly to a column in B. This is handled by the ReaktorColumn + class. + + - It is a basis for a new row in B. This is handled by the ReaktorRow + class (Basically an array of ReaktorColumns). + + - It might not have any value for B. Handled by the IGNORE class + + - It is a basis for several rows in B. This is not handled yet. + + + +FILTERS +------- + +A column value A might encoded in a different way in B. This is +handled by filters. + + +TOOLS +----- + +run-import-test-regression + + Checks the output of run-import against a previous run that is + assumed to be correct looking for regressions. + + It sets up a fresh database before it runs the import. + +run-import-debug + + Runs the import with all logging enabled. + + It sets up a fresh database before it runs the import. + + +import_to_dev + + Copies the imported data to the development database so that the + results can be examined in the web interface. + + diff --git a/prototype/bin/clean-logs b/prototype/bin/clean-logs new file mode 100755 index 0000000..dae953e --- /dev/null +++ b/prototype/bin/clean-logs @@ -0,0 +1,5 @@ +#!/bin/bash +# Remove old logs +rm -f log/*.log +echo "Old logs removed." + diff --git a/prototype/bin/import-fixtures b/prototype/bin/import-fixtures new file mode 100755 index 0000000..6ae2596 --- /dev/null +++ b/prototype/bin/import-fixtures @@ -0,0 +1,20 @@ +#!/bin/bash +# This script imports fixture data to symfony +# +# Author Robert Strind +# +FIXTURES=data/fixtures/*fixtures.yml + +if [ -z "$2" ] +then + echo "Usage: $0 PATH DATABASENAME" + echo "PATH describes path to a symfony installation" + echo "DATABASENAME is the name of the database to import fixture data" +else + cd $1 + symfony cc + symfony propel-insert-sql $2 + symfony propel-load-data $2 prod $FIXTURES + cd - +fi + diff --git a/prototype/bin/run-import b/prototype/bin/run-import new file mode 100755 index 0000000..09ebf57 --- /dev/null +++ b/prototype/bin/run-import @@ -0,0 +1,310 @@ +#!/usr/bin/env ruby +# +# = Synopsis +# This script will start the import +# Options for the import is set from command prompt or in configuration file +# +# = Authors +# * Robert Strind +# +# = Version +# $Id: $ + +t = Time.new + +# +# Some constants +# +IMPORT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..')) +LOG_PATH = File.join(IMPORT_ROOT, 'log') +LIB_PATH = File.join(IMPORT_ROOT, 'lib') +BIN_PATH = File.join(IMPORT_ROOT, 'bin') +CONTENT_PATH = File.expand_path(File.join(IMPORT_ROOT, '..', 'content')) +CONFIG_FILE_PATH = File.join(File.dirname(__FILE__), '..', 'config', 'import.conf') + +# Expand ruby search path +$: << LIB_PATH + +require 'optparse' +require 'parseconfig' + + +require 'import' +require 'parseconfig_extras' +require 'symfony' + +# +# Set log path +# +Log.set_path(LOG_PATH) + +# +# Commandline options +# +cnf = {} +op = OptionParser.new do |opts| + opts.banner = "Usage: #{$0} [-c --config PATH] [options]" + + # + # Path to configuration file + # + opts.on("-c", "--config-path [PATH]", "Define path to configuration file.", + "Commandline options will ovride the configuration file.", + "If no argument is spesified, data will be loaded from", + "configuration file on path: #{CONFIG_FILE_PATH}" + ) do |path| + if path.nil? + path = CONFIG_FILE_PATH if path.nil? + op.warn("Using default configuration file path: #{CONFIG_FILE_PATH}") + end + # Read configuration file + unless File.exists?(path) + op.abort("Configuration file does not exist: #{path}") + else + # Import configuration data + c = ParseConfig.new(path) + cnf.merge!(c.get_all) + end + end + + opts.on("-s", "--path-symfony PATH", "Define PATH to symfony root directory") do |o| + cnf[:path_symfony] = o + end + + opts.on("-f", "--fixtures", "Import fixtures") do |o| + cnf[:fixtures] = true + end + + opts.on("-d", "--debug", "Print debug data") do |o| + cnf[:debug] = true + end + + opts.on("-h", "--help", "Prints this help text") do + STDERR.puts opts + exit 0 + end + + opts.on("-i", "--import-path PATH", "PATH to imported content files.", + "Files in this directory will be copied recursively to the symfony content directory" + ) do |o| + cnf[:path_imported_content] = o + end + + opts.on("-a", "--data-path PATH", "PATH data directory. Textfiles will be created here.", + "This options is required from command prompt or config file." + ) do |o| + cnf[:path_data] = o + end + + opts.separator("") + opts.separator("From database options:") + + opts.on("--from-db-name DATABASENAME", "Define DATABASENAME to import from") do |o| + cnf[:from_db_name] = o + end + + opts.on("--from-db-user USERNAME", "Define USERNAME for the database to import from") do |o| + cnf[:from_db_user] = o + end + + opts.on("--from-db-password PASSWORD", "Define PASSWORD for the database to import from") do |o| + cnf[:from_db_password] = o + end + + opts.separator("") + opts.separator("To database options:") + + opts.on("--to-db-name DATABASENAME", "Define DATABASENAME to import to") do |o| + cnf[:to_db_name] = o + end + + opts.on("--to-db-user USERNAME", "Define USERNAME for the database to import to") do |o| + cnf[:to_db_user] = o + end + + opts.on("--to-db-password PASSWORD", "Define PASSWORD for the database to import to") do |o| + cnf[:to_db_password] = o + end +end + +# +# Parse command line +# +begin + op.parse(*ARGV) +rescue OptionParser::MissingArgument + op.parse(['-h']) + op.abort($1) +rescue OptionParser::InvalidOption + op.parse(['-h']) + op.abort($1) +end + +# +# If no arguments, load default configuration file +# +if ARGV.length == 0 + op.parse(["-h"]) +end + +# +# Check for required options +# +error = [] +[ + :from_db_name, + :from_db_user, + :from_db_password, + :to_db_name, + :to_db_user, + :to_db_password, + :path_data, + :path_symfony, +].each do |r| + unless cnf[r] + error << "Missing required option: #{r.to_s}" + end +end + +unless error.empty? + STDERR.puts "\nThe following errors was detected:" + error.each {|e| STDERR.puts e} + STDERR.puts "" + op.parse(['-h']) + op.abort('Import stopped!') +end + +# +# Modify symfony configuration files and set permissions +# +s = Symfony.new(cnf) +begin + s.cc +rescue + STDERR.puts "run-import: Could not clear cache (symfony cc). See errorlog." + Log.write_log(:error, "#{$!}") + exit 1 +end +begin + s.configure +rescue + STDERR.puts "run-import: Could not configure symfony. See errorlog." + Log.write_log(:error, "#{$!}") + exit 1 +end +begin + s.set_permissions +rescue + STDERR.puts "run-import: Could not set permissions in symfony. See errorlog." + Log.write_log(:error, "#{$!}") + exit 1 +end + +# +# Import fixture data +# +if cnf[:fixtures] + STDERR.print "%-25s" % 'Importing fixtures' + cmd = "#{File.join(BIN_PATH, 'import-fixtures')} #{cnf[:path_symfony]} #{cnf[:to_db_name]} 2>&1" + dbg = `#{cmd}` + Log.write_log(:import_fixtures, dbg) + if dbg.include? 'Exception' + puts "Could not import fixtures." + puts "Commandline: #{cmd}" + exit 1 + end + if dbg.include? 'error' + puts "Could not import fixtures." + puts "Commandline: #{cmd}" + exit 1 + end + STDERR.puts ' [v]' +end + +# +# Import imported content +# +if cnf[:path_imported_content] + unless File.directory?(cnf[:path_imported_content]) + op.abort("Content path is not a directory: #{cnf[:path_imported_content]}") + end + unless File.exists?(cnf[:path_imported_content]) + op.abort("Could not copy content files from directory: #{cnf[:path_imported_content]}") + end + # + # Backup content directory + # + if File.exists?(CONTENT_PATH) + STDERR.print "%-25s" % "Backup content directory" + `mv -v #{CONTENT_PATH} #{CONTENT_PATH}.bak` + Dir.mkdir(CONTENT_PATH) + STDERR.puts ' [v]' + else + STDERR.puts "# WARNING: Content directory, #{CONTENT_PATH}, did not exist." + end + # + # Copy content + # + unless File.exists?(cnf[:path_imported_content]) + STDERR.puts "Path to imported content does not exist!" + exit + end + unless File.directory?(cnf[:path_imported_content]) + STDERR.puts "Path to imported content is not a directory!" + exit + end + STDERR.print "%-25s" % "Copying imported content" + `cp -vr #{cnf[:path_imported_content]}/* #{CONTENT_PATH}/ > #{LOG_PATH}/import_content.log` + STDERR.print ' [v]' + STDERR.puts ' ' + `wc -l #{LOG_PATH}/import_content.log`[/^\d+/] + " files copied." +end + +# +# Write configuration data +# +if cnf[:debug] + STDERR.puts "\nRunning import with the following configuration:" + cnf.each do |k,v| + STDERR.puts "%-25s = %s" % [k,v] + end + STDERR.puts "" +end + +# +# Run the import +# +import(cnf) + +# +# Postqueries +# +puts "Running post queries:" +serieteket = 262 +serieteket1 = 13439 +query = %Q{ + UPDATE reaktor_artwork + SET user_id = #{serieteket} + WHERE user_id = #{serieteket1} +} +begin + $dbh_ms.execute(query) +rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not execute query:#{query}. Message: #{$!}.") + raise +end + +query = %Q{ +UPDATE reaktor_artwork AS ra, reaktor_artwork_file AS raf +SET ra.first_file_id = raf.file_id +WHERE ra.id = raf.artwork_id AND raf.file_order = 1; +} +begin + $dbh_ms.execute(query) +rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not execute query:#{query}. Message: #{$!}.") + raise +end + +STDERR.puts "Time used: #{Time.new - t} seconds" diff --git a/prototype/bin/run-import-debug b/prototype/bin/run-import-debug new file mode 100644 index 0000000..7922704 --- /dev/null +++ b/prototype/bin/run-import-debug @@ -0,0 +1,21 @@ +#! /bin/bash + +DIR=`pwd` + +if [ -z "$1" ] +then + echo "Usage: $0 path/to/symfony" +else + rm -f $DIR/../log/*.log + echo "Old logs removed" + + cd $1 + symfony propel-insert-sql reaktor + symfony propel-load-data reaktor prod data/fixtures/00* + cd - + + echo "Running import script" + echo + ruby -d $DIR/../bin/run-import -l 2>&1 | tee $DIR/../log/run-import-debug.log +fi + diff --git a/prototype/bin/run-import-test-regression b/prototype/bin/run-import-test-regression new file mode 100755 index 0000000..e68e07a --- /dev/null +++ b/prototype/bin/run-import-test-regression @@ -0,0 +1,15 @@ +#! /bin/bash + +DIR=`pwd` + +mysqladmin drop -f reaktor_imp +mysqladmin create reaktor_imp +mysql reaktor_imp < $DIR/reaktor.sql + +rm -rf $DIR/data/* + +$DIR/run-import | tee $DIR/run-import.log + +ls $DIR/data >> $DIR/run-import.log + +diff -u $DIR/run-import-test-base.log $DIR/run-import.log && echo "No regressions found" diff --git a/prototype/bin/run-tests.rb b/prototype/bin/run-tests.rb new file mode 100755 index 0000000..da430a1 --- /dev/null +++ b/prototype/bin/run-tests.rb @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby +# +# = Synopsis +# +# This is the test suite that does all the tests +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# + +require 'test/unit' + +puts "Removing old logs..." +`rm -f log/*.log` + +# Add your testcases here +require 'test/t_c_filter' +#require 'test/t_c_id_store' +#require 'test/t_c_reaktoruser_artworkgroups_plugin' +#require 'test/t_c_artwork_data_plugin' +#require 'test/t_c_reaktoruser_image_plugin' +#require 'test/t_c_reaktoruser_type_plugin' +#require 'test/t_c_reaktoruser_site_plugin' +#require 'test/t_c_artwork_internal_discussion_plugin' diff --git a/prototype/config/import.conf.sample b/prototype/config/import.conf.sample new file mode 100644 index 0000000..39acdc8 --- /dev/null +++ b/prototype/config/import.conf.sample @@ -0,0 +1,13 @@ +# Import configuration data +# +from_db_name = databasename +from_db_user = admin +from_db_password = secret + +to_db_name = new_db_name +to_db_user = super_admin +to_db_password = ultra_secret_password + +path_symfony = /path/to/symfony/application +path_imported_content = /path/to/imported/content +path_data = /path/do/text/data/files diff --git a/prototype/doc/import-user-report.txt b/prototype/doc/import-user-report.txt new file mode 100644 index 0000000..87e6fd2 --- /dev/null +++ b/prototype/doc/import-user-report.txt @@ -0,0 +1,1330 @@ + TOTALT ANTALL BRUKERE + =============================== + +SELECT COUNT(*) FROM reaktoruser; + count +------- + 543 +(1 row) + +SELECT COUNT(*) FROM reaktoruser WHERE type='external'; + count +------- + 508 +(1 row) + +SELECT COUNT(*) FROM reaktoruser WHERE type='administrator'; + count +------- + 5 +(1 row) + +SELECT COUNT(*) FROM reaktoruser WHERE type='editor'; + count +------- + 30 +(1 row) + + + BRUKERE SOM FJERNES + ========================= + +REDAKSJONELLE BRUKERE +--------------------- + +SELECT name, nick, email + FROM reaktoruser ru + WHERE type = 'editor' + AND (name IN ('Asgeir Bjørlykke', 'Copyleft Software AS', 'Ole-Petter Wikene', 'Stian Tyriberget', 'Test', 'Test2', 'Testbruker', 'Thomas Bakketun', 'testbruker', 'Anne-Lena Westrum') + OR (name = 'Mildrid Liasjø' AND disabled = true)); + name | nick | email +----------------------+------+--------------------------------------- + testbruker | | annelena@deichman.no + Anne-Lena Westrum | | anne-lena.westrum@kie.oslo.kommune.no + Asgeir Bjørlykke | | asgeir@copyleft.no + Stian Tyriberget | | stian@feber.nu + Copyleft Software AS | | support@copyleft.no + Testbruker | | annelena@deichman.no + Thomas Bakketun | | thomasb@copyleft.no + Mildrid Liasjø | | mildrid@tfb.no + Test | | annelena@deichman.no + Test2 | | anne-lena.westrum@kie.oslo.kommune.no + Ole-Petter Wikene | | olepw@linpro.no +(11 rows) + + + +ADMINISTRATORER +--------------- + +SELECT name, nick, email + FROM reaktoruser ru + WHERE type = 'administrator'; + name | nick | email +-------------------+------+----------------------- + Anne Lena Westrum | | annelena@deichman.no + Asgeir Rekkavik | | asgeirr@deichman.no + admin | | torhenrik@copyleft.no + Stian Tyriberget | | stian@feber.nu + Ole-Petter Wikene | | olepw@linpro.no +(5 rows) + + +VANLIGE BRUKERE +--------------- + +SELECT name, nick, email + FROM reaktoruser ru + WHERE type = 'external' + AND NOT EXISTS (select * from comment where creator = ru.id) + AND NOT EXISTS (select * from rating where reaktoruser = ru.id) + AND NOT EXISTS (select * from artwork where creator = ru.id) + AND NOT EXISTS (select * from changelog where reaktoruser = ru.id AND action = ':LOGIN') + OR nick IN ('asgeir', 'asgeirr', 'Betty', 'Boltorn', 'erdether', 'groa', 'Hufsa', 'Kerman', 'kolofon', 'leo', 'Oter', 'Silva', 'Spøkelseskladden', 'testpost', 'testvesenet', 'theger', 'torbman', 'trinew', 'varja240', 'venkeu', 'zebh'); + name | nick | email +--------------------------------------+--------------------------------------+--------------------------------------- + Arne Skalleberg | arneska | arneska@hotmail.com + Jacqueline von Arb | Jacko | jacqueline.vonarb@his.no + Svein Thaulow | Svein | sv-tha@online.no + Raymond Pedersen | raypedersen | rp28052004@yahoo.no + Mari Forseth | Mari F. F. | mari.forseth@gmail.com + Beate Louise Sønnervig | Betty | beates@deichman.no + Hugo Bruvoll | Porjus | hbruvoll@chello.no + Leif Storvik | Leif | lestorvi@online.no + Venke Uglenes | venkeu | venkeu@deichman.no + claire annette whelan | claireaw79 | claireaw79@yahoo.com + Henriette Frisenberg Sundgaard | Hufsa | henriets@deichman.no + erdether | erdether | sirit@deichman.no + Knut Oterholm | Oter | knuto@deich.folkebibl.no + Karen | lollo | lollofte@hotmail.com + åshild nerland | åshild | silla_1@hotmail.com + Kolofon AS | kolofon | trine@kolofon.com + Ingrid P. Eide | Yellow | ingride@broadpark.com + Ingrid P. Eide | Ingrid | ingride@broadpark.no + TT | Celsius_no | celsius_no@hotmail.com + Ingrid | Apekatten | tony.ribe@c2i.net + Ingrid | Den lille apekatten | tony.ribe@c2i.net + Ingrid | Don`t blame me for being crazy... | tony.ribe@c2i.net + chreb | chreb | chr.eins@online.no + aurora wikstrøm | Midna | rubywic@hotmail.com + vilde monclair | anayokari | vilde_brannfarlig@hotmail.com + vilde monclair | Ayanokoji | vilde_brannfarlig@hotmail.com + Liv S | Liv | pjuskepels@hotmail.com + Liv | pjuskepels | pjuskepels@hotmail.com + Lene Jahnsen | Lusia | ljahnsen@yahoo.com + Håvard Melbye | Havmel | havmel@hotmail.com + Ingrid Fauske | blondie | ifauske@start.no + Arne Hove | Ørn | arnhove@online.no + Roy Nilsen | Videoroy | roy.nilsen@brundalen.vgs.no + Siri | sirita | sirit@deichman.no + Lisa Kvalbein | lisa0ed | miss_93_10@hotmail.com + Anne-Lena | leo | annelena@deichman.no + Anne | Spøkelseskladden | annem@deichman.no + Tester testesen | testvesenet | ingunn@tfb.no + Per Espeland | perez | per@espeland.as + Bodil Halvorsen | Nyskjerrig | Bodil.Halvorsen@drammen.kommune.no + Trine Westberg | trinew | trinew@deichman.no + Thomas | Honning05 | almtre@hotmail.com + thomas | honning | almtre@hotmail.com + Asgeir Bjørlykke | asgeir | asgeir@ablab.no + Kvam folkebibliotek | Norheimsund | bibliotek@kvam.kommune.no + Gro Larsen Kitmitto | groa | gro@deich.folkebibl.no + Kristina | Kristina | kjistiina@yahoo.no + Terje Skare | Teska | terje_skare@hotmail.com + Isaac Ryen Gloinson | Isaac0103 | caasi_gloinson@hotmail.com + Carl-Christian Salvesen | Calle | calle@ioslo.net + torbjørn | torbman | doctormacabre@hotmail.com + Kristine | Kristine | kab@abm-utvikling.no + Asgeir Rekkavik | asgeirr | asgeirr@deichman.no + Agnar Bang | Agnarushka | agnar@chello.no + Trein | TREI | anne.oterholm@chello.no + Rine K. Brofoss | Kalle | rine_k@hotmail.com + Johannes Grødem | johs | johs@copyleft.no + benedicte elisabeth dalheim | benedite | benedicte_jusstud@hotmail.com + Barbro Bakken | Silva | barbrob@deich.folkebibl.no + Erlend Huseby | Ponto | donnyboy__89@hotmail.com + Liv Randi Andreassen | Life | livr_a@hotmail.com + Stine Aulie | pooka | stine_bittersweet@hotmail.com + Stine Aulie | Papiret | stine_bittersweet@hotmail.com + Eivind | Kaketyv | eivindkarlung2@hotmail.com + Synnøve Storjord | synnmarg | synnmarg@online.no + henrik | henrik | rollerboy3000@hotmail.com + Siemen | Eurobeat | siemen.halvorsen@gmail.com + rabarbrah | rabarbrah | rabarbrah@gmail.com + Trond Wiger | Oscar Øglænd | buustamon@yahoo.no + Greta Fornes | fogr | greta.fornes@brundalen.vgs.no + Lars Tiller | Larsi | larsifaen@hotmail.com + Marit Sivertsvold | Masiver | masiver@hotmail.com + Toralf | Toralf | Toralf@hotmail.com + Elise F. Ø. | Ron | ronjaw@gmail.com + stein | stein | stein@orgdot.com + håkon | kitty | andreaspotter_7@hotmail.com + marthe westjordet | yatzy | yatzyja@gmail.com + håkon | hello-kitty | andreaspotter_7@hotmail.com + Martin Sundin | fonkymorbror | jazzwithmartin@yahoo.com + adnan | shafka | shafka9@hotmail.com + Lars Erik Brennvall | lars | brennvall@flashklubben.com + Erling | erlbor | erlbor@hotmail.com + Stig-Terje Amundsen | stigi | stigterje_amundsen@hotmail.com + Bodil Nilsen | Bodiln | bodil.nilsen@gmail.com + peder andreas hanstad | halla 6000 | peder.hanstad@skoyen.gs.no + Aadne Ore | SirAadne | empireman93@hotmail.com + siri- turid | siri- turid0404 | siri-turid@hotmail.com + Eirik Humlen | Raicon | Newmedia@msn.com + siri-turid | siri-turid | trygve_93@hotmail.com + halvor | hallis | halvor.njerve@skoyen.gs.oslo.no + øyvind | oyvoyv! | oyvind.vennerod@skoyen.gs.oslo.no + Henrik | HeNkE | boffy93@hotmail.com + Inger Elise Solberg | ingeres | ingeres@skedsmo.kommune.no + Linda Rosita Rystad | thelema | thelemaxmagick@yahoo.no + Ivar Kvaal | zebh | ivar@bmx.no + Malin | Rockagirl | angel_1727_@hotmail.com + Zahraa | Zahraa Bani Saad Asaad | zahraa.bani-saad@ostensjo.gs.oslo.no + cicilie | Mini | cicilen@online.no + gøran | kent8dsu | elisba@online.no + martine stordal | martine | princes_stordal@hotmail.com + Anja Strømsted Høvik | varja240 | varja240@hotmail.com + Eili Bråstad Johannessen | Eili | eilijo@hotmail.com + per-eianr | arta | www.rikman@hotmail.com + Susanne | Sussilove | susneshal@hotmail.com + Susanne | sussilove | susneshal@hotmail.com + Taiba | tebbern | pinki_b93@hotmail.com + andre | andre2609 | andre.valente@skoyen.skole.oslo.gs.no + Tormod h. tønsberg | Warside | Tormodgrand@hotmail.com + christian | pet | christian.christianpet@gmail.com + Praman | Praman | inkaur@online.no + Kristine Pedersen Titternes Horsberg | little Devil | kristine.Horsberg@ostensjo. + martin.dønnum | martin.dønnum | martin.donnum@ostensjo.gs.oslo.no + Martin | Martind | martin.donnum@ostensjo.gs.oslo.no + Petter | ørnen | petter.skanke@ostensjo.gs.oslo.no + David | wik | david.wiken@ostensjo.gs.oslo.no + Ida | Ida | Ida.Bojang@ostensjo.gs.oslo.no + dandi | doldo | dandi.olika@ostensjo.gs.oslo.no + Kristine Pedersen Titternes Horsberg | Devil | Kristine.Horsberg@ostensjo.gs.oslo.no + Rakel Oliva Ødegaard Skaugen | relle_celle | rakel.skaugen@ostensjo.gs.oslo.no + Cecilie Henriksen | celle_relle | cecilie.henriksen@ostensjo.gs.oslo.no + Elisabeth Sellin | Besellin20 | elisabeth.sellin@c2i.net + yousef khalid amin | nikeboy | nikeboy100@hotmail.com + Ida Eline Tangen | Idalin | bdtangen@start.no + Maria Smith | masmno | marielis@online.no + alfred furnes | alfi88 | reggae_love88@hotmail.com + CF | Boltorn | brannmannen@hotmail.com + Oyvinds | Oyvinds_post | oki1991@operamail.com + Kristina | Kazlaite | kristal@savb.lt + Antropofagos | Antropofagos | jankoradovanovic@gmail.com + mathias | Blikk1 | mathiasparken111@hotmail.com + Carl Martin Engh | Carlito666 | cmengh@hotmail.com + kåre Krogstad | krokko | krokkostudie@hotmail.com + amina | amina0207 | amixrs@hotmail.com + Thomas Heger | theger | tbheger@student.hf.uio.no + Svein Aaasn | Svennis | svein.aasan@t-fk.no + Berit Sandnes | Berit Sandnes | sandnes@hum.ku.dk + Berit Sandnes | Berit Sa | sandnes@hum.ku.dk + Berit Sandnes | beritsa | sandnes@hum.ku.dk + Jan Kåre "Sander" Østmark | OleMaster | OleMurder@Yahoo.Com + Ola | olawold | ola.wold@stfk.no + Lars Kristian Mathisen | larskr90 | lkm@xbit.no + Morten Kielland | morten | morten.kielland@start.no + Knut Winje | Casa | kriwinje@online.no + marianne | marma2006 | marte_fotball@hotmail.com + Victor Dagar Ellingsen | Mr.undead | vic_dagar@hotmail.com + Siril | siril | sirilwm@ringvemedia.com + teste teste | testpost2 | torhenrik@copyleft.no + Test Testesen | testpost | thh@copyleft.no + test test | testpost3 | torhenrik@copyleft.no + kim elise ervik | kimma | kimma_ervik@hotmail.com + Marianne | Marma | lenesolbakken@hotmail.com + Ole-Martin Erikstad | oleeriks | ole@erikstad.net + eirik | baldus | baldus9000@hotmail.com + Eirik | eidrinho | baldus9000@hotmail.com + Eirik | barca-fan | baldus9000@hotmail.com + Eirik | eirik_barca | baldus9000@hotmail.com + Karoline Bjørnstad | Steinerkarro | steinerkarro@msn.com + Karoline Bjørnstad | tári | steinerkarro@msn.com + Karoline Bjørnstad | karoline | steinerkarro@msn.com + Eirik | eirik | baldus9000@hotmail.com + Hedvig Flaten Lie | hedvig | fy_flaten@hotmail.com + eirik | eika | baldus9000@hotmail.com + Eirik Vale Aase | eirik_skrivegal | baldus9000@hotmail.com + Hedvig Flaten Lie | Yestarë | fy_flaten@hotmail.com + Hedvig Flaten Lie | Lairë | fy_flaten@hotmail.com + Eirik | rar_gutt | baldus9000@hotmail.com + Eirik | eirik_rar | baldus9000@hotmail.com + Bjørn Hømann | bamse | ha-soelv@online.no + Bjørn Funder Halldal | bjornfunder | bjorn_fun@yahoo.com + eirik | fotball | baldus9000@hotmail.no + Gunnhild Hystad | Pott | pott_89@hotmail.com + Cecilie Wennberg | Cecilie86 | cewen86@hotmail.com + Ingrid Rædergård | IngridRædergård | i_redergard@hotmail.com + Ingrid Rædergård | ingrijr | ingrijr@student.uio.no + Ida Marie Sand | cheezy | ims20046@hotmail.com + Torjus h. s. | notorjus | toorjus@gmail.com + trojus | toorjus | toorjus@start.no + Linh-Chi | Ma-meido Chi | virgocream@hotmail.com + Linh-Chi | Ma-meido Purinsesu | virgocream@hotmail.com + Tove | moogle | taagaa@online.no + Tor Arne Wølner | torarnew | tor.a.wolner@hive.no + Eirik | eiriks | eirik.simonsen@gmail.com + May Linda Martinsen | Soppen | maylinda.martinsen@gmail.com + May Linda Martinsen | Soppen2 | maylinda.martinsen@gmail.com + Michael Pangopoulos | mostblind | spinmove@hotmail.com + Andreas Dahl | andread | andread@never.no + Ole Tjensvold Johannessen | oletjens | ole.tjensvold.johannessen@gmail.com + Phuc Ngoc Huynh | phuc | phuc77@gmail.com + Piggy piglet | piglet | piggywiggypiglet@overlie.no + piggy wiggy piglet | piggywiggypiglet | piggywiggypiglet@overlie.no + thepigster | thepigster | thepigster@overlie.no + Ole-Petter | DotCom | dotcom@online.no + peterdass | peterdass | peterdass@overlie.no + Janne M. G. Skarstein | Miaja | miaja11@gmail.com + testbruker | testbruker | annelena@deichman.no + Test510 | test510 | supahleo@gmail.com + Solveig Skjelnes | edrun | solveig.skjelnes@dragskole.no + Mildrid test | mili | mildrid.liasjo@trondheim.kommune.no + Mildrid test | venla | mildrid.liasjo@trondheim.kommune.no + Linh-Chi | ChiChi | virgocream@hotmail.com + Lisa Tøndel Medbøen | lisa86 | lisa_kicks86@hotmail.com + Hanne Dahl | h-karida | h-karida@online.no + Lovise Andreassen | Lou94 | lovisea@start.no + Atle Hansen | flipside | gaudafish@hotmail.com +(204 rows) + + + + BRUKERE SOM BEHOLDES + =========================== + + + +SELECT name, nick, email, type + FROM reaktoruser ru + WHERE CASE type + WHEN 'administrator' THEN + false + WHEN 'editor' THEN + name NOT IN ('Asgeir Bjørlykke', 'Copyleft Software AS', 'Ole-Petter Wikene', 'Stian Tyriberget', 'Test', 'Test2', 'Testbruker', 'Thomas Bakketun', 'testbruker', 'Anne-Lena Westrum') + AND NOT (name = 'Mildrid Liasjø' AND disabled = true) + WHEN 'external' THEN + (EXISTS (select * from comment where creator = ru.id) + OR EXISTS (select * from rating where reaktoruser = ru.id) + OR EXISTS (select * from artwork where creator = ru.id) + OR EXISTS (select * from changelog where reaktoruser = ru.id AND action = ':LOGIN')) + AND nick NOT IN ('asgeir', 'asgeirr', 'Betty', 'Boltorn', 'erdether', 'groa', 'Hufsa', 'Kerman', 'kolofon', 'leo', 'Oter', 'Silva', 'Spøkelseskladden', 'testpost', 'testvesenet', 'theger', 'torbman', 'trinew', 'varja240', 'venkeu', 'zebh') + END + ORDER BY type, name; + name | nick | email | type +---------------------------------+---------------------+--------------------------------------------+---------- + Anne Lena Westrum | | annelena@deichman.no | editor + Anne Lena Westrum | | annelena@deichman.no | editor + Ann Kunish | | annk@deichman.no | editor + Asgeir Rekkavik | | asgeirr@deichman.no | editor + Berit Petersheim | | beritpe@deichman.no | editor + Bjørn Tore Nyland | | BJORN.TORE.NYLAND@trondheim.kommune.no | editor + Cecilie Bergh | | cecilieb@deichman.no | editor + Einar Silset Berg | | einarsb@deichman.no | editor + Gro Johansen Raih | | groj@deichman.no | editor + Henriette Frisenberg Sundgaard | | henriets@deichman.no | editor + Ingunn Evensen | | ingunn@trondheim.folkebibl.no | editor + Knut Oterholm | | knuto@deichman.no | editor + Korana Kurtovic | | koranak@deichman.no | editor + Mildrid Liasjø | | mildrid@tfb.no | editor + Mona Knarvik | | mona@tfb.no | editor + Sigrid Bremseth | | SIGRID.BREMSETH@trondheim.kommune.no | editor + Stine Iren Ballovarre | | STINE-IREN.BALLOVARRE@trondheim.kommune.no | editor + Thor Arne Sæterholen | | thor@deichman.no | editor + Trine Johnsen | | TRINE1.JOHNSEN@trondheim.kommune.no | editor + - | anton anonym | stian@feber.nu | external + Aadne Ores | Sir-Aadne | aadne.ore@skoyen.gs.oslo.no | external + Adrian Bugge | Adrian | adrian@firestudio.no | external + Adrian Busk Strømsmoen | Addinski | addinski14@hotmail.com | external + alaleh | alaleh | alalehnavaii@yahoo.com | external + Albrecht Hofheinz | a007 | Albrecht.Hofheinz@ikos.uio.no | external + alexandra berlin nilssen | alexax | LofotSnuppa@msn.com | external + Anders Grimsrud | andersgrim | andersgrim@gmail.com | external + Anders Haugen | Apsyche | anders.haugen@spray.no | external + andreas | A.c | andreascheng@dbz4k.zzn.com | external + Andreas Olsen | andreas | andreas24-7@hotmail.com | external + Andreas S. Frølich | vonfrolich@yahoo.no | vonfrolich@yahoo.no | external + Ane Stenberg | Chainy | Ane_Stenberg@hotmail.com | external + Anne | annymal | annymal@hotmail.com | external + Anne-Line Henriksen | Anna | lishenri@online.no | external + Annemarie Barker | annemarie | ab_29_10@hotmail.com | external + Anne Woje | acwo | a-woj@online.no | external + Anniken Grønvik | Anken | anniken_karlstad@hotmail.com | external + anniken sæther | heineken | ConeMcCaslin@hotmail.com | external + Ann Kunish | annk | annk@deichman.no | external + Anny Langer | Langer | annylang@annylanger.com | external + Arild | Arild | arildmann@hotmail.com | external + Arild Vassend | arildvassend | arildvassend@hotmail.com | external + Arne-Daniel Storevold Haldorsen | Arne-Daniel | arnedaniel.sh@gmail.com | external + Arne Otto Sandmo | arni | arneotto.sandmo@gmail.com | external + Arne Skalleberg | arsk | arneska@vfk.no | external + Åse Britt Larsen | propaganda | aselarsen@yahoo.no | external + Åshild Plener | lance | gress_m@hotmail.com | external + Åsmund | Åsmund | aasziz90@hotmail.com | external + åsmund sem-johansen | asemjo76 | asemjo@start.no | external + Åsmund Sem-Johansen | Asemjo | asemjo@start.no | external + Atle Enersen | nesrene | atle@enersen.no | external + Beate Børli Løkken | bea | bea_bolla@hotmail.com | external + bettina | Ape | bettina.gudim@ostensjo.gs.oslo.no | external + Bjørnar | molukk | bjornar@nettmail.no | external + Bjørn Endre Langeland | breivik | bjorn.breivik@gmail.com | external + Bjørn Thevik | Bjørn Thevik | bjorn@thevik.com | external + Bjørn Tore Nyland | bny | bjorn.tore.nyland@trondheim.kommune.no | external + bob | bobbao | bobbao1971@hotmail.com | external + Bøler og Oppsal filialer | fopp | annelena@deichman.no | external + Børge Fallmyr Sund | faramir | borgesu2001@yahoo.no | external + Børre Antonsen | apoet | anton@apoet.no | external + Brit Helen Bernsen | ShortyPunk | shorty_punk@hotmail.com | external + Camilla | Thalii | thaliithiel@hotmail.com | external + Camilla Horgøien | Jade | camillh@stud.ntnu.no | external + Carina Borgund | bavian | carina.borgund@ostensjo.gs.oslo.no | external + carmian | lille meg | yoda150690@hotmail.com | external + cathrine | blacky | cathrine_lt@hotmail.com | external + Cathrine Alvin | E6-Cathrine | cathrine@flashklubben.com | external + Cathrine Syverstad | catsyv | catsyv@hotmail.com | external + Cecilie Bergh | CillyBilly | cecilieb@deichman.no | external + Cheryl Lynn Rubin | Suki | cl-rubin@frisurf.no | external + Christian Halvorsen | chaL | chal_89@hotmail.com | external + Christopher Emil Jørgensen | lime | emil_er_kul@hotmail.com | external + Cliff Kjenna | Dagern | cliff@epost.no | external + Cutter filmkompani | Citrus film | erik@tobiassen.no | external + Cynthia | Cynthia | cynthia.muller@ostensjo.gs.oslo.no | external + Dag Stian Baltzersen | Daggers | dagstianb@hotmail.com | external + Damien Smith | damienjsmith | damienjsmith@hotmail.com | external + Daniel | Burning Danielo | oecar@online.no | external + Daniel Carlsen | Captain_Evil | oecar@online.no | external + Daniel Harila Carlsen | Manganerd | oecar@online.no | external + Daniel Korsmoe | Phunk_Phr33k | poebelsmurfen@gmail.com | external + Daniel Kristensen | danniboy | danielkristensen@mail.com | external + Dave Kunish | Invizzible | monsterandfuzzy@mac.com | external + David Barratt-Due | SirDavid01 | didie0932@hotmail.com | external + Deichmanske bibliotek | deichman | reaktor@deichman.no | external + Egil Arnold Vigrestad | E.A.Vigrestad | arnvigre@online.no | external + Eirin Koehler Breivik | Kanel | eirin@kanel.no | external + Eivind Brokke | Ivan | eibrokke@broadpark.no | external + Eivind Vetlesen | eivindv | eivindvetlesen@yahoo.no | external + Elisabeth Heradstveit | elishera | elishahera@hotmail.com | external + Elizabeth | Lizzi | lizziluu@hotmail.com | external + Emilie Kolstø Strømøy | Emilie | miss.stromoy@gmail.com | external + Emin | emi | emin_duraku@hotmail.com | external + Erik | ErikL | erik_lunke@hotmail.com | external + Erlend Huseby | Zaran | zaran_89@hotmail.com | external + Fabian | Capt skeid! | fabian.gleditsch@skoyen.gs.oslo.no | external + Fed Håvar Svartdal | ShadowHunter | fhs_spawn@hotmail.com | external + Ferenc Seres | Ferenc | f.seres@chello.no | external + Frank Iversen | Frank | frank1iversen@gmail.com | external + Frede Herstad | RabbitFly | therabbitfly@hotmail.com | external + Fredrik Sivertsen | djjackal | deejay_jackal@hotmail.com | external + Gaute | Gaute | gauteg@hotmail.com | external + Geir Sundelius | geirok | geir.sundelius@chello.no | external + Gøran Frost | pterodactyl | goran__frost@hotmail.com | external + grafstad | grafstad | grethe@kardemommeby.com | external + Greta Bruu Olsen | Skogpingvin | gretab@deichman.no | external + grethe elvenes | PEZ | grethe@elvenes.org | external + Gro Arneberg Thoresen | groat | groarneberg@hotmail.com | external + Gro Emblemsvåg | gembla | gembla@gmail.com | external + Grünerløkka filial | Grynerløkka filial | annelena@deichman.no | external + Gunhild | Gunhild | ordmix@online.no | external + Gunnar Dypdahl | Sverre | gunnar@deichman.no | external + Håkon | hakon2612 | Hakon.mikaelsen@ostensjo.gs.oslo.no | external + Håkon | hello_kitty | willmelina_91@yahoo.no | external + Håkon Øvreås | Sausenebb | pausemaker@hotmail.com | external + Halvard Hovtun | HAIr | hair@trainsim.no | external + Hanne Hox | Shealien | hhox@broadpark.no | external + Harald Aune Skorpen | harald | harald@skorpen.net | external + Hedda Hakvåg | amanda | hedda_hak@hotmail.com | external + Heidi Ravnås | diablesa | diablesa25@hotmail.com | external + Heine Jensvold | kvikks | heine@gulo.no | external + Henko Waratenko | Henko Waratenko | henko_w@hotmail.com | external + Hilde Aleksandersen | glorybox | hildealeksandersen@hotmail.com | external + hilde pettersen | hilde | hilde.pettersen@lillestrom.vgs.no | external + Ida Helgesen | Princess Zelda | Ida.helgesen@ostensjo.gs.oslo.no | external + Igal Voronel | Igal | igalv@deichman.no | external + inger | inger | ilbergli@online.no | external + Inger Christine Årstad | magica | annelena@deichman.no | external + Ingrid Eide | mango | ingrid.eide@ostensjo.gs.oslo.no | external + Ingrid Engh Johansen | Casiopeja | ingrid_smiling@hotmail.com | external + Ingrid Hegvik | ingrid&stine | dirgniid@hotmail.com | external + Ingrid neverdal | ingrinev | inn91@hotmail.com | external + Ingunn Evensen | Khi | ingunn@trondheim.folkebibl.no | external + Ingvild Holann | Leeloo | icholann@start.no | external + Irene Hellem | nene26 | nene26@gmail.com | external + Isaac R. Gloinson | caasi | caasi_gloinson@hotmail.com | external + Isak Aerendil Menes | aerendil | isakmenes@hotmail.com | external + jaa. | chu | julie_marie90@hotmail.com | external + Jan F. Lindsø | iudex | stolthet@gmail.com | external + Jan H Hansen | Jani | janih@hotmail.com | external + jan revil | janr16 | jan-revi@online.no | external + Ja Si Det | Dude | op_fossum@hotmail.com | external + Javier Torrealba | Javier Torrealba | javier_torrealba@hotmail.com | external + Jo Eskil Røset | RamForth | joe@ramforth.net | external + jofrid sørvoll | jofridso | jofrids@hotmail.com | external + Johannes Grødem | Ehud | johs@copyleft.no | external + johannes zelalem vollan | falken | johannes.vollan@ostensjo.gs.oslo.no | external + Johansen, Siv Kirsten | sivkirsten | sivkj@deichman.no | external + John Ivar Bakken | klompen | mr_bakken@hotmail.com | external + jokke netland | jokke | jokkepost@gmail.com | external + jonas | jonask0611 | jonas.nilsen@ostensjo.gs.oslo.no | external + Jørn Helge B. Dahl | evergud | evergud@gmail.com | external + Jørn Kaarstad | TomPetty | conanfracimmeria@hotmail.com | external + julie | julle | julie.martinussen@skoyen.gs.oslo.no | external + Julie | faceup | julie_turunen@hotmail.com | external + Julie Didriksen | Staralfur | julie988@online.no | external + Julie Henning | julla | julla90@hotmail.com | external + june | piggywiggy | piggywiggy@overlie.no | external + June Maria | JMTiger | junemaria@hotmail.com | external + Kari | karig | kari@groruddalen.info | external + Karina | Karina | ketsjup@hotmail.com | external + katherine | kathy | kjoakimsen@hotmail.com | external + Katja | Wenty | katjakf@chello.no | external + Katja Fuglaas | KikkÆ | katja@no-play.net | external + Kim Alexander Krohn Berle | fullbartender | full-bartender@hotmail.com | external + kim hamang raphaug | uglek | uglek@hotmail.com | external + Kim Lopez | Lopez | kimlopez@gmail.com | external + Kjetil Molnes | Kjetil68 | k_moll@chello.no | external + Knut Erik Tornaas | knut erik | ganadeva@hotmail.com | external + Knut Sørby | knuts | knuts@chello.no | external + Kristina Kazlaite | karoliuk | kristal@savb.lt | external + kristine | krissikrissi | krissi-girl@hotmail.com | external + Kristine Vestøl | Ninian | k@finnvest.no | external + Kristin Farnes | Kristin184 | gladpia_89@msn.com | external + Kristin Øye Gjersdal | Kristin | kr_i_s_t_in@hotmail.com | external + Kristoffer Hansen | Vektorized | kristoffer_h88@hotmail.com | external + Laila | Laila | ha-chri@online.no | external + Larissa Lindseth | larilind | larilind@yahoo.no | external + Lars Erik Brennvall | brennvall | l_e_brennvall@hotmail.com | external + Lars Erik KLEMSDAL | renzo.monte | larsek2@yahoo.com | external + Lars Kristian Mathisen | lkmathis | lkm@xbit.no | external + lars kvam kristoffersen | larskr3 | larskr3@online.no | external + lars lervik | karius | lerviklars@hotmail.com | external + Lars Mikkel Aas | mikkel | lars.aas@eunet.no | external + Lars Øyvind Christiansen | Juliuz | larsoc@online.no | external + Lars Petter | laser | larspm35@hotmail.com | external + Lars Tiller | zefish | larsifaen@hotmail.com | external + leif | leifean | leifriksheim@hotmail.com | external + Leif Sæther | leifsae | leifsae@online.no | external + Lena Victoria Wang Rødli | WiCcA | lille_rubin@hotmail.com | external + Lene Fallan | Lene140290 | lene_4_u@hotmail.com | external + Leo Pierini | Leo Pierini, CUF | leo.pierini@centerpartiet.se | external + Lise | Midnatt | lizz_lovegood@hotmail.com | external + Lise Selvåg | Lise | efremova_666@hotmail.com | external + Lise Strandlien | snotra | lise@strandlien.com | external + Live Schille | lilleschille | liveschille@hotmail.com | external + Liv Olsen | kerman | livo@deich.folkebibl.no | external + louise sølvi | thelove | hellu_kompis@hotmail.com | external + Lund Barnefilmklubb | Lund Barnefilmklubb | steinarm@mac.com | external + Lydia | Pribamm | lydiaborienhatt@hotmail.com | external + Mads | neurol | arntzenjr@hotmail.com | external + Mads Kolbu | mkolbu | mkolbu@start.no | external + Maggie Tu | azian_babe | puzen_din_18@hotmail.com | external + Magnus Forsberg | Alinoe | alinoe@gmail.com | external + Magnus sundsjord | morpheus | magnusstar@spray.no | external + Magnus Viktil | Sofamonsteret | sofamonsteret@hotmail.com | external + Maja H. Kvendseth | Gru | grumejl@hotmail.com | external + Malin | rockagirl91 | angel_1727_@hotmail.com | external + Marcel Dekker Devos | MarcelDD | marcel.dekker.devos@aschehoug.no | external + margaret bøe | margarbo | margaret_boe@hotmail.com | external + margaret bøe | margaret | margaret_boe@hotmail.com | external + Marianne | Marri92 | hanped@online.no | external + Mari Anne | maddi | maddimor@hotmail.com | external + Marie | Mariemor | marri22_4@hotmail.com | external + Marie Olsen | Marie | marsve@skolepost.no | external + Marius Thorvildsen | MThorvildsen | jalla_jonny@hotmail.com | external + Marlene Ullerlien | Mustis | Mustiz3@hotmail.com | external + Marte Grevsgard | Marte | gmarte@postmaster.co.uk | external + Martha | anonym | martha_lynne@hotmail.com | external + martin | marty | martin_fotballgutt@hotmail.com | external + martin | tubgirl1101 | martingrahamtobiassen@hotmail.com | external + Martin Berg | martiin | martinerfin@gmail.com | external + Martin Hansen | PsyQz | martin_hansen89@hotmail.com | external + Martin Haraldsen | martin | martinh@damedoen.com | external + martin solholm | mediasmilie | mediasmilie@hotmail.com | external + Mate Toth | thmate | thmate@freemail.hu | external + Mathias H. Wilhelmsen | MHW | mathia0804@hotmail.com | external + Mattias Appelgren | Mattebong | matap78@hotmail.com | external + Michael Baker | mbakernorway | michael.baker@online.no | external + Mona Dalheim | monad | monad_no@yahoo.no | external + Mona Mogadam | Mona Mogadam | monapus@hotmail.com | external + Morten Kielland | mokiel | morten.kielland@skjaak.kommune.no | external + Morten Rostad | Fisiltut | mrostad@gmail.com | external + nico | nicho | nicholas.solheim@skoyen.gs.oslo.no | external + Niklas Sebastian Grenvik | Niklas | nikgren@hotmail.com | external + Nils Sigve Haughom | niggen | niggen@hotmail.com | external + Norunn Heger | Ava | no_he@hotmail.com | external + Oda Bodsberg Stræte | aestas | oda_straete@hotmail.com | external + Øivind Andresen | oivind | oivind@bradager.net | external + Olav Celius | ovl | olavc@deichman.no | external + Ole Martin Eidesmo | omeid87 | dark_the_guru@hotmail.com | external + Ole-Martin Erikstad | olemartin | ole@erikstad.info | external + Ørjan | V1P3R | viperconsept_is_back@hotmail.com | external + Øystein Nilsen | ANgel | zibiam@hotmail.com | external + Øyvind K. Lillebergen | TraXter | webmaster@lillebergen.net | external + Pål Oliver Kristiansen | twistah | paal.oliver@netcom.no | external + peder | pbd | pbd01@hotmail.com | external + perniss | pernil | pernille.martinussen@skoyen.gs.oslo.no | external + Petter | Nixtar | pettknu@online.no | external + Philip C Scheel | KiNexus | kinexus@start.no | external + Philip C Scheel | Ki Nexus | kinexus@start.no | external + Pramandeep | Pramandeep | pramandeep.dhami@ostensjo.gs.oslo.no | external + Ragnhild | thyenna | ragnhild_solberg@hotmail.com | external + ragnhild torstensen | ragnaråkk | torstensen88@hotmail.com | external + Ragnhild Torstensen | Hobbes | torstensen88@gmail.com | external + Raymond Pedersen | raypede | rp28052004@yahoo.no | external + reidar hesseberg | rolav | rohesse@c2i.net | external + reinert mithassel | rein | reinertm@online.no | external + Rim G | PoetiCurlz | eritreanpride@hotmail.com | external + Rita Aune | iita | ritaaune88@gmail.com | external + roar håland | roar | roahaal@online.no | external + Roger Evans | rev | rev@bluezone.no | external + Ronny Karlsen | DoggyDog | ronkarl2@frisurf.no | external + Roy Hovden | rhov23 | roy.hovden@gmail.com | external + Ruben Solvang | messo | messomail@gmail.com | external + Rune Andrè Larsen | Scavenger | gekko_rune@hotmail.com | external + Ruth Schukalla | Dunja1001 | ruth.schukalla@ntfk.no | external + Salar | Salar | salar_ilami@hotmail.com | external + samira naureen | samira1804 | sapna_2003@hotmail.com | external + Sandra | Jajja | jajja_hest@hotmail.com | external + sara karoline | tassepusen | tassetoff@hotmail.com | external + Sebastian Grande Hofstad | Seb | Sebastian_hofstad@hotmail.com | external + Seema Ghani | SG | eiriknesheim@hotmail.com | external + Selma | Selma | selma_zt@hotmail.com | external + Sepehr Hosseini | cpr | rhepes@hotmail.com | external + Serieteket | serieteket | annelena@deichman.no | external + serieteket1 | serieteket1 | annelena@deichman.no | external + Siril | siril_wm | sirilwm@hotmail.com | external + Snorre hovdal | Windwalker | snorre@thirdkindband.com | external + Sølvi Nilssen | Sol | solvi.nilssen@effectum.com | external + Sonja Hepsø | sonja7 | todsonja@hotmail.com | external + Stefan Wold | Stefan | chriwo@online.no | external + steffie | steffies | steffies@start.no | external + Steinar Eilertsen | Ferdinand | steinar@sedesign.no | external + Steinar Utstrand | stonescar | stonescar@gmail.com | external + Stine Hansen | Stine | stineb-h18@hotmail.com | external + stine indergård | stinei | stineinder@hotmail.com | external + Stine Sjåstad | 72 | stinesjaastad@hotmail.com | external + Sunniva | Sun9 | sunnivaw@online.no | external + Svein E Kvernoey | Boah | boah@sigames.com | external + Svein Hovland | holden | svein.hh@hotmail.com | external + Tarjei Abelsen | Teejay | fettakuken@gmail.com | external + Terje Lien | terjelien | terje.lien@skullerud.gs.oslo.no | external + therese dahl | Therese | lille_trille88@hotmail.com | external + Therese Dahl | myerz | therese_dahl@hotmail.com | external + Thomas Roka-Aardal | thepope | thomas.aardal@conduct.no | external + Thor Arne Sæterholen | Holen | ta.holen@c2i.net | external + Thor Merlin Lervik | Rohtie | roht_gnilk@yahoo.no | external + Tom Ragnar Wold | fosgate | tom.ragnar.wold@lofotencharterbat.no | external + Torbjørn | BëØwÕLf THe 1337 | doctormacabre@hotmail.com | external + Torbjørn Kvam | AmoS | tkvam@broadpark.no | external + Tor-Erik Lindstrøm | AlmostKungFu | gulrotx@hotmail.com | external + Torgeir Berstad | tberstad | torgeir.berstad@t-fk.no | external + Tor Henrik Hanken | torhenrik | torhenrik@copyleft.no | external + tove | mooglepooh | taagaa@online.no | external + Trine Johnsen | tiny | trine1.johnsen@trondheim.kommune.no | external + una | dori-ma | una@ftb.no | external + Ung strek 05/06 | Ung strek 05/06 | reaktor@deichman.no | external + valentin | BigVaLeN | valenvalen@gmail.com | external + Vebjørn Søndersrød | vebjorn | vebjorn.sondersrod@nb.no | external + Vegard | Afalahs | vegard_dybvad@hotmail.com | external + Vemund Ekle | VE | vemunde@student.sv.uio.no | external + Vicki Jacob-Aas | Vicki Jacob-Aas | info@vickijacob.co.uk | external + Vidar Aas | Kaptein Paw-Paw | vidaraas@yahoo.no | external + Vilde Årvold Crowo | Ville | Vilde.Crowo@ostensjo.gs.oslo.no | external + vilje celin | honeybunch | vilje_celin@hotmail.com | external + wan yuan | wan | yuanwan2179@yahoo.com | external + Wenche Person | Mamoo | wepspers@hotmail.com | external + yngve grotmol | yngveg | y-grotmo@online.no | external + Yoda | yoda | yoda150690@hotmail.com | external + Yvonne Vornes | YV | yvonnevornes@hotmail.com | external + Zibiam Zi | zibiam | zibiam@gmail.com | external +(323 rows) + + + + BRUKERE UTEN AKSEPTERTE VERK + =================================== + + +SELECT ru.type, ru.name, ru.nick, ru.email + FROM reaktoruser ru + LEFT OUTER JOIN + (SELECT DISTINCT creator + FROM artwork + WHERE id NOT IN (SELECT object + FROM changelog c1 + INNER JOIN + artwork a + ON c1.object = a.id + INNER JOIN reaktoruser u + ON u.id = a.creator + WHERE object_type = 'artwork' AND action = ':DENY' + AND timestamp > ALL (SELECT timestamp + FROM changelog c2 + WHERE c2.object = c1.object AND c2.action = ':ACCEPT'))) a + ON ru.id = a.creator + WHERE a.creator IS NULL + ORDER BY ru.type, ru.name; + + type | name | nick | email +---------------+--------------------------------------+--------------------------------------+-------------------------------------------- + administrator | admin | | torhenrik@copyleft.no + administrator | Anne Lena Westrum | | annelena@deichman.no + administrator | Asgeir Rekkavik | | asgeirr@deichman.no + administrator | Ole-Petter Wikene | | olepw@linpro.no + administrator | Stian Tyriberget | | stian@feber.nu + editor | Anne Lena Westrum | | annelena@deichman.no + editor | Anne Lena Westrum | | annelena@deichman.no + editor | Anne-Lena Westrum | | anne-lena.westrum@kie.oslo.kommune.no + editor | Ann Kunish | | annk@deichman.no + editor | Asgeir Bjørlykke | | asgeir@copyleft.no + editor | Asgeir Rekkavik | | asgeirr@deichman.no + editor | Berit Petersheim | | beritpe@deichman.no + editor | Bjørn Tore Nyland | | BJORN.TORE.NYLAND@trondheim.kommune.no + editor | Cecilie Bergh | | cecilieb@deichman.no + editor | Copyleft Software AS | | support@copyleft.no + editor | Einar Silset Berg | | einarsb@deichman.no + editor | Gro Johansen Raih | | groj@deichman.no + editor | Henriette Frisenberg Sundgaard | | henriets@deichman.no + editor | Ingunn Evensen | | ingunn@trondheim.folkebibl.no + editor | Knut Oterholm | | knuto@deichman.no + editor | Korana Kurtovic | | koranak@deichman.no + editor | Mildrid Liasjø | | mildrid@tfb.no + editor | Mildrid Liasjø | | mildrid@tfb.no + editor | Mona Knarvik | | mona@tfb.no + editor | Ole-Petter Wikene | | olepw@linpro.no + editor | Sigrid Bremseth | | SIGRID.BREMSETH@trondheim.kommune.no + editor | Stian Tyriberget | | stian@feber.nu + editor | Stine Iren Ballovarre | | STINE-IREN.BALLOVARRE@trondheim.kommune.no + editor | Test | | annelena@deichman.no + editor | Test2 | | anne-lena.westrum@kie.oslo.kommune.no + editor | testbruker | | annelena@deichman.no + editor | Testbruker | | annelena@deichman.no + editor | Thomas Bakketun | | thomasb@copyleft.no + editor | Thor Arne Sæterholen | | thor@deichman.no + editor | Trine Johnsen | | TRINE1.JOHNSEN@trondheim.kommune.no + external | Aadne Ore | SirAadne | empireman93@hotmail.com + external | Aadne Ores | Sir-Aadne | aadne.ore@skoyen.gs.oslo.no + external | adnan | shafka | shafka9@hotmail.com + external | Adrian Busk Strømsmoen | Addinski | addinski14@hotmail.com + external | Agnar Bang | Agnarushka | agnar@chello.no + external | alaleh | alaleh | alalehnavaii@yahoo.com + external | alfred furnes | alfi88 | reggae_love88@hotmail.com + external | amina | amina0207 | amixrs@hotmail.com + external | Anders Grimsrud | andersgrim | andersgrim@gmail.com + external | andre | andre2609 | andre.valente@skoyen.skole.oslo.gs.no + external | andreas | A.c | andreascheng@dbz4k.zzn.com + external | Andreas Dahl | andread | andread@never.no + external | Andreas Olsen | andreas | andreas24-7@hotmail.com + external | Andreas S. Frølich | vonfrolich@yahoo.no | vonfrolich@yahoo.no + external | Ane Stenberg | Chainy | Ane_Stenberg@hotmail.com + external | Anja Strømsted Høvik | varja240 | varja240@hotmail.com + external | Anne | annymal | annymal@hotmail.com + external | Anne | Spøkelseskladden | annem@deichman.no + external | Anne-Lena | leo | annelena@deichman.no + external | Anne-Line Henriksen | Anna | lishenri@online.no + external | Annemarie Barker | annemarie | ab_29_10@hotmail.com + external | Ann Kunish | annk | annk@deichman.no + external | Antropofagos | Antropofagos | jankoradovanovic@gmail.com + external | Arne-Daniel Storevold Haldorsen | Arne-Daniel | arnedaniel.sh@gmail.com + external | Arne Hove | Ørn | arnhove@online.no + external | Arne Otto Sandmo | arni | arneotto.sandmo@gmail.com + external | Arne Skalleberg | arsk | arneska@vfk.no + external | Arne Skalleberg | arneska | arneska@hotmail.com + external | Asgeir Bjørlykke | asgeir | asgeir@ablab.no + external | Asgeir Rekkavik | asgeirr | asgeirr@deichman.no + external | åshild nerland | åshild | silla_1@hotmail.com + external | Åshild Plener | lance | gress_m@hotmail.com + external | Åsmund Sem-Johansen | Asemjo | asemjo@start.no + external | Atle Hansen | flipside | gaudafish@hotmail.com + external | aurora wikstrøm | Midna | rubywic@hotmail.com + external | Barbro Bakken | Silva | barbrob@deich.folkebibl.no + external | Beate Børli Løkken | bea | bea_bolla@hotmail.com + external | Beate Louise Sønnervig | Betty | beates@deichman.no + external | benedicte elisabeth dalheim | benedite | benedicte_jusstud@hotmail.com + external | Berit Sandnes | Berit Sandnes | sandnes@hum.ku.dk + external | Berit Sandnes | Berit Sa | sandnes@hum.ku.dk + external | Berit Sandnes | beritsa | sandnes@hum.ku.dk + external | bettina | Ape | bettina.gudim@ostensjo.gs.oslo.no + external | Bjørnar | molukk | bjornar@nettmail.no + external | Bjørn Funder Halldal | bjornfunder | bjorn_fun@yahoo.com + external | Bjørn Hømann | bamse | ha-soelv@online.no + external | Bjørn Thevik | Bjørn Thevik | bjorn@thevik.com + external | Bjørn Tore Nyland | bny | bjorn.tore.nyland@trondheim.kommune.no + external | Bodil Halvorsen | Nyskjerrig | Bodil.Halvorsen@drammen.kommune.no + external | Bodil Nilsen | Bodiln | bodil.nilsen@gmail.com + external | Børge Fallmyr Sund | faramir | borgesu2001@yahoo.no + external | Brit Helen Bernsen | ShortyPunk | shorty_punk@hotmail.com + external | Carina Borgund | bavian | carina.borgund@ostensjo.gs.oslo.no + external | Carl-Christian Salvesen | Calle | calle@ioslo.net + external | Carl Martin Engh | Carlito666 | cmengh@hotmail.com + external | Cathrine Alvin | E6-Cathrine | cathrine@flashklubben.com + external | Cathrine Syverstad | catsyv | catsyv@hotmail.com + external | Cecilie Bergh | CillyBilly | cecilieb@deichman.no + external | Cecilie Henriksen | celle_relle | cecilie.henriksen@ostensjo.gs.oslo.no + external | Cecilie Wennberg | Cecilie86 | cewen86@hotmail.com + external | CF | Boltorn | brannmannen@hotmail.com + external | Cheryl Lynn Rubin | Suki | cl-rubin@frisurf.no + external | chreb | chreb | chr.eins@online.no + external | christian | pet | christian.christianpet@gmail.com + external | Christian Halvorsen | chaL | chal_89@hotmail.com + external | cicilie | Mini | cicilen@online.no + external | claire annette whelan | claireaw79 | claireaw79@yahoo.com + external | Cliff Kjenna | Dagern | cliff@epost.no + external | Cutter filmkompani | Citrus film | erik@tobiassen.no + external | Cynthia | Cynthia | cynthia.muller@ostensjo.gs.oslo.no + external | Dag Stian Baltzersen | Daggers | dagstianb@hotmail.com + external | Damien Smith | damienjsmith | damienjsmith@hotmail.com + external | dandi | doldo | dandi.olika@ostensjo.gs.oslo.no + external | Daniel Carlsen | Captain_Evil | oecar@online.no + external | Daniel Harila Carlsen | Manganerd | oecar@online.no + external | Daniel Korsmoe | Phunk_Phr33k | poebelsmurfen@gmail.com + external | David | wik | david.wiken@ostensjo.gs.oslo.no + external | David Barratt-Due | SirDavid01 | didie0932@hotmail.com + external | Egil Arnold Vigrestad | E.A.Vigrestad | arnvigre@online.no + external | Eili Bråstad Johannessen | Eili | eilijo@hotmail.com + external | eirik | eika | baldus9000@hotmail.com + external | eirik | fotball | baldus9000@hotmail.no + external | eirik | baldus | baldus9000@hotmail.com + external | Eirik | rar_gutt | baldus9000@hotmail.com + external | Eirik | eirik_rar | baldus9000@hotmail.com + external | Eirik | eidrinho | baldus9000@hotmail.com + external | Eirik | barca-fan | baldus9000@hotmail.com + external | Eirik | eirik_barca | baldus9000@hotmail.com + external | Eirik | eiriks | eirik.simonsen@gmail.com + external | Eirik | eirik | baldus9000@hotmail.com + external | Eirik Humlen | Raicon | Newmedia@msn.com + external | Eirik Vale Aase | eirik_skrivegal | baldus9000@hotmail.com + external | Eirin Koehler Breivik | Kanel | eirin@kanel.no + external | Eivind | Kaketyv | eivindkarlung2@hotmail.com + external | Eivind Brokke | Ivan | eibrokke@broadpark.no + external | Elisabeth Heradstveit | elishera | elishahera@hotmail.com + external | Elisabeth Sellin | Besellin20 | elisabeth.sellin@c2i.net + external | Elise F. Ø. | Ron | ronjaw@gmail.com + external | Emilie Kolstø Strømøy | Emilie | miss.stromoy@gmail.com + external | Emin | emi | emin_duraku@hotmail.com + external | Erlend Huseby | Zaran | zaran_89@hotmail.com + external | Erlend Huseby | Ponto | donnyboy__89@hotmail.com + external | Erling | erlbor | erlbor@hotmail.com + external | Fabian | Capt skeid! | fabian.gleditsch@skoyen.gs.oslo.no + external | Fed Håvar Svartdal | ShadowHunter | fhs_spawn@hotmail.com + external | Ferenc Seres | Ferenc | f.seres@chello.no + external | Frank Iversen | Frank | frank1iversen@gmail.com + external | Frede Herstad | RabbitFly | therabbitfly@hotmail.com + external | Gaute | Gaute | gauteg@hotmail.com + external | Geir Sundelius | geirok | geir.sundelius@chello.no + external | gøran | kent8dsu | elisba@online.no + external | Gøran Frost | pterodactyl | goran__frost@hotmail.com + external | grafstad | grafstad | grethe@kardemommeby.com + external | Greta Fornes | fogr | greta.fornes@brundalen.vgs.no + external | grethe elvenes | PEZ | grethe@elvenes.org + external | Gro Emblemsvåg | gembla | gembla@gmail.com + external | Gro Larsen Kitmitto | groa | gro@deich.folkebibl.no + external | Gunhild | Gunhild | ordmix@online.no + external | Gunnar Dypdahl | Sverre | gunnar@deichman.no + external | Gunnhild Hystad | Pott | pott_89@hotmail.com + external | håkon | hello-kitty | andreaspotter_7@hotmail.com + external | håkon | kitty | andreaspotter_7@hotmail.com + external | Håkon | hakon2612 | Hakon.mikaelsen@ostensjo.gs.oslo.no + external | Håkon Øvreås | Sausenebb | pausemaker@hotmail.com + external | Halvard Hovtun | HAIr | hair@trainsim.no + external | halvor | hallis | halvor.njerve@skoyen.gs.oslo.no + external | Hanne Dahl | h-karida | h-karida@online.no + external | Harald Aune Skorpen | harald | harald@skorpen.net + external | Håvard Melbye | Havmel | havmel@hotmail.com + external | Hedda Hakvåg | amanda | hedda_hak@hotmail.com + external | Hedvig Flaten Lie | Lairë | fy_flaten@hotmail.com + external | Hedvig Flaten Lie | hedvig | fy_flaten@hotmail.com + external | Hedvig Flaten Lie | Yestarë | fy_flaten@hotmail.com + external | Heidi Ravnås | diablesa | diablesa25@hotmail.com + external | Heine Jensvold | kvikks | heine@gulo.no + external | Henko Waratenko | Henko Waratenko | henko_w@hotmail.com + external | Henriette Frisenberg Sundgaard | Hufsa | henriets@deichman.no + external | henrik | henrik | rollerboy3000@hotmail.com + external | Henrik | HeNkE | boffy93@hotmail.com + external | Hilde Aleksandersen | glorybox | hildealeksandersen@hotmail.com + external | hilde pettersen | hilde | hilde.pettersen@lillestrom.vgs.no + external | Hugo Bruvoll | Porjus | hbruvoll@chello.no + external | Ida | Ida | Ida.Bojang@ostensjo.gs.oslo.no + external | Ida Eline Tangen | Idalin | bdtangen@start.no + external | Ida Helgesen | Princess Zelda | Ida.helgesen@ostensjo.gs.oslo.no + external | Ida Marie Sand | cheezy | ims20046@hotmail.com + external | inger | inger | ilbergli@online.no + external | Inger Elise Solberg | ingeres | ingeres@skedsmo.kommune.no + external | Ingrid | Don`t blame me for being crazy... | tony.ribe@c2i.net + external | Ingrid | Den lille apekatten | tony.ribe@c2i.net + external | Ingrid | Apekatten | tony.ribe@c2i.net + external | Ingrid Eide | mango | ingrid.eide@ostensjo.gs.oslo.no + external | Ingrid Engh Johansen | Casiopeja | ingrid_smiling@hotmail.com + external | Ingrid Fauske | blondie | ifauske@start.no + external | Ingrid P. Eide | Yellow | ingride@broadpark.com + external | Ingrid P. Eide | Ingrid | ingride@broadpark.no + external | Ingrid Rædergård | IngridRædergård | i_redergard@hotmail.com + external | Ingrid Rædergård | ingrijr | ingrijr@student.uio.no + external | Ingvild Holann | Leeloo | icholann@start.no + external | Irene Hellem | nene26 | nene26@gmail.com + external | Isaac R. Gloinson | caasi | caasi_gloinson@hotmail.com + external | Isaac Ryen Gloinson | Isaac0103 | caasi_gloinson@hotmail.com + external | Ivar Kvaal | zebh | ivar@bmx.no + external | Jacqueline von Arb | Jacko | jacqueline.vonarb@his.no + external | Jan Kåre "Sander" Østmark | OleMaster | OleMurder@Yahoo.Com + external | Janne M. G. Skarstein | Miaja | miaja11@gmail.com + external | jan revil | janr16 | jan-revi@online.no + external | Jo Eskil Røset | RamForth | joe@ramforth.net + external | jofrid sørvoll | jofridso | jofrids@hotmail.com + external | Johannes Grødem | johs | johs@copyleft.no + external | Johannes Grødem | Ehud | johs@copyleft.no + external | johannes zelalem vollan | falken | johannes.vollan@ostensjo.gs.oslo.no + external | jonas | jonask0611 | jonas.nilsen@ostensjo.gs.oslo.no + external | Jørn Helge B. Dahl | evergud | evergud@gmail.com + external | julie | julle | julie.martinussen@skoyen.gs.oslo.no + external | June Maria | JMTiger | junemaria@hotmail.com + external | kåre Krogstad | krokko | krokkostudie@hotmail.com + external | Karen | lollo | lollofte@hotmail.com + external | Kari | karig | kari@groruddalen.info + external | Karoline Bjørnstad | karoline | steinerkarro@msn.com + external | Karoline Bjørnstad | tári | steinerkarro@msn.com + external | Karoline Bjørnstad | Steinerkarro | steinerkarro@msn.com + external | katherine | kathy | kjoakimsen@hotmail.com + external | Katja Fuglaas | KikkÆ | katja@no-play.net + external | Kim Alexander Krohn Berle | fullbartender | full-bartender@hotmail.com + external | kim elise ervik | kimma | kimma_ervik@hotmail.com + external | kim hamang raphaug | uglek | uglek@hotmail.com + external | Kim Lopez | Lopez | kimlopez@gmail.com + external | Kjetil Molnes | Kjetil68 | k_moll@chello.no + external | Knut Erik Tornaas | knut erik | ganadeva@hotmail.com + external | Knut Oterholm | Oter | knuto@deich.folkebibl.no + external | Knut Winje | Casa | kriwinje@online.no + external | Kolofon AS | kolofon | trine@kolofon.com + external | Kristina | Kazlaite | kristal@savb.lt + external | Kristina | Kristina | kjistiina@yahoo.no + external | Kristina Kazlaite | karoliuk | kristal@savb.lt + external | Kristine | Kristine | kab@abm-utvikling.no + external | Kristine Pedersen Titternes Horsberg | little Devil | kristine.Horsberg@ostensjo. + external | Kristine Pedersen Titternes Horsberg | Devil | Kristine.Horsberg@ostensjo.gs.oslo.no + external | Kristin Øye Gjersdal | Kristin | kr_i_s_t_in@hotmail.com + external | Kvam folkebibliotek | Norheimsund | bibliotek@kvam.kommune.no + external | Laila | Laila | ha-chri@online.no + external | Lars Erik Brennvall | lars | brennvall@flashklubben.com + external | Lars Erik Brennvall | brennvall | l_e_brennvall@hotmail.com + external | Lars Erik KLEMSDAL | renzo.monte | larsek2@yahoo.com + external | Lars Kristian Mathisen | larskr90 | lkm@xbit.no + external | lars kvam kristoffersen | larskr3 | larskr3@online.no + external | Lars Øyvind Christiansen | Juliuz | larsoc@online.no + external | Lars Petter | laser | larspm35@hotmail.com + external | Lars Tiller | Larsi | larsifaen@hotmail.com + external | Lars Tiller | zefish | larsifaen@hotmail.com + external | leif | leifean | leifriksheim@hotmail.com + external | Leif Sæther | leifsae | leifsae@online.no + external | Leif Storvik | Leif | lestorvi@online.no + external | Lene Fallan | Lene140290 | lene_4_u@hotmail.com + external | Lene Jahnsen | Lusia | ljahnsen@yahoo.com + external | Leo Pierini | Leo Pierini, CUF | leo.pierini@centerpartiet.se + external | Linda Rosita Rystad | thelema | thelemaxmagick@yahoo.no + external | Linh-Chi | Ma-meido Purinsesu | virgocream@hotmail.com + external | Linh-Chi | ChiChi | virgocream@hotmail.com + external | Linh-Chi | Ma-meido Chi | virgocream@hotmail.com + external | Lisa Kvalbein | lisa0ed | miss_93_10@hotmail.com + external | Lisa Tøndel Medbøen | lisa86 | lisa_kicks86@hotmail.com + external | Lise Selvåg | Lise | efremova_666@hotmail.com + external | Liv | pjuskepels | pjuskepels@hotmail.com + external | Liv Olsen | kerman | livo@deich.folkebibl.no + external | Liv Randi Andreassen | Life | livr_a@hotmail.com + external | Liv S | Liv | pjuskepels@hotmail.com + external | louise sølvi | thelove | hellu_kompis@hotmail.com + external | Lovise Andreassen | Lou94 | lovisea@start.no + external | Maggie Tu | azian_babe | puzen_din_18@hotmail.com + external | Magnus Viktil | Sofamonsteret | sofamonsteret@hotmail.com + external | Maja H. Kvendseth | Gru | grumejl@hotmail.com + external | Malin | rockagirl91 | angel_1727_@hotmail.com + external | Malin | Rockagirl | angel_1727_@hotmail.com + external | margaret bøe | margarbo | margaret_boe@hotmail.com + external | margaret bøe | margaret | margaret_boe@hotmail.com + external | marianne | marma2006 | marte_fotball@hotmail.com + external | Marianne | Marri92 | hanped@online.no + external | Marianne | Marma | lenesolbakken@hotmail.com + external | Mari Anne | maddi | maddimor@hotmail.com + external | Maria Smith | masmno | marielis@online.no + external | Marie | Mariemor | marri22_4@hotmail.com + external | Marie Olsen | Marie | marsve@skolepost.no + external | Mari Forseth | Mari F. F. | mari.forseth@gmail.com + external | Marit Sivertsvold | Masiver | masiver@hotmail.com + external | Marlene Ullerlien | Mustis | Mustiz3@hotmail.com + external | Marte Grevsgard | Marte | gmarte@postmaster.co.uk + external | Martha | anonym | martha_lynne@hotmail.com + external | marthe westjordet | yatzy | yatzyja@gmail.com + external | martin | marty | martin_fotballgutt@hotmail.com + external | martin | tubgirl1101 | martingrahamtobiassen@hotmail.com + external | Martin | Martind | martin.donnum@ostensjo.gs.oslo.no + external | Martin Berg | martiin | martinerfin@gmail.com + external | martin.dønnum | martin.dønnum | martin.donnum@ostensjo.gs.oslo.no + external | martine stordal | martine | princes_stordal@hotmail.com + external | Martin Hansen | PsyQz | martin_hansen89@hotmail.com + external | martin solholm | mediasmilie | mediasmilie@hotmail.com + external | Martin Sundin | fonkymorbror | jazzwithmartin@yahoo.com + external | Mate Toth | thmate | thmate@freemail.hu + external | mathias | Blikk1 | mathiasparken111@hotmail.com + external | Mathias H. Wilhelmsen | MHW | mathia0804@hotmail.com + external | Mattias Appelgren | Mattebong | matap78@hotmail.com + external | May Linda Martinsen | Soppen | maylinda.martinsen@gmail.com + external | May Linda Martinsen | Soppen2 | maylinda.martinsen@gmail.com + external | Michael Pangopoulos | mostblind | spinmove@hotmail.com + external | Mildrid test | venla | mildrid.liasjo@trondheim.kommune.no + external | Mildrid test | mili | mildrid.liasjo@trondheim.kommune.no + external | Mona Mogadam | Mona Mogadam | monapus@hotmail.com + external | Morten Kielland | mokiel | morten.kielland@skjaak.kommune.no + external | Morten Kielland | morten | morten.kielland@start.no + external | nico | nicho | nicholas.solheim@skoyen.gs.oslo.no + external | Niklas Sebastian Grenvik | Niklas | nikgren@hotmail.com + external | Norunn Heger | Ava | no_he@hotmail.com + external | Øivind Andresen | oivind | oivind@bradager.net + external | Ola | olawold | ola.wold@stfk.no + external | Olav Celius | ovl | olavc@deichman.no + external | Ole Martin Eidesmo | omeid87 | dark_the_guru@hotmail.com + external | Ole-Martin Erikstad | olemartin | ole@erikstad.info + external | Ole-Martin Erikstad | oleeriks | ole@erikstad.net + external | Ole-Petter | DotCom | dotcom@online.no + external | Ole Tjensvold Johannessen | oletjens | ole.tjensvold.johannessen@gmail.com + external | Øystein Nilsen | ANgel | zibiam@hotmail.com + external | øyvind | oyvoyv! | oyvind.vennerod@skoyen.gs.oslo.no + external | Øyvind K. Lillebergen | TraXter | webmaster@lillebergen.net + external | Oyvinds | Oyvinds_post | oki1991@operamail.com + external | peder | pbd | pbd01@hotmail.com + external | peder andreas hanstad | halla 6000 | peder.hanstad@skoyen.gs.no + external | per-eianr | arta | www.rikman@hotmail.com + external | Per Espeland | perez | per@espeland.as + external | perniss | pernil | pernille.martinussen@skoyen.gs.oslo.no + external | peterdass | peterdass | peterdass@overlie.no + external | Petter | Nixtar | pettknu@online.no + external | Petter | ørnen | petter.skanke@ostensjo.gs.oslo.no + external | Philip C Scheel | KiNexus | kinexus@start.no + external | Phuc Ngoc Huynh | phuc | phuc77@gmail.com + external | Piggy piglet | piglet | piggywiggypiglet@overlie.no + external | piggy wiggy piglet | piggywiggypiglet | piggywiggypiglet@overlie.no + external | Praman | Praman | inkaur@online.no + external | Pramandeep | Pramandeep | pramandeep.dhami@ostensjo.gs.oslo.no + external | rabarbrah | rabarbrah | rabarbrah@gmail.com + external | Ragnhild Torstensen | Hobbes | torstensen88@gmail.com + external | Rakel Oliva Ødegaard Skaugen | relle_celle | rakel.skaugen@ostensjo.gs.oslo.no + external | Raymond Pedersen | raypedersen | rp28052004@yahoo.no + external | reidar hesseberg | rolav | rohesse@c2i.net + external | Rim G | PoetiCurlz | eritreanpride@hotmail.com + external | Rine K. Brofoss | Kalle | rine_k@hotmail.com + external | roar håland | roar | roahaal@online.no + external | Roy Nilsen | Videoroy | roy.nilsen@brundalen.vgs.no + external | Ruth Schukalla | Dunja1001 | ruth.schukalla@ntfk.no + external | Salar | Salar | salar_ilami@hotmail.com + external | samira naureen | samira1804 | sapna_2003@hotmail.com + external | sara karoline | tassepusen | tassetoff@hotmail.com + external | Seema Ghani | SG | eiriknesheim@hotmail.com + external | Selma | Selma | selma_zt@hotmail.com + external | Siemen | Eurobeat | siemen.halvorsen@gmail.com + external | Siri | sirita | sirit@deichman.no + external | Siril | siril | sirilwm@ringvemedia.com + external | siri-turid | siri-turid | trygve_93@hotmail.com + external | siri- turid | siri- turid0404 | siri-turid@hotmail.com + external | Solveig Skjelnes | edrun | solveig.skjelnes@dragskole.no + external | Sonja Hepsø | sonja7 | todsonja@hotmail.com + external | stein | stein | stein@orgdot.com + external | Steinar Eilertsen | Ferdinand | steinar@sedesign.no + external | Steinar Utstrand | stonescar | stonescar@gmail.com + external | Stig-Terje Amundsen | stigi | stigterje_amundsen@hotmail.com + external | Stine Aulie | pooka | stine_bittersweet@hotmail.com + external | Stine Aulie | Papiret | stine_bittersweet@hotmail.com + external | Stine Hansen | Stine | stineb-h18@hotmail.com + external | stine indergård | stinei | stineinder@hotmail.com + external | Stine Sjåstad | 72 | stinesjaastad@hotmail.com + external | Sunniva | Sun9 | sunnivaw@online.no + external | Susanne | sussilove | susneshal@hotmail.com + external | Susanne | Sussilove | susneshal@hotmail.com + external | Svein Aaasn | Svennis | svein.aasan@t-fk.no + external | Svein Hovland | holden | svein.hh@hotmail.com + external | Svein Thaulow | Svein | sv-tha@online.no + external | Synnøve Storjord | synnmarg | synnmarg@online.no + external | Taiba | tebbern | pinki_b93@hotmail.com + external | Tarjei Abelsen | Teejay | fettakuken@gmail.com + external | Terje Lien | terjelien | terje.lien@skullerud.gs.oslo.no + external | Terje Skare | Teska | terje_skare@hotmail.com + external | Test510 | test510 | supahleo@gmail.com + external | testbruker | testbruker | annelena@deichman.no + external | Tester testesen | testvesenet | ingunn@tfb.no + external | teste teste | testpost2 | torhenrik@copyleft.no + external | test test | testpost3 | torhenrik@copyleft.no + external | Test Testesen | testpost | thh@copyleft.no + external | thepigster | thepigster | thepigster@overlie.no + external | thomas | honning | almtre@hotmail.com + external | Thomas | Honning05 | almtre@hotmail.com + external | Thomas Heger | theger | tbheger@student.hf.uio.no + external | Toralf | Toralf | Toralf@hotmail.com + external | Tor Arne Wølner | torarnew | tor.a.wolner@hive.no + external | torbjørn | torbman | doctormacabre@hotmail.com + external | Torbjørn Kvam | AmoS | tkvam@broadpark.no + external | Tor-Erik Lindstrøm | AlmostKungFu | gulrotx@hotmail.com + external | Torgeir Berstad | tberstad | torgeir.berstad@t-fk.no + external | Tor Henrik Hanken | torhenrik | torhenrik@copyleft.no + external | Torjus h. s. | notorjus | toorjus@gmail.com + external | Tormod h. tønsberg | Warside | Tormodgrand@hotmail.com + external | tove | mooglepooh | taagaa@online.no + external | Tove | moogle | taagaa@online.no + external | Trein | TREI | anne.oterholm@chello.no + external | Trine Johnsen | tiny | trine1.johnsen@trondheim.kommune.no + external | Trine Westberg | trinew | trinew@deichman.no + external | trojus | toorjus | toorjus@start.no + external | Trond Wiger | Oscar Øglænd | buustamon@yahoo.no + external | TT | Celsius_no | celsius_no@hotmail.com + external | Vebjørn Søndersrød | vebjorn | vebjorn.sondersrod@nb.no + external | Venke Uglenes | venkeu | venkeu@deichman.no + external | Victor Dagar Ellingsen | Mr.undead | vic_dagar@hotmail.com + external | Vilde Årvold Crowo | Ville | Vilde.Crowo@ostensjo.gs.oslo.no + external | vilde monclair | anayokari | vilde_brannfarlig@hotmail.com + external | vilde monclair | Ayanokoji | vilde_brannfarlig@hotmail.com + external | vilje celin | honeybunch | vilje_celin@hotmail.com + external | wan yuan | wan | yuanwan2179@yahoo.com + external | yngve grotmol | yngveg | y-grotmo@online.no + external | Yoda | yoda | yoda150690@hotmail.com + external | yousef khalid amin | nikeboy | nikeboy100@hotmail.com + external | Yvonne Vornes | YV | yvonnevornes@hotmail.com + external | Zahraa | Zahraa Bani Saad Asaad | zahraa.bani-saad@ostensjo.gs.oslo.no +(417 rows) + + + + BRUKERE VI SKAL BEHOLDE UTEN AKSEPTERTE VERK + ================================================ + +(SELECT type, name, nick, email + FROM reaktoruser ru + WHERE CASE type + WHEN 'administrator' THEN + false + WHEN 'editor' THEN + name NOT IN ('Asgeir Bjørlykke', 'Copyleft Software AS', 'Ole-Petter Wikene', 'Stian Tyriberget', 'Test', 'Test2', 'Testbruker', 'Thomas Bakketun', 'testbruker', 'Anne-Lena Westrum') + AND NOT (name = 'Mildrid Liasjø' AND disabled = true) + WHEN 'external' THEN + (EXISTS (select * from comment where creator = ru.id) + OR EXISTS (select * from rating where reaktoruser = ru.id) + OR EXISTS (select * from artwork where creator = ru.id) + OR EXISTS (select * from changelog where reaktoruser = ru.id AND action = ':LOGIN')) + AND nick NOT IN ('asgeir', 'asgeirr', 'Betty', 'Boltorn', 'erdether', 'groa', 'Hufsa', 'Kerman', 'kolofon', 'leo', 'Oter', 'Silva', 'Spøkelseskladden', 'testpost', 'testvesenet', 'theger', 'torbman', 'trinew', 'varja240', 'venkeu', 'zebh') + END) +INTERSECT +(SELECT ru.type, ru.name, ru.nick, ru.email + FROM reaktoruser ru + LEFT OUTER JOIN + (SELECT DISTINCT creator + FROM artwork + WHERE id NOT IN (SELECT object + FROM changelog c1 + INNER JOIN + artwork a + ON c1.object = a.id + INNER JOIN reaktoruser u + ON u.id = a.creator + WHERE object_type = 'artwork' AND action = ':DENY' + AND timestamp > ALL (SELECT timestamp + FROM changelog c2 + WHERE c2.object = c1.object AND c2.action = ':ACCEPT'))) a + ON ru.id = a.creator + WHERE a.creator IS NULL) +ORDER BY type, name; + type | name | nick | email +----------+---------------------------------+---------------------+-------------------------------------------- + editor | Anne Lena Westrum | | annelena@deichman.no + editor | Ann Kunish | | annk@deichman.no + editor | Asgeir Rekkavik | | asgeirr@deichman.no + editor | Berit Petersheim | | beritpe@deichman.no + editor | Bjørn Tore Nyland | | BJORN.TORE.NYLAND@trondheim.kommune.no + editor | Cecilie Bergh | | cecilieb@deichman.no + editor | Einar Silset Berg | | einarsb@deichman.no + editor | Gro Johansen Raih | | groj@deichman.no + editor | Henriette Frisenberg Sundgaard | | henriets@deichman.no + editor | Ingunn Evensen | | ingunn@trondheim.folkebibl.no + editor | Knut Oterholm | | knuto@deichman.no + editor | Korana Kurtovic | | koranak@deichman.no + editor | Mildrid Liasjø | | mildrid@tfb.no + editor | Mona Knarvik | | mona@tfb.no + editor | Sigrid Bremseth | | SIGRID.BREMSETH@trondheim.kommune.no + editor | Stine Iren Ballovarre | | STINE-IREN.BALLOVARRE@trondheim.kommune.no + editor | Thor Arne Sæterholen | | thor@deichman.no + editor | Trine Johnsen | | TRINE1.JOHNSEN@trondheim.kommune.no + external | Aadne Ores | Sir-Aadne | aadne.ore@skoyen.gs.oslo.no + external | Adrian Busk Strømsmoen | Addinski | addinski14@hotmail.com + external | alaleh | alaleh | alalehnavaii@yahoo.com + external | Anders Grimsrud | andersgrim | andersgrim@gmail.com + external | andreas | A.c | andreascheng@dbz4k.zzn.com + external | Andreas Olsen | andreas | andreas24-7@hotmail.com + external | Andreas S. Frølich | vonfrolich@yahoo.no | vonfrolich@yahoo.no + external | Ane Stenberg | Chainy | Ane_Stenberg@hotmail.com + external | Anne | annymal | annymal@hotmail.com + external | Anne-Line Henriksen | Anna | lishenri@online.no + external | Annemarie Barker | annemarie | ab_29_10@hotmail.com + external | Ann Kunish | annk | annk@deichman.no + external | Arne-Daniel Storevold Haldorsen | Arne-Daniel | arnedaniel.sh@gmail.com + external | Arne Otto Sandmo | arni | arneotto.sandmo@gmail.com + external | Arne Skalleberg | arsk | arneska@vfk.no + external | Åshild Plener | lance | gress_m@hotmail.com + external | Åsmund Sem-Johansen | Asemjo | asemjo@start.no + external | Beate Børli Løkken | bea | bea_bolla@hotmail.com + external | bettina | Ape | bettina.gudim@ostensjo.gs.oslo.no + external | Bjørnar | molukk | bjornar@nettmail.no + external | Bjørn Thevik | Bjørn Thevik | bjorn@thevik.com + external | Bjørn Tore Nyland | bny | bjorn.tore.nyland@trondheim.kommune.no + external | Børge Fallmyr Sund | faramir | borgesu2001@yahoo.no + external | Brit Helen Bernsen | ShortyPunk | shorty_punk@hotmail.com + external | Carina Borgund | bavian | carina.borgund@ostensjo.gs.oslo.no + external | Cathrine Alvin | E6-Cathrine | cathrine@flashklubben.com + external | Cathrine Syverstad | catsyv | catsyv@hotmail.com + external | Cecilie Bergh | CillyBilly | cecilieb@deichman.no + external | Cheryl Lynn Rubin | Suki | cl-rubin@frisurf.no + external | Christian Halvorsen | chaL | chal_89@hotmail.com + external | Cliff Kjenna | Dagern | cliff@epost.no + external | Cutter filmkompani | Citrus film | erik@tobiassen.no + external | Cynthia | Cynthia | cynthia.muller@ostensjo.gs.oslo.no + external | Dag Stian Baltzersen | Daggers | dagstianb@hotmail.com + external | Damien Smith | damienjsmith | damienjsmith@hotmail.com + external | Daniel Carlsen | Captain_Evil | oecar@online.no + external | Daniel Harila Carlsen | Manganerd | oecar@online.no + external | Daniel Korsmoe | Phunk_Phr33k | poebelsmurfen@gmail.com + external | David Barratt-Due | SirDavid01 | didie0932@hotmail.com + external | Egil Arnold Vigrestad | E.A.Vigrestad | arnvigre@online.no + external | Eirin Koehler Breivik | Kanel | eirin@kanel.no + external | Eivind Brokke | Ivan | eibrokke@broadpark.no + external | Elisabeth Heradstveit | elishera | elishahera@hotmail.com + external | Emilie Kolstø Strømøy | Emilie | miss.stromoy@gmail.com + external | Emin | emi | emin_duraku@hotmail.com + external | Erlend Huseby | Zaran | zaran_89@hotmail.com + external | Fabian | Capt skeid! | fabian.gleditsch@skoyen.gs.oslo.no + external | Fed Håvar Svartdal | ShadowHunter | fhs_spawn@hotmail.com + external | Ferenc Seres | Ferenc | f.seres@chello.no + external | Frank Iversen | Frank | frank1iversen@gmail.com + external | Frede Herstad | RabbitFly | therabbitfly@hotmail.com + external | Gaute | Gaute | gauteg@hotmail.com + external | Geir Sundelius | geirok | geir.sundelius@chello.no + external | Gøran Frost | pterodactyl | goran__frost@hotmail.com + external | grafstad | grafstad | grethe@kardemommeby.com + external | grethe elvenes | PEZ | grethe@elvenes.org + external | Gro Emblemsvåg | gembla | gembla@gmail.com + external | Gunhild | Gunhild | ordmix@online.no + external | Gunnar Dypdahl | Sverre | gunnar@deichman.no + external | Håkon | hakon2612 | Hakon.mikaelsen@ostensjo.gs.oslo.no + external | Håkon Øvreås | Sausenebb | pausemaker@hotmail.com + external | Halvard Hovtun | HAIr | hair@trainsim.no + external | Harald Aune Skorpen | harald | harald@skorpen.net + external | Hedda Hakvåg | amanda | hedda_hak@hotmail.com + external | Heidi Ravnås | diablesa | diablesa25@hotmail.com + external | Heine Jensvold | kvikks | heine@gulo.no + external | Henko Waratenko | Henko Waratenko | henko_w@hotmail.com + external | Hilde Aleksandersen | glorybox | hildealeksandersen@hotmail.com + external | hilde pettersen | hilde | hilde.pettersen@lillestrom.vgs.no + external | Ida Helgesen | Princess Zelda | Ida.helgesen@ostensjo.gs.oslo.no + external | inger | inger | ilbergli@online.no + external | Ingrid Eide | mango | ingrid.eide@ostensjo.gs.oslo.no + external | Ingrid Engh Johansen | Casiopeja | ingrid_smiling@hotmail.com + external | Ingvild Holann | Leeloo | icholann@start.no + external | Irene Hellem | nene26 | nene26@gmail.com + external | Isaac R. Gloinson | caasi | caasi_gloinson@hotmail.com + external | jan revil | janr16 | jan-revi@online.no + external | Jo Eskil Røset | RamForth | joe@ramforth.net + external | jofrid sørvoll | jofridso | jofrids@hotmail.com + external | Johannes Grødem | Ehud | johs@copyleft.no + external | johannes zelalem vollan | falken | johannes.vollan@ostensjo.gs.oslo.no + external | jonas | jonask0611 | jonas.nilsen@ostensjo.gs.oslo.no + external | Jørn Helge B. Dahl | evergud | evergud@gmail.com + external | julie | julle | julie.martinussen@skoyen.gs.oslo.no + external | June Maria | JMTiger | junemaria@hotmail.com + external | Kari | karig | kari@groruddalen.info + external | katherine | kathy | kjoakimsen@hotmail.com + external | Katja Fuglaas | KikkÆ | katja@no-play.net + external | Kim Alexander Krohn Berle | fullbartender | full-bartender@hotmail.com + external | kim hamang raphaug | uglek | uglek@hotmail.com + external | Kim Lopez | Lopez | kimlopez@gmail.com + external | Kjetil Molnes | Kjetil68 | k_moll@chello.no + external | Knut Erik Tornaas | knut erik | ganadeva@hotmail.com + external | Kristina Kazlaite | karoliuk | kristal@savb.lt + external | Kristin Øye Gjersdal | Kristin | kr_i_s_t_in@hotmail.com + external | Laila | Laila | ha-chri@online.no + external | Lars Erik Brennvall | brennvall | l_e_brennvall@hotmail.com + external | Lars Erik KLEMSDAL | renzo.monte | larsek2@yahoo.com + external | lars kvam kristoffersen | larskr3 | larskr3@online.no + external | Lars Øyvind Christiansen | Juliuz | larsoc@online.no + external | Lars Petter | laser | larspm35@hotmail.com + external | Lars Tiller | zefish | larsifaen@hotmail.com + external | leif | leifean | leifriksheim@hotmail.com + external | Leif Sæther | leifsae | leifsae@online.no + external | Lene Fallan | Lene140290 | lene_4_u@hotmail.com + external | Leo Pierini | Leo Pierini, CUF | leo.pierini@centerpartiet.se + external | Lise Selvåg | Lise | efremova_666@hotmail.com + external | Liv Olsen | kerman | livo@deich.folkebibl.no + external | louise sølvi | thelove | hellu_kompis@hotmail.com + external | Maggie Tu | azian_babe | puzen_din_18@hotmail.com + external | Magnus Viktil | Sofamonsteret | sofamonsteret@hotmail.com + external | Maja H. Kvendseth | Gru | grumejl@hotmail.com + external | Malin | rockagirl91 | angel_1727_@hotmail.com + external | margaret bøe | margarbo | margaret_boe@hotmail.com + external | margaret bøe | margaret | margaret_boe@hotmail.com + external | Marianne | Marri92 | hanped@online.no + external | Mari Anne | maddi | maddimor@hotmail.com + external | Marie | Mariemor | marri22_4@hotmail.com + external | Marie Olsen | Marie | marsve@skolepost.no + external | Marlene Ullerlien | Mustis | Mustiz3@hotmail.com + external | Marte Grevsgard | Marte | gmarte@postmaster.co.uk + external | Martha | anonym | martha_lynne@hotmail.com + external | martin | marty | martin_fotballgutt@hotmail.com + external | martin | tubgirl1101 | martingrahamtobiassen@hotmail.com + external | Martin Berg | martiin | martinerfin@gmail.com + external | Martin Hansen | PsyQz | martin_hansen89@hotmail.com + external | martin solholm | mediasmilie | mediasmilie@hotmail.com + external | Mate Toth | thmate | thmate@freemail.hu + external | Mathias H. Wilhelmsen | MHW | mathia0804@hotmail.com + external | Mattias Appelgren | Mattebong | matap78@hotmail.com + external | Mona Mogadam | Mona Mogadam | monapus@hotmail.com + external | Morten Kielland | mokiel | morten.kielland@skjaak.kommune.no + external | nico | nicho | nicholas.solheim@skoyen.gs.oslo.no + external | Niklas Sebastian Grenvik | Niklas | nikgren@hotmail.com + external | Norunn Heger | Ava | no_he@hotmail.com + external | Øivind Andresen | oivind | oivind@bradager.net + external | Olav Celius | ovl | olavc@deichman.no + external | Ole Martin Eidesmo | omeid87 | dark_the_guru@hotmail.com + external | Ole-Martin Erikstad | olemartin | ole@erikstad.info + external | Øystein Nilsen | ANgel | zibiam@hotmail.com + external | Øyvind K. Lillebergen | TraXter | webmaster@lillebergen.net + external | peder | pbd | pbd01@hotmail.com + external | perniss | pernil | pernille.martinussen@skoyen.gs.oslo.no + external | Petter | Nixtar | pettknu@online.no + external | Philip C Scheel | KiNexus | kinexus@start.no + external | Pramandeep | Pramandeep | pramandeep.dhami@ostensjo.gs.oslo.no + external | Ragnhild Torstensen | Hobbes | torstensen88@gmail.com + external | reidar hesseberg | rolav | rohesse@c2i.net + external | Rim G | PoetiCurlz | eritreanpride@hotmail.com + external | roar håland | roar | roahaal@online.no + external | Ruth Schukalla | Dunja1001 | ruth.schukalla@ntfk.no + external | Salar | Salar | salar_ilami@hotmail.com + external | samira naureen | samira1804 | sapna_2003@hotmail.com + external | sara karoline | tassepusen | tassetoff@hotmail.com + external | Seema Ghani | SG | eiriknesheim@hotmail.com + external | Selma | Selma | selma_zt@hotmail.com + external | Sonja Hepsø | sonja7 | todsonja@hotmail.com + external | Steinar Eilertsen | Ferdinand | steinar@sedesign.no + external | Steinar Utstrand | stonescar | stonescar@gmail.com + external | Stine Hansen | Stine | stineb-h18@hotmail.com + external | stine indergård | stinei | stineinder@hotmail.com + external | Stine Sjåstad | 72 | stinesjaastad@hotmail.com + external | Sunniva | Sun9 | sunnivaw@online.no + external | Svein Hovland | holden | svein.hh@hotmail.com + external | Tarjei Abelsen | Teejay | fettakuken@gmail.com + external | Terje Lien | terjelien | terje.lien@skullerud.gs.oslo.no + external | Torbjørn Kvam | AmoS | tkvam@broadpark.no + external | Tor-Erik Lindstrøm | AlmostKungFu | gulrotx@hotmail.com + external | Torgeir Berstad | tberstad | torgeir.berstad@t-fk.no + external | Tor Henrik Hanken | torhenrik | torhenrik@copyleft.no + external | tove | mooglepooh | taagaa@online.no + external | Trine Johnsen | tiny | trine1.johnsen@trondheim.kommune.no + external | Vebjørn Søndersrød | vebjorn | vebjorn.sondersrod@nb.no + external | Vilde Årvold Crowo | Ville | Vilde.Crowo@ostensjo.gs.oslo.no + external | vilje celin | honeybunch | vilje_celin@hotmail.com + external | wan yuan | wan | yuanwan2179@yahoo.com + external | yngve grotmol | yngveg | y-grotmo@online.no + external | Yoda | yoda | yoda150690@hotmail.com + external | Yvonne Vornes | YV | yvonnevornes@hotmail.com +(197 rows) + + diff --git a/prototype/doc/reaktor-datamodell.pdf b/prototype/doc/reaktor-datamodell.pdf new file mode 100644 index 0000000..6917a90 Binary files /dev/null and b/prototype/doc/reaktor-datamodell.pdf differ diff --git a/prototype/dumps/reaktor-schema-2008-03-03.sql b/prototype/dumps/reaktor-schema-2008-03-03.sql new file mode 100644 index 0000000..1787441 --- /dev/null +++ b/prototype/dumps/reaktor-schema-2008-03-03.sql @@ -0,0 +1,952 @@ +-- +-- PostgreSQL database dump +-- + +SET client_encoding = 'LATIN1'; +SET check_function_bodies = false; + +SET SESSION AUTHORIZATION 'postgres'; + +-- +-- TOC entry 4 (OID 2200) +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +SET SESSION AUTHORIZATION 'asgeir'; + +SET search_path = public, pg_catalog; + +-- +-- TOC entry 5 (OID 18717) +-- Name: id_seq; Type: SEQUENCE; Schema: public; Owner: asgeir +-- + +CREATE SEQUENCE id_seq + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- TOC entry 6 (OID 18719) +-- Name: site; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE site ( + id integer NOT NULL, + title text, + description text, + rights text, + email text +); + + +-- +-- TOC entry 7 (OID 18726) +-- Name: reaktoruser; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE reaktoruser ( + id integer NOT NULL, + "type" text, + name text, + email text, + "password" text, + disabled boolean, + salt text, + nick text, + public_name boolean, + public_email boolean, + description text, + sex character(1), + year_of_birth integer, + in_mailinglist boolean, + image text, + place_of_residence text, + telephone text, + site integer, + email_confirmed boolean, + artwork_groups text, + CONSTRAINT reaktoruser_sex CHECK (((sex = 'm'::bpchar) OR (sex = 'f'::bpchar))), + CONSTRAINT reaktoruser_type CHECK (((("type" = 'external'::text) OR ("type" = 'editor'::text)) OR ("type" = 'administrator'::text))) +); + + +-- +-- TOC entry 8 (OID 18739) +-- Name: artwork; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE artwork ( + id integer NOT NULL, + "type" text, + data text, + screenshot text, + creator integer, + title text, + description text, + keywords text, + howto text, + help text, + rights text, + editor integer, + width integer, + height integer, + site integer, + publish_state text, + under_discussion boolean, + internal_discussion text, + CONSTRAINT "$3" CHECK (((((rights = ':free'::text) OR (rights = ':educational'::text)) OR (rights = ':contactme'::text)) OR (rights = ':none'::text))), + CONSTRAINT artwork_publish_state CHECK (((((publish_state = ':queued'::text) OR (publish_state = ':denied'::text)) OR (publish_state = ':accepted'::text)) OR (publish_state = ':disabled'::text))), + CONSTRAINT artwork_type CHECK (((((((((((("type" = 'image'::text) OR ("type" = 'video'::text)) OR ("type" = 'flash'::text)) OR ("type" = 'pdf'::text)) OR ("type" = 'text'::text)) OR ("type" = 'verbatim text'::text)) OR ("type" = 'sound'::text)) OR ("type" = 'shockwave'::text)) OR ("type" = 'href'::text)) OR ("type" = 'images'::text)) OR ("type" = 'files'::text))) +); + + +-- +-- TOC entry 9 (OID 18757) +-- Name: article; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE article ( + id integer NOT NULL, + "type" text, + title text, + image text, + ingress text, + body text, + published boolean, + deleted boolean DEFAULT false, + rank integer, + artwork integer, + CONSTRAINT article_type CHECK (((((((("type" = 'standard'::text) OR ("type" = 'mypage'::text)) OR ("type" = 'topic'::text)) OR ("type" = 'pick'::text)) OR ("type" = 'help'::text)) OR ("type" = 'about'::text)) OR ("type" = 'internal'::text))) +); + + +-- +-- TOC entry 10 (OID 18770) +-- Name: topic; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE topic ( + id integer NOT NULL, + parent integer, + title text, + description text, + independent_title text +); + + +-- +-- TOC entry 11 (OID 18781) +-- Name: artwork_formats; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE artwork_formats ( + artwork integer NOT NULL, + topic integer NOT NULL +); + + +-- +-- TOC entry 12 (OID 18793) +-- Name: artwork_topics; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE artwork_topics ( + artwork integer NOT NULL, + topic integer NOT NULL +); + + +-- +-- TOC entry 13 (OID 18805) +-- Name: article_formats; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE article_formats ( + article integer NOT NULL, + topic integer NOT NULL +); + + +-- +-- TOC entry 14 (OID 18817) +-- Name: article_topics; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE article_topics ( + article integer NOT NULL, + topic integer NOT NULL +); + + +-- +-- TOC entry 15 (OID 18829) +-- Name: artwork_help_articles; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE artwork_help_articles ( + article integer NOT NULL, + artwork integer NOT NULL +); + + +-- +-- TOC entry 16 (OID 18841) +-- Name: comment; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE "comment" ( + id integer DEFAULT nextval('id_seq'::text) NOT NULL, + parent integer, + creator integer, + artwork integer, + hidden boolean DEFAULT false, + subject text, + body text +); + + +-- +-- TOC entry 17 (OID 18862) +-- Name: changelog; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE changelog ( + id integer DEFAULT nextval('id_seq'::text) NOT NULL, + "timestamp" timestamp without time zone DEFAULT ('now'::text)::timestamp(6) with time zone, + reaktoruser integer, + object integer, + object_type text, + "action" text, + description text, + ip text, + browser text, + CONSTRAINT changelog_action CHECK (((((((("action" = ':CREATE'::text) OR ("action" = ':EDIT'::text)) OR ("action" = ':DELETE'::text)) OR ("action" = ':PUBISH'::text)) OR ("action" = ':DENY'::text)) OR ("action" = ':ACCEPT'::text)) OR ("action" = ':LOGIN'::text))), + CONSTRAINT changelog_object_type CHECK (((((((object_type = 'artwork'::text) OR (object_type = 'article'::text)) OR (object_type = 'reaktoruser'::text)) OR (object_type = 'topic'::text)) OR (object_type = 'comment'::text)) OR (object_type = 'comment_complaint'::text))) +); + + +-- +-- TOC entry 18 (OID 18877) +-- Name: rating; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE rating ( + reaktoruser integer NOT NULL, + artwork integer NOT NULL, + rating integer +); + + +-- +-- TOC entry 19 (OID 18889) +-- Name: comment_complaint; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE comment_complaint ( + id integer DEFAULT nextval('id_seq'::text) NOT NULL, + state text DEFAULT ':queued'::text, + "comment" integer, + creator integer, + description text, + CONSTRAINT comment_complaint_state CHECK ((((state = ':queued'::text) OR (state = ':denied'::text)) OR (state = ':accepted'::text))) +); + + +-- +-- TOC entry 20 (OID 18907) +-- Name: reaktor; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE reaktor ( + id integer DEFAULT nextval('id_seq'::text) NOT NULL, + frontpage_articles_top integer, + frontpage_articles_left integer, + frontpage_articles_right integer, + frontpage_help_top integer, + frontpage_help_left integer, + frontpage_help_right integer, + frontpage_topic integer, + editor_pick integer, + frontpage_articles_top2 integer, + mypage_articles_top integer, + mypage_articles_top2 integer, + frontpage_help_1 integer, + frontpage_help_2 integer, + frontpage_help_3 integer, + frontpage_help_4 integer, + frontpage_help_5 integer, + frontpage_help_6 integer +); + + +-- +-- TOC entry 21 (OID 18944) +-- Name: topic_shortlist; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE topic_shortlist ( + reaktor integer, + topic integer NOT NULL, + rank integer +); + + +-- +-- TOC entry 22 (OID 29978) +-- Name: persmem; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE persmem ( + "key" text NOT NULL, + value text +); + + +-- +-- TOC entry 23 (OID 29985) +-- Name: persdict; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE persdict ( + "key" text NOT NULL, + value text +); + + +-- +-- TOC entry 24 (OID 36348) +-- Name: total_artworks; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW total_artworks AS + SELECT count(*) AS count FROM artwork WHERE (artwork.publish_state = ':accepted'::text); + + +-- +-- TOC entry 25 (OID 36354) +-- Name: denied_works; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW denied_works AS + SELECT count(*) AS count FROM artwork WHERE (artwork.publish_state = ':denied'::text); + + +-- +-- TOC entry 26 (OID 36357) +-- Name: queued_works; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW queued_works AS + SELECT count(*) AS count FROM artwork WHERE (artwork.publish_state = ':queued'::text); + + +-- +-- TOC entry 27 (OID 36360) +-- Name: total_users; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW total_users AS + SELECT count(*) AS count FROM reaktoruser WHERE (reaktoruser."type" = 'external'::text); + + +-- +-- TOC entry 28 (OID 36363) +-- Name: new_users; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW new_users AS + SELECT u.id, u.name, u.nick FROM changelog c, reaktoruser u WHERE ((((c.object_type = 'reaktoruser'::text) AND (c."action" = ':CREATE'::text)) AND (c."timestamp" > ('2005-01-05 14:34:15.665607'::timestamp without time zone - '1 mon'::interval))) AND (c.object = u.id)); + + +-- +-- TOC entry 29 (OID 36366) +-- Name: top20_users; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW top20_users AS + SELECT max(u.id) AS id, max(u.name) AS name, max(u.nick) AS artworks, count(a.id) AS count FROM artwork a, changelog c, reaktoruser u WHERE (((((c.object_type = 'artwork'::text) AND (c."action" = ':CREATE'::text)) AND (c."timestamp" > ('2005-01-05 14:34:15.669707'::timestamp without time zone - '3 mons'::interval))) AND (a.id = c.object)) AND (a.creator = u.id)) GROUP BY u.id ORDER BY count(a.id) DESC LIMIT 20; + + +-- +-- TOC entry 30 (OID 38997) +-- Name: user_help; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE user_help ( + create_time timestamp without time zone, + creator integer, + url text +); + + +-- +-- TOC entry 31 (OID 46340) +-- Name: artwork_by_day; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW artwork_by_day AS + SELECT date_trunc('day'::text, changelog."timestamp") AS date_trunc, count(artwork.id) AS count FROM artwork, changelog WHERE (((artwork.publish_state = ':accepted'::text) AND (changelog.object = artwork.id)) AND (changelog."action" = ':CREATE'::text)) GROUP BY date_trunc('day'::text, changelog."timestamp") ORDER BY date_trunc('day'::text, changelog."timestamp"); + + +SET SESSION AUTHORIZATION 'reaktortest'; + +-- +-- TOC entry 32 (OID 47342) +-- Name: new_works; Type: VIEW; Schema: public; Owner: reaktortest +-- + +CREATE VIEW new_works AS + SELECT count(*) AS count FROM changelog WHERE (((changelog.object_type = 'artwork'::text) AND (changelog."action" = ':CREATE'::text)) AND (changelog."timestamp" > ('2005-05-26 17:03:08.021782'::timestamp without time zone - '1 mon'::interval))); + + +SET SESSION AUTHORIZATION 'asgeir'; + +-- +-- TOC entry 33 (OID 18724) +-- Name: site_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY site + ADD CONSTRAINT site_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 34 (OID 18733) +-- Name: reaktoruser_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktoruser + ADD CONSTRAINT reaktoruser_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 35 (OID 18747) +-- Name: artwork_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork + ADD CONSTRAINT artwork_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 36 (OID 18764) +-- Name: article_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article + ADD CONSTRAINT article_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 37 (OID 18775) +-- Name: topic_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic + ADD CONSTRAINT topic_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 38 (OID 18783) +-- Name: artwork_formats_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_formats + ADD CONSTRAINT artwork_formats_pkey PRIMARY KEY (artwork, topic); + + +-- +-- TOC entry 39 (OID 18795) +-- Name: artwork_topics_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_topics + ADD CONSTRAINT artwork_topics_pkey PRIMARY KEY (artwork, topic); + + +-- +-- TOC entry 40 (OID 18807) +-- Name: article_formats_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_formats + ADD CONSTRAINT article_formats_pkey PRIMARY KEY (article, topic); + + +-- +-- TOC entry 41 (OID 18819) +-- Name: article_topics_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_topics + ADD CONSTRAINT article_topics_pkey PRIMARY KEY (article, topic); + + +-- +-- TOC entry 42 (OID 18831) +-- Name: artwork_help_articles_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_help_articles + ADD CONSTRAINT artwork_help_articles_pkey PRIMARY KEY (article, artwork); + + +-- +-- TOC entry 43 (OID 18848) +-- Name: comment_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY "comment" + ADD CONSTRAINT comment_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 44 (OID 18871) +-- Name: changelog_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY changelog + ADD CONSTRAINT changelog_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 45 (OID 18879) +-- Name: rating_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY rating + ADD CONSTRAINT rating_pkey PRIMARY KEY (reaktoruser, artwork); + + +-- +-- TOC entry 46 (OID 18897) +-- Name: comment_complaint_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY comment_complaint + ADD CONSTRAINT comment_complaint_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 47 (OID 18910) +-- Name: reaktor_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT reaktor_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 48 (OID 18946) +-- Name: topic_shortlist_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic_shortlist + ADD CONSTRAINT topic_shortlist_pkey PRIMARY KEY (topic); + + +-- +-- TOC entry 49 (OID 29983) +-- Name: persmem_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY persmem + ADD CONSTRAINT persmem_pkey PRIMARY KEY ("key"); + + +-- +-- TOC entry 50 (OID 29990) +-- Name: persdict_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY persdict + ADD CONSTRAINT persdict_pkey PRIMARY KEY ("key"); + + +-- +-- TOC entry 51 (OID 18735) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktoruser + ADD CONSTRAINT "$1" FOREIGN KEY (site) REFERENCES site(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 52 (OID 18749) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork + ADD CONSTRAINT "$1" FOREIGN KEY (creator) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 53 (OID 18753) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork + ADD CONSTRAINT "$2" FOREIGN KEY (editor) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 54 (OID 18766) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article + ADD CONSTRAINT "$1" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 55 (OID 18777) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic + ADD CONSTRAINT "$1" FOREIGN KEY (parent) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 56 (OID 18785) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_formats + ADD CONSTRAINT "$1" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 57 (OID 18789) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_formats + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 58 (OID 18797) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_topics + ADD CONSTRAINT "$1" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 59 (OID 18801) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_topics + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 60 (OID 18809) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_formats + ADD CONSTRAINT "$1" FOREIGN KEY (article) REFERENCES article(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 61 (OID 18813) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_formats + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 62 (OID 18821) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_topics + ADD CONSTRAINT "$1" FOREIGN KEY (article) REFERENCES article(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 63 (OID 18825) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_topics + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 64 (OID 18833) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_help_articles + ADD CONSTRAINT "$1" FOREIGN KEY (article) REFERENCES article(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 65 (OID 18837) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_help_articles + ADD CONSTRAINT "$2" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 66 (OID 18850) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY "comment" + ADD CONSTRAINT "$1" FOREIGN KEY (parent) REFERENCES "comment"(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 67 (OID 18854) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY "comment" + ADD CONSTRAINT "$2" FOREIGN KEY (creator) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 68 (OID 18858) +-- Name: $3; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY "comment" + ADD CONSTRAINT "$3" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 69 (OID 18873) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY changelog + ADD CONSTRAINT "$1" FOREIGN KEY (reaktoruser) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 70 (OID 18881) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY rating + ADD CONSTRAINT "$1" FOREIGN KEY (reaktoruser) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 71 (OID 18885) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY rating + ADD CONSTRAINT "$2" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 72 (OID 18899) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY comment_complaint + ADD CONSTRAINT "$1" FOREIGN KEY ("comment") REFERENCES "comment"(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 73 (OID 18903) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY comment_complaint + ADD CONSTRAINT "$2" FOREIGN KEY (creator) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 74 (OID 18912) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$1" FOREIGN KEY (frontpage_articles_top) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 75 (OID 18916) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$2" FOREIGN KEY (frontpage_articles_left) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 76 (OID 18920) +-- Name: $3; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$3" FOREIGN KEY (frontpage_articles_right) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 77 (OID 18924) +-- Name: $4; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$4" FOREIGN KEY (frontpage_help_top) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 78 (OID 18928) +-- Name: $5; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$5" FOREIGN KEY (frontpage_help_left) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 79 (OID 18932) +-- Name: $6; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$6" FOREIGN KEY (frontpage_help_right) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 80 (OID 18936) +-- Name: $7; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$7" FOREIGN KEY (frontpage_topic) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 81 (OID 18940) +-- Name: $8; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$8" FOREIGN KEY (editor_pick) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 89 (OID 18948) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic_shortlist + ADD CONSTRAINT "$1" FOREIGN KEY (reaktor) REFERENCES reaktor(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 90 (OID 18952) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic_shortlist + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 82 (OID 38969) +-- Name: $88; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$88" FOREIGN KEY (frontpage_articles_top2) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 83 (OID 38973) +-- Name: $9; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$9" FOREIGN KEY (mypage_articles_top) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 84 (OID 38977) +-- Name: $10; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$10" FOREIGN KEY (mypage_articles_top2) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 85 (OID 38981) +-- Name: $12; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$12" FOREIGN KEY (frontpage_help_1) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 86 (OID 38985) +-- Name: $13; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$13" FOREIGN KEY (frontpage_help_4) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 87 (OID 38989) +-- Name: $14; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$14" FOREIGN KEY (frontpage_help_5) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 88 (OID 38993) +-- Name: $15; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$15" FOREIGN KEY (frontpage_help_6) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 91 (OID 39002) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY user_help + ADD CONSTRAINT "$1" FOREIGN KEY (creator) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +SET SESSION AUTHORIZATION 'postgres'; + +-- +-- TOC entry 3 (OID 2200) +-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: postgres +-- + +COMMENT ON SCHEMA public IS 'Standard public namespace'; + + diff --git a/prototype/dumps/reaktor-schema-2008-06-02.sql b/prototype/dumps/reaktor-schema-2008-06-02.sql new file mode 100644 index 0000000..1787441 --- /dev/null +++ b/prototype/dumps/reaktor-schema-2008-06-02.sql @@ -0,0 +1,952 @@ +-- +-- PostgreSQL database dump +-- + +SET client_encoding = 'LATIN1'; +SET check_function_bodies = false; + +SET SESSION AUTHORIZATION 'postgres'; + +-- +-- TOC entry 4 (OID 2200) +-- Name: public; Type: ACL; Schema: -; Owner: postgres +-- + +REVOKE ALL ON SCHEMA public FROM PUBLIC; +REVOKE ALL ON SCHEMA public FROM postgres; +GRANT ALL ON SCHEMA public TO PUBLIC; + + +SET SESSION AUTHORIZATION 'asgeir'; + +SET search_path = public, pg_catalog; + +-- +-- TOC entry 5 (OID 18717) +-- Name: id_seq; Type: SEQUENCE; Schema: public; Owner: asgeir +-- + +CREATE SEQUENCE id_seq + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + CACHE 1; + + +-- +-- TOC entry 6 (OID 18719) +-- Name: site; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE site ( + id integer NOT NULL, + title text, + description text, + rights text, + email text +); + + +-- +-- TOC entry 7 (OID 18726) +-- Name: reaktoruser; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE reaktoruser ( + id integer NOT NULL, + "type" text, + name text, + email text, + "password" text, + disabled boolean, + salt text, + nick text, + public_name boolean, + public_email boolean, + description text, + sex character(1), + year_of_birth integer, + in_mailinglist boolean, + image text, + place_of_residence text, + telephone text, + site integer, + email_confirmed boolean, + artwork_groups text, + CONSTRAINT reaktoruser_sex CHECK (((sex = 'm'::bpchar) OR (sex = 'f'::bpchar))), + CONSTRAINT reaktoruser_type CHECK (((("type" = 'external'::text) OR ("type" = 'editor'::text)) OR ("type" = 'administrator'::text))) +); + + +-- +-- TOC entry 8 (OID 18739) +-- Name: artwork; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE artwork ( + id integer NOT NULL, + "type" text, + data text, + screenshot text, + creator integer, + title text, + description text, + keywords text, + howto text, + help text, + rights text, + editor integer, + width integer, + height integer, + site integer, + publish_state text, + under_discussion boolean, + internal_discussion text, + CONSTRAINT "$3" CHECK (((((rights = ':free'::text) OR (rights = ':educational'::text)) OR (rights = ':contactme'::text)) OR (rights = ':none'::text))), + CONSTRAINT artwork_publish_state CHECK (((((publish_state = ':queued'::text) OR (publish_state = ':denied'::text)) OR (publish_state = ':accepted'::text)) OR (publish_state = ':disabled'::text))), + CONSTRAINT artwork_type CHECK (((((((((((("type" = 'image'::text) OR ("type" = 'video'::text)) OR ("type" = 'flash'::text)) OR ("type" = 'pdf'::text)) OR ("type" = 'text'::text)) OR ("type" = 'verbatim text'::text)) OR ("type" = 'sound'::text)) OR ("type" = 'shockwave'::text)) OR ("type" = 'href'::text)) OR ("type" = 'images'::text)) OR ("type" = 'files'::text))) +); + + +-- +-- TOC entry 9 (OID 18757) +-- Name: article; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE article ( + id integer NOT NULL, + "type" text, + title text, + image text, + ingress text, + body text, + published boolean, + deleted boolean DEFAULT false, + rank integer, + artwork integer, + CONSTRAINT article_type CHECK (((((((("type" = 'standard'::text) OR ("type" = 'mypage'::text)) OR ("type" = 'topic'::text)) OR ("type" = 'pick'::text)) OR ("type" = 'help'::text)) OR ("type" = 'about'::text)) OR ("type" = 'internal'::text))) +); + + +-- +-- TOC entry 10 (OID 18770) +-- Name: topic; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE topic ( + id integer NOT NULL, + parent integer, + title text, + description text, + independent_title text +); + + +-- +-- TOC entry 11 (OID 18781) +-- Name: artwork_formats; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE artwork_formats ( + artwork integer NOT NULL, + topic integer NOT NULL +); + + +-- +-- TOC entry 12 (OID 18793) +-- Name: artwork_topics; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE artwork_topics ( + artwork integer NOT NULL, + topic integer NOT NULL +); + + +-- +-- TOC entry 13 (OID 18805) +-- Name: article_formats; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE article_formats ( + article integer NOT NULL, + topic integer NOT NULL +); + + +-- +-- TOC entry 14 (OID 18817) +-- Name: article_topics; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE article_topics ( + article integer NOT NULL, + topic integer NOT NULL +); + + +-- +-- TOC entry 15 (OID 18829) +-- Name: artwork_help_articles; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE artwork_help_articles ( + article integer NOT NULL, + artwork integer NOT NULL +); + + +-- +-- TOC entry 16 (OID 18841) +-- Name: comment; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE "comment" ( + id integer DEFAULT nextval('id_seq'::text) NOT NULL, + parent integer, + creator integer, + artwork integer, + hidden boolean DEFAULT false, + subject text, + body text +); + + +-- +-- TOC entry 17 (OID 18862) +-- Name: changelog; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE changelog ( + id integer DEFAULT nextval('id_seq'::text) NOT NULL, + "timestamp" timestamp without time zone DEFAULT ('now'::text)::timestamp(6) with time zone, + reaktoruser integer, + object integer, + object_type text, + "action" text, + description text, + ip text, + browser text, + CONSTRAINT changelog_action CHECK (((((((("action" = ':CREATE'::text) OR ("action" = ':EDIT'::text)) OR ("action" = ':DELETE'::text)) OR ("action" = ':PUBISH'::text)) OR ("action" = ':DENY'::text)) OR ("action" = ':ACCEPT'::text)) OR ("action" = ':LOGIN'::text))), + CONSTRAINT changelog_object_type CHECK (((((((object_type = 'artwork'::text) OR (object_type = 'article'::text)) OR (object_type = 'reaktoruser'::text)) OR (object_type = 'topic'::text)) OR (object_type = 'comment'::text)) OR (object_type = 'comment_complaint'::text))) +); + + +-- +-- TOC entry 18 (OID 18877) +-- Name: rating; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE rating ( + reaktoruser integer NOT NULL, + artwork integer NOT NULL, + rating integer +); + + +-- +-- TOC entry 19 (OID 18889) +-- Name: comment_complaint; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE comment_complaint ( + id integer DEFAULT nextval('id_seq'::text) NOT NULL, + state text DEFAULT ':queued'::text, + "comment" integer, + creator integer, + description text, + CONSTRAINT comment_complaint_state CHECK ((((state = ':queued'::text) OR (state = ':denied'::text)) OR (state = ':accepted'::text))) +); + + +-- +-- TOC entry 20 (OID 18907) +-- Name: reaktor; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE reaktor ( + id integer DEFAULT nextval('id_seq'::text) NOT NULL, + frontpage_articles_top integer, + frontpage_articles_left integer, + frontpage_articles_right integer, + frontpage_help_top integer, + frontpage_help_left integer, + frontpage_help_right integer, + frontpage_topic integer, + editor_pick integer, + frontpage_articles_top2 integer, + mypage_articles_top integer, + mypage_articles_top2 integer, + frontpage_help_1 integer, + frontpage_help_2 integer, + frontpage_help_3 integer, + frontpage_help_4 integer, + frontpage_help_5 integer, + frontpage_help_6 integer +); + + +-- +-- TOC entry 21 (OID 18944) +-- Name: topic_shortlist; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE topic_shortlist ( + reaktor integer, + topic integer NOT NULL, + rank integer +); + + +-- +-- TOC entry 22 (OID 29978) +-- Name: persmem; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE persmem ( + "key" text NOT NULL, + value text +); + + +-- +-- TOC entry 23 (OID 29985) +-- Name: persdict; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE persdict ( + "key" text NOT NULL, + value text +); + + +-- +-- TOC entry 24 (OID 36348) +-- Name: total_artworks; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW total_artworks AS + SELECT count(*) AS count FROM artwork WHERE (artwork.publish_state = ':accepted'::text); + + +-- +-- TOC entry 25 (OID 36354) +-- Name: denied_works; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW denied_works AS + SELECT count(*) AS count FROM artwork WHERE (artwork.publish_state = ':denied'::text); + + +-- +-- TOC entry 26 (OID 36357) +-- Name: queued_works; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW queued_works AS + SELECT count(*) AS count FROM artwork WHERE (artwork.publish_state = ':queued'::text); + + +-- +-- TOC entry 27 (OID 36360) +-- Name: total_users; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW total_users AS + SELECT count(*) AS count FROM reaktoruser WHERE (reaktoruser."type" = 'external'::text); + + +-- +-- TOC entry 28 (OID 36363) +-- Name: new_users; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW new_users AS + SELECT u.id, u.name, u.nick FROM changelog c, reaktoruser u WHERE ((((c.object_type = 'reaktoruser'::text) AND (c."action" = ':CREATE'::text)) AND (c."timestamp" > ('2005-01-05 14:34:15.665607'::timestamp without time zone - '1 mon'::interval))) AND (c.object = u.id)); + + +-- +-- TOC entry 29 (OID 36366) +-- Name: top20_users; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW top20_users AS + SELECT max(u.id) AS id, max(u.name) AS name, max(u.nick) AS artworks, count(a.id) AS count FROM artwork a, changelog c, reaktoruser u WHERE (((((c.object_type = 'artwork'::text) AND (c."action" = ':CREATE'::text)) AND (c."timestamp" > ('2005-01-05 14:34:15.669707'::timestamp without time zone - '3 mons'::interval))) AND (a.id = c.object)) AND (a.creator = u.id)) GROUP BY u.id ORDER BY count(a.id) DESC LIMIT 20; + + +-- +-- TOC entry 30 (OID 38997) +-- Name: user_help; Type: TABLE; Schema: public; Owner: asgeir +-- + +CREATE TABLE user_help ( + create_time timestamp without time zone, + creator integer, + url text +); + + +-- +-- TOC entry 31 (OID 46340) +-- Name: artwork_by_day; Type: VIEW; Schema: public; Owner: asgeir +-- + +CREATE VIEW artwork_by_day AS + SELECT date_trunc('day'::text, changelog."timestamp") AS date_trunc, count(artwork.id) AS count FROM artwork, changelog WHERE (((artwork.publish_state = ':accepted'::text) AND (changelog.object = artwork.id)) AND (changelog."action" = ':CREATE'::text)) GROUP BY date_trunc('day'::text, changelog."timestamp") ORDER BY date_trunc('day'::text, changelog."timestamp"); + + +SET SESSION AUTHORIZATION 'reaktortest'; + +-- +-- TOC entry 32 (OID 47342) +-- Name: new_works; Type: VIEW; Schema: public; Owner: reaktortest +-- + +CREATE VIEW new_works AS + SELECT count(*) AS count FROM changelog WHERE (((changelog.object_type = 'artwork'::text) AND (changelog."action" = ':CREATE'::text)) AND (changelog."timestamp" > ('2005-05-26 17:03:08.021782'::timestamp without time zone - '1 mon'::interval))); + + +SET SESSION AUTHORIZATION 'asgeir'; + +-- +-- TOC entry 33 (OID 18724) +-- Name: site_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY site + ADD CONSTRAINT site_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 34 (OID 18733) +-- Name: reaktoruser_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktoruser + ADD CONSTRAINT reaktoruser_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 35 (OID 18747) +-- Name: artwork_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork + ADD CONSTRAINT artwork_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 36 (OID 18764) +-- Name: article_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article + ADD CONSTRAINT article_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 37 (OID 18775) +-- Name: topic_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic + ADD CONSTRAINT topic_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 38 (OID 18783) +-- Name: artwork_formats_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_formats + ADD CONSTRAINT artwork_formats_pkey PRIMARY KEY (artwork, topic); + + +-- +-- TOC entry 39 (OID 18795) +-- Name: artwork_topics_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_topics + ADD CONSTRAINT artwork_topics_pkey PRIMARY KEY (artwork, topic); + + +-- +-- TOC entry 40 (OID 18807) +-- Name: article_formats_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_formats + ADD CONSTRAINT article_formats_pkey PRIMARY KEY (article, topic); + + +-- +-- TOC entry 41 (OID 18819) +-- Name: article_topics_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_topics + ADD CONSTRAINT article_topics_pkey PRIMARY KEY (article, topic); + + +-- +-- TOC entry 42 (OID 18831) +-- Name: artwork_help_articles_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_help_articles + ADD CONSTRAINT artwork_help_articles_pkey PRIMARY KEY (article, artwork); + + +-- +-- TOC entry 43 (OID 18848) +-- Name: comment_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY "comment" + ADD CONSTRAINT comment_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 44 (OID 18871) +-- Name: changelog_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY changelog + ADD CONSTRAINT changelog_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 45 (OID 18879) +-- Name: rating_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY rating + ADD CONSTRAINT rating_pkey PRIMARY KEY (reaktoruser, artwork); + + +-- +-- TOC entry 46 (OID 18897) +-- Name: comment_complaint_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY comment_complaint + ADD CONSTRAINT comment_complaint_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 47 (OID 18910) +-- Name: reaktor_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT reaktor_pkey PRIMARY KEY (id); + + +-- +-- TOC entry 48 (OID 18946) +-- Name: topic_shortlist_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic_shortlist + ADD CONSTRAINT topic_shortlist_pkey PRIMARY KEY (topic); + + +-- +-- TOC entry 49 (OID 29983) +-- Name: persmem_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY persmem + ADD CONSTRAINT persmem_pkey PRIMARY KEY ("key"); + + +-- +-- TOC entry 50 (OID 29990) +-- Name: persdict_pkey; Type: CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY persdict + ADD CONSTRAINT persdict_pkey PRIMARY KEY ("key"); + + +-- +-- TOC entry 51 (OID 18735) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktoruser + ADD CONSTRAINT "$1" FOREIGN KEY (site) REFERENCES site(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 52 (OID 18749) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork + ADD CONSTRAINT "$1" FOREIGN KEY (creator) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 53 (OID 18753) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork + ADD CONSTRAINT "$2" FOREIGN KEY (editor) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 54 (OID 18766) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article + ADD CONSTRAINT "$1" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 55 (OID 18777) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic + ADD CONSTRAINT "$1" FOREIGN KEY (parent) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 56 (OID 18785) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_formats + ADD CONSTRAINT "$1" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 57 (OID 18789) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_formats + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 58 (OID 18797) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_topics + ADD CONSTRAINT "$1" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 59 (OID 18801) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_topics + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 60 (OID 18809) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_formats + ADD CONSTRAINT "$1" FOREIGN KEY (article) REFERENCES article(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 61 (OID 18813) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_formats + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 62 (OID 18821) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_topics + ADD CONSTRAINT "$1" FOREIGN KEY (article) REFERENCES article(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 63 (OID 18825) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY article_topics + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 64 (OID 18833) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_help_articles + ADD CONSTRAINT "$1" FOREIGN KEY (article) REFERENCES article(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 65 (OID 18837) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY artwork_help_articles + ADD CONSTRAINT "$2" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 66 (OID 18850) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY "comment" + ADD CONSTRAINT "$1" FOREIGN KEY (parent) REFERENCES "comment"(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 67 (OID 18854) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY "comment" + ADD CONSTRAINT "$2" FOREIGN KEY (creator) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 68 (OID 18858) +-- Name: $3; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY "comment" + ADD CONSTRAINT "$3" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 69 (OID 18873) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY changelog + ADD CONSTRAINT "$1" FOREIGN KEY (reaktoruser) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 70 (OID 18881) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY rating + ADD CONSTRAINT "$1" FOREIGN KEY (reaktoruser) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 71 (OID 18885) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY rating + ADD CONSTRAINT "$2" FOREIGN KEY (artwork) REFERENCES artwork(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 72 (OID 18899) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY comment_complaint + ADD CONSTRAINT "$1" FOREIGN KEY ("comment") REFERENCES "comment"(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 73 (OID 18903) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY comment_complaint + ADD CONSTRAINT "$2" FOREIGN KEY (creator) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 74 (OID 18912) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$1" FOREIGN KEY (frontpage_articles_top) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 75 (OID 18916) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$2" FOREIGN KEY (frontpage_articles_left) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 76 (OID 18920) +-- Name: $3; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$3" FOREIGN KEY (frontpage_articles_right) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 77 (OID 18924) +-- Name: $4; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$4" FOREIGN KEY (frontpage_help_top) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 78 (OID 18928) +-- Name: $5; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$5" FOREIGN KEY (frontpage_help_left) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 79 (OID 18932) +-- Name: $6; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$6" FOREIGN KEY (frontpage_help_right) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 80 (OID 18936) +-- Name: $7; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$7" FOREIGN KEY (frontpage_topic) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 81 (OID 18940) +-- Name: $8; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$8" FOREIGN KEY (editor_pick) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 89 (OID 18948) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic_shortlist + ADD CONSTRAINT "$1" FOREIGN KEY (reaktor) REFERENCES reaktor(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 90 (OID 18952) +-- Name: $2; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY topic_shortlist + ADD CONSTRAINT "$2" FOREIGN KEY (topic) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +-- +-- TOC entry 82 (OID 38969) +-- Name: $88; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$88" FOREIGN KEY (frontpage_articles_top2) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 83 (OID 38973) +-- Name: $9; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$9" FOREIGN KEY (mypage_articles_top) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 84 (OID 38977) +-- Name: $10; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$10" FOREIGN KEY (mypage_articles_top2) REFERENCES article(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 85 (OID 38981) +-- Name: $12; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$12" FOREIGN KEY (frontpage_help_1) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 86 (OID 38985) +-- Name: $13; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$13" FOREIGN KEY (frontpage_help_4) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 87 (OID 38989) +-- Name: $14; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$14" FOREIGN KEY (frontpage_help_5) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 88 (OID 38993) +-- Name: $15; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY reaktor + ADD CONSTRAINT "$15" FOREIGN KEY (frontpage_help_6) REFERENCES topic(id) ON UPDATE CASCADE ON DELETE SET NULL; + + +-- +-- TOC entry 91 (OID 39002) +-- Name: $1; Type: FK CONSTRAINT; Schema: public; Owner: asgeir +-- + +ALTER TABLE ONLY user_help + ADD CONSTRAINT "$1" FOREIGN KEY (creator) REFERENCES reaktoruser(id) ON UPDATE CASCADE ON DELETE CASCADE; + + +SET SESSION AUTHORIZATION 'postgres'; + +-- +-- TOC entry 3 (OID 2200) +-- Name: SCHEMA public; Type: COMMENT; Schema: -; Owner: postgres +-- + +COMMENT ON SCHEMA public IS 'Standard public namespace'; + + diff --git a/prototype/dumps/reaktor.sql b/prototype/dumps/reaktor.sql new file mode 100644 index 0000000..d8a80ed --- /dev/null +++ b/prototype/dumps/reaktor.sql @@ -0,0 +1,1650 @@ +-- MySQL dump 10.11 +-- +-- Host: localhost Database: reaktor +-- ------------------------------------------------------ +-- Server version 5.0.51a-6ubuntu3 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `admin_message` +-- + +DROP TABLE IF EXISTS `admin_message`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `admin_message` ( + `id` int(11) NOT NULL auto_increment, + `subject` varchar(255) default NULL, + `message` text NOT NULL, + `author` int(11) NOT NULL, + `updated_at` datetime default NULL, + `expires_at` datetime NOT NULL, + `is_deleted` int(11) default '0', + PRIMARY KEY (`id`), + KEY `admin_message_FI_1` (`author`) +) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `admin_message` +-- + +LOCK TABLES `admin_message` WRITE; +/*!40000 ALTER TABLE `admin_message` DISABLE KEYS */; +INSERT INTO `admin_message` VALUES (1,NULL,'System has been updated!',1,'2008-08-07 10:55:02','2008-08-07 10:57:02',0); +/*!40000 ALTER TABLE `admin_message` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `article` +-- + +DROP TABLE IF EXISTS `article`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `article` ( + `id` int(11) NOT NULL auto_increment, + `created_at` datetime default NULL, + `author_id` int(11) NOT NULL, + `title` varchar(255) NOT NULL, + `permalink` varchar(255) NOT NULL, + `ingress` text, + `content` text NOT NULL, + `updated_at` datetime default NULL, + `updated_by` int(11) NOT NULL default '0', + `article_type` int(11) NOT NULL, + `article_order` int(11) NOT NULL, + `expires_at` datetime default NULL, + `deleted` int(11) NOT NULL default '0', + `published` int(11) NOT NULL default '0', + `published_at` datetime default NULL, + `banner_file_id` int(11) default '0', + `is_sticky` int(11) default '0', + PRIMARY KEY (`id`), + KEY `article_FI_1` (`author_id`), + KEY `article_FI_2` (`banner_file_id`) +) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `article` +-- + +LOCK TABLES `article` WRITE; +/*!40000 ALTER TABLE `article` DISABLE KEYS */; +INSERT INTO `article` VALUES (1,'2008-08-07 10:55:02',4,'Lorem Ipsum','Lorem_Ipsum','Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse consequat sagittis dui. Aenean tincidunt pulvinar neque. In fermentum, purus eu iaculis ultricies, augue urna accumsan arcu, vel pulvinar turpis massa non neque. Nunc congue dapibus libero. Vivamus ut quam. In pede. Proin ac leo. Phasellus fermentum lacus quis eros. Sed dignissim elit volutpat massa interdum rutrum. Cras non felis vel dolor vestibulum lacinia.','Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Suspendisse consequat sagittis dui. Aenean tincidunt pulvinar neque. In fermentum, purus eu iaculis ultricies, augue urna accumsan arcu, vel pulvinar turpis massa non neque. Nunc congue dapibus libero. Vivamus ut quam. In pede. Proin ac leo. Phasellus fermentum lacus quis eros. Sed dignissim elit volutpat massa interdum rutrum. Cras non felis vel dolor vestibulum lacinia.\n\nNullam porttitor purus in nunc. Sed quis pede vel orci faucibus aliquet. Duis adipiscing. Cras at leo. Morbi tortor nunc, adipiscing at, facilisis quis, lobortis imperdiet, ligula. Donec faucibus consequat mauris. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aliquam erat volutpat. Phasellus ipsum. Duis et turpis ac augue dictum accumsan. Curabitur dictum risus non justo. Sed consequat, ligula vel varius euismod, arcu justo accumsan massa, ut porta elit massa sed tellus. Praesent eleifend euismod sapien. Proin pede mi, condimentum vitae, rhoncus ut, facilisis eu, justo. In tellus odio, aliquet quis, adipiscing a, tristique mollis, justo. Pellentesque ac leo nec est iaculis pellentesque.\n\nNam id nunc. Donec magna ante, elementum sed, venenatis at, ornare in, ipsum. Aliquam erat volutpat. Aliquam ac lectus. Phasellus consequat odio et sapien. Vivamus eu ligula ac libero varius congue. Pellentesque tincidunt, justo vitae ultricies tincidunt, mauris justo aliquam pede, ac tristique nibh leo in dui. Nunc ut lacus. Nulla eu lectus. Nullam pretium, diam sit amet euismod viverra, leo lectus imperdiet odio, at elementum ipsum nulla eget est. In hac habitasse platea dictumst. Praesent ut mi. Fusce ultricies, erat vel blandit porta, justo nisi tempus metus, sed bibendum velit mi et lorem. Suspendisse id arcu sit amet elit semper pellentesque. Maecenas risus lacus, iaculis non, consequat id, iaculis id, tortor. Aenean ipsum leo, aliquet vitae, adipiscing a, eleifend sit amet, augue. Donec congue sagittis risus. Pellentesque eu turpis. Integer fringilla dictum metus.','2008-08-07 10:55:02',0,1,0,NULL,0,1,NULL,0,0),(2,'2008-08-07 10:55:02',4,'What is Lorem Ipsum?','What_is_Lorem_Ipsum_','Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.','What is Lorem Ipsum?\nLorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.\n\nWhy do we use it?\nIt is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using \'Content here, content here\', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for \'lorem ipsum\' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).\n\nWhere does it come from?\nContrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of \"de Finibus Bonorum et Malorum\" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, \"Lorem ipsum dolor sit amet..\", comes from a line in section 1.10.32.','2008-08-07 10:55:02',0,1,0,NULL,0,1,NULL,0,0),(3,'2008-08-07 10:55:02',4,'What is up in the tech world?','What_is_up_in_the_tech_world_','This is an example of how to include RSS feeds in your articles','Here are the latest stories from OSNews.com:\n[feed=http://osnews.com/files/recent.xml]4[/feed]\n\nWhere does it come from?\nThis is automatically fetched from the URL provided in this article. Sweet!','2008-08-07 10:55:02',0,6,0,NULL,0,1,NULL,0,0); +/*!40000 ALTER TABLE `article` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `article_article_relation` +-- + +DROP TABLE IF EXISTS `article_article_relation`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `article_article_relation` ( + `id` int(11) NOT NULL auto_increment, + `created_at` datetime default NULL, + `first_article` int(11) NOT NULL, + `second_article` int(11) NOT NULL, + `created_by` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `article_article_relation_FI_1` (`first_article`), + KEY `article_article_relation_FI_2` (`second_article`), + KEY `article_article_relation_FI_3` (`created_by`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `article_article_relation` +-- + +LOCK TABLES `article_article_relation` WRITE; +/*!40000 ALTER TABLE `article_article_relation` DISABLE KEYS */; +/*!40000 ALTER TABLE `article_article_relation` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `article_artwork_relation` +-- + +DROP TABLE IF EXISTS `article_artwork_relation`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `article_artwork_relation` ( + `id` int(11) NOT NULL auto_increment, + `created_at` datetime default NULL, + `article_id` int(11) NOT NULL, + `artwork_id` int(11) NOT NULL, + `created_by` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `article_artwork_relation_FI_1` (`article_id`), + KEY `article_artwork_relation_FI_2` (`artwork_id`), + KEY `article_artwork_relation_FI_3` (`created_by`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `article_artwork_relation` +-- + +LOCK TABLES `article_artwork_relation` WRITE; +/*!40000 ALTER TABLE `article_artwork_relation` DISABLE KEYS */; +/*!40000 ALTER TABLE `article_artwork_relation` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `article_attachment` +-- + +DROP TABLE IF EXISTS `article_attachment`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `article_attachment` ( + `article_id` int(11) NOT NULL, + `file_id` int(11) NOT NULL, + `id` int(11) NOT NULL auto_increment, + PRIMARY KEY (`id`), + KEY `article_attachment_FI_1` (`article_id`), + KEY `article_attachment_FI_2` (`file_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `article_attachment` +-- + +LOCK TABLES `article_attachment` WRITE; +/*!40000 ALTER TABLE `article_attachment` DISABLE KEYS */; +/*!40000 ALTER TABLE `article_attachment` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `article_category` +-- + +DROP TABLE IF EXISTS `article_category`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `article_category` ( + `article_id` int(11) NOT NULL, + `category_id` int(11) NOT NULL, + `id` int(11) NOT NULL auto_increment, + PRIMARY KEY (`id`), + KEY `article_category_FI_1` (`article_id`), + KEY `article_category_FI_2` (`category_id`) +) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `article_category` +-- + +LOCK TABLES `article_category` WRITE; +/*!40000 ALTER TABLE `article_category` DISABLE KEYS */; +INSERT INTO `article_category` VALUES (1,1,1),(2,55,2); +/*!40000 ALTER TABLE `article_category` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `article_file` +-- + +DROP TABLE IF EXISTS `article_file`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `article_file` ( + `id` int(11) NOT NULL auto_increment, + `filename` varchar(255) NOT NULL, + `path` varchar(255) NOT NULL, + `uploaded_by` int(11) NOT NULL, + `uploaded_at` datetime NOT NULL, + `description` varchar(255) default NULL, + `file_mimetype_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `article_file_FI_1` (`uploaded_by`), + KEY `article_file_FI_2` (`file_mimetype_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `article_file` +-- + +LOCK TABLES `article_file` WRITE; +/*!40000 ALTER TABLE `article_file` DISABLE KEYS */; +/*!40000 ALTER TABLE `article_file` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `article_subreaktor` +-- + +DROP TABLE IF EXISTS `article_subreaktor`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `article_subreaktor` ( + `article_id` int(11) NOT NULL, + `subreaktor_id` int(11) NOT NULL, + `id` int(11) NOT NULL auto_increment, + PRIMARY KEY (`id`), + KEY `article_subreaktor_FI_1` (`article_id`), + KEY `article_subreaktor_FI_2` (`subreaktor_id`) +) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `article_subreaktor` +-- + +LOCK TABLES `article_subreaktor` WRITE; +/*!40000 ALTER TABLE `article_subreaktor` DISABLE KEYS */; +INSERT INTO `article_subreaktor` VALUES (1,1,1),(2,6,2); +/*!40000 ALTER TABLE `article_subreaktor` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `artwork_status` +-- + +DROP TABLE IF EXISTS `artwork_status`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `artwork_status` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(30) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `artwork_status` +-- + +LOCK TABLES `artwork_status` WRITE; +/*!40000 ALTER TABLE `artwork_status` DISABLE KEYS */; +INSERT INTO `artwork_status` VALUES (1,'Draft'),(2,'Ready for approval'),(3,'Approved'),(4,'Rejected'),(5,'Removed'),(6,'Approved hidden'); +/*!40000 ALTER TABLE `artwork_status` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `artwork_status_i18n` +-- + +DROP TABLE IF EXISTS `artwork_status_i18n`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `artwork_status_i18n` ( + `id` int(11) NOT NULL, + `description` varchar(30) NOT NULL, + `culture` varchar(7) NOT NULL, + PRIMARY KEY (`id`,`culture`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `artwork_status_i18n` +-- + +LOCK TABLES `artwork_status_i18n` WRITE; +/*!40000 ALTER TABLE `artwork_status_i18n` DISABLE KEYS */; +INSERT INTO `artwork_status_i18n` VALUES (1,'Draft','no'),(1,'Draft','en'),(1,'Draft','nn'),(2,'Ready for approval','no'),(2,'Ready for approval','en'),(2,'Ready for approval','nn'),(3,'Approved','no'),(3,'Approved','en'),(3,'Approved','nn'),(4,'Rejected','no'),(4,'Rejected','en'),(4,'Rejected','nn'),(5,'Removed','no'),(5,'Removed','en'),(5,'Removed','nn'),(6,'Approved hidden','no'),(6,'Approved hidden','en'),(6,'Approved hidden','nn'); +/*!40000 ALTER TABLE `artwork_status_i18n` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `catalogue` +-- + +DROP TABLE IF EXISTS `catalogue`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `catalogue` ( + `cat_id` int(11) NOT NULL auto_increment, + `name` varchar(100) NOT NULL default '', + `source_lang` varchar(100) NOT NULL default '', + `target_lang` varchar(100) NOT NULL default '', + `date_created` int(11) NOT NULL default '0', + `date_modified` int(11) NOT NULL default '0', + `author` varchar(255) NOT NULL default '', + `description` varchar(255) NOT NULL default '', + PRIMARY KEY (`cat_id`) +) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `catalogue` +-- + +LOCK TABLES `catalogue` WRITE; +/*!40000 ALTER TABLE `catalogue` DISABLE KEYS */; +INSERT INTO `catalogue` VALUES (1,'messages.no','en','no',0,1197401129,'username','Bokmål'),(2,'messages.nn','en','nn',0,1197401130,'username','Nynorsk'),(3,'messages.en','en','en',0,1197401102,'username','English'); +/*!40000 ALTER TABLE `catalogue` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `category` +-- + +DROP TABLE IF EXISTS `category`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `category` ( + `id` int(11) NOT NULL auto_increment, + `basename` varchar(25) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=71 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `category` +-- + +LOCK TABLES `category` WRITE; +/*!40000 ALTER TABLE `category` DISABLE KEYS */; +INSERT INTO `category` VALUES (1,'arkitektur'),(2,'barn'),(3,'dyr'),(4,'kjøretøy'),(5,'landskap'),(6,'makro'),(7,'manipulasjon'),(8,'mennesker'),(9,'nattbilder'),(10,'natur'),(11,'portrett'),(12,'reise'),(13,'sport'),(14,'stilleben'),(15,'undervannsfoto'),(16,'datagrafikk'),(17,'3d'),(18,'maleri'),(19,'skisser'),(20,'tegning'),(21,'animasjonsfilm'),(22,'dataanimasjon'),(23,'dokumentar'),(24,'kortfilm'),(25,'musikkvideo'),(26,'blues'),(27,'elektronika'),(28,'folkemusikk'),(29,'hip hop'),(30,'jazz'),(31,'klassisk musikk'),(32,'pop'),(33,'rock'),(34,'hørespill'),(35,'intervjuer'),(36,'lydeffekter'),(37,'opplesninger'),(38,'rockabilly'),(39,'techno'),(40,'viser'),(41,'world music'),(42,'biografisk'),(43,'drama'),(44,'fantasy'),(45,'funny animals'),(46,'historisk'),(47,'humor'),(48,'manga'),(49,'samfunnssatire'),(50,'science fiction'),(51,'skrekk'),(52,'spenning'),(53,'superhelter'),(54,'western'),(55,'essays'),(56,'eventyr'),(57,'fabler'),(58,'filmmanus'),(59,'foredrag'),(60,'fortellinger'),(61,'haikudikt'),(62,'krim'),(63,'noveller'),(64,'prosadikt'),(65,'rollespill'),(66,'science rollespill'),(67,'animals'),(68,'mitsetegning'),(69,'metaserie'),(70,'arrangementer'); +/*!40000 ALTER TABLE `category` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `category_artwork` +-- + +DROP TABLE IF EXISTS `category_artwork`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `category_artwork` ( + `id` int(11) NOT NULL auto_increment, + `category_id` int(11) default NULL, + `artwork_id` int(11) default NULL, + `added_by` int(11) default NULL, + `created_at` datetime default NULL, + PRIMARY KEY (`id`), + KEY `category_artwork_FI_1` (`category_id`), + KEY `category_artwork_FI_2` (`artwork_id`), + KEY `category_artwork_FI_3` (`added_by`) +) ENGINE=MyISAM AUTO_INCREMENT=25 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `category_artwork` +-- + +LOCK TABLES `category_artwork` WRITE; +/*!40000 ALTER TABLE `category_artwork` DISABLE KEYS */; +INSERT INTO `category_artwork` VALUES (1,12,1,2,'2008-05-15 18:01:09'),(2,8,1,2,'2008-05-15 18:01:11'),(3,4,2,2,'2008-05-15 18:01:27'),(4,8,2,2,'2008-05-15 18:01:29'),(5,12,2,2,'2008-05-15 18:01:34'),(6,55,3,2,'2008-05-15 18:01:52'),(7,63,3,2,'2008-05-15 18:01:55'),(8,24,4,2,'2008-05-15 18:02:03'),(9,23,4,2,'2008-05-15 18:02:05'),(10,40,5,2,'2008-05-15 18:02:14'),(11,36,5,2,'2008-05-15 18:02:16'),(12,55,6,2,'2008-05-15 18:02:23'),(13,60,6,2,'2008-05-15 18:02:24'),(14,64,6,2,'2008-05-15 18:02:28'),(15,3,7,2,'2008-05-15 18:02:34'),(16,10,7,2,'2008-05-15 18:02:37'),(17,3,8,2,'2008-05-15 18:02:48'),(18,10,8,2,'2008-05-15 18:02:49'),(19,53,9,2,'2008-05-15 18:03:04'),(20,47,9,2,'2008-05-15 18:02:58'),(21,43,9,2,'2008-05-15 18:03:07'),(22,19,10,2,'2008-05-15 18:03:29'),(23,21,11,2,'2008-05-15 18:03:29'),(24,22,11,2,'2008-05-15 18:03:29'); +/*!40000 ALTER TABLE `category_artwork` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `category_i18n` +-- + +DROP TABLE IF EXISTS `category_i18n`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `category_i18n` ( + `name` varchar(25) NOT NULL, + `id` int(11) NOT NULL, + `culture` varchar(7) NOT NULL, + PRIMARY KEY (`id`,`culture`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `category_i18n` +-- + +LOCK TABLES `category_i18n` WRITE; +/*!40000 ALTER TABLE `category_i18n` DISABLE KEYS */; +INSERT INTO `category_i18n` VALUES ('arkitektur',1,'no'),('barn',2,'no'),('dyr',3,'no'),('kjøretøy',4,'no'),('landskap',5,'no'),('makro',6,'no'),('manipulasjon',7,'no'),('mennesker',8,'no'),('nattbilder',9,'no'),('natur',10,'no'),('portrett',11,'no'),('reise',12,'no'),('sport',13,'no'),('stilleben',14,'no'),('undervannsfoto',15,'no'),('datagrafikk',16,'no'),('3d',17,'no'),('maleri',18,'no'),('skisser',19,'no'),('tegning',20,'no'),('animasjonsfilm',21,'no'),('dataanimasjon',22,'no'),('dokumentar',23,'no'),('kortfilm',24,'no'),('musikkvideo',25,'no'),('blues',26,'no'),('elektronika',27,'no'),('folkemusikk',28,'no'),('hip hop',29,'no'),('jazz',30,'no'),('klassisk musikk',31,'no'),('pop',32,'no'),('rock',33,'no'),('hørespill',34,'no'),('intervjuer',35,'no'),('lydeffekter',36,'no'),('opplesninger',37,'no'),('rockabilly',38,'no'),('techno',39,'no'),('viser',40,'no'),('world music',41,'no'),('biografisk',42,'no'),('drama',43,'no'),('fantasy',44,'no'),('funny animals',45,'no'),('historisk',46,'no'),('humor',47,'no'),('manga',48,'no'),('samfunnssatire',49,'no'),('science fiction',50,'no'),('skrekk',51,'no'),('spenning',52,'no'),('superhelter',53,'no'),('western',54,'no'),('essays',55,'no'),('eventyr',56,'no'),('fabler',57,'no'),('filmmanus',58,'no'),('foredrag',59,'no'),('fortellinger',60,'no'),('haikudikt',61,'no'),('krim',62,'no'),('noveller',63,'no'),('prosadikt',64,'no'),('rollespill',65,'no'),('science rollespill',66,'no'),('animals',67,'no'),('mitsetegning',68,'no'),('metaserie',69,'no'),('arrangementer',70,'no'),('architecture',1,'en'),('children',2,'en'),('animals',3,'en'),('vehicles',4,'en'),('landscape',5,'en'),('macro',6,'en'),('manipulation',7,'en'),('people',8,'en'),('night pictures',9,'en'),('nature',10,'en'),('portrait',11,'en'),('travel',12,'en'),('sport',13,'en'),('still life',14,'en'),('underwater photo',15,'en'),('computer graphics',16,'en'),('3d',17,'en'),('painting',18,'en'),('sketch',19,'en'),('drawing',20,'en'),('animation',21,'en'),('computer animation',22,'en'),('documentary',23,'en'),('short film',24,'en'),('music video',25,'en'),('blues',26,'en'),('electronica',27,'en'),('folk music',28,'en'),('hip hop',29,'en'),('jazz',30,'en'),('classical music',31,'en'),('pop',32,'en'),('rock',33,'en'),('radio entertainment',34,'en'),('interview',35,'en'),('sound effects',36,'en'),('recitals',37,'en'),('rockabilly',38,'en'),('techno',39,'en'),('demonstration',40,'en'),('world music',41,'en'),('biography',42,'en'),('drama',43,'en'),('fantasy',44,'en'),('funny animals',45,'en'),('historical',46,'en'),('humor',47,'en'),('manga',48,'en'),('satire',49,'en'),('science fiction',50,'en'),('horror',51,'en'),('suspense',52,'en'),('super heroes',53,'en'),('western',54,'en'),('essays',55,'en'),('events',56,'en'),('fables',57,'en'),('film scripts',58,'en'),('speech',59,'en'),('story telling',60,'en'),('haiku poems',61,'en'),('crime',62,'en'),('novels',63,'en'),('prose poems',64,'en'),('roleplay',65,'en'),('science roleplay',66,'en'),('animals',67,'en'),('funny drawing',68,'en'),('meta series',69,'en'),('arrangements',70,'en'),('arkitektur',1,'nn'),('barn',2,'nn'),('dyr',3,'nn'),('kjøretøy',4,'nn'),('landskap',5,'nn'),('makro',6,'nn'),('manipulasjon',7,'nn'),('mennesker',8,'nn'),('nattbilder',9,'nn'),('natur',10,'nn'),('portrett',11,'nn'),('reise',12,'nn'),('sport',13,'nn'),('stilleban',14,'nn'),('undervannsfoto',15,'nn'),('datagrafikk',16,'nn'),('3d',17,'nn'),('maleri',18,'nn'),('skisser',19,'nn'),('tegning',20,'nn'),('animasjonsfilm',21,'nn'),('dataanimasjon',22,'nn'),('dokumentar',23,'nn'),('kortfilm',24,'nn'),('musikkvideo',25,'nn'),('blues',26,'nn'),('elektronika',27,'nn'),('folkemusikk',28,'nn'),('hip hop',29,'nn'),('jazz',30,'nn'),('klassisk musikk',31,'nn'),('pop',32,'nn'),('rock',33,'nn'),('hørespill',34,'nn'),('intervjuer',35,'nn'),('lydeffekter',36,'nn'),('opplesninger',37,'nn'),('rockabilly',38,'nn'),('techno',39,'nn'),('viser',40,'nn'),('world music',41,'nn'),('biografisk',42,'nn'),('drama',43,'nn'),('fantasy',44,'nn'),('funny animals',45,'nn'),('historisk',46,'nn'),('humor',47,'nn'),('manga',48,'nn'),('samfunnssatire',49,'nn'),('science fiction',50,'nn'),('skrekk',51,'nn'),('spenning',52,'nn'),('superhelter',53,'nn'),('western',54,'nn'),('essays',55,'nn'),('eventyr',56,'nn'),('fabler',57,'nn'),('filmmanus',58,'nn'),('foredrag',59,'nn'),('fortellinger',60,'nn'),('haikudikt',61,'nn'),('krim',62,'nn'),('noveller',63,'nn'),('prosadikt',64,'nn'),('rollespill',65,'nn'),('science rollespill',66,'nn'),('animals',67,'nn'),('mitsetegning',68,'nn'),('metaserie',69,'nn'),('arrangementer',70,'nn'); +/*!40000 ALTER TABLE `category_i18n` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `category_subreaktor` +-- + +DROP TABLE IF EXISTS `category_subreaktor`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `category_subreaktor` ( + `id` int(11) NOT NULL auto_increment, + `category_id` int(11) default NULL, + `subreaktor_id` int(11) default NULL, + PRIMARY KEY (`id`), + KEY `category_subreaktor_FI_1` (`category_id`), + KEY `category_subreaktor_FI_2` (`subreaktor_id`) +) ENGINE=MyISAM AUTO_INCREMENT=73 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `category_subreaktor` +-- + +LOCK TABLES `category_subreaktor` WRITE; +/*!40000 ALTER TABLE `category_subreaktor` DISABLE KEYS */; +INSERT INTO `category_subreaktor` VALUES (1,1,1),(2,2,1),(3,3,1),(4,4,1),(5,5,1),(6,6,1),(7,7,1),(8,8,1),(9,9,1),(10,10,1),(11,11,1),(12,12,1),(13,13,1),(14,14,1),(15,15,1),(16,16,2),(17,17,2),(18,18,2),(19,19,2),(20,20,2),(21,21,3),(22,22,3),(23,23,3),(24,24,3),(25,25,3),(26,26,4),(27,27,4),(28,28,4),(29,29,4),(30,30,4),(31,31,4),(32,32,4),(33,33,4),(34,34,4),(35,35,4),(36,36,4),(37,37,4),(38,38,4),(39,39,4),(40,40,4),(41,41,4),(42,25,4),(43,42,5),(44,43,5),(45,44,5),(46,45,5),(47,46,5),(48,47,5),(49,48,5),(50,49,5),(51,50,5),(52,51,5),(53,52,5),(54,53,5),(55,54,5),(56,55,6),(57,56,6),(58,57,6),(59,44,6),(60,58,6),(61,59,6),(62,60,6),(63,61,6),(64,47,6),(65,34,6),(66,62,6),(67,63,6),(68,64,6),(69,65,6),(70,66,6),(71,68,5),(72,69,5); +/*!40000 ALTER TABLE `category_subreaktor` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `favourite` +-- + +DROP TABLE IF EXISTS `favourite`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `favourite` ( + `id` int(11) NOT NULL auto_increment, + `user_id` int(11) NOT NULL, + `artwork_id` int(11) NOT NULL, + `article_id` int(11) NOT NULL, + `friend_id` int(11) NOT NULL, + `fav_type` varchar(8) NOT NULL, + PRIMARY KEY (`id`), + KEY `favourite_FI_1` (`user_id`), + KEY `favourite_FI_2` (`artwork_id`), + KEY `favourite_FI_3` (`article_id`), + KEY `favourite_FI_4` (`friend_id`) +) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `favourite` +-- + +LOCK TABLES `favourite` WRITE; +/*!40000 ALTER TABLE `favourite` DISABLE KEYS */; +INSERT INTO `favourite` VALUES (1,2,2,0,0,'artwork'),(2,4,2,0,0,'artwork'),(3,3,4,0,0,'artwork'),(4,4,1,0,0,'artwork'),(5,5,6,0,0,'artwork'),(6,6,2,0,0,'artwork'),(7,1,2,0,0,'artwork'),(8,2,0,0,1,'user'),(9,2,0,0,4,'user'),(10,2,0,0,5,'user'),(11,2,0,0,6,'user'),(12,6,0,0,2,'user'); +/*!40000 ALTER TABLE `favourite` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `file_metadata` +-- + +DROP TABLE IF EXISTS `file_metadata`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `file_metadata` ( + `id` int(11) NOT NULL auto_increment, + `file` int(11) NOT NULL, + `meta_element` varchar(100) NOT NULL, + `meta_qualifier` varchar(100) NOT NULL, + `meta_value` text NOT NULL, + PRIMARY KEY (`id`), + KEY `file_metadata_FI_1` (`file`) +) ENGINE=MyISAM AUTO_INCREMENT=85 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `file_metadata` +-- + +LOCK TABLES `file_metadata` WRITE; +/*!40000 ALTER TABLE `file_metadata` DISABLE KEYS */; +INSERT INTO `file_metadata` VALUES (1,1,'creator','','Spartacus'),(2,2,'creator','','Uncle Sam'),(3,6,'creator','','Bob'),(4,6,'description','abstract','Something Kjellm uploaded'),(5,6,'description','creation','Kinda out there...'),(6,6,'relation','references','http://www.google.co.uk\nhttp://eatmymonkeydust.com'),(7,6,'subject','','text, latin, filler, snow, ski, marianne, sam'),(8,6,'license','','free_use'),(9,1,'license','','free_use'),(10,2,'license','','contact'),(11,3,'license','','free_use'),(12,1,'title','','Japan subway'),(13,2,'title','','PHP Cookbook'),(14,3,'title','','Filming in Saudi Arabia'),(15,6,'title','','My first nice sound clip'),(16,5,'title','','Some crazy fingers'),(17,7,'license','','free_use'),(18,6,'license','','no_allow'),(19,5,'license','','contact'),(20,1,'description','abstract','What is this crazy lady doing?\nWell, I suppose if you spend every day on the subway... !'),(21,1,'subject','','japan, rest, subway, lady'),(22,2,'description','abstract','It might be a picture of my car, but underneath lies a useful PDF :o)'),(23,2,'description','creation','I didn\'t produce this, although I did take the picture for the thumbnail!'),(24,2,'subject','','php, cookbook, car, ford, focus'),(25,3,'description','abstract','On the water between Bahrain and Saudi Arabia, filming an interview'),(26,3,'description','creation','Clearly I didn\'t take this picture, that was probably Sean!'),(27,3,'subject','','Saudi Arabia, Bahrain, Squash, boat, water, psalive'),(28,3,'creator','','Sean'),(29,5,'description','abstract','Something Kjellm uploaded'),(30,5,'description','creation','No idea who created this, or why!'),(31,5,'subject','','fingers, strange, count'),(32,5,'creator','','Some dude'),(33,7,'description','abstract','Something Kjellm uploaded'),(34,7,'description','creation','Somebody pressed the latin filler text button'),(35,7,'subject','','text, latin, filler'),(36,7,'creator','','Spartacus'),(37,7,'title','','Random plain text'),(38,7,'license','','contact'),(39,4,'description','abstract','Taken inside the Eden Project'),(40,4,'description','creation','EOS 350D\nf/2.8\n1/80\nISO: 100\n50mm'),(41,4,'subject','','bird, wet, Eden project'),(42,4,'creator','','Russ'),(43,4,'title','','Wet Robin'),(44,4,'license','','contact'),(45,8,'description','abstract','Loving the B&W'),(46,8,'description','creation','EOS 350D\nf/6.3\n1/50\nISO: 100\n40mm'),(47,8,'subject','','abigail, statue, frogner'),(48,8,'creator','','Russ'),(49,8,'title','','Abigail at Frogner'),(50,8,'license','','contact'),(51,9,'description','creation','Me and my camera'),(52,9,'type','','image/jpeg'),(53,9,'format','width','2996'),(54,9,'format','height','2084'),(55,9,'date','creation','2007:06:19 14:37:01'),(56,9,'format','size','5280277'),(57,9,'creator','','dave'),(58,9,'title','','Cute monkeys'),(59,9,'description','abstract','Cute monkeys!!'),(60,9,'license','','contact'),(61,10,'description','creation','Me and my camera'),(62,10,'type','','image/jpeg'),(63,10,'format','width','1432'),(64,10,'format','height','1040'),(65,10,'date','creation','2007:06:19 11:29:26'),(66,10,'format','size','1302543'),(67,10,'creator','','dave'),(68,10,'title','','Nice monkeys'),(69,10,'description','abstract','Actually Lemurs... !'),(70,10,'license','','no_allow'),(71,11,'creator','','June'),(72,11,'title','','Nice cartoon'),(73,11,'description','abstract','A cartoon I don\'t understand...'),(74,11,'description','creation','June uploaded it and I nicked it to put in the fixtures'),(75,11,'license','','free_use'),(76,12,'creator','','dave'),(77,12,'title','','Magic roundabout - Swindon'),(78,12,'relation','references','http://en.wikipedia.org/wiki/Magic_Roundabout_(Swindon)'),(79,12,'license','','free_use'),(80,12,'description','abstract','Yes it exists'),(81,12,'description','creation','Nicked it from Google images'),(82,13,'title','','Magic animations'),(83,13,'description','abstract','\'tis my magic animation file! Watch it! Oh, and you need sound.'),(84,13,'license','','by-sa'); +/*!40000 ALTER TABLE `file_metadata` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `file_mimetype` +-- + +DROP TABLE IF EXISTS `file_mimetype`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `file_mimetype` ( + `id` int(11) NOT NULL auto_increment, + `mimetype` varchar(100) NOT NULL, + `identifier` varchar(20) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=30 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `file_mimetype` +-- + +LOCK TABLES `file_mimetype` WRITE; +/*!40000 ALTER TABLE `file_mimetype` DISABLE KEYS */; +INSERT INTO `file_mimetype` VALUES (1,'image/png','image'),(2,'image/jpeg','image'),(3,'application/pdf','pdf'),(4,'video/flv','video'),(5,'audio/mpeg','audio'),(6,'application/x-shockwave-flash','flash_animation'),(7,'image/gif','image'),(8,'image/tiff','image'),(9,'text/plain','text'),(10,'video/mpeg','video'),(11,'video/quicktime','video'),(12,'video/x-msvideo','video'),(13,'video/ogg','video'),(14,'audio/ogg','audio'),(15,'audio/flac','audio'),(16,'application/ogg','video'),(17,'audio/x-wav','audio'),(18,'video/avi','video'),(19,'video/x-ms-wmv','video'),(20,'video/mp4','video'),(21,'audio/mid','audio'),(22,'image/pjpeg','image'),(23,'audio/x-ms-wma','audio'),(24,'image/x-png','image'),(25,'audio/wav','audio'),(26,'audio/midi','audio'),(27,'text/html','text'),(28,'application/octet-stream','video'),(29,'video/x-flv','video'); +/*!40000 ALTER TABLE `file_mimetype` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `history` +-- + +DROP TABLE IF EXISTS `history`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `history` ( + `id` int(11) NOT NULL auto_increment, + `created_at` datetime default NULL, + `action_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `object_id` int(11) default NULL, + `extra_details` text, + PRIMARY KEY (`id`), + KEY `history_FI_1` (`action_id`), + KEY `history_FI_2` (`user_id`) +) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `history` +-- + +LOCK TABLES `history` WRITE; +/*!40000 ALTER TABLE `history` DISABLE KEYS */; +INSERT INTO `history` VALUES (1,'2008-07-11 19:10:15',8,2,2,'reaktorArtwork'); +/*!40000 ALTER TABLE `history` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `history_action` +-- + +DROP TABLE IF EXISTS `history_action`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `history_action` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(50) default NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `history_action` +-- + +LOCK TABLES `history_action` WRITE; +/*!40000 ALTER TABLE `history_action` DISABLE KEYS */; +INSERT INTO `history_action` VALUES (1,'File reported'),(2,'File removed'),(3,'File restored'),(4,'Tag approved'),(5,'Article Created'),(6,'File marked for discussion'),(7,'File unmarked from discussion'),(8,'Artwork marked for discussion'),(9,'Artwork unmarked from discussion'),(10,'Article edited'); +/*!40000 ALTER TABLE `history_action` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `history_action_i18n` +-- + +DROP TABLE IF EXISTS `history_action_i18n`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `history_action_i18n` ( + `description` text NOT NULL, + `id` int(11) NOT NULL, + `culture` varchar(7) NOT NULL, + PRIMARY KEY (`id`,`culture`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `history_action_i18n` +-- + +LOCK TABLES `history_action_i18n` WRITE; +/*!40000 ALTER TABLE `history_action_i18n` DISABLE KEYS */; +INSERT INTO `history_action_i18n` VALUES ('Fil rapportert',1,'no'),('Fil fjernet',2,'no'),('Fil gjenopprettet',3,'no'),('Tag godkjent',4,'no'),('Artikkel opprettet',5,'no'),('Fil markert for diskusjon',6,'no'),('Fil fjernet fra diskusjonen',7,'no'),('Verk merket for diskusjon',8,'no'),('Verk fjernet fra diskusjonen',9,'no'),('Artikkel endret',10,'no'); +/*!40000 ALTER TABLE `history_action_i18n` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `lokalreaktor_artwork` +-- + +DROP TABLE IF EXISTS `lokalreaktor_artwork`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `lokalreaktor_artwork` ( + `id` int(11) NOT NULL auto_increment, + `subreaktor_id` int(11) NOT NULL, + `artwork_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `lokalreaktor_artwork_FI_1` (`subreaktor_id`), + KEY `lokalreaktor_artwork_FI_2` (`artwork_id`) +) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `lokalreaktor_artwork` +-- + +LOCK TABLES `lokalreaktor_artwork` WRITE; +/*!40000 ALTER TABLE `lokalreaktor_artwork` DISABLE KEYS */; +INSERT INTO `lokalreaktor_artwork` VALUES (1,7,1),(2,7,3),(3,7,5),(4,7,8); +/*!40000 ALTER TABLE `lokalreaktor_artwork` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `lokalreaktor_residence` +-- + +DROP TABLE IF EXISTS `lokalreaktor_residence`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `lokalreaktor_residence` ( + `id` int(11) NOT NULL auto_increment, + `created_at` datetime default NULL, + `subreaktor_id` int(11) NOT NULL, + `residence_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `lokalreaktor_residence_FI_1` (`subreaktor_id`), + KEY `lokalreaktor_residence_FI_2` (`residence_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `lokalreaktor_residence` +-- + +LOCK TABLES `lokalreaktor_residence` WRITE; +/*!40000 ALTER TABLE `lokalreaktor_residence` DISABLE KEYS */; +/*!40000 ALTER TABLE `lokalreaktor_residence` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `messages` +-- + +DROP TABLE IF EXISTS `messages`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `messages` ( + `id` int(11) NOT NULL auto_increment, + `to_user_id` int(11) NOT NULL, + `from_user_id` int(11) NOT NULL, + `subject` varchar(255) default NULL, + `message` text, + `timestamp` datetime NOT NULL, + `deleted_by_from` int(11) NOT NULL default '0', + `deleted_by_to` int(11) NOT NULL default '0', + `is_read` int(11) NOT NULL default '0', + `is_ignored` int(11) NOT NULL default '0', + `is_archived` int(11) NOT NULL default '0', + `reply_to` int(11) default '0', + PRIMARY KEY (`id`), + KEY `messages_FI_1` (`to_user_id`), + KEY `messages_FI_2` (`from_user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `messages` +-- + +LOCK TABLES `messages` WRITE; +/*!40000 ALTER TABLE `messages` DISABLE KEYS */; +/*!40000 ALTER TABLE `messages` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `messages_ignored_user` +-- + +DROP TABLE IF EXISTS `messages_ignored_user`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `messages_ignored_user` ( + `id` int(11) NOT NULL auto_increment, + `user_id` int(11) NOT NULL, + `ignores_user_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `messages_ignored_user_FI_1` (`user_id`), + KEY `messages_ignored_user_FI_2` (`ignores_user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `messages_ignored_user` +-- + +LOCK TABLES `messages_ignored_user` WRITE; +/*!40000 ALTER TABLE `messages_ignored_user` DISABLE KEYS */; +/*!40000 ALTER TABLE `messages_ignored_user` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `reaktor_artwork` +-- + +DROP TABLE IF EXISTS `reaktor_artwork`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `reaktor_artwork` ( + `id` int(11) NOT NULL auto_increment, + `user_id` int(11) NOT NULL, + `artwork_identifier` varchar(20) NOT NULL, + `created_at` datetime NOT NULL, + `submitted_at` datetime default NULL, + `actioned_at` datetime default NULL, + `modified_flag` datetime default NULL, + `title` varchar(255) NOT NULL, + `actioned_by` int(11) NOT NULL, + `status` int(11) NOT NULL, + `description` text, + `modified_note` text, + `artwork_order` int(11) default '0', + `average_rating` float default '0', + `team_id` int(11) NOT NULL, + `under_discussion` int(1) NOT NULL default '0', + `multi_user` int(1) NOT NULL default '0', + `deleted` int(11) default '0', + PRIMARY KEY (`id`), + KEY `reaktor_artwork_FI_1` (`user_id`), + KEY `reaktor_artwork_FI_2` (`status`), + KEY `reaktor_artwork_FI_3` (`team_id`) +) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `reaktor_artwork` +-- + +LOCK TABLES `reaktor_artwork` WRITE; +/*!40000 ALTER TABLE `reaktor_artwork` DISABLE KEYS */; +INSERT INTO `reaktor_artwork` VALUES (1,3,'image','2008-03-05 18:30:37','2008-03-02 21:28:08',NULL,NULL,'The wonderful painting',0,2,'This painting is wonderful',NULL,0,0,5,0,0,0),(2,3,'image','2008-03-05 18:30:37','2008-02-20 21:30:54','2008-03-10 21:00:00',NULL,'The fancy gallery',1,3,'This is an awesome gallery',NULL,0,5.5,5,1,0,0),(3,3,'pdf','2008-03-05 18:30:37','2008-01-23 21:31:21','2008-03-03 21:31:27',NULL,'My Pdf',0,3,'This pdf is the bomb',NULL,0,3.5,5,0,0,0),(4,2,'video','2008-03-05 18:30:37','2008-03-02 21:31:35','2008-03-02 21:31:41',NULL,'Fingers',0,3,'Fingers, what more do you want?',NULL,0,4.5,8,0,0,0),(5,2,'audio','2008-03-05 18:30:37','2008-02-14 21:31:50',NULL,NULL,'Spacy',0,2,'woooooosh',NULL,0,0,6,0,0,0),(6,2,'text','2008-03-05 18:30:37','2008-01-07 21:32:05',NULL,NULL,'Dolor Sit',0,2,'Lorem Ipsum blah blah blah',NULL,0,0,7,0,0,0),(7,5,'image','2008-04-07 21:28:03','2008-04-07 21:28:03',NULL,NULL,'Cute monkeys',0,2,'Awwwww, so cute',NULL,0,0,5,0,0,0),(8,5,'image','2008-04-07 21:33:25','2008-04-07 21:33:25','2008-04-08 21:31:27',NULL,'Nice monkeys',1,3,'W00t',NULL,0,0,5,0,0,0),(9,6,'image','2008-05-06 13:45:41','2008-05-06 13:45:41','2008-05-06 13:46:27',NULL,'Nice cartoon',1,3,'Did it make you laugh too?',NULL,0,0,10,0,0,0),(10,6,'image','2008-05-15 11:56:46','2008-05-15 11:56:46','2008-05-15 11:57:39',NULL,'Magic roundabout - Swindon',1,3,'It\'s magic, don\'t you think?',NULL,0,0,5,0,0,0),(11,2,'flash_animation','2008-07-23 13:05:38','2008-07-23 13:05:38','2008-07-23 13:05:38',NULL,'Magic animations',1,3,'\'tis my magic animation file! Watch it! Oh, and you need sound.',NULL,0,0,10,0,0,0); +/*!40000 ALTER TABLE `reaktor_artwork` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `reaktor_artwork_file` +-- + +DROP TABLE IF EXISTS `reaktor_artwork_file`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `reaktor_artwork_file` ( + `artwork_id` int(11) NOT NULL, + `file_id` int(11) NOT NULL, + `file_order` int(11) default '1', + PRIMARY KEY (`artwork_id`,`file_id`), + KEY `reaktor_artwork_file_FI_2` (`file_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `reaktor_artwork_file` +-- + +LOCK TABLES `reaktor_artwork_file` WRITE; +/*!40000 ALTER TABLE `reaktor_artwork_file` DISABLE KEYS */; +INSERT INTO `reaktor_artwork_file` VALUES (1,1,1),(2,3,1),(2,4,1),(2,8,1),(3,2,1),(4,5,1),(5,6,1),(6,7,1),(7,9,1),(8,10,1),(9,11,1),(10,12,1),(11,13,1); +/*!40000 ALTER TABLE `reaktor_artwork_file` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `reaktor_artwork_history` +-- + +DROP TABLE IF EXISTS `reaktor_artwork_history`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `reaktor_artwork_history` ( + `id` int(11) NOT NULL auto_increment, + `artwork_id` int(11) default NULL, + `file_id` int(11) default NULL, + `created_at` datetime default NULL, + `modified_flag` datetime default NULL, + `user_id` int(11) NOT NULL, + `status` int(11) NOT NULL, + `comment` text, + PRIMARY KEY (`id`), + KEY `reaktor_artwork_history_FI_1` (`artwork_id`), + KEY `reaktor_artwork_history_FI_2` (`file_id`), + KEY `reaktor_artwork_history_FI_3` (`user_id`), + KEY `reaktor_artwork_history_FI_4` (`status`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `reaktor_artwork_history` +-- + +LOCK TABLES `reaktor_artwork_history` WRITE; +/*!40000 ALTER TABLE `reaktor_artwork_history` DISABLE KEYS */; +/*!40000 ALTER TABLE `reaktor_artwork_history` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `reaktor_file` +-- + +DROP TABLE IF EXISTS `reaktor_file`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `reaktor_file` ( + `id` int(11) NOT NULL auto_increment, + `filename` varchar(200) NOT NULL, + `user_id` int(11) NOT NULL, + `realpath` varchar(300) NOT NULL, + `thumbpath` varchar(300) NOT NULL, + `originalpath` varchar(300) NOT NULL, + `original_mimetype_id` int(11) NOT NULL, + `converted_mimetype_id` int(11) NOT NULL, + `thumbnail_mimetype_id` int(11) NOT NULL, + `uploaded_at` datetime NOT NULL, + `modified_at` datetime NOT NULL, + `reported_at` datetime default NULL, + `reported` int(8) NOT NULL default '0', + `total_reported_ever` int(8) NOT NULL default '0', + `marked_unsuitable` int(1) NOT NULL default '0', + `under_discussion` int(1) NOT NULL default '0', + `identifier` varchar(20) NOT NULL, + `hidden` int(1) NOT NULL default '0', + `deleted` int(11) default '0', + PRIMARY KEY (`id`), + KEY `reaktor_file_FI_1` (`user_id`) +) ENGINE=MyISAM AUTO_INCREMENT=14 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `reaktor_file` +-- + +LOCK TABLES `reaktor_file` WRITE; +/*!40000 ALTER TABLE `reaktor_file` DISABLE KEYS */; +INSERT INTO `reaktor_file` VALUES (1,'myimage.jpg',3,'image0044.jpg','image0044.jpg','image0044.jpg',2,2,2,'2008-02-10 12:54:08','2008-02-10 12:54:08',NULL,0,0,0,0,'image',0,0),(2,'mydoc.pdf',3,'1202926111_1__O__Reilly__PHP__Cookbook_.pdf','1202926111_1__O__Reilly__PHP__Cookbook_.pdf.jpg','1202926111_1__O__Reilly__PHP__Cookbook_.pdf',3,3,2,'2008-02-12 13:12:09','2008-02-12 13:12:09',NULL,0,0,0,0,'pdf',0,0),(3,'lovely.jpg',3,'1204733647_1_IMG_5382.JPG','1204733647_1_IMG_5382.JPG','1204733647_1_IMG_5382.JPG',2,2,2,'2007-01-01 01:01:54','2007-01-01 01:01:54',NULL,0,0,0,0,'image',0,0),(4,'wetbird.jpg',3,'1204735759_1_IMG_1252.jpg','1204735759_1_IMG_1252.jpg','1204735759_1_IMG_1252.jpg',2,2,2,'2007-02-01 01:01:54','2007-02-01 01:01:54',NULL,0,0,0,0,'image',0,0),(5,'fingers.flv',2,'fingers.flv','fingers.flv.jpg','fingers.flv',4,4,2,'2008-02-10 14:54:08','2008-02-10 14:54:08',NULL,0,0,0,0,'video',0,0),(6,'space-door.mp3',2,'space-door.mp3','space-door.mp3.jpg','space-door.mp3',5,5,2,'2008-02-10 14:54:09','2008-02-10 14:54:09',NULL,0,0,0,0,'audio',0,0),(7,'dolor_sit.txt',2,'dolor_sit.txt','dolor_sit.txt.jpg','dolor_sit.txt',9,9,2,'2008-02-20 13:10:17','2008-02-20 13:10:17',NULL,0,0,0,0,'text',0,0),(8,'abigail_frogner.jpg',3,'1204736133_1_IMG_3154x.jpg','1204736133_1_IMG_3154x.jpg','1204736133_1_IMG_3154x.jpg',2,2,2,'2007-03-01 01:01:54','2007-03-01 01:01:54',NULL,0,0,0,0,'image',0,0),(9,'IMG_0318.JPG',5,'1207596441_5_IMG_0318.JPG','1207596441_5_IMG_0318.JPG','1207596441_5_IMG_0318.JPG',2,2,2,'2008-04-07 21:27:23','2008-04-07 21:27:23',NULL,0,0,0,0,'image',0,0),(10,'IMG_0057c.jpg',5,'1207596762_5_IMG_0057c.jpg','1207596762_5_IMG_0057c.jpg','1207596762_5_IMG_0057c.jpg',2,2,2,'2008-04-07 21:32:43','2008-04-07 21:32:43','2008-04-08 22:14:10',6,24,0,0,'image',0,0),(11,'mcartoon.gif',6,'1210074241_1_mcartoon.gif','1210074241_1_mcartoon.gif','1210074241_1_mcartoon.gif',7,7,7,'2008-05-06 13:44:02','2008-05-06 13:44:02',NULL,0,0,0,0,'image',0,0),(12,'swindonRAB.jpg',6,'1210845302_6_swindonRAB.jpg','1210845302_6_swindonRAB.jpg','1210845302_6_swindonRAB.jpg',2,2,2,'2008-05-15 11:55:03','2008-05-15 11:55:03',NULL,0,0,0,0,'image',0,0),(13,'31D108EFB82DBA8654FD35499218B9A111B3E96792071F3DDCC0FE97FD4D517E.swf',2,'1216811137_2_31D108EFB82DBA8654FD35499218B9A111B3E96792071F3DDCC0FE97FD4D517E.swf','','1216811137_2_31D108EFB82DBA8654FD35499218B9A111B3E96792071F3DDCC0FE97FD4D517E.swf',6,6,5,'2008-07-23 13:05:38','2008-07-23 13:05:38',NULL,0,0,0,0,'flash_animation',0,0); +/*!40000 ALTER TABLE `reaktor_file` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `recommended_artwork` +-- + +DROP TABLE IF EXISTS `recommended_artwork`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `recommended_artwork` ( + `id` int(11) NOT NULL auto_increment, + `artwork` int(11) NOT NULL, + `subreaktor` int(11) NOT NULL, + `localsubreaktor` int(11) default NULL, + `updated_by` int(11) NOT NULL, + `updated_at` datetime default NULL, + PRIMARY KEY (`id`), + KEY `recommended_artwork_FI_1` (`artwork`), + KEY `recommended_artwork_FI_2` (`subreaktor`), + KEY `recommended_artwork_FI_3` (`localsubreaktor`), + KEY `recommended_artwork_FI_4` (`updated_by`) +) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `recommended_artwork` +-- + +LOCK TABLES `recommended_artwork` WRITE; +/*!40000 ALTER TABLE `recommended_artwork` DISABLE KEYS */; +INSERT INTO `recommended_artwork` VALUES (1,8,7,1,2,'2008-05-06 14:52:37'),(2,9,5,NULL,2,'2008-05-06 14:53:37'); +/*!40000 ALTER TABLE `recommended_artwork` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rejection_type` +-- + +DROP TABLE IF EXISTS `rejection_type`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `rejection_type` ( + `id` int(11) NOT NULL auto_increment, + `basename` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `rejection_type` +-- + +LOCK TABLES `rejection_type` WRITE; +/*!40000 ALTER TABLE `rejection_type` DISABLE KEYS */; +INSERT INTO `rejection_type` VALUES (1,'Copyright violation'),(2,'Unsuitable artwork content'),(3,'Question of ownership'),(4,'Unsuitable description of content'),(5,'Other'); +/*!40000 ALTER TABLE `rejection_type` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `rejection_type_i18n` +-- + +DROP TABLE IF EXISTS `rejection_type_i18n`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `rejection_type_i18n` ( + `id` int(11) NOT NULL, + `name` varchar(255) NOT NULL, + `description` text NOT NULL, + `culture` varchar(7) NOT NULL, + PRIMARY KEY (`id`,`culture`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `rejection_type_i18n` +-- + +LOCK TABLES `rejection_type_i18n` WRITE; +/*!40000 ALTER TABLE `rejection_type_i18n` DISABLE KEYS */; +INSERT INTO `rejection_type_i18n` VALUES (1,'Copyright violation','This artwork is a copyright violation, and will not be displayed on reaktor.','no'),(1,'Copyright violation','This artwork is a copyright violation, and will not be displayed on reaktor.','en'),(1,'Copyright violation','This artwork is a copyright violation, and will not be displayed on reaktor.','nn'),(2,'Unsuitable artwork content','This artwork has unsuitable content that Reaktor cannot display.','no'),(2,'Unsuitable artwork content','This artwork has unsuitable content that Reaktor cannot display.','en'),(2,'Unsuitable artwork content','This artwork has unsuitable content that Reaktor cannot display.','nn'),(3,'Question of ownership','There are evidence indicating you are not the correct author of this artwork.','no'),(3,'Question of ownership','There are evidence indicating you are not the correct author of this artwork.','en'),(3,'Question of ownership','There are evidence indicating you are not the correct author of this artwork.','nn'),(4,'Unsuitable description of content','Your description of the artwork is completely wrong.','no'),(4,'Unsuitable description of content','Your description of the artwork is completely wrong.','en'),(4,'Unsuitable description of content','Your description of the artwork is completely wrong.','nn'),(5,'Other','Your artwork has been rejected.','no'),(5,'Other','Your artwork has been rejected.','en'),(5,'Other','Your artwork has been rejected.','nn'); +/*!40000 ALTER TABLE `rejection_type_i18n` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `related_artwork` +-- + +DROP TABLE IF EXISTS `related_artwork`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `related_artwork` ( + `id` int(11) NOT NULL auto_increment, + `first_artwork` int(11) NOT NULL, + `second_artwork` int(11) NOT NULL, + `created_at` datetime NOT NULL, + `created_by` int(11) NOT NULL, + `order_by` int(11) default '0', + PRIMARY KEY (`id`), + KEY `related_artwork_FI_1` (`first_artwork`), + KEY `related_artwork_FI_2` (`second_artwork`), + KEY `related_artwork_FI_3` (`created_by`) +) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `related_artwork` +-- + +LOCK TABLES `related_artwork` WRITE; +/*!40000 ALTER TABLE `related_artwork` DISABLE KEYS */; +INSERT INTO `related_artwork` VALUES (1,1,3,'2008-05-06 15:51:44',4,0),(2,1,2,'2008-05-05 15:52:37',4,0),(3,2,3,'2008-05-06 14:52:37',4,0); +/*!40000 ALTER TABLE `related_artwork` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `report_bookmark` +-- + +DROP TABLE IF EXISTS `report_bookmark`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `report_bookmark` ( + `id` int(11) NOT NULL auto_increment, + `title` varchar(255) NOT NULL, + `description` text NOT NULL, + `args` text NOT NULL, + `type` varchar(10) NOT NULL default 'artwork', + `list_order` int(11) default '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=18 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `report_bookmark` +-- + +LOCK TABLES `report_bookmark` WRITE; +/*!40000 ALTER TABLE `report_bookmark` DISABLE KEYS */; +INSERT INTO `report_bookmark` VALUES (1,'All approved','All approved artworks - no other filters applied','subreaktor_id=1&category_id=17&tags=&editorial_team_id=5&editorial_team_member_id=1&status_check=1&status_value=3&from_date[day]=&from_date[month]=&from_date[year]=&to_date[day]=&to_date[month]=&to_date[year]=&commit=Generate+report','artwork',0),(2,'All rejected','All rejected artwork - no other filters applied','subreaktor_id=1&category_id=17&tags=&editorial_team_id=5&editorial_team_member_id=1&status_check=1&status_value=4&from_date[day]=&from_date[month]=&from_date[year]=&to_date[day]=&to_date[month]=&to_date[year]=&commit=Generate+report','artwork',2),(3,'All under discussion','All artwork that is currently marked under discussion','subreaktor_id=1&category_id=17&tags=&editorial_team_id=5&editorial_team_member_id=1&status_value=4&under_discussion_check=1&from_date[day]=&from_date[month]=&from_date[year]=&to_date[day]=&to_date[month]=&to_date[year]=&commit=Generate+report','artwork',1),(4,'All awaiting approval','All artwork that is currently submitted for approval','subreaktor_id=1&category_id=17&tags=&editorial_team_id=5&editorial_team_member_id=1&status_check=1&status_value=2&from_date[day]=&from_date[month]=&from_date[year]=&to_date[day]=&to_date[month]=&to_date[year]=&commit=Generate+report','artwork',5),(5,'All this month','Artworks that have been submitted in the current month (dynamic)','subreaktor_id=1&category_id=17&tags=&editorial_team_id=5&editorial_team_member_id=1&status_value=2&from_date%5Bday%5D=&from_date%5Bmonth%5D=&from_date%5Byear%5D=&to_date%5Bday%5D=&to_date%5Bmonth%5D=&to_date%5Byear%5D=¤t_month_check=1&commit=Generate+report','artwork',0),(6,'Awaiting approval in Tekst','Artwork in tekst subreaktor that has been submitted and is awaiting approval','subreaktor_check=1&subreaktor_id=6&category_id=17&tags=&editorial_team_id=5&editorial_team_member_id=1&status_check=1&status_value=2&from_date%5Bday%5D=&from_date%5Bmonth%5D=&from_date%5Byear%5D=&to_date%5Bday%5D=&to_date%5Bmonth%5D=&to_date%5Byear%5D=&commit=Generate+report','artwork',3),(7,'All registered users','This report will return all the registered users on the system, regardless of status','residence=1&interest=0&sex=0&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=&commentAndOr=0&voteAndOr=0&commit=Generate+report&execute=userReport','user',1),(8,'All registered this month','All the users that have registered this month (dynamic)','residence=1&interest=0&sex=0&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=¤t_month_check=1&commentAndOr=0&voteAndOr=0&commit=Generate+report&execute=userReport','user',2),(9,'Active uploaders this month','The users that have been most active when uploading content this month','reportType=0&subreaktor=0&sex=0&startActivityDate%5Bday%5D=&startActivityDate%5Bmonth%5D=&startActivityDate%5Byear%5D=&endActivityDate%5Bday%5D=&endActivityDate%5Bmonth%5D=&endActivityDate%5Byear%5D=&commit=Generate+report&execute=activityReport','user',3),(10,'Most comments this month','The users that have been most active at commenting this month','reportType=1&subreaktor=0&sex=0&startActivityDate%5Bday%5D=&startActivityDate%5Bmonth%5D=&startActivityDate%5Byear%5D=&endActivityDate%5Bday%5D=&endActivityDate%5Bmonth%5D=&endActivityDate%5Byear%5D=¤t_month_activity_check=1&commit=Generate+report&execute=activityReport','user',4),(11,'Active users','Users that have commented or written comments or uploaded','residence=1&interest=0&sex=0&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=&publishedArtwork=1&commentAndOr=0&commentedArtwork=1&voteAndOr=0&voted=1&commit=Generate+report&execute=userReport','user',5),(12,'Passive users','Users that have not uploaded, commented or voted','residence=1&interest=0&sex=0&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=¬PublishedArtwork=1&commentAndOr=1¬CommentedArtwork=1&voteAndOr=1¬Voted=1&commit=Generate+report&execute=userReport','user',6),(13,'Active non-uploaders','Users who have commented and voted but have not published anything','residence=1&interest=0&sex=0&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=¬PublishedArtwork=1&commentAndOr=1&commentedArtwork=1&voteAndOr=1&voted=1&commit=Generate+report&execute=userReport','user',7),(14,'Super-active male users','Male users that have uploaded, commented and voted','residence=1&interest=0&sex_check=1&sex=1&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=&publishedArtwork=1&commentAndOr=1&commentedArtwork=1&voteAndOr=1&voted=1&commit=Generate+report&execute=userReport','user',8),(15,'Super-active Female users','Female users that have uploaded, commented and voted','residence=1&interest=0&sex_check=1&sex=2&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=&publishedArtwork=1&commentAndOr=1&commentedArtwork=1&voteAndOr=1&voted=1&commit=Generate+report&execute=userReport','user',0),(16,'Active female users','Female users that have commented, uploaded or voted','residence=1&interest=0&sex_check=1&sex=2&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=&publishedArtwork=1&commentAndOr=0&commentedArtwork=1&voteAndOr=0&voted=1&commit=Generate+report&execute=userReport','user',0),(17,'Active male users','Male users that have commented, voted or uploaded','residence=1&interest=0&sex_check=1&sex=1&startDateArr%5Bday%5D=&startDateArr%5Bmonth%5D=&startDateArr%5Byear%5D=&endDateArr%5Bday%5D=&endDateArr%5Bmonth%5D=&endDateArr%5Byear%5D=&publishedArtwork=1&commentAndOr=0&commentedArtwork=1&voteAndOr=0&voted=1&commit=Generate+report&execute=userReport','user',0); +/*!40000 ALTER TABLE `report_bookmark` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `residence` +-- + +DROP TABLE IF EXISTS `residence`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `residence` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(255) NOT NULL, + `level` int(11) NOT NULL, + `parent` int(11) default NULL, + PRIMARY KEY (`id`), + KEY `residence_FI_1` (`level`) +) ENGINE=MyISAM AUTO_INCREMENT=27 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `residence` +-- + +LOCK TABLES `residence` WRITE; +/*!40000 ALTER TABLE `residence` DISABLE KEYS */; +INSERT INTO `residence` VALUES (1,'Akershus',4,NULL),(2,'Aust-Agder',4,NULL),(3,'Buskerud',4,NULL),(4,'Finnmark',4,NULL),(5,'Hedmark',4,NULL),(6,'Hordaland',4,NULL),(7,'Møre og Romsdal',4,NULL),(8,'Nordland',4,NULL),(9,'Nord-Trøndelag',4,NULL),(10,'Oppland',4,NULL),(11,'Rogaland',4,NULL),(12,'Sogn og Fjordane',4,NULL),(13,'Sør-Trøndelag',4,NULL),(14,'Telemark',4,NULL),(15,'Troms',4,NULL),(16,'Vest-Agder',4,NULL),(17,'Vestfold',4,NULL),(18,'Østfold',4,NULL),(19,'Bergen',2,NULL),(20,'Groruddalen',1,NULL),(21,'Kristiansand',2,NULL),(22,'Lillehammer',2,NULL),(23,'Oslo',2,NULL),(24,'Stavanger',2,NULL),(25,'Tromsø',2,NULL),(26,'Trondheim',2,NULL); +/*!40000 ALTER TABLE `residence` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `residence_level` +-- + +DROP TABLE IF EXISTS `residence_level`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `residence_level` ( + `id` int(11) NOT NULL auto_increment, + `levelname` varchar(255) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `residence_level` +-- + +LOCK TABLES `residence_level` WRITE; +/*!40000 ALTER TABLE `residence_level` DISABLE KEYS */; +INSERT INTO `residence_level` VALUES (1,'Bydel'),(2,'By'),(3,'Kommune'),(4,'Fylke'); +/*!40000 ALTER TABLE `residence_level` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `residence_level_i18n` +-- + +DROP TABLE IF EXISTS `residence_level_i18n`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `residence_level_i18n` ( + `name` varchar(255) NOT NULL, + `id` int(11) NOT NULL, + `culture` varchar(7) NOT NULL, + PRIMARY KEY (`id`,`culture`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `residence_level_i18n` +-- + +LOCK TABLES `residence_level_i18n` WRITE; +/*!40000 ALTER TABLE `residence_level_i18n` DISABLE KEYS */; +INSERT INTO `residence_level_i18n` VALUES ('Bydel',1,'no'),('District',1,'en'),('Bydel',1,'nn'),('By',2,'no'),('City',2,'en'),('By',2,'nn'),('Kommune',3,'no'),('Municipality',3,'en'),('Kommune',3,'nn'),('Fylke',4,'no'),('County',4,'en'),('Fylkje',4,'nn'); +/*!40000 ALTER TABLE `residence_level_i18n` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_comment` +-- + +DROP TABLE IF EXISTS `sf_comment`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_comment` ( + `id` int(11) NOT NULL auto_increment, + `parent_id` int(11) default NULL, + `commentable_model` varchar(30) default NULL, + `commentable_id` int(11) default NULL, + `namespace` varchar(50) default NULL, + `title` text, + `text` text, + `author_id` int(11) NOT NULL, + `author_name` varchar(50) default NULL, + `author_email` varchar(100) default NULL, + `created_at` datetime default NULL, + `unsuitable` int(11) NOT NULL default '0', + `email_notify` int(11) NOT NULL default '0', + PRIMARY KEY (`id`), + KEY `comments_index` (`namespace`,`commentable_model`,`commentable_id`), + KEY `object_index` (`commentable_model`,`commentable_id`), + KEY `author_index` (`author_id`) +) ENGINE=MyISAM AUTO_INCREMENT=21 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_comment` +-- + +LOCK TABLES `sf_comment` WRITE; +/*!40000 ALTER TABLE `sf_comment` DISABLE KEYS */; +INSERT INTO `sf_comment` VALUES (1,NULL,'ReaktorArtwork',1,'frontend','Something I made','She made me giggle when I saw her :D',3,NULL,NULL,'2008-04-07 13:18:36',0,0),(2,NULL,'ReaktorArtwork',3,'frontend','Nice PDF?','Anybody like my PDF?\n\nbøøøøøøøø',3,NULL,NULL,'2008-04-07 13:19:10',0,0),(3,NULL,'ReaktorArtwork',2,'frontend','This is a very fancy gallery, no?','Looks like I\'m the only person making comments then :(',3,NULL,NULL,'2008-04-07 13:19:45',0,0),(4,NULL,'ReaktorArtwork',4,'frontend','Hey Monkey!','Nice Vid :D\n\nI especially like the fingers',3,NULL,NULL,'2008-04-07 13:20:13',0,0),(5,4,'ReaktorArtwork',4,'frontend','Haha','Cheers Monkey',2,NULL,NULL,'2008-04-07 13:21:16',0,0),(6,NULL,'ReaktorArtwork',4,'frontend','My note... !','Personally, I like the way the fingers are all the same length... !',2,NULL,NULL,'2008-04-07 13:21:38',0,0),(7,NULL,'ReaktorArtwork',2,'frontend','Sheesh','Calm down Userboy... there aren\'t exactly a flood of visiors yet are there?\n\nGive it time... God Påske!',2,NULL,NULL,'2008-04-07 13:22:27',0,0),(8,NULL,'ReaktorArtwork',3,'frontend','Huh?','It\'s just a pdf... calm down.\n\nåøæøåøæøå <--- Random :D',2,NULL,NULL,'2008-04-07 13:23:02',0,0),(9,NULL,'ReaktorArtwork',5,'frontend','Music to my ears','hmm... !',2,NULL,NULL,'2008-04-07 13:23:44',0,0),(10,NULL,'ReaktorArtwork',7,'frontend','Like my monkeys?','I do!',5,NULL,NULL,'2008-04-07 21:28:17',0,0),(11,NULL,'ReaktorArtwork',2,'frontend','Great','Great picture mate!',5,NULL,NULL,'2008-04-07 21:28:39',0,0),(12,NULL,'ReaktorArtwork',4,'frontend','WTF','I mean seriously, wtf?',5,NULL,NULL,'2008-04-07 21:29:06',1,0),(13,4,'ReaktorArtwork',4,'frontend','Not me','I have to disagree... they freak me out',5,NULL,NULL,'2008-04-07 21:29:23',0,0),(14,NULL,'ReaktorArtwork',2,'frontend','Wow','I love this pic mate! Nice one... !',5,NULL,NULL,'2008-04-07 21:30:18',0,0),(15,7,'ReaktorArtwork',2,'frontend','huh?','God what?',5,NULL,NULL,'2008-04-07 21:30:35',1,0),(16,NULL,'ReaktorArtwork',3,'frontend','What?','I come looking for porn and all I get is a lousy PDF :(\n\nI must say I am disappointed... !',5,NULL,NULL,'2008-04-07 21:32:35',0,0),(17,NULL,'ReaktorArtwork',3,'frontend','C1alis at net prices','Please your woman today!',5,NULL,NULL,'2008-05-07 13:15:15',2,0),(18,2,'ReaktorArtwork',3,'frontend','Short in bed?','Go to myenlargement.ru and give your p3n1s a lift!',5,NULL,NULL,'2008-05-07 13:15:15',1,0),(19,2,'ReaktorArtwork',3,'frontend','I hate Colin','Colin is nothing but a spongy stack of vapid grits',5,NULL,NULL,'2008-04-07 12:15:15',1,0),(20,NULL,'ReaktorArtwork',2,'administrator','A comment','I just wanted to comment',1,NULL,NULL,'2008-07-11 11:24:10',0,0); +/*!40000 ALTER TABLE `sf_comment` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_guard_group` +-- + +DROP TABLE IF EXISTS `sf_guard_group`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_guard_group` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(255) NOT NULL, + `description` text, + `is_editorial_team` int(11) default '0', + `is_enabled` int(11) default '0', + PRIMARY KEY (`id`), + UNIQUE KEY `sf_guard_group_name_unique` (`name`) +) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_guard_group` +-- + +LOCK TABLES `sf_guard_group` WRITE; +/*!40000 ALTER TABLE `sf_guard_group` DISABLE KEYS */; +INSERT INTO `sf_guard_group` VALUES (1,'admin','Administrator group',0,0),(2,'users','Normal users who can interact on the site',0,0),(3,'staff','Staff group',0,0),(4,'translators','Translator group',0,0),(11,'publishers','Publisher group',0,0); +/*!40000 ALTER TABLE `sf_guard_group` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_guard_group_permission` +-- + +DROP TABLE IF EXISTS `sf_guard_group_permission`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_guard_group_permission` ( + `group_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + PRIMARY KEY (`group_id`,`permission_id`), + KEY `sf_guard_group_permission_FI_2` (`permission_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_guard_group_permission` +-- + +LOCK TABLES `sf_guard_group_permission` WRITE; +/*!40000 ALTER TABLE `sf_guard_group_permission` DISABLE KEYS */; +INSERT INTO `sf_guard_group_permission` VALUES (1,1),(1,2),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10),(1,11),(1,12),(1,13),(1,14),(1,15),(1,16),(1,17),(1,18),(1,19),(1,20),(1,21),(1,22),(1,23),(1,24),(1,25),(1,26),(1,27),(1,28),(1,29),(1,30),(1,31),(1,32),(1,33),(1,34),(1,35),(1,36),(1,37),(1,38),(1,39),(1,40),(1,41),(1,42),(1,43),(1,44),(1,45),(2,8),(2,15),(2,24),(2,30),(2,31),(2,32),(2,33),(2,34),(2,35),(2,36),(3,1),(3,8),(3,12),(3,13),(3,15),(3,19),(3,25),(3,26),(3,29),(3,30),(3,31),(3,32),(3,33),(3,34),(3,35),(3,36),(3,37),(3,38),(3,39),(3,40),(4,23),(5,14),(5,17),(5,18),(5,27),(5,36),(5,40),(5,42),(5,45),(6,14),(6,17),(6,18),(6,27),(6,36),(6,40),(6,42),(6,45),(7,14),(7,17),(7,18),(7,27),(7,36),(7,40),(7,42),(7,45),(8,14),(8,17),(8,18),(8,27),(8,36),(8,40),(8,42),(8,45),(9,14),(9,17),(9,18),(9,27),(9,36),(9,40),(9,42),(9,45),(10,14),(10,17),(10,18),(10,27),(10,36),(10,40),(10,42),(10,45),(11,43),(11,44); +/*!40000 ALTER TABLE `sf_guard_group_permission` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_guard_permission` +-- + +DROP TABLE IF EXISTS `sf_guard_permission`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_guard_permission` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `sf_guard_permission_name_unique` (`name`) +) ENGINE=MyISAM AUTO_INCREMENT=46 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_guard_permission` +-- + +LOCK TABLES `sf_guard_permission` WRITE; +/*!40000 ALTER TABLE `sf_guard_permission` DISABLE KEYS */; +INSERT INTO `sf_guard_permission` VALUES (1,'staff'),(2,'listgroup'),(3,'editgroup'),(4,'deletegroup'),(5,'listpermission'),(6,'editpermission'),(7,'deletepermission'),(8,'listuser'),(9,'edituser'),(10,'deleteuser'),(11,'editprofile'),(12,'viewallcontent'),(13,'viewdetailederrors'),(14,'editusercontent'),(15,'isuser'),(16,'deletecontent'),(17,'approveartwork'),(18,'approvetags'),(19,'commentadmin'),(20,'tagadministrator'),(21,'subreaktoradministrator'),(22,'subreaktorcategorizer'),(23,'translator'),(24,'viewmetadata'),(25,'debug'),(26,'discussartwork'),(27,'recommendartwork'),(28,'sendcommentstoall'),(29,'adminmessages'),(30,'postnewcomments'),(31,'uploadcontent'),(32,'sendmessages'),(33,'rateartwork'),(34,'markfavourite'),(35,'addresources'),(36,'reruntranscoding'),(37,'createresidence'),(38,'deleteresidence'),(39,'listresidences'),(40,'viewreports'),(41,'phpmyadmin'),(42,'editcategories'),(43,'edit_articles'),(44,'publish_articles'),(45,'createcompositeartwork'); +/*!40000 ALTER TABLE `sf_guard_permission` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_guard_permission_i18n` +-- + +DROP TABLE IF EXISTS `sf_guard_permission_i18n`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_guard_permission_i18n` ( + `description` text NOT NULL, + `id` int(11) NOT NULL, + `culture` varchar(7) NOT NULL, + PRIMARY KEY (`id`,`culture`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_guard_permission_i18n` +-- + +LOCK TABLES `sf_guard_permission_i18n` WRITE; +/*!40000 ALTER TABLE `sf_guard_permission_i18n` DISABLE KEYS */; +INSERT INTO `sf_guard_permission_i18n` VALUES ('Show admin links such as moderator box and admin portal',1,'en'),('Can list/view groups',2,'en'),('Can edit groups',3,'en'),('Can delete groups',4,'en'),('Can list/view permissions',5,'en'),('Can edit permissions',6,'en'),('Can delete permissions',7,'en'),('Can list/view users',8,'en'),('Can edit users',9,'en'),('Can delete users',10,'en'),('Can edit any users profile',11,'en'),('Can view all content, including unmoderated',12,'en'),('Will see enhanced error messages where available',13,'en'),('Can edit file/artwork details',14,'en'),('Is a registered user (used for yml checks)',15,'en'),('Can delete files from the system',16,'en'),('Can approve artworks',17,'en'),('Can approve and delete tags on artworks',18,'en'),('Can administer comments',19,'en'),('Can remove tags from the system',20,'en'),('Can add/remove/edit subreaktors',21,'en'),('Can add/remove/edit subreaktor tags',22,'en'),('Can access the translation interface',23,'en'),('Can view artwork/file metadata',24,'en'),('Can view extra debug information on the site',25,'en'),('Can view and discuss artwork under discussion',26,'en'),('Can mark artwork as recommended',27,'en'),('Can send comments to all users',28,'en'),('Can create admin messages',29,'en'),('Can post new comments',30,'en'),('Can upload new content',31,'en'),('Can send messages to other users',32,'en'),('Can rate artwork',33,'en'),('Can mark users or artworks as favourites',34,'en'),('Can add resources to their profile',35,'en'),('Can re-run transcoding if failed',36,'en'),('Can add a new residence',37,'en'),('Can delete a residence',38,'en'),('Can list all residences',39,'en'),('Can view and create reports',40,'en'),('Can use PHPMyAdmin with read only user',41,'en'),('Can add/remove categories on all artwork',42,'en'),('Can edit articles',43,'en'),('Can publish articles',44,'en'),('can create multi-user composite artwork',45,'en'),('Tilgang til å se admin-meny og moderator-boks, samt admin-portalen',1,'no'),('Kan se liste over brukergrupper og redaksjoner',2,'no'),('Kan redigere brukergrupper og redaksjoner',3,'no'),('Kan slette brukergrupper og redaksjoner',4,'no'),('Kan se liste over tilganger',5,'no'),('Kan redigere tilganger',6,'no'),('Kan slette tilganger',7,'no'),('Kan se liste over alle brukere',8,'no'),('Kan redigere brukere via admin-grensesnittet',9,'no'),('Kan slette enkeltbrukere',10,'no'),('Kan redigere brukeres profil',11,'no'),('Kan se alle verk, inkludert ikke-godkjente verk',12,'no'),('Får ekstra detaljerte feilmeldinger der disse er tilgjengelig',13,'no'),('Kan redigere alle verk og filer',14,'no'),('Er en registrert bruker (må være på alle grupper)',15,'no'),('Kan slette filer fullstendig',16,'no'),('Har generell tilgang til å redigere og moderere verk',17,'no'),('Kan moderere tagger på verk (fjerne fra verk + godkjenne)',18,'no'),('Kan redigere og moderere kommentarer',19,'no'),('Kan fjerne tagger fra systemet',20,'no'),('Kan redigere (endre, slette, legge til) subReaktorer',21,'no'),('Kan redigere (endre, slette, legge til) tagger på subReaktorer',22,'no'),('Har tilgang til grensesnittet for oversetting',23,'no'),('Kan se metadata på verk via egen side for metadata',24,'no'),('Får se debuggings-informasjon (kun til bruk ved problemer)',25,'no'),('Kan diskutere verk og se verk under diskusjon',26,'no'),('Kan anbefale verk i subReaktorer og på forsiden',27,'no'),('Kan sende meldinger til flere brukere samtidig',28,'no'),('Kan poste admin-meldinger',29,'no'),('Kan kommentere verk',30,'no'),('Kan laste opp filer og lage verk',31,'no'),('Kan sende meldinger til andre brukere',32,'no'),('Kan gi karakter på verk',33,'no'),('Kan merke brukere og verk som sine favoritter',34,'no'),('Kan lagre ressurser på \"Min side\"',35,'no'),('Kan kjøre transkoding på nytt ved feil',36,'no'),('Kan opprette nye bosted som brukere kan velge i sin profil',37,'no'),('Kan fjerne bosted fra systemet',38,'no'),('Kan se liste over alle bosteder',39,'no'),('Kan generere rapporter og lagre nye hurtigrapporter',40,'no'),('Har tilgang til PHPMyAdmin',41,'no'),('Kan redigere (legge til, fjerne) kategorier på verk',42,'no'),('Kan redigere og opprette artikler',43,'no'),('Kan publisere artikler',44,'no'),('Kan opprette sammensatte verk med filer fra flere brukere',45,'no'); +/*!40000 ALTER TABLE `sf_guard_permission_i18n` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_guard_remember_key` +-- + +DROP TABLE IF EXISTS `sf_guard_remember_key`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_guard_remember_key` ( + `user_id` int(11) NOT NULL, + `remember_key` varchar(32) default NULL, + `ip_address` varchar(15) NOT NULL, + `created_at` datetime default NULL, + PRIMARY KEY (`user_id`,`ip_address`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_guard_remember_key` +-- + +LOCK TABLES `sf_guard_remember_key` WRITE; +/*!40000 ALTER TABLE `sf_guard_remember_key` DISABLE KEYS */; +/*!40000 ALTER TABLE `sf_guard_remember_key` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_guard_user` +-- + +DROP TABLE IF EXISTS `sf_guard_user`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_guard_user` ( + `id` int(11) NOT NULL auto_increment, + `username` varchar(128) NOT NULL, + `algorithm` varchar(128) NOT NULL default 'sha1', + `salt` varchar(128) NOT NULL, + `password` varchar(128) NOT NULL, + `created_at` datetime default NULL, + `last_login` datetime default NULL, + `is_active` int(11) NOT NULL default '1', + `is_super_admin` int(11) NOT NULL default '0', + `is_verified` int(11) default '0', + `show_content` int(11) default '0', + `culture` varchar(10) default 'no', + `email` varchar(128) NOT NULL, + `email_private` int(11) default '1', + `new_email` varchar(128) default NULL, + `new_email_key` varchar(128) default NULL, + `new_password_key` varchar(128) default NULL, + `key_expires` datetime default NULL, + `name` varchar(128) default NULL, + `name_private` int(11) default '0', + `dob` date default NULL, + `sex` int(1) NOT NULL, + `description` longblob, + `residence_id` int(11) NOT NULL, + `avatar` varchar(255) default NULL, + `msn` varchar(128) default NULL, + `icq` int(11) default NULL, + `homepage` varchar(256) default NULL, + `phone` varchar(32) default NULL, + `opt_in` int(11) default '0', + `editorial_notification` int(11) default '0', + `show_login_status` int(11) default '1', + PRIMARY KEY (`id`), + UNIQUE KEY `sf_guard_user_username_unique` (`username`), + KEY `sf_guard_user_FI_1` (`residence_id`) +) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_guard_user` +-- + +LOCK TABLES `sf_guard_user` WRITE; +/*!40000 ALTER TABLE `sf_guard_user` DISABLE KEYS */; +INSERT INTO `sf_guard_user` VALUES (1,'admin','sha1','a9c1d211a340efcb03bd663b9edd0457','07cd197ef0808b66fe10f38ce08f8c3d7408a407','2008-03-05 18:30:37','2008-03-05 23:16:00',1,1,1,1,'no','reaktor-test@linpro.no',1,NULL,NULL,NULL,NULL,'admin',0,'1980-01-01',2,'Hest er best',1,NULL,'reaktor@msn.no',54321,'http://reaktor.lab.linpro.no',NULL,0,0,1),(2,'monkeyboy','sha1','f4fb213bc7db3c0bb024caa05efb898f','bf635d43c34970345c8ee3f2a79db9f18a5af521','2008-03-05 18:30:37',NULL,1,0,1,1,'no','monkeyboy@linpro.no',1,NULL,NULL,NULL,NULL,'monkey johns son',0,'1990-12-24',1,'Monkey is the name, coding is the game. Now - choose your weapon!',4,NULL,'monkeyboy@hotmail.com',55323,'http://reaktor.lab.linpro.no',NULL,1,0,1),(3,'userboy','sha1','cd925dd06bedf99cf73ae702762c9c43','1ea75378afccb7303160b2a6a90b57de6c68abb5','2008-03-05 18:30:37',NULL,1,0,1,1,'no','userboy@linpro.no',1,NULL,NULL,NULL,NULL,'User Boy',0,'2000-03-08',1,'I am a normal user, no groups or priveledges whatsoever <|:o(8',6,NULL,'userboy@hotmail.com',123456,'http://reaktor.lab.linpro.no',NULL,1,0,1),(4,'leo','sha1','9a6c5f26d4959f07208d80195f0fe68a','c04408a077d03b27f32f55f997f070fd0a76a6df','2008-03-05 18:30:37',NULL,1,0,1,1,'no','anne-lena.westrum@kie.oslo.kommune.no',1,NULL,NULL,NULL,NULL,'Anne-Lena Westrum',0,'1977-04-20',2,'I\'m the owner don\'t you know :)',4,NULL,NULL,NULL,'http://minreaktor.no',NULL,1,0,1),(5,'Kerry','sha1','bfd44fa271d570737be1d2a5fcbfe094','bbef4efab29791913bd637695ec7b8509a684b89','2008-04-07 21:00:00',NULL,1,0,1,1,'no','kerry@nowhere.com',0,NULL,NULL,NULL,NULL,'Kerry',1,'1979-07-02',2,'Just Kerry',2,NULL,NULL,NULL,'http://kerry.com',NULL,1,0,1),(6,'dave','sha1','0f94492baa6ec642330e13934bb94b4d','5665080c0f0be56cf55943b63617a3441d3eb7cb','2008-04-07 22:00:00',NULL,1,0,1,0,'no','dave@nowhere.com',1,NULL,NULL,NULL,NULL,'Dave',1,'1979-07-02',2,'Just Dave',7,NULL,NULL,NULL,'http://dave.com',NULL,0,0,1),(7,'languageboy','sha1','36792f1b1e8d666d2262efb8b76eeacf','952c926e015b45732cb6b2c9aa50340a5f10c2bc','2008-05-08 13:45:00',NULL,1,0,1,1,'no','languageboy@nowhere.com',1,NULL,NULL,NULL,NULL,'Language boy',1,'1979-07-02',1,'I am the LANGUAGE BOY!',7,NULL,NULL,NULL,'http://google.com/translate',NULL,0,0,1),(8,'editorialboy1','sha1','969d9a980c10364a966e0f328cc2b4d0','5c93a233e646b866af07a146dd4e3ccce4f481d0','2008-05-08 13:45:00',NULL,1,0,1,1,'no','reaktor-editorialboy1@linpro.no',1,NULL,NULL,NULL,NULL,'Ed I. Torialboy',1,'1973-12-12',1,'I am ED I. TORIALBOY!',7,NULL,NULL,NULL,'http://vg.no',NULL,0,0,1),(9,'editorialboy2','sha1','faf65f1e1d9e2d76b037e3297abf1648','32691da19ed1af2894e6b9d6fb7c51593b0b1def','2008-05-08 13:45:00',NULL,1,0,1,1,'no','reaktor-editorialboy2@linpro.no',1,NULL,NULL,NULL,NULL,'Ed I. Torialboy II',1,'1973-12-12',1,'I am ED I. TORIALBOY II!',7,NULL,NULL,NULL,'http://vg.no',NULL,0,0,1),(10,'editorialboy3','sha1','22b9040b348aaf897eaa07479b23d8d1','425b03b6f51a24bf0e8cc6d644c853b8cf049748','2008-05-08 13:45:00',NULL,1,0,1,1,'no','reaktor-editorialboy3@linpro.no',1,NULL,NULL,NULL,NULL,'Ed I. Torialboy III',1,'1973-12-12',1,'I am ED I. TORIALBOY III!',7,NULL,NULL,NULL,'http://vg.no',NULL,0,0,1),(11,'articleboy','sha1','8eef1cf1c3f7beed00b81b3d6d7f96d9','243f37b6a190443304969ae1cdaae53054abcfcd','2008-05-08 13:45:00',NULL,1,0,1,1,'no','reaktor-articleboy@linpro.no',1,NULL,NULL,NULL,NULL,'Article Boy',1,'1973-12-12',1,'I am Article Boy! Bow before me!',5,NULL,NULL,NULL,'http://dagbladet.no',NULL,0,0,1); +/*!40000 ALTER TABLE `sf_guard_user` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_guard_user_group` +-- + +DROP TABLE IF EXISTS `sf_guard_user_group`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_guard_user_group` ( + `user_id` int(11) NOT NULL, + `group_id` int(11) NOT NULL, + PRIMARY KEY (`user_id`,`group_id`), + KEY `sf_guard_user_group_FI_2` (`group_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_guard_user_group` +-- + +LOCK TABLES `sf_guard_user_group` WRITE; +/*!40000 ALTER TABLE `sf_guard_user_group` DISABLE KEYS */; +INSERT INTO `sf_guard_user_group` VALUES (1,1),(1,3),(1,4),(1,5),(1,6),(1,7),(1,8),(1,9),(1,10),(1,11),(2,2),(3,2),(4,2),(5,2),(6,2),(7,2),(7,4),(8,2),(8,3),(8,5),(8,6),(8,7),(9,3),(9,8),(10,3),(10,11),(11,3),(11,11); +/*!40000 ALTER TABLE `sf_guard_user_group` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_guard_user_permission` +-- + +DROP TABLE IF EXISTS `sf_guard_user_permission`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_guard_user_permission` ( + `user_id` int(11) NOT NULL, + `permission_id` int(11) NOT NULL, + `exclude` int(11) default '0', + PRIMARY KEY (`user_id`,`permission_id`), + KEY `sf_guard_user_permission_FI_2` (`permission_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_guard_user_permission` +-- + +LOCK TABLES `sf_guard_user_permission` WRITE; +/*!40000 ALTER TABLE `sf_guard_user_permission` DISABLE KEYS */; +/*!40000 ALTER TABLE `sf_guard_user_permission` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `sf_ratings` +-- + +DROP TABLE IF EXISTS `sf_ratings`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `sf_ratings` ( + `id` int(11) NOT NULL auto_increment, + `ratable_model` varchar(50) NOT NULL, + `ratable_id` int(11) NOT NULL, + `user_id` int(11) default NULL, + `rating` int(11) NOT NULL default '1', + `rated_at` datetime NOT NULL, + PRIMARY KEY (`id`), + KEY `ratable_index` (`ratable_model`,`ratable_id`,`user_id`) +) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `sf_ratings` +-- + +LOCK TABLES `sf_ratings` WRITE; +/*!40000 ALTER TABLE `sf_ratings` DISABLE KEYS */; +INSERT INTO `sf_ratings` VALUES (1,'ReaktorArtwork',4,3,4,'0000-00-00 00:00:00'),(2,'ReaktorArtwork',3,2,3,'0000-00-00 00:00:00'),(3,'ReaktorArtwork',2,2,6,'0000-00-00 00:00:00'),(4,'ReaktorArtwork',4,5,5,'0000-00-00 00:00:00'),(5,'ReaktorArtwork',2,5,5,'0000-00-00 00:00:00'),(6,'ReaktorArtwork',3,5,4,'0000-00-00 00:00:00'); +/*!40000 ALTER TABLE `sf_ratings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `subreaktor` +-- + +DROP TABLE IF EXISTS `subreaktor`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `subreaktor` ( + `id` int(11) NOT NULL auto_increment, + `reference` varchar(15) NOT NULL, + `lokalreaktor` int(11) NOT NULL default '0', + `live` int(11) NOT NULL default '0', + `subreaktor_order` int(11) default '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `subreaktor` +-- + +LOCK TABLES `subreaktor` WRITE; +/*!40000 ALTER TABLE `subreaktor` DISABLE KEYS */; +INSERT INTO `subreaktor` VALUES (1,'foto',0,1,1),(2,'tegning',0,1,2),(3,'film',0,1,3),(4,'lyd',0,1,4),(5,'tegneserier',0,1,5),(6,'tekst',0,1,6),(7,'groruddalen',1,1,7); +/*!40000 ALTER TABLE `subreaktor` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `subreaktor_artwork` +-- + +DROP TABLE IF EXISTS `subreaktor_artwork`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `subreaktor_artwork` ( + `id` int(11) NOT NULL auto_increment, + `subreaktor_id` int(11) NOT NULL, + `artwork_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `subreaktor_artwork_FI_1` (`subreaktor_id`), + KEY `subreaktor_artwork_FI_2` (`artwork_id`) +) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `subreaktor_artwork` +-- + +LOCK TABLES `subreaktor_artwork` WRITE; +/*!40000 ALTER TABLE `subreaktor_artwork` DISABLE KEYS */; +INSERT INTO `subreaktor_artwork` VALUES (1,1,1),(2,1,2),(3,1,7),(4,1,8),(5,5,9),(6,6,3),(7,3,4),(8,4,5),(9,6,6),(10,2,10),(11,3,11); +/*!40000 ALTER TABLE `subreaktor_artwork` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `subreaktor_i18n` +-- + +DROP TABLE IF EXISTS `subreaktor_i18n`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `subreaktor_i18n` ( + `name` varchar(255) NOT NULL, + `id` int(11) NOT NULL, + `culture` varchar(7) NOT NULL, + PRIMARY KEY (`id`,`culture`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `subreaktor_i18n` +-- + +LOCK TABLES `subreaktor_i18n` WRITE; +/*!40000 ALTER TABLE `subreaktor_i18n` DISABLE KEYS */; +INSERT INTO `subreaktor_i18n` VALUES ('Foto',1,'no'),('Foto',1,'nn'),('Photo',1,'en'),('Tegning/grafikk',2,'no'),('Tegning/grafikk',2,'nn'),('Drawing/graphics',2,'en'),('Film/animasjon',3,'no'),('Film/animasjon',3,'nn'),('Movie/animation',3,'en'),('Lyd/musikk',4,'no'),('Lyd/musikk',4,'nn'),('Sound/music',4,'en'),('Tegneserier',5,'no'),('Tegneserier',5,'nn'),('Cartoons',5,'en'),('Tekst',6,'no'),('Tekst',6,'nn'),('Text',6,'en'),('GroruddalsReaktor',7,'no'),('GroruddalsReaktor',7,'nn'),('GroruddalsReaktor',7,'en'); +/*!40000 ALTER TABLE `subreaktor_i18n` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `subreaktor_identifier` +-- + +DROP TABLE IF EXISTS `subreaktor_identifier`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `subreaktor_identifier` ( + `id` int(11) NOT NULL auto_increment, + `subreaktor_id` int(11) NOT NULL, + `identifier` varchar(20) NOT NULL, + PRIMARY KEY (`id`), + KEY `subreaktor_identifier_FI_1` (`subreaktor_id`) +) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `subreaktor_identifier` +-- + +LOCK TABLES `subreaktor_identifier` WRITE; +/*!40000 ALTER TABLE `subreaktor_identifier` DISABLE KEYS */; +INSERT INTO `subreaktor_identifier` VALUES (1,1,'image'),(2,2,'image'),(3,5,'image'),(4,6,'pdf'),(5,4,'audio'),(6,3,'video'),(7,3,'flash_animation'),(8,4,'video'),(9,6,'text'); +/*!40000 ALTER TABLE `subreaktor_identifier` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tag` +-- + +DROP TABLE IF EXISTS `tag`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `tag` ( + `id` int(11) NOT NULL auto_increment, + `name` varchar(100) default NULL, + `is_triple` int(11) default NULL, + `triple_namespace` varchar(100) default NULL, + `triple_key` varchar(100) default NULL, + `triple_value` varchar(100) default NULL, + `approved` tinyint(4) NOT NULL default '0', + `approved_by` int(11) default NULL, + `approved_at` datetime default NULL, + `width` int(11) default NULL, + PRIMARY KEY (`id`), + KEY `name` (`name`), + KEY `triple1` (`triple_namespace`), + KEY `triple2` (`triple_key`), + KEY `triple3` (`triple_value`), + KEY `tag_FI_1` (`approved_by`) +) ENGINE=MyISAM AUTO_INCREMENT=81 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `tag` +-- + +LOCK TABLES `tag` WRITE; +/*!40000 ALTER TABLE `tag` DISABLE KEYS */; +INSERT INTO `tag` VALUES (1,'fred',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',4),(2,'bob',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',3),(3,'jim',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',3),(4,'elephant',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',8),(5,'sugar cube',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',10),(6,'monkeydust',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',10),(7,'zoidberg',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',8),(8,'gardening',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',9),(9,'japan',0,NULL,NULL,NULL,0,4,'2008-01-01 01:01:00',5),(10,'rest',0,NULL,NULL,NULL,0,4,'2008-01-01 01:01:00',4),(11,'subway',0,NULL,NULL,NULL,0,4,'2008-01-01 01:01:00',6),(12,'lady',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',4),(13,'php',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',3),(14,'cookbook',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',8),(15,'car',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',3),(16,'ford',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',4),(17,'focus',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',5),(18,'saudi arabia',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',12),(19,'bahrain',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',7),(20,'squash',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',6),(21,'boat',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',4),(22,'water',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',5),(23,'psalive',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',7),(24,'bird',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',4),(25,'wet',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',3),(26,'eden project',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',12),(27,'fingers',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',7),(28,'strange',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',7),(29,'count',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',5),(30,'text',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',4),(31,'filler',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',6),(32,'abigail',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',7),(33,'statue',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',6),(34,'frogner',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',7),(35,'dave',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',4),(36,'scuba diving',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',12),(37,'egypt',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',5),(38,'robin',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',5),(39,'space',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',5),(40,'sound',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',5),(41,'marianne',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',8),(42,'bus',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',3),(43,'latin',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',5),(44,'snow',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',4),(45,'ski',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',3),(46,'sam',0,NULL,NULL,NULL,1,4,'2008-01-01 01:01:00',3),(47,'bollocks',0,NULL,NULL,NULL,0,NULL,NULL,8),(48,'birds',0,NULL,NULL,NULL,0,NULL,NULL,5),(49,'random crappy long tag',0,NULL,NULL,NULL,0,NULL,NULL,22),(50,'monkey',0,NULL,NULL,NULL,1,4,'2008-04-07 21:52:30',6),(51,'fluffy',0,NULL,NULL,NULL,1,4,'2008-04-07 21:52:38',6),(52,'lake district',0,NULL,NULL,NULL,1,4,'2008-04-07 21:52:37',13),(53,'lemur',0,NULL,NULL,NULL,1,4,'2008-04-07 21:53:10',5),(54,'lakes',0,NULL,NULL,NULL,1,4,'2008-04-07 21:53:08',5),(55,'wildlife',0,NULL,NULL,NULL,1,4,'2008-04-07 21:53:06',8),(56,'animal',0,NULL,NULL,NULL,1,4,'2008-04-07 21:53:03',6),(57,'fuckit',0,NULL,NULL,NULL,0,NULL,NULL,6),(58,'bil',0,NULL,NULL,NULL,1,4,'2008-04-24 13:41:17',3),(59,'bike',0,NULL,NULL,NULL,1,4,'2008-04-24 13:41:15',4),(60,'filming',0,NULL,NULL,NULL,1,4,'2008-04-24 13:41:43',7),(61,'camera',0,NULL,NULL,NULL,1,4,'2008-04-24 13:41:42',6),(62,'crazy',0,NULL,NULL,NULL,0,NULL,NULL,5),(63,'funny',0,NULL,NULL,NULL,0,4,'2008-04-25 16:24:54',5),(64,'grass',0,NULL,NULL,NULL,1,4,'2008-04-25 16:27:23',5),(65,'field',0,NULL,NULL,NULL,1,4,'2008-04-25 16:27:21',5),(66,'camping',0,NULL,NULL,NULL,1,4,'2008-04-25 16:27:29',7),(67,'russ',0,NULL,NULL,NULL,1,4,'2008-04-25 16:28:22',4),(68,'red',0,NULL,NULL,NULL,1,4,'2008-04-25 16:29:23',3),(69,'silly',0,NULL,NULL,NULL,0,4,'2008-04-25 16:29:52',5),(70,'norefjell',0,NULL,NULL,NULL,1,4,'2008-04-25 16:30:17',9),(71,'coach',0,NULL,NULL,NULL,1,4,'2008-04-25 16:30:15',5),(72,'baby',0,NULL,NULL,NULL,1,4,'2008-04-25 16:30:52',4),(73,'cute',0,NULL,NULL,NULL,1,4,'2008-04-25 16:30:50',4),(74,'park',0,NULL,NULL,NULL,1,4,'2008-04-25 16:31:31',4),(75,'magic',0,NULL,NULL,NULL,1,2,'2008-05-15 11:57:59',NULL),(76,'roundabout',0,NULL,NULL,NULL,1,2,'2008-05-15 11:58:01',NULL),(77,'swindon',0,NULL,NULL,NULL,1,2,'2008-05-15 11:58:02',NULL),(78,'driving',0,NULL,NULL,NULL,1,2,'2008-05-15 11:57:56',NULL),(79,'tourist',0,NULL,NULL,NULL,1,2,'2008-05-15 11:58:04',NULL),(80,'england',0,NULL,NULL,NULL,1,2,'2008-05-15 11:57:58',NULL); +/*!40000 ALTER TABLE `tag` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `tagging` +-- + +DROP TABLE IF EXISTS `tagging`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `tagging` ( + `id` int(11) NOT NULL auto_increment, + `tag_id` int(11) NOT NULL, + `taggable_model` varchar(30) default NULL, + `taggable_id` int(11) default NULL, + `parent_approved` tinyint(4) NOT NULL default '0', + `parent_user_id` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `tag` (`tag_id`), + KEY `taggable` (`taggable_model`,`taggable_id`), + KEY `tagging_FI_2` (`parent_user_id`) +) ENGINE=MyISAM AUTO_INCREMENT=86 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `tagging` +-- + +LOCK TABLES `tagging` WRITE; +/*!40000 ALTER TABLE `tagging` DISABLE KEYS */; +INSERT INTO `tagging` VALUES (1,9,'ReaktorFile',1,0,3),(2,11,'ReaktorFile',1,0,3),(3,1,'ReaktorFile',1,0,3),(4,15,'ReaktorFile',2,1,3),(5,17,'ReaktorFile',2,1,3),(6,58,'ReaktorFile',2,1,3),(7,59,'ReaktorFile',2,1,3),(8,52,'ReaktorFile',2,1,3),(9,54,'ReaktorFile',2,1,3),(10,60,'ReaktorFile',3,1,3),(11,18,'ReaktorFile',3,1,3),(12,61,'ReaktorFile',3,1,3),(13,21,'ReaktorFile',3,1,3),(14,24,'ReaktorFile',4,1,3),(15,51,'ReaktorFile',4,1,3),(16,26,'ReaktorFile',4,1,3),(17,38,'ReaktorFile',4,1,3),(18,27,'ReaktorFile',5,1,2),(19,62,'ReaktorFile',5,0,2),(20,41,'ReaktorFile',6,0,2),(21,44,'ReaktorFile',6,0,2),(22,44,'ReaktorFile',7,0,2),(23,46,'ReaktorFile',7,0,2),(24,41,'ReaktorFile',7,0,2),(25,45,'ReaktorFile',7,0,2),(26,32,'ReaktorFile',8,1,3),(27,34,'ReaktorFile',8,1,3),(28,33,'ReaktorFile',8,1,3),(29,50,'ReaktorFile',9,0,5),(30,54,'ReaktorFile',9,0,5),(31,52,'ReaktorFile',9,0,5),(32,55,'ReaktorFile',9,0,5),(33,53,'ReaktorFile',10,1,5),(34,50,'ReaktorFile',10,1,5),(35,54,'ReaktorFile',10,1,5),(36,55,'ReaktorFile',10,1,5),(37,63,'ReaktorFile',1,0,3),(38,64,'ReaktorFile',2,1,3),(39,65,'ReaktorFile',2,1,3),(40,66,'ReaktorFile',2,1,3),(41,67,'ReaktorFile',3,1,3),(42,67,'ReaktorFile',2,1,3),(43,22,'ReaktorFile',3,1,3),(44,64,'ReaktorFile',4,1,3),(45,8,'ReaktorFile',4,1,3),(46,66,'ReaktorFile',4,1,3),(47,61,'ReaktorFile',4,1,3),(48,68,'ReaktorFile',4,1,3),(49,9,'ReaktorFile',5,0,2),(50,11,'ReaktorFile',5,0,2),(51,10,'ReaktorFile',5,0,2),(52,69,'ReaktorFile',5,0,2),(53,63,'ReaktorFile',5,0,2),(54,70,'ReaktorFile',6,0,2),(55,45,'ReaktorFile',6,0,2),(56,71,'ReaktorFile',6,0,2),(57,42,'ReaktorFile',6,0,2),(58,70,'ReaktorFile',7,0,2),(59,72,'ReaktorFile',8,1,3),(60,73,'ReaktorFile',8,1,3),(61,64,'ReaktorFile',9,0,5),(62,56,'ReaktorFile',9,0,5),(63,63,'ReaktorFile',9,0,5),(64,73,'ReaktorFile',9,0,5),(65,69,'ReaktorFile',9,0,5),(66,74,'ReaktorFile',10,1,5),(67,51,'ReaktorFile',10,1,5),(68,73,'ReaktorFile',10,1,5),(69,74,'ReaktorFile',11,1,6),(70,62,'ReaktorFile',11,1,6),(71,1,'ReaktorFile',11,1,6),(72,75,'ReaktorFile',12,1,6),(73,76,'ReaktorFile',12,1,6),(74,77,'ReaktorFile',12,1,6),(75,78,'ReaktorFile',12,1,6),(76,79,'ReaktorFile',12,1,6),(77,80,'ReaktorFile',12,1,6),(78,43,'Article',1,1,4),(79,1,'Article',1,1,4),(80,43,'Article',2,1,4),(81,34,'Article',2,1,4),(82,31,'Article',2,1,4),(83,31,'Article',1,1,4),(84,70,'ReaktorFile',13,1,2),(85,12,'ReaktorFile',13,1,2); +/*!40000 ALTER TABLE `tagging` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `trans_unit` +-- + +DROP TABLE IF EXISTS `trans_unit`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `trans_unit` ( + `msg_id` int(11) NOT NULL auto_increment, + `cat_id` int(11) NOT NULL default '1', + `id` varchar(255) default '', + `source` text NOT NULL, + `target` text NOT NULL, + `module` varchar(255) default '', + `filename` varchar(255) default '', + `comments` text, + `date_added` int(11) NOT NULL default '0', + `date_modified` int(11) NOT NULL default '0', + `author` varchar(255) NOT NULL default '', + `translated` int(1) NOT NULL default '0', + PRIMARY KEY (`msg_id`), + KEY `trans_unit_FI_1` (`cat_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `trans_unit` +-- + +LOCK TABLES `trans_unit` WRITE; +/*!40000 ALTER TABLE `trans_unit` DISABLE KEYS */; +/*!40000 ALTER TABLE `trans_unit` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_interest` +-- + +DROP TABLE IF EXISTS `user_interest`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `user_interest` ( + `user_id` int(11) NOT NULL, + `subreaktor_id` int(11) NOT NULL, + PRIMARY KEY (`user_id`,`subreaktor_id`), + KEY `user_interest_FI_2` (`subreaktor_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `user_interest` +-- + +LOCK TABLES `user_interest` WRITE; +/*!40000 ALTER TABLE `user_interest` DISABLE KEYS */; +INSERT INTO `user_interest` VALUES (2,4),(3,1),(3,2),(3,3); +/*!40000 ALTER TABLE `user_interest` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `user_resource` +-- + +DROP TABLE IF EXISTS `user_resource`; +SET @saved_cs_client = @@character_set_client; +SET character_set_client = utf8; +CREATE TABLE `user_resource` ( + `id` int(11) NOT NULL auto_increment, + `user_id` int(11) NOT NULL, + `url` varchar(255) NOT NULL, + PRIMARY KEY (`id`,`user_id`), + KEY `user_resource_FI_1` (`user_id`) +) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; +SET character_set_client = @saved_cs_client; + +-- +-- Dumping data for table `user_resource` +-- + +LOCK TABLES `user_resource` WRITE; +/*!40000 ALTER TABLE `user_resource` DISABLE KEYS */; +INSERT INTO `user_resource` VALUES (1,3,'http://photoshop.com'),(2,3,'http://gimp.org'),(3,3,'http://vg.no'),(4,3,'http://facebook.com'),(5,1,'http://photoshop.com'),(6,4,'http://gimp.org'),(7,2,'http://vg.no'),(8,5,'http://facebook.com'); +/*!40000 ALTER TABLE `user_resource` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2008-08-07 8:58:43 diff --git a/prototype/lib/domain_maps.rb b/prototype/lib/domain_maps.rb new file mode 100644 index 0000000..bb80dff --- /dev/null +++ b/prototype/lib/domain_maps.rb @@ -0,0 +1,132 @@ +# +# = Synopsis +# +# Domain maps +# Used to convert strings of data from prototype convension to reaktor convenseion +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# + +$domain_maps = { + :artwork__rights => { + ':contactme' => 'contact', + ':educational' => 'non_commersial', + ':free' => 'free_use', + ':none' => 'no_allow', + }, + + :artwork__publish_state => { + ':accepted' => 'Approved', + ':denied' => 'Rejected', + ':queued' => 'Ready for approval', + }, + + :reaktoruser__sex => { + 'm' => 1, + 'f' => 2, + }, + + :artwork__mime_type_to_identifier => { + 'image-jpeg' => :image, + 'video-asf' => :video, + 'document-pdf' => :pdf, + 'video-mp4' => :video, + 'sound-mp3' => :audio, + 'image-gif' => :image, + 'flash' => :flash_animation, + 'video-quicktime' => :video, + 'image-png' => :image, + 'sound-midi' => :audio, + 'file' => :video, # Only on occurence of a mp4-file + }, + + :artwork__mime_type => { + "image-jpeg" => "image/jpeg", + #"video-asf" => "video/x-ms-asf", + "video-asf" => "video/flv", # FIX + "document-pdf" => "application/pdf", + "video-mp4" => "video/mp4", + "sound-mp3" => "audio/mpeg", + "image-gif" => "image/gif", + "video-quicktime" => "video/quicktime", + "image-png" => "image/png", + "sound-midi" => "audio/midi", + "flash" => { + "flv" => "video/flv", + "swf" => "application/x-shockwave-flash", + }, + "file" => "video/mp4", + }, + + :artwork__type => { + 'files' => 'files', + 'flash' => 'flash', + 'image' => 'image', + 'images' => 'images', + 'pdf' => 'pdf', + 'sound' => 'audio', + 'text' => 'text', + 'video' => 'video', + }, + + :reaktoruser__type => { + "administrator" => "admin", + "editor" => "staff", + "external" => "users", + }, + + # + # Maps site::id and sf_guard_group::id + # + :site_id__sf_guard_group_id => { + 3960 => 10, # musikk_redaksjon + 393 => 8, # serieteket_redaksjon + 4421 => 11, # konkurranse_redaksjon + 4 => 7, # deichman_redaksjon + 1397 => 9, # trondheim_redaksjon + nil => 2, # When there's no site_id + }, + # + # Map site::title to sf_guard_group::name + # + :site_title__sf_guard_group_name => { + 'musikk' => 'musikk_redaksjon', + 'serieteket' => 'serieteket_redaksjon', + 'konkurranse' => 'konkurranse_redaksjon', + 'deichman' => 'deichman_redaksjon', + 'trondheim' => 'trondheim_redaksjon', + 'users' => 'users', + }, + # + # Maps topic::id and subreaktor::id + # + :topic_id__subreaktor_id => { + 80 => 1, # foto + 398 => 2, # tegning + 4380 => 3, # film + 738 => 4, # lyd + 321 => 5, # tegneserier + 311 => 6, # tekst + 4926 => 6, # Dikt + 338 => 3, # Dataanimasjon + 740 => 4, # Intervjuer + + }, + + :artwork_identifier__subreaktor_reference => { + 'image' => 1, + 'text' => 6, + 'flash' => 3, + 'audio' => 4, + 'video' => 3, + 'pdf' => 6, + 'images' => 1, + 'files' => 6, + } +} diff --git a/prototype/lib/filter.rb b/prototype/lib/filter.rb new file mode 100644 index 0000000..ce10dba --- /dev/null +++ b/prototype/lib/filter.rb @@ -0,0 +1,499 @@ +# $Id: filter.rb 2579 2008-09-29 10:03:17Z robert $ + +# +# The filters are functions f(value,row) -> value. Some of the +# functions' behaviours can be configured. +# +# FIX Some of the filters call parse_value() defined in +# run-import. This coupling is unfortunate. +# +# FIX The filters use the logging facility defined in run-import. Make +# it a seperate library? +# +# Author: Kjell-Magne Oierud mailto:kjellm@linpro.no +# + +module Filter + + # + # Applyes the given filters to a value. + # + # filters might be a single filter or an array of filters. + # + def Filter.apply_filters(value, row, *filters) + Log.write_log('filter', "apply_filters:\tvalue = #{value.pretty_inspect}\trow = #{row.pretty_inspect}\tfilters = #{filters.pretty_inspect}") if $DEBUG + filters.flatten! + filters.each do |filter| + next if filter.nil? + value = filter.call(value, row) + end + Log.write_log('filter', "apply_filters:\treturned value = #{value.pretty_inspect}") if $DEBUG + return value + end + + def Filter.this_method + caller[0]=~/`(.*?)'/ + $1 + end + + + + + # + # Inverts a boolean value + # + def Filter.invert(); lambda {|value, row| !value }; end + + # + # Converts a boolean to an integer + # + def Filter.boolean_to_integer + lambda do |value, _| + case value + when 't' + return 1 + when 'f' + return 0 + when false + return 0 + when true + return 1 + else + raise "#{value} is not a boolean value!" + end + end + end + + + # + # Converts all characters in a string to uppercase characters. + # + def Filter.upcase(); lambda {|value, row| value.nil? ? nil : value.upcase} end + + # + # Converts all characters in a string to downcase characters. + # + def Filter.downcase(); lambda {|value, row| value.nil? ? nil : value.downcase} end + + # + # Runs the filters if value is NULL + # + def Filter.if_null(filters) + lambda do |value, row| + return value unless value.nil? + + return apply_filters(value, row, filters) + end + end + + # + # Runs the filters if value is empty + # + def Filter.if_empty(filters) + lambda do |value,row| + return value unless value.empty? + + return apply_filters(value, row, filters) + end + end + + # + # Returns the specified value ignoring its input value. + # + def Filter.set_value(value) + lambda do |_,row| + ReaktorColumn.parse_value(value, nil, row) + end + end + + # + # Return length of string + # + def Filter.string_length() + lambda do |value, _| + value.length + end + end + + # + # Adds a prefix to a value + # + def Filter.add_prefix(str); lambda {|value,row| str + value} end + + + # + # Adds a postfix to a value + # + def Filter.add_postfix(str) + lambda do |value, row| + value + ReaktorColumn.parse_value(str, value, row).to_s + end + end + + + # + # Removes a substring starting at the matching location of 'str'. + # + def Filter.truncate_from(str) + lambda do |value,row| + value[0..(value.index(str)-1)] + end + end + + + + # + # Sets a specific value if row[col] is true + # + def Filter.override_if(col, override_value) + lambda do |value,row| + if row[col] # removes '%' prefix + return override_value + end + return value + end + end + + + # + # If value is NULL return the specified defalt + # + def Filter.default_if_null(default) + lambda do |value,row| + value = value.nil? ? ReaktorColumn.parse_value(default, nil, row) : value + return value + end + end + + # + # Print values (for debugging) + # + def Filter.print_value(prefix = '') + lambda do |value, row| + STDERR.puts "#{prefix}value = #{value.inspect}, row = #{row.inspect}" + return value + end + end + + def Filter.replace(pattern, val) + lambda do |value, row| + return value.gsub(pattern, val) + end + end + + # + # Returns a default value if db value is 0 + # + def Filter.default_if_zero(default) + lambda do |value,row| + STDERR.print "default_if_zero: value: #{value.inspect}" + value = value == 0 ? ReaktorColumn.parse_value(default, nil, row) : value + STDERR.puts " - returned: #{value.inspect}" + return value + end + end + + + # + # Converts a textual value to a id using a value domain table. + # => table: Table name + # => column: Column name + # + def Filter.domain_value_to_id(table, column) + lambda do |value, row| + return value if value.nil? + + query = "SELECT id\n FROM #{table}\n WHERE #{column} = ?;" + sth = $dbh_ms.prepare(query) + begin + sth.execute(value) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log(:error, "domain_value_to_id failed to execute query.\n\tQuery: #{query.pretty_inspect}") + end + qrow = sth.fetch() + if not qrow + # ERROR: empty row, error output, write to log + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log(:error, "domain_value_to_id failed to get id from table. Query return nil row.\n\ttable = \"#{table}\"\n\tcolumn=\"#{column}\"\n\tvalue=\"#{value}\"\n\trow = #{row.pretty_inspect}\n\tQuery: \"#{get_query_string(sth)}\"") + end + + return qrow[0] + end + end + + # + # Get a column value from a database table + # => database: Database handle + # => table: Table name + # => index_column: The name of the column that spesifies the row + # => value_column: The name of the column that holds the value + # + def Filter.get_value_from_db(database, table, index_column, value_column) + lambda do |value, row| + return value if value.nil? + + query = "SELECT #{value_column}\n\tFrom #{table}\n\tWHERE #{index_column} = ?;" + sth = database.prepare(query) + begin + sth.execute(value) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + $stderr.puts $! + Log.write_log(:error, "get_value_from_db failed to execute query.\n\tQuery: #{query.pretty_inspect}") + end + r = sth.fetch + unless r + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log(:error, "get_value_from_db failed to get #{value_column} from table.\n\ttable = \"#{table}\"\n\tindex_column=\"#{index_column}\"\n\tvalue_column=\"#{value_column}\"\n\tvalue=\"#{value}\"\n\tr = #{r.pretty_inspect}\n\trow = #{row.pretty_inspect}\n\tQuery: \"#{get_query_string(sth)}\"") + end + + return r[0] + end + end + + # + # Query database for a value + # Input: database object and a query string + # Output: Result string value + # + def Filter.get_value_from_query(db, query) + lambda do |value, row| + # + # Replace any occurence of %column_name with actual column values + # + q = query.gsub(/%(\w+)/) do |v| + if row.to_h.key?($1) + row.to_h[$1] + else + v + end + end + + q.gsub!(/%_/, value.to_s) unless value.nil? + + q.gsub!('?', value.to_s) unless value.nil? + + Log.write_log(:Filter__get_value_from_query, "Query: \"#{q}\", value = #{value}, row = #{row.inspect}") + + # + # Execute query + # + begin + sth = db.execute(q) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + $stderr.puts $! + Log.write_log(:error, "filter.get_query(db, query) failed to execute query.\n\tQuery: #{q.pretty_inspect}") + exit 1 + end + r = sth.fetch + return '' if r.nil? + return r[0] + end + end + + # + # Truncates values longer than max_length characters. Replaces last + # three characters with ellipsis (default), or with delim parameter + # Input: max length and a delimiter string + # + def Filter.truncate(max_length, delim = '...') + max_length = max_length.to_i + delim_length = delim.length + lambda do |value,_| + value = value.to_s + if value.length > max_length + return value[0..(max_length - (delim_length + 1))] + delim + end + return value + end + end + + + # + # Transforms value by looking up the corresponding value in a hash + # table + # + def Filter.apply_map(map) + lambda do |value, row| + return map[value] + end + end + + # + # Get the mapped primary key set + # => old_table: Old table name + # => old_pk: Old primary key set + # <= [new table name, new primary key set] + # + def Filter.get_new_primary_key_set(old_table, old_pk) + lambda do |value, row| + old_pk.each do |key,val| + old_pk[key] = row[value] if val =~ /%_/ # Replaces %_ with current column value + old_pk[key] = $1 if val =~ /%(\w+)/ # Replaces %[column name] with corresponding column value + end + new_set = KeyMap.get_new_primary_key(old_table, old_pk) + Log.write_log('keymap', "Mapping table #{[old_table, old_pk].pretty_inspect} to #{new_set.pretty_inspect}") + return new_set + end + end + + def Filter.idstore_get(*args) + lambda do |value, row| + args.collect! {|arg| ReaktorColumn.parse_value(arg, value, row)} + IdStore.get(*args) + end + end +end + +def Filter.log_values(name = :Filter__log_vales, text = '') + lambda do |value, row| + Log.write_log(name, "#{text}: value = #{value}, row = #{row.inspect}") + return value + end +end + +###################################################################### +# These filters are speciall to Reaktor ,,, + + +require 'digest/md5' + +module Filter + + # + # Extracts filename from a serialized lisp object. + # + def Filter.extract_filename() + lambda do |value,row| + return if value.nil? || value == 'NIL' + + filename = (value.match(/:filename "([^"]+)"/))[1] + Log.write_log('files', "#{filename}") + return filename + end + end + + # + # Extracts the text from a serialized richtext-simple lisp object + # + def Filter.parse_richtext_simple() + lambda do |value,row| + return value if value.nil? + + mdata = value.match(/:parsed-text '\("(.+)"\)\)/m) + return mdata.nil? ? nil : mdata[1] + end + end + + def Filter.parse_richtext_simple_multiline() + lambda do |value, row| + return value if value.nil? + mdata = value.match(/:parsed-text '\((.+)\)\)/m) + return mdata.nil? ? nil : mdata[1] + end + end + + def Filter.parse_artwork_description() + lambda do |value, row| + return value if value.nil? + # + # :P =>
    + # + value.gsub!(/:P/, %q{"
    "}) + slist = value.scan(/".+?"/m) + linkstatus = false + slist.map! do |l| + l.gsub!(/\n/, '') + l.gsub!(/
    /, "\n") + if l =~ %r{http://} + linkstatus = true + l = %q{' + elsif linkstatus + linkstatus = false + l = l[1...-1] + '' + else + l = l[1...-1] + end + end + return slist.join + end + end + + # + # Writes textual artwork to a file. FIX should probably be renamed. + # + def Filter.parse_artwork_data_old() + lambda do |value,row| + if value.match(%r{\A \( (?:NIL|T) \s \. \s (.*) \) \z}xms) + text = $1 + digest = Digest.MD5.hexdigest(text) + filename = "#{digest}.txt" + File.open(File.join('data', filename), 'w') do |file| + file.puts(text) + end + return ":filename \"#{filename}\"" # Suitable for + # Filter.extract_filename() + end + return value + end + end + + # + # Removes eclosing parantesis + # + def Filter.trim_lisp_encl_params() + lambda do |value, _| + value.gsub(/^\s*\("/,'').gsub(/"\)\s*$/, '') + end + end + + # + # Make a valid data from a year + # + def Filter.mkdate_from_year() + lambda do |value, _| + if value.nil? + return '1800-01-01' + else + return value.to_s + '-01-01' + end + end + end + + # + # Get filename from serialized lips + # + def Filter.get_filename_from_lisp() + lambda do |value, row| + return value if value.nil? + return value.split[3][1...-1] + end + end + + # + # FIX remove the need for this method ... + # + def Filter.fix_encoding + lambda do |value,row| + # FIX HACK remove! These characters are destroyed on the way some + # where. Are stored in postgres as U+0094 and U+0096 and somehow + # ends up as U+C294 and U+C296 which MySQL can't recognize as legal + # unicode (And I think MySQL is right here ...). + # + # This is just so that the import doesn't stop and I can continue + # working. + # TODO: Solve this problem + # + unless value.nil? + value.gsub!("\xC2\x94", "?") + value.gsub!("\xC2\x96", "?") + value.gsub!("\xC3\xA6", "?") + return value + end + + return value + end + end +end diff --git a/prototype/lib/id_store.rb b/prototype/lib/id_store.rb new file mode 100644 index 0000000..b77e51d --- /dev/null +++ b/prototype/lib/id_store.rb @@ -0,0 +1,136 @@ +# +# = Synopsis +# +# This class stores a value in the database with an index based on the md5 +# key calculated from concatenated argument strings. The imigration algorithm +# uses this class to make available primary key ids that are generated when +# inserting data to the database. +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# +require 'digest/md5' + +class IdStore + + @@table_name = 'id_store' + @@create_table = true + @@num_ids = 0 + @@report_name = 'report' + @@log_name = 'id_store' + + attr_reader :hash, :value, :args + + def self.create_db_table + unless $dbh_pg.execute("SELECT relname FROM pg_class WHERE relname = '#{@@table_name}'").fetch + $dbh_pg.execute(%Q{ + CREATE TABLE #{@@table_name} ( + id text NOT NULL PRIMARY KEY, + value text NOT NULL + ) + }) + end + @@create_table = nil + end + + def self.drop_db_table + unless $dbh_pg.execute("SELECT relname FROM pg_class WHERE relname = '#{@@table_name}'").fetch.nil? + $dbh_pg.execute(%Q{DROP TABLE #{@@table_name}}) + end + @@create_table = true + end + + def self.make_hash(*args) + Digest::MD5.hexdigest(args * '') + end + + def self.get(*args) + hash = self.make_hash(args * '') + query = %Q{ + SELECT value + FROM #{@@table_name} + WHERE id = '#{hash}'} + begin + sth = $dbh_pg.execute(query).fetch + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not select id. Message: #{$!}. query: \"#{get_query_string(sth)}\"") + raise + exit + end + unless sth + STDERR.puts "IdStore::get(#{args * ','}) No value in database for hash: #{hash}" + raise + else + return sth[0] + end + end + + def initialize(*args) + @value = nil + @args = args + if @@create_table + IdStore.create_db_table + end + @hash = self.make_hash(args * '') + raise "Hash id allready exist in database: #{@hash}" unless unique_hash + end + + def make_hash(*args) + Digest::MD5.hexdigest(args * '') + end + + def unique_hash + begin + r = $dbh_pg.execute(%Q{SELECT * from id_store WHERE id = '#{@hash}'}).fetch + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not select id. Message: #{$!}. query: \"#{get_query_string(sth)}\"") + raise + exit + end + return true unless r + return nil + end + + def inspect + "#" + end + + def store(value) + raise "Value has allready been set. id = #{@hash} value = #{@value}" unless @value.nil? + query = %Q{INSERT INTO #{@@table_name} (id, value) VALUES ('#{@hash}', '#{value}')} + begin + $dbh_pg.execute(query) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog." + Log.write_log('error', "Could not insert new record. Message: #{$!} Query: #{query}") + end + @value = value + @@num_ids += 1 + Log.write_log(@@log_name, "Stored #{@hash} args: (#{args * ','}) value: #{@value}") + end + + def get + unless @value + raise "Value has not been set for hash: #{@hash}" + return nil + end + return @value + end + + def self.flush_logs + Log.flush_log(@@report_name) + Log.flush_log(@@log_name) + end + + def self.write_report + Log.write_log(@@report_name, "IdStore:") + Log.write_log(@@report_name, "\t#{@@num_ids} total number of ids stored") + end +end diff --git a/prototype/lib/import.rb b/prototype/lib/import.rb new file mode 100755 index 0000000..7fb3a4f --- /dev/null +++ b/prototype/lib/import.rb @@ -0,0 +1,476 @@ +#!/usr/bin/env ruby + +# = Synopsis +# +# Imports the data from the prototype into a mysql database with the +# new reaktor schema following the rules defined in the schema map. +# +# = Author +# +# * Kjell-Magne Oierud mailto:kjellm@linpro.no +# * Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id: import.rb 2579 2008-09-29 10:03:17Z robert $ +# + +# Expand ruby search path +$: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')) +$: << File.expand_path(File.join(File.dirname(__FILE__), '..', 'plugins')) + +require 'dbi'; +require 'ostruct' +require 'pp' + +require 'log' +require 'filter' +require 'mapping' +require 'key_map' +require 'domain_maps' +require 'insert_row' +require 'id_store' +require 'utf8_converter' + +require 'plugin' +require 'artwork_data_plugin' +require 'reaktoruser_artworkgroups_plugin' +require 'reaktoruser_image_plugin' +require 'reaktoruser_type_plugin' +require 'reaktoruser_site_plugin' +require 'artwork_internal_discussion_plugin' +require 'artwork_topic_tagging_plugin' + +# +# Perform the migration +# Input: Hash witl all configuration data +# +def import(cnf) + # + # Connect to databases + # + begin + $dbh_pg = DBI.connect( + "dbi:Pg:#{cnf[:from_db_name]}:", + cnf[:from_db_user], + cnf[:from_db_password] + ) + rescue + STDERR.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog." + Log.write_log(:error, "Could not connect to database. Message: #{$!}\ncnf:#{cnf.inspect}") + exit + end + begin + $dbh_ms = DBI.connect( + "dbi:Mysql:#{cnf[:to_db_name]}:", + cnf[:to_db_user], + cnf[:to_db_password] + ) + rescue + STDERR.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog." + Log.write_log(:error, "Could not connect to database. Message: #{$!}") + exit + end + $dbh_ms.do("SET sql_mode='TRADITIONAL,ANSI'") + $dbh_ms.do("SET NAMES 'utf8'") + + $reaktor_insert_count = 0 + $import_log = 'import' + $debug = cnf[:debug] + + # + # Initialize plugins + # + ArtworkDataPlugin::set_data_path(cnf[:path_data]) + + # + # Drop id_store table if it exists + # + begin + sth = $dbh_pg.execute("SELECT relname FROM pg_class WHERE relname = 'id_store'") + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not process query. Message: #{$!} query: #{get_query_string(sth)}.") + raise + exit + end + relname = sth.fetch + + if relname + begin + sth = $dbh_pg.execute(%Q{DROP TABLE id_store}) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not process query. Message: #{$!} query: #{get_query_string(sth)}.") + raise + exit + end + STDERR.puts "Dropped id_store table from prototype." + end + + # + # Load the schema map + # + require 'schema_map' + + # + # Process tables + # + $schema.each do |t| + process_table(t) + end + + # + # Write reports + # + ArtworkDataPlugin.flush_logs + ArtworkDataPlugin.write_report + + ArtworkTopicTaggingPlugin::flush_logs + ArtworkTopicTaggingPlugin::write_report + + ArtworkInternalDiscussionPlugin::flush_logs + ArtworkInternalDiscussionPlugin::write_report + + ReaktoruserArtworkgroupsPlugin::flush_logs + ReaktoruserArtworkgroupsPlugin::write_report +end + +# +# process_table +# Input: PrototypeTableMap object +# +def process_table(table) + + $stderr.puts "Processing table: %-15s to default table: #{table.__default_table__}" % table.name + Log.write_log(table.name, "Processing table: #{table.name}") + table.each_column do |attr_name, maps_to| + if maps_to.kind_of?(ReaktorColumn) + maps_to.fill_in_defaults(table.__default_table__, attr_name) + end + end + table.__set__.each do |rc| + rc.fill_in_defaults(table.__default_table__, nil) + end + if table.instance_variable_defined?(:@__query__) + query = table.__query__ + else + query = build_query(table.name, table.__filter_rows__) + end + Log.write_log(table.name, "Query: #{query}") + begin + sth = $dbh_pg.execute(query) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not process query. Message: #{$!} query: #{get_query_string(sth)}.") + raise + exit + end + while row = sth.fetch + next unless preconditions_met?(row, table.__precondition__) + + process_row(table, row).each do |r| + reaktor_insert(r) unless r.nil? + end + end +end + + +# +# parse_value +# +# If value is a reference (First character is '%'), substitutes the +# value with a value from 'row_value' when value is '%_' otherwise +# from data. +# +def parse_value(value, row_value, data) + return value if value.nil? + return value unless value.kind_of?(String) + + if value[0] == '%'[0] + if value == '%_' + return row_value + else + if not data[value[1..-1]] + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "parse_value failed. data does not contain value indexed by \"#{value[1..-1]}\"") + exit + else + return data[value[1..-1]] + end + end + end + return value +end + + +# +# Process a row from the old database +# Input: PrototypeTableMap object and SQL result set from prototype table +# +def process_row(table, row) + Log.write_log(table.name, "Processing row: #{row.pretty_inspect}") + row.each do |v| + row.to_h.each do |k,v| + row[k] = Utf8_Converter::convert(v) if v.kind_of?(String) + end + end + pk_string = '' + table.primary_key.each do |pk| + pk_string << row[pk].to_s + end + if pk_string.empty? + row.each {|c| pk_string << c.to_s} + end + if (table.__id_store__) + default_table_row = InsertRow.new(table.__default_table__, IdStore.new(table.name, pk_string)) + else + default_table_row = InsertRow.new(table.__default_table__) + end + default_table_row.prototype_table_map = table + default_table_row.prototype_result_set = row + table_rows = [] + + table.each_column do |attr_name, maps_to| + next if maps_to == IGNORE + + if maps_to.kind_of?(ReaktorColumn) + # + # ReaktorColumn + # + default_table_row.add(*process_reaktor_column(maps_to, attr_name, row)) + elsif maps_to.kind_of?(ReaktorRow) + # + # ReaktorRow + # + table_rows << process_reaktor_row(maps_to, attr_name, row) + elsif maps_to.kind_of?(Class) + # + # Plugin + # + plugin = process_plugin(maps_to, attr_name, row) + list = plugin.each + if list.kind_of?(Array) + list.each do |reaktor_object| + if reaktor_object.kind_of?(ReaktorColumn) + default_table_row.add(*process_reaktor_column(reaktor_object, attr_name, row)) + elsif reaktor_object.kind_of?(ReaktorRow) + table_rows << process_reaktor_row(reaktor_object, attr_name, row) + else + STDERR.puts "reaktor_object was a #{reaktor_object.class} class" + exit + end + end + end + else + STDERR.puts "maps_to was of class: #{maps_to.class} and not processed" + exit + end + end + + table.__set__.each do |set| + t = set.value + if set.value.kind_of?(Query) + tsth = $dbh_pg.prepare(set.value.sql) + begin + tsth.execute(row[:id]) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not process query. Message: #{$!} query: #{get_query_string(tsth)}.") + raise + exit + end + r = tsth.fetch + t = r.nil? ? r : r[0] + else + t = set.parse_value(nil, row) + end + t = Filter.apply_filters(t, row, set.filters) + default_table_row.add(set.name, t) + end + table_rows.insert(0, default_table_row) unless table.__default_table__.nil? + return table_rows +end + +# +# Extract column name and value from a ReaktorColumn +# => rco: ReaktorColumn object +# => attr_name: Attribute name defined in PrototypeTableMap +# => row: SQL result set from prototype table +# <= [column_name, value] +# +def process_reaktor_column(rco, attr_name, row) + begin + val = Filter.apply_filters(row[attr_name], row, rco.filters) + rescue Exception + STDERR.puts "row: #{row.inspect}" + raise + end + Log.write_log(rco.table, "Setting column: #{rco.inspect} value = #{val.inspect}") + return [rco.name,val] +end + +# +# Extract table name, column names and values from a ReaktorRow object +# => rro: ReaktorRow object +# => attr_name: Attribute name see: schema_map.rb +# => row: SQL result set from prototype table +# <= InsertRow object +# +def process_reaktor_row(rro, attr_name, row) + return nil if row[attr_name].nil? + table_row_data = InsertRow.new(rro.table, rro.idstore) + rro.columns.each do |column| + val = column.parse_value(row[attr_name], row) + val = Filter.apply_filters(val, row, column.filters) + table_row_data.add(column.name, val) + end + Log.write_log(rro.table, "Setting row: #{rro.pretty_inspect}") + return table_row_data +end + +# +# Run a plugin +# => po: Plugin object +# => attr_name: Attribute name see: schema_map.rb +# => row: SQL result set from prototype table +# <= A list of ReaktorRow objects +def process_plugin(po, attr_name, row) + po.new(attr_name, row) +end + +# +# precondition_met? +# +# Executes and evaluates the precondition query. The query can contain +# references to row values ('%foo') which will be replaced before +# execution. +# +def preconditions_met?(row, precondition) + unless precondition.nil? + pre_query = precondition.gsub(/%(\w+)/) do |m| + if row[$1].kind_of?(String) + row[$1].downcase + else + row[$1] + end + end + + begin + r = $dbh_ms.select_one(pre_query) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not process pre-query. Message: #{$!}. Pre-query: \"#{pre_query}\"") + STDERR.puts "r: #{r.inspect}" + raise + exit + end + if r[0] == 0 + Log.write_log('not_met_preconditions', "Row does not satisfy pre condition. Pre-query: #{pre_query}") + return false + end + end + + return true +end + +# +# Insert values to database +# => row: A InsertRow object +# +def reaktor_insert(row) + insert_id = 0 + unless row.idstore.nil? + Log.write_log($import_log, "reaktor_insert: Table: #{row.table_name} args: #{row.idstore.args * ', '}") + else + Log.write_log($import_log, "reaktor_insert: Table: #{row.table_name} No IdStore object") + end + query = "INSERT INTO #{row.table_name} (#{row.get_column_name_string})\n VALUES (#{(['?']*row.size).join(', ')})" + sth = $dbh_ms.prepare(query) + begin + sth.execute(*row.get_column_values) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not insert data. Message: #{$!}. query: \"#{get_query_string(sth)}\"") + raise + exit + end + begin + insert_id = $dbh_ms.func(:insert_id) unless row.idstore.nil? + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not get insert id. Message: #{$!}.") + raise + exit + end + if insert_id > 0 + row.store_id(insert_id) + Log.write_log($import_log, "Insert id store to table: #{row.table_name} id_store parameters: (#{row.idstore.args * ', '}) id: #{insert_id}") + else + unless row.idstore.nil? + Log.write_log($import_log, "No id stored for table: #{row.table_name} id_store parameters: (#{row.idstore.args * ', '})") + else + Log.write_log($import_log, "No id stored for table: #{row.table_name} No IdStore object") + end + + end +end + +def get_query_string(sth) + return '' if sth.nil? + eval(sth.inspect[/@result[^\]]*\]/].gsub(/@result=/,'')).to_s +end + +# +# find_primary_key +# +# Queries the database (information_schema) to find the primary key +# for a table. +# +def find_primary_key(table) + query = %q{ + SELECT column_name + FROM information_schema.table_constraints tc + INNER JOIN + information_schema.key_column_usage kcu + ON tc.constraint_name = kcu.constraint_name + WHERE constraint_type = 'PRIMARY KEY' + AND tc.table_catalog = 'reaktor' + AND tc.table_schema = 'public' + AND tc.table_name = ? + ORDER BY ordinal_position; + } + + sth = $dbh_pg.prepare(query) + begin + sth.execute(table.to_s) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not find primary key. Message: #{$!}. query: #{get_query_string(sth)}") + raise + exit + end + pk = [] + while row = sth.fetch + pk << row[0] + end + return pk +end + + +# +# build_query +# +# Generates a query that selects everything from a table ordered by +# the primary key. +# +def build_query(table_name, where_expression) + query = %Q{SELECT *\n FROM "#{table_name}"} + unless where_expression.nil? + query << "\n WHERE #{where_expression}" + end + unless (pk = find_primary_key(table_name)).empty? + query << "\n ORDER BY " << pk.join(', ') + end + return query +end diff --git a/prototype/lib/insert_row.rb b/prototype/lib/insert_row.rb new file mode 100644 index 0000000..5530c04 --- /dev/null +++ b/prototype/lib/insert_row.rb @@ -0,0 +1,142 @@ +#!/usr/bin/env ruby +# +# = Synopsis +# +# This class holds data rows to be inserted into a database table +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# + +class Array + + # + # Escapes all elements: ["element", ...] + # + def escape + self.collect {|c| "\"#{c.to_s}\"" } + end + + # + # This function makes it posible to sort a list of symbols + # + def sort_sym + self.sort {|a,b| a.to_s <=> b.to_s } + end +end + +class InsertRow + + attr_accessor :prototype_table_map, :prototype_result_set, :idstore + attr_reader :table_name + + @@log_name = 'insert_row' + + # + # => name: Name of the table to insert to + # => idstore: IdStore object + # + def initialize(name, idstore = nil) + @table_name = name + @idstore = idstore + @columns = {} + Log.write_log('insert_row', "Created InsertRow object. name = #{name}, #{idstore.inspect}") + end + + def inspect + "#" + end + + # + # Return a sorted comma seperated list of column names + # + def get_column_name_string + @columns.keys.sort_sym.escape.join(', ') + end + + # + # Return value from column + # => name: Name of column to return value from + # + def column(name) + @columns[name] + end + + # + # Return the number of columns + # + def size + @columns.length + end + + # + # Returns a list of column values sorted by column name + # + def get_column_values + @columns.each {|c| @columns[c[0]] = c[1].get if c[1].kind_of?(IdStore)} + @columns.values_at(*@columns.keys.sort_sym) + end + + # + # Add a column name - value pair to the row + # => pair: A list: [column name, value] + # + def add(column_name, value) + @columns[column_name] = value + end + + # + # Find the primary key for this table + # => db_handle: A DBI handle + # => database: Database name + # Returns a list of primary keys + # + def find_primary_key(db_handle, database) + query = %q{ + SELECT k.column_name + FROM information_schema.table_constraints t + JOIN information_schema.key_column_usage k + USING(constraint_name,table_schema,table_name) + WHERE t.constraint_type='PRIMARY KEY' + AND t.table_schema='?' + AND t.table_name='?'; + } + sth = db_handle.prepare(query) + begin + sth.execute(database, @table_name) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not find primary key. Message: #{$!}. query: \"#{get_query_string(sth)}\"") + raise + exit + end + pk = [] + while row = sth.fetch + pk << row[0] + end + return pk + end + + # + # Get primary key set + # => db_handle: A DBI handle + # => database: Database name + # <= {column_name => value, ...} + # + def get_primary_key_set(db_handle, database) + @primary_key_set = {} + find_primary_key(db_handle, database).each do |pk| + @primary_key_set.store(pk, @columns[pk]) + end + end + + def store_id(value) + Log.write_log(@@log_name, "Storing id for table #{@table_name} IdStore args: #{@idstore.args * ','}") + @idstore.store(value) unless @idstore.nil? + end +end diff --git a/prototype/lib/key_map.rb b/prototype/lib/key_map.rb new file mode 100644 index 0000000..fec743a --- /dev/null +++ b/prototype/lib/key_map.rb @@ -0,0 +1,53 @@ +# +# Maps old primary key sets with new ones +# + + +class KeyMap + + @@old_to_new = {} + @@new_to_old = {} + + # + # Save a key mapping + # => old_table: Old table name + # => old_pk: Old primary key set {columnname=>value, ...} + # => new_table: New table name + # => new_pk: New primary key set {columnname=>value, ...} + # + def self.save(old_table, old_pk, new_table, new_pk) + @@old_to_new[[old_table, old_pk]] = [new_table, new_pk] + @@new_to_old[[new_table, new_pk]] = [old_table, old_pk] + end + + # + # Get new primary key set + # => old_table: Old table name + # => old_pk: Old primary key set + # <= Returns new table and primary key set [new_table, {cn=>value, ...}] + # + def self.get_new_primary_key(old_table, old_pk) + unless @@old_to_new[[old_table, old_pk]] + raise "Key does not exists: #{old_table.pretty_inspect}, #{old_pk.pretty_inspect}" + end + end + + # + # Get old primary key set + # => new_table: New table name + # => new_pk: New primary key set + # <= Returns old table and primary key set [old_table, {cn=>value, ...}] + # + def self.get_old_primary_key(new_table, new_pk) + @@new_to_old[[new_table, new_pk]] + end + + def initialize(old_table, old_pk, new_table, new_pk) + self.save(old_table, old_pk, new_table, new_pk) + end + + def self.print_all + puts "Printing all!" + @@old_to_new.pretty_inspect + end +end diff --git a/prototype/lib/log.rb b/prototype/lib/log.rb new file mode 100755 index 0000000..91c0c46 --- /dev/null +++ b/prototype/lib/log.rb @@ -0,0 +1,140 @@ +#!/usr/bin/env ruby +# +# = Synopsis +# +# Used to write logs and reports +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id$ +# + +class Log + + @@log_directory = 'log' + @@log = {} + + # + # Set log path + # + def self.set_path(path) + unless File.writable?(path) + raise "Log path is not writable: #{path}" + end + @@log_directory = path + end + + # + # Write to a logfine + # => name: Name of the log. Saved to name.log + # => message: Message to write + # + def self.write_log(name, message) + if @@log.empty? + @@log[:log] = Log.new(:log) + end + unless @@log[name] + @@log[name] = Log.new(name) + @@log[:log].write("Created log: #{@@log[name].path}") + end + @@log[name].write(message) + end + + # + # Flushes a logfile + # => name: Name of the logfile to flush + # + def self.flush_log(name) + @@log[name].flush unless @@log[name].nil? + end + + # + # Check for existing log + # => name: Name of the log to check for + # + def self.log_exist(name) + if @@log_handle[name] + return true + else + return nil + end + end + + # + # Make a path from log name + # => name: log name + # + def self.make_path(name) + File.join(@@log_directory, "#{name}.log") + end + + def self.make_regression_path(name) + File.join(@@log_directory, "#{name}.regression") + end + + # + # Remove log file + # => Log name + # + def self.remove(name) + unless @@log[name].nil? + @@log.delete(name).remove + else + path = self.make_path(name) + File.unlink(path) if File.exist?(path) + end + end + + # + # Test regression + # => name: Name of the log to test + # + def self.test_regression(name) + @@log[name].test_regression unless @@log[name].nil? + end + + attr_reader :path + + def initialize(name) + @name = name + @path = Log.make_path(name) + @handle = File.new(@path, 'w') + end + + # + # Write to log + # => msg: Message to write + # + def write(msg) + @handle.puts(msg) + end + + # + # Flush content to logfile + # + def flush + @handle.flush + end + + # + # Remove logfile + # + def remove + @handle.close + File.unlink(@path) + end + + def test_regression + result = `diff #{Log.make_path(@name)} #{Log.make_regression_path(@name)}` + unless result.empty? + puts "Regression found in #{Log.make_path(@name)}:" + puts result + return true + end + return nil + end +end diff --git a/prototype/lib/mapping.rb b/prototype/lib/mapping.rb new file mode 100644 index 0000000..2fe21f5 --- /dev/null +++ b/prototype/lib/mapping.rb @@ -0,0 +1,205 @@ +# = Synopsis +# +# Classes that store schema mapping information. +# +# = Author +# +# - Kjell-Magne Oierud mailto:kjellm@linpro.no +# +# = Version +# +# $Id: mapping.rb 2442 2008-09-04 15:31:10Z robert $ +# + + +# +# Stores the mapping for a table +# +class PrototypeTableMap + + attr :name + + def method_missing(m, *args) + instance_variable_set("@#{m}".to_sym, args[0]) unless args.empty? + instance_variable_get("@#{m}".to_sym) + end + + def initialize(name, &blk) + @name = name + @primary_key = find_primary_key() + @__filter_rows__ = nil + @__precondition__ = nil + @__set__ = [] + @__default_table__ = nil + self.instance_eval(&blk) + end + + def each_column + instance_variables.sort.each do |attr| + + next if attr[0..2] == "@__" + next if attr[0..1] != "@_" + + yield(attr[2..-1], instance_variable_get(attr)) + end + end + + def find_primary_key + query = %Q{ + SELECT column_name + FROM information_schema.table_constraints tc + INNER JOIN + information_schema.key_column_usage kcu + ON tc.constraint_name = kcu.constraint_name + WHERE constraint_type = 'PRIMARY KEY' + AND tc.table_catalog = 'reaktor' + AND tc.table_schema = 'public' + AND tc.table_name = '#{@name}' + ORDER BY ordinal_position; + } + begin + sth = $dbh_pg.execute(query) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not find primary key. Message: #{$!}.") + raise + exit + end + pk = [] + while row = sth.fetch + pk << row[0] + end + return pk + end +end + + +# +# Stores the mapping of a single column +# +class ReaktorColumn + + + attr :name + attr :table + attr :filters + attr :value + + def initialize(attrs = {}) + attrs.each do |k, v| + instance_variable_set("@#{k}", v) + end + end + + def fill_in_defaults(default_table, default_column) + @table ||= default_table + @name ||= default_column + @filters ||= nil + @value = nil unless instance_variable_defined?(:@value) + end + + def inspect + '#' % [@table, @name, [@filters].flatten.length, @value.inspect] + end + + def to_s; inspect; end + + # + # Creates a ReaktorColumn object and make use of its parse_value method + # => value: Default value for column + # => attr_value: Column row value + # => row: SQL result set + # + def self.parse_value(value, attr_value, row) + rc = ReaktorColumn.new({'value' => value}) + rc.parse_value(attr_value, row) + end + + # + # Parses the column value + # %value returns the value on column value + # %_ returns the value of column with the name attr_name + # If no % prefix the column value is returned + # => attr_name: Column name for this column + # => row: SQL result set + # + def parse_value(attr_value, row) + unless row.class == DBI::Row + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "parse_value(): row is not a DBI::Row but a #{row.class}") + exit 1 + end + return @value if @value.nil? + return @value unless @value.kind_of?(String) + + if @value[0] == '%'[0] + if @value == '%_' + return attr_value + else + unless row.to_h.key?(@value[1..-1]) + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "parse_value failed. Data does not contain value indexed by \"#{@value[1..-1]}\". row = #{row.to_h.inspect}, attr_value = #{attr_value.inspect}") + raise + exit + end + unless row[@value[1..-1]] + return '' + else + return row[@value[1..-1]] + end + end + end + return @value + end +end + + +# +# Stores information on an entire row +# +class ReaktorRow + + attr :table + attr :columns + attr :idstore + + def initialize(table, columns, idstore = nil) + @table = table + @columns = columns + @idstore = idstore + end + + def inspect + '#' % [table, (@columns.inject("") {|r, c| r << c.inspect << ', '})] + end + + def to_s; inspect; end +end + + + +# +# Used to signal the import algorithm that this value should be +# ignored. +# +class IGNORE; end + + +# +# Stores a SQL query that is to be executed on the prototype. The +# result of executing the query should typically be a single value. +# +class Query + attr :sql + + def initialize(sql) + @sql = sql + end + + def inspect + '#' % sql + end + + def to_s; inspect; end +end + diff --git a/prototype/lib/parseconfig_extras.rb b/prototype/lib/parseconfig_extras.rb new file mode 100644 index 0000000..4dada97 --- /dev/null +++ b/prototype/lib/parseconfig_extras.rb @@ -0,0 +1,21 @@ +# +# Add methods to the Parseconfig class +# +# = Authors +# * Robert Strind +# + +class ParseConfig + + # + # Returns a hash containing all the instance variable values indexed + # by its instance varaible name with the @ stripped off + # + def get_all + vars = {} + self.instance_variables.map do |v| + vars[v[1..-1].to_sym] = self.instance_variable_get(v) + end + return vars + end +end diff --git a/prototype/lib/schema_map.rb b/prototype/lib/schema_map.rb new file mode 100644 index 0000000..d405686 --- /dev/null +++ b/prototype/lib/schema_map.rb @@ -0,0 +1,748 @@ +#!/usr/bin/env ruby +# +# = Synopsis +# +# Describes the mapping between the schmaes of the prototype +# vs. reaktor +# +# = Authors +# +# - Kjell-Magne Oierud mailto:kjellm@linpro.no +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id: schema_map.rb 2579 2008-09-29 10:03:17Z robert $ +# + +=begin +Table overview: + + T article + T article_formats + T article_topics +[M] T artwork + V artwork_by_day +[M] T artwork_formats + T artwork_help_articles +[M] T artwork_topics +[D] T changelog +[M] T comment + T comment_complaint + V denied_works + S id_seq + V new_users + V new_works + T persdict + T persmem + V queued_works +[M] T rating + T reaktor +[M] T reaktoruser + T site + V top20_users +[M] T topic + T topic_shortlist + V total_artworks + V total_users + T user_help + +T = Table +V = View +S = Sequense +[M] = Migrated +[D] = Data used in migration +=end + +$schema = [] + +############################### U S E R ####################################### + +$schema << PrototypeTableMap.new(:reaktoruser) do + __id_store__ true + __default_table__ :sf_guard_user # Default reaktor table to use + + __filter_rows__ < :dob, + :filters => [Filter.mkdate_from_year], + }) + _in_mailinglist ReaktorColumn.new({:name => :opt_in, :filers =>[ + Filter.boolean_to_integer + ] }) + _site ReaktorRow.new( + :sf_guard_user_group, + [ + ReaktorColumn.new({ + :name => :user_id, + :value => '%id' + }), + ReaktorColumn.new({ + :name => :group_id, + :value => '%_', + :filters => [ + Filter.apply_map($domain_maps[:site_id__sf_guard_group_id]), + Filter.default_if_null(2) + ] + }) + ] + ) + _email_confirmed IGNORE + _artwork_groups ReaktoruserArtworkgroupsPlugin + _type ReaktorRow.new( + :sf_guard_user_group, + [ + ReaktorColumn.new({ + :name => :user_id, + :value => '%id' + }), + ReaktorColumn.new({ + :name => :group_id, + :value => '%_', + :filters => [ + Filter.apply_map($domain_maps[:reaktoruser__type]), + Filter.domain_value_to_id('sf_guard_group', 'name'), + ] + }) + ] + ) + + # Some user types use email as username. They are the only users + # with no nick. + _nick ReaktorColumn.new({ + :name => :username, + :filters => [Filter.if_null([Filter.set_value('%email'), + Filter.add_prefix('staff_'), + Filter.truncate_from('@'), + Filter.add_postfix('%site'), + Filter.add_postfix('-'), + Filter.add_postfix('%id'), + ])] + + }) + + # Some booleans we need to invert ... + _disabled ReaktorColumn.new({ + :name => :is_active, + :filters => Filter.invert, + }) + _public_name ReaktorColumn.new({ + :name => :name_private, + :filters => Filter.invert, + }) + _public_email ReaktorColumn.new({ + :name => :email_private, + :filters => Filter.invert, + }) + + # There are no phone numbers in prototype ... + _telephone ReaktorColumn.new({:name => :phone}) + + _description ReaktorColumn.new({:filters => Filter.parse_richtext_simple}) + + # Convert to ISO encoding + _sex ReaktorColumn.new({ + :filters => [Filter.apply_map($domain_maps[:reaktoruser__sex]), + Filter.default_if_null(0) ] + }) + + _image ReaktorColumn.new({ + :name => :avatar, + :filters => [ + Filter.get_filename_from_lisp, + ] + }) + + # Our residence list should be equal to the values in the prototype + _place_of_residence ReaktorColumn.new({ + :name => :residence_id, + :filters => [Filter.domain_value_to_id('residence', 'name'), + Filter.default_if_null(0)] + }) + + # + # SET + # + __set__ [ + ReaktorColumn.new({:name => :is_super_admin, :value => false}), + ReaktorColumn.new({:name => :algorithm, :value => 'md5'}), + ReaktorColumn.new({ + :name => :created_at, + :value => Query.new("SELECT timestamp FROM changelog WHERE object_type='reaktoruser' AND object = ? AND action = ':CREATE'"), + }), + ReaktorColumn.new({ + :name => :last_login, + :value => Query.new("SELECT MAX(timestamp) FROM changelog WHERE object_type='reaktoruser' AND object = ? AND action = ':LOGIN'"), + }), + ReaktorColumn.new({ + :name => :is_verified, + :value => 1, + }), + ReaktorColumn.new({ + :name => :show_content, + :value => 1, + }), + ReaktorColumn.new({ + :name => :need_profile_check, + :value => 1, + }), + ReaktorColumn.new({ + :name => :dob_is_derived, + :value => 1, + }), + ] +end + + +############################# A R T W O R K #################################### + +$schema << PrototypeTableMap.new(:artwork) do + __id_store__ true + __default_table__ :reaktor_artwork +# +# For å importere verk med id: 14370 legg tallet til i listen under slik: +# AND id NOT IN (11808, 11562, 6329, 6200, 6195, 7417, 6357, 6346, 14370) +# +# Se track ticket #351 +# + __filter_rows__ < :artwork_identifier, + :filters => [Filter.apply_map($domain_maps[:artwork__type])], + }) + + _data ArtworkDataPlugin + + _screenshot IGNORE # This one is handled together with the data column + + _creator ReaktorColumn.new({:name => :user_id}) + + _title ReaktorColumn.new({ + :filters => [ + Filter.replace('#', 'nr.'), + ] + }) + + _description ReaktorColumn.new({ + :filters => [ + Filter.parse_artwork_description, + ] + }) + + _keywords IGNORE + _howto IGNORE # Taken care of in the ArtworkDataPlugin + _help IGNORE # Taken care of in the ArtworkDataPlugin + + _editor IGNORE + + #### METADATA + + _rights IGNORE # Handled by ArtworkDataPlugin + + _width ReaktorRow.new(:file_metadata, [ + ReaktorColumn.new({:name => :file, :value => '%id'}), + ReaktorColumn.new({:name => :meta_element, :value => 'format'}), + ReaktorColumn.new({:name => :meta_qualifier, :value => 'width'}), + ReaktorColumn.new({:name => :meta_value, :value => '%_'}), + ]) + + _height ReaktorRow.new(:file_metadata, [ + ReaktorColumn.new({:name => :file, :value => '%id'}), + ReaktorColumn.new({:name => :meta_element, :value => 'format'}), + ReaktorColumn.new({:name => :meta_qualifier, :value => 'height'}), + ReaktorColumn.new({:name => :meta_value, :value => '%_'}), + ]) + + #### END METADATA + + _site ReaktorColumn.new({ + :name => :team_id, + :value => '%_', + :filters => [ + Filter.get_value_from_query($dbh_pg, "SELECT LOWER(title) AS title FROM site WHERE id = ?"), + Filter.default_if_null('users'), + Filter.apply_map($domain_maps[:site_title__sf_guard_group_name]), + Filter.get_value_from_query($dbh_ms, "SELECT id FROM sf_guard_group WHERE name = '?'"), + Filter.default_if_null(2), + ] + }) + + _publish_state ReaktorColumn.new({ + :name => :status, + :filters => [ + Filter.apply_map($domain_maps[:artwork__publish_state]), + Filter.domain_value_to_id('artwork_status', 'name'), # Get id from artwork_status + ] + }) + _under_discussion ReaktorColumn.new({:filters => [Filter.boolean_to_integer]}) + + _internal_discussion ArtworkInternalDiscussionPlugin + + + # + # SET + # + __set__ [ + # + # Created at + # + ReaktorColumn.new({ + :name => :created_at, + :value => Query.new("SELECT timestamp FROM changelog WHERE action = ':CREATE' AND object = ?"), + :filters => [ + Filter.truncate(19, ''), + ] + }), + # + # Actioned at + # + ReaktorColumn.new({ + :name => :actioned_at, + :value => Query.new("SELECT timestamp FROM changelog WHERE action = ':ACCEPT' AND object = ?"), + :filters => [ + Filter.if_null([ + Filter.get_value_from_query($dbh_pg, %Q{SELECT timestamp FROM changelog WHERE action = ':CREATE' AND object = %id}), + ]), + Filter.truncate(19, ''), + ] + }), + # + # Submitted at + # + ReaktorColumn.new({ + :name => :submitted_at, + :value => Query.new("SELECT timestamp FROM changelog WHERE action = ':CREATE' AND object = ?"), + :filters => [ + Filter.truncate(19, ''), + ] + }), + # + # Actioned by + # + ReaktorColumn.new({ + :name => :actioned_by, + :value => Query.new("SELECT reaktoruser FROM changelog WHERE action = ':ACCEPT' AND object_type = 'artwork' AND object = ?"), + :filters => Filter.default_if_null(0), + }), + # + # Average rating + # + ReaktorColumn.new({ + :name => :average_rating, + :value => Query.new("SELECT AVG(rating) FROM rating WHERE artwork = ?"), + }), + ] +end + + + +##################### A R T W O R K R A T I N G S ########################## + +$schema << PrototypeTableMap.new(:rating) do + __default_table__ :sf_ratings + + # Check that artwork has been imported before inserting + __precondition__ %q{SELECT EXISTS(SELECT * FROM reaktor_artwork WHERE id = %artwork)} + + _reaktoruser ReaktorColumn.new({:name => :user_id}) + _artwork ReaktorColumn.new({:name => :ratable_id}) + + # The scale for rating seems to be 1..6 in both version -> no + # conversion needed :) + _rating ReaktorColumn.new() + + __set__ [ + ReaktorColumn.new({:name => :ratable_model, :value => 'ReaktorArtwork'}), + ReaktorColumn.new({:name => :rated_at, :value => '2008-10-01'}), + ] +end + + + +#################### A R T W O R K C O M M E N T S ######################### + +$schema << PrototypeTableMap.new(:comment) do + __default_table__ :sf_comment + # Check that user and artwork has been imported + __precondition__ %q{ + SELECT ( + EXISTS(SELECT * FROM sf_guard_user WHERE id = %creator) + AND + EXISTS(SELECT * FROM reaktor_artwork WHERE id = %artwork) + ) + } + __query__ < :parent_id}) + _creator ReaktorColumn.new({:name => :author_id}) + _artwork ReaktorColumn.new({:name => :commentable_id}) + _hidden ReaktorColumn.new({:name => :unsuitable}) + _subject ReaktorColumn.new({:name => :title}) + _body ReaktorColumn.new({ + :name => :text, + :filters => [Filter.trim_lisp_encl_params], + }) + + __set__ [ + ReaktorColumn.new({:name => :commentable_model, :value => 'ReaktorArtwork'}), + ReaktorColumn.new({:name => :namespace, :value => 'frontend'}), + ReaktorColumn.new({ + :name => :created_at, + :value => Query.new("SELECT MAX(timestamp) FROM changelog WHERE object_type='comment' AND object = ?"), + }) + ] +end + +#################### S U B R E A K T O R ######################### +=begin Subreaktors are imported in fixtures +$schema << PrototypeTableMap.new(:topic) do + __default_table__ :subreaktor + __filter_rows__ 'parent = 2' + + _id ReaktorColumn.new + _parent IGNORE + _title ReaktorColumn.new({ + :name => :reference, + :value => '%_', + :filters => [ + Filter.downcase(), # reference must be lower case + Filter.truncate(15, '') # reference is a VARCHAR(15) + ] + }) + _description IGNORE + _independant_title IGNORE + + __set__ [ + ReaktorColumn.new({:name => :lokalreaktor, :value => 0}), + ReaktorColumn.new({:name => :live, :value => 1}), + ReaktorColumn.new({:name => :subreaktor_order, :value => 0}), + ] +end +=end + +#################### C A T E G O R Y ######################### + +$schema << PrototypeTableMap.new(:topic) do + __default_table__ :category + + __precondition__ %q{ + SELECT NOT EXISTS( + SELECT * + FROM category + WHERE basename = LOWER('%title') + ) + } + + __query__ < 2 +EOF + + _id ReaktorColumn.new + _title ReaktorColumn.new({ + :name => :basename, + :value => '%_', + :filters => [ + Filter.downcase(), # basename must be lower case + ] + }) +end + +#################### C A T E G O R Y I 1 8 N (no) ####################### + +$schema << PrototypeTableMap.new(:topic) do + __default_table__ :category_i18n + + # Don't import categories that allready exists + __precondition__ %q{ + SELECT EXISTS( + SELECT * + FROM category + WHERE basename = '%title' + ) + } + + __query__ < 2 AND parent > 2 +EOF + + _id ReaktorColumn.new + _title ReaktorColumn.new({ + :name => :name, + :value => '%_', + :filters => [ + Filter.downcase(), # basename must be lower case + ] + }) + + __set__ [ + ReaktorColumn.new({ + :name => :culture, + :value => 'no', + }) + ] +end + +#################### C A T E G O R Y I 1 8 N (nn) ####################### + +$schema << PrototypeTableMap.new(:topic) do + __default_table__ :category_i18n + + # Don't import categories that allready exists + __precondition__ %q{ + SELECT EXISTS( + SELECT * + FROM category + WHERE basename = '%title' + ) + } + + __query__ < 2 AND parent > 2 +EOF + + _id ReaktorColumn.new + _title ReaktorColumn.new({ + :name => :name, + :value => '%_', + :filters => [ + Filter.downcase(), # basename must be lower case + Filter.truncate(25, ''), # basename is a VARCHAR(25) + ] + }) + + __set__ [ + ReaktorColumn.new({ + :name => :culture, + :value => 'nn', + }) + ] +end + +#################### C A T E G O R Y I 1 8 N (en) ####################### + +$schema << PrototypeTableMap.new(:topic) do + __default_table__ :category_i18n + + # Don't import categories that allready exists + __precondition__ %q{ + SELECT EXISTS( + SELECT * + FROM category + WHERE basename = '%title' + ) + } + + __query__ < 2 AND parent > 2 +EOF + + _id ReaktorColumn.new + _title ReaktorColumn.new({ + :name => :name, + :value => '%_', + :filters => [ + Filter.downcase(), # basename must be lower case + Filter.truncate(25, ''), # basename is a VARCHAR(25) + ] + }) + + __set__ [ + ReaktorColumn.new({ + :name => :culture, + :value => 'en', + }) + ] +end + +#################### T A G ######################### + +$schema << PrototypeTableMap.new(:topic) do + __default_table__ :tag + __query__ < 1 +EOF + + _id ReaktorColumn.new + _title ReaktorColumn.new({ + :name => :name, + :value => '%_', + :filters => [Filter.downcase()] + }) + + __set__ [ + ReaktorColumn.new({:name => :approved, :value => 1}), + ReaktorColumn.new({:name => :approved_by, :value => 0}), + ReaktorColumn.new({:name => :approved_at, :value => '1970-01-01 00:00:00'}), + ReaktorColumn.new({ + :name => :width, + :value => '%title', + :filters => [Filter.string_length()] + }), + ] +end + +#################### C A T E G O R Y A R T W O R K ####################### + +$schema << PrototypeTableMap.new(:artwork_formats) do + __default_table__ :category_artwork + __ + __precondition__ %q{SELECT EXISTS( + SELECT * + FROM reaktor_artwork + WHERE id = %artwork + )} + + _artwork ReaktorColumn.new({ + :name => :artwork_id, + :value => '%_', + }) + _topic ReaktorColumn.new({ + :name => :category_id, + :value => '%_', + :filters => [ + Filter.get_value_from_query($dbh_pg, %q{SELECT lower(title) FROM topic WHERE id = %_}), + Filter.get_value_from_query($dbh_ms, %q{SELECT id FROM category WHERE basename = '?'}), + Filter.default_if_null('%topic'), + ] + }) +end + +######################### T A G G I N G ########################## + +$schema << PrototypeTableMap.new(:artwork_topics) do + #__default_table__ :tagging # This is handled by the ArtworkTopicTaggingPlugin + + # Select only artworks that have a tag set + __precondition__ %q{SELECT ( + EXISTS (SELECT * FROM tag WHERE id = %topic) + AND + EXISTS (SELECT * FROM reaktor_artwork WHERE id = %artwork) + )} + + _artwork ArtworkTopicTaggingPlugin + + _topic IGNORE # Handled by the ArtworkTopicTaggingPlugin +end + +#################### S U B R E A K T O R A R T W O R K ##################### + +$schema << PrototypeTableMap.new(:topic) do + __default_table__ :subreaktor_artwork + + __query__ < 2 +EOF + + __precondition__ %q{ + SELECT EXISTS ( + SELECT * FROM reaktor_artwork WHERE id = %artwork_id + ) + } + + _subreaktor_id ReaktorColumn.new({ + :filters => [ + Filter.apply_map($domain_maps[:topic_id__subreaktor_id]), + ] + }) + + _artwork_id ReaktorColumn.new +end + +################# C A T E G O R Y S U B R E A K T O R ###################### + +$schema << PrototypeTableMap.new(:topic) do + __default_table__ :category_subreaktor + + __query__ < 2 +EOF + + __precondition__ %q{ + SELECT EXISTS ( + SELECT * FROM category WHERE id = %category_id + ) + } + + _subreaktor_id ReaktorColumn.new({ + :filters => [ + Filter.apply_map($domain_maps[:topic_id__subreaktor_id]), + ] + }) + _category_id ReaktorColumn.new({ + :filters => [ + Filter.get_value_from_query($dbh_pg, "SELECT lower(title) FROM topic WHERE id = %category_id"), + Filter.get_value_from_query($dbh_ms, "SELECT id FROM category WHERE basename = '?'"), + Filter.default_if_null('%_'), + ], + }) +end + +############################################################################### +###################### E N D O F S C H E M A M A P ###################### +############################################################################### diff --git a/prototype/lib/symfony.rb b/prototype/lib/symfony.rb new file mode 100644 index 0000000..c397fb3 --- /dev/null +++ b/prototype/lib/symfony.rb @@ -0,0 +1,97 @@ +# +# = Synopsis +# Configure a symfony installation +# +# = Authors +# * Robert Strind +# +# = Version +# $Id: $ +# +require 'fileutils' + +class Symfony + def initialize(cnf) + @path = cnf[:path_symfony] + @db_name = cnf[:to_db_name] + @db_user = cnf[:to_db_user] + @db_password = cnf[:to_db_password] + @debug = cnf[:debug] + end + + # + # Configure symfony configuration files + # + def configure + configure_databases_yml + configure_propel_ini + end + + # + # Perform a symfony clear cache + # + def cc + Dir.chdir(@path) {@output = `symfony cc`} + puts @output if @debug + end + + # + # Set file permissions + # + def set_permissions + files = [ + 'log', 'content', 'cache', 'web/uploads', 'web/images', + 'apps/reaktor/modules/subreaktors/templates', + 'apps/reaktor/lib/transcode/transcodevideo.sh', + 'apps/reaktor/lib/transcode/transcodeaudio.sh', + ] + files.map! {|f| @path + '/' + f} + FileUtils.chmod_R 0777, files + if @debug + puts "Set permissions (0777) on following files/directories:" + files.each {|f| puts "\t#{f}"} + end + end + + # + # Configure the databases.yml file + # + def configure_databases_yml + path = @path + '/config/databases.yml' + unless File.readable?(path) + raise "Could not configure databases.yml. File is not writable!" + end + fc = open(path).read + path_backup = path + '.bak' + unless File.exists?(path_backup) + FileUtils::mv path, path_backup + puts "Copied databases.yml to #{path_backup}" if @debug + end + fc.gsub!(/database:\s*.+/, "database: #{@db_name}") + fc.gsub!(/username:\s*.+/, "username: #{@db_user}") + fc.gsub!(/password:\s*.+/, "password: #{@db_password}") + open(path, 'w').print fc + puts "Configured databases.yml" if @debug + end + + # + # Configure the propel.ini file + # + def configure_propel_ini + path = @path + '/config/propel.ini' + unless File.readable?(path) + raise "Could not configure databases.yml. File is not writable!" + end + fc = open(path).read + path_backup = path + '.bak' + unless File.exists?(path_backup) + FileUtils::mv path, path_backup + puts "Copied propel.ini to #{path_backup}" if @debug + end + fc.gsub!(/propel.database.createUrl\s*=\s*.+/, "propel.database.createUrl = mysql://#{@db_user}:#{@db_password}@localhost/") + fc.gsub!(/propel.database.url\s*=\s*.+/, "propel.database.url = mysql://#{@db_user}:#{@db_password}@localhost/#{@db_name}") + open(path, 'w').print fc + puts "Configured propel.ini" if @debug + end + +end diff --git a/prototype/lib/utf8_converter.rb b/prototype/lib/utf8_converter.rb new file mode 100644 index 0000000..7893b31 --- /dev/null +++ b/prototype/lib/utf8_converter.rb @@ -0,0 +1,33 @@ +# +# To change this template, choose Tools | Templates +# and open the template in the editor. + + +class Utf8_Converter + + attr_reader :text + + @@map = { + "\xC2\x96" => '-', + "\xC2\x94" => '"', + "\xC3\xA6" => 'æ', + "\xC3\x86" => 'Æ', + "\xC3\xB8" => 'ø', + "\xC3\x98" => 'Ø', + "\xC3\xA5" => 'å', + "\xC3\x85" => 'Å', + } + def self.convert(text) + @@map.each {|u,a| text.gsub!(u, a)} + return text + end + + def initialize(text) + @text = self.convert(text) + end +end + +if __FILE__ == $0 + puts Utf8_Converter::convert("Hei dette er en \xC2\x96") + puts Utf8_Converter::convert("Hei dette er en \xC3\x86") +end diff --git a/prototype/log/artwork_data_plugin.regression b/prototype/log/artwork_data_plugin.regression new file mode 100644 index 0000000..b27e956 --- /dev/null +++ b/prototype/log/artwork_data_plugin.regression @@ -0,0 +1,1486 @@ +73B9DBC4B8F27D39BC486FDCC9188B061D23307C93F07425A006A169F3A9BF84.jpg +ED6A8C945DA1DBE1AB7949EEB9AA961907766202F73F8559F7AC0B86042B9EEE.jpg +E48B87AF966E2CDC9BEE00EC556E388A7FA502773313DB5FC2242B76CAD8288F.jpg +DE0D1B93ADD81F135A6FCD776869BAA8EB10B64771DDC2C1A57867448AD4A703.jpg +12CFC36465C57986B8F289CD1B08CE5F15CE39DDB1112723DBBE578D81D398BC.jpg +C25B22A2D9944DC459EE2E7FBA227787ED6AB137AF16C83AEA844564ABC6BD6C.asf +11C654026BE378196244832BFD22FBBE3ACFEE72BF1710D42815832160E8E1A5.asf +E25F037F92DBB6930F0BF55AE3A976B0C2E6B1FA7746E8B898EC59655302921C.asf +8AF32FCD2072A8EB93B4609329D25683E6EFF2138CAAF68C0E92321A4A1E10D5.pdf +A03F20B8A81A184F98A5169998116CBD5DF0AEE5F751470358EDEA00A1466447.jpg +AD532AEDD483769BEA746483F24F44DD33518C3D84F1C3D33F6C63CC42F16FDE.jpg +522630C556A7B6D7EED4C6DEF6E0899942A3D69566C79AF69E1C3883E1D2620B.asf +A71BACEB01E795FC3C93FC84DD54E9975299DC0CDDC0255FD3A7EF4E0B7951F0.asf +2B4D4CD56BA905FDF005C5FC40001A1C30BD6B238E7BDA1CF67B25C1A9560C81.asf +4382F07C2E57E88CA538259743C5C4D27A0C45A3335512919C526EC8B744292C.jpg +98610827169E32CB6320AE91805E305AB7AF0778B50DFC2BF399356E51BD8685.asf +A556A13720A50E62F6EA73085C604377BBC2500C2B4089BC3EFFC4C70508E94C.asf +D879A795A382E1B50C6ECD6A5E786519A2BF2A8312A0B293067D33D3A85F5392.asf +2D4D817BE2550CB3A89592DC92E42982C447D58E4831CD6BEBC847F4524E0AF9.asf +7A1D5FE5C86C6CBC7E4C8D58F805AAF4CAA05919618DABE4F9293E976FADD689.asf +FD0CDDFB906081693CF628AE0E53DA85D3AF8E02E2A9A27D165381507A2C0078.jpg +CC5FC4BF4BE952CE00590DD87E95BFA6511583A2393924786A877D1A2718CBEC.jpg +FD0E2A3FF776194F82E3F78E34F41686616D32497F489032889ED03F00088FDD.jpg +BDA11E9A2E676E021132813AC7F7621ADD431AE998D3EC6784D5F88DF5474C71.jpg +E0019FEB6F202C87CCB825750FFDC7833EC92BFF74D59F39A6A4F2D8129E1D29.asf +853A48E01ABA76C228CC5BB5775CAB5DF4064F6D5D51694FF6B5F240BE15843.asf +508C184CA0242F9E37A15989C039C827D4785CEB3EE7FA5B122B2DF4BF961B13.asf +B1E8BA63A60C39464D6C32AC37D690CC6C36FE56B6E59375FECA24F5BD833E24.jpg +8877390BBD5249B34EB776DC8A994A625DC0FFA1F1C0E3A5B76B76101D287465.mov +EE4E6A665883E425EC2B942C21F1E4B00C2D2282D17F194CB63EB6CA6E0B7DA6.mov +A39938DDA2CD016FA2E05142DCA9DBA77F0998B53BD2C7D6BAF3259F22B1DEC2.jpg +27C847532B4E01FFDD0A6DF36968CD775CA9C893ADFE9A9ABEB9600B8FFE6F50.jpg +F9C76F6A6E8723BC259FF7C879FA8DA5D60CA6CACA57D347EE9A1FC176C659C1.mp3 +B7C75F4EE0D926A79DC45ABC840B273A2916BC09BA0DED3B1FDB856F326B6161.jpg +1BF3B054557C4957A8E1491E391515C082DEDC2CBC06EA201113508991958D13.jpg +6D6BBD2CECC91E26F887D74E324E75B8D7A0D3578A47AF6A0881AF00F6B3D571.mp3 +AB0F8DC3BE2408303534BAEABAC18614CC5AD24EAF169EC50C187AA5A3C10DE0.mp3 +1EBABE664D98E89228F64633D642024F1EFC5DB1ACCD6A81178DC6B22AE2B57C.mp3 +C0F7EE87C6AB52F48BC29AD4BE87EAA19B2657E436BAA0D9E2B72278961B3CA9.mp3 +83D745A01F603C7FF0F5F9EC3DCBAB99F89CE3FD8F7A993253E5CA596258F58C.mp3 +EDC5A84B054B5CBE8EF916933EAD66CE2B5DECB71CA1C061EC086B2DB5B68AC1.mp3 +8E60A9D680205ABE88EED13AE17DE68435BD561BF8B71C5C96A5603C552620A7.mp3 +DD93F191C18BC1717D28F2497074D92E66ADB5A9F8CA2C3F604D230ABB8E988A.jpg +9985875C399106D8925987C913669926C2FF71A87F2F7D5161C07BD86775E498.mp3 +D6B92BF96695088E934390621A4F43503767A5E78C6D4DD6B6BE7728D429F51C.mov +D99EABED95D8E001B883801B2E0FA4CA62E366B248A37EE0CAA1B0A5057D5220.asf +57381493AE1F8B45F5910D71D76F22659999999A37FADA00D0547F6348505412.asf +7ED52FA460CEFF94F7AE1D3BD910552063512654A65157A1F6C1C324FFE4B058.asf +BAF1D45B8D137CB90E8B7A74962E3574382FBB39D08CCAA4A030C75ADD27C483.asf +A29A7EEF98DF2275C604253B9C3AF6B390FDAF08B184A20D4751CB1F4C9C88C5.asf +8F1F0F2AE7736EC0DD4B67DF75EE67B1101C9A47212937EC773E579AD9474613.jpg +C08A412C704D54125EDA4561B3F335618E0F3FE029CACF5A66DCD2B28FE339CC.jpg +A318236434B661683D6DF34063B0513F888B540C65ABE8654124D71942CEF8EE.jpg +BB8EC4749486F4125727D9D693129FD56BCA927360568610F6C4A9A8DDBDF22A.jpg +808409C5162C5E5E5F2DFE4CC797F284128654758B52D4DF4A290FB3143F08FF.jpg +F8C602062ED31A33CF0962B3BC00BD3E408774B7BC70CB5273B5A4A0D40B150E.mp3 +211D5EAFB5055B825AC9CA25A2821AA50A746586BDE49F176D7E061A534D5AA4.mov +3D04499C522D992508D3E766203A69A2846F8E597F640F333DB7CF2B3716980.jpg +ECFB174D2A817DF18A0EAFF7483DC292D49B6608D9EA1B7C160380B82C85A10D.mp3 +83A0F07BDAE263FF7BF00CE03D7480A0FB28ECD2D94F3ED981D5A53A1F2E8AD9.asf +704E7D1996A4888F08AF393ED989FFD48C906BFBBB0F92C87993C9074516F3FE.asf +57EF5C0518E308B1754C8613F0687AA37BC7BD8E40F889AECC07DAB28F68E3AC.asf +AD3FDD49EA489A61D4143BCEA00589C456C2DAFF30A00B5AAEF403960294CEC1.asf +39F1C78CC14B77EAD60FF01FD4D492F638A5D6F5E9AAA69E1B84B1355302FA5E.jpg +12271046D96B0417F33AA459CDDB595E394E5131A6C7953BCCBBA042E3F06F3A.jpg +DF2F76A16720AAF87AC97807E0D168DF7401F65169BCF7BCCAD55CE450E90E0F.mov +BC66192DB46EE6F5EE867F6E448AC9B90B2009FA4DFA6B8C231B61D8F644DBB8.mov +FB744BC629CC33BDD404BEA8895B6C077914C91A4ADF0C62F504A0F6C191BD31.mov +5C9B22B83B19D367B898AEA3F73FA0AADAEBFF6A2CBAC84BC6C21A22D5137176.jpg +B4858C02030FBBD6754E820402629C142722C0E71AA6E50B15C6DC008E6578D.jpg +5C6A4AD3F73010D6290734FC19332B007DC624208AF2D5BC6DB23062C073AD98.mp3 +CDFEBFDBF92FF5A163DBC33036B675A4CBB7FAF93F07259316B4BD3109A23325.jpg +F5E3C5B7643E70640F9D7B3FB6EF3D70910E6CC92A6B3D81650C61591CD9DE7E.jpg +D80E2305550985A9364C3CBA399CFEF4E562BC559FAED4E81C3459DCBCAEDCBF.mov +6416CE5D989C9CC12934A7A21E82D52C219EAFDEA5023C8095016152F04BFF74.asf +C056049C37585449F0912F45C830A89CB04D77E47FCC9A1471F9608AD2A9884B.mov +55F1444CD29EA5F6F9B157262E8C2C6D28F13F174DACA9B37B89C5C1032978B9.jpg +E00FCACA1618E6E91223481B977329496E00B8EB06C90F514DD43B8F32DDEA79.jpg +731BD38D3353F41E771320D942FCE0C178510A106E06148F7B513A5F6153747C.jpg +9877D374A20B43DE0CDA08217FD9850286A37B853A3B276793525DF53CE1FEE4.mov +900DF352B55084E0748F2DAD376660E25C45A080546435DFC1DD6219D33D36C2.mp3 +3E20A5D7CE3E730CAE69F15435C163B33C45EA49A5A093915415A40604CFB3AD.jpg +C1C8943E72813B4B3D6782EBC7CB8C0C1AF627C63B7D008E4540F6A32405F45F.jpg +FCA8AC4731EFF5D4B8EF321162E63E56CA31DDF6D77B1F3716D9F0150F193C6D.jpg +35E4998226C287E6A608DBA2B73AD42EFAAAE21A5D9B1231EE1EC8DEB0242108.mp3 +CF9228A5105C20C8FAE62014E7DD4E480C2F63EC12CE00EBAA04FDB5D9ED8F9F.jpg +FCBB1B212652981549BA294AFB25D00263C0F789CBF825073688737C47C3B4CF.jpg +AE8D9DFFDA8FC83A4A5EEEB5532BDD168E17293A889A911D94206CFEAC35B56A.jpg +F4ED2831D747246214C7B67F7E5FCC7C2AAFE2AD75970EF8147AA75EFD8667C5.mov +27169D462B555D9BB8F36AFE2D2A0AB8EBC3F613958E9CF3351F32E50FBB28E.mov +F667F3E966D7F96E254181E42DCC855C34B761A15EAC376A498D80EB12E723EC.jpg +303B2BB6730421F81E5ADA17A91A4B5353C8BAAE95B75B987213C7C1B2608413.jpg +E86F6CCA08C32C60ACD3AA92579D2C2142933CD4C39005F7468FF3835A644C07.mov +D633C058BD236A7622D31ADB8634A02CD5E9F1EE5BE5FF3E2677D26B60F0E8F3.jpg +3AE47AEAB6E9C7A27D143B616AFD9974B203E8C740736CF34BF1FC7414ABA2DE.jpg +7263FC27B7072E9AF45DF63870A1FDBDB2A9A58DAB534B89189E9F8BC7CF812A.jpg +F3626E9192A029B69304F956133E256A5A9EB852CA57130C6CFB606DED0FC8F2.jpg +15B4EDEEC08ECED054B1CE329BAABD3191C731FF487A7E471ABB62C75A303B51.jpg +F3D196B04F35E1D7ECCA8BF6D4BF206C5E735C34B8D9EB832BCC2AA54F1A98A9.jpg +1AB809028E393EDA4A815B7477C292AFA140B9DE16E0DF7BD4AC719B998EBC54.mp3 +29ACB87D85EC9B8FB6460E002E2CD830DE3C09194C912FEBC7D5D1B6D3DEF93F.jpg +51B8499EEDC32ABAD573917D2DD17E8AA38AEC900730550B6AA91B5BBC015875.mp3 +D4BB5CF750A745941199F36B2CB2E0A9061926831993822E05CBC02E5797DD48.jpg +A15F65BFD51F1BF51E87EB654D881E0C26EF811A9663C83517D2B1D6E1BDC369.mp3 +DF4E5D076D024D8B238374542326D7B462942FF702470354D0C986E26336D9D2.jpg +23B7D99C4A87E6D802F1C57B80D114EEB6A7EC9F7FA19142C4DC14CBAA7D4C82.gif +ECAC69B682FD64FA5FF035DBA727F76F3BAEBB6BBEA5DA8FC0914BE081A9406D.jpg +EDCD753A41738D28A828908F731B3AF9C46AC63969003B21E5656696D0A20B13.jpg +876898E4AA70C79694CB3D744D52B4EB8094213A20C5AB3EC597F88C4B1B9469.jpg +369494C733184DF2A68FFFD5CDE0CD828AA8DD56294D4F1641EDDC0EAB845207.mp3 +AEC55CED96D8743917D543BF12505365162121990AA10DC06D9A6288A76E16AA.jpg +C397D3EA32036257A678880E83B817953D3A0CA9AEC31948E56F0B97F45DC2DA.jpg +75F159DDD096038CB54E1B052F8151CF3A14C5ADF62E4B3AC8AD65950B267CC9.jpg +E940448C04FE6554F8702CA1221A81B19000150E4A9212E8AC6E7A9BB9BFC50F.jpg +3FE3ECBC26C4B2F14E8B46EF18010C091733FF567ABA1377E285D0A6FE0ED0C.jpg +16A5B59DE96F27DCAF803E077FE1C42885C282E904C4B8243B39B8B6DC283707.jpg +7B1D3A3C9E648E2ACD71D98CB9E38259F9C8A19D889FF773E9C4D390DDC39AD1.jpg +876898E4AA70C79694CB3D744D52B4EB8094213A20C5AB3EC597F88C4B1B9469.jpg +A4F97748CB0404B9321456CDF316BCEB01B3233D5CFC82ABAEC29F6CD88CDD6E.jpg +5DDBD9A5262BE17BE5335D8E29416979B0FAA1F89A10646D82E9890BB892F019.jpg +1B9A6075902349BA207DCCD8D5ABF753F9B49F643D5110B761787056A9E4AAE3.jpg +42E606B35FDC74EA06880F8B51BF30AFDB781C65A6FF0135EB7E1A185DE8ACAB.jpg +19BC6357E8631BA72319A7BE14D2B793A5E46840A65450189673990664137E4C.mp3 +AF5B8756E93768F4A7DEECD86D8EFED13507E0ED0A6B449B77FC41D7F8C92294.jpg +1EB8C0DC65603DC3237E1A01E52BE7DF8CBA9EE0FEDC19AA710E6E395B520DD1.jpg +EE2032028F427BF10E971BCA571E93F07A0948385C3EFFD25E84AE2A00A2A906.jpg +64FBE4D53D98DB4FFC6147443085FE49EF97B883FE2E9AFD9F04789D8337AB82.jpg +1236FF93880C94F2B73B31AA240E71FDC87B893B99D2F00D5BACF7D23FDD8FDD.jpg +3189E0730AE2B3753DC28523EAD0AC6F5DF0AE362246B12BE3474F039932B6D2.gif +B261873748CAB1AE680296D8E3AC7B68DF0DBAA0D0A7CFE0F86B2954DDACC75F.jpg +A83EF68B1616B04A9ED91642CC985729975D7F4C34AA1B8E37250BF53816AB3B.jpg +9DF4794DB5D36A1A8E2707FE7ED228C78DA8653FFFA4E29C467E907073D52256.jpg +F06652A0FBE4B51EA11512AB4AC5C4D000BE876948836737D0DC1596CA7619D6.jpg +BC84D852E043A7C8194E1A9A57147C1A3AB9CDA28BCDF8AD30BA27503717640C.jpg +C1FD3F9A1FCA688A0EA5A80FB44BD890DF1039B2D78D4EF8540D72F8BB43C85C.jpg +F2B0A15CFE7520309B4088C849C34A10B18169A7DC45D59E5C652DBB1ABB0ABB.jpg +ABBD20D5002109D2486BD75ADFBC61C8ABBDBD7C95D1012CCD515E94D43BEAD.jpg +27A59DDC70DC7B8FC7D32E30B1B79031B270F248F60D5A0D5A6B90CC58648D9F.jpg +85BC1465DAE5DE1830C8C262EF29EB63A0F2603DCF480D9E43A32F25DDEF33E5.jpg +ADD35B977EF95620B3BFA2AFD7C508757227F18D8B5668D736F455BF051B3001.jpg +3492B1EF8EF3755F19118977D970EFD1AD4EE32F8423E196320A58DAEC8D70F1.jpg +CDC868E5F1407FB7BFA9FD94D3D001151EAFAD404025AFCF5B2ABDF9BE164F6B.jpg +55BAB35781B4E03D9D0A6FD41E428006548CA9D8DA09FAD70A6B446841E5C2A0.jpg +A1A92D3CFDEBB259D1EF6E048B080E3107DE6EADA47AA0CBB098B5AE4C21C08C.jpg +E83CD63154F44BF81C6E2BE7D92BE77A5C1723E5E64A202E68DB295F69C979E5.mp3 +901ADDAF984AA713733009C462F799B70CFAD5857EB1B432606B3AC4AAE2B2CF.jpg +46154B9990E32FC23E9FFBB94A816C6C5C2B20D6A3B839B5C4C843DD9BFD6C09.jpg +DCD693430AF22BB29ABA52DCF18E5FA8EFE7EE4336F63EFA80EB6ADE43B8F6A0.jpg +3F41C3991F117F5A6C4589AC208713A6AA08685D6A1544E41E4AE7D51D24320D.jpg +1FE841C7F225C27E68A81B3410E6AFF8962156666C498829D49A1DA02B5FD22B.jpg +F3031234D5F9BBF9EAFA76AE70D80D0CC44ABD0D3D3E6C91991F9B23F2CB4ADA.jpg +C80D2005E45F97C8FD9040793C9A5774C5B6E01C2E2CF0E51793704867F57E8E.mp3 +5216CCBED0AE78A8BCFFF734796459AC288144F5FA84FB2ED4F888C6BECA9913.mp3 +2451969A356AA0074F806DCD69241CF91403D02BF44DBD5C3D6FD317F151E899.mp3 +CC4B148CDC71C14FEB90B056CFAF019EE06F57A1E4FF02A4BD2243BD633B06DA.mp3 +FF47F4A6C045BCA031E44C3F0A4954AED575DD1BB8431BFB678FC4E2983BDF38.mp3 +3909B7F5E14D44275C6F84B52B7466E288FAC84234916C592D2FC845C34CB2A3.mp3 +287DA659FEE3E3B221E68C6E20A51EC6D9ADF5B943096B31C7D425607CCF8E83.mp3 +FAB5CBF73039423D5B4796AAB6DC93BF3DD906FBAA2DA63AB2C45FA20BA7475.mp3 +3BA56FAE753569F7026A8CE8890F52FADA5571162B7C5E01348CD54D5B9AF4A8.jpg +86625294C2104D5C42F3B8A9FA9742BEE08326FDEBC073B2F32BDF5E36F7DFA3.jpg +1DB6717D2CC48ABDFE60FF2A3A5469520B7C615B2E80F8E9FA73831800C3DBC2.gif +ADE3F448054B48B5637AB964676BF2CB2A958DC4E0F4BC730F0D531C7FA18ABE.jpg +AA95055B1784A804D4696220AC13DAB5EE2AF0556766E9A24CE256F360D3426D.jpg +6E9E95E7305C4F62163154BB82FC3702FF3C6B4F1884B147FE2F76A2C0342E62.jpg +36FBC153E55B975D002B4E96B6DEDEB135E4DB85054582D4D501D1B1A65B17A8.jpg +8DDA32359718BFB6D34F2C571678BB09E5AA8684070776E3E352010BE8F1DF0E.jpg +C9119410224CC88BC9C1804368E01C0DFEF8147A59AF6FDF248CC3C0333BF1D7.jpg +9B575BB3F60F18B9E89D87725E82A7F105B37B3B1606DB7B407BBB5CB334C564.mp3 +DE8CCA54D2FAE046E828652BB3D602C812CAE01C5D540AFF856892BB3DB493A8.gif +7D78E81FDEF87680AAC401D737697C1ADAC49198BBFCD65708E727E408E1F42A.jpg +287F5848819B1A5693562EF0C90F414C769A847EF18E3300EB0AB0F0C5B2024D.jpg +5AECC180D670792B871A5FCC0741CA0661B3FCA747A9574D420D05D22E497281.jpg +7DAD6F7FE4E7D9BB63543CCF4E25ABC4B67548C0D332EE87598CA92D5F68A46B.jpg +62066F147E7353B21FA54790E6342EB236B560B0D4EAE1A55CCF52543E921A16.mp3 +1F23BA881C2593E56E057905C96EE5A229BE447AAA411E8410EBA73048AF935.gif +A2002F216458E9D117F5BB29D7F9B6B7353051F87ABF5CBB15CC15F5F7E3939.jpg +C86DDF5ECB1630D3F346F5397001B0F7B46DDD8A143F26BD733E99D71F3CC457.gif +EA9FB6E499838F1D18D60D5E1E611CED84D05A647DCFD8ED8AEBD8CFDF8DC3DC.jpg +508C9762359002B6D3AF0D90EB3AA7C903AAA21C9297E890E17FFEB9A7A57188.gif +E488ABBC2364C701C253FBFB0E2393CD7342EF489072D19224EBF586AB04EABE.jpg +C7D1ABE5B1102B0A11FCB5A9992AD3D90B6DB15F4297592CD615935094321664.gif +5AE79F2C34D38999AD2A54DD0A5A43740ACC8A6EAF36A66070E0A9DC743EFC35.jpg +7A0115C63DC115E90E1FF285EB01C85B741E8D1EE48271EDA757E945F8C6C910.jpg +F68382B71D6896C278A77E80270D4C14BD932DDFEA5516A8D21E4319DFCC9070.gif +BB8AF5410D87D6E7C0ED194AC8FAA6B7B25049183581F154A9D15FB96A5A911A.jpg +2EA5E480DA55E098965374F6D2C33215B1E70A41B00A59A52C5E806C75924DA7.gif +3AFBB869A0904A8DA7CBD49D7483FDA77A8B6E7CA576583D148993B943364735.jpg +93FA2902CDBA83BE9671C86F76154F22D57E8478BFF3B4C97B4E829055A1B010.jpg +E20A603BB19E108054CE53D4811E1A82C86A22A4E19B488ABA1D7321B87FA0BC.jpg +A9EEEEABB8AF89369B0191BAF460E383BC0847CEBC6077C31F6A296CB6102FB1.jpg +DEFE4C5CB08A8FD163201B3856FDA8C3F5715BB55176A2E5DD6D43904FA06235.jpg +4095EA7EEC66031B1929EB1FB2E0F0204C198190865C1EB95A1451EA5686BEE4.jpg +80A375C5E517A33787A7CC915B2B5F20B1740BAEA5DB346E2906D6C476DC62BB.gif +AD79BDBE947ECEBFE21EE47B195FC5734EE7F836E17909C389BFBBA8A7E9A502.jpg +7F60FE31A35F1974E2D955A27758E8CEDDFC81B9DDD291553206B0E63D0BFD62.jpg +3DB1D9179E6604882F0314B0076664D04ED4F4EBC73CBF1BA3F9559F6603C8A8.gif +420F3475F320A03DEEB3E138B313F61A27CD54CE1BF8DA6A2571007905A0627F.jpg +2B6F4BEA2CF444C8A00C9FEE98E039675F1DA8708028F477F07098505CF99629.swf +857FE490BD9B8F574F1BDBCC38DEC7A0DCE7CC96182254702A9D783927EE20CF.jpg +8B7276447FC5BEF289E459041A7E920925E6FF8553087F1E9B76070D3AD6547C.jpg +2DD55EDA79E7E1C02B5CFCDEDF320D63A255425DC7E1D7805BDF5A74D062180.jpg +B6083D2095D3F0D1D767233F69315D0C0AF2BE2B3342DB0782BBA7EC8750CA8C.jpg +CEF6746CFFDC70230B8EEF1EE7A7DB6BAF9DA4B0A1D2A5EF549D9143470C2E77.swf +99B2D8F2683289C5734AA3DE9CAD43ABF562E357904C7E026060A6AB3DD518D6.jpg +6D0C18BE4D92BAEC01FB5C8365FF2DA01334BCF6AD86E7A9314AACE5C5B978A0.jpg +5CD9AC992B219EB4DC1CCAD102FFE4CD20960554014D46C0C7865732A4BD6372.jpg +65233485EB529FD1BF5A11F7C12ADCB185B1104C9B660B7C98202A2E2FC788BF.jpg +2705BB571DB5F3AC86309FAF9015B741EAC81FD34AD47475224F121638C925A0.jpg +F012865D5CA4A22D60EE5931D3D6BC3DB1A5722A08560F16663DA6FE56C9CD9F.gif +27AF73C11468E540948266C1497BED7305C9EB4BD01730F3F423F34527BCCA7A.jpg +505982152C446C94C38EFAB47B0CE4834D2D33C09D8E39A9871BEF29E5BF8B42.jpg +E61ACF94E1747E540B2B4A54CABDDECB1EFBAD00F4E5055D86F87121F6A185CC.jpg +32D5C1C650B461B3C2CE5EC4438A865E3440736D50159420B2EAE25679CA6046.gif +2C2C5FB7367F9A3ABE4AC57514DA082D59BC2AEBD5450B0F106AF2ED875BB257.jpg +9C6276CE1DAE5D1A39D66BF2B6230C24FDA622BBBF21867DCBE4A0B10653D24C.jpg +FE8BFCDEAB458B5EDCAC7DAE1E95622580C24F9AEC167BB8C23C8DD1C64E4CFE.jpg +16EB8F9F27FDB64975EB88D67C92C1CA75BAAD59649E6C5E282B280A8BE94E38.swf +5D228DFF134ACB15D4A03B4516A2487BEC032E552C3F7ACBC6A6BB817E6BADDD.jpg +5464AA9C2894A16205A2D991612C508D18DCA865EAD9B806AADF3D0AF3A18B71.jpg +D05869247B523F7881C7EAD183AD00BA3C6C0544105B4772CD7888EF46E7FDE6.jpg +CE6194AC8AFF0D9778216D6608B53C34334369A4D7416E82AD54F5DDEAFD564D.jpg +F839E445039D4593C47E816F42ADEFEC0C47E339C2E010EF284237234ADDAED6.jpg +D0D23795F72E96526BED986FBFAC23E67A79FA90B0A31B2323D5079531BAF313.jpg +8250EA9A25AC0CCB8DC30A25615CF8802B669AFB8C6A0F32523EA33CDF4FC2D9.jpg +A62616F5C7351C88411B4AB66BE24F437759CAA30720E1F1B8248FA6623096B4.gif +CEA25520F88280B0438AD084A66504583E11511F4D1423685BB29F6A6DC11100.swf +8250EA9A25AC0CCB8DC30A25615CF8802B669AFB8C6A0F32523EA33CDF4FC2D9.jpg +A0C04471AD85CF2AD069BE7C40E61FBA49DA24D7BB758FE537550E00D38524BE.jpg +9A0970AEE4D25D71782A0BB0C1FDA67BB4C2DBAFBA4E5CB8E2055F0C7F5F98C7.jpg +33A76F48889D2776DEF1B07E91DEEEC2F55275FA1EB692FAB2EC80E7AE61EAB2.gif +83A159EF8BEF744AB8BC287708A6CD36EA19CDD3182E48C34AA4113D5E04427.jpg +D00B5BB2FEA2F7B5D77761A42AA808D225DE3E899278E780B1F6848C8CA283D9.jpg +BECFD772D0AFA6EB6335434D102ACB7214D699BED9490B40E0280E3BA98B901B.jpg +32A814406C97ADB95372BC5A56B505AE0A2B99A19523C1A211B8EF597F79B5F.jpg +2E2BA8DC93F868D7465D0F6E1ACEDFBC9ED67238E68EC53E40B9CBBBB720980C.jpg +658B3330ABADDD9BC58EC46E2D391027400B282A668258E22274B31669DFFE15.jpg +A83C727373A6F3E6EEB9058AB3370A8946C6DD80BA1B417922EC5F749E6DF5CB.jpg +1A9A0986290D7BCF956E32B6A1FBB7083D5175BEF6B9E0E158AED6C4B65DBA72.jpg +15605CDA3C3F0BAB677112803126C24CC98390D1118937551FE85A46E12EE512.jpg +DF602E2BB6C850C7542639571D2C256355087B13F9E52BB4545D629C303587FB.jpg +EB4B49AC3B2BE628E0314240AB6FC2447EE2682959D8A2AED91CD9E72F377B54.jpg +F1AB6B9D4439820633B4C99FC4E3FAB530015A2EEBA93074A2FFE333E20F1BE6.gif +7708AE6217C732782E0C22B9D8AB3CBD767424019718DDD69FB7CDA689964851.gif +B2037F7D2F4D2EE9B11143CE0F4D1328183DC9C3A5F5B997BE3DAFCA8F8CEB02.jpg +F85EDF45CA89D1E19021D58F80CA5E5FB1CF56080C3EC4D8B716C6A6933439BF.gif +43BA1CD2F1D8A9C77AE95F166C96C003472B6366CA11FE71842306524806EE31.jpg +E26CA726955BB7EC256AD7A03E628903FCB5E9B0F8D728B45F59884349914BE0.jpg +B9C9710146FC4E2BC8D6C71AB17FBD35D45EB0171C7632E7960DD701460C62E3.jpg +E90440B9F3B32EF95D23B21F89D532F0CEDD880896F7F5D2235DCDF6F55B15C6.jpg +9DC82563A7380B73F87A63FD3341224129460A879E63DCE73CB33047E99F6BFF.jpg +438CD78380CCC09F8E830FBCF01F5199572E9C363E72C777FD7E536B231597.jpg +E439C840FD88A820DC41F6F09FA2D31200A47C7D7B76732342B44C52CC70DC8B.jpg +42FD37320E92012AC3E2BDE91DF0ABEFB6FF2A86128EB9449FA8CB1C14A0BD9A.jpg +291154A3F66DEC6D9A020A41BC7958567F6E16EE78FC2CF0DAC5733396E37EC3.jpg +B779DBE9B99290B0CF84D21727A008F7A7947C7121F96BB1B3B76D3862EB494C.jpg +DC9C2585190BC8BF85045EF3FE5C531B56AADCD9B7A3C9EA4F3CC3E7827910D7.jpg +D75BA663C651F4E4B45BE6129687F5091F948C5DD08017F3B51E62C7A87643EF.jpg +C9FBFB6085AA1C9A870F8BC6343451DE861C2B32CBAD69C96D4350507C2414D6.mov +8BEAAEA20526BE686E695D065793CB34798BEF583D575B55B3CC0EEE39A76E38.jpg +9D5BA927613CB30840C3F25CED9780B6752659A803B5B37510D5127E16656AA1.jpg +C7506325C2F589E33388E809D10AEDA48D0AF03454661450DBA48C4BB2950F1F.mov +387F394AB79D29AA8B13D8D771E495C30FB9DBF56F19B7C0CA625D77B11FBF9E.jpg +9F38C9DE371B01AA19C97344E74EFB10D93885F60F9DA5CE7C74BA75526109A1.jpg +84CA1F217B6BC3846605A9D47A32A99C534FBAA5797835C1CE5817A8BCD4F5.jpg +4E6CB7F2488441953370F85414C0B46FB8EB0F81140E61BA87B1C8187F3C54C5.jpg +8186D5911C5B94363EEF7E76A83AE20997BD9B3CD49CCC2D9E821E3E2768CD86.jpg +D38444AA375BC98CCC249B792A869B231AFB60B8437F79B7A2A82E2A2CBED9F.png +9613EA6EE2D550F3336EEB5A626E175DFCDD17CDAC9EC6B38ECC8738A0EB29D2.mp3 +D76F6B6761611D6EA555CDE60D3B96B43E065785B5C6EE15ACDA77B83B6B3254.mp3 +945576656F81BC41AC751B97DAF1E2FC72CD678FFD468160F37CD59A8751AC5C.mp3 +B83A9ECA9AF019F03861087332DD3FCF26548042F249FC74DDE0004B0312EC50.mp3 +42E77D1D4E71437FBE906656CAED4D0FE62D2A3400C870D3E97AB6198D4000CF.mp3 +1394C9E9EB7859DDC7FCF81CF7B3E4B3B3DBBF853590330E8C41B9D3C04D6891.mp3 +D5DB75DEF74E783E10F4A556B1841D068E73176FC278DD01047366161CF0D1E2.mp3 +6B2368BE55529F1337E57D562609A1D2A82F9FB31BEFB270B47FDBA7D9C23C24.mov +23B7D99C4A87E6D802F1C57B80D114EEB6A7EC9F7FA19142C4DC14CBAA7D4C82.gif +BD55A3803224B33F54DCDCF594B4A38BE8CE08246A3B4FB2169AD60CBAF68525.mid +362A3BEF5610B642A3C492E3B9B46838040B14CFC7300A58C81A801C030ABD0.jpg +EB824946CFF2F20B2277548732BFDD0228955263174A5772C305FD8BDEB7AE1.jpg +8DD90CCB561560BC9D59A7E40A97061904F37B4E7F4656F5D838C62D71501368.mp3 +55F18E23406CC7786A9CFCE938EDC81B4E88DC3C11B3E5891303DF871E05BBAF.mp3 +3B701CCCDEA79F47FC338A15CB286EFC62330F825BA7D11555F8753D34EA3322.mp3 +63C1075C385BACB7FA006E87C91F6FE61B72E1AF90CD606C3B2F5C380C3EE505.mp3 +B96245014C3E54155CD31324086F4953F12CC724ACFAF8CE6997D3155A0328B0.mp3 +8E53795434FDC6224B3F28D9283A24EA8791591A24CC393A5DA95C7C1ABB2179.mp3 +6FA73800F7434F56F7AD7CC2DCCAA014CE6AB116452DA3C3B7A86713C482D542.mp3 +6A7B9401B443FD593B02EE0D48309BB99EBF72155BE6EFC3ABBC69E1A4875B59.mp3 +542FAA617CAA9F7EDE194089AB4E3C22B46BF67D5041FD533F3D39F421FA05E3.mp3 +BF080E40616816F4819B4EDB844DBDB897908AAFB96C94663795F5199FECF665.mp3 +F63EC795EC00CCC7C4FD4CF1B21DD1F0E75CA5BAA932A9FE92A21B36B52E465D.mp3 +A549F89245E465A02B501938947D1FC41B5715123ED4DD579DD6C6B0150ABFFA.mp3 +570D764236B7F5EDC8184D91CC6ABF894C1ABC3B1F74432A1B49F1EE2E9CF77D.mp3 +A144EEC662DB6A5865F319C329645A59B0C83C056CA32B931699F3B672BD8AD9.mp3 +D43C1F6E7468ED521B4586A100803BF137A1C12EE722E38D9F6E0162C240996D.mp4 +B9B0E996860C7C3BC00E5EA6CB78A4A4CFB73E9C3A1CAE97154AE2F090F4C2F2.jpg +ACB1CA987D59BA56A1D56537AE3A421C4919497A7E6EB0DAABAF211C73C7524C.mp4 +2E7502859A1ADF4639B584B2C32E907BD9E0AA9250276A01F7D2053710E9519B.mp3 +495935FA211A6A37BDFB7581BFF2338A92302628FF64FF6F210C7452F94EB75.mp3 +CBAA5C723DF5E85E6CAB7BF832026BA352D3EB84D08D9AA7A775260EB295CAF8.mp3 +EBDA08D7660963D15BC45834E3621B24F16B143433D210FE62725C0697B10828.mp3 +F092CD541FC233A98746941422F6F3227DC24C0EB2A9A45F61A3E3384378609.mp3 +7D2643F2DDA6FF74231C096577E7D3441EDA738E883B21E22F38A0B28327F078.mp3 +B147B8ED59E4E46496303D598FAC1BFC64F0F0B34A17BCF8C9386B670387C728.mp3 +B263F9CDCB9D93013F6E45BE7AC849579AB0669D97938D7B8E53AD9B54C6E613.mp3 +C7C384DD3AD6906E5A35EC7B3F42127E4123FF6AF581DDCE05D54158D54D9242.mp4 +FE7095C0E06BD7CE78BAC5A73F7956F18538D083F6B61161F9E4A7064CD6ADBC.jpg +1F974EE7044D39DEC9C79B334DEBCC3AF279E77892EB51AC9B60615DD1C9B416.mp4 +83F928F4391AFCA5F62CBA61F9493C8A75833B5730095BC71788D2BA06AAC3DB.mp3 +D40F472E677995CCC9DED1A407B0A026005C92CD5643971684E2335F051CE149.mp3 +AC1CBA20CBE98410E4BFEA0ECBE0473A35D6CBE09EE6CEC11192688D2FEF5DBE.mp3 +7DFA44F6701C26E177220D38258CF0FFF487365AEC25E3912FB6F3C984BE979E.mp3 +C300E0AC6BD804E70D9D4D2EA23BC0F449A638B6507A30D1FFC0E0FFD76195E9.mp3 +412F3149D9BADF5D63E53F4A9293DA479D1FE35277A90482D4DD68C5FAEAE246.mp3 +28911466F59A5021E5FF0A025421D0CC63408AB72C2BEADDFBD729925A6B1C80.mp3 +D73E644CC4A9E06B9F586566B7EDCF2C600E39F3CC54D041F65E47FF10346706.jpg +41CC9B3437C71E1A4FA182C0FAC88060D5126A13C59A874F31C165D673C4C0E1.jpg +5229D61D3805BF9E53FB3ECE0E8CC3D53CE812D150E30BD782AAB08F082E6A7E.mp4 +BC762A1B07A1751563ADA8610782489DF4635E7D64C3CF09BA225B3879E86CC2.jpg +4076B2329739099C28B93C971BDE9DDD2FC8161593B142E1A87CBC405DFE4FC2.mp3 +EB934928C86EE8AD4A9A4B9877FE5CBE54F87F02019498F99E1AFFDD87966494.mp3 +D1121C5D31DEECD30C079B249EE96D53B0FDC9A04AD4765B9707CDEBF53B0A3E.mp3 +AA74569BC4061FE657B357186C2BE43EE618FE485FAC8D4814C463AFE67375B9.mp3 +AF24867248A90096419F2E7D91C6FBFA732577E182B37BA9D42AE9860FF523E3.mp3 +FC311E0C766621FBC1BE7E94613585047651B88346C59D4E2F7F838E39D36935.mp3 +397AF6CE0D549688270232B28F6331BC17EE3409B5C64318409A84D36E936D81.mp3 +64E86F6F18D728C5F862227A451D242D246E62397A1E7294020E3EDA501BD36B.mp4 +204E2CCDF4BEBA6E1B6F4F8CFB91F3BB77E23DE554FCF1EB1A04D755B5CA5F20.jpg +91B0841519507C2BA1E27A76CEC7BB22832C4291831708CCE320372673724B70.mp3 +9C0C241557A2AF929890D0AB339D7324B2421EF3256CCD2B48AD0E3C8661AE56.mp3 +212B4CB0FBB7E38FB1E7415770CDE681EC1C66FF35F2CA54B5052AC6C66B72A9.mp3 +8F986D16860353FE09033C5E975A51593260824A2E8E2E0C7DB11CA405328FC4.mp3 +AB6B6560B495CB5426A233A7557A82014FB28E7187CEC7D8E074CBC20D910334.mp3 +C78B3B0CC0C0FF8CFA5261228E76AC9F5B25CD807C058F6FAAFDE847C06B6755.mp3 +3A362588389433358C67037C8157A8ABCB2ABE441F6AF2739D85CB466A83B110.mp3 +9C75E01F590A143C9DBA699008E0B383456BCE2AAE224855166484C94F9778C4.jpg +175D6313C58F54C11E7E9D013520F9DAC73617533464552CFD1AF13C4585A56B.mp4 +661236BAEAA48D2FA360C256FBD8B9FC64C213A578C3B82B97369563E4F57286.jpg +1264BE2324C0BC0492379825C2A0F8743F00903E3622B57AA38C7679FF9EAA1F.mp3 +79CB5A402C4A934CCFD68DF610CBAB2B165703095D2EE94A0EF20FF4C67A2E69.mp3 +CBFE824C4DB83AC991FF7188EAC4D7B83A807811FB026965207174A0958C6D9B.mp3 +5EC891B4E3BEF533F7A4E5FEA533018E9E1EDC425AFE200B7BE1E47F9D932318.mp3 +A6A78B94CDD978DBF7334521436DC3744F02A4BF488050C5C66834733A8AC921.mp3 +EFD9B9003573E84ACF3C4C5EB21A8C91F088DADA623698AF1C9FFB3A42325E45.mp3 +2E498A235C2C6FC326D5FE45DEE1D4EBCD379461ED950661F4D4E7F8820A28F6.mp3 +8E3BFA09A97CEB6F80E5312701C5A5F94ACB64D049493985FE9517CD55381A00.mp3 +ACF86A1ADDE59BAF68F824154D5D94E4258A55B4E4963A8C06C08FA6FC4240AA.mp3 +E7E9F7E7B2EA490AEE7B102D560FD6DC63C50F97986476112FCEF9DBD7BEA2B.mp3 +27B0CBA0D37DB6F0FE9D22297ED8AB95484B152F9345C90A1CC6916A16CA9CEB.mp3 +5D2F64A2A1A7660EB2811D36273B8A3D6AE29243AFBF63C7470E826511903065.mp3 +613B12B237870576188E3AE6729A60B3C4A50174845BD93C58754BDA9A9F3DB3.mp3 +B048BB1E2A9234408AE55C17DE09B88ABB09500A28819828E6D0827BDF433D60.mp3 +FDBF15993BCA7467463B54F808769293F5AA5C25EA2E50A158BEA308D3E66D99.mp3 +4AB065A2ED23C0FC1D0791A78B578768CD35F0F99626136A417F504DDF2476E8.gif +68E1BFF75E8DC951E5CF2D45B43B4B542C54CAAFC5B98ADB523D0FCCFCA396E8.jpg +A2CB212C88FC4019D601AC00E5F1A43185B37C04987294A4C7188C9AE0DB963C.jpg +63AFD796C4AD73D3CDB9F94F4A60F12A0AE490107B00ECCD79131CA29CBB06FC.mp3 +EEB00505B432835600811D8AD0C9083056475341AEFD47B7379BE900495ECAE.mp3 +AE1A96F46AB1523DC5BE98D463C6934B7398C6640CE667DE2EEB375D03BE78C6.mp3 +B210093BBD7A417EA188721B4571FC3BC603929D35FE4FD2ADEE1AB3C9B005C8.mp3 +432CC526EB642EAB6FB2411CF5D4CBA3AB4698C961762E17A8E9E7B70B94E72F.mp3 +98E1F93508F3E4B9BA9B0E78C0EEE0D2BD0963F035C55D171DE290FDA90B8E9D.mp3 +3A3A13963349F3E953E549C4082D4155C1D5E812E1BA41F28FDB54E2DFB6484A.mp3 +9293BFAFBCCFC0B2C552D265788EF19A44E6393376B1697F5A220A6248AB03FC.jpg +42FB6629386914B291E9DC27901C0EC16A70D2CD43575A34F002A44E1258DC9B.mp3 +FAECA6CC2D7DD6C498D4753F466530FA845BC5A2BA6DD530845911940FE95BCF.mp3 +BCCC9BEA6E9C6CC10E47F6F3694D6BF21527274288AB1774346153539C10C853.mp3 +C5E5F18EBECD4BD57AEB05C0740FBC84F136CDA6477B2FBDB722253308DB4C2D.mp3 +F2E17734C2DB3169C98004AD97D888589432938891D6345C1C8A80172FF4BBC5.mp3 +EE4DF8221E0AE5C1A0D70257BE53526D2866848A6E6040F48B792AB5AD4DC8F.mp3 +57C6BF4E6C92D0DF1406E743A979A049AC6CCA61DC38B8E3A178E5BEDBF71175.mp3 +864234A770BBDE5CA6A96C902E7D03BCE6F8BD2304A9C5F809ADC2A4BCE7FF39.gif +AED0C745A7EB65E76504830DA10CD7D39EA3E59134418D4A093D56672691AE7C.gif +3E1D5E1EA2677385B2901E20DF021EE338F9640716A1728BCDFC4F6DE07D76B4.mp3 +7DE0469E7E57E065DE39BC29F93E990B139613F79166C92D3DB3A8BE2CB9D330.mp3 +13B564D213229C1DF35B9358F604B6682A66812BFA6B1744D8B01155DDB109B4.mp3 +2A9D5DD8E5E2640DCCBD6DDADB9CD7D168A4F77CC17DDF7F3EA5171F78B2A622.mp3 +295C14AF907996E70E4C69C042E07BDEAFD6EEBD1AD229A5C8A8F5C04981BF73.mp3 +ADD0FA980665B994933B6BC79D23E47803CA7AFE4AC2B626D03C16C69A235C02.mp3 +73128E66C4FC55DC77F5190496E326E021BB5B57E1F55C5C7B7AAE7CED67D107.mp3 +47EDB3236FB948EAC55CCA9947E8660379A7186E523A98E8D3C1616286E76052.jpg +B8A7B9A42A84299CCBCAA92A9BA879A1DE27C7E528651D7D1477BAA02852EE11.gif +AC8936E6F27559862139B2DE2256205ECC292E26A92BD1BE39D54C5DA166F86.gif +B131A63C2D7484039A42FA57855865CC44C82B71C06529C1E976F306B99EFCB6.jpg +9DAACC22C1EAC2F117E83502EC01CECC4C7093CFB8ADCD28F2A9AA26FC4CFC2F.mp3 +42FF72A2EB3643089BCA4BF00929CD4BDFA96129FE73FEF27C74049640FCF370.mp3 +E4E1F9A7BBA7C606C217E35C1EACA40613AD149D94A898200EDA4E100ACA5589.mp3 +F89BC5C9654F5B06A16DC19820A6039C3C6CF048261F30E65FAAD00EDFF223FA.mp3 +71409D3A0BA219ADE1D1EBECC598AFF4C872EB4AD5220309EA37C882C57E019E.mp3 +4E653C5EC846857CCD1B1A75A19DCD6183D5965B11995042D81A01ACB0ACC53F.mp3 +E03C95FC756FDE59BEB0E7CAE51A9F3E857AF2631B4D8CC86EC1585EFCDB9C26.mp3 +EF8DBAD34A68C8009503AC5AA31B6E1A0352D6A7A7B645718B5D13E13F178017.jpg +D0C55534146277286256BD78338BBDF666DD7CC27BD9D4EEC6B68DD1EA156817.gif +DAA2BE99089A01684DE118864202932BB9E09413B8EFBD568412F25C758AF5A9.gif +DFB157B272138A0E25B8353CC9C1DAAAF17C289B699116A071429AE48CF642E4.gif +6FA0F9186E5ABCA7C37077F2C7DFED21970B69B97883FF3BA368D32F8ABA340.jpg +1C02D36E91B2BFC1B8838642B69D8420AE50E2F07448EA2F72B7A6D4B81A1911.gif +398C8E72E4077D10950D766F3AEDA5432CE30EFE079188345CB83931F740883F.mp3 +5DA340B0B8F1DE9BAA8C396444B9463DF47148CC4927E67CE3B937B32668E5E6.mp3 +6AB95146AC052C2AA77247897EBA16B24C4C76645C3761979BE761134EF3DEB2.mp3 +DD936EDB2CF1FE12C01E327EF80269ABA05098DCD0CB2D23F34985C7DFB34588.mp3 +ACF83AC473C2D8040EDC449936A5133C3AE3DE0C487C528E45CD09FD8C209519.mp3 +9F87815B61EFCB94F2345AEB7EF5607079AD1269F4F5444972C66CA472F4712A.mp3 +3FDB50F4F6F5AE3D0F8FD25C9B2083DC93EB0B2E403403304235CA112455CE1C.mp3 +1915E345A2A83B471A8EB707435A6395EA30FAD11C22C75A239BBF3065323E43.jpg +97A83EE48246B0A621731C88CABD8F0189ED07518C7911BDC9B899C62DE52BB9.gif +7C65900E560BD8EFC080F9C10BC6B359F1D67CDD5F7436AF4C40F9BF7BDF3439.gif +336423C1476A1FC230DFE53BAA0E0ADA07B485683CC83EBBAC5A091CC9E8B394.mp3 +B911190620327E143E0721C69A537261149F57D640BBD4C5CBCC7AC3B731CEC1.mp3 +8CBDDAB8B34BB3FFA402BB1F94CAA6607D29B6E4CFAC3F5FD6CCCFD319FF877A.mp3 +81A3A2F1C0A13D12EF5699F99FB0BA2481650A76B792A401483E391177E0D305.mp3 +5EC21954DDDE72C1C2BC70404B72A6DDA69981671E34E8B403DA1EE72F3B93FA.mp3 +E230E4D88664683F42A7220DAEAD60BF07DD215A1D28CA1CF539EAF709B75C27.mp3 +CE79C1CC13AE441A27075475F7DAF398110241009B9153CCADC40819FE6EA4BD.mp3 +1597710EB0DA4F07D88945A113845B5604F61402604B82247A097EDE864DF348.mp3 +B46F2D096884A1473E3ABB53E908DF8701F089B34FFAECE8F9829D786FA085FA.mp3 +14DDC015C2FA94A91640919DFEEA391F128DDFBF99E90AE0293E8E4E671CA8F5.mp3 +4C2BA712D0F15A55759C3E4F5EEF9CD10DA61003ACC865EC597974C02A81B439.mp3 +923F5E144FDDC17B59740F34DFCEAC41FF2D633AD45002BE1DB720F72B34A9B2.mp3 +39A69E263C8BD2E999C3BE7E30A2565305AB7C0CB55256AD4E385EAB91BC05FF.mp3 +39B0174F45465F239F0317CD7F38BD869DD75DD7F1092C945B9AE29A2D4C06AA.mp3 +BFACC6E1412DFA417545FCAC83A09178F35AFC5AE25C9C3BB9C44B57660CE6CA.jpg +6966F8C2B2A9BC03A33383C5A062C4F4B10439C56E9A418CE00C0696AF002A8F.jpg +BFAECF7C13C817950B889C55384E397522575C9B1383DA9566AC523F2050D72C.jpg +D2592966A41DC71AAFDA45B6BD03626DB72B8A62D49818015233068C56A59E30.mp3 +5DC5E148935FC36CE8477AFA667B002662C29AE9A4F7E17651660CA63EFFD45C.mp3 +3AACB6B5AC990C26FD08F23026D5A824C406216C40CD1BC0477CB5929C672D97.mp3 +588E9DE1FC86FFDF95CC38BC3D658B131A8A462EA3EDCBC7C4F913069F51274E.mp3 +EE20B3228920D2E7617A19E7D42719A43E52ED466DDC1461F9DFB054C68B5F1A.mp3 +51FC5103819D09290A4EF0B9120CE0A22BBA77C72F7F3F1B525E13CA16017FE.mp3 +7B63F4C076051F7B96AA5C224ED30422E493595ADB67DC4052674E29427A40D9.mp3 +1BDAD34456F4FD92026D56BD7FC41664D76A7C77EEBA8CD57BF333FF5F3A72D5.mp3 +6DCA90F27801EBFEEF0CF456DD318EE0C4F0B80A0A72FB2ABDB4741416A75639.mp3 +39746869C111028980D6BF77519CB8A7B14826B69BA119A0402D9F5911AC164.mp3 +41BBB94363F49A319C990C976CBF68B33A704D664E9F830F6B4454C73D89A797.mp3 +9D132EBEB9302B37C76DE387EA20D42764D2CD1046D01FC9712198B6962BC57E.mp3 +3DFE8558B97374055D4B63208F19A2415FBDB5AD05508B28DC8C8ECBA21E2B5B.mp3 +1A419F8E75BAED8B199BA863E4F596DDC7A8A2AF544B868A0482688D8C08599C.mp3 +2E2A4425A1D1807DFF620F4028670716B5EADBDE5D14BF3737D4D5EC5F02834B.mp3 +745C5CF6719DBD8CB3E1AD76B21C4423F53CD717F6719C7442E7C74AA97FBBB6.mp3 +9AAEF1B4DDB47C4EAF1A30CB2A8D0C59C2EB67ECF293CA8CD4151D61EACD8AAF.mp3 +391E54B93E70EA6537715CB28F711584649E0F5DCFE60EB35B1E3F4D5EA0F02D.mp3 +2EB593DF325A6608CBD53FB350209147E6B8BBDE08863B0EE69F003BD126AABF.mp3 +4CB059EB9E6C09CA1139567D247CFCB0A741A64F4BD535E115F238E07486B746.mp3 +F8032A444A5EBFADF05EA2482391145908F6F6DB6CC17A38C5C660127C7CBBF4.mp3 +D28BEE161CD472CE2E55E565737B9EF99633DB57CAB8F96FBE67A6C0770198DB.mp3 +45E4C011080065CFCE3491F1E64BE22483BF92CA1E268F5CFCD4879743B9DD70.jpg +D2A42A509A00ADCA5936B0DB6055CF40846DDB7E89D8EA83446B2A8904FBDC80.jpg +11A1096AF9D6910BA9CF2F3E59496B4B6F07418CB9030D93212383A4D989A299.mp3 +C76AFB6DD44F0ABE1913D133C1797D7F68F2A7890BA938312DE56D3F858B3BEC.mp3 +7BCD80176A63A8E4EC1ACA43A0AAFE2420427A43F0E88BAC7E2AB1C4E43C2266.mp3 +EDE8D8249C102630BE63466859BA8F6D6DBFAC79B57BB59C5FB9BBB816DFBD0F.mp3 +7107DD87D48AF5AEA843CF804A6CA514931FA7AEA2AAD6BDBE9D14EB78376797.mp3 +E6FE591C8D95F1B3D0D566F0C24A3C8EB4A190BB9B9BCFA4A52B900A16188EC5.mp3 +267172A3746CBBCB9C626FB3E9E92530BE58EF2F4F868213AD36052241872262.mp3 +AD795B20E805768F45080915C0B7E8B2910882BE1F57C1965556E73F20FF8A87.jpg +EF51C7C146C93E7B48D00C6C612B440C1BCFEF3063AFE2D50BD0876CF6A868C9.mp3 +E5F87F32F2451173D4BB0E586F8FA421F435CF151994F4E7181B440684B8C8D2.mp3 +F935C2F2EFEA8E508B543BC0B65D23E2C45F4B7676D0E7BD57D378E5E2F21B19.mp3 +7C5DA5567D18B37BF738173E147AE6B87CCE3B8FA75710097BEA7CDC4551CF0.mp3 +E5C596F0F6DF043D89F4C505C81BEBB142B023C2E355697610E1D2EC1A049B1B.mp3 +B210A57898A3D53C6926AD38AB865FDBC5386C0F22A7EB3019AA073B8316C41F.mp3 +EC0C1E532CC94A2283194397E25066860C423E9EFAD2E943278CCD1B3D952E87.mp3 +A8363D6C4E9DFE5767752C1C5550F69757CE60836AF6212B0EBF8D08CE562F8D.jpg +8C4A3DCAC408EEDD9529010BDF3DB2DB4AD752DF3F681383A12D184C84A99FAE.jpg +40E6A68B31E461B338A2D1A6194E14D36E7E724EAAE62421D0473DD65D3CB3FC.mp3 +593B344E538A51F6CDFFC28341F2B1A47C5F16F76375EC022BEBC48C57B895A.mp3 +9A162BBBF8A972B39851B361B033A1783CAAC6D99EC44E6E32E46CC21187B605.mp3 +68B0A66FD8B6CE4938F8A0DCD4B361CCB074D17325A234F0ED686ACD8E27930.mp3 +82B5B09770A63AA13BECE4EC36388B7F52FCE058924F55B5253FB80384D73653.mp3 +1C94ACA810C9101BCC8410223BEDA03DE17BB3BD5F385D872D80585202AA6B0D.mp3 +D982A814C40378220DFA005A597F96651E6BFF5F6AACA3694F985AA78691C3A3.mp3 +8576B35FEAEEA96A54EDE19756C3A3AFF5AC47D644EE7092EBB148B61FE587C0.mp3 +6D1421410E6D1B831C33CFFE7629631CB1B12931FF72DEEA571730E9F4914CDF.jpg +AAA312D0BD5542E30C52C4FE6EAA4880D7F94307AC6802FF13C35BF7C09B1C65.jpg +AC8BC6BDC5727301F393E06844B923AEDA6A5F507F72122677DD007F40AC31EA.mp3 +38121421A4871407C60D5D3E4ABEE479E8D854DD885B829F5F51FD3EF206C7D1.mp3 +9A9E22D1044AACB4F95FA78A084B830AFFA24A63EBCFA237BFFBBB354070756F.mp3 +DFBFAE8B1EFB70DD5F06231C939D64590F3683ADB774CDD46AB1042F474EAF48.mp3 +B9A735991BCE7469EE3800E0CCAE5A85F7560E43712D51C531ACF26A717742A6.mp3 +54F8EC51A5E866814A869533D0845BDADB836DAE9C56DA2EB9C5F13CE53B35F6.mp3 +51AD8ADA7FF83B544C5579CD32D580C4BB3B3BE0E2C96A3236D86E7BA62304F3.mp3 +B93FA9E6DC638D59F4B68C3444C102CC6BA04A46B11425C4BFC683A52CD23B94.mp3 +29D80B0F6B79F37820B8A5D68BA148952B4A7D92C9F38517F7F680A5B70C6D14.mp3 +1C59677BF96AF42B886EAF4BFA51FBE4A54EC3DB86F1A2D6BAA374905670B735.jpg +4BE7BAD27D06AA62B4ECB5D5AA117EE7BD10196987A3292B82BF63401B97C3D3.jpg +3EEB8F79F1FEF24CC904BACAFF928C2DB0FB86D31F1876EDA72FF3FED49D5C0B.mp3 +45320BA0784B5C48B6612EFAB48116A4A0AAD63B519211D71343DE4499FEBD40.mp3 +15A5CEA40F1670354B80D263050965229FB65AF4DD92B2637DB7E2DDAEBB05A6.mp3 +45CCCEDCA97CD00A3D99A4F5E7748CB00A350B5BE6793851B990EED809C13FC0.mp3 +F7F50E6DDAC825DC9E53D92748D18AACDFCE0AE840CF3BCC6C1CB79123D03748.mp3 +41E80BAADC7C2DADC3E399665B97F1085A118642F10257C6EBAF0627A18016EF.mp3 +2B93BD4E372C685EC56E43A2ACC26DD87692EC454CA29D5EF9C6CFB00F8A0372.mp3 +1BBF50AB812153DD97855B6179603CC1987C375B5AF0991A8F8098A0EB5332F9.mp3 +939FAEAA4DB24C5A4AB4AED1F2F827D0701FEF74FCFBAC0021F64C212D05218.jpg +D978DA1DF475215D7257414DB676B21681034A7BAB89A0A36F0EE5DE5F35B82A.jpg +FC2189B39C4F932A25CDEB1C0A38849DE412E6B01A4E62ADA8A39569C5B7AAE3.mp3 +3245317BCFADFAD22739DD35C7F6540563BD5C466834FF237F20D19870D23650.mp3 +8C3E5FA848DEE48EC68BE7A7D2A1A60E485EBB002F1376DE4BAC35B5E1569C9F.mp3 +7446DE33AFB4217853755A267E5807DEF85AA34D40C576C671C54C1226FEDD39.mp3 +E38B2FDF45181E303B0D2CD8604A3536A1A8E65CFA78F576B25AF920B31BF4ED.mp3 +57B49C58E346C7985FD361F04D5720EDAB7013C584C1D464DC0025A64D8ADD7F.mp3 +D5780210147953CB6E31E31A31703AC7E6AE802DFB2C9AD741A1DB1AF2729F9D.mp3 +2AD4CEC12C1334E9E17E64FE111556356E13646837569BAE23188B740F454BD2.mov +4CDF10217D5989AEDDF6DFB7BAF8D577DB99096EF6EF49386DE7CFBB80D1FC28.jpg +AB3203961C52BB23E67982E1835C7EB944033F40BD6E84BE9BFDD519F89676AE.jpg +1AD48D3E578CC10451489E2AD0A5D57E7928E652785B375C1ED872C40B36E104.jpg +3A4FC2AE13AA579B1A312EFE329FDC725326BDE945B3631AA0BF77FF6EFE38C2.jpg +7C25D7D3EE7207586B4D1E481DDEBCB2FEA74EE10037CEBE9CA9095617864538.gif +B37172F9ED173CBD3EABE2B6A81405FB7BA1EFA52D5D4F4CC5EE45DFB67C96AF.mp3 +57BB46D33CCD30F1A165088B9167170B34FA970587A486B3C5A2EE3FA412235B.mp3 +F1C78432205A8A1501CF5AFCBD80037F90006BF81574DB0DBFA11E20DAB4EC32.mp3 +BE64BE807E09569FF56835E17B6FB0927CA0C117DAE3C08191E00379F06F4007.mp3 +50BBD5F956BD3878FCC910B3ABE720692BA4112D073D3AC51061C80537E636BF.mp3 +A93FB424CA9DFE5D04F83C42476F4B73DEF76950ADB3EB2E902C40597453CC3F.mp3 +BA2E18684E4050E31D0408CEBDE7E42D31629AB39D77B3B06D3202DE92C5C8F1.mp3 +1FD5DD19F8E3A12ACB47900E9FC4EB8D856C76B43C41D416D526CBF742D909F1.mp3 +8B017FDD8C3E66ABD2A983D3639E2670D26E4B34BA7A1D22BFE9D2ED8A9CD0D3.jpg +ECDE22426B8C437F439090AEC501B0BBDD5FAB336C03947590B97CE52E871585.mp3 +7DD7B693235179D3779923A58AD6ABF0E050E1A6D1BB7F6FA6C8DF9B8801CD6C.jpg +BA297F05243CE40BC331A6E316F77352D3158A9DA7E6D854F3357A1439DCA959.mp3 +1C1642C137009341DADCE35F237F9C3EDBA5F5678ECF2816BDEA328F8FF67946.jpg +70D5645F45DC8AFC183A1EA0821C6E6C9F5CE9CCE800E44064770E9C1898FFCC.mp3 +5108C1F6DA18E23A3BF5859402EA8377A652BF68D551989277BC35F89B541AAF.mp3 +5B7CD757D11FD7B5590FEF50C5814744F76BA49EFFF2DC73630315A9FFC3C097.jpg +99A2F6F4374EA45C61F9C73BB0C33F9BB82D43CA6F840A5446123897E5835AA6.jpg +3B77E4A8D4E8DAC44911DAF6929193306559A703999733F9DB0DC3659FDAE3C7.mp3 +BC315EA29D5C1D0C1885ABEA1591DE7981F4731A57C24E798A022AA2AAB7E5E9.mp3 +DEA020A393AE9A62987081B772414E57C0DA1005984D27BE3F3D3A6B7AC78BBA.mp3 +1DBB588C5AE5FEEA182ED475CFB1BC62E4CAD278367C04B2A16FB464A1392C31.jpg +39DE99B5D02E4AF5995136C13B730BC7EAA468414C877466387B19A60A3148A9.jpg +9B9E2F74E7C3A1A0EBC307A203FEA0F901C386F5B96A405816086576122C323F.mp3 +AD7B47CD73EC7616F8AB87705B6AB938D2311767B1E6F5E331AA2204C5D39C7C.jpg +8368409FEC95D05F7ACC1DF83C29861B2F06638A9CEC5FD4F0450F41A85264D.mp3 +A866FEFE94197D71FC35333793905E3008917D05A34E1381F415EF7464429843.jpg +DB5A2AC6FDDE6ACD50008DB57B82A9988968903BB918DE00358A600CEBC807B4.jpg +407018465C3508FE8BB61E73B5F9F87834C446DA7B733B3C757F468E1C158707.jpg +756E16421C1FFB8F284DB42E6F5D5B3A0AF8E2A7C50B64D4B1C4527E11796AFB.mp3 +FCF0103EA2DFE53E002383B72F160484267C52A1F90DD47FD8D4AADD89097CFC.jpg +5B9C75C6C70A40C687C6194CAB83DE34B9ADB0C7D9B5F5CD5911D548B7986814.mp3 +A0F7328F70017131FD386B7862E522C58E10A790C020311000CE0D834D37BC65.jpg +214A6EC59437CF15D9AB941699257BC7F841D7F5E508EF73CB20F68530E797FE.mp3 +A98055F3A65A7E1A3DB97A313160AA33E5BE37B1A62C1BD6028460CD9362CDA3.jpg +505991D6F42127B9D033A49B199F2B347172AF6635D0492FEAF348A7846DE1C9.jpg +982F8C352FBFFFA06E7B02E0CD9256DD31F8DA70FD26732C64E384ACD7CB0F85.jpg +259304EAA9132964D2926B067E71BD3AA1DCA3EB6F1D4C9C0891DD21EDCD7470.mp3 +604BE8E6A8EFF69326E6BA3817AAD9E2B7F3AA55FC473F245088BDE977C8D42C.jpg +79934C71D81C93533F0AE25960F58A2F4B02ADFC1D06C67FE8B371DA9250C0C.jpg +BDB8D32F3365490465F4373654338C972C46A0426FAC8D01814DD7C60476E7C4.jpg +7125C0C93B3B072933B00A99209A256A60E97DB82C0F24C21D4A8EF3631F5E78.jpg +2087C2F4A7E54ADFBEB55C6DB402328956B28C3545A8D936FCD07CF55BC9B4C0.jpg +FAB7A88DFC1FF160AF24322014623B13C5D7F6BC862C7E64B009946EEDC36DDB.gif +1851A04F3BDD1021D79AA79C8840A16706504387E86829A035BC819FDE5E57D9.jpg +C5041E646039E7643D5127F10CC54F5829A016E9B00D7A301744467788D689F0.gif +5D413F1749D1300F9ADA2839A12F52224DA6CB4950E8B7E287017E0C1387107D.jpg +3D79820F074E57E563C6C32AE6780BD3E5A2F6B315932080C7A04B84336BBFE5.jpg +2A5713C7B3DC021B3CB1107CCA7D826EE8F45539202F7C4FD8172534175092C1.jpg +F78028C5494377547240A0A82F560F0205A91EFE7C84E00011D122078BE06ABC.jpg +54013F641E988F84879CEDB9F54E9BAE1899B8D699D0637EA5ED6ACAB20896A3.jpg +E4F6DAE642AEA3DA89CD1FCFBD8C0FF187B971CDD117746DEBB20DDEF83A1C43.jpg +E8E0E29C8641B0D2DD9DA86337DA060192EFFE748BE04CF467B90A67EF082D47.jpg +15D0AEE59429C3D220F33BBF1EA6FA2273E1EEE4B18B5427E464415D5C09DE8B.jpg +227A5731C3388840277D219800110BACD99AA2E11EB84D85B98BD2CE771C448F.jpg +261C70011DFCCE9C959103E067B1D8F9A217F161C4B62AB4B981DD7B0CC7631.jpg +A10A5EEC66E98CECF7786532C2EDCC348B870034C5EF5562617B4A6106703A9F.jpg +6C5F03BE18F17735FE5789935D4E4F922C854186DC6833FF998C89497D2B5990.jpg +5DF1457C4F148277E1F1529D01EF66A0B71FB5310857F83E5C8E8B85A8CC1824.jpg +5AD49EA998C45005DDA6C59FA8C2F0E9B6DF6249432C49B261C755E05CD628DB.jpg +B6EAA65F48BB465696C1EF82BC075BAE2DF407D7FE327015D96A6F2E7292542D.jpg +75CADDE83DFF8A5C04B10A70539E3E83E153BE7C71408AEB9A345430E26EFF83.jpg +4EC8EE086765874C9319884E7316DE92E4CF5339363A92C048976595D76457DD.jpg +1C921CAA4E91FAC994C9B4B16619C5788A8AC84D86072267B23A9E95BCE169FD.jpg +CE1D87362A7C819E0C681689BBA7C9E8AE4DAE999BA63D53D597815DCE9F3DEC.jpg +FB96ED79A8D932AF036C100AC95680C491DE09DBDA444B5BA0F76E96FB2472F6.jpg +A738DD549FA2F663C13B5474ACC93144A6A11C5E8178CE4DD8AF326DD8B86FAF.jpg +AD03132EB90606084DE72AC2C4F5A32445975C3A221040A1C762D3DA8BA333CA.jpg +62C8B1A6663DD2A3D75E81182C3D52DA632996BF9C6772D8BB8A8B6FC2608A8E.jpg +6F11DAD6D80C7D97A0EED6C26B46B5C9CED0EFA15FDB5B5D731D7EC8C845BB7C.jpg +64EE54F2814247E6CD298C16A746B6058EE06BDC1F8D67773B04C53E16394FE.jpg +11B5AF0814BAC8E5976C2147A552344AD59D80EAC2CB9EC5269518D1F2DFEDB4.jpg +FDF892E348A89365E624367155FD19D97D36C0E07017A36D49E1C44B1F64857C.jpg +1E7A15F76675AAF886C2173F59BEF340C5467ABE7E9A984A96087B9B6FF2CF8A.jpg +1DA4203C6603D41EACC69C104C8EF86AF3D6B0D694B1F2C0DDCDB63CAC022DB8.jpg +817BD3D21B6AAC23558D8D5EBB4BA4E9AB0F6F0606E24369CD14C088260C36AF.jpg +43E100BE0D0172F064A0DF1214259E98D671E1553125E9B798411D54EB07837B.jpg +D6BA45F938FD013330D7F9FD595B417CB37300931CA4BAD04DDD8DB776FE42A6.jpg +7CF08C7BA700E5FF4A0D1D7B7B21201BAAC77F2856C9D8910386420700A44538.jpg +7FD732A5C6A6D7CBD06FDCF4D9205B6CA135D4A4DB6FB14049E876E463D447ED.jpg +A330E58A1D369F7D42E7933E45994E44D3A717EB123B747F07BD5A4D39858E43.jpg +1CAA605C184140C5F623E77665D0DBDA4C74EE5B63F4467E120F1B100907DBF7.jpg +73F7097FD2AC6EF567488B801C88F5F01D91CA0D4B35FAD867AA85A4759A7817.gif +7A529CB623CE8F177AC0D60930AF38409B9C39F5CF090ECADB38DE81AEB6BCE5.jpg +C0ABBB7EF227CC33698115018A950B1E50A07866A9DD30434AE88305F8A1DE27.jpg +36A68FBAB7676F7E3A3D7D5F3DE77FA3EF74581F1D3A248CF9D53A9C05EBC579.mp4 +BB69E6B63986850A7E9CFBD5FB63CAA6F714388B80C4EAD5D546871B4DCD2550.jpg +2D593BE2220EC329F17B157F858988A53F8F811A8DF3F2A140D98B04384A32F2.gif +DBCBAFAD6CAB7CEC627CDA7911E3B9735F6BB49F80F3B6A413BD46827E543C61.mp4 +B5558E49057A5D9909AA98D0F335694F39DF3AAB48E20B2E02B42455E49F690F.jpg +89D3B1A4328DB0A1FB53447595904972A8AE6F5E0750455AD066FB20C322E347.gif +D7571FEDC6142B46DD07CC466E5973038551AC697F94383F3C8B84DF5DC278A7.jpg +F427CEFFB88EE2B2D1F5846DE1AE85098D427AC43C2F66C43B716C403D70070B.jpg +EE84464CFEA680E4306BFD456A756426D68C947003CD623CB32DBF6D1B5B6571.jpg +4615ED3DD0833EE792799161F4B9FC4DE700A4579BBA376F266F38525CC8C7B2.gif +75B56170E48046BE26F0BD490701A53527D30DB5DFBC439E8A2D3A904A8E2225.jpg +97A769A524BD86B0DB39CE31F388BA433E275B6B74F9885415201C15F10F2A4.gif +6F9DE9ACFC8D3F66C2A89D490D05B7C1906EE475A1371EA4022B84063D7E2D6A.jpg +765A37454468AA4B2101AD982B8BDC5D50A787C75329516F9B0CD11A0DA52B98.jpg +2EA1779A24148D532478A050DE3C07488E76FC314DF4F26FABF1625820A22791.gif +F81505BD5F1E02234B42E4BDC1429164815B1967B45716E42F653AC636AB811F.jpg +860A537EA4732410E6DD8DB443BD5DBCB7A4CC101BFA303611D090FBAD88A084.gif +FD16EAB04610B96982F9CBD39F013D6D9A9068DDF855EDBFBF545BBBC54D6990.jpg +A437C6DAD81713A149C1D88480E670419BF109BB92B9211D11A517732BD24F7C.gif +54E37F2B7F6D80D7AD46432558309E04D8DD274703E5ECB83F3FE0FECA7B3DA2.gif +12CD80C0B8E3294967949A80DDA937B2B7484412885F8FDC91FBF5B6FDF5FAEE.gif +A676AB199CBA865611F1CB59A79FD9595603D295C06F5616A785BB5EDF88BAF7.mp4 +DEBB0B062BBE99D9CF36A4C1CFA5AE8C44D85C715DEDDC9A714F49333E34B211.gif +3ADB0CC88CA7B885D7F0A8512D2B712896169E6CCAE8BE8692CAB733A8B5D78.mp4 +59FE4E4C524262A10E76CD1016D8B24B67FEE4ACE644FD282BE0BA860CCA05BD.mp4 +2BDD743A74F65F8AB01CF9C4C88D636185888FF18A9B2D1FCBB92C33EF42BFAF.jpg +245C439B6E2259C3613AEA43B35611DD6023B4D9A7C212BD32D727CC12B5C34F.mp4 +FA8FBB00F25E74B978AE4CC8B81A63FE11FCCBF8B63799B130B75ED804DEC1DA.jpg +10284A4AB54155B2F25C1321035555541D00DF965CAB159109D91D08BB9EF9DC.mp3 +16022D1EDDBC7802876A29A6ED5D78C215DFF63BDC413ABD2AA6CE5EFE2BE27F.jpg +A9320AF5A5007EDB0B569831553A4C9B91090C86A9B6DC88BCA3A983BC2568F0.jpg +C55F23D0D90C4562FEB7B4BD843E3998E2EB9EBC193E5F5EE24FAFF158D84387.mp3 +9CB66D819C4357FD63FFF5BFFE7168B62F87934EACC8F603BEAE5826DFC6D115.mp4 +8ABCBBA4599A318180EE87EFD81A24874CC38C6E45D9B46457EE11E71C03A9C5.mid +F85BA2BB6526436BC623C592D8F80E33D26C6EDE6B758B3538FC081943BFA4DB.mp3 +314AAB782F188EF13EFBAF0B301C9FBC28E3B275C220B55F3CCCA43940FF5964.jpg +975AEFE1971B2B0B9022A2116B7CDB81CC4E57013C933694DA5FE3188ED8BE0.mp4 +4C31A6C30DF7334775B07DAE1BC144A8BFCF35E04CFF1EBE90ECC5A6CDC565D1.jpg +6095FE823609ABAC033231DDD465E8AFDB6257997DA258F82A78A33D383CC42F.gif +2C52DCE817083AD898A52A8BDC339F02E36A1FFEADAFB0428A02EB3F8A0FE1EB.gif +CEE4C6A323C592D03E4F4DDAEFDE67B034DB40B30119E594832AB4174AE18CC2.mov +E9AB05624F5B1D1B92C6E5D8426702E549083DC5288E7CA410D496F0993EEBB5.gif +F3BD118FF58642D15C2CC7D1D0E4C2B5C894D16347996ACDF3E4975937854615.jpg +A8645B5C8501FDC78F037B46194874813AFDFBB519581891C4C72B4E07EC3BEA.gif +BD671AD03927179430A9186995E64F6428AC2A3125786AEEA44E174303220E9B.jpg +C445E0B35162814F9C7A87FFEE38732208C055353C8323E01B0D6A375EA17B94.jpg +B82444D9460F39B83EA228BA00C4C7292762C870FD1D9EA98107F04462C6B63A.gif +EFE4534D134E31E55A342F76B96374ACB701EE139E4F2D6BAD216C522B0B580F.gif +CC022DE453489EDBE68E1678F94AF4E0A35629CAE7C3994864A19D102CD2D7C2.jpg +DE5FEB0EBE327F1CC837952D6CB0279CFC3F71E2E01BD6D1621FC863FA3A17B7.gif +85CEE431CAD4A8ED8181A9FD412D7AF4CF3362D5CBDF54E608E740A88F3A26A6.gif +396A80613392F23EF402F1AD4A6254A52026F6A667FEAB45EEB718ECE5D65E74.jpg +D962ABB0A205090BD826E1DF8E3AEAD20F0BD13755F65C720BF45B4A117E0C2E.gif +E22407220683B78A17B806CA45B90576C5D3E845CB35AB9F53427FC8CBD5BDB6.jpg +E86878F0354B6584BC22A4C8D9DDC09CB27AB38FA2BFD1D1001E8A5BC0E4F544.jpg +5DC26A7082D83156EC3344F3BA4BA862C728ED1297181083A8B27133F4E38031.jpg +4546F9084CA3BC540B25F0089CCFE3577BFCBBD1EBB07BB26D16061520B96C8F.gif +F387B0CA44B4AED83D74C83D70549F6F15FA5CD7F6967C9B0AEA6703210A3455.jpg +119AB5570E963E1C8B96A289885D0CB6FE3A0CE176BFB5014D0CC0E3247223BF.gif +AB32FCD4C3558935726772B9E5E46821BB50B43B69BF22AF3F95A7AB7CF22A76.jpg +B6F2AD6530B528CCAEB8D1F92180918E33AAE913AB1872A1184235171D2CB44A.jpg +46BF02B7B6B0482A5453B9053E7E31696B572A8A8153819ECAFD957F0948487.gif +6D1A62B470D7609D6233BEABF4FC1F7F0DC1FF76F97C501276BAA048A506489A.jpg +E2112947491A38081F5C5441298BE274EE5B0ED8EDE6FC22A2DAF814F54E0AF4.jpg +BEEA46C7DABD512A107202DDE35A348278F3E236F30FF4A2FF059C3A91F52E56.jpg +AD22D898C1EA723F748478F967F6BDC92591B71D6C7513745CFF362438EFEAA.jpg +94C34A697BA8F6CA070CDF0DC9EBDEADAC5CE127A63A43AAD936FDF8FE807D2D.jpg +6D831B7629EEFFF9A0915FD2E2D93B80DCAA32917D024EC5A62D62B110495DD0.jpg +D469681F117A524010B3BC0CCCE61839725B082F6379CFF0179C28491588EE39.jpg +69338D0E6024E7FF1CA01F1D2BCA39E3A748A1747AFF8F61078499CCE3F97B96.jpg +3E113636FCBB8794C20DA9D63CABE14A66A308D030865D56F75D4E84C0EFB27E.jpg +E7E5A06EE6A32F8911AB502093BA26CA24E0CECE4BC662C395E2A5AC5FFC7DF.jpg +12DB5B23278B11C815B9D63C7A3D315C408E16115C2124F7376398C9E47B404B.jpg +5A04C1B1A9010428FDD5E5D6CE8D07985B6E4372D8A546ED4F1BC9658BD210A8.jpg +AB3B5725EAD3939763F74D32DD7A298F4282ECF1885102FE131FCDA737F26E6F.jpg +C648FBBA52C3D143C8E0A47E5ACA0AB948607D4712778749FB880D05992F84CC.jpg +D84AB1D71D9FEB3412EACAD1116D278572E0A30BD0C12C13BB9B48960E6712F9.jpg +4AA02AFACB1987DD1543D929469BA5CEA47D50C2547D85F2611232A609129237.jpg +F2F206E05FD6042EDB808085D221DD211E494E274C30C6E244D391D762B4D6C6.jpg +8D865D046CA4C107A12DC4D5B2B7E63FCD8A39210F246D8D5AC70F5C156F1E42.jpg +E43A808884C543EB29043D13A22B7F0B156238EA608C2BB11095A32738F786B5.jpg +A675A3340DA901309CFBB79068FC3ABC958D9C3D985DC6BF599A7E6D94E13D7D.jpg +3B4609DAF50A7EB0A993772FBED20C3CC1EDF547F3768B41F810E8138FE8CAA7.jpg +B962337E76713BB443FE31A110E41D881466A3357A4AB8C61FDA31116AF210B0.jpg +70FF674A8F5EC75FC4823B66A9E9329DA7F6E3ED55356A3FB1468299FC619A07.jpg +F116ED0462570488C92A533F0D00E7ED23EB0C9270AE437B3A817B71101EA424.jpg +27B370AF928F4691F463FA975A9D01A91BBB3B1F71CAB0A41EA6044A26EDB035.jpg +A0BA0A7B6E374E9CFAF2B97F85DD19A6E98ED686DEB5543166C53B244436425.jpg +CA8700121AA8E07BEBADA08719D020CDBD8CC16C06CCA2CA9FF56152BBBEA0D7.jpg +E8B9D005D25B05EA2A121854A012895F8F9E81B58D3B0742A69D2AA94129F472.jpg +E8804BD6E472DE8AB67C1C97BEF69C1D334900682E0C09D8F70381A25A652FDF.jpg +70FA745F2378ED2B4AA609E0982942335AF9B1291BE5C4574CCE977A23ECC322.jpg +A70E34B4CC6BE578F076C97965CA3BC4E940A0DE13E186E985E8B7B6DFA8BCF0.gif +CFFCAEE373EA85FF503262AA19DABFD0A869136047E1150E9122A3922EF93361.jpg +B2786C8B55A634CB2CB96E434AC8438CEA889C8184B0030DA52304987B17137.jpg +EDB2B157AB918B26AE4B33915CBE591ECE71B089FEA8AB4EAE89A29B5506AF87.jpg +7E0AF61815DFDF6F1ABAABFC1BF95069FC0318A48673B47CA655CB4C14624B7E.jpg +2B097E744F44E40BF79D80AC136151FBBEBA72EDE3DE0CCDADDF667C6280478A.gif +264D98810E052A0C0EE23A418D74D0C0F25DC1A1770C84D27D90984E68915CDC.gif +485A6C241A9CBA9330BCAFC3CA7A2E44E787A9F9ADB118B6F953F10EFD0D160F.jpg +FD04839B8FE973E39CAECF41E98BD3C0281C6B7B2AFB88371AF21265FB0DCA35.gif +DA3847FE5FB7DAA2360B7ACEF60381AC3EA57F163B79E83E9F14AC82EFE43B49.gif +B221BB9B12B39BABEFC0F28EE8A9054BE0B60673710CB2F41DCAC6564B62C6F9.jpg +C131495BCFF5AB05B09AF916BC557BEEC17CCE91CE93DE8890E894E6E5453932.gif +AED29AFF297144564055C43F728107C05E403A79DA1708BDAD482C9FA19E9143.jpg +37EC7D310EDA4D4EF797DE32DCB7D925BD513A336E0765439C1E2900A8E846D5.jpg +4E88FD5D95C5B07E6BAE68CDD0FF5A7D2099637C289997C6CD39B07674089186.jpg +AC9C138229A76C4A56EF4941CCF305E288F9C4252C5FF0BBD0966104ED16CEDD.gif +D2D27C69B4359B04581B7ADDA8F091D60A38C201CD0B55272AF1DCD243C1207B.jpg +E9EDDBB04C9C17F2FADD61230D83C2C951C93166789F387A86301797ACCA9745.gif +BA15E655A0BA603852C75A216DE1912852392AE83E81682C2C2311E72CE10060.jpg +449D2AFB128FA21E5BE909F8C2ED7DE9704F274D9AE44253ECEDEBD9510C91B1.jpg +1440B651001DB945FCBD185D46EAD8CB274172CACA3C3B995DB907B216CE2B70.gif +837E042CEFFCB4241A98EF0D54D49D643B7DF1A2D2B58524B6CE5445E0C3DC16.jpg +4EE82868511DA61A99CE25E48B68897F1BE41C679B96FD143A9B5F4277CE7513.jpg +CF0EF2324DF16FA8C7397FF35BD0CA6A362A1514DA75933963ECAD1DCB48682A.gif +37DD6FF39BA32A28DF03AC5CD35AE1B3C1F08CDB2BF3F0197234EA0C0360917D.jpg +F79CE693E706717CF21530C8A19999383A1986E25E3528981A5E37BA13054CAA.jpg +B3A19EF0C33758A7FE1ED3740883AACE707E2392200CE97DF2B865FA6DD4DBF1.gif +C5A8AF5C3099932F2509C6612F031DD1D60E721345C8C2048BC906604A9E5889.gif +ED6218FE290F0312BC4D207B3332B3CC76E7E8D977A251BCC2562637789A4DA4.jpg +9BC139D8DCE6DA445C065F742865109830DC042A6AB0CCB34A0E570F9F9A7102.jpg +1AF36FD85014F96A7C115D3D24C61CB9B6A591A08EEC3CA5AF5155860C638F90.gif +83100139612738E6A9A20CCAAC3A7608B722BD8EB98DC6BB1544854CC850FD2A.jpg +82DDFD18FB896013BD7923E9BBAC34A1830F038A089189CA81D8C7CA4D9C823C.jpg +F037A67070C81A60C65C4FCF0F3B9018FA610290ACD58FD73B5F9F9D9595BB7A.jpg +5573A17A6E5899DFEF86ED287EEC168A625981A581434577361C1EB2996FB965.jpg +D10CB72BEDA579C1F1A1ECAF3837D226FFF619C2931979FE66C9CBF3471BFF85.jpg +FC51BB65BF0E45B4F5939A7EAD43979F20A4792BAE4DBDCEC0C44C0B9C23F0D1.jpg +B39EB8A7EC168CD2711C28565B192013773F7F51B10CF7808BFDA831DDDEE932.gif +418ED9C369D06D92D89D54F60998B44BD074A98DB19CD2712FC34612E15CF1D9.jpg +580F0006FC654D6E253C3E74F43E74EB3F60B77F26F689BE52A0BBEA477A901F.jpg +19EF32FA21D573F42B0C010F6D95B9A0467D1B557E8537EDD94CA62083B9D032.gif +5CC7EAA482AADAF7203E887B665DB2BB3C96D1DCA04DFE6381514D390B556362.jpg +66170D58F9749AC2FAFB70C75217EE4AF74C580C5E9BFFB2C8067A3FDB40458D.gif +82D7D69A9CA489170B27AE6EA32456B9AC542F79A78B80C02CBD35D1A6F3F941.jpg +3170E71D956323327DE4B48E8EF771D04C88584C5C9F94AEA80C90C29B3D0D9B.jpg +FB7D456B625471775663B53085AA8BEB8C9771785568473A2EC68B4F6832E5C3.jpg +6DF69E354657726FE8BBD1A1D50E634BDF264F54A3536E64247F5946D9290E5B.jpg +2EEA598502B510C26705B41608FAB7E0EC1EE5D16E59ADA4871D29D5CE0644A0.jpg +9D128624134F30DF112B536DF00E672661E60C91F46E15137BC3A8C809B87841.jpg +79D3E70BFC7C84950E59E10B55F98B44CCCB6CF251D1FAA9130DA6092B033D2B.jpg +935242C339015B3D960CA84191C294F8E1FD52E3EF8FAE7D9E73F5BE8372A046.jpg +207D23358C1DF8576C8F28BE79D6B5E2A963A3E76B9C1FBE52258AA7BBA51936.jpg +966E4B03EE64D6CC042696E1BB2F08A7F129357DB2AD9EA832505F0515E90F7C.jpg +415BBF4D31837C80B0360DF6B38CA517B4BF952908A4EF1ACF7078C9A454D455.jpg +8F796B2EE103069210858576AD86AA91204AC55429A030F3B31C96B60F9E2A62.jpg +D43A601CB2A2242E90429FFA283C471DBB3B90A07E436089F9EB67B4B6ED959C.jpg +B666070E6F09FAA1F50686CE0927B0D0E8179AE1AEE2FE8F388AB4DF51289B1.jpg +1D37A95B71E62750D844A52047BA833F92DC5FAEE93089B7145A715BF6B2B707.mp3 +CE127B5B1C3942F8FE450E7B5E5D318F2714478E240AC24686D4AA73E0093407.gif +5305E16FE9DE310CB50D3FEA86D6B66EE39A96CA8D3374211835D9AD8DAE666D.swf +1324D412DF7C6DE2D8E395AF6A9B98B2E6E1675301B24E468579EEBBDAF60376.jpg +98A5BB63443258D3B484518DA4EEA46ED993B4E41848503CE6DF7C9537185500.jpg +68C27A2EEBAF70B044F90B2A936CE2409287C59176B90547CCD56C74EBDC99C6.jpg +C03FB48095F89AE9F802A33A0F22094C532D6F4863AC2F9EC6C363D052F16609.jpg +F58548431D4D4FDB027C09259E4FC9089F41AF63C39141F45000B298FF054C58.jpg +9C8B8764F9305B84790BE2ED6A91465DC4680EDBF14E2B0169D847693D7D5405.jpg +E0BE2992C7E5B7B674A0C748B4B913771D353CBADEFF35589821A4E672C8E61A.jpg +2429132235B6B5426B62D6846FBFB28CA661AE3272CC286006FEBFD6C6E9D5EA.jpg +C1690E6E3326E4D9180B1ABDEDF5A9AE1807F10AC7B26C05DAF9CDC039E91170.jpg +96A12C45903375C0300648C7211F9DCA970FE1C7A8C15E23775B0CB3596584BE.jpg +727AF955728A5575B68A81B3FB39447837E157F496F7F2307C2765951C71A5F.jpg +83A03CC64F2408DD5CADCAEB9353114242ED1B38F60E2C33C1910F6A978B6A9.jpg +7360AD98046698BAB9C313A4B0611BA017BA3C4496D9BE3F10DFC4D110927F1C.jpg +2EC4DE65F46242DC9E10078D1F96E01F160D13CCD03DDB8507B6DEE7C9EAD56F.jpg +18AD2D9DF7BF3D00452D0C7DF3F11D35DD5997C25FA9B1D97D99E86762D72D2B.jpg +4F0801FC1435025F70BE20552F1E778A6DA1835C2FDAE26BF10B1B5D49C1692.jpg +4C2396799E753441309146551D465D64D1A4AEA6327F875793E0F4E55CFE93EC.jpg +1B5A49921806DA60A434BFCE8FF73378E2270AC77D27346FEABFC6CD983CB32A.jpg +66FA0BA565F5E90B494E901A8B1981279714F91B17A3CAA142E7A033E4B95AA4.jpg +E56FDF1E2233C42A240A628B514C763718C399AFE4A6A0D33BCD84514726B177.gif +F0C0316937E3DB9424A36C8466A952B62F5E74D430D0F37CA7D4ABF57F179250.jpg +EC6040754A8315593237AE63B92B0B85E2A1784A4635E0676C4CC71813AF2581.mp4 +4C4E66F16EFD09F932421D32112D92A174B72D977461AB4DE17AFE4417378C59.jpg +BCBC5D23F266BF3933C411B3F34C761B3BFABCECDAB6C7FA83256DADBE789C6C.jpg +8089FE071E886CA33B5FAE5C736B79CDD87B975A445F6B1F9C516DF876C19BF4.jpg +BB318956F55873E7456FF7E6FA1335930873CACFB846EB62FF994467357AD6A0.jpg +4F9EE2505464EBAFC682D9599FB0901D355B05D8AE44E7245F1E91BE89C19755.jpg +17E3D81BCA3115870BC6F4945781E57E5E61B5094ED2A21364FCA9276474A1C8.jpg +F673E7B73D90C6AB6DDF13F231906E6FFA7B8975D85BBE08D4E284092E1C6A0.jpg +FF6E1A0590B830CC8A76B9EF760B2392DAD7B8528A2644D12D00501C933DAADE.jpg +D284D960026530500EFD9733CE06EEC71A3D9795768D15D2DE8CC24B57B6CD96.jpg +DDBAADB7A99DB4BC409082101D3C63F175E9957EDDA943E7E82626B67C66787B.jpg +6E1623B0481741DD9E0F58FB3C95291ED1A84E21752BA892B04BF69C4155A8E8.jpg +D25C9C6902FDBAE9ACBC0F961E20DAAD63B7E4F9905050AE0E571EE416A8968C.jpg +AB2E069253E779B4DD783BE9C453F1A5FBB480B1309118A4BECB8C4A1DB31579.jpg +19836050970ACC2997C1C649255D69AB3D2EB252C9889D6F1AECC317E20CC136.jpg +7E6FB7DCED96B09DBFE85DAD476A40344CB26782816675F18AD868C5223CFDE3.jpg +D889277EEF3DFBD7597B376FE4DF8623DCF5F49A54FAA92840EE30F70949B8F7.jpg +D0253E2CA0F0937C6132AF1AA2FD4A734380123AF366B362453AC4FCC7D1F6B.jpg +4040548461B08C896696C79ADBF8EA64EECB79DF13B9400A81C6194CB2AB326D.mp3 +F1BD4F566BF2B41B2BD695E77B7020867E0757BC387FA152D50D7AA3FD358BDA.jpg +2191E791FAE9A9638D749B1D0C29F07C76A25C5DAB0CFEE73F59B89F23138E64.jpg +7B1E028C363DC6F3FE0BE496878F4CC0958839073B347B6C2D18EDFB614244E.mp3 +D2E7A53BBC899025F5413F0AF1CB994C1182439CEDDE8BAF2E9047D889FF0C24.jpg +C0FF03C9325871AE93CD125D4A6C8AE35268A672801D2B654AB5418C190762F3.jpg +8327742B5B91B9A3051AE2045E96FD5B5E46BE6EB07F97F16D121043DEB820CF.jpg +418FD4E5755999E2E76E5C07953B6DF04CC9F942270FA862713C3E45CDC38B76.jpg +2FF63068A0B6291784F2B79C3E29C118FFAC1F7C227591509F79E0A6979829B.jpg +861DCF5F0068911DEFFB876C01D37D815EEA7C943A6EA10BCE7C3E82AE80E50D.jpg +F8013BC3C6D4CF7469B91AC6ED4CB0521975450360C15CC5437A8EA682D10558.jpg +A59FCD1857684A3DCC3156B572F94603DD55739DC5C0030843A2CFD464E80DC4.jpg +7EBDFD1D7856664005288DC4F79FB52938FE8F59BE694292565B5432B2AA95C9.jpg +CF0A0A843F002028DA6BAA950D5058EF9546956857E8C2D5969ADE2FAF153898.jpg +76371EB733711993816A6C4B075EB22C9916523D4CD093C5E37FAC54D365348D.jpg +66284AA43212D7C34503F63E290C6A6F4DCC2C15C9F6F72D84EC14F342C674B7.jpg +EB8B9B00DFA3C853677149C0FD9ABE6216F2EA8B2C328875A5034685AB5F119E.jpg +17B393D46BBE490F858FC1836DDDBBE4FD734C3050AC795A77C0B7C97A7CB3FC.jpg +7225600B749A345E4C59064C1EC68874DBEC818303C629CD93A1065985300FFE.jpg +46EEAE07EF413E8991315E991B63A24F8A967F5806B63D874C08B6CCF2DE296D.jpg +C4219E02B7996997521B1F0637AE2F26C7C1746FE289FED16DF829FB7F6EF1D8.jpg +EB5FF634E2000E2EE7C2D3059062E1058F51AA7A6931D8ACA6BDC68F09D3BFB9.jpg +A75B7B50A92C51AD2E4975F5DFFB082DC21C199404FFE72C179FBFB8889F7FF9.gif +A0F8B959D5FA5DE8AC35F8CA8ADFB49B116751059F5A3E0E6C1AB7B01F992D76.gif +AA4759ED625D39381D6392892EA0166207A938FD5079760A605D27DD45BE8FA6.gif +49DA1C60867AA05198D5E481213B82F62591476657D814A3391692BFD1658D83.gif +D86D6C73AF6432EC2124A2E3D7E9113815068D143FC3B9D784E4A0046893D6CB.gif +678B8263D1049F647A6C3B05DCDFBBBD4E3FDBC52424BA73968114C08EB3F22.gif +FC4C806282768D91EBDF1B270A35DC44A1A6A76EA2503838B6FC030D23772C11.gif +C9A5314CEACDAD8C574B0CEC99ADEFB1812B3F844CB6032010F6F2BC17175282.gif +122B416DC06735FB910B690173A7B4B3845D6E2E264792D44C91104EE6AB38CE.gif +9A32F673C57ED2DAEEA174E7AFF56920C24FEEC22A43E5A7B5EDB23324330E66.gif +D4335FEB3CB35373E695A56EDEC14B1E247C23A696FC569E1AE432D4875F86BF.gif +E7A9B1D5FB176FA99A10A89950D0B8601D763F53DE63596FE62870BD50EB8FC8.mov +92435C14B74DF4AEEEE89689D2541A8CAF60A60593821B1281C08DF88DF67AA4.jpg +E0BBEE9BCA64C9FFBC737B7A2CEA79B6B0534D0D68DECC41A2920A76FE811E82.jpg +7A4D93EAAC9911034F44E1FC7CF8B44C006BD2F4FEEF04FE2644B9664FD73FC8.gif +1D58102ED89A88126B07F62184F5BB8CFBD04131992A96872912DAC7084002CA.gif +B220A9591D75383CA8E69A22BE58B3AB8DCB16CE63DDB34EC62D013A4E3F804.jpg +7F86DDB4DF1424C77B3590363BFA877ED0253CB0439A9290C6E4C9AF094F16F4.swf +735D168AA0BE5BBB29BB05FF449569357C34391DD584651A90983505CA3495BA.swf +5409B9E7F520BF0F140D2CF44469E45B3C33C5A67CFBBE7C8C1CA08D465FDB2C.mp3 +530576EF8400F2037BC822CF489E8CA9A430062BCD37F0B6AA3BBD6E06C6EA85.jpg +3846A8D0927E9ECAFAABB0DA7C9AA08B014C9BECA000A6028C3EEC451D581819.pdf +A02716727108B53AE5D89055E11EDA4F44664A025DEE8157DEDE2CBF60A386C0.pdf +269BE160AAE76EC6D6AF999A69BA8A69E96C590C5987319C320D4443C79D45BC.jpg +9DB4C4966B8F075FFAF1204E5E798DF03C21D07C016C0DC6009EA1D8A8F76C3F.jpg +98775DAC3024F2964B658E81F26173A027CF28F2D387E2315FEE2F5DDF5F4C5C.jpg +AEC11D6EE284524AB99BA6FDBA489369F8F05186665C4D2C013E6A81C1A7E4E2.jpg +1BE9901B8A4C8B759AE789CCACABD8EC49EB866105C32DC7362DB18664501629.jpg +D2202176A9D17A7BD1E29C6D3159C03D44C6C38C0E18FCF44E84084605E31602.jpg +135AD8B9001FCEEBA58FC86C2FBCDD908FA0F6D5A9EA8A31325958F48A8A76D2.jpg +EC47D02FB2CD4646F9B9729316C829780E23FE8E172BF8396D8814AC9FE91E96.jpg +A4E0955A9B5B7A43E507D72CC9377B7B3139165EEF5CF85588F22113651FC53F.jpg +11F6EBF07C0087634B8D3ABBD9384FA9EF49BFCEF8DA21A004815A519ABB906B.jpg +C8D0768C7E996C6F9E74AA57C9057F151425454EBE2F2014E1B8E8C1F942EB5.jpg +9968CBC38FA48E6CB065B2FCAD96C0ACE992BAFF09696549C6DFA7D355D3933F.jpg +5E2A9C9FA197A2E145ACA90C10F126F1AB72AB88B06ABDC70991EC42615FEDAA.jpg +6CDBD71D5B41AE669D87628E36F002FFF21A549AEC6704B09C8715AF04A15A29.jpg +36896F85E0E8F37CAAC981E901C057FF080BBBE784775BDF4054DF0396A68F54.jpg +85F1C69215B5CBB0DADFA804338930413516069E3115E5BA12871CC67D8CA52A.jpg +43AF913A7D6C99394AA49B3259037A6135F234AAB88C82C54AB08A27902A53E9.jpg +8996936FAD1954151593D85E1DFFA3CDB5C49155DC3CCCE311BFB517713B31B2.jpg +5E945989B9DBEBA16CFE715833E1C5B1ACBBE8A20FC32174E0E69D37CF05A992.jpg +FFD20C99EE11E02F52AEDDEE62F5A19CEF125EEC69E9D67853F652C818352353.jpg +1BA725C29D7D294A32CB35A77FB9CC6BFF7D46C64E8687C008461B9BCA99106E.jpg +5A710DD67986599364C32583A7CBC993EA727E8EE62DBFCA72BF9037C81671E4.jpg +4AC162E56E47856E3325455CF380BF15F83E06A6D9138DF14361FA6091CE00CA.jpg +41D1FA49B7C729DDBC15954B0A795B0E61B839DD09719973EE9797BE09B8D7B2.jpg +A9612333855C343DF560CD5E1254BAB32743A28194DF8C3497AB4B8BCD4BCA19.jpg +2BBD3C68104174BA797E9895799906E525EA61F11EA141E15097180006DE916E.jpg +3E0717A674391239B4D5064241B49D71ACD1A520C36FF0D9D82C8A478BCF6FB2.jpg +896BE22D77BFD840F31AC74BF691DFBE5FAE2BCA2DC8A143892309E7A1C2660E.jpg +D545315FAB1E55D1CAA5ECABF620E05CD8303752D153A87CE587D9E48AE58424.jpg +46233057060EB1AAB3705AD145332F47924EDF1A00C5860513AD1EF15FDA4F71.jpg +19B1B4CCF9836AFB81F46FF3738757E45186A70AD38FB4349B7485E0708A20C2.jpg +CA8DE41F4774EB4710D010061A6C35C4A768700511C8168CE75FEC0897057DF7.jpg +907A7F1703D64D31DFC8AFAAD74AA6CA7E02BE247DB87FFABACA2DD6DF5B727B.jpg +CEF190B4A2CD4C48216CAE3E5E4428BAF4AF25B9B52367005EB3FD4ED306564F.jpg +3A4D8E81A0106BB169DEB109D63354933A3E9E193722A3F7345ABB73367EB675.jpg +298DB38B11BA8CB0CBDB88F8C38291ACC89D4552B41475DA8EBD22F2E1FB0617.pdf +F0F1A9539172147AA7B808583CD5E9128DF95309AAA710326E8A446273A7F415.jpg +82F91C60A6BE0EE4D12D9B2498F02E6129E78FCD19AAF30427FFC786315C8D04.mp3 +F394CB4023406293E8700AEC98916709F38E95FA2215F76320239A5B52EF2925.jpg +5F830D8647C7ABF28D631B171EC9C189B841B0998E0B9CDBF7507612E192900.jpg +643C7F234F2AB09EA4805995ACAF7B8E9106CA4DF4258504B40C0F46B934D188.jpg +4D06BBB8EB001F600BFC8491BBA7B588E5AEFD09A5A8D03E33589C9111E66DF0.jpg +7C3986B0EBD4BD7CCED1A98A66BC8AAA942D0D68B95CC87A5468AD152C19575F.jpg +B9DE271B7FE4D08D0C65528331C30537B2C41EAFA0A422A05EC6F40423C1A8E9.jpg +835E9F68BD8E2593D0F7CA2EB4A843C9C92596CB10249B0A880B5676C6A0B560.jpg +BF63B8CB52912AFF5D550C4BBCA67C1BEB4145120315DD6CBEC4BAEF5431C1B0.jpg +6CC67E6073EC1BAF243F49268EEED543F6ADC7E845146E9F167A900DD6F9BFCA.jpg +652FCAF10B234D671C10DC21B8431CD39323281AE98CD1BC3A4E4FF7813426F5.jpg +8BCCEAB1255063B03A5038C8FBDF4DBE80FAABD51CB7AEABBEEE3AF17CDA145A.jpg +28FCA825E0C7CF74EB04F55BA25ACA85335BC65581CDCDAC5729229722624886.jpg +2577DFB7552B10E862E6102CE16F9FF0D92A2B9E447CF0A036E1A50128EC1FCB.jpg +33233F0CC212F8DC1EB357050B3BA3BEB712BFE117B3FB933C0AE50901292C58.jpg +6E4727DCB999F71E7DB8F6BD67E24DC32D55A837B1D6427FA97DFEE53BA6CB09.jpg +B7695F210FE0F7B0BFD775DD763833268F99ED971980F1E9B192538A9038A2B1.jpg +D90EB64654F601938DD8CF2707DB6F8FA8507AB064DB8C91597E80C28857C686.jpg +F1CECC8C0F1884B88D10A96FDEE8A8CFA3513D46B47779F0BB002AC6C84359DB.jpg +F627B1553E8560F8FE388E54393F420E516D53915F8F2E8E2D41D131D99860A8.jpg +BF0B7F10FB82DEC0D371284476E2F59498BF59240BE74CCF22DA7973588B1FA4.jpg +244250559170CD4DBDB84B971CB6CEB3D41167E18E797E46C7B999736A465C8.jpg +B385319382CA6807C0EBE4258DBD6FB2DFD74F2DB582D1CD93CDCC5DF9C2B5F3.jpg +C3F0D55A1FE5D723ACD68AC05FA08A100829EF218EF74471E79FEB9C7B8F9C58.jpg +F4EB2B06DE72B200D7B748B4C9EBDF86DFB747B303CFE85165A37EF0636F9A13.jpg +4D606A49B551CABF7D7AFD3636AF06E8EBC2325147BC95BFDCE865B9FD151A75.jpg +2A32A33E65082974D14B13F5F93F0ABE4460D58FBF9569472DA5A5E22808D279.jpg +1CEC82DBFA95415553CDA5410A0FC2B3CB213FBD3C53F24C649111AA2879D94A.jpg +E6D364A0591142D913D7B3EFFA99AE482666B6FF22780F1A28465C8C9D2D97DD.jpg +5A01866FA49B0A4BC1BAB0F871747E8698AD1A4CF4B44C9DE9166EBCA853D60.jpg +2510EF6EC2130DBE625B352D27989A2E627A6E46D87EF35D330B86D066B467C1.jpg +2A0D133099740CF33BEADCE6A49997BC9701F8C482BF9C5BF41DC38B2BDF260E.jpg +13152A272567152FB87ECBC0243A0619908866AE1689E7CDAC07AA6E9D492BBB.jpg +E947119A22271EA9224E338FA876D8EF869783C67EC04720EBDB7828E7541ACC.jpg +CB99F66BE1469AF405A221F4E0885500AFA90F7BAF06AE50146026B9E3EC3626.jpg +9D7D03B69BDC2858D76167FF1D05F6FC1EFA87546E44E3E08D649E3AD1309245.jpg +A4CE67C746D28444898A4C34BFF0FA05DFA3FADDA1FA91C125335280ECF10BE7.jpg +FDA0A22E2C7BAB762B8B030C466AF90F36A547152DD640094CBE7F2FE501690D.jpg +3C8C7AAE0E3F557F9B2612F60E3F17306A1DF05E988FEFEC5216E20C9808D6C5.jpg +D376C71961227562133F33EB5C8D0C209B0CED1E54A2F97519B93FBEEEA14AD1.jpg +68B369C74289E25167EDDAEA20127E8CB929DC200CA3C2D49F6F8E7DFFA2BC2E.jpg +F38C701E1B8EB5199156CC71B402C9B462E3461A7C15E39ECC965B8ECD05C577.jpg +77E9D21B0EE91B9C9378228E814BA7963B75ACD957D00DADA304042BE7744338.jpg +8F1339B62F0BD0C11CC85C93A6496034DD9E2873631DCB9DD13BEDB3D7C946C2.jpg +EE5CC1B0409E1F065CEEC04DE4AB32DF1E482CFBC28DC0AE43128E3358C11CC8.jpg +D6A8C7D1E87BA06CE0F89970E199689C32DD2F8739EFFCAD29D5EBDEC55A15E5.jpg +C988016F6D9EFD9142ED326D55431C297A6CDD453C8394C084CBE5160DF78783.jpg +C691ACBEF9A071EF7D7234779AEAA20B9ECC4E1D4298D3FCB34B9F4892810DAE.jpg +7F015926C44CB726D319D72B20E905DC7218CB7602BDD7A25CD2F1B152A34F4D.jpg +6E77B22EB25EFB2571A5105077CFBD4F4AB6D272C7849BBB218E0A63B51EE928.asf +EF03DD279D613B78549158DB794CA8B0B3E6128769A4EF52C944FA7FFC4A7688.jpg +CAA18859C24F214C728AC6B5DA7B599CB8D4D696AD1B60AB9B8F3D46BA857FA9.jpg +13621ACA8265AA7CF4EF1208184FCFF625C2CE5934501292A21EB291F1AAE551.asf +C6485C9806A87854560FBDC8B113148049F4E24362FDD9E241893AC73B67533E.jpg +3D57BFB59A04135E502096CAF3D44B53081201AF214B4B36B7CE17F7447C0352.jpg +F82ADF1441B210E6C02B6F3674E8EAECB1D5A47C0F4BEA323A4648127E8F9E9B.jpg +63AD732E70B169BDA428CD9F4CECA9EC8C10360890E1A6CEF75C5B8A709BC958.jpg +B6015FE025F9E56914E4CFBC6627558F11887E24981D760C5A1EC332C2E083FE.jpg +E3E2AEBF960EE24AEB473ACC1B16BAF96C9154C820BE9CD330C4AFFFD7175F27.jpg +2853F03ABDB0126808450BB2576D3C05264FE10FB25C66FD2ED4DBB4D35E144E.jpg +C58E5EB5B1557C05523EC0F7FBC4B64DC231C33DDEB9F9E387F7F38F4251C43D.jpg +37C9B1DBEA985C56B1827D3122D66E89753292F2AF6E8237140933746A84934.jpg +94D1F7C23CC4F9CA59FAB9324258E42B033594DCFBCAA78F823731FD019101CA.mp3 +9F0A9856B83EE93A419A8360672022F981D2D18867C692CED37C9DFB8544F4B.mp3 +5700B17C8C370F74D1921738971E272B4D1180AB7960443E4999F5F2DD838294.mp3 +56369834838FE7F6FB7C2100F383A5F3BEC07AEE2506685334BE12561D754E7F.mp3 +1C8C2AFAB9A1CDF5EE1AE1C7FD397D018BAA231E905493D4EFA3A457F6E54E84.mp3 +8A320C75D02E2811445E3CADE3F2840F36682244B68849DC7841D4CA4AD49159.mp3 +D0FF3DF0991AA9CA607ED9DD5E9E89FCCF0A5679C673E76F0A81CDF9939D90E2.mp3 +BC187C3EEAC940BAEF51FE9B7BDD99A1DFB897D423E8FE0F62617D94AD98BFF8.jpg +19B3C0B9BFA5E4C458AD464E946B6BDB3DD3123CFD664B71983EA73D961606D1.jpg +3D658FA9CA441B6CA2541A1C284DB8355A6319AD8D109AA7E0F8445832CF5452.jpg +7494BBD1929CCCFCBF3FA00306806FC3A36D7C86D43F11AF144949C8267A8385.jpg +9A1501B9C3DC091C1C67E1E4879F9E8364036697D010AE725274E1C664F5393.jpg +35BA953EDE9B05C2260843D0F9652D99F2F0F887FB4E96AE9267C619BBAD5DA6.jpg +A9A15C4B940152B7FC490CBA87B2074EF0E5EB97F57F2464D522C6FD61C46A8A.jpg +D74409FF9CF0E6BC1DC0F2C5FD5383EAE4929DE718E5439668632D0716A3BE7B.jpg +5A3DC97D14CD2A687C64EAB28D2379AE0B6EAB32C5059D7627724C5CCDCBFE7A.jpg +B2A4102C665FE25FCA77AD9C52D1FBA3B43AA548667536AB7C467E8467C742A2.jpg +F4FF96960798C1B5F89044ACC0F685A4EC6A4E5291B6FC1301C891123F271789.jpg +C7255637A74356A1AAB8F71B760DD5CC55E34CB879410A332B2841345ED110C6.jpg +103DEC92178606A60BA7384088F6951D8C323EBF88C232A3A4408B4FCAF2E240.jpg +D2CC564774CC72483540278C90DBC5E1BA80A0072FBFDB8BEBF57F3C78A10808.jpg +8229166D167E1D985E2C541B5E89EB4443F192FD0A1B35DC34C9116C354B3D21.jpg +832D6CAA040DA69B12B61E2BA09B1C9EA2FF8B44E276D69CE4E910F29191E563.jpg +AD94136D7B545A21B34DCCD6B85B2BCA359AFBCBE0A8B2588D6FE6A7C0B1254A.jpg +7C34E486320107EA37F471E52EC39D2F6D488B2DE2069235C82846840D8042E1.jpg +4F39CA89FF40C0DF1341F47E1628AD6308ADDDF9D93CF9D4742E765980DA37EF.jpg +9F751437056FD3886B3E51300F6D67E24335220336A757639E01E7275B8777D9.jpg +73CAD5037DEA7F8A44ACA72C15D9D7EE1E5712819A5A3E4C2B54F76A5C7EC4C9.jpg +734792DDFA6F93AFEEE3C6748D02D10CB87C3E2E8898A12D3AD7C1BD166E3E3D.jpg +381E865A465B908C6E64B945F45EE874CCD3A516DABBAAA39E4A8D1A79C78FB2.jpg +69007F998F97EACCC3634D9B5B80568F8F37EB1BC503848A7994574DDD938A30.jpg +1DDB1712D1F9E8248DE89FD539CDEDBECE051F7819C2EAD1F0E0B5C9D56E43F6.jpg +3B47ABA83BA231445FA8DB5297BA8688B76D5A5D6739F85ED098701B96F82C3F.jpg +77EFFB797A442AEAD7AA598E2A5F5E44460EED988B8458A3D0B7B8FAB7237463.jpg +E59834EA2943ED9D2B448BDCFC436AC2694432709442CD0153447F50F60BDA99.jpg +9C3E92009DDD00D107E2CC7D95F59E324368C7EBC71D93E784DBA1CCA6AF11AF.jpg +C21E57854C432370B06942B431650EEE55D86BF877CC3477D73F88487981A94A.jpg +FABD7E37A149FF75620EA2D52ADCFB6FB94DCDE40731087CB10585FE66F490AE.jpg +FCA6F17429CF921F8C0722A24AA9114B2A546C2AF68980DCBFABB1F5BECCA1B2.jpg +9015A90140D8EC43C07DD22A779B2C78457350F9AB761312A836F542D5F601F5.jpg +389761EB8E409F24057F59143996410EB363D09824AADB0929B4EDF6E7419948.jpg +B00F67807A6912A6A51F5F75757911484C0A618A77FD11C41516D284DBA2ADE9.jpg +8388C48654044BE67CF6C0863F9EF3DA8B1AC980A0405FA2CFB52F186AC6039C.jpg +6E2B17EE86246A30CB2DE66D44E73D4AFD8EDDDBD466D0CC24450C03EDEFFD2B.jpg +F8D6878B2C5CD83B4F4541500921AF67FEC6C2919ED0B0E375A06815BA7E6B3B.jpg +B39A81763205489D66F43BE5EFE803BE98CA614C04C97025FE670040D3194001.jpg +A949979402A2220E941AB6823BE892D5C66CA3815C4A1B03AE01BC89E3AE7304.jpg +348E326E5708759B596C674201A0592B22CB8735F4F83BA1DB00E7C76362EA65.jpg +F51FC47ED1BAB43D28540F16EC4FF94DF242258F45BE9C915221081B7586CA96.jpg +D8277857BDA94D0DE7F19DC5176F671DB4B1C03913790E6FB3294F2242F8AE8C.jpg +5928832F30E1606CFAFF427548E57814C41D6C3F6CAC024E33650B4925582819.jpg +BD06A89361067C3690413203E07862EC5A8D20D2CF534780F246271CB27DEB86.jpg +EAB2F4C01973B9414CFD70D2DF76DB3A53B8EF4D4B077B54AAEFAFF0ACCC82D1.jpg +65A1CE969788979DC856A91B1A649CB6736867409308612EAAE7B2E830671260.jpg +54CA03185CB1D6B9E7E2530C65227DBD25DE79F71BF09F9FAC53925AC6BAD191.jpg +3B62CADA6ACB82304D91C070307E744CD98CA49196623276A8D89BDB7C124DFA.jpg +2559AEAE64A4522B57126472B8CA11A834B5E8CA42E4142F6E77DCB7430E64A6.jpg +93B1931D41301817732B614146FB453A74743F8F56B089FE71DD1B4CEF04976A.jpg +8BF7ED512734747346C0A0FEFE6486E41FE7CD6B9A01B9AAFEE3EFB3C0199E69.jpg +4B741514D0D2B7CFDF8D724F341C2FDE9105AFA55A23C3F1FFA9310D7C9E0DBD.jpg +46A4A4BBD95442FCA329BD714D00B4B7126517DCFED049C95F8C558B6C6815BC.jpg +9CA6D207690B6A0E47BB8F2923C67E914C1253558C7CD7E302E773EAF74B3C2A.jpg +D42D837F36445BFC5170C6267C7B01364F7677A9F30403662F5CC69537DAE387.jpg +A7B6CDB96CA94E545A34693566A5CEFD62628E2828ED7D70280161D775F688EA.jpg +91545D7906CE8A3F9B0F17358EF71B06D23FE256E737839904EDD4CDA47289DF.jpg +C75478DFCCB4900F75E3C890BF4C6A89967A457C834AA3193E7C29C1BC549CDD.jpg +40BEF9651AC99C7F9B24BB9862CBB6CEEF688F4E2224176585C4546219EA309A.jpg +C2A6EEAC2232D69538B988EA860B5CF0523739F4B9A1B80A2B03C920BFC7FB20.jpg +54383403CEBD56011DD3F1DB98D3083C60BCE037F6315BD07D124778FECD0545.jpg +100C1D5349A07348C4D7671C2E0B29DC92ADC310F5AC6E05A31E64D0B2FFAD96.pdf +F7757F0425BCB874269E9800B80EA3EEB182CDF5BCE0E37C6C43A0A96347B936.jpg +EE86D315A989896B59550B6161EBE84F1469E81637EF64998530E180554F95.jpg +271B09F29E5C28E820F071CC0BB084A8751D10726DA9A5EAA2B1EBFC0C9C8416.jpg +221A842120665C0E41F0F3816CE0C4F1542964DCE74E0818D8A3E01F70B2B4B9.jpg +1C8621FDB9B5B7546D292BF3F7AFA4EF487C74062AA0BF684086E55A588337B9.jpg +297C9B6D7FEE6C97D2CBB30DB578658E7F82A10310D3B5C9F76901838ECD70C9.jpg +B67FE42F291C95EA92F24D92729F1DA8857F0BBA632ED90A38893738AB0CD7DD.jpg +160B759E853D650133A4D6B41E97B3E132A155ADC35B3487645A830AEB627159.jpg +3C28DD114FC6451BACACDCC5EFA1841E1F77D8ED3EBC33F60645308363ADF8BB.jpg +F0BC1B1C8FAD0FDEC4667F2F275FBA8454752E9230A43D8ACCEB2845297C0E68.jpg +1496BFE9DA61446E329734FEB46DF4D71DCC85D028584AFE51B004A31C806882.jpg +D85544A3D0470F09C7359FB61164767793F2C867B0BCFB3D40141BDE6320ED62.jpg +72B4C55A318590441E43A61574B9D91B755B92F7EBB92FB98EF0B17C4DD15699.jpg +EABDC47B65930DA6C712749504F6A41954687EA411112A338FD4BCA2E4416DAD.jpg +D99C40AF6545E9045AEE4C9B40F683997993067EBDA714436D765423C3D0B11E.jpg +24E7840F9D734D6736B0EBFD1988D779906E0C86B37BA8FCC01F55E70F688033.jpg +EBFA474934B4B8BB1CA8A9BAF750802A89D447515BBBD5E1CC305801DC69288B.jpg +1AEC05A0CA83D8EAEFA62A48F0A7031AC6B24D02E194C9C765AC2875D920880C.jpg +E4DBB774C588CA161AFED55CB242BBAA40497877A7634E4880982DF529DFDDD2.jpg +4DC5DD2FCF69A0F68AAF15E57BF1288CAD95263AFBE10789325BA8ABFCD333E3.jpg +A82AC91A742697F571C9ED56945AED54CDF5379C41B8CB54F8FCAE94BBC5C7E3.jpg +7659012AB66C26FE70981DC1DB24C7A54262A51223E2CE72AE52BF184FBA50D4.jpg +86317C8942244CF630F872543D8C629640588AE80C87B37014CAB44BECA00C9F.jpg +6BC083F7338E1BDFAAFE734CF811FC8F383A9625F196EBE986BBA4FAB7973189.jpg +8FCF90AFE14A626F1A74823BBB4B76BA8D461DD294E7192105F36E802D4BEAF1.jpg +9A38C4967FD49F284468B9020C1F52501224368BF0613792C0372B0A91C05E40.jpg +DE4E9E1E9B78E7F56F043D93A3FA117137BB0EF315F34B222F9562B71EAF2F12.jpg +6382C180B655E20EB12D2B2122D0C8B95D6A08BB7968B809388DA1D77E8D95ED.jpg +35C2F6E5AC1FF33C1E28257A5AABD1C3A2A161D34734BA21810179D9DF902A3A.png +187A3E71106330202CF5AA5947BB9EEE06964F06B20BBD79D991E242E581C226.jpg +DFC292667F90E167BBACAA220AF51C4B0343C636D4BD8DABA115462354101593.png +86F3659117A6DC9007106C9CF80ADF35E04239E697650B240FADD8217A553EC6.jpg +A1A4460890D9582A969971BF45376031E4F2863FE5BCA874A29B19CD77F03409.jpg +B95E2BA09E7D8BBF85F66BE278906DEA90C833DE7995AFAF4C4D0F9FD46187EC.jpg +46D850302AC8F0FA12C404A419DA8C65EE095FB66FCFD6B2474EB0CB200EF07C.jpg +35C4CF1D4C2EF153CF820A22806DC0DA13BA811184F8F4526606C98D06405363.jpg +36DC086AF2C776FBFA266E2B7787A54C874BD4EE912BFB09505AFD9D08F70571.jpg +E945253AC2C60328F0794C574E10CF8903D0003878632FC962A67E6879E6DC0D.jpg +52A72E493DDC5D1D64E91A8FD2B23E13363BE74DE8595947C6FCC192C312FD63.png +58D8B5529F17E5F06D09AB6F931CD028669BFD1E5C204E072EA3A10085053200.jpg +F7744DA78550FAA7792AFF1DFF78B38293357919232811397DC2C217612FF996.jpg +BD291E6F2037602E113EB7918E95F449F1B7A4E6F297A904737E972E3DA66B5.jpg +4433F3DB23C2B40DC0BE116E042998C3BBC9DCCF919AE150442313DB15B71E38.jpg +8074CF493BDF5B686E8ECF3A94C47B32BA7EBCF6793B4B130F6EC00CD7018311.gif +2153AEAF4B4987EA23888AB49C079EDF1EF873A0E950ECD64A04505262AC56B9.jpg +891E140C6C8096D0562FADC20A9B2883AB175742B4D43CB185E5AC61CEEA14C7.jpg +CDFBFB1D1DE6192BF3745FC37AAA375ACE8A444C550D7D9773787E39ACA0FFEB.gif +523CF6AC68D8752915AA49791A96CBBC4D4669D62F3CB1B90ED791FB3599E633.jpg +34B915358088C570491D26664A6738C8C80F7C5B1815C905A6B97BBC23022E4C.jpg +A82CFABCBD755FFE81E2519330E40DC8669E65207677C6D84361DD76A149771.jpg +CA974489D023986ACB9ED2760258FE8E1098E7A1581158AAE4F6A0DC73264F45.jpg +48FE1E72E25090D2AC112C6B211C599DC87D7126CB9EA03167D6860A2CC9DA39.jpg +3ADFB34A682646018B240BA5538109EFD8BBF9FBC36A97217C4B5AF2E1CA7A2E.jpg +48846AFD596F92ABE8DF51774D1DCB2839FA7DF80BFC9263D531FA6D300DF186.jpg +E11B64EDDF90C320F79169F9E0891F96FD89DC747D35B9A7FEC79893CE7FFAFB.jpg +2D3CD0DF71D774274FC4C43B0A152227D6BA5F3975808E1B00D090D6A2B60A37.jpg +F6D9F71DD51ABDA6ED37826DB57DF3DBCA9989604CA27F9BD11908E50F1F6F29.jpg +C14C68716ED6D3385B480DE76D6C663391BA76F329E863AA136272B5C2A8FCE2.jpg +51F1C3997AE16F1031B7AB50CA86A0BB8147C5874ABE400383F9A3952F17BB25.jpg +A700590D740EF60C6558EFA570AE62D1C3F20F12A2FA5E06F3195510E3024D92.jpg +96287B0B61D7E571F124B439970BFD4A8E4AFD5AB68F6CB8FF125EFEC6103481.jpg +20F2707C18EED5FE22F8BC0F357ED375980A42C22479C41BDD3F5E27E420EB02.jpg +9E92A5E67C870B838E3B64886716B2837C43063AEF079C4C7544E64CA8C7C798.jpg +D083DA201E2276D93AAF51FD85E6CFBF5370A856469EA36170E86FB07A856F91.jpg +9BE7A395C2A7EA74635BB4A84A92F3E62B8981FAE8B0EF1E79D62C47BBDB3071.jpg +B0917C59E21CE08C6D6623FC3347FF65DE725AE9C5FC8F0591F81F937899712A.jpg +26E7664ABB0466BA91681D6E634A4AB1B328BF4EE044ACD1879508657E8F033B.jpg +DD4EEF9165CC78256D7C77B03E5C1678917D90ACF8A6AFCA524E80D0F47544B5.jpg +DF853FA98AF9BEFB7EF5D39A55B3E2F04DE5F0AB8E36863A474531E268DE8AC4.jpg +B8B1A090AB52E8A069289C73E6CC9EC7A397698D48D0AD1FED71AF3F3EB56670.jpg +54A0C599C8402B7EE1019556E53CEC656E1DBBF08DB906D1D9A368FA76374DA1.jpg +8C99B20A94C8380D8DBAE87C6AF163FD1FC8433147D594A933F297ED9D8D4B8.jpg +CAA38040B6D290229DD7E3090E6468D248C1F57822904B609A3B911BAEAD73CE.jpg +4BD676A68A23896D4A135A42FB59AB69081E46761CC585ED976057506711C586.jpg +B505E00365260B9A69A776E987F4CC3056AAB7DFFE812002321E979D3B9262E3.jpg +51425095E5707F66B7E2ABA07E5DCA17BF0B626F4546FFB8F20CEE675C1B0661.jpg +A419CD0ABA3DBFD6D723A1C3C707515628AFE23F78E34267CC523C7DB2363BAA.jpg +C8B2996DD844B3BF961569AD8A951698D1B44CF92C307EAD7A44A46D80411E63.jpg +F21C75081539A3B1F4CFADFA5385C496ED12A0A645E2DE7FDCED9E6EE35260E1.jpg +E9468E2A242E9E3B3014DB55FC4B57302380FB032673D51B5D63F937552825B9.jpg +703906A736FAFB0A2088C82B9F4D9D4D7DFF8956DE8DDBA4005407380EC2ADAE.jpg +F37D39CB23EA6AFEA8AE9D8692A6776BAC404864E6792431828A630F3E626B83.jpg +90EDC2F853F88EEA771CDDB53890C8DFCE19935DC54E7E7D3F73DACC551B5C2C.jpg +D2A475D76DE5FF26003CD8AFF652263F140A120115A21C17FD5D2325CDDAF505.jpg +1B6199909D2EB225B0FBC506DC37E31FEC947A835F0088C452C8B6E17EB70A33.jpg +51ACB65919C65AF2565D8C8317EB5E3B65D76B56BE9B483B9D85B735A3EEF65B.jpg +F098F16E94C72ECC48BC0359372583E81AE6F8AC10670C85FD54AB7765F73EFC.jpg +5FB207E3D46E797AB61143DDED5F79C1CFAC8C0B79AD5F4C7F2AA074680A4013.jpg +94D41261622AA7A42BF5AA6F39A29D672673FF8078790CBE8E356A00D4BEEE41.jpg +2A6290EB0FAC3984E1F83299E368E0376605FD54F077D30DEB5BF1A2C6ACD9D9.jpg +106B46DC01BA20143BB6DEBA7F346A20FAA1C9F06E555D5044F8CA1E06C45CDE.jpg +6F201038921E4289ED1518F96B88D855CE129B9A253F5AB26E341FC413E39D73.mp3 +B09F08D12C8405CAADA7F6772FA2EEC930A13139D9402C2825F92B4205234B39.jpg +E8905440BC876950CD2BB5FA90B3C556DB9F77FE486FB94095CFDF7B114B9340.jpg +24560263996E4107788735F70F03F03CD24D74FFABDCC546BE2B63A0DCEF85C4.jpg +7A91208E0F9F223EE891B71C54B47F0AC49E202D11930EA9C079E984DD0026EE.jpg +9EB8BDACBC60CB83999B3BC0A2489C65EA52240AE6C24190C2C50555844948DF.jpg +C72D6A14C64BFB86691A74C5984B798C9FF69E543F222048B99694DA3EA3B1.jpg +C8DC84AB82B89192163C242776C455E7025654EA419F62DA1E45E2AA6F6CE703.jpg +DC1EDADBAF1D144650BBAB073521028AD0CBBF66D7B60E9CE523B8A3B9153C0E.mp3 +12773F262623FDF0DD55B02D7ACE1145503AEF8DDF08B555B0BC8B6EBBA83925.jpg +44F2B8318A97F53795FB23682F71A8653D2C86B6E7C3F3812F397928A37CFBF0.mp3 +4E10E66722E1F1D1641865229FB446FEFFE2D7EC8A18A80705BB80BBD1FF9C7E.mp3 +1854C96AF2D11DC255C0E80707716997B394D682558B62B1A1EE89BC500F111.mp3 +390E5853C92CD538E8D6C99BE9D3AD55D432C78D0B42583286D7707D8DA14509.mp3 +9EF192C13BD1DEAA081DEF4FAE5B633196C0B4A311DBE4247869AE4EDB77E53B.jpg +953BAF7E26986A1BB0B208ECE119B12116E7FEB85E99EF5423547DB842B65D87.jpg +BE165E268D1CD1442C981915B2D1993726C7EB78683D33655E62C45F5D44643D.jpg +467869E147C7659F25AC72B50EA5D1B50709FF8E6BCD4B3808DD1C0D20CDD8AC.jpg +7091CDF073698C5299359F940998C63C2AFB2733ABA46D0EAC913FAD2E3D65E1.jpg +E8D80EBF84E0A15DB3BA681805959AF9B4B92E391AA96D282715272FCE6F3870.jpg +9255F4CE9D80E6373D8049656C6BCE83BA16E84C78350EECD27314573648776F.jpg +2CBF94AA927EACC95C5D30B16231B884F0E31C3517227EF99B9716A0EF0B15B7.jpg +29F464C07012CFE6145A27909B38B8CE4D1817E8CF7A50FC878B2335A42B3A7B.mp3 +1601889A7BB1E03C21942A4225616ACD8493FD161132B51A0C27ABB7D742211B.mp3 +99394CACA9B3C84FD4C800700E932AC84F65C928007A1D8D26F6D2DF33550F40.mp3 +F5CE82B592B5FE047F97877B1E51EF66F4AAECDB2EF93AFF5DCFE11D8E7A7EA.mp3 +6E4BFCFC36A611E55799F58977FAC38921E6F0A8E7FDA73F73CA4EFA2065EDE6.mp3 +9FBE30520BCD9851FFE339F0D74EB60275FF338A0087A704ED52CC3EF4554A99.mp3 +6C67085AC0609DFCA5AD7CE8E0577D0CB0F4762483AD57C4FD5ACBFF1AB9DC44.mp3 +F42E301BF76302D8F75877E212963D95A7B455F6DDAE97F3892741ACCF94B92B.jpg +D64490D750741B0FD04B04F96DC7D0DB5761C6E89CD224BB13FF773A24849277.jpg +64D9D582C48D6991A1A33514946384177DECC0A6259EBC1D7A7CE0F230E63498.jpg +75932DCB3EAC17EEB9E1CBC0C33C8E54D30C8728AE16E747F68E9AD22EA092C4.asf +9433460315AE8FD94A8EE07F6B7A2F191BA77F386331E2AE335B6B9E895DBD22.jpg +2FE50C9FF936876A59D8FDAAE66CCE22EFC6627ACAA7954CF35E0233F2AAF017.jpg +2E96F0BAB4A2E533C2AAD4BFA7F7028D77CE3DDCF448AD614A73480AFC13942D.jpg +9498C4E4C9C77FE707C4AA4309E815391896D74170FC132020358852BCC1A5E7.mp3 +91E1431CB0B430FE399269013F857E02C52267A9AE16EF8D88A9DDBFAAB25EF1.jpg +799DA141BB1D7982851511C8F6F213405AAFD18FABA66B69A71EA09FBDCAB044.mp3 +C0D0D0FB2F9318846DC84F3D3F585ABABDFFAA44819C690763E4D3642E4C59E4.mp3 +DC51F8BC6E80DAC2F627D711A29B71BDCA6517F28AC744B4B7D8058909DC7951.mp4 +7C3C3109C165D0B079C95215CADDE575B9485DCD1A98C2194E6EF0992F60BC6F.jpg +1CDDD3D240A69588ECD91A85806D2AEA454A084F3733A4664C925463F03C0B39.mp3 +13652B75D2F5B468EA4C04C7DC3CFC0458CF7A8CDC0E9C9AB588E418C157D88D.asf +DFFE9CE079731F9D89FFA4455C3E1423F9DDCB7B8F1D4CA802E93D40C7A08496.asf +38706765002B871B710DE87EBC8CD862DAD7C50F24EB066BACC7486AF838D8A3.asf +E979BF8895CCC1B15A619FC2E0C18313E8D09105EA1E1290E3387A6B1D3411CB.mp3 +70F824DADD7D33DB9881259E8C532077354851AEC9D8418A992C399499229DCE.jpg +2888F69F3A01004C604D1DDA64B6857DD170D201D24F8298814CBBD8426EF783.gif +C1F23802202303734FB6DB1C1496C14402F75D9AF7654CD779327DBB3D4B1B85.mov +427BBC6BC6950C78698388DDB79AA3DB3C48C4FC509076BF4AC0B777C81CB77A.jpg +D5923BF742EE9BA80B5F3F617E2E164F9C08373A54FF0091F3F9ACCA7B696F32.jpg +CBD7C13A668A913563980209398885D9DA947003ED757DC9554BEFAB85AB957.jpg +6B99B28EBF6B5BE3EBBD8466D28FF51C479AF3CA1D9CD2975B12D90209E801B7.jpg +D9925EA101C138750E604B564486D5BC6E5D99BE162BB4F0021D5D512196A78D.jpg +813C36FC47992424A38DC91FBD0DB0DAF930200F54DAAC7CA080532A874B1EEE.jpg +69687B691A773F6AE1CD6214B55090412ECBEABAF1998CB9C9CED523FD473BF9.jpg +31D108EFB82DBA8654FD35499218B9A111B3E96792071F3DDCC0FE97FD4D517E.swf +6F67ADF72B8704121640D0FADA6D20F06982F4760B054C3FF4A8ABFFF6A78DD6.jpg +5FE176679BB59E84630CC46146582A0EB69235593EE5C90179BBA3C34B0DC519.swf +A0B256AFA540F62EF883173095B8CEC5C249F9F7C552AAAB76AD9C7C8BD1097B.jpg +4EC7DD43F8CEBB77D240CEF987F3F57282AC81FCFFBAAAB7BD3FB4E101082216.jpg +6A1E2F6B2079229D7A19DCFA1B7FF9508195B40F0396C77FFBC02BF98272D78.jpg +9A8EB32E7B4554CB05DB87BD7ED5C7BC639C6EA21D5D489D116CD3726467A64F.jpg +EF26270FCB54C16ADAD48E0F702FB917B3A85ECFE36157BF9ADAF358A7940C6C.jpg +DDDD25132A2F5B866345283EABA1A71AE2386ED9108C423F6206D384BED27315.jpg +65F635CE46388EAA2EB72589354DE22F1E1B045CDECFFEC6B08CD9D8B71F4C2A.jpg +1468C5DC8577CE6D84FED8F6952418ECB2EA8D18B75B77EB7603BD73BBAEEC3E.jpg +6BFFBDB46930E2BB0B8AE3A975B9724328386CCC91341B75BDEBB1447D2C0A37.jpg +9C7452935A0BADF291991DC4A1D84B94BDDC3E4BFEB0A69254B408411CAD8C3B.png +28A449F0F1EB42F3DD4C27C27BBB9A88A881B6E27A4F0B3AF0E5CE76F6F771B9.jpg +D37E454E599774447D544A8342705FF58BD8AA3BF4AC60F8959C4C6022F3794A.png +A57A5B5C9374767D58D4CDE97B1DEF4EDC3F12C1917995A9AA3FA74212FF219D.jpg +35C58DFC51DE504BDB133E96BC584C648C1BCF42BEF3D4C7B6EA3DF910C23D21.jpg +34949B0713124AAC98394EED9E5F00D57387A75F5265654B6C24E1B34C60CE37.jpg +61963F3206CB5A653A3E705E530B6F7426728C116BBB8CED04B9A7793ADF7EDA.jpg +C6A1A13D991BF53D96CC93A85F8D4AAB782F1EC7D8F86F0B2CD5945F0449A86D.jpg +8C6DE1BD7FE902CEDF20020E725E7A06AE76746AFB09E89B39EC986398A2443.jpg +D328CCEB2B392780D451DCF96A9BFBA945DDC1A61F0DA57140278CABA6CCAE4F.jpg +C88454D61241D882ABFD27856F8E28BB6850CF6A358DE4CA63409A5D6BBAFE6.jpg +7105390FB8848CCB3A0D17ACE4DF542145A2D63760D180EEC44A2A59CA82E2EF.jpg +EDF3CD037FFBED59224CB8D2AA673B8777F527EC73A4A35766C323B0C9FF440A.jpg +3E3B1762775800167342033E226ED9B1DF61EAC5A0E647AA6B391349F06BDB77.jpg +18D6B26D6A04B7AC37846FC660C72D9F86CC654DD3015DC9031F807133AF2BA0.png +F30F765BD564F29C2CED3E9B18E4A4B696115B36FE0AE6D1F97BC14AC3553848.jpg +8632F47AC9F664BF322F52FCAF98B8D7F64116491AD94B5013B38B0B86A2E6C8.jpg +4E4C65E140B573C7D61C08E5482CC4D3879F2D827DAF9EA2584017741163D98E.jpg +A48F825A1DE03199A85495BB6EB0A43903FA794E31F955CDACF2437DAFF0794C.jpg +29722C472EE17D1D75E5CF08A1C4E7843A677D10CAECC8CF6A823C714C418994.jpg +DCCF24C08D5343030E8735CCC3A84B69E4E6AD9CBA5FE5E7550B0A7136394536.jpg +ACCE96CC50D5CB37F0A3B54746F3448F93D7262BBFF40DC8439D133B6BBF64C3.jpg +60E12988620D1C79838D38740A19AF529E93C6F8ADB3BA02C88BF93E90060986.jpg +E05B6B35CF38E1659E27F2916E223E97B56122B85718CD206D7C60A4643E0F43.jpg +6900D48CD8EF2C1010BC7C1F790EDF1D0762D05685697F4DADB17A17D0F5CEEE.mov +AEC3266FECB2072C65884B4FD6A431FA3F8530151E7515457BFEA5886B0EE37B.mov +914C7DC4A8A24B45229AFA15254201ED8C18B9EE31C46257E82F9E991E83D55F.jpg +9E328072353974DC622C5CBE94BAABD3164EB87C5FF80DEE7586E718C0580E5E.jpg +D5F21F11507D5455514C6DE92F7AA2D3DB91023FD836812ED72351F10E9BE88.jpg +D4D148F50478591185037C2E1968A885A169276A1CCC944A506A6470BDC8D93B.jpg +AC058246F2834A7E9BBD86036EDC179AE53252FF65D36982FF021A7C5339430B.jpg +A9E237D3CE858F2EC2B7280C3383FF73AB5ECEA2759B646D9418301BA8A4E2C0.jpg +4C7F3089B808696DAD5FBE96841261D008B442666333097BD5A8B5D6FCF1D074.jpg +A4EB2A1594F9DA39156EB6CF6930087C23B92F5035B783711985F7453EEEEBE5.jpg +27B77D61A3942C49BC3E52B8D7F6F07BC3DBD521FF32B6106EBC4292A3188F09.jpg +B4E1442FDF6A9388EF4DD89A72F27C54AA84E7CA266A3B460B450704C1175844.jpg +6DDDA955C40E18AB9C922BBE0635CD041BDBCF28EABB97C408A4030ACF71BB96.jpg +8ADFA3764C12DAE9D6F46EC554260680DCFF2E71ACA13989A5E078351EE17C1B.jpg +B6E4B56BFF56BE2A4739B507469768E8445622DD2069DF261A1DD5B84A7694DC.jpg +7136D6F3FB1E8BF700F07C76F581EDF49F85EA2202DA44448C13A289DFC37E8B.jpg +44952F4B500EC9C2257F9F52B2EC53A3E5E164B3CA1E7F3A2D97C6DAB7D658CB.jpg +DAAEFE6F8AF20F3C9BB89D28842ED35949EEC4740E384B4491E79BCF9B8E436.jpg +9069D7586723E9A2A1A77CE3917F01773EFD03E3C835E6DCA3A81ED4AB2FA5F9.jpg +F232A1EEB0E6C6D2BA3D492DE3C83C220153320236ADD9B2D7AAF59856A9DAE1.jpg +3C0226FF80B79B41980665DB0902D456606DFAA3E4734132F140A7286EF0F775.jpg +5D4111EE301BDA3ADDDC1AD7322F25CFAADD344EE277D4807EA045E078CE884C.jpg +508EA4AE114EA29E2E503309E2E5F1EE09F6700D399E7B33E99A38950B4F081E.jpg +16F1B4F20EA79AA811339C8591711170E967DEEF5A9B2F1E1F8281F1AC9DD7E5.swf +1A094786938F13D7F165CBDE74F1F1757439CB2BC3F33E4EC9A340121FEA6A5E.jpg +827E89CEEA3E98A1113F20374B0B97A7876A659A3296DC450AC9B2F146D1131B.jpg +ADDBF049871735F8DDB2DC3C7FD19FB4B84FBE54C20199273E3CB5C66100851.jpg +DB1AEC6B467D34E82EB1EB1689ED0272023D96B2DF03CA28DB147157C9D7505F.jpg +862C4EACB0654644EC5F99156E65092810B819BAFA0FF5F275F02C38AD1A5408.jpg +3DDABE837603EA7B35DD5DD365F8B75BCC0B31A147C05EDB521E975C249182FB.jpg +9ECCB51B27EBB77ECFDBD01FC7A49F70C99103B7746FAE2E45E21923CC3F5A8E.jpg +43CA1997B7DD97D4B9C357206E6148D5EB41353D7DE797E5D9625B5572312479.jpg +2649EFF7EB80A056D66CA91CE365BAF6B16A49A0683B8200769AC41FDEE777E6.jpg +6A35F1C54F3E23C7C718C1036841A1F526C9CCB0D1862367DB4876EFF07AB922.jpg +B743D70B45A25A017F72574EB1CF7A6A1DF2AC0F9941E5E8C9D4396A246227C7.jpg +9B234E814861BDDBAE653C22456FD81362D987A9C9F744E1716E72386FCC212E.jpg +10B7C81700F71F7CA9AC32E3FEB893344913A7A6B44DF3FCDEF75A4E9E27F6D8.jpg +39A89D96A5297AE5CA53C967B8FF29B02813046F66D3190B4E0D8728EF6FEEE5.jpg +EC45A8DCF26EF7C7C20EDBA5074F7A2983FA8654D4C99D5E6CA78DCEA91B9202.jpg +18FFFB86951F0CE22F426896A8D231003F856D016237FEC25E783D73F64CD62A.jpg +5FE9618E8699E594BC090154D87F660472D3CFD9CE4F8E0F1FAF78AFA807D838.jpg +D206A750B53968B19001E4F94AFC2DB0D91A2761AD1FEE9C7D3C8FBB8F008154.jpg +9AFC3278CC1FA34078281F526838B16ED5F74F6C5F26A625095AD728434D4021.jpg +3B2C8DD29A1A1CAEE24E482E3BB1EEDCFE3D40041C496C445E856F10E0655F08.jpg +F188DDCE3B3762C3805F674335A16544B98C59FA26A9529F5F4D1FE3F7BE33D5.jpg +567D8307CEEB2AFCCBEBC9DA0824F711ED69CFFE7EC253B9FEE5C84F253894E1.jpg +5FE35C7472D7E26C540E27B8D18C61280B5E15AF2CBD205F426106ED561F6AF2.jpg +501A14D9263B148264C43CABAF911F510CDF23D9846BB5EC534DE4C4A05AFAC8.jpg +9291C8CD6782F0DCEE6D35D9E83DDB9A63D2DDCC3C5B2548C6DAB946760208AF.gif +440DB4030684BE6387AC66AB3ADAFCE3091CD4540BD3926A644039D6EF3EAE8F.jpg +C39A24BF119695918F4C20BF7C6E2C4F0F95A97D65C6B5492872EB4008359B43.mp4 +F042943DCF82F77AB77F03E64B5BC174E9F8C1578C62081B72362205F0F55522.mov +3927B0F97723FEA46C7B7A4438E9F35E61062FFF43C92E0D7F129F0DD95CD8A6.mp4 +DBC8CE53FB0B5B83F6145CE640C29F2D4074A1DF80E167BB5F2998F69744941D.mov +B7439C82BF67ED3C6CFF8618A8272577D3FF9E2EE7727974363B63FBDFB1CD84.mov +3DE39AC796DB6D07A0911A8C03DC97FB6FB9501F652700C285286A62D824C37D.mov +2BFA099BB0DB045AD4E26A928179F9EF18C2B1EDFDF80EEC2F5C896A6713D02.mov +7BE192B093ABEBD18C150AA0DDB7AAE2DC439C195C26ED0486F8EC4B43A459D.mp4 +E2F1C586E21BF1679B50B367CBF0F4E1982F8CCBDAE2F29195DA625AB02F07BD.jpg +ACA7321FC13F65FB29B8E835C936259A7645631A3DB48E22F3C0A7C27D8C5E69.jpg +F5D6686A8E4A54C67A35D35A86B6E5B65AA56435AAB7DE6DD851EA67B473F07A.jpg +A346A3D85F6EC53CEDB80B1B914B297FE92DF1FB12D7F3DB0D245B7EA913DC6D.jpg +286E3CFAF0000DBE2659C41DA20FF014D1F3549F83D956AD4BA6B67D3716D95F.jpg +7425AF67274B965CA89D4BDA56481ED44C5F85B1C9633D93551DDA82CA2E05CD.jpg +AF90F143AE5A660A20068B3746B814F34289E724433810E3C811F5823C00E0F9.jpg +DCD8ABACB3DD8A6C28A2B6D0A5EDB05541A568727881E8DDA7B1DD8B74F908F8.jpg +85AC21CEC8BD2EB3C1AA669E03B0E5E8D69EECFDD3BE4076EA2793E4F35B6508.jpg +837BDA34BD1553138E0F4377281645F415AAFD5DC4572FA0D5222793A0BD506.jpg +86D0F20725BF5B6781FE447B5984CDB0C48F57D9D656AB2AB5DDFB1DBE3419FE.jpg +60C5B78536155B6E78A412F673A59DF765C0B40CD848FD6172A1D31C69329DA2.jpg +A6F8EE051197DA1474AE8D7FE5D95D71E9FCD1452524FF50E7C169629B231F42.jpg +24D3B738C4FF9059EB69322D526FD6FD6E88CCA9C0F6CC10AB382415AEE4712B.jpg +16DCCC49A822114B6BBA5A5D710D5EC64B94B9CB8DEB7AB67CD1F0D86B69F877.jpg +5762100D2BA112F0E318144D98201EB89CEF825CE7AC786AF7D8F14EFF3C05A5.jpg +781DEC0B29EF6518598E80A068BAA2CA7A23D9D36AAD67105DC845106C7CB143.jpg +F6516A8382A54455E4388A0D3AD5200D7A817C115A18B090E90D9462A1B85D19.jpg +485FFB31EE8259A5397A96BC115AEFD73D015F3EF2D10E5AFBFEF00C50416674.jpg +6921B4CDA36394FE923EBB98D80E24541CF6520574ECEE4FFEA7575D4759F949.jpg +C67AB0974AE6529D84A83E19A80E5189156D97E093F6958CF76E28AE22E11ECC.jpg +CA9041EC1E35BA50B02D195D2BC8C50B11E413D7E283E4CB551DA94937619834.jpg +A20CDBC52F35E0EAABCA4F32B7C56F9C117D49EA7CE5B44BB62BCB81BFFFA800.jpg +D94D29D1F44C382DE1B5A28EAD5C36F61F8EA5950E35037A69F54CD4E1034BD0.jpg +400269A2676B124D9E8D19782FF626E56698B754AE118A84004751B114CA8F90.jpg +CF31C1BCFC7849CAEEF6507EC5CBB48C9C233800A263EA2D22DE361588BBD71.jpg +423186E77005F4888A46C7BD65C36ABFB4D5D71BB1ED243D97AC13510783C598.jpg +542ABC4D8DA9F0D9FA96530485D554E10C3B19B7F760FCFA81B0EAE93AD2DBB2.jpg +DD6AA57329466A01E7A1E9BF724FC935B428FE8E77B1CDF29ED28C1A2340347C.jpg +1E5A4FD87AE073D10CF0D0B0C454E2E55AF51608087AF8F797CA8C8DCBD1B929.jpg +7EC74FE9277B625CDDA0BE8F0E467434C9BD888438AFAA3818541A78E8FEF6DF.jpg +F4784F46BBAC61F563F52182234A8C8829EE943372236DCF800C895F59410A2F.jpg +E69DE4230EF8DFF1FB391B563CB89130A5675C35170610CB1F5ED17C2D523EDD.jpg +BDCA4E1C656806E90AA61A6D0D6D44A5738F618FCF84D5646E3AFA5177233510.jpg +E88F7D8F83D58045EC4782902506F986567CD5CC600308C4833F9B8A2C14251A.jpg +643D0CACC8B42B60B2FF628CE5B42978748092E4A22B4F71139A6B11106397BF.jpg +EE732CB74EAB62EF68AB2A9D0C2EDAB41EE1E3E4833D54ED72DA37520A3C4968.jpg +61F5B728DCA43FC470E3250834EF54B0C1F60CF1F8F5788C93D850FB2B2472CC.jpg +E15D6D008686C3AA4FFAB08BB38170F13992904707E1975B9C8B9B26FBE8D7E5.jpg +34DE3FB8E0B9B969A6DB152BA25B180A0B5AE8A0D9BE143F5A459FE897D76757.jpg +DA8FE88198C2D552BA4326A871EE88B610D55AC65DD461D0045EDC1CC10ECDBC.jpg +E35104B84FAA1A9198AD3BA09FE871C4659359DB7AAA1B890D26D6C29532709.jpg +F6CE7518DDA657F2A02AAAFBBD6F22CF463DE4379E9162FBFD37C48757A3C614.jpg +FA55B50CFB9E46D812E82523E0DABBB624FFBC34CA4E189BB1722CEBA9CC8462.jpg +7EA0C97FBE0DA27ACBC538C057399EA77E413333345C2A5E82819D037892769B.jpg +A7F563C5886682AC5D8DAACC710BAA41C83FE19D741FB058AFFFF0061CBCB6F2.jpg +87A3F3DAFDBCB19AF7FBF31B39A11931907377DEE96539C470EAB11B36F99FF6.jpg +F88ECE65529EE1909A2B240139B6D68EE8CE1839444435676D9462EF86633031.jpg +F457BD6DDBB42354CD36B10320680F47D00917C037308B85E4645316D93C1A2.jpg +A1E16A283F5281F9AEB788837691016B0A7032D08891CAC21FA4E4AD91E08C60.jpg +F0E9BB903B90A5999A638FCF988A7AC21E6214901DC3BEF0F8E38CDEAD55A279.jpg +81B0C6660E2A1152EC421A29C8913D46925F80A4ACAF461DB1569199D68514EA.jpg +9DB482F26ECFB63B0631BF8A660A38F0448DA97D71B6327DDB0EAB92CACBE9BD.jpg +8DC721C80EEA1119FD083120330E0077A4C8E2B67197FFAB8F36FE390CFFBA12.jpg +223BFE270FC064145D52088A9671E7817D59BC897D0733D80929CAD5A23D6454.swf +5D517D06E52D873DFE13AB502C314ECAAD1677FF01147C8644F75880A2B879F8.jpg +685CC5C19917A3ABD3AACB379C990BB7BB458D235A3EBBE9FB8275DFB62C0CE5.jpg +A0B4B13B22CA769BE1084B3A14215008AAC72BBB7D05C0152C71ECE1CCE98505.jpg +B33C682BE1F12AB2CE2C87685233403EB93E751C6789AA3819B3742D5167D8B1.jpg +29C6DA0228025430B44AE0B807E5A6E44FF842553F7B4084A51F7C03306DF0FC.jpg +7A844BE68E359C829A0CA81BFF33AD25DB91381A3BBABB58D691A1E7A7113EAC.jpg +98C8CDD0F0089EA3DCFEC5D81C53D570A78E73B681A0E25297280B67C84EFD6C.jpg +CEA50549BEEE5C2C0BCB688DC2EA1DF5BBF6A0859C6523C40EBD72D726FD1D6C.swf +CAFA00B99B40965E83E96D6B7D7142D7AF67A31FA140F25F90F48BB38A87E875.jpg +5EA2455A269339F669DA6DF2F53D0913E1E9154EF6AB519F0052F5629C29B77E.jpg +19F27B320D39C952F8F66DF4180045795CE729CB1ED981CEE5121083CE0A2EEE.swf +9C25888699C3A7913489FD5E01AF0876AE3A138307A722469B6FAA53A4E479FA.asf +731F7F7596D8DBBBD91A625D05A9C7377F1B21BD736684424647A2CE45274AB.jpg +FD2539D7B501AEE9B49678EA7700CAD36EAF086D0D51AC94C3D635A480E34604.jpg +D08A87E3F9F32256E77AAE84928AB749B46FD8742F0F36A2552995067A81BA60.jpg +2C2A576EACDB9D7FD46C2CD8C7F291BEE12409B85697BD9A9910F4710EA404DC.jpg +1C0A58F16E6E815ED037803A65C0FFCE2A92182B5DCBCDE5B690BC01A261EB31.jpg +72D96A9F87120E3B20584FAF7729977516EC2B4014E1AEE1F4886130EEA33AFA.jpg +FBE78E5F9080ACCA759E6AF75A902775F5900FC594045C68BB798A50CD469545.jpg +7C67D1B0337A588A07126F38F7B7C59FCCE78272714C072447C073A127C1D1B1.jpg +F9CF2A72BF8DA3C425932D21DDADF75151B81AE2B755845F9276EDD8589BE06F.jpg +F38AD7CD65B7C93AAE2020A8D6B38DF31F89DCB7D972FE73F9E52FB4AF218068.jpg +BFB05D1D07C3ABF5890CDE1AE445B4F2E69778B0505FBEACE7CCDE02DE2D04DC.jpg +197531FD917A0C32A8195E8B4AB5FFE7100DA2957FCBDC027B07A8E4F6415AFB.png +C982B3BAEC28A6B600EC2C48F9195F5E6235653E82DBEA87E4A1C6142951AD0A.png +6E417B1AC5EB07041167A2AC15583E69A996DBB766763916C999317AC809ABFB.png +F138D42AAB37B1C67AB9F4A310E8FA0A300BF5CA90097925D280E24CB7300AE8.png +B760D3599E35C07DCCDDF7988A117831FC7F5BEC6FB4E71FC928C54D8F27E9AC.jpg +88B2D063139B4E072C7AD8F8E49D4368BBF473CA00BDCFE692C368D8638838AD.jpg +24A8E0D2D32ECD8F8255D9730197F57677F942FDD5B3031E71237875B52A8726.jpg +5ED9F6F58B1509C2828D4CEE5FFD32CFF585B4C2ED023E8FDE6E8E3BB509E1A.jpg +8093ABFF6AB76C14ED1CB0586E935C7635F70AB15249AA8407494B891097363B.jpg +B7C37F26EFC9E0C90F5D38EC20B135151F7970FA270F6FD63842440E9A8DEB4E.jpg +517D5ADE796C196A0D30FB06D694882E79A54B3A73C95642F95B149B3AB87F0B.jpg +30415C5B87FEDD4B249FAEB63BA823C819EED456B6C39BF0D67DB74590A69D69.jpg +50782371C66EEFA8774AE4FB5B71D052AF7E098EFA98951D3234F2303CC1EC14.jpg +5978E527797C529FB35B0AAFFCBD0C460C2EC8EB5D14D46494F8B69FC38BA880.jpg +EA099351625C73F052303E52D9593B23549736684C212B5B514691A507C459A8.jpg +F06895EABF24A7E2E2BC7CF47CD53CC8F348E291D502A4D171874AFCE6F94AFD.jpg +EC9BDC511BBC08BD05126B2CDFD2634AFA56745B3F3DB399A0AFF188925FC6C.jpg +C80CE2CD7905BC21440EDC4AF0C0E39BFAFC9DE66A657C6FA389CA30D8080231.jpg +32FCEA65A04EEF4C14862B3124957C3CA5DB87DE047A8DD78BA3357D30005726.jpg +D8B46F10EBF02FD8E59A2F5BCF5C307CA9EC0AFEA560CD1D8A2641CB297CD009.jpg +8E92DCAD191BF350A62321C6981EBCCB8ACF054C724B440281F753AFE53BD66A.jpg +FBDF2655755C785FCEDE86897AC0C0E3E8AD9E27CBD57573ACD71C29409AA134.mp4 +16AD6F262D9AB9D10CEE65F33209DB19C66C0724AD6755F0BBC5B92B7AA77203.jpg +1FDA937A81B4DB7CF7111D17BE76B628CFA99C8BB0F2538CA5ABE868A4A80094.jpg +F8CCA64248B4055998848A4B3C1DF1E5AF6EC372BED5591BD3CE53A11BF1F8D7.jpg +50D72584B721ED0D085163029B3CEEC4208BE60B1E44DCA6925F740A192F4897.jpg +255A63286E924A6E7659E9E934FB8D714194514941B7F2060D5E8BCEDAA876AA.jpg +EE1E40BAFFFEA03A2844EEEB0D238281E917FBC1A2A97F54D6A15D8EEEA3D1E2.jpg +F8CB7567D1245F5FABDD70DBF58D42A0A17FAB10053FEACBB1BF52EBF8059E4C.jpg +39F72690285697B9C5B697183E0C6C8D39832E1B058CBBCB5679678282C3362D.jpg +35F5A9B7038BB6CC23EF14DDAA94D2D5F5925842B075F1C64DD8C25F0AD8EC4A.jpg +B60CF82AA38A87D55CCE82BF6E0117B5F819AF3C6B7154B7F30CF9D3C00FC7B3.jpg +7516CD47C7FB07A3399F3849C27A3D4C127C6974EB89C1845523F3DB6A3F692C.jpg +70A06E501357E4B30BCDE03CF8EC1A77E986927D951699D9744398510F1AFF31.jpg +B28CBE64D116DF1F8E07650618F8C8DA06CEBB3D7FD0ADE1A484A32D6C9B96AC.jpg +D84FCB15FBACB7F3D20CBA3484D6D26DDC7D28A8B14B771FF80410AE836DFC1A.jpg +44F261E15C89AFA11A220BC12F25C41ED5079AC2C6A0CA22D8B8EC59B6C0D3A6.jpg +EAC4C5F31F6EE1946FC2A21DD85834AD98F100207D21C052210A4EDFB5738F01.jpg +39EABD33638247F3308AF819859785F105CA61C710F39D388252FB17A99C512B.jpg +5B391A2E91CB16A99072BBE4B8379BCE1A15D8386B950F734E3312EE733AAD51.jpg +27079566FE448F66731D20A7692B5FBCF7198FA1ACA0DD9E1AE6D6B198068639.jpg +D95D5B1DB86BE02376E3B47FDA2CED7D0B035D371FF88C11BF277C3130BBAE78.jpg +A074BC055692C4C2B35244070266E88188DD101EEAEB1B98DBDC1FF664458309.jpg +E85DBA213FE62D1A64B4A79AF9B3A88F555885BB018311414A2AE03B1324E729.jpg +A799DC75A22A67F33B9D925825B5CE58B6675666C844809130CCBE6439B7BC1B.jpg +BB3EB17E0353CAB01BD9096CC39B13C042048C1BFA259DB62B836E7DEEC88057.jpg +305C73D030510ABD70EE3E28AC5744D7312D2BA68DABBB0B2842F7AB7A1FD093.jpg +2FADB151DC4CA8A58C530055E96269F9C41744C48822EAE26515276E13AEBB0A.jpg +8FD3AF153E4C61C78DEF8BB33B03F8A8DA20AD3E9266ADD2B618EC4767997265.jpg +187F3EBC290BDA37921693C2787294CADF105A045F1D03F8F016723AAC5C7277.jpg +39DD1ED066C5CF6E8DB0DFC649E2CCFCADE46FBBC329A048563D0E72357E5916.jpg +38B2E813F521D4A0F67C9334CB52A9EB395D7CED69C32B34CFBF509CE2E322CE.jpg +4E0379FD368DFC9111BC75660B3B8AAA8EF14142185F9FC6C0CE37335C8CE656.jpg +6EDC9DB00BCBAE63E08A54260464133E300B5002F8D063FDD6F9DDC123FAA8BA.jpg +52FB1D94FCB6F51402BD393949C2A327FF71184802955B7A268680D70F1F8F49.jpg +E13CE1344B9EB1F8DD56CFF365467A445F43DCE202CEDE511822DE58D4FB9E51.jpg +8D4F1CCC213CAA5E7BEFC21775186FFE6F970411F34974BC6271EC8DAF19C57B.jpg +EDDD59587EDC633502C132F24DCB46A3AB1F782AA47F56E07DD477E4196DE93F.jpg +3FFF37F3B3D457790F248E415ED5BDDEF4DC032596EA327881BC57C6288C23D5.jpg +4F2D584BB3E3C3173276AF94ED08B78247CA8B467E775D1EA769C6B5DD8AA396.jpg +96EDCA46485E39CD3B6C45079EF4380BCC0A2200344F3204DDB0743FDCE99B40.jpg +80B1AEE7CEFB404D46681475E160A9C815E49D0A0CAA6F85D55B5D33A785FD58.jpg +AFC21B760920E04B8C8A7A70BF707CC3675E35334AB1FEC57B733C9DA7D01078.gif +2CF2AF394E41E6DAD025F7B0BED0D0DB08E61C1271240CC6BB46D09BDC214A9D.jpg +E7E0026CD299680AF9CD6F15681166B285ABFBA6D9AED79E184795A0C9CFC449.jpg +C3ED3290B6F1F2B20F90FC67032BDD467EAA8E251D54DC09C4528C3EFAA80620.jpg +9789CC2665DC1D6E0AFE31DAB83E0044C0815DB90B3264B721892E6E30D59A26.jpg +BEE8707D79CE5BDBBB4818C699DAE1C86053BDA47E2FB11897B1A03EA246257F.jpg +EF9BFAF9508DD5F657C851AB64BD1CD3FBA48F73EAA084A7D4629AB2063243D.jpg +BF2BEEAA099F39C525B891D307A1E89E7271A65891E1D41762C038F20643E726.jpg +870E34565AF0B6F35688659A4CE8C14646BCA122341519BF36E23C35B9170331.jpg +D23E113413E1AB022A6A1749F05ADFFC87B41756C1827F4ECAB7DE8DB1EA7780.jpg +1C2F4956BEBF9C12EE47D7B0450DE3F9D7C79DA955597D5F6DA0B87BF27A47A5.jpg +33C9F04C80C805C15A537DDDBC58FD6AA84D9247680105FD4A87824E89CCC7A8.jpg +A8C95E1761C855D6D09F02B53DF0536944ED4A24C0E3B1B53C2EB9095F7614DB.png +E623E78694ED5E655E51430AA4EDC8524D2BBD54C98B0B2ACFD24AB538277346.jpg +A7D83A04C9B4CAD41BABB0731B0CAC5E6BB58F653924A98E9EF5A93EF7DDDF66.jpg +8EF8C7B876261C6B84113E254753A72C6F99049AF3E0C4765FDB35FCB2388322.jpg +2557F49592E24D01B1C4BF1BD904A578F33A9DAAC1C3FA6E344976ABF9FDFF36.jpg +3852073B9C5E0D74BF2CAB9A637E76692E8A084BC28E87E9D8AB97B10AFCB4A8.jpg +74D08967CD7144C2798AFBF22E5B2022E91F0E94107BA285D6973F2BF9EA6E39.jpg +FC04CBCA1371C4532447F9F2BD26A631E44BCF52112F5A9D51FC61FBB0A8EA27.jpg +A8CA4A49BDBFD40805EE0CD268DC41B53C7627418C2EBF7ECB46478A0E2B0F0.jpg +31058CFD485D5C19ACE1AA109C2EE31CE71163B02CA6E6240FB22D785EFB07CD.jpg +C786D04CA9CD419766A9479E28021D59E633D5F9307890CC338263910064635E.jpg +8AC2F7C0B2ED4530D5F67D9CBC33AB396BFAC28E21AFF905ED91B35215287D7.jpg +C15D3AE6DC10295C06B986D825EA628BAFB7364F1FBE36D616D30C5B53851CB.jpg +E6E7E03EF06F922219C0B6F6549257C799EDD01FCA98BB1CF9665503661F1CA8.jpg +11FC29BDBDFCFDD0F9D892D6337B1B2207CDE99780A481F042EC590A2644F6E2.jpg +1CF04A3780E63632DFFE35D79F66CADD3E883A8CA91C9FED6188E5AE0A882A18.jpg +16731789F2CCED96B9AF7BF466228C119B467FFED5736EB69345DAECF60ED485.jpg +3BDCE548CB035E4EF2D57EDD1048286BE70A1CD9D60FBE762F72B5BB2588F32A.jpg +B6A3860F16E07FD77ACE86BC35BEB30BEE80A7F05B4F7D17314824B7F495F23A.jpg +40B66F7597ABFC83A13A8CB80CA0A8EAFB55916FBD07C3EC44CC2B915B2D8B2B.jpg +228623E5FD0DB10FB2EA5020D4FBF963FBBC3FD71259D44ECB194963054375BA.jpg +DB8443CE058A3AFE6F99B5408FA8777495AAA7F3B1AF322B0E519179C86583A1.jpg +A386ECB5CF7DC13EEEE303CB9AC559A846AA8A6F936AA83FFC8D49DD9E566147.jpg +2F0BACAD6632DCA2E83E0366E900A9218FBC40F501F7F5E11B5416A7E3361AB6.jpg +26C99F18C9129F0D106CD258F6CC75BBEA1D33DD60277F5F2E64A8855323A2A5.jpg +8910B47F9BB493A5FFE1DE4EB6D967714DFF820510C108CC9A73A92DCD77ACE7.jpg +4AC5F4598F983C018E165FD72245AA1DB9CE94CEEA466A8EF20AA53A86AE95A2.jpg +1468850355CBBD06961F085165E72C22CA2F365467208B04AFA8C306288909FD.jpg +D93DE5118FB68648E48FB59F1390F6C1F567429A0553DF3763C85AC424BD6E05.jpg +947E8622BCF0097AD0DE07BD5A5C94E9978FC49C3294A57D40B18B02810461AC.jpg +43522ECCDE9F57973BB679FF4EB9598E299FDA5AB1E7DE946C4F2485EBC6A6FD.jpg +E3B07E1D922AECA46B1C8207F7CEBE565B2A176D3890CC8B4F568F4236FC89A9.jpg +92768FDD76F9430CF4BA2ED2C51B174246E487C2466EA6550C90FAF93C3C0871.jpg +146558C08C8379B0DC6151524B9059AEDB90EF8F61470F581C60A81A15108DBC.jpg +722725B029A6E94187F2B775D68C2C1687C17574A21B2EB56F01714C1DA4158D.jpg +5C267C99A86C6B9C7954414818D9F596A67048BF201AA556AE158389659029A9.jpg +C549E541EF6052BB53E37A43EF65FC8DD0D7B1FEAE9ECB2446FAE4644813C642.swf +9471D0441A107FFA85D1FD83C852506E3941F100BC45DD3D045200A025A119B3.jpg +5CFAB98E6500A9EAF944430DB2181BE064EF32B352FCE78FA21CD5D50CF3E46D.jpg +B802AF9C54E99A1167BC5F8403A4566E3D259512F1684009D705894FD7264117.jpg +E06751095ACA2C10B8911E2CDA30232C378D107CD6337FBA3953C637EF67969D.png +BA1E37EC47C4D743A527FBC24CAC7D76C93B4BF43D771B9E61B01C3F04CC8087.jpg +B083433B71AD60D9B13589BAFABCCF27BA68509779F27EEC8E14BB5765A0436C.jpg +73A186D217E6268FF13D6ABC5F298EB70CC5E3FE3265857AB6338F83DEBFAAD3.jpg +6E61DC5D97C3A508DC90A2DD79297DD327B8DDE51249B798E14B2D09FD8826A.jpg +CE9D13863374A264AAD6CBB3EC2C5CA62098BA522A853A505992D2982F6508BB.jpg +5E1EA066877212AFB45F115284581F21913148AF0A26A0B87CD48A9077365004.jpg +13116739893B2D0BDD3E1F8834C7CF51FA2600E3E3DB8C7AF09BBBA360E918EF.jpg +56089D8982F95106F6756F8FE759685C0D3337FBB48FD3EB7E6E595181D4FB23.jpg +B4F773FBCD074ABED42E3ED773E74977BC048793DDD2B6577CCB59C3D8524E32.jpg +EEA7119D04EBE8092829FC614B82802C0C51D259855A87FE86332C8006E836A2.jpg +B9BAB34FEC5119BA8CA028E504BEDFA2262D2278D1DA10B3440E5FA374DF970F.jpg +FFEB8DA2527FAB854A6ADB502C33C349B0FB697E80FED2DD62386F575AFA22CE.jpg +85F3D51F36F097FC9EFDC55C4C200FF78CA3FC3CA6EE22D08F97B1DD909F2A11.jpg +43DA223AC443A43631B0E29B5BF9B1852D94B96017A199BB777A603AEE5EDF48.jpg +CFAE1DC0887011F718635789ACCD6F73C319BD0CB0A5511C320134D3B1A0453.jpg +40627A4C9D07ACF39C8774BF99D8F019DDD7D0F4821FFFF4D8C9C4243E1A3188.jpg +33E2F57F929936BBB96ABE3758DCE1177707155306E36C7B150BD4C6ECC871C.jpg +72FD88E6D7CC49FEE4BF2CF3382D85CEA1489518AABC7943930001618940F1EF.jpg +18D77DE114A488D2F539F53C546C935016031A50B0C3DB3C51A019648CA7EAE6.jpg +73922443B825C0E5EC4B700E5FB326A222A546201322E3F31A2819C834D57052.jpg +D6AFB1939A9EE2C1A93118E055657BB990A57DE9A33AE4A175144FA01BCB149E.jpg +D46F35433F453ED20D027FF9201E4D35094BD4FC899FE8A66CD9D124B9F5C00D.jpg +D803E7C600D685482C433B0F80B2E92ED8E941105F07BF01D8B27677F895CA5E.jpg +2783D4121771D0DDD9433E001C29A1BF848477B913C388A07260D427BA2AAE4.jpg +A9B463BFF18CD6C176C1962BA8A34C79F889CFECB5285641302615F6B4E6B6F3.jpg +73E2120086114FE30677507DB204D573086D0F75390378B3207D32B5CC4F25B4.jpg +2F084E1E6CF52843278A50952376C9BB9646D0C21137FBA9B0AE1E282933FE5.jpg +123C76256DA49CB2A46119A9105A11D61885402DD28A45C5703CE320F19B8E4F.jpg +A13B94A5E10B685DE9EEC28E3D4FFD8AC8870F990C42478EFB645706F0338121.jpg +B3AF540AD8977DF901284787CAB2911A7CBA4FBC6A133787B933B39FCE5B8E4C.jpg +F64DDB3C2CB6DF29C4F7F7EAED1CCB9A0A6AA11A5D4AD6C547BD9BE893D2F23F.jpg +EEAF10E74D859AF94BBA2EBBE3DC04BD64CFDFA038DA9B9BFA39B627B92B60AE.jpg +B821D1639BBBA6524CE5DFEECB37B0EF1D81B932B8B3FAE47A5445C92F75B720.jpg +388EDB80BD3EA4AADCAA25BCC5E90FC4CC8D9F9E9F6903D43FF3A8B68E9A9C8B.jpg +32D5A3344404F78EB666A3BADDBAAC2F3D4DD3308AE67036889974EFC27BE2A4.jpg +76B07F6D87D2D7745DB4374DA499301B6BF91AF05896918E83E91489D62166A7.jpg +91BB6FDC92AF43C64EBAA3B43FEBBF0E9A8409A172F0CBBCA47C470068B7B0CC.jpg +71A5B31B55FA1797DBDE331098C9CE37FCA5A93AAF61399EE14C77F429D3B240.jpg +E95FA78A4B8C2D5B7C7FC3B62A4A585182D0638AC227AEEEA35B0EFDEE3364ED.jpg +A8FF4257F3A65E84E1B9A4DA057E3785775620161F8C65959B813C77F22AD818.jpg +74C47561EDC0F49EEDCEA4F79FE422DA0117F7AD1A2594D543B36D50B8ABEFA8.jpg +D716E71564DE44E20E1DFA564289EEA5F464396AC19F21F389B4D2D61F748289.jpg +D4F7D6A14E4FAD740C9B90F7B1B9B36BF4E8C35D52DF9C0403A88BA9A6E01A56.jpg +513DFCD0D66EF37404804D23872E8AD06FDDBEC08568A42FDAB1E18B10124FFA.jpg +F0B98767F8665094E0DF7A7088A6ADFECC7A8C3E161981D334E0AB32D845E9F0.jpg +500E808048E0DB2408FA4D1EAE22B2E2D4660443B836F7593C8B7529701A4A9A.jpg +AFCDEA8D5A2649602E213232E12E79999D7122D84F14418C3194D976F7AA10D0.jpg +70D3E3C1EC338A78A1EFB49211751C7DA3CB6258C07E0E407B859AFD292F9A98.jpg +BAA0D1BBA063F9762F14D3952B47AABEC7E8A111DF1E1E1A0107A35C8D07BA5.jpg +B8C1FC3D5937D7DEBEEB0C0B1C7BC5C4D597D9970C4F86E4516AF92FFA955D75.jpg +3FE1585D47E51D824CC71D963AD897B64DEE090DD01A4C33634F9FCA29E29E5.jpg +1283D13D075EEC8BEF3705C712094AAA7197213CE9A768FBA3B374FEDF50861A.jpg +9324CE40F8FDF7D9FC0F36D0E84796B8F9C123886CDCF0862FDB2101F2E4BE87.mov diff --git a/prototype/log/artwork_internal_discussion_plugin.regression b/prototype/log/artwork_internal_discussion_plugin.regression new file mode 100644 index 0000000..7bb80e7 --- /dev/null +++ b/prototype/log/artwork_internal_discussion_plugin.regression @@ -0,0 +1,109 @@ +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +Dato: tor, april 27, 2006, 23:11 +Til: reaktor@deichman.no " :P "=)> +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# +# diff --git a/prototype/log/reaktoruser_artworkgroups_plugin.regression b/prototype/log/reaktoruser_artworkgroups_plugin.regression new file mode 100644 index 0000000..04a13bd --- /dev/null +++ b/prototype/log/reaktoruser_artworkgroups_plugin.regression @@ -0,0 +1,25 @@ +Created transit table: related_artwork +Entry with 2 groups, 8 uniq artworks, stored with 16 permutations +Entry with 1 groups, 5 uniq artworks, stored with 10 permutations +Entry with 1 groups, 3 uniq artworks, stored with 3 permutations +Entry with 1 groups, 2 uniq artworks, stored with 1 permutations +Entry with 1 groups, 2 uniq artworks, stored with 1 permutations +Entry with 3 groups, 7 uniq artworks, stored with 5 permutations +Entry with 1 groups, 7 uniq artworks, stored with 21 permutations +Entry with 1 groups, 12 uniq artworks, stored with 66 permutations +Entry with 1 groups, 7 uniq artworks, stored with 21 permutations +Entry with 2 groups, 4 uniq artworks, stored with 2 permutations +Entry with 3 groups, 11 uniq artworks, stored with 19 permutations +Entry with 1 groups, 24 uniq artworks, stored with 276 permutations +Entry with 7 groups, 21 uniq artworks, stored with 25 permutations +Entry with 1 groups, 2 uniq artworks, stored with 1 permutations +Entry with 2 groups, 33 uniq artworks, stored with 328 permutations +Entry with 1 groups, 2 uniq artworks, stored with 1 permutations +Entry with 1 groups, 5 uniq artworks, stored with 10 permutations +Entry with 4 groups, 73 uniq artworks, stored with 643 permutations +Entry with 14 groups, 225 uniq artworks, stored with 1997 permutations +Entry with 1 groups, 3 uniq artworks, stored with 3 permutations +Entry with 1 groups, 2 uniq artworks, stored with 1 permutations +Entry with 1 groups, 2 uniq artworks, stored with 1 permutations +Entry with 12 groups, 57 uniq artworks, stored with 166 permutations +Entry with 3 groups, 53 uniq artworks, stored with 444 permutations diff --git a/prototype/log/reaktoruser_image_plugin.regression b/prototype/log/reaktoruser_image_plugin.regression new file mode 100644 index 0000000..52d2476 --- /dev/null +++ b/prototype/log/reaktoruser_image_plugin.regression @@ -0,0 +1,87 @@ +B5BC21A5080EF168C94CB76F6A5953303D5224A57661D3D1FFBEACA650E2C4F3.jpg +8AD0BC7FC76E68E7B611F55B4C8DCC25372159B5163D191C7808096D809A1B5A.jpg +C67C02B2F83D598AA9624A50A90067112233A5C8D5944C82C09075DCE1737630.jpg +61AF7CDCFA863B6973815007AAD0B9CA8064DC7309847B1FE6B67C2243E05094.jpg +4AA6CE90D68A17F86678AF2D45AD07004C19F4E524B3176497237C138925401D.jpg +1A8205D147481A76E1F2C592D73AB3A7564C7AD68242E69909A9F65160AFD32B.jpg +1A8205D147481A76E1F2C592D73AB3A7564C7AD68242E69909A9F65160AFD32B.jpg +EAA3A9F06846679AE6F1D9F42E6C962A5B857D15E2BBD13056182E98D9DA81CA.jpg +5F0772A13A83D7EB6E7FAF6C139087A590A9E9C3127F9718641513C8CEE07837.jpg +8E168C85DAB22A41B5003AAB58D69B59DA1099B68EAC9FF750077283CDC1AE3B.jpg +8423BCD2E82DEE0ED19DBF90370626CF57C103A08766B466D9875454E7C91CCE.jpg +28ECB911BDDE84D1648F843E61F7645AFC2541729B62ED5FB5E975A8A4B550FA.gif +C7A1FA4D39966FD2CDB16C2E2E7BD4BB776C9C4CD3CD4686A5FBE9869DDBFC20.jpg +C7620AC9F04E7D53E114F52927E91A8BC42A00464AFE1C6ACCABA2D0BAD35470.jpg +B83A53415B566103679BD62C2009743F445FB279E8800636E260B8FDBDF0F681.jpg +ED190B947962F4D531BD9E336ED57BC4EDD38C63D9968E5A0F0E7BF9A547FE25.jpg +46664BE4BFBE6C4C84FFFAA78CD449D74642EE6E7DD02F9B9DBC25C273399124.jpg +10CD4B54530D51685245AFD7F426D4A97EE05DC7D242BFA2B258A5BDE9A8F05F.jpg +349BC34D7A6C2E2A0AD2E368CBDE2D4A34F45A93F60608433F9A5F5566ADAC1D.jpg +90293BBB72F80D4B4149CED4AF97A89AEE71C5EB35DE46386D5725496F6515FC.gif +80AA86EA195D1EB394F0B0E6E8FD2A0B8C3A09ECCDF7994E569E471EFD80980D.gif +62FCA56E7937434F0CE756682140FA2D48790F27DDC324623F52B1DE4D9E9290.gif +61AF7CDCFA863B6973815007AAD0B9CA8064DC7309847B1FE6B67C2243E05094.jpg +18766DE12C0C00C6D996F8C5213DC1C21CA654DD490C20F14D9B2EC355AB27C1.jpg +838B987E57558BEFB76845A5EE79514719E466190038D3FCC74BA83F6D9F0714.jpg +1753A3498C6A571165B091D04870CF71E17FD1C8B37ECE1EFAB73FBCA0F8AF63.jpg +118E473B2F7237B6F14E4A4F9B4BE6B25B08541381FAE6BD78AC5D847350D67A.gif +D0BA09A3DC6EBA18EEAD078DC45643F48541C2087FFDBFF0B96E48DAFE3BF259.jpg +DAAF55B8FB2C1D7AF19308E194A2924B09982BB117483D87390E192E2D288FF2.jpg +FF9B411178F96C9D90D9D56912477E32356BC523590D5AD03F2956D200A803C0.gif +6B451DEF5D16B4AC69280A91CE2329AD5BD67019FE0FB06EC2CAF7BFDC8A6276.jpg +DE87C9D4E2D0CC74F0E91A011BF5D59B59E5C79AAFF96E3DBD5B9B4B5928996F.jpg +E03DA92171687CD9A4FE4C80DBD7B945B096A6BA927EB0728D50BC8B64DF3339.jpg +9BB5BA7A879178B74F10A949B64272047AE11B7654E58A4B64D7222552AB2AB4.jpg +1F6B9A2AA7F566428829E155A7895F205391904E661F119B73E79C20BD98BAEB.gif +1BF22D8FC8B1504AD7802FB7DD9F623BD14159C555B9AF60FAFA8FC1E989EE3D.jpg +8B2E1B67757CBEB0EB74770F409901CE78BBE21CCC08E8E2C8AD3C99362F2B94.jpg +28363C10CFB05CC63641503DB69B741871A4064A97ADC0A5B1E740AE9A8ACAE9.jpg +13D07EB2E814D93402E4B251D1CD43A0C2F7E4CE9A0F9798F5EE9DB3B94FED7C.jpg +A60B123DE222F9073777FF6676DFF2F62ECBC8E2780A9109F57D803C66D6F358.jpg +D65B0C5C46BC88A0EDF3453C9983E106E81D1082EEF745EBA58A588CA398DEEE.jpg +C5FE6151FECC520339285E2DEF904E6C361B4AC3A84DA8BEB6BCE74A61694C48.jpg +75BB4AEC2F44C925D172F4A21A0C0245B1A6A362A3437935F91407C386AB5E7C.jpg +A67BF1C5380AE4B1F316ABDD8197C6D86CD95FD922AA459130ACDE3C3101334C.jpg +2D9EF6B4A1881CE1F7A4D37EF6E8CE7268AD124601BEEF8867BC154C0CF9EB46.jpg +680E034373B75846D6EBF9146F210474B38358E69572E273E3DA07953C08971.jpg +FCAA7F1539B2170CF0332685E42F74B6C2355F78B26D7260B5EDEABB72433EEA.jpg +4947221D78D715251624FF38B113E84F1E090E6E127BC4DA3D88BA060377D95.jpg +915446D23390245BB2B74E39EEBA8FEE7F575F29B4E9B35B00D2ECB8E312F46B.jpg +FE44798E62452E9EA06940DAEBD8520A8BE5D760081CA1BCD1598F72ADA4ECA0.jpg +F282C6585EEDC2DC41A0F41D7DAF6F47FDBD7716758ACDCD3162EF955AA7DE52.jpg +CAAE5B47AC89FB6013CD1B481A830014ADB8D241A118289FA877C403C9D0B0E5.jpg +65AB17EDD089D79D0F16F62DF9CF7840B02066511CF9BF108568D7450466191B.jpg +2328B5DE161DFC2205BA76DB1C1CB1256F7F796B0053133F9CFEB698A6432A68.jpg +C9E594CDFD67576A36AD735D445654D38BDA4EAF387C830ACCF476E7688DDCFF.jpg +B72CD7121464687FFAD0525BEEDA25E2A5D581DE572B54FFFAADD9477AAF57B4.jpg +27467DBA233B6896B531C87FF13D0808FB4F07FECE71041177B7B0F70869061D.jpg +5FAF731F9407B285368A50BD8CBEC7FAEC1DE969DD4202CCBB5F43BAC7F0A761.jpg +4E8216802BF555D6EB96B61D3809F49F9E7F1D185A38A834104D3E83DE97AC6.jpg +B39DCE3DE32C5C089EE740E0C147229769B31846091F9BDCAA32199C064F73C7.jpg +711BA82794B972F039C154C591EDE9A9C8AC908C81438F279DDCC700D4ABFE9A.jpg +9999D4EFC6B173E0DB09CB786FB5596928337BDC6E1430A13BEFD0A7B7F99688.jpg +5903CF40F856F670303839C28A3A8D0E7E6E61C52FBDB7FE65153756874ED9B9.gif +82D5D6142C71CA428B796AE6128969963DD5E21CF59BC91EB5E432B394301FCC.jpg +E0573B68A5F83C621DC7DA606FBFA2603FC71C5F22B9E9EEEC02D0C21E55ECCC.jpg +ADD318A8985409340E9D2EB504320A4F2D15DC950D5D0744EC1CC7FCD7367195.jpg +DA961B0C04F730D781EBD9CDFB286761902F97629D6601C43B68BA15377BD7BE.jpg +5EEC629079BED438F5D6B44559667476F1C286EE20386B3EB3BDC0245B0C6B26.jpg +58BD9A4BA4DC792D7C253297C7BEB0D26DC919630D24289CC5F14FF84CD10694.jpg +9BC36E16ED0C763A5A915F48F5EA6178426F631C997BEC06DBC53891F88206F9.jpg +3353286A37853C2A580C9D457E4F2BCE5BE1E1BE8ABD0A2F129C95CB2BD77A06.jpg +ECBE48B9D931E7FBEAE604F3698E3CD92483BEA0C28079AB94499398D9ECA803.jpg +F5BFE3B6828FD571F4B9EDDCBCD282FBDF80B6E660BC0CB27B5E1B30173EB76C.jpg +91816FF38F2DC8DFC38A8E390FC95222728884374D775674F697085C029EB5B5.jpg +91816FF38F2DC8DFC38A8E390FC95222728884374D775674F697085C029EB5B5.jpg +23BF4378E0090D76E309453F92E7AF72887B210557B1175AF458AD2469EEFAB1.jpg +FFDC59629DECA2FFB3CC441B6F09A1A08C07CF0D421C94D14DC1462649EC946B.jpg +4C428C9DD7347CB50525519953D9E51411F5F4C64BB7C5508CD1A8C83CDA1F52.gif +69C586E0C079119E16FA800771B0F5954E2386C912B7CBDB97869BC2E0D30EC0.jpg +69C586E0C079119E16FA800771B0F5954E2386C912B7CBDB97869BC2E0D30EC0.jpg +191DC77CE8F2CE06BE070E50F97C0CD8BE575A4D1D696BCC00CF48C38BCE1540.jpg +191DC77CE8F2CE06BE070E50F97C0CD8BE575A4D1D696BCC00CF48C38BCE1540.jpg +A9F9C7AE4E006C637335B3E5FEB27E3FC857418FDE89126F3C20F655C9D29206.jpg +9520008975C9D7978996096AA8727D6B27C8725D57328B3BDEEB65C8EFB3791D.jpg +D9BBF85773CED704CD1BE6AA414C4E24A4EA92FD872A515D17B395A495340040.jpg +83BA1F697A35DB05442D052250749B5C1F492A82F9A785E6EBA01425244C6ECA.jpg +2F790479349B616A5F9D8CC24FBD248ED60BE903ADE4FE69E47A5BF51A227719.jpg diff --git a/prototype/log/reaktoruser_type_plugin.regression b/prototype/log/reaktoruser_type_plugin.regression new file mode 100644 index 0000000..8608e27 --- /dev/null +++ b/prototype/log/reaktoruser_type_plugin.regression @@ -0,0 +1,551 @@ +Created transit table: sf_guard_user_group +Saved relation 13645, 2 +Saved relation 10978, 2 +Saved relation 2693, 2 +Saved relation 7605, 2 +Saved relation 1348, 2 +Saved relation 7488, 2 +Saved relation 2956, 2 +Saved relation 13648, 2 +Saved relation 2971, 2 +Saved relation 6984, 2 +Saved relation 2963, 2 +Saved relation 10997, 2 +Saved relation 13665, 2 +Saved relation 3027, 2 +Saved relation 7542, 2 +Saved relation 1422, 2 +Saved relation 3019, 2 +Saved relation 11038, 2 +Saved relation 3030, 2 +Saved relation 1953, 2 +Saved relation 11047, 2 +Saved relation 2030, 2 +Saved relation 1583, 2 +Saved relation 1832, 2 +Saved relation 3119, 2 +Saved relation 1733, 2 +Saved relation 3123, 2 +Saved relation 704, 2 +Saved relation 3126, 2 +Saved relation 11071, 2 +Saved relation 5926, 2 +Saved relation 13682, 2 +Saved relation 3129, 2 +Saved relation 12794, 2 +Saved relation 13568, 2 +Saved relation 12826, 2 +Saved relation 3133, 2 +Saved relation 3149, 2 +Saved relation 11058, 2 +Saved relation 13729, 2 +Saved relation 13741, 2 +Saved relation 11137, 2 +Saved relation 8001, 2 +Saved relation 13744, 2 +Saved relation 13747, 2 +Saved relation 13824, 2 +Saved relation 11170, 2 +Saved relation 13827, 2 +Saved relation 10700, 2 +Saved relation 7527, 2 +Saved relation 8259, 2 +Saved relation 13843, 2 +Saved relation 8271, 2 +Saved relation 13846, 2 +Saved relation 13859, 2 +Saved relation 8351, 2 +Saved relation 13862, 2 +Saved relation 4332, 2 +Saved relation 8358, 2 +Saved relation 8400, 2 +Saved relation 6859, 2 +Saved relation 1231, 2 +Saved relation 8472, 2 +Saved relation 4437, 2 +Saved relation 8679, 2 +Saved relation 3283, 2 +Saved relation 7339, 2 +Saved relation 4454, 2 +Saved relation 4329, 3 +Saved relation 8716, 2 +Saved relation 3152, 2 +Saved relation 8722, 2 +Saved relation 3328, 2 +Saved relation 3331, 2 +Saved relation 3379, 2 +Saved relation 3394, 2 +Saved relation 725, 2 +Saved relation 3464, 2 +Saved relation 8778, 3 +Saved relation 8776, 3 +Saved relation 1571, 2 +Saved relation 3723, 2 +Saved relation 178, 2 +Saved relation 4681, 3 +Saved relation 1784, 2 +Saved relation 3727, 2 +Saved relation 4483, 2 +Saved relation 3733, 2 +Saved relation 4351, 2 +Saved relation 4792, 3 +Saved relation 3737, 2 +Saved relation 1826, 2 +Saved relation 3741, 2 +Saved relation 3746, 2 +Saved relation 3961, 3 +Saved relation 3963, 3 +Saved relation 47, 2 +Saved relation 2377, 3 +Saved relation 4082, 2 +Saved relation 5328, 2 +Saved relation 5341, 2 +Saved relation 1889, 2 +Saved relation 5414, 2 +Saved relation 5464, 2 +Saved relation 5496, 2 +Saved relation 5528, 2 +Saved relation 5532, 2 +Saved relation 5540, 2 +Saved relation 5537, 2 +Saved relation 5544, 2 +Saved relation 5549, 2 +Saved relation 5559, 2 +Saved relation 5584, 2 +Saved relation 11315, 2 +Saved relation 5588, 2 +Saved relation 394, 3 +Saved relation 165, 1 +Saved relation 222, 2 +Saved relation 1141, 2 +Saved relation 1148, 2 +Saved relation 1247, 2 +Saved relation 1375, 2 +Saved relation 1414, 2 +Saved relation 284, 2 +Saved relation 1723, 2 +Saved relation 2211, 2 +Saved relation 170, 3 +Saved relation 1640, 2 +Saved relation 1574, 2 +Saved relation 1773, 2 +Saved relation 1823, 2 +Saved relation 1781, 2 +Saved relation 1871, 2 +Saved relation 1875, 2 +Saved relation 1886, 2 +Saved relation 2192, 3 +Saved relation 1963, 2 +Saved relation 2009, 2 +Saved relation 2006, 2 +Saved relation 2037, 2 +Saved relation 2121, 2 +Saved relation 2203, 2 +Saved relation 2188, 3 +Saved relation 2190, 3 +Saved relation 5594, 2 +Saved relation 11321, 2 +Saved relation 5620, 2 +Saved relation 5630, 2 +Saved relation 5641, 2 +Saved relation 5657, 1 +Saved relation 7617, 2 +Saved relation 11348, 2 +Saved relation 2309, 2 +Saved relation 5663, 2 +Saved relation 11358, 2 +Saved relation 5, 3 +Saved relation 2371, 2 +Saved relation 3, 1 +Saved relation 2375, 3 +Saved relation 11390, 2 +Saved relation 11397, 2 +Saved relation 11447, 2 +Saved relation 11452, 2 +Saved relation 10993, 2 +Saved relation 5682, 2 +Saved relation 11461, 2 +Saved relation 5676, 2 +Saved relation 11504, 2 +Saved relation 5723, 2 +Saved relation 5750, 2 +Saved relation 5766, 2 +Saved relation 11510, 2 +Saved relation 11527, 2 +Saved relation 5817, 2 +Saved relation 5826, 2 +Saved relation 5839, 2 +Saved relation 5859, 2 +Saved relation 559, 2 +Saved relation 11574, 2 +Saved relation 5878, 2 +Saved relation 1262, 2 +Saved relation 173, 1 +Saved relation 167, 3 +Saved relation 5887, 2 +Saved relation 5908, 2 +Saved relation 5913, 2 +Saved relation 5934, 2 +Saved relation 251, 2 +Saved relation 2458, 2 +Saved relation 2470, 2 +Saved relation 5951, 2 +Saved relation 2129, 2 +Saved relation 5956, 2 +Saved relation 11613, 2 +Saved relation 2194, 3 +Saved relation 2626, 3 +Saved relation 8924, 2 +Saved relation 5969, 2 +Saved relation 2651, 2 +Saved relation 5810, 2 +Saved relation 2672, 2 +Saved relation 11636, 2 +Saved relation 11644, 2 +Saved relation 9009, 2 +Saved relation 2669, 2 +Saved relation 2662, 2 +Saved relation 2677, 2 +Saved relation 2666, 2 +Saved relation 9028, 2 +Saved relation 11680, 2 +Saved relation 2686, 2 +Saved relation 11653, 2 +Saved relation 6010, 2 +Saved relation 11687, 2 +Saved relation 6049, 2 +Saved relation 6054, 2 +Saved relation 11692, 2 +Saved relation 11698, 2 +Saved relation 9077, 2 +Saved relation 9086, 2 +Saved relation 11717, 2 +Saved relation 11476, 2 +Saved relation 9183, 2 +Saved relation 11703, 2 +Saved relation 6076, 2 +Saved relation 9293, 2 +Saved relation 11736, 2 +Saved relation 8930, 2 +Saved relation 6120, 2 +Saved relation 9346, 2 +Saved relation 9361, 2 +Saved relation 9513, 2 +Saved relation 11747, 2 +Saved relation 9515, 2 +Saved relation 11751, 2 +Saved relation 6125, 2 +Saved relation 11797, 2 +Saved relation 11803, 2 +Saved relation 11810, 2 +Saved relation 11825, 2 +Saved relation 6211, 2 +Saved relation 11831, 2 +Saved relation 6224, 2 +Saved relation 6232, 2 +Saved relation 11836, 2 +Saved relation 6246, 2 +Saved relation 6260, 2 +Saved relation 11873, 2 +Saved relation 6263, 2 +Saved relation 6266, 2 +Saved relation 11884, 2 +Saved relation 6272, 2 +Saved relation 11895, 2 +Saved relation 6281, 2 +Saved relation 6277, 2 +Saved relation 6295, 2 +Saved relation 10800, 2 +Saved relation 6304, 2 +Saved relation 6290, 2 +Saved relation 6280, 2 +Saved relation 6249, 2 +Saved relation 6319, 2 +Saved relation 11958, 2 +Saved relation 6311, 2 +Saved relation 6287, 2 +Saved relation 11973, 2 +Saved relation 6253, 2 +Saved relation 6299, 2 +Saved relation 4136, 2 +Saved relation 6369, 2 +Saved relation 12027, 2 +Saved relation 12032, 2 +Saved relation 6380, 2 +Saved relation 9557, 2 +Saved relation 5352, 2 +Saved relation 9585, 2 +Saved relation 6399, 2 +Saved relation 9590, 2 +Saved relation 6394, 2 +Saved relation 12046, 2 +Saved relation 6414, 2 +Saved relation 6432, 2 +Saved relation 6490, 2 +Saved relation 6500, 2 +Saved relation 3181, 2 +Saved relation 12064, 2 +Saved relation 6639, 2 +Saved relation 12107, 2 +Saved relation 6652, 2 +Saved relation 6648, 2 +Saved relation 12128, 2 +Saved relation 12112, 2 +Saved relation 6642, 2 +Saved relation 2483, 2 +Saved relation 6658, 2 +Saved relation 12154, 2 +Saved relation 6667, 2 +Saved relation 9721, 2 +Saved relation 12159, 2 +Saved relation 6686, 2 +Saved relation 12165, 2 +Saved relation 12176, 2 +Saved relation 6703, 2 +Saved relation 12182, 2 +Saved relation 12185, 2 +Saved relation 6714, 2 +Saved relation 12196, 2 +Saved relation 11533, 2 +Saved relation 8948, 2 +Saved relation 12206, 2 +Saved relation 10017, 2 +Saved relation 5504, 2 +Saved relation 12213, 2 +Saved relation 10069, 2 +Saved relation 12239, 2 +Saved relation 10081, 2 +Saved relation 10087, 2 +Saved relation 6337, 2 +Saved relation 6917, 2 +Saved relation 6316, 2 +Saved relation 6941, 2 +Saved relation 6947, 2 +Saved relation 10223, 2 +Saved relation 6958, 2 +Saved relation 6779, 2 +Saved relation 10245, 2 +Saved relation 10399, 2 +Saved relation 6973, 2 +Saved relation 7043, 2 +Saved relation 6963, 2 +Saved relation 7057, 2 +Saved relation 7060, 2 +Saved relation 7066, 2 +Saved relation 7072, 2 +Saved relation 7054, 2 +Saved relation 7077, 2 +Saved relation 7080, 2 +Saved relation 7168, 2 +Saved relation 7176, 2 +Saved relation 7181, 2 +Saved relation 7200, 2 +Saved relation 7207, 2 +Saved relation 7210, 2 +Saved relation 7231, 2 +Saved relation 7218, 2 +Saved relation 7238, 2 +Saved relation 7225, 2 +Saved relation 7222, 2 +Saved relation 7249, 2 +Saved relation 7254, 2 +Saved relation 7257, 2 +Saved relation 7269, 2 +Saved relation 7264, 2 +Saved relation 7274, 2 +Saved relation 7215, 2 +Saved relation 7280, 2 +Saved relation 7283, 2 +Saved relation 7296, 2 +Saved relation 7301, 2 +Saved relation 7306, 2 +Saved relation 7317, 2 +Saved relation 7327, 2 +Saved relation 7330, 2 +Saved relation 7372, 2 +Saved relation 6059, 2 +Saved relation 7420, 2 +Saved relation 7447, 2 +Saved relation 7455, 2 +Saved relation 7472, 2 +Saved relation 7562, 2 +Saved relation 7585, 2 +Saved relation 6711, 2 +Saved relation 10420, 2 +Saved relation 10425, 2 +Saved relation 2982, 2 +Saved relation 10466, 2 +Saved relation 1921, 2 +Saved relation 10458, 2 +Saved relation 10507, 2 +Saved relation 10512, 2 +Saved relation 10521, 2 +Saved relation 10532, 2 +Saved relation 10552, 2 +Saved relation 10560, 2 +Saved relation 10472, 2 +Saved relation 10571, 2 +Saved relation 10592, 2 +Saved relation 10646, 2 +Saved relation 10661, 2 +Saved relation 10666, 2 +Saved relation 12264, 2 +Saved relation 10671, 2 +Saved relation 12579, 2 +Saved relation 12591, 2 +Saved relation 10677, 2 +Saved relation 12613, 2 +Saved relation 10694, 2 +Saved relation 12023, 2 +Saved relation 12648, 3 +Saved relation 12712, 2 +Saved relation 10728, 2 +Saved relation 10742, 2 +Saved relation 12720, 2 +Saved relation 12735, 2 +Saved relation 10745, 2 +Saved relation 10766, 2 +Saved relation 10770, 2 +Saved relation 10777, 2 +Saved relation 10784, 2 +Saved relation 10795, 2 +Saved relation 10809, 2 +Saved relation 10821, 3 +Saved relation 10861, 2 +Saved relation 10875, 2 +Saved relation 6013, 2 +Saved relation 10904, 2 +Saved relation 10918, 2 +Saved relation 10921, 2 +Saved relation 10915, 2 +Saved relation 10930, 2 +Saved relation 10949, 2 +Saved relation 10968, 2 +Saved relation 12832, 2 +Saved relation 12836, 2 +Saved relation 262, 2 +Saved relation 12886, 2 +Saved relation 12889, 2 +Saved relation 12906, 2 +Saved relation 12917, 2 +Saved relation 12920, 2 +Saved relation 12927, 2 +Saved relation 12953, 2 +Saved relation 12963, 2 +Saved relation 12984, 2 +Saved relation 12993, 2 +Saved relation 12998, 2 +Saved relation 13001, 2 +Saved relation 13007, 2 +Saved relation 13016, 2 +Saved relation 13048, 3 +Saved relation 13029, 2 +Saved relation 13054, 3 +Saved relation 12903, 3 +Saved relation 12979, 2 +Saved relation 13198, 2 +Saved relation 12901, 3 +Saved relation 13224, 2 +Saved relation 13259, 2 +Saved relation 12967, 2 +Saved relation 13256, 2 +Saved relation 13135, 2 +Saved relation 13329, 2 +Saved relation 13173, 2 +Saved relation 13426, 2 +Saved relation 13446, 2 +Saved relation 13454, 2 +Saved relation 13465, 2 +Saved relation 13143, 2 +Saved relation 13474, 2 +Saved relation 13477, 2 +Saved relation 13510, 2 +Saved relation 13485, 2 +Saved relation 13517, 2 +Saved relation 13530, 2 +Saved relation 13535, 2 +Saved relation 13565, 2 +Saved relation 13575, 2 +Saved relation 13583, 2 +Saved relation 13556, 2 +Saved relation 13617, 2 +Saved relation 13620, 2 +Saved relation 13865, 2 +Saved relation 13868, 2 +Saved relation 13871, 2 +Saved relation 13875, 2 +Saved relation 13878, 2 +Saved relation 13881, 2 +Saved relation 13884, 2 +Saved relation 13887, 2 +Saved relation 13890, 2 +Saved relation 13932, 2 +Saved relation 13939, 2 +Saved relation 13943, 2 +Saved relation 13946, 2 +Saved relation 13949, 2 +Saved relation 13952, 2 +Saved relation 13956, 2 +Saved relation 13960, 2 +Saved relation 13963, 2 +Saved relation 13976, 2 +Saved relation 13979, 2 +Saved relation 13982, 2 +Saved relation 13985, 2 +Saved relation 14095, 2 +Saved relation 14105, 2 +Saved relation 14112, 2 +Saved relation 14115, 2 +Saved relation 14118, 2 +Saved relation 14121, 2 +Saved relation 14125, 2 +Saved relation 14128, 2 +Saved relation 14139, 2 +Saved relation 14142, 2 +Saved relation 14145, 2 +Saved relation 14148, 2 +Saved relation 14158, 2 +Saved relation 14161, 2 +Saved relation 14167, 2 +Saved relation 14171, 2 +Saved relation 14174, 2 +Saved relation 14177, 2 +Saved relation 14180, 2 +Saved relation 14183, 2 +Saved relation 14186, 2 +Saved relation 1949, 2 +Saved relation 14212, 2 +Saved relation 14216, 2 +Saved relation 1713, 3 +Saved relation 14263, 2 +Saved relation 14281, 2 +Saved relation 14284, 2 +Saved relation 14318, 2 +Saved relation 14341, 2 +Saved relation 14349, 2 +Saved relation 14346, 2 +Saved relation 14295, 3 +Saved relation 14354, 3 +Saved relation 14356, 3 +Saved relation 14361, 3 +Saved relation 14387, 2 +Saved relation 7289, 2 +Saved relation 14482, 2 +Saved relation 14532, 2 +Saved relation 14538, 2 +Saved relation 14543, 2 +Saved relation 14562, 1 +Saved relation 14564, 3 +Saved relation 14570, 2 +Saved relation 13895, 2 +Saved relation 14577, 2 +Saved relation 14653, 2 +Saved relation 5671, 2 +Saved relation 14819, 2 +Saved relation 14828, 2 +Saved relation 14838, 2 +Saved relation 14841, 2 +Saved relation 14847, 2 +Saved relation 14850, 2 +Saved relation 15107, 2 +Saved relation 13439, 2 diff --git a/prototype/plugins/artwork_data_plugin.rb b/prototype/plugins/artwork_data_plugin.rb new file mode 100644 index 0000000..256d236 --- /dev/null +++ b/prototype/plugins/artwork_data_plugin.rb @@ -0,0 +1,538 @@ +#!/usr/bin/env ruby +# +# = Synopsis +# +# Scans the data filed of the artwork table +# The constant @@data_path must be set or the plugin will fail +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# + +require 'digest/md5' + +class ArtworkDataPlugin < Plugin + + attr :reaktor_data + attr :reaktor_rows + + @@totals = { + :parsed => 0, # Total number of artwork rows parsed + :scanned => 0, # Total number of artwork data scanned (no nil datas) + :matched => 0, # Total number of data with matches + :files => 0, # Total number of files + :file_size => 0, # Total size of files + :t_textdata => 0, # Total number of text data marked with T + :nil_textdata => 0, # Total number of text data marked with NIL + :unmatched => 0, # Total number of unmatched rows + :textfiles => 0, # Total number of text data files created + :screenshots => 0, # Total number of screenshot files to be moved + } + @@report_name = 'report' + @@log_name = 'artwork_data_plugin' + @@data_path = nil + + def self.log_name + @@log_name + end + + def self.set_data_path(path) + @@data_path = path + end + + def initialize(attr_name, row) + if @@data_path.nil? + STDERR.puts "# Error in #{__FILE__} on line #{__LINE__}. See errorlog." + Log.write_log(:error, "Required data path has not been set.") + exit + end + @attr_name = attr_name + @row = row + @id = row['id'].to_s + @data = row['data'] + @screenshot = row['screenshot'] + @reaktor_rows = [] + @old_table = 'artwork' + @file_order = 0 + + process + end + + # + # Returns the list of ReaktorRow objects + # + def each + @reaktor_rows + end + + # + # Process record + # Return: List of ReactorRow objects + # + def process + + @@totals[:parsed] += 1 + return nil unless @data + + @@totals[:scanned] += 1 + um = @@totals[:matched] + + user_id = @row['creator'] + uploaded_at = get_uploaded_at(@id) + modified_at = get_modified_at(@id) + + thumbnails = scan_for_files(@screenshot) + thumbnail_used = nil + + ########################################################################## + # Media files + ########################################################################## + scan_for_files(@data).each do |file| + @file_order += 1 + mimetype_id = get_mimetype_id(file[:mime_type], file[:file_name]) + identifier = get_identifier(file[:mime_type]) + + begin + reaktor_file_id = IdStore.new(file[:file_name], user_id) + rescue + Log.write_log('warning', "Could not create new IdStore object for (#{file[:file_name]}, #{user_id}). Message: #{$!}. File will not get processed!") + next + end + + file[:title] = @row['title'] unless file[:title] + + # + # Change extension for audio and video files + # + realpath = file[:file_name] + reg_ext = /\.\w+$/ + case + when identifier == 'video' + realpath = file[:file_name].gsub(reg_ext, '.flv') + when identifier == 'audio' + realpath = file[:file_name].gsub(reg_ext, '.mp3') + end + @reaktor_rows << ReaktorRow.new( + :reaktor_file, + [ + ReaktorColumn.new({:name => :filename, :value => file[:file_name]}), + ReaktorColumn.new({:name => :user_id, :value => user_id}), + ReaktorColumn.new({:name => :realpath, :value => realpath}), + ReaktorColumn.new({:name => :thumbpath, :value => ''}), + ReaktorColumn.new({:name => :originalpath, :value => file[:file_name]}), + ReaktorColumn.new({:name => :original_mimetype_id, :value => mimetype_id}), + ReaktorColumn.new({:name => :converted_mimetype_id,:value => mimetype_id}), + ReaktorColumn.new({:name => :thumbnail_mimetype_id,:value => mimetype_id}), + ReaktorColumn.new({:name => :uploaded_at, :value => uploaded_at}), + ReaktorColumn.new({:name => :modified_at, :value => modified_at}), + #ReaktorColumn.new({:name => :reported_at, :value => '1970-01-01 00:00:00'}), + ReaktorColumn.new({:name => :reported, :value => 0}), + ReaktorColumn.new({:name => :total_reported_ever, :value => 0}), + ReaktorColumn.new({:name => :marked_unsuitable, :value => 0}), + ReaktorColumn.new({:name => :under_discussion, :value => 0}), + ReaktorColumn.new({:name => :identifier, :value => identifier.to_s}), + ReaktorColumn.new({:name => :deleted, :value => 0}), + ], reaktor_file_id + ) + @@totals[:matched] += 1 + @@totals[:files] += 1 + @@totals[:file_size] += file[:file_size] + Log::write_log(@@log_name, "#{file[:file_name]}") + + @reaktor_rows << ReaktorRow.new( + :file_metadata, + [ + ReaktorColumn.new(:name => :file, :value => reaktor_file_id), + ReaktorColumn.new(:name => :meta_element, :value => 'description'), + ReaktorColumn.new(:name => :meta_qualifier, :value => 'creation'), + ReaktorColumn.new( + :name => :meta_value, + :value => @row[:howto], + :filters => [ + Filter.parse_richtext_simple, + Filter.default_if_null(''), + ] + ), + ] + ) + + # + # File title + # + @reaktor_rows << ReaktorRow.new( + :file_metadata, + [ + ReaktorColumn.new(:name => :file, :value => reaktor_file_id), + ReaktorColumn.new(:name => :meta_element, :value => 'title'), + ReaktorColumn.new(:name => :meta_qualifier, :value => ''), + ReaktorColumn.new({ + :name => :meta_value, + :value => file[:title], + }), + ] + ) if file[:title] + + @reaktor_rows << ReaktorRow.new( + :file_metadata, + [ + ReaktorColumn.new(:name => :file, :value => reaktor_file_id), + ReaktorColumn.new(:name => :meta_element, :value => 'relation'), + ReaktorColumn.new(:name => :meta_qualifier, :value => 'references'), + ReaktorColumn.new( + :name => :meta_value, + :value => @row[:howto], + :filters => [ + Filter.parse_richtext_simple, + Filter.default_if_null(''), + ] + ), + ] + ) + + # + # Lincense data + # + @reaktor_rows << ReaktorRow.new( + :file_metadata, + [ + ReaktorColumn.new(:name => :file, :value => reaktor_file_id), + ReaktorColumn.new(:name => :meta_element, :value => 'license'), + ReaktorColumn.new(:name => :meta_qualifier, :value => ''), + ReaktorColumn.new( + :name => :meta_value, + :value => @row[:rights], + :filters => [ + Filter.apply_map($domain_maps[:artwork__rights]), + ] + ), + ] + ) + + @reaktor_rows << ReaktorRow.new( + :reaktor_artwork_file, + [ + ReaktorColumn.new(:name => :artwork_id, :value => @id), + ReaktorColumn.new(:name => :file_id, :value => reaktor_file_id), + ReaktorColumn.new(:name => :file_order, :value => @file_order), + ] + ) + end + + ########################################################################## + # Teksts marked with T + ########################################################################## + scan_for_t_files(@id, @data).each do |file_name| + unless thumbnails + thumbnail_filename = '' + thumbnail_mime_type_id = 2 + else + thumbnail_filename = thumbnails[0][:file_name] + thumbnail_mime_type_id = get_mimetype_id(thumbnails[0][:mime_type], thumbnails[0][:file_name]) + thumbnail_used = true + end + + begin + reaktor_tfile_id = IdStore.new(file_name, user_id) + rescue + Log.write_log('warning', "Could not create new IdStore object for (#{file_name}, #{user_id}). Message: #{$!}. File will not get processed!") + next + end + + @reaktor_rows << ReaktorRow.new( + :reaktor_file, + [ + ReaktorColumn.new(:name => :filename, :value => file_name), + ReaktorColumn.new(:name => :user_id, :value => user_id), + ReaktorColumn.new(:name => :realpath, :value => file_name), + ReaktorColumn.new(:name => :thumbpath, :value => thumbnail_filename), + ReaktorColumn.new(:name => :originalpath, :value => file_name), + ReaktorColumn.new(:name => :original_mimetype_id, :value => 9), # text/plain + ReaktorColumn.new(:name => :converted_mimetype_id,:value => 9), # text/plain + ReaktorColumn.new(:name => :thumbnail_mimetype_id,:value => thumbnail_mime_type_id), + ReaktorColumn.new(:name => :uploaded_at, :value => uploaded_at), + ReaktorColumn.new(:name => :modified_at, :value => modified_at), + #ReaktorColumn.new(:name => :reported_at, :value => '1970-01-01 00:00:00'), + ReaktorColumn.new(:name => :reported, :value => 0), + ReaktorColumn.new(:name => :total_reported_ever, :value => 0), + ReaktorColumn.new(:name => :marked_unsuitable, :value => 0), + ReaktorColumn.new(:name => :under_discussion, :value => 0), + ReaktorColumn.new(:name => :identifier, :value => 'text'), + ReaktorColumn.new(:name => :deleted, :value => 0), + ],reaktor_tfile_id + ) + + # TODO: Verify this! + @reaktor_rows << ReaktorRow.new( + :reaktor_artwork_file, + [ + ReaktorColumn.new({:name => :artwork_id, :value => @id}), + ReaktorColumn.new({:name => :file_id, :value => reaktor_tfile_id}), + ] + ) + + @@totals[:textfiles] += 1 + @@totals[:matched] += 1 + @@totals[:t_textdata] += 1 + end + + ########################################################################## + # Teksts marked with NIL + ########################################################################## + scan_for_nil_files(@id, @data).each do |file_name| + unless thumbnails + thumbnail_filename = '' + thumbnail_mime_type_id = 2 + else + thumbnail_filename = thumbnails[0][:file_name] + thumbnail_mime_type_id = get_mimetype_id(thumbnails[0][:mime_type], thumbnails[0][:file_name]) + end + + begin + reaktor_nilfile_id = IdStore.new(file_name, user_id) + rescue + Log.write_log('warning', "Could not create new IdStore object for (#{file_name}, #{user_id}). Message: #{$!}. File will not get processed!") + next + end + + @reaktor_rows << ReaktorRow.new( + :reaktor_file, + [ + ReaktorColumn.new(:name => :filename, :value => file_name), + ReaktorColumn.new(:name => :user_id, :value => user_id), + ReaktorColumn.new(:name => :realpath, :value => file_name), + ReaktorColumn.new(:name => :thumbpath, :value => thumbnail_filename), + ReaktorColumn.new(:name => :originalpath, :value => file_name), + ReaktorColumn.new(:name => :original_mimetype_id, :value => 9), # text/plain + ReaktorColumn.new(:name => :converted_mimetype_id,:value => 9), # text/plain + ReaktorColumn.new(:name => :thumbnail_mimetype_id,:value => thumbnail_mime_type_id), + ReaktorColumn.new(:name => :uploaded_at, :value => uploaded_at), + ReaktorColumn.new(:name => :modified_at, :value => modified_at), + #ReaktorColumn.new(:name => :reported_at, :value => '1970-01-01 00:00:00'), + ReaktorColumn.new(:name => :reported, :value => 0), + ReaktorColumn.new(:name => :total_reported_ever, :value => 0), + ReaktorColumn.new(:name => :marked_unsuitable, :value => 0), + ReaktorColumn.new(:name => :under_discussion, :value => 0), + ReaktorColumn.new(:name => :identifier, :value => 'text'), + ReaktorColumn.new(:name => :deleted, :value => 0), + ],reaktor_nilfile_id + ) + + @reaktor_rows << ReaktorRow.new( + :reaktor_artwork_file, + [ + ReaktorColumn.new({:name => :artwork_id, :value => @id}), + ReaktorColumn.new({:name => :file_id, :value => reaktor_nilfile_id}), + ] + ) + + @@totals[:textfiles] += 1 + @@totals[:matched] += 1 + @@totals[:nil_textdata] += 1 + end + + if thumbnail_used + @@totals[:screenshots] += 1 + @@totals[:files] += 1 + @@totals[:file_size] += thumbnails[0][:file_size] + Log::write_log(@@log_name, "#{thumbnails[0][:file_name]}") + end + @@totals[:unmatched] += 1 if um == @@totals[:matched] + end + + # + # Scan data for artwork-files + # => data: Textual data contained in the screenshot or data column + # <= A list of hashes + # + def scan_for_files(data) + return nil unless data + + ret = [] + data.scan(/("([^"]+)".*?)?#\.\([^f]*(file::([^\s]+))*[^"]*"([^"]*)"\s*(:filesize\s*(\d+))*/m).each do |m| + # + # Set column values + # + file = { + :title => nil, + :mime_type => 'no-type', + :file_name => 'no-filename', + :file_size => 0, + } + file[:title] = m[1] if m[1] + file[:mime_type] = m[3] if m[3] + file[:file_name] = m[4] if m[4] + file[:file_size] = m[6].to_i if m[6] + ret << file + end + return ret + end + + # + # Scan data column for texts marked (T + # Each occurence of a text is stored in a file + # <= Returns a list of filenames of the created text files + # + def scan_for_t_files(artwork_id, data) + files = [] + data.scan(/\(T \. \("(.*)"\)\)/mu).each do |text| + d = text[0] + d.gsub!(/"\s+"/, '') + d.gsub!(/"\s*:P\s*"/, "\n\n" ) + digest = Digest::MD5.hexdigest(artwork_id) + file_name = "#{digest}.txt" + File.open(File.join(@@data_path, file_name), 'w') do |file| + file.puts(d) + end + files << file_name + end + return files + end + + # + # Scan data column for texts marked (NIL + # Each occurence of a text is stored in a file + # <= Returns a list of filenames of the created text files + # + def scan_for_nil_files(artwork_id, data) + files = [] + data.scan(/\(NIL \. "(.*)"\)/mu).each do |text| + digest = Digest::MD5.hexdigest(artwork_id) + file_name = "#{digest}.txt" + File.open(File.join(@@data_path, file_name), 'w') do |file| + file.puts(text[0]) + end + files << file_name + end + return files + end + + # + # Get the file_mimetype::id from a prototype mime-type and file extension + # + def get_mimetype_id(mime_type, file_name = nil) + if reaktor_file_mime_type = $domain_maps[:artwork__mime_type] + reaktor_file_mime_type = $domain_maps[:artwork__mime_type][mime_type] + else + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log::write_log('error', "Could not determine mime-type from #{mime_type}") + exit + end + if reaktor_file_mime_type.kind_of?(Hash) + reaktor_file_mime_type = reaktor_file_mime_type[file_name[/[^\.]+$/]] + end + if reaktor_file_mime_type.nil? + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log::write_log('error', "No reaktor mime-type found for #{mime_type}") + exit + end + query = %Q{ + SELECT id + FROM file_mimetype + WHERE mimetype = '#{reaktor_file_mime_type}' + } + unless mimetype_id = $dbh_ms.execute(query).fetch + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log::write_log('error', "Could not get file_mimetype id from mime-type: #{reaktor_file_mime_type}") + exit + end + return mimetype_id + end + + # + # Get corresponding identtifier to a mime-type + # Input: A string describing the mime-type + # Output: A string describing the identifier + # + def get_identifier(mime_type) + query = "SELECT identifier FROM file_mimetype WHERE mimetype = '#{mime_type}'" + if id = $dbh_ms.execute(query).fetch + identifier = id[0] + elsif identifier = $domain_maps[:artwork__mime_type_to_identifier][mime_type] + else + identifier = 'no-identifier' + Log::write_log('error', "Could not find identifier for the mime-type #{mime_type}") + end + return identifier.to_s + end + + # + # Get sf_guard_user::id mapped to reaktoruser::id through KeyMap + # => reaktoruser_id: reaktoruser id + # <= sf_guard_user id + # + def get_user_id(reaktoruser_id) + user_id = KeyMap::get_new_primary_key(:reaktoruser, {:id => reaktoruser_id}) + if user_id.nil? + KeyMap::print_all + user_id = {:sf_guard_user => {:id => 0}} + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log::write_log('error', "Was not able to retrive new id of reaktoruser #{reaktoruser_id}.") + end + return user_id[:sf_guard_user][:id] + end + + # + # Get timestamp string from changelog on this artwork data + # + def get_uploaded_at(artwork_id) + query = %Q{ + SELECT timestamp + FROM changelog + WHERE object_type = 'artwork' + AND action = ':CREATE' + AND object = #{artwork_id} + } + if ts = $dbh_pg.execute(query).fetch + uploaded_at = ts[0].to_s + else + uploaded_at = '1970-01-01 00:00:00' + end + return uploaded_at + end + + # + # Get timestamp string from changelog when this artwork was changed + # + def get_modified_at(artwork_id) + query = %Q{ + SELECT timestamp + FROM changelog + WHERE object_type = 'artwork' + AND action = ':EDIT' + AND object = #{artwork_id} + } + if ts = $dbh_pg.execute(query).fetch + modified_at = ts[0].to_s + else + modified_at = '1970-01-01 00:00:00' + end + return modified_at + end + + def self.flush_logs + Log.flush_log(@@report_name) + Log.flush_log(@@log_name) + end + + def self.write_report + Log::write_log(@@report_name, "ArtworkDataPlugin:") + Log::write_log(@@report_name, "\t#{@@totals[:parsed]} number of artworks parsed") + Log::write_log(@@report_name, "\t#{@@totals[:scanned]} number of artwork data scanned") + Log::write_log(@@report_name, "\t#{@@totals[:matched]} number of matches") + Log::write_log(@@report_name, "\t#{@@totals[:files]} number of files (#{@@totals[:file_size] / 1024 / 1024} MB) to move") + Log::write_log(@@report_name, "\t#{@@totals[:t_textdata]} number of text data (marked T)") + Log::write_log(@@report_name, "\t#{@@totals[:nil_textdata]} number of text data (marked NIL)") + Log::write_log(@@report_name, "\t#{@@totals[:t_textdata] + @@totals[:nil_textdata]} total number of text data matches") + Log::write_log(@@report_name, "\t#{@@totals[:matched] - (@@totals[:files] + @@totals[:t_textdata] + @@totals[:nil_textdata] - @@totals[:screenshots])} number of unhandled matches") + Log::write_log(@@report_name, "\t#{@@totals[:unmatched]} number of unmatched rows") + Log::write_log(@@report_name, "\t#{@@totals[:textfiles]} number of text files created") + Log::write_log(@@report_name, "\t#{@@totals[:screenshots]} number of screenshots") + Log::write_log(@@report_name, "\tList of artwork files to move is saved to #{@@log_name}") + end +end + diff --git a/prototype/plugins/artwork_internal_discussion_plugin.rb b/prototype/plugins/artwork_internal_discussion_plugin.rb new file mode 100644 index 0000000..9998380 --- /dev/null +++ b/prototype/plugins/artwork_internal_discussion_plugin.rb @@ -0,0 +1,164 @@ +# +# = Synopsis +# +# Artwork internal_discussion plugin +# Handles data from the artwork tables internal_discussion column +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# + +class ArtworkInternalDiscussionPlugin < Plugin + + attr :reaktor_data + attr :reaktor_rows + + @@totals = { + :parsed => 0, # Total number of artwork rows parsed + :scanned => 0, # Total number of artwork data scanned (no nil datas) + :matched => 0, # Total number of records with matches + :comments => 0, # Total number of comments found + :unmatched => 0, # Total number of unmatched records + } + @@report_name = 'report' + @@log_name = 'artwork_internal_discussion_plugin' + @@seconds_1900_1970 = 2208988800 + + def self.log_name + @@log_name + end + + def initialize(attr_name, row) + @attr_name = attr_name + @row = row + @data = row[attr_name] + @artwork_id = row[:id] + @reaktor_rows = [] + process + end + + # + # Returns the list of ReaktorRow objects + # + def each + @reaktor_rows + end + + # + # Process the data + def process + + @@totals[:parsed] += 1 + return nil unless @data + return nil if @data.empty? + + @@totals[:scanned] += 1 + comments = @@totals[:comments] + + scan.each do |comment| + @reaktor_rows << ReaktorRow.new( + :sf_comment, + [ + ReaktorColumn.new(:name => :commentable_model, :value => "ReaktorArtwork"), + ReaktorColumn.new(:name => :commentable_id, :value => @artwork_id), + ReaktorColumn.new(:name => :namespace, :value => "administrator"), + ReaktorColumn.new(:name => :text, :value => comment[:text].to_s), + ReaktorColumn.new(:name => :author_id, :value => get_user_id(comment[:reaktoruser_id])), + ReaktorColumn.new(:name => :created_at, :value => get_datetime(convert_timestamp(comment[:timestamp]))), + ReaktorColumn.new(:name => :title, :value => ''), + ] + ) + @@totals[:comments] += 1 + end + if @row[:under_discussion] + @reaktor_rows << ReaktorRow.new( + :history, + [ + ReaktorColumn.new({ + :name => :action_id, + :value => 8, + }), + ReaktorColumn.new({ + :name => :user_id, + :value => 1, + }), + ReaktorColumn.new({ + :name => :object_id, + :value =>@artwork_id, + }) + ] + ) + end + if @@totals[:comments] > comments + @@totals[:matched] += 1 # Record with matches + else + @@totals[:unmatched] =+ 1 # Unmatched record + end + end + + # + # Get the date on format: yyyy-mm-dd hh:mm:ss from timestamp + def get_datetime(timestamp) + t = Time.at(timestamp) + "%d-%d-%d %d:%d:%d" % [t.year, t.month, t.day, t.hour, t.min, t.sec] + end + + # + # Get the new user id from IdStore + # => reaktoruser_id: user id from reaktoruser record + # + def get_user_id(reaktoruser_id) + IdStore.get(:reaktoruser, reaktoruser_id) + end + + # + # Scans the data from the internal_discussion record column + # <= A list of comment occurenses + # + def scan + return nil unless @data + + comments = [] + + @data.scan(/(\d+)\s+(\d+)[^']+'[^']+'\(([^\)]+)/m).each do |m| + comments << { + :reaktoruser_id => m[0], + :timestamp => m[1], + :text => m[2], + # TODO:title ? + } + Log.write_log(@@log_name, "#") + end + return comments + end + + # + # Convert from timestamp with epoch 1900-01-01 to timestamp + # with epoch 1970-01-01 + # => Timestamp with epoch 1900-01-01 + # <= Timestamp with epoch 1970-01-01 + # + def convert_timestamp(ts) + return ts.to_i - @@seconds_1900_1970 + end + + def self.flush_logs + Log.flush_log(@@report_name) + Log.flush_log(@@log_name) + end + + def self.write_report + Log::write_log(@@report_name, "ArtworkInternalDiscussionPlugin") + Log::write_log(@@report_name, "\t#{@@totals[:parsed]} number of artworks parsed") + Log::write_log(@@report_name, "\t#{@@totals[:scanned]} number of artwork internal_discussion scanned") + Log::write_log(@@report_name, "\t#{@@totals[:matched]} number of records with matches") + Log::write_log(@@report_name, "\t#{@@totals[:comments]} number of comments found") + Log::write_log(@@report_name, "\t#{@@totals[:unmatched]} number of unmatched records") + Log::write_log(@@report_name, "\tA log of all comments are saved to #{@@log_name}") + end +end diff --git a/prototype/plugins/artwork_topic_tagging_plugin.rb b/prototype/plugins/artwork_topic_tagging_plugin.rb new file mode 100644 index 0000000..84d09e6 --- /dev/null +++ b/prototype/plugins/artwork_topic_tagging_plugin.rb @@ -0,0 +1,163 @@ +# +# Create relations between artwork files and tagging +# +# = Default values +# * taggable_model: ReaktorFile +# * parent_approved: 1 +# * parent_user_id: 0 +# + + +class ArtworkTopicTaggingPlugin < Plugin + + @@totals = { + :parsed => 0, # Total number of artwork_topics rows parsed + :no_files => 0, # Total number of tagged artworks that has no files + :tagging => 0, # Total number of tagging records created + :max_files => 0, # Max number of files ascosiated with an artwork + :artwork => 0, # Total number of artworks tagged + } + @@report_name = 'report' + @@log_name = 'artwork_topic_tagging_plugin' + + # + # Input: attribute name of the value we are reading and a dbi result set + # from the artwork_topic table + # + def initialize(attr_name, row) + @attr_name = attr_name + @row = row + @artwork_id = row['artwork'] + @topic_id = row['topic'] + @reaktor_rows = [] + @@totals[:parsed] += 1 + import_taggin_for_artwork(@artwork_id, @topic_id) + import_tagging_for_artwork_files(@artwork_id, @topic_id) + end + + # + # Returns the list of ReaktorRow objects + # + def each + @reaktor_rows + end + + # + # Import tagging for artwork files + # Input: artwork id and topic id + # + def import_tagging_for_artwork_files(artwork_id, topic_id) + + query = %Q{ + SELECT r.file_id, a.user_id + FROM reaktor_artwork_file AS r + LEFT OUTER JOIN reaktor_artwork AS a ON r.artwork_id = a.id + WHERE r.artwork_id = #{artwork_id} + } + sth = $dbh_ms.execute(query) + if sth.nil? + @@totals[:no_files] += 1 + else + files = 0 # Number of files tagged + sth.each do |r| + insert_tagging(topic_id, 'ReaktorFile', r[0], 1, r[1]) + files += 1 + end + @@totals[:max_files] = files if files > @@totals[:max_files] + end + end + + # + # Import tagging records based on artwork_id and topic_id + # + def import_taggin_for_artwork(artwork_id, topic_id) + if user_id = get_user_id_from_artwork(artwork_id) + insert_tagging(topic_id, 'ReaktorArtwork', artwork_id, 1, user_id) + @@totals[:artwork] += 1 + parent_id = topic_id + while parent_id = get_parent_from_topic_id(parent_id) + insert_tagging(parent_id, 'ReaktorArtwork', artwork_id, 1, user_id) + @@totals[:artwork] += 1 + end + end + end + + # + # Get parent id from topic id + # Input: topic id + # Output: parents topic id or nil if not present + # + def get_parent_from_topic_id(topic_id) + query = %Q{ + SELECT parent + FROM topic + WHERE id = #{topic_id} + } + begin + sth = $dbh_pg.execute(query) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not get parent from topic id. Message: #{$!}. Query: #{query}") + raise + exit + end + return sth.fetch[0] + end + + # + # Insert record into tagging + # + def insert_tagging(tag_id, taggable_model, taggable_id, parent_approved, parent_user_id) + @@totals[:tagging] += 1 + @reaktor_rows << ReaktorRow.new( + :tagging, + [ + ReaktorColumn.new({:name => :tag_id, :value => tag_id}), + ReaktorColumn.new({:name => :taggable_model, :value => taggable_model,}), + ReaktorColumn.new({:name => :taggable_id, :value => taggable_id,}), + ReaktorColumn.new({:name => :parent_approved, :value => parent_approved,}), + ReaktorColumn.new({:name => :parent_user_id, :value => parent_user_id,}), + ] + ) + Log.write_log(@@log_name, "#{@reaktor_rows.last.inspect}") + end + + # + # Get user id from artwork + # + def get_user_id_from_artwork(artwork_id) + # + # Get user id + # + query = %Q{ + SELECT creator + FROM artwork + WHERE id = #{artwork_id} + } + begin + sth = $dbh_pg.execute(query) + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not get creator from artwork. Message: #{$!}. Query: #{query}") + raise + exit + end + return nil if sth.nil? + return sth.fetch[0] + end + + def self.flush_logs + Log.flush_log(@@report_name) + Log.flush_log(@@log_name) + end + + def self.write_report + Log::write_log(@@report_name, "ArtworkTopicTaggingPlugin:") + Log::write_log(@@report_name, "\t#{@@totals[:parsed]} number of artwork_topics parsed") + Log::write_log(@@report_name, "\t#{@@totals[:no_files]} number of artwork that had no files") + Log::write_log(@@report_name, "\t#{@@totals[:tagging]} number of tagging records created") + Log::write_log(@@report_name, "\t#{@@totals[:artwork]} number of artworks tagged") + Log::write_log(@@report_name, "\tMaximum number of files tagged by one artwork_topic relation: #{@@totals[:max_files]}") + Log::write_log(@@report_name, "\tList of all created tags is saved to #{@@log_name}") + end +end diff --git a/prototype/plugins/plugin.rb b/prototype/plugins/plugin.rb new file mode 100644 index 0000000..79ac231 --- /dev/null +++ b/prototype/plugins/plugin.rb @@ -0,0 +1,8 @@ + +# Plugin super class + +class Plugin + def initialize + + end +end diff --git a/prototype/plugins/reaktoruser_artworkgroups_plugin.rb b/prototype/plugins/reaktoruser_artworkgroups_plugin.rb new file mode 100644 index 0000000..c100742 --- /dev/null +++ b/prototype/plugins/reaktoruser_artworkgroups_plugin.rb @@ -0,0 +1,120 @@ +# +# = Synopsis +# +# Reaktoruser artwork_groups plugin +# This plugin reads data from reaktoruser::artwork_groups and writes all +# permutations for the artworkgroups described by serialized lisp to +# the related_artwork table +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# + +class ReaktoruserArtworkgroupsPlugin + + @@totals = { + :permutations => 0, # Total number of permutations + :groups => 0, # Total number of detected groups + } + @@table_name = 'related_artwork' + @@log_name = 'reaktoruser_artworkgroups_plugin' + @@report_name = 'report' + + def self.log_name + @@log_name + end + + def initialize(attr_name, row) + @reaktor_rows = [] + @user_id = row['id'] + parse_data(row[attr_name]) unless row.nil? + end + + def get_result + @reaktor_rows + end + + def each + @reaktor_rows + end + + # + # Parse data entry + # => data: data from artwork_groups column in reaktoruser table + # + def parse_data(data) + return nil if data.nil? + return nil if data.empty? + return nil if data =~ /NIL/ + + num_groups = 0; + num_artworks = 0 + permutations = 0 + data.scan(%r{(\(([^\(\)]*)\))+}).each do |g| + num_groups += 1 + group = g[1].scan(/\d+/) + group.each do |a1| + num_artworks += 1 + group.each do |a2| + unless a1.to_i == a2.to_i or permutation_exists(a1.to_i, a2.to_i) + permutations += 1 + @reaktor_rows << ReaktorRow.new( + :related_artwork, + [ + ReaktorColumn.new({:name => :first_artwork, :value => a1.to_i}), + ReaktorColumn.new({:name => :second_artwork, :value => a2.to_i}), + ReaktorColumn.new({:name => :created_at, :value => '1970-01-01'}), + ReaktorColumn.new({:name => :created_by, :value => @user_id}), + ] + ) + end + end + end + end + @@totals[:groups] += num_groups + @@totals[:permutations] += permutations + Log.write_log(@@log_name, "Entry with #{num_groups} groups, #{num_artworks} uniq artworks, stored with #{permutations} permutations ") + return [num_groups, num_artworks, permutations] + end + + # + # Check if a permutation allready exists + # Takes two artwork ids + # + def permutation_exists(id1, id2) + query = %Q{ + SELECT * from #{@@table_name} + WHERE + (first_artwork = #{id1} AND second_artwork = #{id2}) + OR + (first_artwork = #{id2} AND second_artwork = #{id1}) + } + begin + tables = $dbh_ms.execute(query).fetch + rescue + $stderr.puts "### Error in #{__FILE__} on line #{__LINE__}. See errorlog" + Log.write_log('error', "Could not check for permutations from table #{@@table_name}. Message: #{$!}.") + raise + exit + end + return true if tables + return nil + end + + def self.flush_logs + Log.flush_log(@@log_name) + Log.flush_log(@@report_name) + end + + def self.write_report + Log.write_log(@@report_name, "ReaktoruserArtworkgroupsPlugin:") + Log.write_log(@@report_name, "\t#{@@totals[:permutations]} total number of permutations saved") + Log.write_log(@@report_name, "\t#{@@totals[:groups]} total number of grops detected") + Log.flush_log(@@report_name) + end +end diff --git a/prototype/plugins/reaktoruser_image_plugin.rb b/prototype/plugins/reaktoruser_image_plugin.rb new file mode 100644 index 0000000..8ad08fc --- /dev/null +++ b/prototype/plugins/reaktoruser_image_plugin.rb @@ -0,0 +1,91 @@ +# +# = Synopsis +# +# Reaktoruser image plugin +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id: $ +# + +class ReaktoruserImagePlugin < Plugin + + attr_reader :report_name + + @@totals = { + :parsed => 0, # Total number of rows parsed + :files => 0, # Total number of files + :file_size => 0, # Total size of files + } + @@log_name = 'reaktoruser_image_plugin' + @@report_name = 'report' + + def self.report_name + @@report_name + end + + def self.log_name + @@log_name + end + + def initialize(attr_name, row) + return if row.nil? + @@totals[:parsed] += 1 + @result_column = IGNORE + file = get_filename(row[attr_name]) + unless file.nil? + Log.write_log(@@log_name, "#{file[:file_name]}") + @@totals[:files] += 1 + @@totals[:file_size] += file[:file_size] + @result_column = [ReaktorColumn.new({:name => :avatar, :value => file[:file_name]}),] + end + end + + # + # Return the resulting ReaktorColumn object or IGNORE object + # + def each + @result_column + end + + # + # Get the first filename from the image column + # => data: Data from the image column + # + def get_filename(data) + return nil unless data + + data.scan(/#\.\([^f]*(file::([^\s]+))*[^"]*"([^"]*)"\s*(:filesize\s*(\d+))*/m).each do |m| + # + # Set column values + # + file = { + :mime_type => 'no-type', + :file_name => 'no-filename', + :file_size => 0, + } + file[:mime_type] = m[1] if m[1] + file[:file_name] = m[2] if m[2] + file[:file_size] = m[4].to_i if m[4] + return file + end + return nil + end + + def self.flush_logs + Log.flush_log(@@log_name) + Log.flush_log(@@report_name) + end + + def self.write_report(report = @@report_name) + Log.write_log(report, "ReaktoruserImagePlugin:") + Log.write_log(report, "\t#{@@totals[:parsed]} number of image columns parsed") + Log.write_log(report, "\t#{@@totals[:files]} number of images files (%.2f MB) to move" % (@@totals[:file_size] / 1024 / 1024.0)) + Log.write_log(report, "\tList of avatars to move is saved to #{@@log_name}.log") + end + +end diff --git a/prototype/plugins/reaktoruser_site_plugin.rb b/prototype/plugins/reaktoruser_site_plugin.rb new file mode 100644 index 0000000..dd8a607 --- /dev/null +++ b/prototype/plugins/reaktoruser_site_plugin.rb @@ -0,0 +1,83 @@ +# +# = Synopsis +# +# Reaktoruser site plugin +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# + +class ReaktoruserSitePlugin < Plugin + @@totals = { + :saved => 0, # Total number of rows parsed + } + @@table_name = :sf_guard_user_group + @@log_name = :reaktoruser_site_plugin + @@report_name = 'report' + + def self.report_name + @@report_name + end + + def self.log_name + @@log_name + end + + # + # Create transit table + # + def self.create_db_table + unless $dbh_pg.execute("SELECT relname FROM pg_class WHERE relname = '#{@@table_name}'").fetch + query = %Q{ + CREATE TABLE #{@@table_name} ( + user_id integer NOT NULL, + group_id integer NOT NULL + )} + $dbh_pg.execute(query) + Log.write_log(@@log_name, "Created transit table: #{@@table_name}") + end + end + + # + # Drop transit table + # + def self.drop_db_table + if $dbh_pg.execute("SELECT relname FROM pg_class WHERE relname = '#{@@table_name}'").fetch + $dbh_pg.execute("DROP TABLE #{@@table_name}") + Log.write_log(@@log_name, "Dropped transit table: #{@@table_name}") + end + end + + attr_reader :result + + def initialize(attr_name, row) + return [] unless row[attr_name] + ReaktoruserSitePlugin.create_db_table + query = %Q{INSERT INTO #{@@table_name} (user_id, group_id) VALUES (?, ?)} + sf_guard_group_id = IdStore.get('site', row[attr_name]) + $dbh_pg.prepare(query).execute(row['id'], sf_guard_group_id) + Log.write_log(@@log_name, "Saved relation #{row['id']}, #{sf_guard_group_id}") + @@totals[:saved] += 1 + end + + def each + IGNORE + end + + def self.flush_logs + Log.flush_log(@@report_name) + Log.flush_log(@@log_name) + end + + def self.write_report + Log.write_log(@@report_name, "ReaktoruserSitePlugin:") + Log.write_log(@@report_name, "\t#{@@totals[:saved]} total number of saved group relations") + Log.write_log(@@report_name, "\trelations saved to postreSQL table: #{@@table_name}") + Log.flush_log(@@report_name) + end +end diff --git a/prototype/plugins/reaktoruser_type_plugin.rb b/prototype/plugins/reaktoruser_type_plugin.rb new file mode 100644 index 0000000..eb86193 --- /dev/null +++ b/prototype/plugins/reaktoruser_type_plugin.rb @@ -0,0 +1,97 @@ +# +# = Synopsis +# +# Reaktoruser type plugin +# +# = Author +# +# - Robert Strind mailto:robert@linpro.no +# +# = Version +# +# $Id:$ +# + +class ReaktoruserTypePlugin < Plugin + + @@totals = { + :saved => 0, # Total number of rows parsed + } + @@table_name = :sf_guard_user_group + @@log_name = :reaktoruser_type_plugin + @@report_name = 'report' + + def self.report_name + @@report_name + end + + def self.log_name + @@log_name + end + + # + # Create transit table + # + def self.create_db_table + unless $dbh_pg.execute("SELECT relname FROM pg_class WHERE relname = '#{@@table_name}'").fetch + query = %Q{ + CREATE TABLE #{@@table_name} ( + user_id integer NOT NULL, + group_id integer NOT NULL + )} + $dbh_pg.execute(query) + Log.write_log(@@log_name, "Created transit table: #{@@table_name}") + end + end + + # + # Drop transit table + # + def self.drop_db_table + if $dbh_pg.execute("SELECT relname FROM pg_class WHERE relname = '#{@@table_name}'").fetch + $dbh_pg.execute("DROP TABLE #{@@table_name}") + Log.write_log(@@log_name, "Dropped transit table: #{@@table_name}") + end + end + + attr_reader :result + + def initialize(attr_name, row) + ReaktoruserTypePlugin.create_db_table + query = %Q{INSERT INTO #{@@table_name} (user_id, group_id) VALUES (?, ?)} + sf_guard_group_id = get_sf_guard_group(row[attr_name]) + $dbh_pg.prepare(query).execute(row['id'], sf_guard_group_id) + Log.write_log(@@log_name, "Saved relation #{row['id']}, #{sf_guard_group_id}") + @@totals[:saved] += 1 + end + + def each + IGNORE + end + + # + # Get sf_guard_goup id from type + # * type:: String type column from reaktoruser + # + def get_sf_guard_group(type) + raise "Illegal user type" unless $domain_maps[:reaktoruser__type][type] + query = %Q{ + SELECT id + FROM sf_guard_group + WHERE name = '#{$domain_maps[:reaktoruser__type][type]}' + } + $dbh_ms.execute(query).fetch[0] + end + + def self.flush_logs + Log.flush_log(@@report_name) + Log.flush_log(@@log_name) + end + + def self.write_report + Log.write_log(@@report_name, "ReaktoruserTypePlugin:") + Log.write_log(@@report_name, "\t#{@@totals[:saved]} total number of saved group relations") + Log.write_log(@@report_name, "\trelations saved to postreSQL table: #{@@table_name}") + Log.flush_log(@@report_name) + end +end diff --git a/prototype/revert_backups.bash b/prototype/revert_backups.bash new file mode 100755 index 0000000..262700f --- /dev/null +++ b/prototype/revert_backups.bash @@ -0,0 +1,32 @@ +#!/bin/bash +# This file will revert all the backups made to symfony created by the import script + +if [ -z $1 ] +then + echo "Usage $0 /path/to/symfony" + exit +fi + +cd $1 +if [ -d content.bak ] +then + echo "Reverting content directory" + if [ -d content ]; then mv content content.imp; fi + mv content.bak content +fi + +cd config + +declare -a files +files=(databases.yml propel.ini) + +for file in ${files[@]} +do + if [ -f $file.bak ] + then + echo "Reverting $file" + if [ -f $file ]; then rm -rf $file; fi + mv $file.bak $file + fi +done + diff --git a/prototype/swop_content.bash b/prototype/swop_content.bash new file mode 100755 index 0000000..e9c2a8f --- /dev/null +++ b/prototype/swop_content.bash @@ -0,0 +1,28 @@ +#!/bin/bash +# Swap directories +# +# Author: Robert Strind +# +echo "Swoping content" + +if [ -z $1 ] +then + echo "Usage: $0 /path/to/symfony [swop_directory_name]" + exit +fi + +SWOP=$1content.bak +CONTENT=$1content +TMP=$1content.tmp + +if [ $2 ] +then + echo "Swopping $SWOP" + SWOP=$1$2 +fi + +mv $CONTENT $TMP +mv $SWOP $CONTENT +mv $TMP $SWOP +echo "Swap complete" + diff --git a/prototype/test/t_c_artwork_data_plugin.rb b/prototype/test/t_c_artwork_data_plugin.rb new file mode 100644 index 0000000..0272318 --- /dev/null +++ b/prototype/test/t_c_artwork_data_plugin.rb @@ -0,0 +1,72 @@ +# +# To change this template, choose Tools | Templates +# and open the template in the editor. + + +$:.unshift File.join(File.dirname(__FILE__),'..','plugins') +$:.unshift File.join(File.dirname(__FILE__),'..','lib') + +require 'dbi' +require 'test/unit' +require 'pp' + +require 'log' +require 'domain_maps' +require 'mapping' +require 'key_map' +require 'id_store' + +require 'plugin' +require 'artwork_data_plugin' + +# +# Test stubs +# +class ArtworkDataPlugin < Plugin + def get_user_id(id) + return id + end +end + +class KeyMap + def self.get_new_primary_key(old_table, old_pk) + return {old_table => old_pk} + end +end + +# +# Test case +# +class TC_ArtworkDataPlugin < Test::Unit::TestCase + + def setup + $dbh_pg = DBI.connect("dbi:Pg:reaktor:", "", "") unless $dbh_pg + unless $dbh_ms + $dbh_ms = DBI.connect("dbi:Mysql:reaktor_imp:", "", "") + $dbh_ms.do("SET sql_mode='TRADITIONAL,ANSI'") + $dbh_ms.do("SET NAMES 'utf8'") + end + end + + # + # Import all records from artwork table and test regression + # + def test_import + Log.remove(ArtworkDataPlugin.log_name) + + query = 'SELECT * FROM artwork' + sth = $dbh_pg.execute(query) + + while row = sth.fetch + ArtworkDataPlugin.new('data', row) + end + + ArtworkDataPlugin.flush_logs + Log.test_regression(ArtworkDataPlugin.log_name) + ArtworkDataPlugin.write_report + IdStore.write_report + end + + def teardown + end +end diff --git a/prototype/test/t_c_artwork_internal_discussion_plugin.rb b/prototype/test/t_c_artwork_internal_discussion_plugin.rb new file mode 100644 index 0000000..35673ce --- /dev/null +++ b/prototype/test/t_c_artwork_internal_discussion_plugin.rb @@ -0,0 +1,59 @@ +# +# To change this template, choose Tools | Templates +# and open the template in the editor. + + +$:.unshift File.join(File.dirname(__FILE__),'..','plugins') +$:.unshift File.join(File.dirname(__FILE__),'..','lib') + +require 'dbi' +require 'test/unit' +require 'pp' + +require 'log' +require 'domain_maps' +require 'mapping' +require 'id_store' + +require 'plugin' +require 'artwork_internal_discussion_plugin' + +class IdStore + def self.get(*args) + 1 + end +end + +class TC_ArtworkInternalDiscussionPlugin < Test::Unit::TestCase + + def setup + $dbh_pg = DBI.connect("dbi:Pg:reaktor:", "", "") unless $dbh_pg + unless $dbh_ms + $dbh_ms = DBI.connect("dbi:Mysql:reaktor_imp:", "", "") + $dbh_ms.do("SET sql_mode='TRADITIONAL,ANSI'") + $dbh_ms.do("SET NAMES 'utf8'") + end + end + + # + # Import all records from artwork table and test regression + # + def test_import + Log.remove(ArtworkInternalDiscussionPlugin.log_name) + + query = 'SELECT * FROM artwork' + sth = $dbh_pg.execute(query) + + while row = sth.fetch + ArtworkInternalDiscussionPlugin.new('internal_discussion', row) + end + + ArtworkInternalDiscussionPlugin.flush_logs + #Log.test_regression(ArtworkInternalDiscussionPlugin.log_name) TODO: regression test? + ArtworkInternalDiscussionPlugin.write_report + IdStore.write_report + end + + def teardown + end +end diff --git a/prototype/test/t_c_filter.rb b/prototype/test/t_c_filter.rb new file mode 100644 index 0000000..976e9d4 --- /dev/null +++ b/prototype/test/t_c_filter.rb @@ -0,0 +1,190 @@ +# +# To change this template, choose Tools | Templates +# and open the template in the editor. + + +$:.unshift File.join(File.dirname(__FILE__),'..','lib') + +require 'test/unit' +require 'dbi' +require 'pp' +require 'filter' +require 'log' +require 'mapping' + +class TC_Filter < Test::Unit::TestCase + + def setup + $dbh_pg = DBI.connect("dbi:Pg:reaktor:", "", "") unless $dbh_pg + unless $dbh_ms + $dbh_ms = DBI.connect("dbi:Mysql:reaktor_imp:", "", "") + $dbh_ms.do("SET sql_mode='TRADITIONAL,ANSI'") + $dbh_ms.do("SET NAMES 'utf8'") + end + end + + def test_invert + f = Filter.invert + assert_equal(f.call(nil, nil), true) + assert_equal(f.call(true, nil), false) + end + + def test_boolean_to_integer + f = Filter.boolean_to_integer + assert(f.call('t', nil) == 1) + assert(f.call('f', nil) == 0) + end + + def test_upcase + f = Filter.upcase + assert_equal('HEI', f.call('hei', nil)) + end + + def test_downcase + f = Filter.downcase + assert_equal('hei', f.call('HEI', nil)) + end + + def test_if_null + def Filter.testcase + lambda do |value, row| + return 'testcase' + end + end + f = Filter.if_null(Filter.testcase) + assert(f.call(nil, nil) == 'testcase') + assert(f.call(true, nil)) + end + + def test_set_value + f1 = Filter.set_value('testcase') + assert_equal('testcase', f1.call(nil, {'testcase' => 'Ruby'})) + f2 = Filter.set_value('%testcase') + assert_equal('Ruby', f2.call(nil, {'testcase' => 'Ruby'})) + end + + def test_add_prefix + f = Filter.add_prefix('testcase_') + assert(f.call('ruby', nil) == 'testcase_ruby') + end + + def test_add_postfix + f = Filter.add_postfix('_testcase') + assert(f.call('ruby', nil) == 'ruby_testcase') + end + + def test_truncate_from + f = Filter.truncate_from('ruby') + assert(f.call('testcase_ruby', nil) == 'testcase_') + end + + def test_override_if + f = Filter.override_if('ruby', 'testcase') + assert(f.call('robert', {'ruby' => 'is cool'}) == 'testcase') + end + + def test_default_if_null + f = Filter.default_if_null('default') + assert(f.call(nil, nil) == 'default') + assert(f.call('ruby', nil) == 'ruby') + end + + def test_domain_value_to_id + f = Filter.domain_value_to_id('sf_guard_user', 'username') + assert_equal(1, f.call('admin', nil)) + end + + def test_get_value_from_db + f = Filter.get_value_from_db($dbh_pg, 'reaktoruser', 'id', 'nick') + assert(f.call(13645, nil) == 'arneska') + end + + def test_truncate + f1 = Filter.truncate(15) + f2 = Filter.truncate(15, '') + short_string = 'robert strind' + log_string = 'robert strind robert strind' + assert_equal(short_string, f1.call(short_string, nil)) + assert_equal('robert strin...', f1.call(log_string, nil)) + assert_equal(short_string, f2.call(short_string, nil)) + assert_equal('robert strind r', f2.call(log_string, nil)) + end + + def test_apply_map + map = {:ruby => :robert} + f = Filter.apply_map(map) + assert(f.call(:ruby, nil) == :robert) + end + + def test_extract_filename + f = Filter.extract_filename + data = %q{#.(make-instance 'file::image-jpeg :filename "FD0CDDFB906081693CF628AE0E53DA85D3AF8E02E2A9A27D165381507A2C0078.jpg" :filesize 585585 :permanent T :sizex 1600 :sizey 1200)} + assert(f.call(data, nil) == 'FD0CDDFB906081693CF628AE0E53DA85D3AF8E02E2A9A27D165381507A2C0078.jpg') + end + + def test_trim_lisp_encl_params + f = Filter.trim_lisp_encl_params + data = %q{("Arrangeres det turer til dette stedet? :)")} + assert(f.call(data, nil) == 'Arrangeres det turer til dette stedet? :)') + end + + def test_parse_artwork_description + f = Filter.parse_artwork_description + data = <Ramslies bøker:\r +

    \r + " (:HREF "http://www.deich.folkebibl.no/cgi-bin/websok?ccl=Ramslie,+Lars%2ffo&st=ccl&sortering=aar" "Lån bøkene i Oslo") "
    \r + " (:HREF "http://www.trondheim.folkebibl.no/cgi-bin/websok?ccl=Ramslie,+Lars%2ffo&st=ccl&sortering=aar" "Lån bøkene i Trondheim") "\r +

    " :P "Ramslies anbefalinger:\r +

    \r + Hunter S. Thompson. Frykt og avsky i Las Vegas
    \r + " (:HREF "http://www.deich.folkebibl.no/cgi-bin/websok?mode=p&tnr=364236&st=p" "Lån boka i Oslo") "
    \r + " (:HREF "http://www.trondheim.folkebibl.no/cgi-bin/websok?mode=p&tnr=142215&st=p" "Lån boka i Trondheim") "\r +

    \r +

    \r + William Burroughs. Naken Lunsj
    \r + " (:HREF "http://www.deich.folkebibl.no/cgi-bin/websok?mode=p&tnr=193086&st=p" "Lån boka i Oslo") "
    \r + " (:HREF "http://www.trondheim.folkebibl.no/cgi-bin/websok?mode=p&tnr=105684&st=p" "\r + Lån boka i Trondheim") "\r +

    \r +

    \r + Ingvar Ambjørnsen. Jesus står i porten
    \r + " (:HREF "http://www.deich.folkebibl.no/cgi-bin/websok?mode=p&tnr=242632&st=p" "Lån boka i Oslo") "
    \r + " (:HREF "http://www.trondheim.folkebibl.no/cgi-bin/websok?mode=p&tnr=87571&st=p" "Lån boka i Trondheim") "\r +

    " :P "

    \r + Dalton Trumbo. Jonny got his gun
    \r + " (:HREF "http://www.deich.folkebibl.no/cgi-bin/websok?mode=p&tnr=219074&st=p" "Lån boka i Oslo") "
    \r + " (:HREF "http://www.trondheim.folkebibl.no/cgi-bin/websok?mode=p&tnr=19076&st=p" "Lån boka i Trondheim") "\r +

    ")) +EOF + new_data = <LitteraturnettetRamslies bøker: +

    + Lån bøkene i Oslo
    + Lån bøkene i Trondheim +

    Ramslies anbefalinger: +

    + Hunter S. Thompson. Frykt og avsky i Las Vegas
    + Lån boka i Oslo
    + Lån boka i Trondheim +

    +

    + William Burroughs. Naken Lunsj
    + Lån boka i Oslo
    + + Lån boka i Trondheim +

    +

    + Ingvar Ambjørnsen. Jesus står i porten
    + Lån boka i Oslo
    + Lån boka i Trondheim +

    + Dalton Trumbo. Jonny got his gun
    + Lån boka i Oslo
    + Lån boka i Trondheim +

    +EOF + puts f.call(data, nil) + assert(f.call(data, nil) == new_data) + end +end diff --git a/prototype/test/t_c_id_store.rb b/prototype/test/t_c_id_store.rb new file mode 100644 index 0000000..2659c63 --- /dev/null +++ b/prototype/test/t_c_id_store.rb @@ -0,0 +1,44 @@ +# +# Run tests on IdStore class +# +$:.unshift File.join(File.dirname(__FILE__),'..','lib') + +require 'test/unit' +require 'dbi' +require 'id_store' +require 'log' + +class TC_IdStore < Test::Unit::TestCase + + def setup + $dbh_pg = DBI.connect("dbi:Pg:reaktor:", "", "") unless $dbh_pg + IdStore.drop_db_table + end + + def test_store_get + data = 2800670 + robert = IdStore.new('robert', 'strind') + robert.store(data.to_s) + assert_equal(data.to_s, robert.get) + end + + def test_store_get_static + data = 2800670 + IdStore.new('robert', 'strind').store(data.to_s) + assert_equal(data.to_s, IdStore.get('robert', 'strind')) + end + + def test_store_get_datatypes + key = [:ruby, 'testcase', 280670] + data = 2800670 + IdStore.new(*key).store(data) + assert_equal(data.to_s, IdStore.get(*key)) + end + + def test_store_mixed_datatypes + key = ['280670', 280670] + data = 2800670 + IdStore.new(*key).store(data) + assert_equal(data.to_s, IdStore.get(*key.reverse)) + end +end diff --git a/prototype/test/t_c_reaktoruser_artworkgroups_plugin.rb b/prototype/test/t_c_reaktoruser_artworkgroups_plugin.rb new file mode 100644 index 0000000..6937246 --- /dev/null +++ b/prototype/test/t_c_reaktoruser_artworkgroups_plugin.rb @@ -0,0 +1,84 @@ +# +# To change this template, choose Tools | Templates +# and open the template in the editor. + + +$:.unshift File.join(File.dirname(__FILE__),'..','plugins') +$:.unshift File.join(File.dirname(__FILE__),'..','lib') + +require 'dbi' +require 'test/unit' +require 'reaktoruser_artworkgroups_plugin' + +class TC_ReaktoruserArtworkgroupsPlugin < Test::Unit::TestCase + + def setup + $dbh_pg = DBI.connect("dbi:Pg:reaktor:", "", "") unless $dbh_pg + ReaktoruserArtworkgroupsPlugin::drop_db_table + end + + def fact(n) + if n == 0 + 1 + else + n * fact(n-1) + end + end + + def calc_permutations(items) + return 0 if items < 2 + (fact(items) / fact(items - 2)) / 2 + end + + def test_import_data + Log.remove(ReaktoruserArtworkgroupsPlugin.log_name) + + query = 'SELECT * FROM reaktoruser' + sth = $dbh_pg.execute(query) + + while row = sth.fetch + ReaktoruserArtworkgroupsPlugin.new('artwork_groups', row) + end + + ReaktoruserArtworkgroupsPlugin.flush_logs + Log.test_regression(ReaktoruserArtworkgroupsPlugin.log_name) + ReaktoruserArtworkgroupsPlugin.write_report + end + + def test_permutation_exists + agp = ReaktoruserArtworkgroupsPlugin.new(:nothing, nil) + agp.save_permutation(1, 2) + assert(agp.permutation_exists(1, 2), "Wrong. Permutation 1, 2 does exist") + assert(agp.permutation_exists(2, 1), "Wrong. Permutation 2, 1 does exist") + end + + def test_parse_data + data = "((920 908 922 924 926 910 934 914 912 928 916 904 906 918 930 932) (509 391 530 525 515 507 523 511 532 517 513) (607 605 609 662 613 615 617 622 619 611) (876 862 864 866 878 872 868 874 856 858 860 870) (970 978 976 972 996 994 998 980 982 992 988 974 968 984 986 990) (3822 3818 3820 3828 3830 3826) (3834 3832 3836 3838 3840 3842 3844 3846 3848 3850 3852 3854 3856 3858 3860 3862 3864 3866 3868 3870) (3811 3759 3771 3775 3767 3785 3769 3761 3773 3783 3787 3789 3791 3793 3795 3797 3799 3801 3803 3805 38073809 4166 4168) (3940 3938 3948 3977 3952 3975 3973 3971 3954 3969 3956 3967 3958 3965) (3983 3979 3981 3987 3985 3989 3991 3993 3995 3997 3999 4001 4003 4005 4012 4014 4088 4020 4104 4090 4102 4096 4098 4094 4092 4100) (4023 4025 4027 4029 4075 4073 4071 4053 4065 4069 4067 4063 4061 4059 4055 4057 4051 4045 4047 4049 4037 4041 4043 4035 4039 4033 4031) (8854 8856 8852 8850 8848 8846 8844 8842 8840 8838 8836 8834 8831 8825 8823 8821 8819 8817 8806 8803 8801 9910) (11247 11224 11245 11243 11241 11239 1123 11235 11233 11231 11229 11227 11254 11256) (12856 12858 12854 12850 12848 12846 12852))" + attr_name = :data + row = {:data => data} + agp = ReaktoruserArtworkgroupsPlugin.new(attr_name, row) + assert_equal(14, agp.result[0], "Wrong number of groups") + assert_equal(224, agp.result[1], "Wrong number of artworks") + assert_equal(1974, agp.result[2], "Wrong number of permutations") + end + + def test_one_group + data = "((920 908 922 924 926 910 934 914 912 928 916 904 906 918 930 932))" + attr_name = :data + row = {:data => data} + agp = ReaktoruserArtworkgroupsPlugin.new(attr_name, row) + assert_equal(1, agp.result[0], "Wrong number of groups") + assert_equal(16, agp.result[1], "Wrong number of artworks") + assert_equal(calc_permutations(16), agp.result[2], "Wrong number of permutations") + end + + def test_no_group + data = "(920 908 922 924 926 910 934 914 912 928 916 904 906 918 930 932)" + attr_name = :data + row = {:data => data} + agp = ReaktoruserArtworkgroupsPlugin.new(attr_name, row) + assert_equal(1, agp.result[0], "Wrong number of groups") + assert_equal(16, agp.result[1], "Wrong number of artworks") + assert_equal(calc_permutations(16), agp.result[2], "Wrong number of permutations") + end +end diff --git a/prototype/test/t_c_reaktoruser_image_plugin.rb b/prototype/test/t_c_reaktoruser_image_plugin.rb new file mode 100644 index 0000000..8e3d689 --- /dev/null +++ b/prototype/test/t_c_reaktoruser_image_plugin.rb @@ -0,0 +1,45 @@ +# +# To change this template, choose Tools | Templates +# and open the template in the editor. + + +$:.unshift File.join(File.dirname(__FILE__),'..','plugins') +$:.unshift File.join(File.dirname(__FILE__),'..','lib') + +require 'dbi' +require 'test/unit' +require 'pp' + +require 'log' +require 'domain_maps' +require 'mapping' +require 'key_map' +require 'insert_row' + +require 'plugin' +require 'reaktoruser_image_plugin' + +class TC_ReaktoruserImagePlugin < Test::Unit::TestCase + + def setup + $dbh_pg = DBI.connect("dbi:Pg:reaktor:", "", "") unless $dbh_pg + end + + # + # Import all records from artwork table and test regression + # + def test_import + Log.remove(ReaktoruserImagePlugin.log_name) + + query = 'SELECT * FROM reaktoruser' + sth = $dbh_pg.execute(query) + + while row = sth.fetch + ReaktoruserImagePlugin.new('image', row) + end + + ReaktoruserImagePlugin.flush_logs + Log.test_regression(ReaktoruserImagePlugin.log_name) + ReaktoruserImagePlugin.write_report + end +end diff --git a/prototype/test/t_c_reaktoruser_site_plugin.rb b/prototype/test/t_c_reaktoruser_site_plugin.rb new file mode 100644 index 0000000..18f58e8 --- /dev/null +++ b/prototype/test/t_c_reaktoruser_site_plugin.rb @@ -0,0 +1,59 @@ +# +# To change this template, choose Tools | Templates +# and open the template in the editor. + + +$:.unshift File.join(File.dirname(__FILE__),'..','plugins') +$:.unshift File.join(File.dirname(__FILE__),'..','lib') + +require 'dbi' +require 'test/unit' +require 'pp' + +require 'log' +require 'domain_maps' +require 'mapping' +require 'key_map' +require 'insert_row' +require 'id_store' + +require 'plugin' +require 'reaktoruser_site_plugin' + +class TC_ReaktoruserSitePlugin < Test::Unit::TestCase + + def setup + $dbh_pg = DBI.connect("dbi:Pg:reaktor:", "", "") unless $dbh_pg + unless $dbh_ms + $dbh_ms = DBI.connect("dbi:Mysql:reaktor_imp:", "", "") + $dbh_ms.do("SET sql_mode='TRADITIONAL,ANSI'") + $dbh_ms.do("SET NAMES 'utf8'") + end + end + + # + # Import all records from artwork table and test regression + # + def test_import + ReaktoruserSitePlugin.drop_db_table + IdStore.drop_db_table + Log.remove(ReaktoruserSitePlugin.log_name) + + IdStore.new('site', '3960').store(1) + IdStore.new('site', '393').store(2) + IdStore.new('site', '4421').store(3) + IdStore.new('site', '4').store(4) + IdStore.new('site', '1397').store(5) + + query = 'SELECT * FROM reaktoruser' + sth = $dbh_pg.execute(query) + while row = sth.fetch + ReaktoruserSitePlugin.new('site', row) + end + + ReaktoruserSitePlugin.flush_logs + Log.test_regression(ReaktoruserSitePlugin.log_name) + ReaktoruserSitePlugin.write_report + IdStore.write_report + end +end diff --git a/prototype/test/t_c_reaktoruser_type_plugin.rb b/prototype/test/t_c_reaktoruser_type_plugin.rb new file mode 100644 index 0000000..3d904fe --- /dev/null +++ b/prototype/test/t_c_reaktoruser_type_plugin.rb @@ -0,0 +1,50 @@ +# +# To change this template, choose Tools | Templates +# and open the template in the editor. + + +$:.unshift File.join(File.dirname(__FILE__),'..','plugins') +$:.unshift File.join(File.dirname(__FILE__),'..','lib') + +require 'dbi' +require 'test/unit' +require 'pp' + +require 'log' +require 'domain_maps' +require 'mapping' +require 'key_map' +require 'insert_row' + +require 'plugin' +require 'reaktoruser_type_plugin' + +class TC_ReaktoruserTypePlugin < Test::Unit::TestCase + + def setup + $dbh_pg = DBI.connect("dbi:Pg:reaktor:", "", "") unless $dbh_pg + unless $dbh_ms + $dbh_ms = DBI.connect("dbi:Mysql:reaktor_imp:", "", "") + $dbh_ms.do("SET sql_mode='TRADITIONAL,ANSI'") + $dbh_ms.do("SET NAMES 'utf8'") + end + end + + # + # Import all records from artwork table and test regression + # + def test_import + ReaktoruserTypePlugin.drop_db_table + Log.remove(ReaktoruserTypePlugin.log_name) + + query = 'SELECT * FROM reaktoruser' + sth = $dbh_pg.execute(query) + while row = sth.fetch + ReaktoruserTypePlugin.new('type', row) + end + + ReaktoruserTypePlugin.flush_logs + Log.test_regression(ReaktoruserTypePlugin.log_name) + ReaktoruserTypePlugin.write_report + end +end diff --git a/symfony b/symfony new file mode 100755 index 0000000..b540da2 --- /dev/null +++ b/symfony @@ -0,0 +1,14 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +chdir(dirname(__FILE__)); +include('config/config.php'); +include($sf_symfony_data_dir.'/bin/symfony.php'); diff --git a/test-todo/bootstrap/functional.php b/test-todo/bootstrap/functional.php new file mode 100644 index 0000000..53b49ce --- /dev/null +++ b/test-todo/bootstrap/functional.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +// guess current application +if (!isset($app)) +{ + $traces = debug_backtrace(); + $caller = $traces[0]; + $array = explode(DIRECTORY_SEPARATOR, dirname($caller['file'])); + $app = array_pop($array); +} + +// define symfony constant +if (!defined('SF_ROOT_DIR')) +{ + define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/../..')); + define('SF_APP', $app); + define('SF_ENVIRONMENT', 'test'); + define('SF_DEBUG', true); +} +// initialize symfony +require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'); + +$ds = DIRECTORY_SEPARATOR; +require_once(SF_ROOT_DIR.$ds.'test'.$ds.'bin'.$ds.'reaktorTestBrowser.class.php'); +// remove all cache +sfToolkit::clearDirectory(sfConfig::get('sf_cache_dir')); + +// initialize test data +$databaseManager = new sfDatabaseManager(); +$databaseManager->initialize(); + +// Clear and load sql table structure +if (!defined("NO_CLEAR")) +{ + $dirHandle = opendir(sfConfig::get('sf_root_dir').'/data/sql'); + while ($file = readdir($dirHandle)) + { + if (substr($file, strlen($file) - 3, 3) == "sql") + { + exec("mysql -u reaktor_user --password=cT0PHPCm reaktor_test < ".sfConfig::get("sf_root_dir")."/data/sql/".$file); + } + } + + // Load the fixtures + $data = new sfPropelData(); + $data->loadData(sfConfig::get('sf_root_dir').'/data/fixtures/'); +} + +// If the magical $extract18n isset and the $i18ndata variable contains data, +// then dump it into file and import it +if (isset($extract18n) && $extract18n && strlen($i18ndata)) { + $fp = tmpfile(); + fwrite($fp, $i18ndata); + $tmp = stream_get_meta_data($fp); + system("mysql -u reaktor_user --password=cT0PHPCm reaktor_test < " . $tmp["uri"]); +} + + diff --git a/test-todo/bootstrap/unit.php b/test-todo/bootstrap/unit.php new file mode 100644 index 0000000..54387ac --- /dev/null +++ b/test-todo/bootstrap/unit.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$_test_dir = realpath(dirname(__FILE__).'/..'); +define('SF_ROOT_DIR', realpath($_test_dir.'/..')); + +// symfony directories +include(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'); + +require_once($sf_symfony_lib_dir.'/vendor/lime/lime.php'); + +include($base_dir.'/plugins/sfModelTestPlugin/bootstrap/model-unit.php'); + +class newLimeTest extends sfPropelTest +{ + + function __construct($fixturesDirOrFile = null) + { + parent::__construct($fixturesDirOrFile); + } + +} + +// initialize test data +$databaseManager = new sfDatabaseManager(); +$databaseManager->initialize(); + +// Clear and load sql table structure +if (!defined("NO_CLEAR")) +{ + $dirHandle = opendir(sfConfig::get('sf_root_dir').'/data/sql'); + while ($file = readdir($dirHandle)) + { + if (substr($file, strlen($file) - 3, 3) == "sql") + { + exec("mysql -u reaktor_user --password=cT0PHPCm reaktor_test < ".sfConfig::get("sf_root_dir")."/data/sql/".$file); + } + } + + // Load the fixtures + $data = new sfPropelData(); + $data->loadData(sfConfig::get('sf_root_dir').'/data/fixtures/'); +} + diff --git a/test-todo/tests/reaktor/003Test.php b/test-todo/tests/reaktor/003Test.php new file mode 100644 index 0000000..6aef291 --- /dev/null +++ b/test-todo/tests/reaktor/003Test.php @@ -0,0 +1,75 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); + +//check that /profile brings us to register page when not logged in +$b->get('/register'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'profile'); +$b->isRequestParameter('action', 'register'); +$b->responseContains('Register as a user'); + +$b->get('/'); +$b->setField('username', 'monkeyboy'); +$b->setField('password','monkeyboy'); +$b->click('Sign in'); + +$b->isRedirected()->followRedirect(); + +$b->responseContains('Log out'); + +// open editprofile +$b->restart(); +$b->get('/profile'); +$b->responseContains('Edit profile of monkeyboy'); + +// generate some bogus data +$bogus1 = '#¤%&/!!!'; +$bogus2 = '########'; + +// $b->restart(); +// $b->get('/profile'); +// Save "full name" and check that it's stored +$b->setField('name', 'chimp'); +$b->click('Save changes'); + +$b->isRedirected()->followRedirect(); + +$b->responseContains('chimp'); + +$b->setField('email', 'root@localhost.localdomain'); +$b->click('Save changes'); + +$b->isRedirected()->followRedirect(); + +$b->responseContains('verification email has been sent'); + +$b->click('here'); + +$b->checkResponseElement('body', '!/verification email has been sent/'); +/*$b->setField('username', $bogus1)-> + setField('password',$bogus1)-> + setField('password_repeat',$bogus2)-> + setField('email',$bogus1)-> + setField('phone',$bogus1)-> + click('save')-> + responseContains('tjall'); +*/ diff --git a/test-todo/tests/reaktor/008tagsActionsTest.php b/test-todo/tests/reaktor/008tagsActionsTest.php new file mode 100644 index 0000000..18b711d --- /dev/null +++ b/test-todo/tests/reaktor/008tagsActionsTest.php @@ -0,0 +1,53 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); + +// Check that the tags page is loaded completely +$b->get('/tags'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'tags'); +$b->isRequestParameter('action', 'index'); +$b->checkResponseElement('body', '/tagsEnd/'); + +// Check that we do not add any test tags +$b->checkResponseElement('body', '/not manipulating/'); + +// log in with "admin/admin" +// !! depends on the sfGuardUser plugin to function properly !! +$b->get('/login'); + +$b->setField('password', 'admin'); +$b->setField('username', 'admin'); +$b->click('sign in'); +// !! we should be logged in now - end depends !! + +// if we are logged in, then a test tag will be created and stored +// and then it will be removed + +// navigate to the 'tags' page again, and add test tag +$b->get('/tags/index/addtag/fu'); +$b->checkResponseElement('body', '/added/'); + +// search for the test tag and confirm that it's added +$b->get('/tags/find/tag/fu'); +$b->checkResponseElement('body', '!/None/'); + +// navigate to the 'tags' page again, and delete test tag +$b->get('/tags/index/deltag/fu'); +$b->checkResponseElement('body', '/deleted/'); \ No newline at end of file diff --git a/test-todo/tests/reaktor/016Test.php b/test-todo/tests/reaktor/016Test.php new file mode 100644 index 0000000..861df0b --- /dev/null +++ b/test-todo/tests/reaktor/016Test.php @@ -0,0 +1,46 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); + +$b->get("/tags/index"); + +$b->isStatusCode(200); +$b->isRequestParameter('module', 'tags'); +$b->isRequestParameter('action', 'index'); + +// Make sure the tag cloud is displaying, and that it is styled +$b->checkResponseElement('ul[class="tag-cloud"]', '/fred/'); +$b->checkResponseElement('big', '/bob/'); +$b->checkResponseElement('small', '/elephant/'); + +// Click the fred tag +$b->click('fred'); + +// Make sure it lists results +$b->checkResponseElement('h3', '/Files tagged with fred/'); +$b->checkResponseElement('body', '/My first nice pdf/'); +$b->checkResponseElement('body', '/My second nice image/'); diff --git a/test-todo/tests/reaktor/025permissionAdminActionsTest.php b/test-todo/tests/reaktor/025permissionAdminActionsTest.php new file mode 100644 index 0000000..2218935 --- /dev/null +++ b/test-todo/tests/reaktor/025permissionAdminActionsTest.php @@ -0,0 +1,64 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); + +//Check if functionality is protected for users not logged in +$b->get('/sfGuardPermission/list')->responseContains("You need to log in"); + +//Check if functionality is protected for logged in users without access +$b->setField('username', 'userboy')->setField('password', 'userboy')->click('sign in'); + +$b->get('/sfGuardPermission/list')->responseContains("You don't have the requested permission")->get('/logout'); + +// Log in as user with access +$b->get('/')->setField('username', 'admin')->setField('password', 'admin')->click('sign in'); + +// +//Create Permission, and check it's added to list +// +$b->get('/sfGuardPermission/create') + ->isStatusCode(200) + ->isRequestParameter('module', 'sfGuardPermission') + ->isRequestParameter('action', 'create') + ->setField('sf_guard_permission[name]', 'joketelling') + ->setField('sf_guard_permission[description]', 'joketelling description') + ->setField('associated_permissions[]', array(1,2,3)) + ->click('Save and continue editing') + ->followRedirect() + ->responseContains('joketelling description') + ->responseContains('joketelling'); + +// +//Delete permission +// +$b->get('/sfGuardPermission/list') + ->isStatusCode(200) + ->isRequestParameter('module', 'sfGuardPermission') + ->isRequestParameter('action', 'list') + ->click('joketelling') + ->click('Delete permission') + ->followRedirect() + ->responseContains('Permission list') + ->isRequestParameter('module', 'sfGuardPermission') + ->isRequestParameter('action', 'list'); + +?> \ No newline at end of file diff --git a/test-todo/tests/reaktor/025userAdminActionsTest.php b/test-todo/tests/reaktor/025userAdminActionsTest.php new file mode 100644 index 0000000..135f4fa --- /dev/null +++ b/test-todo/tests/reaktor/025userAdminActionsTest.php @@ -0,0 +1,103 @@ + + * @copyright 2008 Linpro + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); + +//Check if functionality is protected for users not logged in +$b->get('/sfGuardUser/list'); +$b->responseContains("You need to log in"); + + +//Check if functionality is protected for logged in users without access +$b->setField('username', 'userboy'); +$b->setField('password', 'userboy'); +$b->click('sign in'); + +$b->get('/sfGuardUser/list'); +$b->responseContains("You don't have the requested permission"); +$b->get('/logout'); + +// Log in as user with access +$b->get('/'); +$b->setField('username', 'admin'); +$b->setField('password', 'admin'); +$b->click('sign in'); + +// +//Create user +// +$b->get('/sfGuardUser/create'); +$b->isStatusCode(200); +$b->isRequestParameter('module', 'sfGuardUser'); +$b->isRequestParameter('action', 'create'); + +//Test validation +$fields['username'] = array('sf_guard_user[username]', 'enter a username', 'test'); +$fields['password'] = array('sf_guard_user[password]', 'Password is mandatory', 'testdummy'); +$fields['residence'] = array('sf_guard_user[residence_id]', 'Required', '6'); +$fields['dob'] = array('', 'enter a valid date of birth'); + +$b->click('Save and continue editing'); +//$b->setField('sf_guard_user[dob]', '2000-01-01'); +/*$b->setField('sf_guard_user[dob][day]', '1'); +$b->setField('sf_guard_user[dob][month]', '1'); +$b->setField('sf_guard_user[dob][year]', '2000');*/ +foreach ($fields as $field) +{ + $b->responseContains($field[1]); +} +array_pop($fields); +//print_r($fields); +//$fields[] = array('sf_guard_user_dob_day', 'date you entered is not valid', '1'); +//$fields[] = array('sf_guard_user[dob][month]', 'date you entered is not valid', '1'); +//$fields[] = array('sf_guard_user[dob][year]', 'date you entered is not valid', '2000'); + +foreach ($fields as $field) +{ + $b->setField($field[0], $field[2]); + $b->click('Save and continue editing'); + $b->checkResponseElement('div.form-row', '!/'.$field[1].'/'); +} + + +/* +//Check that password do not match validation works +$fields['password_repeat'] = array('sf_guard_user[password_bis]','do not match', 'notdummy'); +$b->setField($fields['password'][0], $fields['password'][2]); +$b->setField($fields['password_repeat'][0], $fields['password_repeat'][2]); +$b->click('Save and continue editing'); +$b->responseContains($fields['password_repeat'][1]); + +// +//Create user by filling in the rest of the form +// +/* +$b->setField($fields['password'][0], $fields['password'][2]); +$b->setField($fields['password_repeat'][0], $fields['password'][2]); +$b->setField('sf_guard_user[sex]', '2'); +//$b->setField('sf_guard_user[dob]', '2000-01-01'); +$b->setField('sf_guard_user[dob][day]', '1'); +$b->setField('sf_guard_user[dob][month]', '1'); +$b->setField('sf_guard_user[dob][year]', '2000'); +$b->click('Save and continue editing'); +$b->checkResponseElement('div.form-row', '!/'.$fields['password_repeat'][1].'/'); + + diff --git a/test-todo/tests/reaktor/035UploadEditTest.php b/test-todo/tests/reaktor/035UploadEditTest.php new file mode 100644 index 0000000..ce067be --- /dev/null +++ b/test-todo/tests/reaktor/035UploadEditTest.php @@ -0,0 +1,336 @@ + + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +include(dirname(__FILE__).'/../../bootstrap/functional.php'); + +// create a new test browser +$b = new sfTestBrowser(); +$b->initialize(); + +// Try to be here without specifying a file +$b->get("/upload/edit"); +$b->isStatusCode(); +$b->isRequestParameter('module', 'upload'); +$b->isRequestParameter('action', 'edit'); + +//We should be presented with a login message, since this page is only ever for logged in users +$b->checkResponseElement("div#content_main", "*You need to log in*"); + +// Get an object that belongs to a normal user to work with from the database +// Lets start with an image object so we can test that users can't change thumbnail +// We are using Userboy's first image, which is linked to "The Wonderful Painting" artwork +$c = new Criteria(); +$c->add(sfGuardUserPeer::USERNAME, "userboy"); +$c->add(ReaktorFilePeer::IDENTIFIER, "image"); +$c->addAscendingOrderByColumn("id"); +$c->addJoin(ReaktorFilePeer::USER_ID, sfGuardUserPeer::ID); +//$c->addJoin(ReaktorFilePeer::LOCATION_ID, FileLocationPeer::ID); +$fileObject = ReaktorFilePeer::doSelectOne($c); +$thisImageFile = new artworkFile($fileObject->getId()); +$parentImageArtwork = $thisImageFile->getParentArtwork(); + +//Navigate to the correct edit page +$b->get("/upload/edit/".$thisImageFile->getId()); + +//Lets log in as the wrong user - this user should always exist in test db +$b->setField('password', 'monkeyboy'); +$b->setField('username', 'monkeyboy'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +// This is not monkeyboy's work, so he gets a 404 +$b->isStatusCode(404); + +// Try with userboy +$b->click('Log out'); +$b->get("/upload/edit/".$thisImageFile->getId()); + +$b->setField('password', 'userboy'); +$b->setField('username', 'userboy'); +$b->click('Sign in'); +$b->isRedirected()->followRedirect(); + +$b->isStatusCode(); +$b->isRequestParameter('module', 'upload'); +$b->isRequestParameter('action', 'edit'); + +// Now we should be looking at the edit page +$b->checkResponseElement("div#editpage_form", "*Modify file details*"); + +// This file should be linked to User Boy's first artwork, and contain a link to it + +$b->checkResponseElement('div#editpage_form', '*(Part of '.$parentImageArtwork->getTitle().' artwork)*'); + +// Since this is an image file, thumbnail upload should not be available +$b->checkResponseElement('div#thumbnail_editpage', '!*startCallback()*'); + +// Check that the page is displaying the correct data for this file +$b->responseContains($thisImageFile->getMetadata("title")); +$b->responseContains($thisImageFile->getMetadata("creator")); +$b->responseContains($thisImageFile->getMetadata("description", "abstract")); +$b->responseContains($thisImageFile->getMetadata("description", "creation")); +$b->responseContains($thisImageFile->getMetadata("relation", "references")); +$b->responseContains('
    %s%d%%
    + + + + + + +
    SplashPlay
    Honda ad (with disabled controls and a linkURL) Play
    SkiingPlay
    New lage (image that pauses the player when advancing from previous clip)Play
    Sunset (image shown 10 seconds)Play
    Chaco sunset (image shown 10 seconds)Play
    + + + \ No newline at end of file diff --git a/web/flowplayer/html/FlowPlayerJs2.html b/web/flowplayer/html/FlowPlayerJs2.html new file mode 100644 index 0000000..462bd7b --- /dev/null +++ b/web/flowplayer/html/FlowPlayerJs2.html @@ -0,0 +1,290 @@ + + + + +FlowPlayer + + + + + +
    + This will be replaced by the player. +
    + + +

    Folliwing links jump within a playlist, requires a playlist configuration in the player. You can initialize the + player with a playlist by pressing this!

    + + + + + + + + + + + + + + + + +
    SplashGo
    Honda accordGo
    Hollywood (mp3 audio)Go
    Sympathy (mp3 audio)Go
    MiltonGo
    + +

    Alternative method, call playClip() - replaces the existing playlists with one clip.

    + + + + + + + + + + + + + + + + +
    Honda accordGo
    Honda accordGo
    Hollywood (mp3 audio)Go
    Sympathy (mp3 audio)Go
    MiltonGo
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PlayPause
    Stop
    Seek
    Get time
    Get duration
    Get % loaded
    Replace playlist!Back to original playlist!
    Set some cuePoints
    + Events: +
    +
    + + + diff --git a/web/flowplayer/html/FlowPlayerSkins.html b/web/flowplayer/html/FlowPlayerSkins.html new file mode 100644 index 0000000..a28bf9f --- /dev/null +++ b/web/flowplayer/html/FlowPlayerSkins.html @@ -0,0 +1,100 @@ + + + + +FlowPlayer + + + + + + + + + + + + +

    Dark skin

    +
    + This will be replaced by the player. +
    + +

    Click on the images below to change skins.

    +
    + + + diff --git a/web/flowplayer/html/example.html b/web/flowplayer/html/example.html new file mode 100644 index 0000000..81b3d0d --- /dev/null +++ b/web/flowplayer/html/example.html @@ -0,0 +1,86 @@ + + + + + + + + + + + + + +

    Simple flowplayer example

    + + + + + +
    + + + +

    + + If you are running this example locally and cannot see any video running
    + then you need to edit your + + Flash security settings + . + +

    + +

    + Select "Edit locations" > "Add location" > "Browse for files" and select + FlowPlayerDark.swf you just downloaded. +

    diff --git a/web/flowplayer/html/flashembed.min.js b/web/flowplayer/html/flashembed.min.js new file mode 100644 index 0000000..6c3db81 --- /dev/null +++ b/web/flowplayer/html/flashembed.min.js @@ -0,0 +1,18 @@ +/** + * flashembed 0.26. Adobe Flash embedding script + * + * http://flowplayer.org/player/flash-embed.html + * + * Copyright (c) 2008 Tero Piirainen (tero@flowplayer.org) + * + * Released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * = Basically you can do anything but leave this header as is + * + * Version: 0.10 - 03/11/2008 + * Version: 0.20 - 03/20/2008 + * Version: 0.25 - 03/29/2008 + * Version: 0.26 - 04/06/2008 + */ +function flashembed(g,h,j){if(typeof g=='string')g=document.getElementById(g);var k={src:'#',width:320,height:240,version:null,loadEvent:null,onFail:null,expressInstall:null,allowfullscreen:true,allowscriptaccess:'always',quality:'high',bgcolor:'#ffffff',type:'application/x-shockwave-flash',pluginspage:'http://www.adobe.com/go/getflashplayer'};extend(k,h);var l=k.loadEvent;k.loadEvent=null;if(l){g['on'+l]=function(){load()}}else{load()}function extend(a,b){if(b){for(key in b){a[key]=b[key]}}}var m=k.id;function load(){var a=getVersion();var b=k.version;var c=k.expressInstall;if(!b||isSupported(b)){k.onFail=k.version=k.expressInstall=null;g.innerHTML=getHTML()}else if(k.onFail){var d=k.onFail.call(k,getVersion(),j);if(d)g.innerHTML=d}else if(b&&c&&isSupported([6,0,65])){extend(k,{src:c});j={MMredirectURL:location.href,MMplayerType:'PlugIn',MMdoctitle:document.title};g.innerHTML=getHTML()}else{if(g.innerHTML!=''){}else{g.innerHTML="

    Flash version "+b+" or greater is required

    "+"

    "+(a[0]>0?"Your version is "+a:"You have no flash plugin installed")+"

    "+"

    Download latest version from here

    "}}g['on'+l]=null}function isSupported(a){var b=getVersion();return b[0]>=a[0]&&b[1]>=a[1]&&(b[2]==null||b[2]>=a[2])}function getHTML(){var a="";if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){a=''}else{a='';k.id=k.src=k.width=k.height=null;for(var b in k){if(k[b]!=null)a+='\n\t'}if(typeof j=='function')j=j();if(j){a+='\n\t'}a+=""}return a}function getVersion(){var a=[0,0];if(navigator.plugins&&typeof navigator.plugins["Shockwave Flash"]=="object"){var b=navigator.plugins["Shockwave Flash"].description;if(typeof b!="undefined"){b=b.replace(/^.*\s+(\S+\s+\S+$)/,"$1");var c=parseInt(b.replace(/^(.*)\..*$/,"$1"),10);var d=/r/.test(b)?parseInt(b.replace(/^.*r(.*)$/,"$1"),10):0;a=[c,d]}}else if(window.ActiveXObject){try{var f=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7")}catch(e){try{var f=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");a=[6,0];f.AllowScriptAccess="always"}catch(e){if(a[0]==6)return}try{var f=new ActiveXObject("ShockwaveFlash.ShockwaveFlash")}catch(e){}}if(typeof f=="object"){var b=f.GetVariable("$version");if(typeof b!="undefined"){b=b.replace(/^\S+\s+(.*)$/,"$1").split(",");a=[parseInt(b[0],10),parseInt(b[2],10)]}}}return a}function asString(b){switch(typeOf(b)){case'string':return'"'+b.replace(new RegExp('(["\\\\])','g'),'\\$1')+'"';case'array':return'['+map(b,function(a){return asString(a)}).join(',')+']';case'object':var c=[];for(var d in b){c.push('"'+d+'":'+asString(b[d]))}return'{'+c.join(',')+'}'}return String(b).replace(/\s/g," ").replace(/\'/g,"\"")}function typeOf(a){if(a===null||a===undefined)return false;var b=typeof a;return(b=='object'&&a.push)?'array':b}if(window.attachEvent){window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}})}function map(a,b){var c=[];for(var i in a){c[i]=b(a[i])}return c}flashembed.getVersion=getVersion;flashembed.isSupported=isSupported;return g}if(typeof jQuery=='function'){(function($){$.fn.extend({flashembed:function(a,b){return this.each(function(){new flashembed(this,a,b)})}})})(jQuery)} diff --git a/web/flowplayer/html/flowPlayer.js b/web/flowplayer/html/flowPlayer.js new file mode 100644 index 0000000..1ca9ed5 --- /dev/null +++ b/web/flowplayer/html/flowPlayer.js @@ -0,0 +1,444 @@ +/* + * FlowPlayer external configuration file. + * Copyright 2005-2006 Anssi Piirainen + * + * All settings defined in this file can be alternatively defined in the + * embedding HTML object tag (as flashvars variables). Values defined in the + * object tag override values defined in this file. You could use this + * config file to provide defaults for multiple player instances that + * are used in a Web site. Individual instances can be then customized + * with their embedding HTML. + * + * Note that you should probably remove all the comments from this file + * before using it. That way the file will be smaller and will load faster. + */ +{ + /* + * Instructs the player to load the configuration from an external config file. + * This can be a abosulte URL or a relative url (relative to the HTML page + * where the player is embedded). + */ +// configFileName: 'flowPlayer.js', + + /* + * Instructs the player to load the configuration from a RTMP server. + * The player connects to the server listening in the address specified + * by this URL and calls a method 'getStreamPlayerConfig' that should return a + * valid FP configuration object. + */ +// rtmpConfigUrl: 'rtmp://localhost/myapp', + + /* + * A param value to be passed to getStreamPlayerConfig(). A value 'foobar' + * will make the player to call getStreamPlayerConfig('foobsr') + */ +// rtmpConfigParam: 'anssi', + + /* + * Name of the video file. Used if only one video is shown. + * + * Note for testing locally: Specify an empty baseURL '', if you want to load + * the video from your local disk from the directory that contains + * FlowPlayer.swf. In this case the videoFile parameter value should start + * with a slash, for example '/video.flv'. + * + * See also: 'baseURL' that affects this variable + */ +// videoFile: 'honda_accord.flv', + + /* + * Clip to be used if the file specified with 'videoFile' or any of the clips in the playlist + * was not found. The missing video clips are replaced by this clip. This can be + * an image or a FLV clip. Typically this will contain an image/video saying + * "the video you requested cannot be found.....". + * + * The syntax for the value is the same is with the clips in a playlist + * including the possibility to have start/end and duration properties. + * + * See also: 'baseURL' that affects this variable + */ + noVideoClip: { url: 'main_clickToPlay.jpg', duration: 10 }, + //noVideoClip: { url: 'MiltonFriedmanonLimi.flv' }, + + /* + * Playlist is used to publish several videos using one player instance. + * You can also have images in the playlist. The playback pauses in the + * image unless a 'duration' property is given for the image: + + * * The clips in the playlist may have following properties: + * + * name: Name for the clip to be shown in the playlist view. If this is + * not given, the clip will be hidden from the view. + * + * url: The URL used to load the clip. + * + * type: One of 'video', 'flv', 'swf', 'jpg'. Optional, determined from the URL's filename extension + * if that is present. 'video' means a video file in any format supported by Flash. + * 'flv' is present here for backward compatibility, use 'video' in new FlowPlayer installations + * now. Defaults to 'video' if the extension is not present in the URL. + * + * start: The start time (seconds) from where to start the playback. A nonzero + * value can only be used when using a streaming server!! + * end: The end time (seconds) where to stop the playback. + * + * duration: The duration the image is to be shown. If not given the playback + * pauses when the image is reached in the list. + * + * protected: (true/false) Apply inlinine linking protection for this clip? + * Optional, defaults to false. + * + * linkUrl: Associates a hyperlink pointing to the specified URL. The linked + * document will be opened to the browser when the clip area is clicked. + * Specifying this parameter will replace the normal pause/resume behavior + * that is associated to clicking the display area. If you specify an empty + * linkUrl '' the pause/resume behavior is disabled but no hyperlink + * is created. + * linkWindow: Specifies the name of the browser window or frame into which to load + * the linked document. Can be a custom name or one of presets: '_blank', + * '_parent', '_self', '_top'. (optional, defaults to '_blank') + * + * controlEnabled: (true/false) Enable transport control buttons for this clip? + * Optional, defaults to true. + * + * allowResize: (true/false) Allow resizing this clip according to the menu selection. + * Optional, defaults to true. + * + * overlay: A filename pointing to an image that will be placed on top of this image clip. This + * is only applicable to image clips (jpg or png files). Essentially this layers two images + * on top of each other. Typically the image on top is a big play button that is used on + * top of an image taken from the main movie. + * + * overlayId: ID that specifies a built-in overlay to be used. Currently the player supports + * one built-in overlay with ID 'play'. It renders a large play button with mouse hover color change. + * You can use this on top of image clips (one clip with both the 'url' property and + * 'overlayId' property). + * You can also specify a clip that only has this ID. In that + * case you should place it immediately before or after a FLV clip. This overlay-only + * clip is then rendered on top of the first or the last frame of the FLV video. + * + * live: (true/false) Is this a live stream (played from a media server)? + * + * showOnLoadBegin: (true/false) If true, make this clip visible when the fist bits have been loaded. + * If false, do not show this clip (show the background instead) before the buffer is filled + * and the playback starts. Optional, defaults to true. + * + * maxPlayCount: The maximum play count for this clip. The clip is removed from the playlist when + * the playcount reaches this amount. + * + * suggestedClipsInfoUrl: URL used to fetch suggestions (related videos) information from the server + * + * See also: 'baseURL' is prefixed with each URL + */ + playList: [ + { url: 'main_clickToPlay.jpg' }, + { name: 'Honda Accord', url: '!honda_accord.flv' }, + { name: 'River', url: 'river.flv' }, + { name: 'Ounasvaara', url: 'ounasvaara.flv' } + ], + + /* + * Specifies wether the playlist control buttons should be shown in the player SWF component or not. + * Optional, defaults to the value of showPlayList. + */ + showPlayListButtons: true, + + /* + * Streaming server connection URL. + * You don't need this with lighttpd, just use the streamingServer setting (see below) with it. + */ +// streamingServerURL: 'rtmp://localahost:oflaDemo', + + /* + * baseURL specifies the URL that is appended in front of different file names + * given in this file. + * + * You don't need to specify this at all if you place the video next to + * the player SWF file on the Web server (to be available under the same URL path). + */ +// baseURL: 'http://flowplayer.sourceforge.net/video', + + + /* + * What kind of streaming server? Available options: 'fms', 'red5', 'lighttpd' + */ +// streamingServer: 'fms', + + /* + * Specifies whether thumbnail information is contained in the FLV's cue point + * metadata. Cue points can be injected into the FLV file using + * for example Flvtool2. See the FlowPlayer web site for more info. + * (optional, defaults to false) + * + * See also: cuePoints below for an alternative way of specifying thumb metadata + */ +// thumbsOnFLV: true, + + /* + * Thumbnails specific to cue points. Use this if you don't want to + * embed thumbnail metadata into the FLV's cue points. + * If you have thumbNails defined here you should have thumbsOnFLV: false ! + * thumb times are given in seconds + */ +// thumbs: [ +// { thumbNail: 'Thumb1.jpg', time: 10 }, +// { thumbNail: 'Thumb2.jpg', time: 24 }, +// { thumbNail: 'Thumb3.jpg', time: 54 }, +// { thumbNail: 'Thumb4.jpg', time: 74 }, +// { thumbNail: 'Thumb5.jpg', time: 94 }, +// { thumbNail: 'Thumb6.jpg', time: 110 } +// ], + // Location of the thumbnail files +// thumbLocation: 'http://www.kolumbus.fi/apiirain/video', + + /* + * 'autoPlay' variable defines whether playback begins immediately or not. + * + * Note that currently with red5 you should not have false in autoPlay + * when you specify a nonzero starting position for the video clip. This is because red5 + * does not send FLV metadata when the playback starts from a nonzero value. + * + * (optional, defaults to true) + */ + autoPlay: true, + + /* + * 'autoBuffering' specifies wheter to start loading the video stream into + * buffer memory immediately. Only meaningful if 'autoPlay' is set to + * false. (optional, defaults to true) + */ + autoBuffering: true, + + /* + * 'startingBufferLength' specifies the video buffer length to be used to kick + * off the playback. This is used in the beginning of the playback and every time + * after the player has ran out of buffer memory. + * More info at: http://www.progettosinergia.com/flashvideo/flashvideoblog.htm#031205 + * (optional, defaults to the value of 'bufferLength' setting) + * + * see also: bufferLength + */ +// startingBufferLength: 5, + + /* + * 'bufferLength' specifies the video buffer length in seconds. This is used + * after the playback has started with the initial buffer length. You should + * use an arbitrary large value here to ensure stable playback. + * (optional, defaults to 10 seconds) + * + * see also: startingBufferLength + */ + bufferLength: 20, + + /* + * 'loop' defines whether the playback should loop to the first clip after + * all clips in the playlist have been shown. It is used as the + * default state of the toggle button that controls looping. (optional, + * defaults to true) + */ + loop: true, + + /* + * Rewind back to the fist clip in the playlist when end of the list has been reached? + * This option only has effect if loop is false (please see loop variable above). + * (optional, defaults to false) + */ + autoRewind: true, + + /* + * Specifies wether the loop toggle button should be shown in the player SWF component or not. + * Optional, defaults to false. + */ +// showLoopButton: true, + + /* + * Specifies the height to be allocated for the video display. This is the + * maximum height available for the different resizing options. + */ + videoHeight: 320, + + /* + * Specifies the width for the control buttons area. Optiona, defaults to the + * width setting used in the embedding code. + */ +// controlsWidth: 480, + + /* + * Specifies how the video is scaled initially. This can be then changed by + * the user through the menu. (optional, defaults to 'fit') + * Possible values: + * 'fit' Fit to window by preserving the aspect ratios encoded in the FLV metadata. + * This is the default behavior. + * 'half' Half size (preserves aspect ratios) + * 'orig' Use the dimensions encoded in FLV. If the video is too big for the + * available space the video is scaled as if using the 'fit' option. + * 'scale' Scale the video to fill all available space for the video. Ignores + * the dimensions in metadata. + * + */ + initialScale: 'fit', + + /* + * Specifies if the menu containing the size options should be shown or not. + * (optional, defaults to true) +// showMenu: false, + + /* + * 'hideControls' if set to true, hides all buttons and the progress bar + * leaving only the video showing (optional, defaults to false) + */ + hideControls: false, + + /* + * URL that specifies a base URL that points to a folder containing + * images used to skin the player. You must specify this if you intend + * to load external button images (see 'loadButtonImages' below). + */ + skinImagesBaseURL: 'http://flowplayer.sourceforge.net/resources' + + /* + * Will button images be loaded from external files, or will images embedded + * in the player SWF component be used? Set this to false if you want to "skin" + * the buttons. Optional, defaults to true. + * + * NOTE: If you set this to false, you need to have the skin images available + * on the server! Otherwise the player will not show up at all or will show + * up corrupted. + * + * See also: 'skinImagesBaseURL' that affects this variable + */ +// useEmbeddedButtonImages: false, + + /* + * 'splashImageFile' specifies an image file to be used as a splash image. + * This is useful if 'autoPlay' is set to false and you want to show a + * welcome image before the video is played. Should be in JPG format. The + * value of 'baseURL' is used similarily as with the video file name and + * therefore the video and the image files should be placed in the Web + * server next to each other. + * + * NOTE: If you set a value for this, you need to have the splash image available + * on the server! Otherwise the player will not show up at all or will show + * up corrupted. + * + * NOTE2: You can also specify the splash in a playlist. This is just + * an alternative way of doing it. It was preserved for backward compatibility. + * + * See also: 'baseURL' that affects this variable + */ +// splashImageFile: 'main_clickToPlay.jpg', + + /* + * Should the splash image be scaled to fit the entire video area? If false, + * the image will be centered. Optional, defaults to false. + */ +// scaleSplash: false, + + /* + * 'progressBarColor1' defines the color of the progress bar at the bottom + * and top edges. Specified in hexadecimal triplet form indicating the RGB + * color component values. (optional) + */ +// progressBarColor1: 0xFFFFFF, + + + /* + * 'progressBarColor2' defines the color in the middle of the progress bar. + * The value of this and 'progressBarColor1' variables define the gradient + * color fill of the progress bar. (optional) + */ +// progressBarColor2: 0xDDFFDD, + + /* + * 'bufferBarColor1' defines the color of the buffer size indicator bar at the bottom + * and top edges. (optional) + */ +// bufferBarColor1: 0xFFFFFF, + + + /* + * 'bufferBarColor2' defines the color of the buffer size indicator bar in the middle + * of the bar. (optional) + */ +// bufferBarColor2: 0xDDFFDD, + + /* + * 'progressBarBorderColor1' defines the color of the progress bar's border at the bottom + * and top edges. (optional) + */ +// progressBarBorderColor1: 0xDDDDDD, + + + /* + * 'progressBarBorderColor2' defines the color of the progress bar's border in the middle + * of the bar. (optional) + */ +// progressBarBorderColor2: 0xEEEEEE, + + /* + * 'bufferingAnimationColor' defines the color of the moving bars used in the buffering + * animation. (optional) + */ +// bufferingAnimationColor: 0x0000FF, + + /* + * 'controlsAreaBorderColor' defines the color of the border behind buttons and progress bar + * (optional) + */ +// controlsAreaBorderColor: 0x1234, + + /* + * 'timeDisplayFontColor' defines the color of the progress/duration time display + * (optional) + */ +// timeDisplayFontColor: 0xAABBCC, + + /* + * Height of the progress bar. (optional) + */ +// progressBarHeight: 10, + + /* + * Height of the progress bar area. (optional) + */ +// progressBarAreaHeight: 10, + + /* + * Name of the authentication code file name that is used to prevent inline linking + * of video and image files. This can be a complete URL or just a file name relative + * to the location from where the player is loaded. (optional, defaults to flowplayer_auth.txt) + */ +// authFileName: 'http://www.mytube.org/authCode.txt', + + /* + * The URL pointing to a sctipt that opens the player full screen. + * If this is not configured explicitly, the default script, + * http://flowplayer.sourceforge.net/fullscreen.js, is used. + */ +// fullScreenScriptURL: 'http://mysite.org/fullscreen.js' + + /** + * Specifies which menu items will be show. This is an array that contains a boolean + * value for each of the items. By default shows them all except "full screen". + */ +// menuItems[ +// true, // show 'Fit to window' +// true, // show 'Half size' +// true, // show 'Original size' +// true, // show 'Fill window' +// true, // show 'Full screen' +// false // hide 'Embed...' +// ], + + + /* + * Specifies wether the full screen button should be shown in the player SWF component or not. + * Optional, defaults to true. + */ +// showFullScreenButton: false, + + /* + * Use the Flash 9 native full screen mode. + */ +// useNativeFullScreen: true, +} + diff --git a/web/flowplayer/html/fullscreen.js b/web/flowplayer/html/fullscreen.js new file mode 100644 index 0000000..fbb45e8 --- /dev/null +++ b/web/flowplayer/html/fullscreen.js @@ -0,0 +1,15 @@ +/* + * Default FlowPlayer fullscreen opener. + * http://flowplayer.sourceforge.net + */ + +function flowPlayerOpenFullScreen(config) { + var winWidth = window.screen.availWidth; + var winHeight = window.screen.availHeight; + var fullScreenWindow = window.open('http://flowplayer.org/video/1_20/fullscreen.html?config='+config, 'FlowPlayer', 'left=0,top=0,width='+winWidth+',height='+winHeight+',status=no,resizable=yes'); +} + +function flowPlayerExitFullScreen(config) { + self.close(); +} + diff --git a/web/flowplayer/html/suggestions.js b/web/flowplayer/html/suggestions.js new file mode 100644 index 0000000..c6f9eeb --- /dev/null +++ b/web/flowplayer/html/suggestions.js @@ -0,0 +1,10 @@ +{ + clips: [ + { url: 'honda_accord.flv', name: 'Honda commercial', suggestedClipsInfoUrl: 'suggestions.js', + duration: 180, thumbnailUrl: 'Thumb1.jpg', + info: { viewed: 631, category: 'ads' } }, + { url: 'river.flv', name: 'Skiing in Rovaniemi', suggestedClipsInfoUrl: 'suggestions.js', + duration: 180, thumbnailUrl: 'Thumb2.jpg', + info: { viewed: 2, category: 'sports' } } + ] +} \ No newline at end of file diff --git a/web/flowplayer/html/swfobject.js b/web/flowplayer/html/swfobject.js new file mode 100644 index 0000000..7345ef0 --- /dev/null +++ b/web/flowplayer/html/swfobject.js @@ -0,0 +1,138 @@ +/** + * SWFObject v1.4.4: Flash Player detection and embed - http://blog.deconcept.com/swfobject/ + * + * SWFObject is (c) 2006 Geoff Stearns and is released under the MIT License: + * http://www.opensource.org/licenses/mit-license.php + * + * **SWFObject is the SWF embed script formerly known as FlashObject. The name was changed for + * legal reasons. + */ +if(typeof deconcept=="undefined"){var deconcept=new Object();} +if(typeof deconcept.util=="undefined"){deconcept.util=new Object();} +if(typeof deconcept.SWFObjectUtil=="undefined"){deconcept.SWFObjectUtil=new Object();} +deconcept.SWFObject=function(_1,id,w,h,_5,c,_7,_8,_9,_a,_b){if(!document.getElementById){return;} +this.DETECT_KEY=_b?_b:"detectflash"; +this.skipDetect=deconcept.util.getRequestParameter(this.DETECT_KEY); +this.params=new Object(); +this.variables=new Object(); +this.attributes=new Array(); +if(_1){this.setAttribute("swf",_1);} +if(id){this.setAttribute("id",id);} +if(w){this.setAttribute("width",w);} +if(h){this.setAttribute("height",h);} +if(_5){this.setAttribute("version",new deconcept.PlayerVersion(_5.toString().split(".")));} +this.installedVer=deconcept.SWFObjectUtil.getPlayerVersion(); +if(c){this.addParam("bgcolor",c);} +var q=_8?_8:"high"; +this.addParam("quality",q); +this.setAttribute("useExpressInstall",_7); +this.setAttribute("doExpressInstall",false); +var _d=(_9)?_9:window.location; +this.setAttribute("xiRedirectUrl",_d); +this.setAttribute("redirectUrl",""); +if(_a){this.setAttribute("redirectUrl",_a);}}; +deconcept.SWFObject.prototype={setAttribute:function(_e,_f){ +this.attributes[_e]=_f; +},getAttribute:function(_10){ +return this.attributes[_10]; +},addParam:function(_11,_12){ +this.params[_11]=_12; +},getParams:function(){ +return this.params; +},addVariable:function(_13,_14){ +this.variables[_13]=_14; +},getVariable:function(_15){ +return this.variables[_15]; +},getVariables:function(){ +return this.variables; +},getVariablePairs:function(){ +var _16=new Array(); +var key; +var _18=this.getVariables(); +for(key in _18){_16.push(key+"="+_18[key]);} +return _16;},getSWFHTML:function(){var _19=""; +if(navigator.plugins&&navigator.mimeTypes&&navigator.mimeTypes.length){ +if(this.getAttribute("doExpressInstall")){ +this.addVariable("MMplayerType","PlugIn");} +_19="0){_19+="flashvars=\""+_1c+"\"";}_19+="/>"; +}else{if(this.getAttribute("doExpressInstall")){this.addVariable("MMplayerType","ActiveX");} +_19=""; +_19+=""; +var _1d=this.getParams(); +for(var key in _1d){_19+="";} +var _1f=this.getVariablePairs().join("&"); +if(_1f.length>0){_19+="";}_19+="";} +return _19; +},write:function(_20){ +if(this.getAttribute("useExpressInstall")){ +var _21=new deconcept.PlayerVersion([6,0,65]); +if(this.installedVer.versionIsValid(_21)&&!this.installedVer.versionIsValid(this.getAttribute("version"))){ +this.setAttribute("doExpressInstall",true); +this.addVariable("MMredirectURL",escape(this.getAttribute("xiRedirectUrl"))); +document.title=document.title.slice(0,47)+" - Flash Player Installation"; +this.addVariable("MMdoctitle",document.title);}} +if(this.skipDetect||this.getAttribute("doExpressInstall")||this.installedVer.versionIsValid(this.getAttribute("version"))){ +var n=(typeof _20=="string")?document.getElementById(_20):_20; +n.innerHTML=this.getSWFHTML();return true; +}else{if(this.getAttribute("redirectUrl")!=""){document.location.replace(this.getAttribute("redirectUrl"));}} +return false;}}; +deconcept.SWFObjectUtil.getPlayerVersion=function(){ +var _23=new deconcept.PlayerVersion([0,0,0]); +if(navigator.plugins&&navigator.mimeTypes.length){ +var x=navigator.plugins["Shockwave Flash"]; +if(x&&x.description){_23=new deconcept.PlayerVersion(x.description.replace(/([a-zA-Z]|\s)+/,"").replace(/(\s+r|\s+b[0-9]+)/,".").split("."));} +}else{try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");} +catch(e){try{var axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"); +_23=new deconcept.PlayerVersion([6,0,21]);axo.AllowScriptAccess="always";} +catch(e){if(_23.major==6){return _23;}}try{axo=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");} +catch(e){}}if(axo!=null){_23=new deconcept.PlayerVersion(axo.GetVariable("$version").split(" ")[1].split(","));}} +return _23;}; +deconcept.PlayerVersion=function(_27){ +this.major=_27[0]!=null?parseInt(_27[0]):0; +this.minor=_27[1]!=null?parseInt(_27[1]):0; +this.rev=_27[2]!=null?parseInt(_27[2]):0; +}; +deconcept.PlayerVersion.prototype.versionIsValid=function(fv){ +if(this.majorfv.major){return true;} +if(this.minorfv.minor){return true;} +if(this.rev + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..')); +define('SF_APP', 'reaktor'); +define('SF_ENVIRONMENT', 'prod'); +define('SF_DEBUG', false); + +require_once SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'; + +sfContext::getInstance()->getController()->dispatch(); \ No newline at end of file diff --git a/web/js/VM_FlashContent.js b/web/js/VM_FlashContent.js new file mode 100644 index 0000000..ae9f7fb --- /dev/null +++ b/web/js/VM_FlashContent.js @@ -0,0 +1,106 @@ +function VM_Generateobj(objAttrs, params, embedAttrs) +{ + var str = ' '; + str += '"; + } catch(e) {} + var element = parentElement.firstChild || null; + + // see if browser added wrapping tags + if(element && (element.tagName.toUpperCase() != elementName)) + element = element.getElementsByTagName(elementName)[0]; + + // fallback to createElement approach + if(!element) element = document.createElement(elementName); + + // abort if nothing could be created + if(!element) return; + + // attributes (or text) + if(arguments[1]) + if(this._isStringOrNumber(arguments[1]) || + (arguments[1] instanceof Array) || + arguments[1].tagName) { + this._children(element, arguments[1]); + } else { + var attrs = this._attributes(arguments[1]); + if(attrs.length) { + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" +elementName + " " + + attrs + ">"; + } catch(e) {} + element = parentElement.firstChild || null; + // workaround firefox 1.0.X bug + if(!element) { + element = document.createElement(elementName); + for(attr in arguments[1]) + element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; + } + if(element.tagName.toUpperCase() != elementName) + element = parentElement.getElementsByTagName(elementName)[0]; + } + } + + // text, or array of children + if(arguments[2]) + this._children(element, arguments[2]); + + return element; + }, + _text: function(text) { + return document.createTextNode(text); + }, + + ATTR_MAP: { + 'className': 'class', + 'htmlFor': 'for' + }, + + _attributes: function(attributes) { + var attrs = []; + for(attribute in attributes) + attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) + + '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"'); + return attrs.join(" "); + }, + _children: function(element, children) { + if(children.tagName) { + element.appendChild(children); + return; + } + if(typeof children=='object') { // array can hold nodes and text + children.flatten().each( function(e) { + if(typeof e=='object') + element.appendChild(e) + else + if(Builder._isStringOrNumber(e)) + element.appendChild(Builder._text(e)); + }); + } else + if(Builder._isStringOrNumber(children)) + element.appendChild(Builder._text(children)); + }, + _isStringOrNumber: function(param) { + return(typeof param=='string' || typeof param=='number'); + }, + build: function(html) { + var element = this.node('div'); + $(element).update(html.strip()); + return element.down(); + }, + dump: function(scope) { + if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope + + var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " + + "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " + + "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+ + "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+ + "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+ + "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/); + + tags.each( function(tag){ + scope[tag] = function() { + return Builder.node.apply(Builder, [tag].concat($A(arguments))); + } + }); + } +} diff --git a/web/js/controls.js b/web/js/controls.js new file mode 100644 index 0000000..75763e4 --- /dev/null +++ b/web/js/controls.js @@ -0,0 +1,965 @@ +// script.aculo.us controls.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008 + +// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = { } +Autocompleter.Base = Class.create({ + baseInitialize: function(element, update, options) { + element = $(element) + this.element = element; + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + this.oldElementValue = this.element.value; + + if(this.setOptions) + this.setOptions(options); + else + this.options = options || { }; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, { + setHeight: false, + offsetTop: element.offsetHeight + }); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if(typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + // Force carriage returns as token delimiters anyway + if (!this.options.tokens.include('\n')) + this.options.tokens.push('\n'); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (Prototype.Browser.IE) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + ''); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index-- + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(false); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++ + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = $(selectedElement).select('.' + this.options.select) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var bounds = this.getTokenBounds(); + if (bounds[0] != -1) { + var newValue = this.element.value.substr(0, bounds[0]); + var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value + this.element.value.substr(bounds[1]); + } else { + this.element.value = value; + } + this.oldElementValue = this.element.value; + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if(this.update.firstChild && this.update.down().childNodes) { + this.entryCount = + this.update.down().childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + this.index = 0; + + if(this.entryCount==1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + this.tokenBounds = null; + if(this.getToken().length>=this.options.minChars) { + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + this.oldElementValue = this.element.value; + }, + + getToken: function() { + var bounds = this.getTokenBounds(); + return this.element.value.substring(bounds[0], bounds[1]).strip(); + }, + + getTokenBounds: function() { + if (null != this.tokenBounds) return this.tokenBounds; + var value = this.element.value; + if (value.strip().empty()) return [-1, 0]; + var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); + var offset = (diff == this.oldElementValue.length ? 1 : 0); + var prevTokenPos = -1, nextTokenPos = value.length; + var tp; + for (var index = 0, l = this.options.tokens.length; index < l; ++index) { + tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); + if (tp > prevTokenPos) prevTokenPos = tp; + tp = value.indexOf(this.options.tokens[index], diff + offset); + if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; + } + return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); + } +}); + +Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { + var boundary = Math.min(newS.length, oldS.length); + for (var index = 0; index < boundary; ++index) + if (newS[index] != oldS[index]) + return index; + return boundary; +}; + +Ajax.Autocompleter = Class.create(Autocompleter.Base, { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + this.startIndicator(); + + var entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(Autocompleter.Base, { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) + return "
      " + ret.join('') + "
    "; + } + }, options || { }); + } +}); + +// AJAX in-place editor and collection editor +// Full rewrite by Christophe Porteneuve (April 2007). + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +} + +Ajax.InPlaceEditor = Class.create({ + initialize: function(element, url, options) { + this.url = url; + this.element = element = $(element); + this.prepareOptions(); + this._controls = { }; + arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! + Object.extend(this.options, options || { }); + if (!this.options.formId && this.element.id) { + this.options.formId = this.element.id + '-inplaceeditor'; + if ($(this.options.formId)) + this.options.formId = ''; + } + if (this.options.externalControl) + this.options.externalControl = $(this.options.externalControl); + if (!this.options.externalControl) + this.options.externalControlOnly = false; + this._originalBackground = this.element.getStyle('background-color') || 'transparent'; + this.element.title = this.options.clickToEditText; + this._boundCancelHandler = this.handleFormCancellation.bind(this); + this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); + this._boundFailureHandler = this.handleAJAXFailure.bind(this); + this._boundSubmitHandler = this.handleFormSubmission.bind(this); + this._boundWrapperHandler = this.wrapUp.bind(this); + this.registerListeners(); + }, + checkForEscapeOrReturn: function(e) { + if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; + if (Event.KEY_ESC == e.keyCode) + this.handleFormCancellation(e); + else if (Event.KEY_RETURN == e.keyCode) + this.handleFormSubmission(e); + }, + createControl: function(mode, handler, extraClasses) { + var control = this.options[mode + 'Control']; + var text = this.options[mode + 'Text']; + if ('button' == control) { + var btn = document.createElement('input'); + btn.type = 'submit'; + btn.value = text; + btn.className = 'editor_' + mode + '_button'; + if ('cancel' == mode) + btn.onclick = this._boundCancelHandler; + this._form.appendChild(btn); + this._controls[mode] = btn; + } else if ('link' == control) { + var link = document.createElement('a'); + link.href = '#'; + link.appendChild(document.createTextNode(text)); + link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; + link.className = 'editor_' + mode + '_link'; + if (extraClasses) + link.className += ' ' + extraClasses; + this._form.appendChild(link); + this._controls[mode] = link; + } + }, + createEditField: function() { + var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); + var fld; + if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { + fld = document.createElement('input'); + fld.type = 'text'; + var size = this.options.size || this.options.cols || 0; + if (0 < size) fld.size = size; + } else { + fld = document.createElement('textarea'); + fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); + fld.cols = this.options.cols || 40; + } + fld.name = this.options.paramName; + fld.value = text; // No HTML breaks conversion anymore + fld.className = 'editor_field'; + if (this.options.submitOnBlur) + fld.onblur = this._boundSubmitHandler; + this._controls.editor = fld; + if (this.options.loadTextURL) + this.loadExternalText(); + this._form.appendChild(this._controls.editor); + }, + createForm: function() { + var ipe = this; + function addText(mode, condition) { + var text = ipe.options['text' + mode + 'Controls']; + if (!text || condition === false) return; + ipe._form.appendChild(document.createTextNode(text)); + }; + this._form = $(document.createElement('form')); + this._form.id = this.options.formId; + this._form.addClassName(this.options.formClassName); + this._form.onsubmit = this._boundSubmitHandler; + this.createEditField(); + if ('textarea' == this._controls.editor.tagName.toLowerCase()) + this._form.appendChild(document.createElement('br')); + if (this.options.onFormCustomization) + this.options.onFormCustomization(this, this._form); + addText('Before', this.options.okControl || this.options.cancelControl); + this.createControl('ok', this._boundSubmitHandler); + addText('Between', this.options.okControl && this.options.cancelControl); + this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); + addText('After', this.options.okControl || this.options.cancelControl); + }, + destroy: function() { + if (this._oldInnerHTML) + this.element.innerHTML = this._oldInnerHTML; + this.leaveEditMode(); + this.unregisterListeners(); + }, + enterEditMode: function(e) { + if (this._saving || this._editing) return; + this._editing = true; + this.triggerCallback('onEnterEditMode'); + if (this.options.externalControl) + this.options.externalControl.hide(); + this.element.hide(); + this.createForm(); + this.element.parentNode.insertBefore(this._form, this.element); + if (!this.options.loadTextURL) + this.postProcessEditField(); + if (e) Event.stop(e); + }, + enterHover: function(e) { + if (this.options.hoverClassName) + this.element.addClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onEnterHover'); + }, + getText: function() { + return this.element.innerHTML; + }, + handleAJAXFailure: function(transport) { + this.triggerCallback('onFailure', transport); + if (this._oldInnerHTML) { + this.element.innerHTML = this._oldInnerHTML; + this._oldInnerHTML = null; + } + }, + handleFormCancellation: function(e) { + this.wrapUp(); + if (e) Event.stop(e); + }, + handleFormSubmission: function(e) { + var form = this._form; + var value = $F(this._controls.editor); + this.prepareSubmission(); + var params = this.options.callback(form, value) || ''; + if (Object.isString(params)) + params = params.toQueryParams(); + params.editorId = this.element.id; + if (this.options.htmlResponse) { + var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Updater({ success: this.element }, this.url, options); + } else { + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.url, options); + } + if (e) Event.stop(e); + }, + leaveEditMode: function() { + this.element.removeClassName(this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + if (this.options.externalControl) + this.options.externalControl.show(); + this._saving = false; + this._editing = false; + this._oldInnerHTML = null; + this.triggerCallback('onLeaveEditMode'); + }, + leaveHover: function(e) { + if (this.options.hoverClassName) + this.element.removeClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onLeaveHover'); + }, + loadExternalText: function() { + this._form.addClassName(this.options.loadingClassName); + this._controls.editor.disabled = true; + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._form.removeClassName(this.options.loadingClassName); + var text = transport.responseText; + if (this.options.stripLoadedTextTags) + text = text.stripTags(); + this._controls.editor.value = text; + this._controls.editor.disabled = false; + this.postProcessEditField(); + }.bind(this), + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + postProcessEditField: function() { + var fpc = this.options.fieldPostCreation; + if (fpc) + $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); + }, + prepareOptions: function() { + this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); + Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); + [this._extraDefaultOptions].flatten().compact().each(function(defs) { + Object.extend(this.options, defs); + }.bind(this)); + }, + prepareSubmission: function() { + this._saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + registerListeners: function() { + this._listeners = { }; + var listener; + $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { + listener = this[pair.value].bind(this); + this._listeners[pair.key] = listener; + if (!this.options.externalControlOnly) + this.element.observe(pair.key, listener); + if (this.options.externalControl) + this.options.externalControl.observe(pair.key, listener); + }.bind(this)); + }, + removeForm: function() { + if (!this._form) return; + this._form.remove(); + this._form = null; + this._controls = { }; + }, + showSaving: function() { + this._oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + this.element.addClassName(this.options.savingClassName); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + }, + triggerCallback: function(cbName, arg) { + if ('function' == typeof this.options[cbName]) { + this.options[cbName](this, arg); + } + }, + unregisterListeners: function() { + $H(this._listeners).each(function(pair) { + if (!this.options.externalControlOnly) + this.element.stopObserving(pair.key, pair.value); + if (this.options.externalControl) + this.options.externalControl.stopObserving(pair.key, pair.value); + }.bind(this)); + }, + wrapUp: function(transport) { + this.leaveEditMode(); + // Can't use triggerCallback due to backward compatibility: requires + // binding + direct element + this._boundComplete(transport, this.element); + } +}); + +Object.extend(Ajax.InPlaceEditor.prototype, { + dispose: Ajax.InPlaceEditor.prototype.destroy +}); + +Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { + initialize: function($super, element, url, options) { + this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; + $super(element, url, options); + }, + + createEditField: function() { + var list = document.createElement('select'); + list.name = this.options.paramName; + list.size = 1; + this._controls.editor = list; + this._collection = this.options.collection || []; + if (this.options.loadCollectionURL) + this.loadCollection(); + else + this.checkForExternalText(); + this._form.appendChild(this._controls.editor); + }, + + loadCollection: function() { + this._form.addClassName(this.options.loadingClassName); + this.showLoadingText(this.options.loadingCollectionText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + var js = transport.responseText.strip(); + if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check + throw 'Server returned an invalid collection representation.'; + this._collection = eval(js); + this.checkForExternalText(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadCollectionURL, options); + }, + + showLoadingText: function(text) { + this._controls.editor.disabled = true; + var tempOption = this._controls.editor.firstChild; + if (!tempOption) { + tempOption = document.createElement('option'); + tempOption.value = ''; + this._controls.editor.appendChild(tempOption); + tempOption.selected = true; + } + tempOption.update((text || '').stripScripts().stripTags()); + }, + + checkForExternalText: function() { + this._text = this.getText(); + if (this.options.loadTextURL) + this.loadExternalText(); + else + this.buildOptionList(); + }, + + loadExternalText: function() { + this.showLoadingText(this.options.loadingText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._text = transport.responseText.strip(); + this.buildOptionList(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + + buildOptionList: function() { + this._form.removeClassName(this.options.loadingClassName); + this._collection = this._collection.map(function(entry) { + return 2 === entry.length ? entry : [entry, entry].flatten(); + }); + var marker = ('value' in this.options) ? this.options.value : this._text; + var textFound = this._collection.any(function(entry) { + return entry[0] == marker; + }.bind(this)); + this._controls.editor.update(''); + var option; + this._collection.each(function(entry, index) { + option = document.createElement('option'); + option.value = entry[0]; + option.selected = textFound ? entry[0] == marker : 0 == index; + option.appendChild(document.createTextNode(entry[1])); + this._controls.editor.appendChild(option); + }.bind(this)); + this._controls.editor.disabled = false; + Field.scrollFreeActivate(this._controls.editor); + } +}); + +//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** +//**** This only exists for a while, in order to let **** +//**** users adapt to the new API. Read up on the new **** +//**** API and convert your code to it ASAP! **** + +Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { + if (!options) return; + function fallback(name, expr) { + if (name in options || expr === undefined) return; + options[name] = expr; + }; + fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : + options.cancelLink == options.cancelButton == false ? false : undefined))); + fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : + options.okLink == options.okButton == false ? false : undefined))); + fallback('highlightColor', options.highlightcolor); + fallback('highlightEndColor', options.highlightendcolor); +}; + +Object.extend(Ajax.InPlaceEditor, { + DefaultOptions: { + ajaxOptions: { }, + autoRows: 3, // Use when multi-line w/ rows == 1 + cancelControl: 'link', // 'link'|'button'|false + cancelText: 'cancel', + clickToEditText: 'Click to edit', + externalControl: null, // id|elt + externalControlOnly: false, + fieldPostCreation: 'activate', // 'activate'|'focus'|false + formClassName: 'inplaceeditor-form', + formId: null, // id|elt + highlightColor: '#ffff99', + highlightEndColor: '#ffffff', + hoverClassName: '', + htmlResponse: true, + loadingClassName: 'inplaceeditor-loading', + loadingText: 'Loading...', + okControl: 'button', // 'link'|'button'|false + okText: 'ok', + paramName: 'value', + rows: 1, // If 1 and multi-line, uses autoRows + savingClassName: 'inplaceeditor-saving', + savingText: 'Saving...', + size: 0, + stripLoadedTextTags: false, + submitOnBlur: false, + textAfterControls: '', + textBeforeControls: '', + textBetweenControls: '' + }, + DefaultCallbacks: { + callback: function(form) { + return Form.serialize(form); + }, + onComplete: function(transport, element) { + // For backward compatibility, this one is bound to the IPE, and passes + // the element directly. It was too often customized, so we don't break it. + new Effect.Highlight(element, { + startcolor: this.options.highlightColor, keepBackgroundImage: true }); + }, + onEnterEditMode: null, + onEnterHover: function(ipe) { + ipe.element.style.backgroundColor = ipe.options.highlightColor; + if (ipe._effect) + ipe._effect.cancel(); + }, + onFailure: function(transport, ipe) { + alert('Error communication with the server: ' + transport.responseText.stripTags()); + }, + onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. + onLeaveEditMode: null, + onLeaveHover: function(ipe) { + ipe._effect = new Effect.Highlight(ipe.element, { + startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, + restorecolor: ipe._originalBackground, keepBackgroundImage: true + }); + } + }, + Listeners: { + click: 'enterEditMode', + keydown: 'checkForEscapeOrReturn', + mouseover: 'enterHover', + mouseout: 'leaveHover' + } +}); + +Ajax.InPlaceCollectionEditor.DefaultOptions = { + loadingCollectionText: 'Loading options...' +}; + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create({ + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}); diff --git a/web/js/cropper.js b/web/js/cropper.js new file mode 100644 index 0000000..486a92a --- /dev/null +++ b/web/js/cropper.js @@ -0,0 +1,566 @@ +/** + * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://www.opensource.org/licenses/bsd-license.php + * + * See scriptaculous.js for full scriptaculous licence + */ + +var CropDraggable=Class.create(); +Object.extend(Object.extend(CropDraggable.prototype,Draggable.prototype),{initialize:function(_1){ +this.options=Object.extend({drawMethod:function(){ +}},arguments[1]||{}); +this.element=$(_1); +this.handle=this.element; +this.delta=this.currentDelta(); +this.dragging=false; +this.eventMouseDown=this.initDrag.bindAsEventListener(this); +Event.observe(this.handle,"mousedown",this.eventMouseDown); +Draggables.register(this); +},draw:function(_2){ +var _3=Position.cumulativeOffset(this.element); +var d=this.currentDelta(); +_3[0]-=d[0]; +_3[1]-=d[1]; +var p=[0,1].map(function(i){ +return (_2[i]-_3[i]-this.offset[i]); +}.bind(this)); +this.options.drawMethod(p); +}}); +var Cropper={}; +Cropper.Img=Class.create(); +Cropper.Img.prototype={initialize:function(_7,_8){ +this.options=Object.extend({ratioDim:{x:0,y:0},minWidth:0,minHeight:0,displayOnInit:false,onEndCrop:Prototype.emptyFunction,captureKeys:true,onloadCoords:null,maxWidth:0,maxHeight:0},_8||{}); +this.img=$(_7); +this.clickCoords={x:0,y:0}; +this.dragging=false; +this.resizing=false; +this.isWebKit=/Konqueror|Safari|KHTML/.test(navigator.userAgent); +this.isIE=/MSIE/.test(navigator.userAgent); +this.isOpera8=/Opera\s[1-8]/.test(navigator.userAgent); +this.ratioX=0; +this.ratioY=0; +this.attached=false; +this.fixedWidth=(this.options.maxWidth>0&&(this.options.minWidth>=this.options.maxWidth)); +this.fixedHeight=(this.options.maxHeight>0&&(this.options.minHeight>=this.options.maxHeight)); +if(typeof this.img=="undefined"){ +return; +} +$A(document.getElementsByTagName("script")).each(function(s){ +if(s.src.match(/cropper\.js/)){ +var _a=s.src.replace(/cropper\.js(.*)?/,""); +var _b=document.createElement("link"); +_b.rel="stylesheet"; +_b.type="text/css"; +_b.href=_a+"cropper.css"; +_b.media="screen"; +document.getElementsByTagName("head")[0].appendChild(_b); +} +}); +if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){ +var _c=this.getGCD(this.options.ratioDim.x,this.options.ratioDim.y); +this.ratioX=this.options.ratioDim.x/_c; +this.ratioY=this.options.ratioDim.y/_c; +} +this.subInitialize(); +if(this.img.complete||this.isWebKit){ +this.onLoad(); +}else{ +Event.observe(this.img,"load",this.onLoad.bindAsEventListener(this)); +} +},getGCD:function(a,b){ +if(b==0){ +return a; +} +return this.getGCD(b,a%b); +},onLoad:function(){ +var _f="imgCrop_"; +var _10=this.img.parentNode; +var _11=""; +if(this.isOpera8){ +_11=" opera8"; +} +this.imgWrap=Builder.node("div",{"class":_f+"wrap"+_11}); +this.north=Builder.node("div",{"class":_f+"overlay "+_f+"north"},[Builder.node("span")]); +this.east=Builder.node("div",{"class":_f+"overlay "+_f+"east"},[Builder.node("span")]); +this.south=Builder.node("div",{"class":_f+"overlay "+_f+"south"},[Builder.node("span")]); +this.west=Builder.node("div",{"class":_f+"overlay "+_f+"west"},[Builder.node("span")]); +var _12=[this.north,this.east,this.south,this.west]; +this.dragArea=Builder.node("div",{"class":_f+"dragArea"},_12); +this.handleN=Builder.node("div",{"class":_f+"handle "+_f+"handleN"}); +this.handleNE=Builder.node("div",{"class":_f+"handle "+_f+"handleNE"}); +this.handleE=Builder.node("div",{"class":_f+"handle "+_f+"handleE"}); +this.handleSE=Builder.node("div",{"class":_f+"handle "+_f+"handleSE"}); +this.handleS=Builder.node("div",{"class":_f+"handle "+_f+"handleS"}); +this.handleSW=Builder.node("div",{"class":_f+"handle "+_f+"handleSW"}); +this.handleW=Builder.node("div",{"class":_f+"handle "+_f+"handleW"}); +this.handleNW=Builder.node("div",{"class":_f+"handle "+_f+"handleNW"}); +this.selArea=Builder.node("div",{"class":_f+"selArea"},[Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeNorth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeEast"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeSouth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeWest"},[Builder.node("span")]),this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW,Builder.node("div",{"class":_f+"clickArea"})]); +this.imgWrap.appendChild(this.img); +this.imgWrap.appendChild(this.dragArea); +this.dragArea.appendChild(this.selArea); +this.dragArea.appendChild(Builder.node("div",{"class":_f+"clickArea"})); +_10.appendChild(this.imgWrap); +this.startDragBind=this.startDrag.bindAsEventListener(this); +Event.observe(this.dragArea,"mousedown",this.startDragBind); +this.onDragBind=this.onDrag.bindAsEventListener(this); +Event.observe(document,"mousemove",this.onDragBind); +this.endCropBind=this.endCrop.bindAsEventListener(this); +Event.observe(document,"mouseup",this.endCropBind); +this.resizeBind=this.startResize.bindAsEventListener(this); +this.handles=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW]; +this.registerHandles(true); +if(this.options.captureKeys){ +this.keysBind=this.handleKeys.bindAsEventListener(this); +Event.observe(document,"keypress",this.keysBind); +} +new CropDraggable(this.selArea,{drawMethod:this.moveArea.bindAsEventListener(this)}); +this.setParams(); +},registerHandles:function(_13){ +for(var i=0;i0&&this.options.ratioDim.y>0){ +_1a.x1=Math.ceil((this.imgW-this.options.ratioDim.x)/2); +_1a.y1=Math.ceil((this.imgH-this.options.ratioDim.y)/2); +_1a.x2=_1a.x1+this.options.ratioDim.x; +_1a.y2=_1a.y1+this.options.ratioDim.y; +_1b=true; +} +} +this.setAreaCoords(_1a,false,false,1); +if(this.options.displayOnInit&&_1b){ +this.selArea.show(); +this.drawArea(); +this.endCrop(); +} +this.attached=true; +},remove:function(){ +if(this.attached){ +this.attached=false; +this.imgWrap.parentNode.insertBefore(this.img,this.imgWrap); +this.imgWrap.parentNode.removeChild(this.imgWrap); +Event.stopObserving(this.dragArea,"mousedown",this.startDragBind); +Event.stopObserving(document,"mousemove",this.onDragBind); +Event.stopObserving(document,"mouseup",this.endCropBind); +this.registerHandles(false); +if(this.options.captureKeys){ +Event.stopObserving(document,"keypress",this.keysBind); +} +} +},reset:function(){ +if(!this.attached){ +this.onLoad(); +}else{ +this.setParams(); +} +this.endCrop(); +},handleKeys:function(e){ +var dir={x:0,y:0}; +if(!this.dragging){ +switch(e.keyCode){ +case (37): +dir.x=-1; +break; +case (38): +dir.y=-1; +break; +case (39): +dir.x=1; +break; +case (40): +dir.y=1; +break; +} +if(dir.x!=0||dir.y!=0){ +if(e.shiftKey){ +dir.x*=10; +dir.y*=10; +} +this.moveArea([this.areaCoords.x1+dir.x,this.areaCoords.y1+dir.y]); +Event.stop(e); +} +} +},calcW:function(){ +return (this.areaCoords.x2-this.areaCoords.x1); +},calcH:function(){ +return (this.areaCoords.y2-this.areaCoords.y1); +},moveArea:function(_1e){ +this.setAreaCoords({x1:_1e[0],y1:_1e[1],x2:_1e[0]+this.calcW(),y2:_1e[1]+this.calcH()},true,false); +this.drawArea(); +},cloneCoords:function(_1f){ +return {x1:_1f.x1,y1:_1f.y1,x2:_1f.x2,y2:_1f.y2}; +},setAreaCoords:function(_20,_21,_22,_23,_24){ +if(_21){ +var _25=_20.x2-_20.x1; +var _26=_20.y2-_20.y1; +if(_20.x1<0){ +_20.x1=0; +_20.x2=_25; +} +if(_20.y1<0){ +_20.y1=0; +_20.y2=_26; +} +if(_20.x2>this.imgW){ +_20.x2=this.imgW; +_20.x1=this.imgW-_25; +} +if(_20.y2>this.imgH){ +_20.y2=this.imgH; +_20.y1=this.imgH-_26; +} +}else{ +if(_20.x1<0){ +_20.x1=0; +} +if(_20.y1<0){ +_20.y1=0; +} +if(_20.x2>this.imgW){ +_20.x2=this.imgW; +} +if(_20.y2>this.imgH){ +_20.y2=this.imgH; +} +if(_23!=null){ +if(this.ratioX>0){ +this.applyRatio(_20,{x:this.ratioX,y:this.ratioY},_23,_24); +}else{ +if(_22){ +this.applyRatio(_20,{x:1,y:1},_23,_24); +} +} +var _27=[this.options.minWidth,this.options.minHeight]; +var _28=[this.options.maxWidth,this.options.maxHeight]; +if(_27[0]>0||_27[1]>0||_28[0]>0||_28[1]>0){ +var _29={a1:_20.x1,a2:_20.x2}; +var _2a={a1:_20.y1,a2:_20.y2}; +var _2b={min:0,max:this.imgW}; +var _2c={min:0,max:this.imgH}; +if((_27[0]!=0||_27[1]!=0)&&_22){ +if(_27[0]>0){ +_27[1]=_27[0]; +}else{ +if(_27[1]>0){ +_27[0]=_27[1]; +} +} +} +if((_28[0]!=0||_28[0]!=0)&&_22){ +if(_28[0]>0&&_28[0]<=_28[1]){ +_28[1]=_28[0]; +}else{ +if(_28[1]>0&&_28[1]<=_28[0]){ +_28[0]=_28[1]; +} +} +} +if(_27[0]>0){ +this.applyDimRestriction(_29,_27[0],_23.x,_2b,"min"); +} +if(_27[1]>1){ +this.applyDimRestriction(_2a,_27[1],_23.y,_2c,"min"); +} +if(_28[0]>0){ +this.applyDimRestriction(_29,_28[0],_23.x,_2b,"max"); +} +if(_28[1]>1){ +this.applyDimRestriction(_2a,_28[1],_23.y,_2c,"max"); +} +_20={x1:_29.a1,y1:_2a.a1,x2:_29.a2,y2:_2a.a2}; +} +} +} +this.areaCoords=_20; +},applyDimRestriction:function(_2d,val,_2f,_30,_31){ +var _32; +if(_31=="min"){ +_32=((_2d.a2-_2d.a1)val); +} +if(_32){ +if(_2f==1){ +_2d.a2=_2d.a1+val; +}else{ +_2d.a1=_2d.a2-val; +} +if(_2d.a1<_30.min){ +_2d.a1=_30.min; +_2d.a2=val; +}else{ +if(_2d.a2>_30.max){ +_2d.a1=_30.max-val; +_2d.a2=_30.max; +} +} +} +},applyRatio:function(_33,_34,_35,_36){ +var _37; +if(_36=="N"||_36=="S"){ +_37=this.applyRatioToAxis({a1:_33.y1,b1:_33.x1,a2:_33.y2,b2:_33.x2},{a:_34.y,b:_34.x},{a:_35.y,b:_35.x},{min:0,max:this.imgW}); +_33.x1=_37.b1; +_33.y1=_37.a1; +_33.x2=_37.b2; +_33.y2=_37.a2; +}else{ +_37=this.applyRatioToAxis({a1:_33.x1,b1:_33.y1,a2:_33.x2,b2:_33.y2},{a:_34.x,b:_34.y},{a:_35.x,b:_35.y},{min:0,max:this.imgH}); +_33.x1=_37.a1; +_33.y1=_37.b1; +_33.x2=_37.a2; +_33.y2=_37.b2; +} +},applyRatioToAxis:function(_38,_39,_3a,_3b){ +var _3c=Object.extend(_38,{}); +var _3d=_3c.a2-_3c.a1; +var _3e=Math.floor(_3d*_39.b/_39.a); +var _3f; +var _40; +var _41=null; +if(_3a.b==1){ +_3f=_3c.b1+_3e; +if(_3f>_3b.max){ +_3f=_3b.max; +_41=_3f-_3c.b1; +} +_3c.b2=_3f; +}else{ +_3f=_3c.b2-_3e; +if(_3f<_3b.min){ +_3f=_3b.min; +_41=_3f+_3c.b2; +} +_3c.b1=_3f; +} +if(_41!=null){ +_40=Math.floor(_41*_39.a/_39.b); +if(_3a.a==1){ +_3c.a2=_3c.a1+_40; +}else{ +_3c.a1=_3c.a1=_3c.a2-_40; +} +} +return _3c; +},drawArea:function(){ +var _42=this.calcW(); +var _43=this.calcH(); +var px="px"; +var _45=[this.areaCoords.x1+px,this.areaCoords.y1+px,_42+px,_43+px,this.areaCoords.x2+px,this.areaCoords.y2+px,(this.img.width-this.areaCoords.x2)+px,(this.img.height-this.areaCoords.y2)+px]; +var _46=this.selArea.style; +_46.left=_45[0]; +_46.top=_45[1]; +_46.width=_45[2]; +_46.height=_45[3]; +var _47=Math.ceil((_42-6)/2)+px; +var _48=Math.ceil((_43-6)/2)+px; +this.handleN.style.left=_47; +this.handleE.style.top=_48; +this.handleS.style.left=_47; +this.handleW.style.top=_48; +this.north.style.height=_45[1]; +var _49=this.east.style; +_49.top=_45[1]; +_49.height=_45[3]; +_49.left=_45[4]; +_49.width=_45[6]; +var _4a=this.south.style; +_4a.top=_45[5]; +_4a.height=_45[7]; +var _4b=this.west.style; +_4b.top=_45[1]; +_4b.height=_45[3]; +_4b.width=_45[0]; +this.subDrawArea(); +this.forceReRender(); +},forceReRender:function(){ +if(this.isIE||this.isWebKit){ +var n=document.createTextNode(" "); +var d,el,fixEL,i; +if(this.isIE){ +fixEl=this.selArea; +}else{ +if(this.isWebKit){ +fixEl=document.getElementsByClassName("imgCrop_marqueeSouth",this.imgWrap)[0]; +d=Builder.node("div",""); +d.style.visibility="hidden"; +var _4e=["SE","S","SW"]; +for(i=0;i<_4e.length;i++){ +el=document.getElementsByClassName("imgCrop_handle"+_4e[i],this.selArea)[0]; +if(el.childNodes.length){ +el.removeChild(el.childNodes[0]); +} +el.appendChild(d); +} +} +} +fixEl.appendChild(n); +fixEl.removeChild(n); +} +},startResize:function(e){ +this.startCoords=this.cloneCoords(this.areaCoords); +this.resizing=true; +this.resizeHandle=Event.element(e).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/,""); +Event.stop(e); +},startDrag:function(e){ +this.selArea.show(); +this.clickCoords=this.getCurPos(e); +this.setAreaCoords({x1:this.clickCoords.x,y1:this.clickCoords.y,x2:this.clickCoords.x,y2:this.clickCoords.y},false,false,null); +this.dragging=true; +this.onDrag(e); +Event.stop(e); +},getCurPos:function(e){ +var el=this.imgWrap,wrapOffsets=Position.cumulativeOffset(el); +while(el.nodeName!="BODY"){ +wrapOffsets[1]-=el.scrollTop||0; +wrapOffsets[0]-=el.scrollLeft||0; +el=el.parentNode; +} +return curPos={x:Event.pointerX(e)-wrapOffsets[0],y:Event.pointerY(e)-wrapOffsets[1]}; +},onDrag:function(e){ +if(this.dragging||this.resizing){ +var _54=null; +var _55=this.getCurPos(e); +var _56=this.cloneCoords(this.areaCoords); +var _57={x:1,y:1}; +if(this.dragging){ +if(_55.x_59){ +_5c.reverse(); +} +_5a[_5b+"1"]=_5c[0]; +_5a[_5b+"2"]=_5c[1]; +},endCrop:function(){ +this.dragging=false; +this.resizing=false; +this.options.onEndCrop(this.areaCoords,{width:this.calcW(),height:this.calcH()}); +},subInitialize:function(){ +},subDrawArea:function(){ +}}; +Cropper.ImgWithPreview=Class.create(); +Object.extend(Object.extend(Cropper.ImgWithPreview.prototype,Cropper.Img.prototype),{subInitialize:function(){ +this.hasPreviewImg=false; +if(typeof (this.options.previewWrap)!="undefined"&&this.options.minWidth>0&&this.options.minHeight>0){ +this.previewWrap=$(this.options.previewWrap); +this.previewImg=this.img.cloneNode(false); +this.previewImg.id="imgCrop_"+this.previewImg.id; +this.options.displayOnInit=true; +this.hasPreviewImg=true; +this.previewWrap.addClassName("imgCrop_previewWrap"); +this.previewWrap.setStyle({width:this.options.minWidth+"px",height:this.options.minHeight+"px"}); +this.previewWrap.appendChild(this.previewImg); +} +},subDrawArea:function(){ +if(this.hasPreviewImg){ +var _5d=this.calcW(); +var _5e=this.calcH(); +var _5f={x:this.imgW/_5d,y:this.imgH/_5e}; +var _60={x:_5d/this.options.minWidth,y:_5e/this.options.minHeight}; +var _61={w:Math.ceil(this.options.minWidth*_5f.x)+"px",h:Math.ceil(this.options.minHeight*_5f.y)+"px",x:"-"+Math.ceil(this.areaCoords.x1/_60.x)+"px",y:"-"+Math.ceil(this.areaCoords.y1/_60.y)+"px"}; +var _62=this.previewImg.style; +_62.width=_61.w; +_62.height=_61.h; +_62.left=_61.x; +_62.top=_61.y; +} +}}); + diff --git a/web/js/dragdrop.js b/web/js/dragdrop.js new file mode 100644 index 0000000..bf429c2 --- /dev/null +++ b/web/js/dragdrop.js @@ -0,0 +1,974 @@ +// script.aculo.us dragdrop.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008 + +// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +if(Object.isUndefined(Effect)) + throw("dragdrop.js requires including script.aculo.us' effects.js library"); + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || { }); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if(Object.isArray(containment)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var drop, affected = []; + + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) + drop = Droppables.findDeepestChild(affected); + + if(this.last_active && this.last_active != drop) this.deactivate(this.last_active); + if (drop) { + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + if (drop != this.last_active) Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) { + this.last_active.onDrop(element, this.last_active.element, event); + return true; + } + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +} + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + if(draggable.options.delay) { + this._timeout = setTimeout(function() { + Draggables._timeout = null; + window.focus(); + Draggables.activeDraggable = draggable; + }.bind(this), draggable.options.delay); + } else { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + } + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + } + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + if(draggable.options[eventName]) draggable.options[eventName](draggable, event); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +} + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create({ + initialize: function(element) { + var defaults = { + handle: false, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, + queue: {scope:'_draggable', position:'end'} + }); + }, + endeffect: function(element) { + var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, + queue: {scope:'_draggable', position:'end'}, + afterFinish: function(){ + Draggable._dragging[element] = false + } + }); + }, + zindex: 1000, + revert: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } + delay: 0 + }; + + if(!arguments[1] || Object.isUndefined(arguments[1].endeffect)) + Object.extend(defaults, { + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + Draggable._dragging[element] = true; + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + } + }); + + var options = Object.extend(defaults, arguments[1] || { }); + + this.element = $(element); + + if(options.handle && Object.isString(options.handle)) + this.handle = this.element.down('.'+options.handle, 0); + + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { + options.scroll = $(options.scroll); + this._isScrollChild = Element.childOf(this.element, options.scroll); + } + + Element.makePositioned(this.element); // fix IE + + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(!Object.isUndefined(Draggable._dragging[this.element]) && + Draggable._dragging[this.element]) return; + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if((tag_name = src.tagName.toUpperCase()) && ( + tag_name=='INPUT' || + tag_name=='SELECT' || + tag_name=='OPTION' || + tag_name=='BUTTON' || + tag_name=='TEXTAREA')) return; + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = Position.cumulativeOffset(this.element); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + if(!this.delta) + this.delta = this.currentDelta(); + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + this.element._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); + if (!this.element._originallyAbsolute) + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + + if(!this.options.quiet){ + Position.prepare(); + Droppables.show(pointer, this.element); + } + + Draggables.notify('onDrag', this, event); + + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft + Position.deltaX; + p[1] += this.options.scroll.scrollTop + Position.deltaY; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(Prototype.Browser.WebKit) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.quiet){ + Position.prepare(); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + Droppables.show(pointer, this.element); + } + + if(this.options.ghosting) { + if (!this.element._originallyAbsolute) + Position.relativize(this.element); + delete this.element._originallyAbsolute; + Element.remove(this._clone); + this._clone = null; + } + + var dropped = false; + if(success) { + dropped = Droppables.fire(event, this.element); + if (!dropped) dropped = false; + } + if(dropped && this.options.onDropped) this.options.onDropped(this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && Object.isFunction(revert)) revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + if (dropped == 0 || revert != 'failure') + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = Position.cumulativeOffset(this.element); + if(this.options.ghosting) { + var r = Position.realOffset(this.element); + pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; + } + + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(Object.isFunction(this.options.snap)) { + p = this.options.snap(p[0],p[1],this); + } else { + if(Object.isArray(this.options.snap)) { + p = p.map( function(v, i) { + return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this)) + } else { + p = p.map( function(v) { + return (v/this.options.snap).round()*this.options.snap }.bind(this)) + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + if(!(speed[0] || speed[1])) return; + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + if (this._isScrollChild) { + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + } + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight + } + } + return { top: T, left: L, width: W, height: H }; + } +}); + +Draggable._dragging = { }; + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create({ + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +}); + +var Sortable = { + SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, + + sortables: { }, + + _findRootElement: function(element) { + while (element.tagName.toUpperCase() != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + var s = Sortable.options(element); + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + delay: 0, + hoverclass: null, + ghosting: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: this.SERIALIZE_RULE, + + // these take arrays of elements or ids and can be + // used for better initialization performance + elements: false, + handles: false, + + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || { }); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + quiet: options.quiet, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + delay: options.delay, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + } + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + } + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (options.elements || this.findElements(element, options) || []).each( function(e,i) { + var handle = options.handles ? $(options.handles[i]) : + (options.handle ? $(e).select('.' + options.handle)[0] : e); + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.id] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Sortable._marker.hide(); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = + ($('dropmarker') || Element.extend(document.createElement('DIV'))). + hide().addClassName('dropmarker').setStyle({position:'absolute'}); + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = Position.cumulativeOffset(dropon); + Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); + else + Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); + + Sortable._marker.show(); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: [], + position: parent.children.length, + container: $(children[i]).down(options.treeTag) + } + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child) + + parent.children.push (child); + } + + return parent; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || { }); + + var root = { + id: null, + parent: null, + children: [], + container: element, + position: 0 + } + + return Sortable._tree(element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || { }); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || { }); + + var nodeMap = { }; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || { }); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "[id]=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +} + +// Returns true if child is contained within element +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + if (child.parentNode == element) return true; + return Element.isParent(child.parentNode, element); +} + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +} + +Element.offsetSize = function (element, type) { + return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; +} diff --git a/web/js/dw_cookies.js b/web/js/dw_cookies.js new file mode 100644 index 0000000..28d90f0 --- /dev/null +++ b/web/js/dw_cookies.js @@ -0,0 +1,44 @@ +/********************************************************************************* + dw_cookies.js - cookie functions for www.dyn-web.com + Recycled from various sources +**********************************************************************************/ + +// Modified from Bill Dortch's Cookie Functions (hidaho.com) +// (found in JavaScript Bible) +function setCookie(name,value,days,path,domain,secure) { + var expires, date; + if (typeof days == "number") { + date = new Date(); + date.setTime( date.getTime() + (days*24*60*60*1000) ); + expires = date.toGMTString(); + } + document.cookie = name + "=" + escape(value) + + ((expires) ? "; expires=" + expires : "") + + ((path) ? "; path=" + path : "") + + ((domain) ? "; domain=" + domain : "") + + ((secure) ? "; secure" : ""); +} + +// Modified from Jesse Chisholm or Scott Andrew Lepera ? +// (found at both www.dansteinman.com/dynapi/ and www.scottandrew.com/junkyard/js/) +function getCookie(name) { + var nameq = name + "="; + var c_ar = document.cookie.split(';'); + for (var i=0; i this.maxSize || size < this.minSize ) { + size = getCookie("fontSize"); + if ( isNaN( parseFloat(size) ) || size > this.maxSize || size < this.minSize ) { + size = this.defaultSize; + } + } + this.curSize = this.defaultSize; // create curSize property to use in calculations + sizerEl = document.getElementById('sizer'); + if (sizerEl) sizerEl.style.display = "block"; + // if neither set nor setDefaults populates adjustList, apply sizes to body and td's + if (this.adjustList.length == 0) { + this.setDefaults( this.sizeUnit, this.defaultSize, this.minSize, this.maxSize, ['body','p','li', 'span', 'label'] ); + } + if ( size != this.defaultSize ) this.adjust( size - this.defaultSize ); + }, + + adjust: function(n) { + if ( !this.curSize ) return; + var alist, size, list, i, j; + // check against max/minSize + if ( n > 0 ) { + if ( this.curSize + n > this.maxSize ) n = this.maxSize - this.curSize; + } else if ( n < 0 ) { + if ( this.curSize + n < this.minSize ) n = this.minSize - this.curSize; + } + if ( n == 0 ) return; + this.curSize += n; + // loop through adjustList, calculating size, checking max/min + alist = this.adjustList; + for (i=0; alist[i]; i++) { + size = this.curSize * alist[i]['ratio']; // maintain proportion + size = Math.max(alist[i]['min'], size); size = Math.min(alist[i]['max'], size); + list = dw_getElementsBySelector( alist[i]['sel'] ); + for (j=0; list[j]; j++) { list[j].style.fontSize = size + this.sizeUnit; } + } + setCookie( "fontSize", this.curSize, 180, "/" ); + }, + + reset: function() { + if ( !this.curSize ) return; + var alist = this.adjustList, list, i, j; + for (i=0; alist[i]; i++) { + list = dw_getElementsBySelector( alist[i]['sel'] ); + for (j=0; list[j]; j++) { + // Reset adjustList elements to their default sizes + //list[j].style.fontSize = alist[i]['dflt'] + this.sizeUnit; + list[j].style.fontSize = ''; // restores original font size + } + } + this.curSize = this.defaultSize; + deleteCookie("fontSize", "/"); + } + +}; + +// resource: simon.incutio.com/archive/2003/03/25/getElementsBySelector +function dw_getElementsBySelector(selector) { + if (!document.getElementsByTagName) return []; + var nodeList = [document], tokens, bits, list, col, els, i, j, k; + selector = selector.normalize(); + tokens = selector.split(' '); + for (i=0; tokens[i]; i++) { + if ( tokens[i].indexOf('#') != -1 ) { // id + bits = tokens[i].split('#'); + var el = document.getElementById( bits[1] ); + if (!el) return []; + if ( bits[0] ) { // check tag + if ( el.tagName.toLowerCase() != bits[0].toLowerCase() ) return []; + } + for (j=0; nodeList[j]; j++) { // check containment + if ( nodeList[j] == document || dw_contained(el, nodeList[j]) ) + nodeList = [el]; + else return []; + } + } else if ( tokens[i].indexOf('.') != -1 ) { // class + bits = tokens[i].split('.'); col = []; + for (j=0; nodeList[j]; j++) { + els = dw_getElementsByClassName( bits[1], bits[0], nodeList[j] ); + for (k=0; els[k]; k++) { col[col.length] = els[k]; } + } + nodeList = []; + for (j=0; col[j]; j++) { nodeList.push(col[j]); } + } else { // element + els = []; + for (j = 0; nodeList[j]; j++) { + list = nodeList[j].getElementsByTagName(tokens[i]); + for (k = 0; list[k]; k++) { els.push(list[k]); } + } + nodeList = els; + } + } + return nodeList; +}; + +function dw_getElementsByClassName(sClass, sTag, oCont) { + var result = [], list, i; + var re = new RegExp("\\b" + sClass + "\\b", "i"); + oCont = oCont? oCont: document; + if ( document.getElementsByTagName ) { + if ( !sTag || sTag == "*" ) { + list = oCont.all? oCont.all: oCont.getElementsByTagName("*"); + } else { + list = oCont.getElementsByTagName(sTag); + } + for (i=0; list[i]; i++) + if ( re.test( list[i].className ) ) result.push( list[i] ); + } + return result; +}; + +// 2nd arg: return whole query string if varName not found? +// (compatible with previous version, which just checked for number after ?) +function getValueFromQueryString(varName, bReturn) { + var val = ""; + if (window.location.search) { + var qStr = window.location.search.slice(1); + var ar = qStr.split("&"); + var get = [], ar2; + // portion before = becomes index (like $_GET) + for (var i=0; ar[i]; i++) { + if ( ar[i].indexOf("=") != -1 ) { + ar2 = ar[i].split("="); + get[ ar2[0] ] = ar2[1]; + } + } + val = get[varName]; + // if varName is not passed to this function or not found, return entire query string ? + if ( !val && bReturn ) { + val = qStr; + } + } + return val; +}; + +// returns true of oNode is contained by oCont (container) +function dw_contained(oNode, oCont) { + if (!oNode) return; // in case alt-tab away while hovering (prevent error) + while ( oNode = oNode.parentNode ) if ( oNode == oCont ) return true; + return false; +}; + +if (!Array.prototype.push) { // ie5.0 + Array.prototype.push = function() { + for (var i=0; arguments[i]; i++) this[this.length] = arguments[i]; + return this[this.length-1]; // return last value appended + } +}; + +String.prototype.normalize = function() { + var re = /\s\s+/g; + return this.trim().replace(re, " "); +}; + +String.prototype.trim = function() { + var re = /^\s+|\s+$/g; + return this.replace(re, ""); +}; diff --git a/web/js/effects.js b/web/js/effects.js new file mode 100644 index 0000000..b8c0259 --- /dev/null +++ b/web/js/effects.js @@ -0,0 +1,1122 @@ +// script.aculo.us effects.js v1.8.1, Thu Jan 03 22:07:12 -0500 2008 + +// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if (this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if (this.slice(0,1) == '#') { + if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if (this.length==7) color = this.toLowerCase(); + } + } + return (color.length==7 ? color : (arguments[0] || this)); +}; + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +}; + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +}; + +Element.setContentZoom = function(element, percent) { + element = $(element); + element.setStyle({fontSize: (percent/100) + 'em'}); + if (Prototype.Browser.WebKit) window.scrollBy(0,0); + return element; +}; + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +}; + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +var Effect = { + _elementDoesNotExistError: { + name: 'ElementDoesNotExistError', + message: 'The specified DOM element does not exist, but is required for this effect to operate' + }, + Transitions: { + linear: Prototype.K, + sinoidal: function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; + }, + reverse: function(pos) { + return 1-pos; + }, + flicker: function(pos) { + var pos = ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; + return pos > 1 ? 1 : pos; + }, + wobble: function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; + }, + pulse: function(pos, pulses) { + pulses = pulses || 5; + return ( + ((pos % (1/pulses)) * pulses).round() == 0 ? + ((pos * pulses * 2) - (pos * pulses * 2).floor()) : + 1 - ((pos * pulses * 2) - (pos * pulses * 2).floor()) + ); + }, + spring: function(pos) { + return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); + }, + none: function(pos) { + return 0; + }, + full: function(pos) { + return 1; + } + }, + DefaultOptions: { + duration: 1.0, // seconds + fps: 100, // 100= assume 66fps max. + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' + }, + tagifyText: function(element) { + var tagifyStyle = 'position:relative'; + if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; + + element = $(element); + $A(element.childNodes).each( function(child) { + if (child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + new Element('span', {style: tagifyStyle}).update( + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if (((typeof element == 'object') || + Object.isFunction(element)) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || { }); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, arguments[2] || { }); + Effect[element.visible() ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(Enumerable, { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = Object.isString(effect.options.queue) ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'with-last': + timestamp = this.effects.pluck('startOn').max() || timestamp; + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if (!this.interval) + this.interval = setInterval(this.loop.bind(this), 15); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if (this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + for(var i=0, len=this.effects.length;i= this.startOn) { + if (timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if (this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / this.totalTime, + frame = (pos * this.totalFrames).round(); + if (frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + cancel: function() { + if (!this.options.sync) + Effect.Queues.get(Object.isString(this.options.queue) ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if (this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + var data = $H(); + for(property in this) + if (!Object.isFunction(this[property])) data.set(property, this[property]); + return '#'; + } +}); + +Effect.Parallel = Class.create(Effect.Base, { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if (effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Tween = Class.create(Effect.Base, { + initialize: function(object, from, to) { + object = Object.isString(object) ? $(object) : object; + var args = $A(arguments), method = args.last(), + options = args.length == 5 ? args[3] : null; + this.method = Object.isFunction(method) ? method.bind(object) : + Object.isFunction(object[method]) ? object[method].bind(object) : + function(value) { object[method] = value }; + this.start(Object.extend({ from: from, to: to }, options || { })); + }, + update: function(position) { + this.method(position); + } +}); + +Effect.Event = Class.create(Effect.Base, { + initialize: function() { + this.start(Object.extend({ duration: 0 }, arguments[0] || { })); + }, + update: Prototype.emptyFunction +}); + +Effect.Opacity = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + // make this work on IE on elements without 'layout' + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || { }); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if (this.options.mode == 'absolute') { + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: (this.options.x * position + this.originalLeft).round() + 'px', + top: (this.options.y * position + this.originalTop).round() + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || { })); +}; + +Effect.Scale = Class.create(Effect.Base, { + initialize: function(element, percent) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or { } with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || { }); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = { }; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if (fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if (this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if (/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if (!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if (this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = { }; + if (this.options.scaleX) d.width = width.round() + 'px'; + if (this.options.scaleY) d.height = height.round() + 'px'; + if (this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if (this.elementPositioning == 'absolute') { + if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if (this.options.scaleY) d.top = -topd + 'px'; + if (this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if (this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { }; + if (!this.options.keepBackgroundImage) { + this.oldStyle.backgroundImage = this.element.getStyle('background-image'); + this.element.setStyle({backgroundImage: 'none'}); + } + if (!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if (!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = function(element) { + var options = arguments[1] || { }, + scrollOffsets = document.viewport.getScrollOffsets(), + elementOffsets = $(element).cumulativeOffset(), + max = (window.height || document.body.scrollHeight) - document.viewport.getHeight(); + + if (options.offset) elementOffsets[1] += options.offset; + + return new Effect.Tween(null, + scrollOffsets.top, + elementOffsets[1] > max ? max : elementOffsets[1], + options, + function(p){ scrollTo(scrollOffsets.left, p.round()) } + ); +}; + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if (effect.options.to!=0) return; + effect.element.hide().setStyle({opacity: oldOpacity}); + } + }, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from).show(); + }}, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { + opacity: element.getInlineOpacity(), + position: element.getStyle('position'), + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height + }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + Position.absolutize(effect.effects[0].element) + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().setStyle(oldStyle); } + }, arguments[1] || { }) + ); +}; + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }, arguments[1] || { }) + ); +}; + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || { })); +}; + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); + } + }) + } + }, arguments[1] || { })); +}; + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); + } + }, arguments[1] || { })); +}; + +Effect.Shake = function(element) { + element = $(element); + var options = Object.extend({ + distance: 20, + duration: 0.5 + }, arguments[1] || {}); + var distance = parseFloat(options.distance); + var split = parseFloat(options.duration) / 10.0; + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { + effect.element.undoPositioned().setStyle(oldStyle); + }}) }}) }}) }}) }}) }}); +}; + +Effect.SlideDown = function(element) { + element = $(element).cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || { }) + ); +}; + +Effect.SlideUp = function(element) { + element = $(element).cleanWhitespace(); + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); + } + }, arguments[1] || { }) + ); +}; + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, { + restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }); +}; + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide().makeClipping().makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); + } + }, options) + ) + } + }); +}; + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } + }, options) + ); +}; + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || { }; + var oldOpacity = element.getInlineOpacity(); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 2.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +}; + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + element.makeClipping(); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().setStyle(oldStyle); + } }); + }}, arguments[1] || { })); +}; + +Effect.Morph = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + style: { } + }, arguments[1] || { }); + + if (!Object.isString(options.style)) this.style = $H(options.style); + else { + if (options.style.include(':')) + this.style = options.style.parseStyle(); + else { + this.element.addClassName(options.style); + this.style = $H(this.element.getStyles()); + this.element.removeClassName(options.style); + var css = this.element.getStyles(); + this.style = this.style.reject(function(style) { + return style.value == css[style.key]; + }); + options.afterFinishInternal = function(effect) { + effect.element.addClassName(effect.options.style); + effect.transforms.each(function(transform) { + effect.element.style[transform.style] = ''; + }); + } + } + } + this.start(options); + }, + + setup: function(){ + function parseColor(color){ + if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; + color = color.parseColor(); + return $R(0,2).map(function(i){ + return parseInt( color.slice(i*2+1,i*2+3), 16 ) + }); + } + this.transforms = this.style.map(function(pair){ + var property = pair[0], value = pair[1], unit = null; + + if (value.parseColor('#zzzzzz') != '#zzzzzz') { + value = value.parseColor(); + unit = 'color'; + } else if (property == 'opacity') { + value = parseFloat(value); + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + } else if (Element.CSS_LENGTH.test(value)) { + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); + value = parseFloat(components[1]); + unit = (components.length == 3) ? components[2] : null; + } + + var originalValue = this.element.getStyle(property); + return { + style: property.camelize(), + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), + targetValue: unit=='color' ? parseColor(value) : value, + unit: unit + }; + }.bind(this)).reject(function(transform){ + return ( + (transform.originalValue == transform.targetValue) || + ( + transform.unit != 'color' && + (isNaN(transform.originalValue) || isNaN(transform.targetValue)) + ) + ) + }); + }, + update: function(position) { + var style = { }, transform, i = this.transforms.length; + while(i--) + style[(transform = this.transforms[i]).style] = + transform.unit=='color' ? '#'+ + (Math.round(transform.originalValue[0]+ + (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + + (Math.round(transform.originalValue[1]+ + (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + + (Math.round(transform.originalValue[2]+ + (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : + (transform.originalValue + + (transform.targetValue - transform.originalValue) * position).toFixed(3) + + (transform.unit === null ? '' : transform.unit); + this.element.setStyle(style, true); + } +}); + +Effect.Transform = Class.create({ + initialize: function(tracks){ + this.tracks = []; + this.options = arguments[1] || { }; + this.addTracks(tracks); + }, + addTracks: function(tracks){ + tracks.each(function(track){ + track = $H(track); + var data = track.values().first(); + this.tracks.push($H({ + ids: track.keys().first(), + effect: Effect.Morph, + options: { style: data } + })); + }.bind(this)); + return this; + }, + play: function(){ + return new Effect.Parallel( + this.tracks.map(function(track){ + var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); + var elements = [$(ids) || $$(ids)].flatten(); + return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); + }).flatten(), + this.options + ); + } +}); + +Element.CSS_PROPERTIES = $w( + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + + 'fontSize fontWeight height left letterSpacing lineHeight ' + + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + + 'right textIndent top width wordSpacing zIndex'); + +Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; + +String.__parseStyleElement = document.createElement('div'); +String.prototype.parseStyle = function(){ + var style, styleRules = $H(); + if (Prototype.Browser.WebKit) + style = new Element('div',{style:this}).style; + else { + String.__parseStyleElement.innerHTML = '
    '; + style = String.__parseStyleElement.childNodes[0].style; + } + + Element.CSS_PROPERTIES.each(function(property){ + if (style[property]) styleRules.set(property, style[property]); + }); + + if (Prototype.Browser.IE && this.include('opacity')) + styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); + + return styleRules; +}; + +if (document.defaultView && document.defaultView.getComputedStyle) { + Element.getStyles = function(element) { + var css = document.defaultView.getComputedStyle($(element), null); + return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { + styles[property] = css[property]; + return styles; + }); + }; +} else { + Element.getStyles = function(element) { + element = $(element); + var css = element.currentStyle, styles; + styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { + results[property] = css[property]; + return results; + }); + if (!styles.opacity) styles.opacity = element.getOpacity(); + return styles; + }; +}; + +Effect.Methods = { + morph: function(element, style) { + element = $(element); + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); + return element; + }, + visualEffect: function(element, effect, options) { + element = $(element) + var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[klass](element, options); + return element; + }, + highlight: function(element, options) { + element = $(element); + new Effect.Highlight(element, options); + return element; + } +}; + +$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ + 'pulsate shake puff squish switchOff dropOut').each( + function(effect) { + Effect.Methods[effect] = function(element, options){ + element = $(element); + Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); + return element; + } + } +); + +$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( + function(f) { Effect.Methods[f] = Element[f]; } +); + +Element.addMethods(Effect.Methods); diff --git a/web/js/flowPlayer.js b/web/js/flowPlayer.js new file mode 100644 index 0000000..f4e8097 --- /dev/null +++ b/web/js/flowPlayer.js @@ -0,0 +1,449 @@ +/* + * FlowPlayer external configuration file. + * + * NOTE! This file is only needed if you don't want to include all configuration + * in the embedding HTML file. Please see the installation instructions at + * http://flowpalyer.org + * + * Copyright 2005-2008 Anssi Piirainen + * + * All settings defined in this file can be alternatively defined in the + * embedding HTML object tag (as flashvars variables). Values defined in the + * object tag override values defined in this file. You could use this + * config file to provide defaults for multiple player instances that + * are used in a Web site. Individual instances can be then customized + * with their embedding HTML. + * + * Note that you should probably remove all the comments from this file + * before using it. That way the file will be smaller and will load faster. + */ +{ + /* + * Instructs the player to load the configuration from an external config file. + * This can be a abosulte URL or a relative url (relative to the HTML page + * where the player is embedded). + */ +// configFileName: 'flowPlayer.js', + + /* + * Instructs the player to load the configuration from a RTMP server. + * The player connects to the server listening in the address specified + * by this URL and calls a method 'getStreamPlayerConfig' that should return a + * valid FP configuration object. + */ +// rtmpConfigUrl: 'rtmp://localhost/myapp', + + /* + * A param value to be passed to getStreamPlayerConfig(). A value 'foobar' + * will make the player to call getStreamPlayerConfig('foobsr') + */ +// rtmpConfigParam: 'anssi', + + /* + * Name of the video file. Used if only one video is shown. + * + * Note for testing locally: Specify an empty baseURL '', if you want to load + * the video from your local disk from the directory that contains + * FlowPlayer.swf. In this case the videoFile parameter value should start + * with a slash, for example '/video.flv'. + * + * See also: 'baseURL' that affects this variable + */ +// videoFile: 'honda_accord.flv', + + /* + * Clip to be used if the file specified with 'videoFile' or any of the clips in the playlist + * was not found. The missing video clips are replaced by this clip. This can be + * an image or a FLV clip. Typically this will contain an image/video saying + * "the video you requested cannot be found.....". + * + * The syntax for the value is the same is with the clips in a playlist + * including the possibility to have start/end and duration properties. + * + * See also: 'baseURL' that affects this variable + */ + noVideoClip: { url: 'main_clickToPlay.jpg', duration: 10 }, + //noVideoClip: { url: 'MiltonFriedmanonLimi.flv' }, + + /* + * Playlist is used to publish several videos using one player instance. + * You can also have images in the playlist. The playback pauses in the + * image unless a 'duration' property is given for the image: + + * * The clips in the playlist may have following properties: + * + * name: Name for the clip to be shown in the playlist view. If this is + * not given, the clip will be hidden from the view. + * + * url: The URL used to load the clip. + * + * type: One of 'video', 'flv', 'swf', 'jpg'. Optional, determined from the URL's filename extension + * if that is present. 'video' means a video file in any format supported by Flash. + * 'flv' is present here for backward compatibility, use 'video' in new FlowPlayer installations + * now. Defaults to 'video' if the extension is not present in the URL. + * + * start: The start time (seconds) from where to start the playback. A nonzero + * value can only be used when using a streaming server!! + * end: The end time (seconds) where to stop the playback. + * + * duration: The duration the image is to be shown. If not given the playback + * pauses when the image is reached in the list. + * + * protected: (true/false) Apply inlinine linking protection for this clip? + * Optional, defaults to false. + * + * linkUrl: Associates a hyperlink pointing to the specified URL. The linked + * document will be opened to the browser when the clip area is clicked. + * Specifying this parameter will replace the normal pause/resume behavior + * that is associated to clicking the display area. If you specify an empty + * linkUrl '' the pause/resume behavior is disabled but no hyperlink + * is created. + * linkWindow: Specifies the name of the browser window or frame into which to load + * the linked document. Can be a custom name or one of presets: '_blank', + * '_parent', '_self', '_top'. (optional, defaults to '_blank') + * + * controlEnabled: (true/false) Enable transport control buttons for this clip? + * Optional, defaults to true. + * + * allowResize: (true/false) Allow resizing this clip according to the menu selection. + * Optional, defaults to true. + * + * overlay: A filename pointing to an image that will be placed on top of this image clip. This + * is only applicable to image clips (jpg or png files). Essentially this layers two images + * on top of each other. Typically the image on top is a big play button that is used on + * top of an image taken from the main movie. + * + * overlayId: ID that specifies a built-in overlay to be used. Currently the player supports + * one built-in overlay with ID 'play'. It renders a large play button with mouse hover color change. + * You can use this on top of image clips (one clip with both the 'url' property and + * 'overlayId' property). + * You can also specify a clip that only has this ID. In that + * case you should place it immediately before or after a FLV clip. This overlay-only + * clip is then rendered on top of the first or the last frame of the FLV video. + * + * live: (true/false) Is this a live stream (played from a media server)? + * + * showOnLoadBegin: (true/false) If true, make this clip visible when the fist bits have been loaded. + * If false, do not show this clip (show the background instead) before the buffer is filled + * and the playback starts. Optional, defaults to true. + * + * maxPlayCount: The maximum play count for this clip. The clip is removed from the playlist when + * the playcount reaches this amount. + * + * suggestedClipsInfoUrl: URL used to fetch suggestions (related videos) information from the server + * + * See also: 'baseURL' is prefixed with each URL + */ + playList: [ + { url: 'main_clickToPlay.jpg' }, + { name: 'Honda Accord', url: '!honda_accord.flv' }, + { name: 'River', url: 'river.flv' }, + { name: 'Ounasvaara', url: 'ounasvaara.flv' } + ], + + /* + * Specifies wether the playlist control buttons should be shown in the player SWF component or not. + * Optional, defaults to the value of showPlayList. + */ + showPlayListButtons: true, + + /* + * Streaming server connection URL. + * You don't need this with lighttpd, just use the streamingServer setting (see below) with it. + */ +// streamingServerURL: 'rtmp://localahost:oflaDemo', + + /* + * baseURL specifies the URL that is appended in front of different file names + * given in this file. + * + * You don't need to specify this at all if you place the video next to + * the player SWF file on the Web server (to be available under the same URL path). + */ +// baseURL: 'http://flowplayer.sourceforge.net/video', + + + /* + * What kind of streaming server? Available options: 'fms', 'red5', 'lighttpd' + */ +// streamingServer: 'fms', + + /* + * Specifies whether thumbnail information is contained in the FLV's cue point + * metadata. Cue points can be injected into the FLV file using + * for example Flvtool2. See the FlowPlayer web site for more info. + * (optional, defaults to false) + * + * See also: cuePoints below for an alternative way of specifying thumb metadata + */ +// thumbsOnFLV: true, + + /* + * Thumbnails specific to cue points. Use this if you don't want to + * embed thumbnail metadata into the FLV's cue points. + * If you have thumbNails defined here you should have thumbsOnFLV: false ! + * thumb times are given in seconds + */ +// thumbs: [ +// { thumbNail: 'Thumb1.jpg', time: 10 }, +// { thumbNail: 'Thumb2.jpg', time: 24 }, +// { thumbNail: 'Thumb3.jpg', time: 54 }, +// { thumbNail: 'Thumb4.jpg', time: 74 }, +// { thumbNail: 'Thumb5.jpg', time: 94 }, +// { thumbNail: 'Thumb6.jpg', time: 110 } +// ], + // Location of the thumbnail files +// thumbLocation: 'http://www.kolumbus.fi/apiirain/video', + + /* + * 'autoPlay' variable defines whether playback begins immediately or not. + * + * Note that currently with red5 you should not have false in autoPlay + * when you specify a nonzero starting position for the video clip. This is because red5 + * does not send FLV metadata when the playback starts from a nonzero value. + * + * (optional, defaults to true) + */ + autoPlay: true, + + /* + * 'autoBuffering' specifies wheter to start loading the video stream into + * buffer memory immediately. Only meaningful if 'autoPlay' is set to + * false. (optional, defaults to true) + */ + autoBuffering: true, + + /* + * 'startingBufferLength' specifies the video buffer length to be used to kick + * off the playback. This is used in the beginning of the playback and every time + * after the player has ran out of buffer memory. + * More info at: http://www.progettosinergia.com/flashvideo/flashvideoblog.htm#031205 + * (optional, defaults to the value of 'bufferLength' setting) + * + * see also: bufferLength + */ +// startingBufferLength: 5, + + /* + * 'bufferLength' specifies the video buffer length in seconds. This is used + * after the playback has started with the initial buffer length. You should + * use an arbitrary large value here to ensure stable playback. + * (optional, defaults to 10 seconds) + * + * see also: startingBufferLength + */ + bufferLength: 20, + + /* + * 'loop' defines whether the playback should loop to the first clip after + * all clips in the playlist have been shown. It is used as the + * default state of the toggle button that controls looping. (optional, + * defaults to true) + */ + loop: true, + + /* + * Rewind back to the fist clip in the playlist when end of the list has been reached? + * This option only has effect if loop is false (please see loop variable above). + * (optional, defaults to false) + */ + autoRewind: true, + + /* + * Specifies wether the loop toggle button should be shown in the player SWF component or not. + * Optional, defaults to false. + */ +// showLoopButton: true, + + /* + * Specifies the height to be allocated for the video display. This is the + * maximum height available for the different resizing options. + */ + videoHeight: 320, + + /* + * Specifies the width for the control buttons area. Optiona, defaults to the + * width setting used in the embedding code. + */ +// controlsWidth: 480, + + /* + * Specifies how the video is scaled initially. This can be then changed by + * the user through the menu. (optional, defaults to 'fit') + * Possible values: + * 'fit' Fit to window by preserving the aspect ratios encoded in the FLV metadata. + * This is the default behavior. + * 'half' Half size (preserves aspect ratios) + * 'orig' Use the dimensions encoded in FLV. If the video is too big for the + * available space the video is scaled as if using the 'fit' option. + * 'scale' Scale the video to fill all available space for the video. Ignores + * the dimensions in metadata. + * + */ + initialScale: 'fit', + + /* + * Specifies if the menu containing the size options should be shown or not. + * (optional, defaults to true) +// showMenu: false, + + /* + * 'hideControls' if set to true, hides all buttons and the progress bar + * leaving only the video showing (optional, defaults to false) + */ + hideControls: false, + + /* + * URL that specifies a base URL that points to a folder containing + * images used to skin the player. You must specify this if you intend + * to load external button images (see 'loadButtonImages' below). + */ + skinImagesBaseURL: 'http://flowplayer.sourceforge.net/resources' + + /* + * Will button images be loaded from external files, or will images embedded + * in the player SWF component be used? Set this to false if you want to "skin" + * the buttons. Optional, defaults to true. + * + * NOTE: If you set this to false, you need to have the skin images available + * on the server! Otherwise the player will not show up at all or will show + * up corrupted. + * + * See also: 'skinImagesBaseURL' that affects this variable + */ +// useEmbeddedButtonImages: false, + + /* + * 'splashImageFile' specifies an image file to be used as a splash image. + * This is useful if 'autoPlay' is set to false and you want to show a + * welcome image before the video is played. Should be in JPG format. The + * value of 'baseURL' is used similarily as with the video file name and + * therefore the video and the image files should be placed in the Web + * server next to each other. + * + * NOTE: If you set a value for this, you need to have the splash image available + * on the server! Otherwise the player will not show up at all or will show + * up corrupted. + * + * NOTE2: You can also specify the splash in a playlist. This is just + * an alternative way of doing it. It was preserved for backward compatibility. + * + * See also: 'baseURL' that affects this variable + */ +// splashImageFile: 'main_clickToPlay.jpg', + + /* + * Should the splash image be scaled to fit the entire video area? If false, + * the image will be centered. Optional, defaults to false. + */ +// scaleSplash: false, + + /* + * 'progressBarColor1' defines the color of the progress bar at the bottom + * and top edges. Specified in hexadecimal triplet form indicating the RGB + * color component values. (optional) + */ +// progressBarColor1: 0xFFFFFF, + + + /* + * 'progressBarColor2' defines the color in the middle of the progress bar. + * The value of this and 'progressBarColor1' variables define the gradient + * color fill of the progress bar. (optional) + */ +// progressBarColor2: 0xDDFFDD, + + /* + * 'bufferBarColor1' defines the color of the buffer size indicator bar at the bottom + * and top edges. (optional) + */ +// bufferBarColor1: 0xFFFFFF, + + + /* + * 'bufferBarColor2' defines the color of the buffer size indicator bar in the middle + * of the bar. (optional) + */ +// bufferBarColor2: 0xDDFFDD, + + /* + * 'progressBarBorderColor1' defines the color of the progress bar's border at the bottom + * and top edges. (optional) + */ +// progressBarBorderColor1: 0xDDDDDD, + + + /* + * 'progressBarBorderColor2' defines the color of the progress bar's border in the middle + * of the bar. (optional) + */ +// progressBarBorderColor2: 0xEEEEEE, + + /* + * 'bufferingAnimationColor' defines the color of the moving bars used in the buffering + * animation. (optional) + */ +// bufferingAnimationColor: 0x0000FF, + + /* + * 'controlsAreaBorderColor' defines the color of the border behind buttons and progress bar + * (optional) + */ +// controlsAreaBorderColor: 0x1234, + + /* + * 'timeDisplayFontColor' defines the color of the progress/duration time display + * (optional) + */ +// timeDisplayFontColor: 0xAABBCC, + + /* + * Height of the progress bar. (optional) + */ +// progressBarHeight: 10, + + /* + * Height of the progress bar area. (optional) + */ +// progressBarAreaHeight: 10, + + /* + * Name of the authentication code file name that is used to prevent inline linking + * of video and image files. This can be a complete URL or just a file name relative + * to the location from where the player is loaded. (optional, defaults to flowplayer_auth.txt) + */ +// authFileName: 'http://www.mytube.org/authCode.txt', + + /* + * The URL pointing to a sctipt that opens the player full screen. + * If this is not configured explicitly, the default script, + * http://flowplayer.sourceforge.net/fullscreen.js, is used. + */ +// fullScreenScriptURL: 'http://mysite.org/fullscreen.js' + + /** + * Specifies which menu items will be show. This is an array that contains a boolean + * value for each of the items. By default shows them all except "full screen". + */ +// menuItems[ +// true, // show 'Fit to window' +// true, // show 'Half size' +// true, // show 'Original size' +// true, // show 'Fill window' +// true, // show 'Full screen' +// false // hide 'Embed...' +// ], + + + /* + * Specifies wether the full screen button should be shown in the player SWF component or not. + * Optional, defaults to true. + */ +// showFullScreenButton: false, + + /* + * Use the Flash 9 native full screen mode. + */ +// useNativeFullScreen: true, +} + diff --git a/web/js/inlineupload.js b/web/js/inlineupload.js new file mode 100644 index 0000000..a7e8552 --- /dev/null +++ b/web/js/inlineupload.js @@ -0,0 +1,55 @@ +/** +* +* AJAX IFRAME METHOD (AIM) +* http://www.webtoolkit.info/ +* +**/ + +AIM = { + + frame : function(c) { + + var n = 'f' + Math.floor(Math.random() * 99999); + var d = document.createElement('DIV'); + d.innerHTML = ''; + document.body.appendChild(d); + + var i = document.getElementById(n); + if (c && typeof(c.onComplete) == 'function') { + i.onComplete = c.onComplete; + } + + return n; + }, + + form : function(f, name) { + f.setAttribute('target', name); + }, + + submit : function(f, c) { + AIM.form(f, AIM.frame(c)); + if (c && typeof(c.onStart) == 'function') { + return c.onStart(); + } else { + return true; + } + }, + + loaded : function(id) { + var i = document.getElementById(id); + if (i.contentDocument) { + var d = i.contentDocument; + } else if (i.contentWindow) { + var d = i.contentWindow.document; + } else { + var d = window.frames[id].document; + } + if (d.location.href == "about:blank") { + return; + } + + if (typeof(i.onComplete) == 'function') { + i.onComplete(d.body.innerHTML); + } + } +} \ No newline at end of file diff --git a/web/js/lightwindow.js b/web/js/lightwindow.js new file mode 100644 index 0000000..fbbdcc7 --- /dev/null +++ b/web/js/lightwindow.js @@ -0,0 +1,1961 @@ +// lightwindow.js v2.0 +// +// Copyright (c) 2007 stickmanlabs +// Author: Kevin P Miller | http://www.stickmanlabs.com +// +// LightWindow is freely distributable under the terms of an MIT-style license. +// +// I don't care what you think about the file size... +// Be a pro: +// http://www.thinkvitamin.com/features/webapps/serving-javascript-fast +// http://rakaz.nl/item/make_your_pages_load_faster_by_combining_and_compressing_javascript_and_css_files +// + +/*-----------------------------------------------------------------------------------------------*/ + +if(typeof Effect == 'undefined') + throw("lightwindow.js requires including script.aculo.us' effects.js library!"); + +// This will stop image flickering in IE6 when elements with images are moved +try { + document.execCommand("BackgroundImageCache", false, true); +} catch(e) {} + +var lightwindow = Class.create(); +lightwindow.prototype = { + // + // Setup Variables +// + element : null, + contentToFetch : null, + windowActive : false, + dataEffects : [], + dimensions : { + cruft : null, + container : null, + viewport : { + height : null, + width : null, + offsetTop : null, + offsetLeft : null + } + }, + pagePosition : { + x : 0, + y : 0 + }, + pageDimensions : { + width : null, + height : null + }, + preloadImage : [], + preloadedImage : [], + galleries : [], + resizeTo : { + height : null, + heightPercent : null, + width : null, + widthPercent : null, + fixedTop : null, + fixedLeft : null + }, + scrollbarOffset : 18, + navigationObservers : { + previous : null, + next : null + }, + containerChange : { + height : 0, + width : 0 + }, + activeGallery : false, + galleryLocation : { + current : 0, + total : 0 + }, + // + // Initialize the lightwindow. + // + initialize : function(options) { + this.options = Object.extend({ + resizeSpeed : 8, + contentOffset : { + height : 20, + width : 20 + }, + dimensions : { + image : {height : 250, width : 250}, + page : {height : 250, width : 250}, + inline : {height : 250, width : 250}, + media : {height : 250, width : 250}, + external : {height : 250, width : 250}, + titleHeight : 25 + }, + classNames : { + standard : 'lightwindow', + action : 'lightwindow_action' + }, + fileTypes : { + page : ['asp', 'aspx', 'cgi', 'cfm', 'htm', 'html', 'pl', 'php4', 'php3', 'php', 'php5', 'phtml', 'rhtml', 'shtml', 'txt', 'vbs', 'rb'], + media : ['aif', 'aiff', 'asf', 'avi', 'divx', 'm1v', 'm2a', 'm2v', 'm3u', 'mid', 'midi', 'mov', 'moov', 'movie', 'mp2', 'mp3', 'mpa', 'mpa', 'mpe', 'mpeg', 'mpg', 'mpg', 'mpga', 'pps', 'qt', 'rm', 'ram', 'swf', 'viv', 'vivo', 'wav'], + image : ['bmp', 'gif', 'jpg', 'png', 'tiff'] + }, + mimeTypes : { + avi : 'video/avi', + aif : 'audio/aiff', + aiff : 'audio/aiff', + gif : 'image/gif', + bmp : 'image/bmp', + jpeg : 'image/jpeg', + m1v : 'video/mpeg', + m2a : 'audio/mpeg', + m2v : 'video/mpeg', + m3u : 'audio/x-mpequrl', + mid : 'audio/x-midi', + midi : 'audio/x-midi', + mjpg : 'video/x-motion-jpeg', + moov : 'video/quicktime', + mov : 'video/quicktime', + movie : 'video/x-sgi-movie', + mp2 : 'audio/mpeg', + mp3 : 'audio/mpeg3', + mpa : 'audio/mpeg', + mpa : 'video/mpeg', + mpe : 'video/mpeg', + mpeg : 'video/mpeg', + mpg : 'audio/mpeg', + mpg : 'video/mpeg', + mpga : 'audio/mpeg', + pdf : 'application/pdf', + png : 'image/png', + pps : 'application/mspowerpoint', + qt : 'video/quicktime', + ram : 'audio/x-pn-realaudio-plugin', + rm : 'application/vnd.rn-realmedia', + swf : 'application/x-shockwave-flash', + tiff : 'image/tiff', + viv : 'video/vivo', + vivo : 'video/vivo', + wav : 'audio/wav', + wmv : 'application/x-mplayer2' + }, + classids : { + mov : 'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B', + swf : 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000', + wmv : 'clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6' + }, + codebases : { + mov : 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0', + swf : 'http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0', + wmv : 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,4,5,715' + }, + viewportPadding : 10, + EOLASFix : 'swf,wmv,fla,flv', + overlay : { + opacity : 0.7, + image : '/images/black.png', + presetImage : '/images/black-70.png' + }, + skin : { + main : '
    '+ + '
    '+ + '
    '+ + ''+ + 'close'+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + ''+ + '
    '+ + '
    '+ + ''+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    '+ + 'by '+ + '
    '+ + '
    '+ + '
    (if you are watching a slideshow, use the "left" / "right" arrow keys on your keyboard to navigate)
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    ', + loading : '
    '+ + 'loading'+ + 'Loading or Cancel'+ + ''+ + '
    ', + iframe : ''+ + ''+ + ''+ + '{body_replace}'+ + ''+ + '', + gallery : { + top : '
    '+ + '

    {gallery_title_replace}

    '+ + '
      ', + middle : '
    • '+ + '{gallery_link_replace}'+ + '
    • ', + bottom : '
    '+ + '
    ' + } + }, + formMethod : 'get', + hideFlash : false, + hideGalleryTab : false, + showTitleBar : true, + animationHandler : false, + navigationHandler : false, + transitionHandler : false, + finalAnimationHandler : false, + formHandler : false, + galleryAnimationHandler : false, + showGalleryCount : true + }, options || {}); + this.duration = ((11-this.options.resizeSpeed)*0.15); + this._setupLinks(); + this._getScroll(); + this._getPageDimensions(); + this._browserDimensions(); + this._addLightWindowMarkup(false); + this._setupDimensions(); + this.buildGalleryList(); + }, + // + // Activate the lightwindow. + // + activate : function(e, link){ + // Clear out the window Contents + this._clearWindowContents(true); + + // Add back in out loading panel + this._addLoadingWindowMarkup(); + + // Setup the element properties + this._setupWindowElements(link); + + // Setup everything + this._getScroll(); + this._browserDimensions(); + this._setupDimensions(); + this._toggleTroubleElements('hidden', false); + this._displayLightWindow('block', 'hidden'); + this._setStatus(true); + this._monitorKeyboard(true); + this._prepareIE(true); + this._loadWindow(); + }, + // + // Turn off the window + // + deactivate : function(){ + // The window is not active + this.windowActive = false; + + // There is no longer a gallery active + this.activeGallery = false; + if (!this.options.hideGalleryTab) { + this._handleGalleryAnimation(false); + } + + // Kill the animation + this.animating = false; + + // Clear our element + this.element = null; + + // hide the window. + this._displayLightWindow('none', 'visible'); + + // Clear out the window Contents + this._clearWindowContents(false); + + // Stop all animation + var queue = Effect.Queues.get('lightwindowAnimation').each(function(e){e.cancel();}); + + // Undo the setup + this._prepareIE(false); + this._setupDimensions(); + this._toggleTroubleElements('visible', false); + this._monitorKeyboard(false); + }, + // + // Initialize specific window + // + createWindow : function(element, attributes) { + this._processLink($(element)); + }, + // + // Open a Window from a hash of attributes + // + activateWindow : function(options) { + this.element = Object.extend({ + href : null, + title : null, + author : null, + author_by_text : null, + caption : null, + helptext : null, + closetext : null, + rel : null, + top : null, + left : null, + type : null, + showImages : null, + height : null, + width : null, + loadingAnimation : null, + iframeEmbed : null, + form : null + }, options || {}); + + // Set the window type + this.contentToFetch = this.element.href; + this.windowType = this.element.type ? this.element.type : this._fileType(this.element.href); + + // Clear out the window Contents + this._clearWindowContents(true); + + // Add back in out loading panel + this._addLoadingWindowMarkup(); + + // Setup everything + this._getScroll(); + this._browserDimensions(); + this._setupDimensions(); + this._toggleTroubleElements('hidden', false); + this._displayLightWindow('block', 'hidden'); + this._setStatus(true); + this._monitorKeyboard(true); + this._prepareIE(true); + this._loadWindow(); + }, + // + // Fire off our Form handler + // + submitForm : function(e) { + if (this.options.formHandler) { + this.options.formHandler(e); + } else { + this._defaultFormHandler(e); + } + }, + // + // Reload the window with another location + // + openWindow : function(element) { + var element = $(element); + + // The window is active + this.windowActive = true; + + // Clear out the window Contents + this._clearWindowContents(true); + + // Add back in out loading panel + this._addLoadingWindowMarkup(); + + // Setup the element properties + this._setupWindowElements(element); + + this._setStatus(true); + this._handleTransition(); + }, + // + // Navigate the window + // + navigateWindow : function(direction) { + this._handleNavigation(false); + if (direction == 'previous') { + this.openWindow(this.navigationObservers.previous); + } else if (direction == 'next'){ + this.openWindow(this.navigationObservers.next); + } + }, + // + // Build the Gallery List and Load it + // + buildGalleryList : function() { + var output = ''; + var galleryLink; + for (i in this.galleries) { + if (typeof this.galleries[i] == 'object') { + output += (this.options.skin.gallery.top).replace('{gallery_title_replace}', unescape(i)); + for (j in this.galleries[i]) { + if (typeof this.galleries[i][j] == 'object') { + galleryLink = ''+unescape(j)+''; + output += (this.options.skin.gallery.middle).replace('{gallery_link_replace}', galleryLink); + } + } + output += this.options.skin.gallery.bottom; + } + } + new Insertion.Top('lightwindow_galleries_list', output); + + // Attach Events + for (i in this.galleries) { + if (typeof this.galleries[i] == 'object') { + for (j in this.galleries[i]) { + if (typeof this.galleries[i][j] == 'object') { + Event.observe($('lightwindow_gallery_'+i+'_'+j), 'click', this.openWindow.bind(this, this.galleries[i][j][0]), false); + $('lightwindow_gallery_'+i+'_'+j).onclick = function() {return false;}; + } + } + } + } + }, + // + // Set Links Up + // + _setupLinks : function() { + var links = $$('.'+this.options.classNames.standard); + links.each(function(link) { + this._processLink(link); + }.bind(this)); + }, + // + // Process a Link + // + _processLink : function(link) { + if ((this._fileType(link.getAttribute('href')) == 'image' || this._fileType(link.getAttribute('href')) == 'media')) { + if (gallery = this._getGalleryInfo(link.rel)) { + if (!this.galleries[gallery[0]]) { + this.galleries[gallery[0]] = new Array(); + } + if (!this.galleries[gallery[0]][gallery[1]]) { + this.galleries[gallery[0]][gallery[1]] = new Array(); + } + this.galleries[gallery[0]][gallery[1]].push(link); + } + } + + // Take care of our inline content + var url = link.getAttribute('href'); + if (url.indexOf('?') > -1) { + url = url.substring(0, url.indexOf('?')); + } + + var container = url.substring(url.indexOf('#')+1); + if($(container)) { + $(container).setStyle({ + display : 'none' + }); + } + + Event.observe(link, 'click', this.activate.bindAsEventListener(this, link), false); + link.onclick = function() {return false;}; + }, + // + // Setup our actions + // + _setupActions : function() { + var links = $$('#lightwindow_container .'+this.options.classNames.action); + links.each(function(link) { + Event.observe(link, 'click', this[link.getAttribute('rel')].bindAsEventListener(this, link), false); + link.onclick = function() {return false;}; + }.bind(this)); + }, + // + // Add the markup to the page. + // + _addLightWindowMarkup : function(rebuild) { + var overlay = Element.extend(document.createElement('div')); + overlay.setAttribute('id', 'lightwindow_overlay'); + // FF Mac has a problem with putting Flash above a layer without a 100% opacity background, so we need to use a pre-made + if (Prototype.Browser.Gecko) { + overlay.setStyle({ + backgroundImage: 'url('+this.options.overlay.presetImage+')', + backgroundRepeat: 'repeat', + height: this.pageDimensions.height+'px' + }); + } else { + overlay.setStyle({ + opacity: this.options.overlay.opacity, + backgroundImage: 'url('+this.options.overlay.image+')', + backgroundRepeat: 'repeat', + height: this.pageDimensions.height+'px' + }); + } + + var lw = document.createElement('div'); + lw.setAttribute('id', 'lightwindow'); + lw.innerHTML = this.options.skin.main; + + var body = document.getElementsByTagName('body')[0]; + body.appendChild(overlay); + body.appendChild(lw); + + if ($('lightwindow_title_bar_close_link')) { + Event.observe('lightwindow_title_bar_close_link', 'click', this.deactivate.bindAsEventListener(this)); + $('lightwindow_title_bar_close_link').onclick = function() {return false;}; + } + + Event.observe($('lightwindow_previous'), 'click', this.navigateWindow.bind(this, 'previous'), false); + $('lightwindow_previous').onclick = function() {return false;}; + Event.observe($('lightwindow_next'), 'click', this.navigateWindow.bind(this, 'next'), false); + $('lightwindow_next').onclick = function() {return false;}; + + if (!this.options.hideGalleryTab) { + Event.observe($('lightwindow_galleries_tab'), 'click', this._handleGalleryAnimation.bind(this, true), false); + $('lightwindow_galleries_tab').onclick = function() {return false;}; + } + + // Because we use position absolute, kill the scroll Wheel on animations + if (Prototype.Browser.IE) { + Event.observe(document, 'mousewheel', this._stopScrolling.bindAsEventListener(this), false); + } else { + Event.observe(window, 'DOMMouseScroll', this._stopScrolling.bindAsEventListener(this), false); + } + + Event.observe(overlay, 'click', this.deactivate.bindAsEventListener(this), false); + overlay.onclick = function() {return false;}; + }, + // + // Add loading window markup + // + _addLoadingWindowMarkup : function() { + $('lightwindow_contents').innerHTML += this.options.skin.loading; + }, + // + // Setup the window elements + // + _setupWindowElements : function(link) { + this.element = link; + this.element.title = null ? '' : link.getAttribute('title'); + this.element.author = null ? '' : link.getAttribute('author'); + this.element.author_by_text = null ? 'by' : link.getAttribute('author_by_text'); + this.element.caption = null ? '' : link.getAttribute('caption'); + this.element.rel = null ? '' : link.getAttribute('rel'); + this.element.helptext = null ? '' : link.getAttribute('helptext'); + this.element.closetext = null ? '' : link.getAttribute('closetext'); + this.element.params = null ? '' : link.getAttribute('params'); + + // Set the window type + this.contentToFetch = this.element.href; + this.windowType = this._getParameter('lightwindow_type') ? this._getParameter('lightwindow_type') : this._fileType(this.contentToFetch); + }, + // + // Clear the window contents out + // + _clearWindowContents : function(contents) { + // If there is an iframe, its got to go + if ($('lightwindow_iframe')) { + Element.remove($('lightwindow_iframe')); + } + + // Stop playing an object if its still around + if ($('lightwindow_media_primary')) { + try { + $('lightwindow_media_primary').Stop(); + } catch(e) {} + Element.remove($('lightwindow_media_primary')); + } + + // Stop playing an object if its still around + if ($('lightwindow_media_secondary')) { + try { + $('lightwindow_media_secondary').Stop(); + } catch(e) {} + Element.remove($('lightwindow_media_secondary')); + } + + this.activeGallery = false; + this._handleNavigation(this.activeGallery); + + if (contents) { + // Empty the contents + $('lightwindow_contents').innerHTML = ''; + + // Reset the scroll bars + $('lightwindow_contents').setStyle({ + overflow: 'hidden' + }); + + if (!this.windowActive) { + $('lightwindow_data_slide_inner').setStyle({ + display: 'none' + }); + + $('lightwindow_title_bar_title').innerHTML = ''; + } + + // Because of browser differences and to maintain flexible captions we need to reset this height at close + $('lightwindow_data_slide').setStyle({ + height: 'auto' + }); + } + + this.resizeTo.height = null; + this.resizeTo.width = null; + }, + // + // Set the status of our animation to keep things from getting clunky + // + _setStatus : function(status) { + this.animating = status; + if (status) { + Element.show('lightwindow_loading'); + } + if (!(/MSIE 6./i.test(navigator.userAgent))) { + this._fixedWindow(status); + } + }, + // + // Make this window Fixed + // + _fixedWindow : function(status) { + if (status) { + if (this.windowActive) { + this._getScroll(); + $('lightwindow').setStyle({ + position: 'absolute', + top: parseFloat($('lightwindow').getStyle('top'))+this.pagePosition.y+'px', + left: parseFloat($('lightwindow').getStyle('left'))+this.pagePosition.x+'px' + }); + } else { + $('lightwindow').setStyle({ + position: 'absolute' + }); + } + } else { + if (this.windowActive) { + this._getScroll(); + $('lightwindow').setStyle({ + position: 'fixed', + top: parseFloat($('lightwindow').getStyle('top'))-this.pagePosition.y+'px', + left: parseFloat($('lightwindow').getStyle('left'))-this.pagePosition.x+'px' + }); + } else { + if ($('lightwindow_iframe')) { + // Ideally here we would set a 50% value for top and left, but Safari rears it ugly head again and we need to do it by pixels + this._browserDimensions(); + } + $('lightwindow').setStyle({ + position: 'fixed', + top: (parseFloat(this._getParameter('lightwindow_top')) ? parseFloat(this._getParameter('lightwindow_top'))+'px' : this.dimensions.viewport.height/2+'px'), + left: (parseFloat(this._getParameter('lightwindow_left')) ? parseFloat(this._getParameter('lightwindow_left'))+'px' : this.dimensions.viewport.width/2+'px') + }); + } + } + }, + // + // Prepare the window for IE. + // + _prepareIE : function(setup) { + if (Prototype.Browser.IE) { + var height, overflowX, overflowY; + if (setup) { + var height = '100%'; + } else { + var height = 'auto'; + } + var body = document.getElementsByTagName('body')[0]; + var html = document.getElementsByTagName('html')[0]; + html.style.height = body.style.height = height; + } + }, + _stopScrolling : function(e) { + if (this.animating) { + if (e.preventDefault) { + e.preventDefault(); + } + e.returnValue = false; + } + }, + // + // Get the scroll for the page. + // + _getScroll : function(){ + if(typeof(window.pageYOffset) == 'number') { + this.pagePosition.x = window.pageXOffset; + this.pagePosition.y = window.pageYOffset; + } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) { + this.pagePosition.x = document.body.scrollLeft; + this.pagePosition.y = document.body.scrollTop; + } else if(document.documentElement) { + this.pagePosition.x = document.documentElement.scrollLeft; + this.pagePosition.y = document.documentElement.scrollTop; + } + }, + // + // Reset the scroll. + // + _setScroll : function(x, y) { + document.documentElement.scrollLeft = x; + document.documentElement.scrollTop = y; + }, + // + // Hide Selects from the page because of IE. + // We could use iframe shims instead here but why add all the extra markup for one browser when this is much easier and cleaner + // + _toggleTroubleElements : function(visibility, content){ + + if (content) { + var selects = $('lightwindow_contents').getElementsByTagName('select'); + } else { + var selects = document.getElementsByTagName('select'); + } + + for(var i = 0; i < selects.length; i++) { + selects[i].style.visibility = visibility; + } + + if (!content) { + if (this.options.hideFlash){ + var objects = document.getElementsByTagName('object'); + for (i = 0; i != objects.length; i++) { + objects[i].style.visibility = visibility; + } + var embeds = document.getElementsByTagName('embed'); + for (i = 0; i != embeds.length; i++) { + embeds[i].style.visibility = visibility; + } + } + var iframes = document.getElementsByTagName('iframe'); + for (i = 0; i != iframes.length; i++) { + iframes[i].style.visibility = visibility; + } + } + }, + // + // Get the actual page size + // + _getPageDimensions : function() { + var xScroll, yScroll; + if (window.innerHeight && window.scrollMaxY) { + xScroll = document.body.scrollWidth; + yScroll = window.innerHeight + window.scrollMaxY; + } else if (document.body.scrollHeight > document.body.offsetHeight){ + xScroll = document.body.scrollWidth; + yScroll = document.body.scrollHeight; + } else { + xScroll = document.body.offsetWidth; + yScroll = document.body.offsetHeight; + } + + var windowWidth, windowHeight; + if (self.innerHeight) { + windowWidth = self.innerWidth; + windowHeight = self.innerHeight; + } else if (document.documentElement && document.documentElement.clientHeight) { + windowWidth = document.documentElement.clientWidth; + windowHeight = document.documentElement.clientHeight; + } else if (document.body) { + windowWidth = document.body.clientWidth; + windowHeight = document.body.clientHeight; + } + + if(yScroll < windowHeight){ + this.pageDimensions.height = windowHeight; + } else { + this.pageDimensions.height = yScroll; + } + + if(xScroll < windowWidth){ + this.pageDimensions.width = windowWidth; + } else { + this.pageDimensions.width = xScroll; + } + }, + // + // Display the lightWindow. + // + _displayLightWindow : function(display, visibility) { + $('lightwindow_overlay').style.display = $('lightwindow').style.display = $('lightwindow_container').style.display = display; + $('lightwindow_overlay').style.visibility = $('lightwindow').style.visibility = $('lightwindow_container').style.visibility = visibility; + }, + // + // Setup Dimensions of lightwindow. + + // + _setupDimensions : function() { + + var originalHeight, originalWidth; + switch (this.windowType) { + case 'page' : + originalHeight = this.options.dimensions.page.height; + originalWidth = this.options.dimensions.page.width; + break; + + case 'image' : + originalHeight = this.options.dimensions.image.height; + originalWidth = this.options.dimensions.image.width; + break; + + case 'media' : + originalHeight = this.options.dimensions.media.height; + originalWidth = this.options.dimensions.media.width; + break; + + case 'external' : + originalHeight = this.options.dimensions.external.height; + originalWidth = this.options.dimensions.external.width; + break; + + case 'inline' : + originalHeight = this.options.dimensions.inline.height; + originalWidth = this.options.dimensions.inline.width; + break; + + default : + originalHeight = this.options.dimensions.page.height; + originalWidth = this.options.dimensions.page.width; + break; + + } + + var offsetHeight = this._getParameter('lightwindow_top') ? parseFloat(this._getParameter('lightwindow_top'))+this.pagePosition.y : this.dimensions.viewport.height/2+this.pagePosition.y; + var offsetWidth = this._getParameter('lightwindow_left') ? parseFloat(this._getParameter('lightwindow_left'))+this.pagePosition.x : this.dimensions.viewport.width/2+this.pagePosition.x; + + // So if a theme has say shadowed edges, they should be consistant and take care of in the contentOffset + $('lightwindow').setStyle({ + top: offsetHeight+'px', + left: offsetWidth+'px' + }); + + $('lightwindow_container').setStyle({ + height: originalHeight+'px', + width: originalWidth+'px', + left: -(originalWidth/2)+'px', + top: -(originalHeight/2)+'px' + }); + + $('lightwindow_contents').setStyle({ + height: originalHeight+'px', + width: originalWidth+'px' + }); + }, + // + // Get the type of file. + // + _fileType : function(url) { + var image = new RegExp("[^\.]\.("+this.options.fileTypes.image.join('|')+")\s*$", "i"); + if (image.test(url)) return 'image'; + if (url.indexOf('#') > -1 && (document.domain == this._getDomain(url))) return 'inline'; + if (url.indexOf('?') > -1) url = url.substring(0, url.indexOf('?')); + var type = 'unknown'; + var page = new RegExp("[^\.]\.("+this.options.fileTypes.page.join('|')+")\s*$", "i"); + var media = new RegExp("[^\.]\.("+this.options.fileTypes.media.join('|')+")\s*$", "i"); + if (document.domain != this._getDomain(url)) type = 'external'; + if (media.test(url)) type = 'media'; + if (type == 'external' || type == 'media') return type; + if (page.test(url) || url.substr((url.length-1), url.length) == '/') type = 'page'; + return type; + }, + // + // Get file Extension + // + _fileExtension : function(url) { + if (url.indexOf('?') > -1) { + url = url.substring(0, url.indexOf('?')); + } + var extenstion = ''; + for (var x = (url.length-1); x > -1; x--) { + if (url.charAt(x) == '.') { + return extenstion; + } + extenstion = url.charAt(x)+extenstion; + } + }, + // + // Monitor the keyboard while this lightwindow is up + // + _monitorKeyboard : function(status) { + if (status) document.onkeydown = this._eventKeypress.bind(this); + else document.onkeydown = ''; + }, + // + // Perform keyboard actions + // + _eventKeypress : function(e) { + if (e == null) { + var keycode = event.keyCode; + } else { + var keycode = e.which; + } + + switch (keycode) { + case 27: + this.deactivate(); + break; + + case 13: + return; + + default: + break; + } + + // Gotta stop those quick fingers + if (this.animating) { + return false; + } + + switch (keycode) { + case 37: // left key + if (this.navigationObservers.previous) { + this.navigateWindow('previous'); + } + break; + + case 39: // right key + if (this.navigationObservers.next) { + this.navigateWindow('next'); + } + break; + + default: + break; + } + + switch (String.fromCharCode(keycode).toLowerCase()) { + case 'p': + if (this.navigationObservers.previous) { + this.navigateWindow('previous'); + } + break; + + case 'n': + if (this.navigationObservers.next) { + this.navigateWindow('next'); + } + break; + + default: + break; + } + }, + // + // Get Gallery Information + // + _getGalleryInfo : function(rel) { + if (!rel) return false; + if (rel.indexOf('[') > -1) { + return new Array(escape(rel.substring(0, rel.indexOf('['))), escape(rel.substring(rel.indexOf('[')+1, rel.indexOf(']')))); + } else { + return false; + } + }, + // + // Get the domain from a string. + // + _getDomain : function(url) { + var leadSlashes = url.indexOf('//'); + var domainStart = leadSlashes+2; + var withoutResource = url.substring(domainStart, url.length); + var nextSlash = withoutResource.indexOf('/'); + var domain = withoutResource.substring(0, nextSlash); + if (domain.indexOf(':') > -1){ + var portColon = domain.indexOf(':'); + domain = domain.substring(0, portColon); + } + return domain; + }, + // + // Get the value from the params attribute string. + // + _getParameter : function(parameter, parameters) { + if (!this.element) return false; + if (parameter == 'lightwindow_top' && this.element.top) { + return unescape(this.element.top); + } else if (parameter == 'lightwindow_left' && this.element.left) { + return unescape(this.element.left); + } else if (parameter == 'lightwindow_type' && this.element.type) { + return unescape(this.element.type); + } else if (parameter == 'lightwindow_show_images' && this.element.showImages) { + return unescape(this.element.showImages); + } else if (parameter == 'lightwindow_height' && this.element.height) { + return unescape(this.element.height); + } else if (parameter == 'lightwindow_width' && this.element.width) { + return unescape(this.element.width); + } else if (parameter == 'lightwindow_loading_animation' && this.element.loadingAnimation) { + return unescape(this.element.loadingAnimation); + } else if (parameter == 'lightwindow_iframe_embed' && this.element.iframeEmbed) { + return unescape(this.element.iframeEmbed); + } else if (parameter == 'lightwindow_form' && this.element.form) { + return unescape(this.element.form); + } else { + if (!parameters) { + if (this.element.params) parameters = this.element.params; + else return; + } + var value; + var parameterArray = parameters.split(','); + var compareString = parameter+'='; + var compareLength = compareString.length; + for (var i = 0; i < parameterArray.length; i++) { + if (parameterArray[i].substr(0, compareLength) == compareString) { + var currentParameter = parameterArray[i].split('='); + value = currentParameter[1]; + break; + } + } + if (!value) return false; + else return unescape(value); + } + }, + // + // Get the Browser Viewport Dimensions + // + _browserDimensions : function() { + if (Prototype.Browser.IE) { + this.dimensions.viewport.height = document.documentElement.clientHeight; + this.dimensions.viewport.width = document.documentElement.clientWidth; + } else { + this.dimensions.viewport.height = window.innerHeight; + this.dimensions.viewport.width = document.width || document.body.offsetWidth; + } + }, + // + // Get the scrollbar offset, I don't like this method but there is really no other way I can find. + // + _getScrollerWidth : function() { + var scrollDiv = Element.extend(document.createElement('div')); + scrollDiv.setAttribute('id', 'lightwindow_scroll_div'); + scrollDiv.setStyle({ + position: 'absolute', + top: '-10000px', + left: '-10000px', + width: '100px', + height: '100px', + overflow: 'hidden' + }); + + + + var contentDiv = Element.extend(document.createElement('div')); + contentDiv.setAttribute('id', 'lightwindow_content_scroll_div'); + contentDiv.setStyle({ + width: '100%', + height: '200px' + }); + + scrollDiv.appendChild(contentDiv); + + var body = document.getElementsByTagName('body')[0]; + body.appendChild(scrollDiv); + + var noScroll = $('lightwindow_content_scroll_div').offsetWidth; + scrollDiv.style.overflow = 'auto'; + var withScroll = $('lightwindow_content_scroll_div').offsetWidth; + + Element.remove($('lightwindow_scroll_div')); + + this.scrollbarOffset = noScroll-withScroll; + }, + + + // + // Add a param to an object dynamically created + // + _addParamToObject : function(name, value, object, id) { + var param = document.createElement('param'); + param.setAttribute('value', value); + param.setAttribute('name', name); + if (id) { + param.setAttribute('id', id); + } + object.appendChild(param); + return object; + }, + // + // Get the outer HTML of an object CROSS BROWSER + // + _outerHTML : function(object) { + if (Prototype.Browser.IE) { + return object.outerHTML; + } else { + var clone = object.cloneNode(true); + var cloneDiv = document.createElement('div'); + cloneDiv.appendChild(clone); + return cloneDiv.innerHTML; + } + }, + // + // Convert an object to markup + // + _convertToMarkup : function(object, closeTag) { + var markup = this._outerHTML(object).replace('', ''); + if (Prototype.Browser.IE) { + for (var i = 0; i < object.childNodes.length; i++){ + markup += this._outerHTML(object.childNodes[i]); + } + markup += ''; + } + return markup; + }, + // + // Depending what type of browser it is we have to append the object differently... DAMN YOU IE!! + // + _appendObject : function(object, closeTag, appendTo) { + if (Prototype.Browser.IE) { + appendTo.innerHTML += this._convertToMarkup(object, closeTag); + + // Fix the Eolas activate thing but only for specified media, for example doing this to a quicktime film breaks it. + if (this.options.EOLASFix.indexOf(this._fileType(this.element.href)) > -1) { + var objectElements = document.getElementsByTagName('object'); + for (var i = 0; i < objectElements.length; i++) { + if (objectElements[i].getAttribute("data")) objectElements[i].removeAttribute('data'); + objectElements[i].outerHTML = objectElements[i].outerHTML; + objectElements[i].style.visibility = "visible"; + } + } + } else { + appendTo.appendChild(object); + } + }, + // + // Add in iframe + // + _appendIframe : function(scroll) { + var iframe = document.createElement('iframe'); + iframe.setAttribute('id', 'lightwindow_iframe'); + iframe.setAttribute('name', 'lightwindow_iframe'); + iframe.setAttribute('src', 'about:blank'); + iframe.setAttribute('height', '100%'); + iframe.setAttribute('width', '100%'); + iframe.setAttribute('frameborder', '0'); + iframe.setAttribute('marginwidth', '0'); + iframe.setAttribute('marginheight', '0'); + iframe.setAttribute('scrolling', scroll); + + this._appendObject(iframe, 'iframe', $('lightwindow_contents')); + }, + // + // Write Content to the iframe using the skin + // + _writeToIframe : function(content) { + var template = this.options.skin.iframe; + template = template.replace('{body_replace}', content); + if ($('lightwindow_iframe').contentWindow){ + $('lightwindow_iframe').contentWindow.document.open(); + $('lightwindow_iframe').contentWindow.document.write(template); + $('lightwindow_iframe').contentWindow.document.close(); + } else { + $('lightwindow_iframe').contentDocument.open(); + $('lightwindow_iframe').contentDocument.write(template); + $('lightwindow_iframe').contentDocument.close(); + } + }, + // + // Load the window Information + // + _loadWindow : function() { + switch (this.windowType) { + case 'image' : + + var current = 0; + var images = []; + this.checkImage = []; + this.resizeTo.height = this.resizeTo.width = 0; + this.imageCount = this._getParameter('lightwindow_show_images') ? parseInt(this._getParameter('lightwindow_show_images')) : 1; + + // If there is a gallery get it + if (gallery = this._getGalleryInfo(this.element.rel)) { + for (current = 0; current < this.galleries[gallery[0]][gallery[1]].length; current++) { + if (this.contentToFetch.indexOf(this.galleries[gallery[0]][gallery[1]][current].href) > -1) { + break; + } + } + if (this.galleries[gallery[0]][gallery[1]][current-this.imageCount]) { + this.navigationObservers.previous = this.galleries[gallery[0]][gallery[1]][current-this.imageCount]; + } else { + this.navigationObservers.previous = false; + } + if (this.galleries[gallery[0]][gallery[1]][current+this.imageCount]) { + this.navigationObservers.next = this.galleries[gallery[0]][gallery[1]][current+this.imageCount]; + } else { + this.navigationObservers.next = false; + } + + this.activeGallery = true; + } else { + this.navigationObservers.previous = false; + this.navigationObservers.next = false; + + this.activeGallery = false; + } + + for (var i = current; i < (current+this.imageCount); i++) { + + if (gallery && this.galleries[gallery[0]][gallery[1]][i]) { + this.contentToFetch = this.galleries[gallery[0]][gallery[1]][i].href; + + this.galleryLocation = {current: (i+1)/this.imageCount, total: (this.galleries[gallery[0]][gallery[1]].length)/this.imageCount}; + + if (!this.galleries[gallery[0]][gallery[1]][i+this.imageCount]) { + $('lightwindow_next').setStyle({ + display: 'none' + }); + } else { + $('lightwindow_next').setStyle({ + display: 'block' + }); + $('lightwindow_next_title').innerHTML = this.galleries[gallery[0]][gallery[1]][i+this.imageCount].title; + } + + if (!this.galleries[gallery[0]][gallery[1]][i-this.imageCount]) { + $('lightwindow_previous').setStyle({ + display: 'none' + }); + } else { + $('lightwindow_previous').setStyle({ + display: 'block' + }); + $('lightwindow_previous_title').innerHTML = this.galleries[gallery[0]][gallery[1]][i-this.imageCount].title; + } + } + + images[i] = document.createElement('img'); + images[i].setAttribute('id', 'lightwindow_image_'+i); + images[i].setAttribute('border', '0'); + images[i].setAttribute('src', this.contentToFetch); + $('lightwindow_contents').appendChild(images[i]); + + // We have to do this instead of .onload + this.checkImage[i] = new PeriodicalExecuter(function(i) { + if (!(typeof $('lightwindow_image_'+i).naturalWidth != "undefined" && $('lightwindow_image_'+i).naturalWidth == 0)) { + + this.checkImage[i].stop(); + + var imageHeight = $('lightwindow_image_'+i).getHeight(); + if (imageHeight > this.resizeTo.height) { + this.resizeTo.height = imageHeight; + } + this.resizeTo.width += $('lightwindow_image_'+i).getWidth(); + if (this.resizeTo.width < 200) + { + this.resizeTo.width = 200; + } + this.imageCount--; + + $('lightwindow_image_'+i).setStyle({ + height: '100%' + }); + + if (this.imageCount == 0) { + this._processWindow(); + } + } + + }.bind(this, i), 1); + } + + + break; + + case 'media' : + + var current = 0; + this.resizeTo.height = this.resizeTo.width = 0; + + // If there is a gallery get it + if (gallery = this._getGalleryInfo(this.element.rel)) { + for (current = 0; current < this.galleries[gallery[0]][gallery[1]].length; current++) { + if (this.contentToFetch.indexOf(this.galleries[gallery[0]][gallery[1]][current].href) > -1) { + break; + } + } + + if (this.galleries[gallery[0]][gallery[1]][current-1]) { + this.navigationObservers.previous = this.galleries[gallery[0]][gallery[1]][current-1]; + } else { + this.navigationObservers.previous = false; + } + if (this.galleries[gallery[0]][gallery[1]][current+1]) { + this.navigationObservers.next = this.galleries[gallery[0]][gallery[1]][current+1]; + } else { + this.navigationObservers.next = false; + } + + this.activeGallery = true; + } else { + this.navigationObservers.previous = false; + this.navigationObservers.next = false; + + this.activeGallery = false; + } + + + if (gallery && this.galleries[gallery[0]][gallery[1]][current]) { + this.contentToFetch = this.galleries[gallery[0]][gallery[1]][current].href; + + this.galleryLocation = {current: current+1, total: this.galleries[gallery[0]][gallery[1]].length}; + + if (!this.galleries[gallery[0]][gallery[1]][current+1]) { + $('lightwindow_next').setStyle({ + display: 'none' + }); + } else { + $('lightwindow_next').setStyle({ + display: 'block' + }); + $('lightwindow_next_title').innerHTML = this.galleries[gallery[0]][gallery[1]][current+1].title; + } + + if (!this.galleries[gallery[0]][gallery[1]][current-1]) { + $('lightwindow_previous').setStyle({ + display: 'none' + }); + } else { + $('lightwindow_previous').setStyle({ + display: 'block' + }); + $('lightwindow_previous_title').innerHTML = this.galleries[gallery[0]][gallery[1]][current-1].title; + } + } + + if (this._getParameter('lightwindow_iframe_embed')) { + this.resizeTo.height = this.dimensions.viewport.height; + this.resizeTo.width = this.dimensions.viewport.width; + } else { + this.resizeTo.height = this._getParameter('lightwindow_height'); + this.resizeTo.width = this._getParameter('lightwindow_width'); + } + + this._processWindow(); + + break; + + case 'external' : + + this._appendIframe('auto'); + + this.resizeTo.height = this.dimensions.viewport.height; + this.resizeTo.width = this.dimensions.viewport.width; + + this._processWindow(); + + break; + + case 'page' : + + var newAJAX = new Ajax.Request( + this.contentToFetch, { + method: 'get', + parameters: '', + onComplete: function(response) { + $('lightwindow_contents').innerHTML += response.responseText; + this.resizeTo.height = $('lightwindow_contents').scrollHeight+(this.options.contentOffset.height); + this.resizeTo.width = $('lightwindow_contents').scrollWidth+(this.options.contentOffset.width); + this._processWindow(); + }.bind(this) + } + ); + + break; + + case 'inline' : + + var content = this.contentToFetch; + if (content.indexOf('?') > -1) { + content = content.substring(0, content.indexOf('?')); + } + content = content.substring(content.indexOf('#')+1); + + new Insertion.Top($('lightwindow_contents'), $(content).innerHTML); + + this.resizeTo.height = $('lightwindow_contents').scrollHeight+(this.options.contentOffset.height); + this.resizeTo.width = $('lightwindow_contents').scrollWidth+(this.options.contentOffset.width); + + this._toggleTroubleElements('hidden', true); + this._processWindow(); + + break; + + default : + throw("Page Type could not be determined, please amend this lightwindow URL "+this.contentToFetch); + break; + } + }, + // + // Resize the Window to fit the viewport if necessary + // + _resizeWindowToFit : function() { + if (this.resizeTo.height+this.dimensions.cruft.height > this.dimensions.viewport.height) { + var heightRatio = this.resizeTo.height/this.resizeTo.width; + this.resizeTo.height = this.dimensions.viewport.height-this.dimensions.cruft.height-(2*this.options.viewportPadding); + // We only care about ratio's with this window type + if (this.windowType == 'image' || (this.windowType == 'media' && !this._getParameter('lightwindow_iframe_embed'))) { + this.resizeTo.width = this.resizeTo.height/heightRatio; + $('lightwindow_data_slide_inner').setStyle({ + width: this.resizeTo.width+'px' + }); + } + } + if (this.resizeTo.width+this.dimensions.cruft.width > this.dimensions.viewport.width) { + var widthRatio = this.resizeTo.width/this.resizeTo.height; + this.resizeTo.width = this.dimensions.viewport.width-2*this.dimensions.cruft.width-(2*this.options.viewportPadding); + // We only care about ratio's with this window type + if (this.windowType == 'image' || (this.windowType == 'media' && !this._getParameter('lightwindow_iframe_embed'))) { + this.resizeTo.height = this.resizeTo.width/widthRatio; + $('lightwindow_data_slide_inner').setStyle({ + height: this.resizeTo.height+'px' + }); + } + } + + }, + // + // Set the Window to a preset size + // + _presetWindowSize : function() { + if (this._getParameter('lightwindow_height')) { + this.resizeTo.height = parseFloat(this._getParameter('lightwindow_height')); + } + if (this._getParameter('lightwindow_width')) { + this.resizeTo.width = parseFloat(this._getParameter('lightwindow_width')); + } + }, + // + // Process the Window + // + _processWindow : function() { + // Clean out our effects + this.dimensions.dataEffects = []; + + // Set up the data-slide if we have caption information + if (this.element.caption || this.element.author || (this.activeGallery && this.options.showGalleryCount)) { + if (this.element.caption) { + $('lightwindow_data_caption').innerHTML = this.element.caption; + $('lightwindow_data_caption').setStyle({ + display: 'block' + }); + } else { + $('lightwindow_data_caption').setStyle({ + display: 'none' + }); + } + if (this.element.author) { + $('lightwindow_data_author').innerHTML = this.element.author; + $('lightwindow_data_author_by').innerHTML = this.element.author_by_text; + $('lightwindow_data_author_container').setStyle({ + display: 'block' + }); + } else { + $('lightwindow_data_author_container').setStyle({ + display: 'none' + }); + } + if (this.activeGallery && this.options.showGalleryCount) { + $('lightwindow_data_gallery_current').innerHTML = this.galleryLocation.current; + $('lightwindow_data_gallery_total').innerHTML = this.galleryLocation.total; + $('lightwindow_data_gallery_container').setStyle({ + display: 'block' + }); + } else { + $('lightwindow_data_gallery_container').setStyle({ + display: 'none' + }); + } + + $('lightwindow_data_slide_inner').setStyle({ + width: this.resizeTo.width+'px', + height: 'auto', + visibility: 'visible', + display: 'block' + }); + $('lightwindow_data_slide').setStyle({ + height: $('lightwindow_data_slide').getHeight()+'px', + width: '1px', + overflow: 'hidden', + display: 'block' + }); + } else { + $('lightwindow_data_slide').setStyle({ + display: 'none', + width: 'auto' + }); + $('lightwindow_data_slide_inner').setStyle({ + display: 'none', + visibility: 'hidden', + width: this.resizeTo.width+'px', + height: '0px' + }); + } + + if (this.element.title != 'null') { + $('lightwindow_title_bar_title').innerHTML = this.element.title; + } else { + $('lightwindow_title_bar_title').innerHTML = ''; + } + + if (this.element.helptext != 'null') { + $('lightwindow_navigation_text').innerHTML = this.element.helptext; + } else { + $('lightwindow_navigation_text').innerHTML = ''; + } + if (this.element.closetext != 'null') { + $('lightwindow_title_bar_close_link').innerHTML = this.element.closetext; + } else { + $('lightwindow_title_bar_close_link').innerHTML = ''; + } + + var originalContainerDimensions = {height: $('lightwindow_container').getHeight(), width: $('lightwindow_container').getWidth()}; + // Position the window + $('lightwindow_container').setStyle({ + height: 'auto', + // We need to set the width to a px not auto as opera has problems with it + width: $('lightwindow_container').getWidth()+this.options.contentOffset.width-(this.windowActive ? this.options.contentOffset.width : 0)+'px' + }); + var newContainerDimensions = {height: $('lightwindow_container').getHeight(), width: $('lightwindow_container').getWidth()}; + + // We need to record the container dimension changes + this.containerChange = {height: originalContainerDimensions.height-newContainerDimensions.height, width: originalContainerDimensions.width-newContainerDimensions.width}; + + // Get out general dimensions + this.dimensions.container = {height: $('lightwindow_container').getHeight(), width: $('lightwindow_container').getWidth()}; + this.dimensions.cruft = {height: this.dimensions.container.height-$('lightwindow_contents').getHeight()+this.options.contentOffset.height, width: this.dimensions.container.width-$('lightwindow_contents').getWidth()+this.options.contentOffset.width}; + + // Set Sizes if we need too + this._presetWindowSize(); + this._resizeWindowToFit(); // Even if the window is preset we still don't want it to go outside of the viewport + + if (!this.windowActive) { + // Position the window + $('lightwindow_container').setStyle({ + left: -(this.dimensions.container.width/2)+'px', + top: -(this.dimensions.container.height/2)+'px' + }); + } + $('lightwindow_container').setStyle({ + height: this.dimensions.container.height+'px', + width: this.dimensions.container.width+'px' + }); + + // We are ready, lets show this puppy off! + this._displayLightWindow('block', 'visible'); + this._animateLightWindow(); + }, + // + // Fire off our animation handler + // + _animateLightWindow : function() { + if (this.options.animationHandler) { + this.options.animationHandler().bind(this); + } else { + this._defaultAnimationHandler(); + } + }, + // + // Fire off our transition handler + // + _handleNavigation : function(display) { + if (this.options.navigationHandler) { + this.options.navigationHandler().bind(this, display); + } else { + this._defaultDisplayNavigation(display); + } + }, + // + // Fire off our transition handler + // + _handleTransition : function() { + if (this.options.transitionHandler) { + this.options.transitionHandler().bind(this); + } else { + this._defaultTransitionHandler(); + } + }, + // + // Handle the finish of the window animation + // + _handleFinalWindowAnimation : function(delay) { + if (this.options.finalAnimationHandler) { + this.options.finalAnimationHandler().bind(this, delay); + } else { + this._defaultfinalWindowAnimationHandler(delay); + } + }, + // + // Handle the gallery Animation + // + _handleGalleryAnimation : function(list) { + if (this.options.galleryAnimationHandler) { + this.options.galleryAnimationHandler().bind(this, list); + } else { + this._defaultGalleryAnimationHandler(list); + } + }, + // + // Display the navigation + // + _defaultDisplayNavigation : function(display) { + if (display) { + $('lightwindow_navigation').setStyle({ + display: 'block', + height: $('lightwindow_contents').getHeight()+'px', + width: '100%', + marginTop: this.options.dimensions.titleHeight+'px' + }); + } else { + $('lightwindow_navigation').setStyle({ + display: 'none', + height: 'auto', + width: 'auto' + }); + } + }, + // + // This is the default animation handler for LightWindow + // + _defaultAnimationHandler : function() { + // Now that we have figures out the cruft lets make the caption go away and add its effects + if (this.element.caption || this.element.author || (this.activeGallery && this.options.showGalleryCount)) { + $('lightwindow_data_slide').setStyle({ + display: 'none', + width: 'auto' + }); + this.dimensions.dataEffects.push( + new Effect.SlideDown('lightwindow_data_slide', {sync: true}), + new Effect.Appear('lightwindow_data_slide', {sync: true, from: 0.0, to: 1.0}) + ); + } + + // Set up the Title if we have one + $('lightwindow_title_bar_inner').setStyle({ + height: '0px', + marginTop: this.options.dimensions.titleHeight+'px' + }); + + // We always want the title bar as well + this.dimensions.dataEffects.push( + new Effect.Morph('lightwindow_title_bar_inner', {sync: true, style: {height: this.options.dimensions.titleHeight+'px', marginTop: '0px'}}), + new Effect.Appear('lightwindow_title_bar_inner', {sync: true, from: 0.0, to: 1.0}) + ); + + if (!this.options.hideGalleryTab) { + this._handleGalleryAnimation(false); + if ($('lightwindow_galleries_tab_container').getHeight() == 0) { + this.dimensions.dataEffects.push( + new Effect.Morph('lightwindow_galleries_tab_container', {sync: true, style: {height: '20px', marginTop: '0px'}}) + ); + $('lightwindow_galleries').setStyle({ + width: '0px' + }); + } + } + + var resized = false; + var ratio = this.dimensions.container.width-$('lightwindow_contents').getWidth()+this.resizeTo.width+this.options.contentOffset.width; + if (ratio != $('lightwindow_container').getWidth()) { + new Effect.Parallel([ + new Effect.Scale('lightwindow_contents', 100*(this.resizeTo.width/$('lightwindow_contents').getWidth()), {scaleFrom: 100*($('lightwindow_contents').getWidth()/($('lightwindow_contents').getWidth()+(this.options.contentOffset.width))), sync: true, scaleY: false, scaleContent: false}), + new Effect.Scale('lightwindow_container', 100*(ratio/(this.dimensions.container.width)), {sync: true, scaleY: false, scaleFromCenter: true, scaleContent: false}) + ], { + duration: this.duration, + delay: 0.25, + queue: {position: 'end', scope: 'lightwindowAnimation'} + } + ); + } + + ratio = this.dimensions.container.height-$('lightwindow_contents').getHeight()+this.resizeTo.height+this.options.contentOffset.height; + if (ratio != $('lightwindow_container').getHeight()) { + new Effect.Parallel([ + new Effect.Scale('lightwindow_contents', 100*(this.resizeTo.height/$('lightwindow_contents').getHeight()), {scaleFrom: 100*($('lightwindow_contents').getHeight()/($('lightwindow_contents').getHeight()+(this.options.contentOffset.height))), sync: true, scaleX: false, scaleContent: false}), + new Effect.Scale('lightwindow_container', 100*(ratio/(this.dimensions.container.height)), {sync: true, scaleX: false, scaleFromCenter: true, scaleContent: false}) + ], { + duration: this.duration, + afterFinish: function() { + if (this.dimensions.dataEffects.length > 0) { + if (!this.options.hideGalleryTab) { + $('lightwindow_galleries').setStyle({ + width: this.resizeTo.width+'px' + }); + } + new Effect.Parallel(this.dimensions.dataEffects, { + duration: this.duration, + afterFinish: function() { + this._finishWindow(); + }.bind(this), + queue: {position: 'end', scope: 'lightwindowAnimation'} + } + ); + } + }.bind(this), + queue: {position: 'end', scope: 'lightwindowAnimation'} + } + ); + resized = true; + } + + // We need to do our data effect since there was no resizing + if (!resized && this.dimensions.dataEffects.length > 0) { + new Effect.Parallel(this.dimensions.dataEffects, { + duration: this.duration, + beforeStart: function() { + if (!this.options.hideGalleryTab) { + $('lightwindow_galleries').setStyle({ + width: this.resizeTo.width+'px' + }); + } + if (this.containerChange.height != 0 || this.containerChange.width != 0) { + new Effect.MoveBy('lightwindow_container', this.containerChange.height, this.containerChange.width, {transition: Effect.Transitions.sinoidal}); + } + }.bind(this), + afterFinish: function() { + this._finishWindow(); + }.bind(this), + queue: {position: 'end', scope: 'lightwindowAnimation'} + } + ); + } + + }, + // + // Finish up Window Animation + // + _defaultfinalWindowAnimationHandler : function(delay) { + if (this.windowType == 'media' || this._getParameter('lightwindow_loading_animation')) { + // Because of major flickering with the overlay we just hide it in this case + Element.hide('lightwindow_loading'); + this._handleNavigation(this.activeGallery); + this._setStatus(false); + } else { + Effect.Fade('lightwindow_loading', { + duration: 0.75, + delay: 1.0, + afterFinish: function() { + // Just in case we need some scroll goodness (this also avoids the swiss cheese effect) + if (this.windowType != 'image' && this.windowType != 'media' && this.windowType != 'external') { + $('lightwindow_contents').setStyle({ + overflow: 'auto' + }); + } + this._handleNavigation(this.activeGallery); + this._defaultGalleryAnimationHandler(); + this._setStatus(false); + }.bind(this), + queue: {position: 'end', scope: 'lightwindowAnimation'} + }); + } + }, + // + // Handle the gallery Animation + // + _defaultGalleryAnimationHandler : function(list) { + if (this.activeGallery) { + $('lightwindow_galleries').setStyle({ + display: 'block', + marginBottom: $('lightwindow_data_slide').getHeight()+this.options.contentOffset.height/2+'px' + }); + $('lightwindow_navigation').setStyle({ + height: $('lightwindow_contents').getHeight()-20+'px' + }); + } else { + $('lightwindow_galleries').setStyle({ + display: 'none' + }); + $('lightwindow_galleries_tab_container').setStyle({ + height: '0px', + marginTop: '20px' + }); + $('lightwindow_galleries_list').setStyle({ + height: '0px' + }); + return false; + } + + if (list) { + if ($('lightwindow_galleries_list').getHeight() == 0) { + var height = $('lightwindow_contents').getHeight()*0.80; + $('lightwindow_galleries_tab_span').className = 'down'; + } else { + var height = 0; + $('lightwindow_galleries_tab_span').className = 'up'; + } + + new Effect.Morph('lightwindow_galleries_list', { + duration: this.duration, + transition: Effect.Transitions.sinoidal, + style: {height: height+'px'}, + beforeStart: function() { + $('lightwindow_galleries_list').setStyle({ + overflow: 'hidden' + }); + }, + afterFinish: function() { + $('lightwindow_galleries_list').setStyle({ + overflow: 'auto' + }); + }, + queue: {position: 'end', scope: 'lightwindowAnimation'} + }); + } + + + }, + // + // Default Transition Handler + // + _defaultTransitionHandler : function() { + // Clean out our effects + this.dimensions.dataEffects = []; + + // Now that we have figures out the cruft lets make the caption go away and add its effects + if ($('lightwindow_data_slide').getStyle('display') != 'none') { + this.dimensions.dataEffects.push( + new Effect.SlideUp('lightwindow_data_slide', {sync: true}), + new Effect.Fade('lightwindow_data_slide', {sync: true, from: 1.0, to: 0.0}) + ); + } + + if (!this.options.hideGalleryTab) { + if ($('lightwindow_galleries').getHeight() != 0 && !this.options.hideGalleryTab) { + this.dimensions.dataEffects.push( + new Effect.Morph('lightwindow_galleries_tab_container', {sync: true, style: {height: '0px', marginTop: '20px'}}) + ); + } + + if ($('lightwindow_galleries_list').getHeight() != 0) { + $('lightwindow_galleries_tab_span').className = 'up'; + this.dimensions.dataEffects.push( + new Effect.Morph('lightwindow_galleries_list', { + sync: true, + style: {height: '0px'}, + transition: Effect.Transitions.sinoidal, + beforeStart: function() { + $('lightwindow_galleries_list').setStyle({ + overflow: 'hidden' + }); + }, + afterFinish: function() { + $('lightwindow_galleries_list').setStyle({ + overflow: 'auto' + }); + } + }) + ); + } + } + + // We always want the title bar as well + this.dimensions.dataEffects.push( + new Effect.Morph('lightwindow_title_bar_inner', {sync: true, style: {height: '0px', marginTop: this.options.dimensions.titleHeight+'px'}}), + new Effect.Fade('lightwindow_title_bar_inner', {sync: true, from: 1.0, to: 0.0}) + ); + + new Effect.Parallel(this.dimensions.dataEffects, { + duration: this.duration, + afterFinish: function() { + this._loadWindow(); + }.bind(this), + queue: {position: 'end', scope: 'lightwindowAnimation'} + } + ); + }, + // + // Default Form handler for LightWindow + // + _defaultFormHandler : function(e) { + var element = Event.element(e).parentNode; + var parameterString = Form.serialize(this._getParameter('lightwindow_form', element.getAttribute('params'))); + if (this.options.formMethod == 'post') { + var newAJAX = new Ajax.Request(element.href, { + method: 'post', + postBody: parameterString, + onComplete: this.openWindow.bind(this, element) + }); + } else if (this.options.formMethod == 'get') { + var newAJAX = new Ajax.Request(element.href, { + method: 'get', + parameters: parameterString, + onComplete: this.openWindow.bind(this, element) + }); + } + }, + // + // Wrap everything up + // + _finishWindow : function() { + if (this.windowType == 'external') { + // We set the externals source here because it allows for a much smoother animation + $('lightwindow_iframe').setAttribute('src', this.element.href); + this._handleFinalWindowAnimation(1); + } else if (this.windowType == 'media') { + + var outerObject = document.createElement('object'); + outerObject.setAttribute('classid', this.options.classids[this._fileExtension(this.contentToFetch)]); + outerObject.setAttribute('codebase', this.options.codebases[this._fileExtension(this.contentToFetch)]); + outerObject.setAttribute('id', 'lightwindow_media_primary'); + outerObject.setAttribute('name', 'lightwindow_media_primary'); + outerObject.setAttribute('width', this.resizeTo.width); + outerObject.setAttribute('height', this.resizeTo.height); + outerObject = this._addParamToObject('movie', this.contentToFetch, outerObject); + outerObject = this._addParamToObject('src', this.contentToFetch, outerObject); + outerObject = this._addParamToObject('controller', 'true', outerObject); + outerObject = this._addParamToObject('wmode', 'transparent', outerObject); + outerObject = this._addParamToObject('cache', 'false', outerObject); + outerObject = this._addParamToObject('quality', 'high', outerObject); + + if (!Prototype.Browser.IE) { + var innerObject = document.createElement('object'); + innerObject.setAttribute('type', this.options.mimeTypes[this._fileExtension(this.contentToFetch)]); + innerObject.setAttribute('data', this.contentToFetch); + innerObject.setAttribute('id', 'lightwindow_media_secondary'); + innerObject.setAttribute('name', 'lightwindow_media_secondary'); + innerObject.setAttribute('width', this.resizeTo.width); + innerObject.setAttribute('height', this.resizeTo.height); + innerObject = this._addParamToObject('controller', 'true', innerObject); + innerObject = this._addParamToObject('wmode', 'transparent', innerObject); + innerObject = this._addParamToObject('cache', 'false', innerObject); + innerObject = this._addParamToObject('quality', 'high', innerObject); + + outerObject.appendChild(innerObject); + } + + if (this._getParameter('lightwindow_iframe_embed')) { + this._appendIframe('no'); + this._writeToIframe(this._convertToMarkup(outerObject, 'object')); + } else { + this._appendObject(outerObject, 'object', $('lightwindow_contents')); + } + + this._handleFinalWindowAnimation(0); + } else { + this._handleFinalWindowAnimation(0); + } + + // Initialize any actions + this._setupActions(); + } +} + +/*-----------------------------------------------------------------------------------------------*/ + +Event.observe(window, 'load', lightwindowInit, false); + +// +// Set up all of our links +// +var myLightWindow = null; +function lightwindowInit() { + myLightWindow = new lightwindow(); +} \ No newline at end of file diff --git a/web/js/main.js b/web/js/main.js new file mode 100644 index 0000000..bed6c33 --- /dev/null +++ b/web/js/main.js @@ -0,0 +1,283 @@ +var rss_links = []; + +function uploadStatusShow() +{ + $('upload_status_box').show(); + $('upload_box').hide(); + $('upload_text_box').hide(); + if($('big_gray_upload')) + $('big_gray_upload').hide(); +} + +function showHideRss(showText, shownText) +{ + rss_links.each( + function(bob) { + Effect.toggle('id_' + bob, 'Appear'); + } + ) + if ($('rss_toggle').innerHTML == shownText) + { + $('rss_toggle').innerHTML = showText; + } + else + { + $('rss_toggle').innerHTML = shownText; + } +} + +function countVisibleRemoveButtons() +{ + var elements = document.getElementsByClassName('remove'); + var count = 0; + + for(i = 0; i < elements.length; i++) { + if (elements[i].visible) + { + count++; + } + } + return count; + +} + +function updateContentSidebar(username) +{ + new Ajax.Updater('content_manager_sidebar', '/updateContentSidebar/'+username); +} + +function updateFileList(artworkId) +{ + new Ajax.Updater('filelist', '/updateFileList/'+artworkId); +} + +function updateArtworkTagList(fileId, artworkId) +{ + new Ajax.Updater('currentTags_artwork'+artworkId, '/updateArtworkTagList/'+fileId+'/'+artworkId); +} + +var usernameCount = 0; + +function checkUsername() +{ + usernameCount++; + setTimeout("doCheckUsername("+usernameCount+")", 500); +} + +function doCheckUsername(currCount) +{ + if (currCount == usernameCount) + { + usernameCount = 0; + + var uname = $('username_profile').value; + new Ajax.Request('/checkusername', { + method: 'post', + onSuccess: function(transport) { + responseArray = eval(transport.headerJSON); + $('username_check_img').src="/images/"+responseArray["image"]; + $('username_status').innerHTML=responseArray["message"]; + }, + parameters: {username: uname} + }); + } +} + +function checkNormalisationResponse(transport) +{ + responseArray = eval(transport.headerJSON); + if (responseArray['error']) { alert(responseArray['error']); } + else { location.reload(); } +} + +function checkForRss() +{ + if ( rss_links.length > 0 ) { return true }; + + return false; +} + + +function clearPasswordBoxes() +{ + if ($('password')) { + $('password').value = ""; + } + if ($('repeat_password')) { + $('repeat_password').value = ""; + } + + if ($('sf_guard_user_password')) { + $('sf_guard_user_password').value = ""; + } + if ($('sf_guard_user_password_bis')) { + $('sf_guard_user_password_bis').value = ""; + } +} + +function lostPassToggle() +{ + Effect.toggle('sf_guard_auth_form', 'slide'); + Effect.toggle('lost_pass', 'slide'); +} + +function sfMediaLibrary_Engine() +{ + // Browser check + var ua = navigator.userAgent; + this.isMSIE = (navigator.appName == "Microsoft Internet Explorer"); + this.isMSIE5 = this.isMSIE && (ua.indexOf('MSIE 5') != -1); + this.isMSIE5_0 = this.isMSIE && (ua.indexOf('MSIE 5.0') != -1); + this.isGecko = ua.indexOf('Gecko') != -1; + this.isSafari = ua.indexOf('Safari') != -1; + this.isOpera = ua.indexOf('Opera') != -1; + this.isMac = ua.indexOf('Mac') != -1; + this.isNS7 = ua.indexOf('Netscape/7') != -1; + this.isNS71 = ua.indexOf('Netscape/7.1') != -1; + this.isTinyMCE = false; + + // Fake MSIE on Opera and if Opera fakes IE, Gecko or Safari cancel those + if (this.isOpera) { + this.isMSIE = true; + this.isGecko = false; + this.isSafari = false; + } +} + +sfMediaLibrary_Engine.prototype = { + init : function(url) + { + this.url = url; + }, + + fileBrowserReturn : function (url) + { + if(this.isTinyMCE) + { + tinyMCE.setWindowArg('editor_id', this.fileBrowserWindowArg); + if (this.fileBrowserType == 'image') + { + this.fileBrowserWin.showPreviewImage(url); + } + } + this.fileBrowserWin.document.forms[this.fileBrowserFormName].elements[this.fileBrowserFieldName].value = url; + }, + + fileBrowserCallBack : function (field_name, url, type, win) + { + this.isTinyMCE = true; + this.fileBrowserWindowArg = tinyMCE.getWindowArg('editor_id'); + var template = new Array(); + template['title'] = 'Assets'; + var url = this.url; + if (type == 'image') + url += '/images_only/1'; + template['file'] = url; + template['width'] = 550; + template['height'] = 600; + template['close_previous'] = 'no'; + + this.fileBrowserWin = win; + this.fileBrowserFormName = 0; + this.fileBrowserFieldName = field_name; + this.fileBrowserType = type; + tinyMCE.openWindow(template, {inline : "yes", scrollbars: 'yes'}); + }, + + openWindow : function(options) + { + var width, height, x, y, resizable, scrollbars, url; + + if (!options) + return; + if (!options['field_name']) + return; + if (!options['url'] && !this.url) + return; + this.fileBrowserWin = self; + this.fileBrowserFormName = (options['form_name'] == '') ? 0 : options['form_name']; + this.fileBrowserFieldName = options['field_name']; + this.fileBrowserType = options['type']; + + url = this.url; + if (options['type'] == 'image') + url += '/images_only/1'; + + if (!(width = parseInt(options['width']))) + width = 550; + + if (!(width = parseInt(options['width']))) + width = 550; + + if (!(height = parseInt(options['height']))) + height = 600; + + // Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!! + if (sfMediaLibrary.isMSIE) + height += 40; + else + height += 20; + + x = parseInt(screen.width / 2.0) - (width / 2.0); + y = parseInt(screen.height / 2.0) - (height / 2.0); + + resizable = (options && options['resizable']) ? options['resizable'] : "no"; + scrollbars = (options && options['scrollbars']) ? options['scrollbars'] : "no"; + + var modal = (resizable == "yes") ? "no" : "yes"; + + if (sfMediaLibrary.isGecko && sfMediaLibrary.isMac) + modal = "no"; + + if (options['close_previous'] != "no") + try {sfMediaLibrary.lastWindow.close();} catch (ex) {} + + var win = window.open(url, "sfPopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=" + modal + ",minimizable=" + resizable + ",modal=" + modal + ",width=" + width + ",height=" + height + ",resizable=" + resizable); + + if (options['close_previous'] != "no") + sfMediaLibrary.lastWindow = win; + + eval('try { win.resizeTo(width, height); } catch(e) { }'); + + // Make it bigger if statusbar is forced + if (sfMediaLibrary.isGecko) + { + if (win.document.defaultView.statusbar.visible) + win.resizeBy(0, sfMediaLibrary.isMac ? 10 : 24); + } + + win.focus(); + + } +} + +var SfMediaLibrary = sfMediaLibrary_Engine; // Compatiblity with gzip compressors +var sfMediaLibrary = new sfMediaLibrary_Engine(); + + +function resizeArtworkImage(image_id) { + + if ($(image_id).getWidth() > 150) { + $('magnify_link').setStyle({width: $(image_id).getWidth()+'px'}); + } +} + +function deleteEmptyNode(n) +{ + if ($(n).getElementsByTagName("a").length == 0 && !($(n).getElementsByTagName("img").length > 1)) { + $(n).remove(); + } +} + + +function checkAllinform(formName, checkValue){ + for (var i = 0; i < $(formName).elements.length; i++) { + var e = $(formName).elements[i]; + if (e.type == 'checkbox') { + e.checked = checkValue; + } + } +} + + + diff --git a/web/js/prototype.js b/web/js/prototype.js new file mode 100644 index 0000000..6385503 --- /dev/null +++ b/web/js/prototype.js @@ -0,0 +1,4221 @@ +/* Prototype JavaScript framework, version 1.6.0.2 + * (c) 2005-2008 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.6.0.2', + + Browser: { + IE: !!(window.attachEvent && !window.opera), + Opera: !!window.opera, + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1, + MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/) + }, + + BrowserFeatures: { + XPath: !!document.evaluate, + ElementExtensions: !!window.HTMLElement, + SpecificElementExtensions: + document.createElement('div').__proto__ && + document.createElement('div').__proto__ !== + document.createElement('form').__proto__ + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +/* Based on Alex Arnell's inheritance implementation. */ +var Class = { + create: function() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + var subclass = function() { }; + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0; i < properties.length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + + return klass; + } +}; + +Class.Methods = { + addMethods: function(source) { + var ancestor = this.superclass && this.superclass.prototype; + var properties = Object.keys(source); + + if (!Object.keys({ toString: true }).length) + properties.push("toString", "valueOf"); + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames().first() == "$super") { + var method = value, value = Object.extend((function(m) { + return function() { return ancestor[m].apply(this, arguments) }; + })(property).wrap(method), { + valueOf: function() { return method }, + toString: function() { return method.toString() } + }); + } + this.prototype[property] = value; + } + + return this; + } +}; + +var Abstract = { }; + +Object.extend = function(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; +}; + +Object.extend(Object, { + inspect: function(object) { + try { + if (Object.isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + toJSON: function(object) { + var type = typeof object; + switch (type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (Object.isElement(object)) return; + + var results = []; + for (var property in object) { + var value = Object.toJSON(object[property]); + if (!Object.isUndefined(value)) + results.push(property.toJSON() + ': ' + value); + } + + return '{' + results.join(', ') + '}'; + }, + + toQueryString: function(object) { + return $H(object).toQueryString(); + }, + + toHTML: function(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({ }, object); + }, + + isElement: function(object) { + return object && object.nodeType == 1; + }, + + isArray: function(object) { + return object != null && typeof object == "object" && + 'splice' in object && 'join' in object; + }, + + isHash: function(object) { + return object instanceof Hash; + }, + + isFunction: function(object) { + return typeof object == "function"; + }, + + isString: function(object) { + return typeof object == "string"; + }, + + isNumber: function(object) { + return typeof object == "number"; + }, + + isUndefined: function(object) { + return typeof object == "undefined"; + } +}); + +Object.extend(Function.prototype, { + argumentNames: function() { + var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip"); + return names.length == 1 && !names[0] ? [] : names; + }, + + bind: function() { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } + }, + + bindAsEventListener: function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [event || window.event].concat(args)); + } + }, + + curry: function() { + if (!arguments.length) return this; + var __method = this, args = $A(arguments); + return function() { + return __method.apply(this, args.concat($A(arguments))); + } + }, + + delay: function() { + var __method = this, args = $A(arguments), timeout = args.shift() * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + }, + + wrap: function(wrapper) { + var __method = this; + return function() { + return wrapper.apply(this, [__method.bind(this)].concat($A(arguments))); + } + }, + + methodize: function() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + return __method.apply(null, [this].concat($A(arguments))); + }; + } +}); + +Function.prototype.defer = Function.prototype.delay.curry(0.01); + +Date.prototype.toJSON = function() { + return '"' + this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z"'; +}; + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + } finally { + this.currentlyExecuting = false; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var self = arguments.callee; + self.text.data = this; + return self.div.innerHTML; + }, + + unescapeHTML: function() { + var div = new Element('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + times: function(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { + var character = String.specialChar[match[0]]; + return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + }, + + toJSON: function() { + return this.inspect(true); + }, + + unfilterJSON: function(filter) { + return this.sub(filter || Prototype.JSONFilter, '#{1}'); + }, + + isJSON: function() { + var str = this; + if (str.blank()) return false; + str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + }, + + evalJSON: function(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + }, + + include: function(pattern) { + return this.indexOf(pattern) > -1; + }, + + startsWith: function(pattern) { + return this.indexOf(pattern) === 0; + }, + + endsWith: function(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + }, + + empty: function() { + return this == ''; + }, + + blank: function() { + return /^\s*$/.test(this); + }, + + interpolate: function(object, pattern) { + return new Template(this, pattern).evaluate(object); + } +}); + +if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { + escapeHTML: function() { + return this.replace(/&/g,'&').replace(//g,'>'); + }, + unescapeHTML: function() { + return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +}; + +String.prototype.parseQuery = String.prototype.toQueryParams; + +Object.extend(String.prototype.escapeHTML, { + div: document.createElement('div'), + text: document.createTextNode('') +}); + +with (String.prototype.escapeHTML) div.appendChild(text); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return ''; + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3]; + var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = { + each: function(iterator, context) { + var index = 0; + iterator = iterator.bind(context); + try { + this._each(function(value) { + iterator(value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + }, + + eachSlice: function(number, iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var index = -number, slices = [], array = this.toArray(); + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + }, + + all: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function(iterator, context) { + iterator = iterator.bind(context); + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator, context) { + iterator = iterator.bind(context); + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(filter, iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(filter); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator(value, index)); + }); + return results; + }, + + include: function(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inGroupsOf: function(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + }, + + inject: function(memo, iterator, context) { + iterator = iterator.bind(context); + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result; + this.each(function(value, index) { + value = iterator(value, index); + if (result == null || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var result; + this.each(function(value, index) { + value = iterator(value, index); + if (result == null || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator, context) { + iterator = iterator ? iterator.bind(context) : Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator, context) { + iterator = iterator.bind(context); + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator, context) { + iterator = iterator.bind(context); + return this.map(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.map(); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + size: function() { + return this.toArray().length; + }, + + inspect: function() { + return '#'; + } +}; + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + filter: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray, + every: Enumerable.all, + some: Enumerable.any +}); +function $A(iterable) { + if (!iterable) return []; + if (iterable.toArray) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + +if (Prototype.Browser.WebKit) { + $A = function(iterable) { + if (!iterable) return []; + if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') && + iterable.toArray) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; + }; +} + +Array.from = $A; + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(Object.isArray(value) ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + reduce: function() { + return this.length > 1 ? this : this[0]; + }, + + uniq: function(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + }, + + intersect: function(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + }, + + clone: function() { + return [].concat(this); + }, + + size: function() { + return this.length; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + }, + + toJSON: function() { + var results = []; + this.each(function(object) { + var value = Object.toJSON(object); + if (!Object.isUndefined(value)) results.push(value); + }); + return '[' + results.join(', ') + ']'; + } +}); + +// use native browser JS 1.6 implementation if available +if (Object.isFunction(Array.prototype.forEach)) + Array.prototype._each = Array.prototype.forEach; + +if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; +}; + +if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; +}; + +Array.prototype.toArray = Array.prototype.clone; + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +if (Prototype.Browser.Opera){ + Array.prototype.concat = function() { + var array = []; + for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); + for (var i = 0, length = arguments.length; i < length; i++) { + if (Object.isArray(arguments[i])) { + for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) + array.push(arguments[i][j]); + } else { + array.push(arguments[i]); + } + } + return array; + }; +} +Object.extend(Number.prototype, { + toColorPart: function() { + return this.toPaddedString(2, 16); + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + }, + + toPaddedString: function(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + }, + + toJSON: function() { + return isFinite(this) ? this.toString() : 'null'; + } +}); + +$w('abs round ceil floor').each(function(method){ + Number.prototype[method] = Math[method].methodize(); +}); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + return { + initialize: function(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + }, + + _each: function(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + set: function(key, value) { + return this._object[key] = value; + }, + + get: function(key) { + return this._object[key]; + }, + + unset: function(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + }, + + toObject: function() { + return Object.clone(this._object); + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + index: function(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + }, + + merge: function(object) { + return this.clone().update(object); + }, + + update: function(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return values.map(toQueryPair.curry(key)).join('&'); + } + return toQueryPair(key, values); + }).join('&'); + }, + + inspect: function() { + return '#'; + }, + + toJSON: function() { + return Object.toJSON(this.toObject()); + }, + + clone: function() { + return new Hash(this); + } + } +})()); + +Hash.prototype.toTemplateReplacements = Hash.prototype.toObject; +Hash.from = $H; +var ObjectRange = Class.create(Enumerable, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +}; + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); + +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isString(this.options.parameters)) + this.options.parameters = this.options.parameters.toQueryParams(); + else if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); + +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Object.toQueryString(params)) { + // when GET, append parameters to URL + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); + }, + + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if(readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + // DOM level 2 ECMAScript Language Binding + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + +(function() { + var element = this.Element; + this.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + if (Prototype.Browser.IE && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + }; + Object.extend(this.Element, element || { }); +}).call(window); + +Element.cache = { }; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + $(element).style.display = 'none'; + return element; + }, + + show: function(element) { + $(element).style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + content = Object.toHTML(content); + element.innerHTML = content.stripScripts(); + content.evalScripts.bind(content).defer(); + return element; + }, + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $(element).select("*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (Object.isString(selector)) + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = element.ancestors(); + return Object.isNumber(expression) ? ancestors[expression] : + Selector.findElement(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? element.descendants()[expression] : + element.select(expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = element.previousSiblings(); + return Object.isNumber(expression) ? previousSiblings[expression] : + Selector.findElement(previousSiblings, expression, index); + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = element.nextSiblings(); + return Object.isNumber(expression) ? nextSiblings[expression] : + Selector.findElement(nextSiblings, expression, index); + }, + + select: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + adjacent: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element.parentNode, args).without(element); + }, + + identify: function(element) { + element = $(element); + var id = element.readAttribute('id'), self = arguments.callee; + if (id) return id; + do { id = 'anonymous_element_' + self.counter++ } while ($(id)); + element.writeAttribute('id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!element.hasClassName(className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return element[element.hasClassName(className) ? + 'removeClassName' : 'addClassName'](className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + var originalAncestor = ancestor; + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (element.sourceIndex && !Prototype.Browser.Opera) { + var e = element.sourceIndex, a = ancestor.sourceIndex, + nextAncestor = ancestor.nextSibling; + if (!nextAncestor) { + do { ancestor = ancestor.parentNode; } + while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode); + } + if (nextAncestor && nextAncestor.sourceIndex) + return (e > a && e < nextAncestor.sourceIndex); + } + + while (element = element.parentNode) + if (element == originalAncestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = element.cumulativeOffset(); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = $(element).getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (element.tagName == 'BODY') break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + absolutize: function(element) { + element = $(element); + if (element.getStyle('position') == 'absolute') return; + // Position.prepare(); // To be done manually by Scripty when it needs it. + + var offsets = element.positionedOffset(); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + return element; + }, + + relativize: function(element) { + element = $(element); + if (element.getStyle('position') == 'relative') return; + // Position.prepare(); // To be done manually by Scripty when it needs it. + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + return element; + }, + + cumulativeScrollOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + getOffsetParent: function(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element == document.body) return $(element); + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return $(element); + + return $(document.body); + }, + + viewportOffset: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent == document.body && + Element.getStyle(element, 'position') == 'absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!Prototype.Browser.Opera || element.tagName == 'BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return Element._returnOffset(valueL, valueT); + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + // find page position of source + source = $(source); + var p = source.viewportOffset(); + + // find coordinate system to use + element = $(element); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(element, 'position') == 'absolute') { + parent = element.getOffsetParent(); + delta = parent.viewportOffset(); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Element.Methods.identify.counter = 1; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'left': case 'top': case 'right': case 'bottom': + if (proceed(element, 'position') === 'static') return null; + case 'height': case 'width': + // returns '0px' for hidden elements; we want it to return null + if (!Element.visible(element)) return null; + + // returns the border-box dimensions rather than the content-box + // dimensions, so we subtract padding and borders from the value + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + // IE doesn't report offsets correctly for static elements, so we change them + // to "relative" to get the values, then change them back. + Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + $w('positionedOffset viewportOffset').each(function(method) { + Element.Methods[method] = Element.Methods[method].wrap( + function(proceed, element) { + element = $(element); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + // Trigger hasLayout on the offset parent so that IE6 reports + // accurate offsetTop and offsetLeft values for position: fixed. + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + offsetParent.setStyle({ zoom: 1 }); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + }); + + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = { + read: { + names: { + 'class': 'className', + 'for': 'htmlFor' + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: function(element, attribute) { + attribute = element.getAttribute(attribute); + return attribute ? attribute.toString().slice(23, -2) : null; + }, + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + }; + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr, + src: v._getAttr, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if(element.tagName == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; + + // Safari returns margins on body which is incorrect if the child is absolutely + // positioned. For performance reasons, redefine Element#cumulativeOffset for + // KHTML/WebKit only. + Element.Methods.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return Element._returnOffset(valueL, valueT); + }; +} + +if (Prototype.Browser.IE || Prototype.Browser.Opera) { + // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements + Element.Methods.update = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) return element.update().insert(content); + + content = Object.toHTML(content); + var tagName = element.tagName.toUpperCase(); + + if (tagName in Element._insertionTranslations.tags) { + $A(element.childNodes).each(function(node) { element.removeChild(node) }); + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { element.appendChild(node) }); + } + else element.innerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +if ('outerHTML' in document.createElement('div')) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(); + var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html) { + var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; + if (t) { + div.innerHTML = t[0] + html + t[1]; + t[2].times(function() { div = div.firstChild }); + } else div.innerHTML = html; + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['', '
    ', 1], + TBODY: ['', '
    ', 2], + TR: ['', '
    ', 3], + TD: ['
    ', '
    ', 4], + SELECT: ['', 1] + } +}; + +(function() { + Object.extend(this.tags, { + THEAD: this.tags.TBODY, + TFOOT: this.tags.TBODY, + TH: this.tags.TD + }); +}).call(Element._insertionTranslations); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return node && node.specified; + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +if (!Prototype.BrowserFeatures.ElementExtensions && + document.createElement('div').__proto__) { + window.HTMLElement = { }; + window.HTMLElement.prototype = document.createElement('div').__proto__; + Prototype.BrowserFeatures.ElementExtensions = true; +} + +Element.extend = (function() { + if (Prototype.BrowserFeatures.SpecificElementExtensions) + return Prototype.K; + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || element._extendedByPrototype || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName, property, value; + + // extend methods for specific tags + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + for (property in methods) { + value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + // extend methods for all tags (Safari doesn't need this) + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +Element.hasAttribute = function(element, attribute) { + if (element.hasAttribute) return element.hasAttribute(attribute); + return Element.Methods.Simulated.hasAttribute(element, attribute); +}; + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + window[klass] = { }; + window[klass].prototype = document.createElement(tagName).__proto__; + return window[klass]; + } + + if (F.ElementExtensions) { + copy(Element.Methods, HTMLElement.prototype); + copy(Element.Methods.Simulated, HTMLElement.prototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + +document.viewport = { + getDimensions: function() { + var dimensions = { }; + var B = Prototype.Browser; + $w('width height').each(function(d) { + var D = d.capitalize(); + dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] : + (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D]; + }); + return dimensions; + }, + + getWidth: function() { + return this.getDimensions().width; + }, + + getHeight: function() { + return this.getDimensions().height; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; +/* Portions of the Selector class are derived from Jack Slocum’s DomQuery, + * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style + * license. Please see http://www.yui-ext.com/ for more information. */ + +var Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + this.compileMatcher(); + }, + + shouldUseXPath: function() { + if (!Prototype.BrowserFeatures.XPath) return false; + + var e = this.expression; + + // Safari 3 chokes on :*-of-type and :empty + if (Prototype.Browser.WebKit && + (e.include("-of-type") || e.include(":empty"))) + return false; + + // XPath can't do namespaced attributes, nor can it read + // the "checked" property from DOM nodes + if ((/(\[[\w-]*?:|:checked)/).test(this.expression)) + return false; + + return true; + }, + + compileMatcher: function() { + if (this.shouldUseXPath()) + return this.compileXPathMatcher(); + + var e = this.expression, ps = Selector.patterns, h = Selector.handlers, + c = Selector.criteria, le, p, m; + + if (Selector._cache[e]) { + this.matcher = Selector._cache[e]; + return; + } + + this.matcher = ["this.matcher = function(root) {", + "var r = root, h = Selector.handlers, c = false, n;"]; + + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + p = ps[i]; + if (m = e.match(p)) { + this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : + new Template(c[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.matcher.push("return h.unique(n);\n}"); + eval(this.matcher.join('\n')); + Selector._cache[this.expression] = this.matcher; + }, + + compileXPathMatcher: function() { + var e = this.expression, ps = Selector.patterns, + x = Selector.xpath, le, m; + + if (Selector._cache[e]) { + this.xpath = Selector._cache[e]; return; + } + + this.matcher = ['.//*']; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + if (m = e.match(ps[i])) { + this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : + new Template(x[i]).evaluate(m)); + e = e.replace(m[0], ''); + break; + } + } + } + + this.xpath = this.matcher.join(''); + Selector._cache[this.expression] = this.xpath; + }, + + findElements: function(root) { + root = root || document; + if (this.xpath) return document._getElementsByXPath(this.xpath, root); + return this.matcher(root); + }, + + match: function(element) { + this.tokens = []; + + var e = this.expression, ps = Selector.patterns, as = Selector.assertions; + var le, p, m; + + while (e && le !== e && (/\S/).test(e)) { + le = e; + for (var i in ps) { + p = ps[i]; + if (m = e.match(p)) { + // use the Selector.assertions methods unless the selector + // is too complex. + if (as[i]) { + this.tokens.push([i, Object.clone(m)]); + e = e.replace(m[0], ''); + } else { + // reluctantly do a document-wide search + // and look for a match in the array + return this.findElements(document).include(element); + } + } + } + } + + var match = true, name, matches; + for (var i = 0, token; token = this.tokens[i]; i++) { + name = token[0], matches = token[1]; + if (!Selector.assertions[name](element, matches)) { + match = false; break; + } + } + + return match; + }, + + toString: function() { + return this.expression; + }, + + inspect: function() { + return "#"; + } +}); + +Object.extend(Selector, { + _cache: { }, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: function(m) { + m[1] = m[1].toLowerCase(); + return new Template("[@#{1}]").evaluate(m); + }, + attr: function(m) { + m[1] = m[1].toLowerCase(); + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (Object.isFunction(h)) return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", + 'checked': "[@checked]", + 'disabled': "[@disabled]", + 'enabled': "[not(@disabled)]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, v; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in p) { + if (m = e.match(p[i])) { + v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); + exclusion.push("(" + v.substring(1, v.length - 1) + ")"); + e = e.replace(m[0], ''); + break; + } + } + } + return "[not(" + exclusion.join(" and ") + ")]"; + }, + 'nth-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); + }, + 'nth-last-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); + }, + 'nth-of-type': function(m) { + return Selector.xpath.pseudos.nth("position() ", m); + }, + 'nth-last-of-type': function(m) { + return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); + }, + 'first-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); + }, + 'last-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); + }, + 'only-of-type': function(m) { + var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); + }, + nth: function(fragment, m) { + var mm, formula = m[6], predicate; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + if (mm = formula.match(/^(\d+)$/)) // digit only + return '[' + fragment + "= " + mm[1] + ']'; + if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (mm[1] == "-") mm[1] = -1; + var a = mm[1] ? Number(mm[1]) : 1; + var b = mm[2] ? Number(mm[2]) : 0; + predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + + "((#{fragment} - #{b}) div #{a} >= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: { + // combinators must be listed first + // (and descendant needs to be last combinator) + laterSibling: /^\s*~\s*/, + child: /^\s*>\s*/, + adjacent: /^\s*\+\s*/, + descendant: /^\s/, + + // selectors follow + tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, + id: /^#([\w\-\*]+)(\b|$)/, + className: /^\.([\w\-\*]+)(\b|$)/, + pseudo: +/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, + attrPresence: /^\[([\w]+)\]/, + attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ + }, + + // for Selector.match and Element#match + assertions: { + tagName: function(element, matches) { + return matches[1].toUpperCase() == element.tagName.toUpperCase(); + }, + + className: function(element, matches) { + return Element.hasClassName(element, matches[1]); + }, + + id: function(element, matches) { + return element.id === matches[1]; + }, + + attrPresence: function(element, matches) { + return Element.hasAttribute(element, matches[1]); + }, + + attr: function(element, matches) { + var nodeValue = Element.readAttribute(element, matches[1]); + return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); + } + }, + + handlers: { + // UTILITY FUNCTIONS + // joins two collections + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + // marks an array of nodes for counting + mark: function(nodes) { + var _true = Prototype.emptyFunction; + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = _true; + return nodes; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._countedByPrototype = undefined; + return nodes; + }, + + // mark each child node with its position (for nth calls) + // "ofType" flag indicates whether we're indexing for nth-of-type + // rather than nth-child + index: function(parentNode, reverse, ofType) { + parentNode._countedByPrototype = Prototype.emptyFunction; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + var node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + } + }, + + // filters out duplicates and extends all nodes + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (!(n = nodes[i])._countedByPrototype) { + n._countedByPrototype = Prototype.emptyFunction; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + // COMBINATOR FUNCTIONS + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + // TOKEN FUNCTIONS + tagName: function(nodes, root, tagName, combinator) { + var uTagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + // fastlane for ordinary descendant combinators + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() === uTagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + if (!targetNode) return []; + if (!nodes && root == document) return [targetNode]; + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator, combinator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + if (nodes && combinator) nodes = this[combinator](nodes); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + // handles the an+b logic + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._countedByPrototype) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + // IE treats comments as element nodes + if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._countedByPrototype) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled) results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv.startsWith(v); }, + '$=': function(nv, v) { return nv.endsWith(v); }, + '*=': function(nv, v) { return nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } + }, + + split: function(expression) { + var expressions = []; + expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + return expressions; + }, + + matchElements: function(elements, expression) { + var matches = $$(expression), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._countedByPrototype) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (Object.isNumber(expression)) { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + expressions = Selector.split(expressions.join(',')); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +if (Prototype.Browser.IE) { + Object.extend(Selector.handlers, { + // IE returns comment nodes on getElementsByTagName("*"). + // Filter them out. + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + if (node.tagName !== "!") a.push(node); + return a; + }, + + // IE improperly serializes _countedByPrototype in (inner|outer)HTML. + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node.removeAttribute('_countedByPrototype'); + return nodes; + } + }); +} + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit; + + var data = elements.inject({ }, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + if (key in result) { + // a key is already present; construct an array of values + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return options.hash ? data : Object.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.blur(); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element, value); + default: + return Form.Element.Serializers.textarea(element, value); + } + }, + + inputSelector: function(element, value) { + if (Object.isUndefined(value)) return element.checked ? element.value : null; + else element.checked = !!value; + }, + + textarea: function(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + }, + + select: function(element, index) { + if (Object.isUndefined(index)) + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + else { + var opt, value, single = !Object.isArray(index); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + value = this.optionValue(opt); + if (single) { + if (value == index) { + opt.selected = true; + return; + } + } + else opt.selected = index.include(value); + } + } + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +}; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) var Event = { }; + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: { }, + + relatedTarget: function(event) { + var element; + switch(event.type) { + case 'mouseover': element = event.fromElement; break; + case 'mouseout': element = event.toElement; break; + default: return null; + } + return Element.extend(element); + } +}); + +Event.Methods = (function() { + var isButton; + + if (Prototype.Browser.IE) { + var buttonMap = { 0: 1, 1: 4, 2: 2 }; + isButton = function(event, code) { + return event.button == buttonMap[code]; + }; + + } else if (Prototype.Browser.WebKit) { + isButton = function(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 1 && event.metaKey; + default: return false; + } + }; + + } else { + isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + }; + } + + return { + isLeftClick: function(event) { return isButton(event, 0) }, + isMiddleClick: function(event) { return isButton(event, 1) }, + isRightClick: function(event) { return isButton(event, 2) }, + + element: function(event) { + var node = Event.extend(event).target; + return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node); + }, + + findElement: function(event, expression) { + var element = Event.element(event); + if (!expression) return element; + var elements = [element].concat(element.ancestors()); + return Selector.findElement(elements, expression, 0); + }, + + pointer: function(event) { + return { + x: event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)), + y: event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)) + }; + }, + + pointerX: function(event) { return Event.pointer(event).x }, + pointerY: function(event) { return Event.pointer(event).y }, + + stop: function(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + event.stopped = true; + } + }; +})(); + +Event.extend = (function() { + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (Prototype.Browser.IE) { + Object.extend(methods, { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return "[object Event]" } + }); + + return function(event) { + if (!event) return false; + if (event._extendedByPrototype) return event; + + event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + Object.extend(event, { + target: event.srcElement, + relatedTarget: Event.relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + return Object.extend(event, methods); + }; + + } else { + Event.prototype = Event.prototype || document.createEvent("HTMLEvents").__proto__; + Object.extend(Event.prototype, methods); + return Prototype.K; + } +})(); + +Object.extend(Event, (function() { + var cache = Event.cache; + + function getEventID(element) { + if (element._prototypeEventID) return element._prototypeEventID[0]; + arguments.callee.id = arguments.callee.id || 1; + return element._prototypeEventID = [++arguments.callee.id]; + } + + function getDOMEventName(eventName) { + if (eventName && eventName.include(':')) return "dataavailable"; + return eventName; + } + + function getCacheForID(id) { + return cache[id] = cache[id] || { }; + } + + function getWrappersForEventName(id, eventName) { + var c = getCacheForID(id); + return c[eventName] = c[eventName] || []; + } + + function createWrapper(element, eventName, handler) { + var id = getEventID(element); + var c = getWrappersForEventName(id, eventName); + if (c.pluck("handler").include(handler)) return false; + + var wrapper = function(event) { + if (!Event || !Event.extend || + (event.eventName && event.eventName != eventName)) + return false; + + Event.extend(event); + handler.call(element, event); + }; + + wrapper.handler = handler; + c.push(wrapper); + return wrapper; + } + + function findWrapper(id, eventName, handler) { + var c = getWrappersForEventName(id, eventName); + return c.find(function(wrapper) { return wrapper.handler == handler }); + } + + function destroyWrapper(id, eventName, handler) { + var c = getCacheForID(id); + if (!c[eventName]) return false; + c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); + } + + function destroyCache() { + for (var id in cache) + for (var eventName in cache[id]) + cache[id][eventName] = null; + } + + if (window.attachEvent) { + window.attachEvent("onunload", destroyCache); + } + + return { + observe: function(element, eventName, handler) { + element = $(element); + var name = getDOMEventName(eventName); + + var wrapper = createWrapper(element, eventName, handler); + if (!wrapper) return element; + + if (element.addEventListener) { + element.addEventListener(name, wrapper, false); + } else { + element.attachEvent("on" + name, wrapper); + } + + return element; + }, + + stopObserving: function(element, eventName, handler) { + element = $(element); + var id = getEventID(element), name = getDOMEventName(eventName); + + if (!handler && eventName) { + getWrappersForEventName(id, eventName).each(function(wrapper) { + element.stopObserving(eventName, wrapper.handler); + }); + return element; + + } else if (!eventName) { + Object.keys(getCacheForID(id)).each(function(eventName) { + element.stopObserving(eventName); + }); + return element; + } + + var wrapper = findWrapper(id, eventName, handler); + if (!wrapper) return element; + + if (element.removeEventListener) { + element.removeEventListener(name, wrapper, false); + } else { + element.detachEvent("on" + name, wrapper); + } + + destroyWrapper(id, eventName, handler); + + return element; + }, + + fire: function(element, eventName, memo) { + element = $(element); + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent("HTMLEvents"); + event.initEvent("dataavailable", true, true); + } else { + event = document.createEventObject(); + event.eventType = "ondataavailable"; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) { + element.dispatchEvent(event); + } else { + element.fireEvent(event.eventType, event); + } + + return Event.extend(event); + } + }; +})()); + +Object.extend(Event, Event.Methods); + +Element.addMethods({ + fire: Event.fire, + observe: Event.observe, + stopObserving: Event.stopObserving +}); + +Object.extend(document, { + fire: Element.Methods.fire.methodize(), + observe: Element.Methods.observe.methodize(), + stopObserving: Element.Methods.stopObserving.methodize(), + loaded: false +}); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards and John Resig. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearInterval(timer); + document.fire("dom:loaded"); + document.loaded = true; + } + + if (document.addEventListener) { + if (Prototype.Browser.WebKit) { + timer = window.setInterval(function() { + if (/loaded|complete/.test(document.readyState)) + fireContentLoadedEvent(); + }, 0); + + Event.observe(window, "load", fireContentLoadedEvent); + + } else { + document.addEventListener("DOMContentLoaded", + fireContentLoadedEvent, false); + } + + } else { + document.write(" + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + +
    + + +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/advimage/css/advimage.css b/web/js/tiny_mce/plugins/advimage/css/advimage.css new file mode 100644 index 0000000..4d549a5 --- /dev/null +++ b/web/js/tiny_mce/plugins/advimage/css/advimage.css @@ -0,0 +1,13 @@ +#src_list, #over_list, #out_list {width:280px;} +.mceActionPanel {margin-top:7px;} +.alignPreview {border:1px solid #000; width:140px; height:140px; overflow:hidden; padding:5px;} +.checkbox {border:0;} +.panel_wrapper div.current {height:305px;} +#prev {margin:0; border:1px solid #000; width:99%; height:150px; overflow:auto;} +#align, #classlist {width:150px;} +#width, #height {vertical-align:middle; width:50px; text-align:center;} +#vspace, #hspace, #border {vertical-align:middle; width:30px; text-align:center;} +#class_list {width:180px;} +input {width: 280px;} +#constrain, #onmousemovecheck {width:auto;} +#id, #dir, #lang, #usemap, #longdesc {width:200px;} diff --git a/web/js/tiny_mce/plugins/advimage/editor_plugin.js b/web/js/tiny_mce/plugins/advimage/editor_plugin.js new file mode 100644 index 0000000..3af5057 --- /dev/null +++ b/web/js/tiny_mce/plugins/advimage/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.AdvancedImagePlugin',{init:function(ed,url){ed.addCommand('mceAdvImage',function(){if(ed.dom.getAttrib(ed.selection.getNode(),'class').indexOf('mceItem')!=-1)return;ed.windowManager.open({file:url+'/image.htm',width:480+parseInt(ed.getLang('advimage.delta_width',0)),height:385+parseInt(ed.getLang('advimage.delta_height',0)),inline:1},{plugin_url:url});});ed.addButton('image',{title:'advimage.image_desc',cmd:'mceAdvImage'});},getInfo:function(){return{longname:'Advanced image',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('advimage',tinymce.plugins.AdvancedImagePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advimage/editor_plugin_src.js b/web/js/tiny_mce/plugins/advimage/editor_plugin_src.js new file mode 100644 index 0000000..f526842 --- /dev/null +++ b/web/js/tiny_mce/plugins/advimage/editor_plugin_src.js @@ -0,0 +1,47 @@ +/** + * $Id: editor_plugin_src.js 677 2008-03-07 13:52:41Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.AdvancedImagePlugin', { + init : function(ed, url) { + // Register commands + ed.addCommand('mceAdvImage', function() { + // Internal image object like a flash placeholder + if (ed.dom.getAttrib(ed.selection.getNode(), 'class').indexOf('mceItem') != -1) + return; + + ed.windowManager.open({ + file : url + '/image.htm', + width : 480 + parseInt(ed.getLang('advimage.delta_width', 0)), + height : 385 + parseInt(ed.getLang('advimage.delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + // Register buttons + ed.addButton('image', { + title : 'advimage.image_desc', + cmd : 'mceAdvImage' + }); + }, + + getInfo : function() { + return { + longname : 'Advanced image', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('advimage', tinymce.plugins.AdvancedImagePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advimage/image.htm b/web/js/tiny_mce/plugins/advimage/image.htm new file mode 100644 index 0000000..56d3238 --- /dev/null +++ b/web/js/tiny_mce/plugins/advimage/image.htm @@ -0,0 +1,238 @@ + + + + {#advimage_dlg.dialog_title} + + + + + + + + + + +
    + + +
    +
    +
    + {#advimage_dlg.general} + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    +
    + +
    + {#advimage_dlg.preview} + +
    +
    + +
    +
    + {#advimage_dlg.tab_appearance} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + {#advimage_dlg.example_img} + Lorem ipsum, Dolor sit amet, consectetuer adipiscing loreum ipsum edipiscing elit, sed diam + nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.Loreum ipsum + edipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam + erat volutpat. +
    +
    + x + px +
      + + + + +
    +
    +
    +
    + +
    +
    + {#advimage_dlg.swap_image} + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    + + + + +
     
    +
    + +
    + {#advimage_dlg.misc} + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + +
    + + + + +
     
    +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/advimage/img/sample.gif b/web/js/tiny_mce/plugins/advimage/img/sample.gif new file mode 100644 index 0000000..53bf689 Binary files /dev/null and b/web/js/tiny_mce/plugins/advimage/img/sample.gif differ diff --git a/web/js/tiny_mce/plugins/advimage/js/image.js b/web/js/tiny_mce/plugins/advimage/js/image.js new file mode 100644 index 0000000..73a6e89 --- /dev/null +++ b/web/js/tiny_mce/plugins/advimage/js/image.js @@ -0,0 +1,441 @@ +var ImageDialog = { + preInit : function() { + var url; + + tinyMCEPopup.requireLangPack(); + + if (url = tinyMCEPopup.getParam("external_image_list_url")) + document.write(''); + }, + + init : function(ed) { + var f = document.forms[0], nl = f.elements, ed = tinyMCEPopup.editor, dom = ed.dom, n = ed.selection.getNode(); + + tinyMCEPopup.resizeToInnerSize(); + this.fillClassList('class_list'); + this.fillFileList('src_list', 'tinyMCEImageList'); + this.fillFileList('over_list', 'tinyMCEImageList'); + this.fillFileList('out_list', 'tinyMCEImageList'); + TinyMCE_EditableSelects.init(); + + if (n.nodeName == 'IMG') { + nl.src.value = dom.getAttrib(n, 'src'); + nl.width.value = dom.getAttrib(n, 'width'); + nl.height.value = dom.getAttrib(n, 'height'); + nl.alt.value = dom.getAttrib(n, 'alt'); + nl.title.value = dom.getAttrib(n, 'title'); + nl.vspace.value = this.getAttrib(n, 'vspace'); + nl.hspace.value = this.getAttrib(n, 'hspace'); + nl.border.value = this.getAttrib(n, 'border'); + selectByValue(f, 'align', this.getAttrib(n, 'align')); + selectByValue(f, 'class_list', dom.getAttrib(n, 'class'), true, true); + nl.style.value = dom.getAttrib(n, 'style'); + nl.id.value = dom.getAttrib(n, 'id'); + nl.dir.value = dom.getAttrib(n, 'dir'); + nl.lang.value = dom.getAttrib(n, 'lang'); + nl.usemap.value = dom.getAttrib(n, 'usemap'); + nl.longdesc.value = dom.getAttrib(n, 'longdesc'); + nl.insert.value = ed.getLang('update'); + + if (/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/.test(dom.getAttrib(n, 'onmouseover'))) + nl.onmouseoversrc.value = dom.getAttrib(n, 'onmouseover').replace(/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/, '$1'); + + if (/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/.test(dom.getAttrib(n, 'onmouseout'))) + nl.onmouseoutsrc.value = dom.getAttrib(n, 'onmouseout').replace(/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/, '$1'); + + if (ed.settings.inline_styles) { + // Move attribs to styles + if (dom.getAttrib(n, 'align')) + this.updateStyle('align'); + + if (dom.getAttrib(n, 'hspace')) + this.updateStyle('hspace'); + + if (dom.getAttrib(n, 'border')) + this.updateStyle('border'); + + if (dom.getAttrib(n, 'vspace')) + this.updateStyle('vspace'); + } + } + + // Setup browse button + document.getElementById('srcbrowsercontainer').innerHTML = getBrowserHTML('srcbrowser','src','image','theme_advanced_image'); + if (isVisible('srcbrowser')) + document.getElementById('src').style.width = '260px'; + + // Setup browse button + document.getElementById('onmouseoversrccontainer').innerHTML = getBrowserHTML('overbrowser','onmouseoversrc','image','theme_advanced_image'); + if (isVisible('overbrowser')) + document.getElementById('onmouseoversrc').style.width = '260px'; + + // Setup browse button + document.getElementById('onmouseoutsrccontainer').innerHTML = getBrowserHTML('outbrowser','onmouseoutsrc','image','theme_advanced_image'); + if (isVisible('outbrowser')) + document.getElementById('onmouseoutsrc').style.width = '260px'; + + // If option enabled default contrain proportions to checked + if (ed.getParam("advimage_constrain_proportions", true)) + f.constrain.checked = true; + + // Check swap image if valid data + if (nl.onmouseoversrc.value || nl.onmouseoutsrc.value) + this.setSwapImage(true); + else + this.setSwapImage(false); + + this.changeAppearance(); + this.showPreviewImage(nl.src.value, 1); + }, + + insert : function(file, title) { + var ed = tinyMCEPopup.editor, t = this, f = document.forms[0]; + + if (f.src.value === '') { + if (ed.selection.getNode().nodeName == 'IMG') { + ed.dom.remove(ed.selection.getNode()); + ed.execCommand('mceRepaint'); + } + + tinyMCEPopup.close(); + return; + } + + if (tinyMCEPopup.getParam("accessibility_warnings", 1)) { + if (!f.alt.value) { + tinyMCEPopup.editor.windowManager.confirm(tinyMCEPopup.getLang('advimage_dlg.missing_alt'), function(s) { + if (s) + t.insertAndClose(); + }); + + return; + } + } + + t.insertAndClose(); + }, + + insertAndClose : function() { + var ed = tinyMCEPopup.editor, f = document.forms[0], nl = f.elements, v, args = {}, el; + + tinyMCEPopup.restoreSelection(); + + // Fixes crash in Safari + if (tinymce.isWebKit) + ed.getWin().focus(); + + if (!ed.settings.inline_styles) { + args = { + vspace : nl.vspace.value, + hspace : nl.hspace.value, + border : nl.border.value, + align : getSelectValue(f, 'align') + }; + } else { + // Remove deprecated values + args = { + vspace : '', + hspace : '', + border : '', + align : '' + }; + } + + tinymce.extend(args, { + src : nl.src.value, + width : nl.width.value, + height : nl.height.value, + alt : nl.alt.value, + title : nl.title.value, + 'class' : getSelectValue(f, 'class_list'), + style : nl.style.value, + id : nl.id.value, + dir : nl.dir.value, + lang : nl.lang.value, + usemap : nl.usemap.value, + longdesc : nl.longdesc.value + }); + + args.onmouseover = args.onmouseout = ''; + + if (f.onmousemovecheck.checked) { + if (nl.onmouseoversrc.value) + args.onmouseover = "this.src='" + nl.onmouseoversrc.value + "';"; + + if (nl.onmouseoutsrc.value) + args.onmouseout = "this.src='" + nl.onmouseoutsrc.value + "';"; + } + + el = ed.selection.getNode(); + + if (el && el.nodeName == 'IMG') { + ed.dom.setAttribs(el, args); + } else { + ed.execCommand('mceInsertContent', false, '', {skip_undo : 1}); + ed.dom.setAttribs('__mce_tmp', args); + ed.dom.setAttrib('__mce_tmp', 'id', ''); + ed.undoManager.add(); + } + + tinyMCEPopup.close(); + }, + + getAttrib : function(e, at) { + var ed = tinyMCEPopup.editor, dom = ed.dom, v, v2; + + if (ed.settings.inline_styles) { + switch (at) { + case 'align': + if (v = dom.getStyle(e, 'float')) + return v; + + if (v = dom.getStyle(e, 'vertical-align')) + return v; + + break; + + case 'hspace': + v = dom.getStyle(e, 'margin-left') + v2 = dom.getStyle(e, 'margin-right'); + + if (v && v == v2) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + + case 'vspace': + v = dom.getStyle(e, 'margin-top') + v2 = dom.getStyle(e, 'margin-bottom'); + if (v && v == v2) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + + case 'border': + v = 0; + + tinymce.each(['top', 'right', 'bottom', 'left'], function(sv) { + sv = dom.getStyle(e, 'border-' + sv + '-width'); + + // False or not the same as prev + if (!sv || (sv != v && v !== 0)) { + v = 0; + return false; + } + + if (sv) + v = sv; + }); + + if (v) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + } + } + + if (v = dom.getAttrib(e, at)) + return v; + + return ''; + }, + + setSwapImage : function(st) { + var f = document.forms[0]; + + f.onmousemovecheck.checked = st; + setBrowserDisabled('overbrowser', !st); + setBrowserDisabled('outbrowser', !st); + + if (f.over_list) + f.over_list.disabled = !st; + + if (f.out_list) + f.out_list.disabled = !st; + + f.onmouseoversrc.disabled = !st; + f.onmouseoutsrc.disabled = !st; + }, + + fillClassList : function(id) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl; + + if (v = tinyMCEPopup.getParam('theme_advanced_styles')) { + cl = []; + + tinymce.each(v.split(';'), function(v) { + var p = v.split('='); + + cl.push({'title' : p[0], 'class' : p[1]}); + }); + } else + cl = tinyMCEPopup.editor.dom.getClasses(); + + if (cl.length > 0) { + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), ''); + + tinymce.each(cl, function(o) { + lst.options[lst.options.length] = new Option(o.title || o['class'], o['class']); + }); + } else + dom.remove(dom.getParent(id, 'tr')); + }, + + fillFileList : function(id, l) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl; + + l = window[l]; + + if (l && l.length > 0) { + lst.options[lst.options.length] = new Option('', ''); + + tinymce.each(l, function(o) { + lst.options[lst.options.length] = new Option(o[0], o[1]); + }); + } else + dom.remove(dom.getParent(id, 'tr')); + }, + + resetImageData : function() { + var f = document.forms[0]; + + f.elements.width.value = f.elements.height.value = ''; + }, + + updateImageData : function(img, st) { + var f = document.forms[0]; + + if (!st) { + f.elements.width.value = img.width; + f.elements.height.value = img.height; + } + + this.preloadImg = img; + }, + + changeAppearance : function() { + var ed = tinyMCEPopup.editor, f = document.forms[0], img = document.getElementById('alignSampleImg'); + + if (img) { + if (ed.getParam('inline_styles')) { + ed.dom.setAttrib(img, 'style', f.style.value); + } else { + img.align = f.align.value; + img.border = f.border.value; + img.hspace = f.hspace.value; + img.vspace = f.vspace.value; + } + } + }, + + changeHeight : function() { + var f = document.forms[0], tp, t = this; + + if (!f.constrain.checked || !t.preloadImg) { + return; + } + + if (f.width.value == "" || f.height.value == "") + return; + + tp = (parseInt(f.width.value) / parseInt(t.preloadImg.width)) * t.preloadImg.height; + f.height.value = tp.toFixed(0); + }, + + changeWidth : function() { + var f = document.forms[0], tp, t = this; + + if (!f.constrain.checked || !t.preloadImg) { + return; + } + + if (f.width.value == "" || f.height.value == "") + return; + + tp = (parseInt(f.height.value) / parseInt(t.preloadImg.height)) * t.preloadImg.width; + f.width.value = tp.toFixed(0); + }, + + updateStyle : function(ty) { + var dom = tinyMCEPopup.dom, st, v, f = document.forms[0], img = dom.create('img', {style : dom.get('style').value}); + + if (tinyMCEPopup.editor.settings.inline_styles) { + // Handle align + if (ty == 'align') { + dom.setStyle(img, 'float', ''); + dom.setStyle(img, 'vertical-align', ''); + + v = getSelectValue(f, 'align'); + if (v) { + if (v == 'left' || v == 'right') + dom.setStyle(img, 'float', v); + else + img.style.verticalAlign = v; + } + } + + // Handle border + if (ty == 'border') { + dom.setStyle(img, 'border', ''); + + v = f.border.value; + if (v || v == '0') { + if (v == '0') + img.style.border = ''; + else + img.style.border = v + 'px solid black'; + } + } + + // Handle hspace + if (ty == 'hspace') { + dom.setStyle(img, 'marginLeft', ''); + dom.setStyle(img, 'marginRight', ''); + + v = f.hspace.value; + if (v) { + img.style.marginLeft = v + 'px'; + img.style.marginRight = v + 'px'; + } + } + + // Handle vspace + if (ty == 'vspace') { + dom.setStyle(img, 'marginTop', ''); + dom.setStyle(img, 'marginBottom', ''); + + v = f.vspace.value; + if (v) { + img.style.marginTop = v + 'px'; + img.style.marginBottom = v + 'px'; + } + } + + // Merge + dom.get('style').value = dom.serializeStyle(dom.parseStyle(img.style.cssText)); + } + }, + + changeMouseMove : function() { + }, + + showPreviewImage : function(u, st) { + if (!u) { + tinyMCEPopup.dom.setHTML('prev', ''); + return; + } + + if (!st && tinyMCEPopup.getParam("advimage_update_dimensions_onchange", true)) + this.resetImageData(); + + u = tinyMCEPopup.editor.documentBaseURI.toAbsolute(u); + + if (!st) + tinyMCEPopup.dom.setHTML('prev', ''); + else + tinyMCEPopup.dom.setHTML('prev', ''); + } +}; + +ImageDialog.preInit(); +tinyMCEPopup.onInit.add(ImageDialog.init, ImageDialog); diff --git a/web/js/tiny_mce/plugins/advimage/langs/en_dlg.js b/web/js/tiny_mce/plugins/advimage/langs/en_dlg.js new file mode 100644 index 0000000..f493d19 --- /dev/null +++ b/web/js/tiny_mce/plugins/advimage/langs/en_dlg.js @@ -0,0 +1,43 @@ +tinyMCE.addI18n('en.advimage_dlg',{ +tab_general:"General", +tab_appearance:"Appearance", +tab_advanced:"Advanced", +general:"General", +title:"Title", +preview:"Preview", +constrain_proportions:"Constrain proportions", +langdir:"Language direction", +langcode:"Language code", +long_desc:"Long description link", +style:"Style", +classes:"Classes", +ltr:"Left to right", +rtl:"Right to left", +id:"Id", +map:"Image map", +swap_image:"Swap image", +alt_image:"Alternative image", +mouseover:"for mouse over", +mouseout:"for mouse out", +misc:"Miscellaneous", +example_img:"Appearance preview image", +missing_alt:"Are you sure you want to continue without including an Image Description? Without it the image may not be accessible to some users with disabilities, or to those using a text browser, or browsing the Web with images turned off.", +dialog_title:"Insert/edit image", +src:"Image URL", +alt:"Image description", +list:"Image list", +border:"Border", +dimensions:"Dimensions", +vspace:"Vertical space", +hspace:"Horizontal space", +align:"Alignment", +align_baseline:"Baseline", +align_top:"Top", +align_middle:"Middle", +align_bottom:"Bottom", +align_texttop:"Text top", +align_textbottom:"Text bottom", +align_left:"Left", +align_right:"Right", +image_list:"Image list" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advimage/langs/nb_dlg.js b/web/js/tiny_mce/plugins/advimage/langs/nb_dlg.js new file mode 100644 index 0000000..43a780b --- /dev/null +++ b/web/js/tiny_mce/plugins/advimage/langs/nb_dlg.js @@ -0,0 +1,43 @@ +tinyMCE.addI18n('nb.advimage_dlg',{ +tab_general:"Generelt", +tab_appearance:"Utseende", +tab_advanced:"Avansert", +general:"Generelt", +title:"Tittel", +preview:"Forh\u00E5ndsvisning", +constrain_proportions:"Behold st\u00F8rrelsesforhold", +langdir:"Skriftretning", +langcode:"Spr\u00E5kkode", +long_desc:"Lang beskrivelse", +style:"Stil", +classes:"Klasser", +ltr:"Venstre mot h\u00F8yre", +rtl:"H\u00F8yre mot venstre", +id:"Id", +map:"Bildekart", +swap_image:"Bytt bilde", +alt_image:"Alternativt bilde", +mouseover:"for musepeker p\u00E5", +mouseout:"for musepeker utenfor", +misc:"Annet", +example_img:"Utseende Forh\u00E5ndsvisning bilde", +missing_alt:"Er du sikker p\u00E5 at du vil fortsette uten \u00E5 sette inn en beskrivelse av bildet? Uten beskrivelse vil bildet ikke gi mening for enkelte funksjonshemmede eller for personer som bruker en nettleser med bildevisning avsl\u00E5tt.", +dialog_title:"Sett inn / endre bilde", +src:"Bildets URL", +alt:"Bildebeskrivelse", +list:"Bildeliste", +border:"Ramme", +dimensions:"Dimensjoner", +vspace:"Vertikal avstand", +hspace:"Horisontal avstand", +align:"Justering", +align_baseline:"Grunnlinje", +align_top:"Topp", +align_middle:"Midtstilt", +align_bottom:"Bunn", +align_texttop:"Tekst topp", +align_textbottom:"Tekst bunn", +align_left:"Venstre", +align_right:"H\u00F8yre", +image_list:"Bildeliste" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advimage/langs/nn_dlg.js b/web/js/tiny_mce/plugins/advimage/langs/nn_dlg.js new file mode 100644 index 0000000..89e10c1 --- /dev/null +++ b/web/js/tiny_mce/plugins/advimage/langs/nn_dlg.js @@ -0,0 +1,43 @@ +tinyMCE.addI18n('nn.advimage_dlg',{ +tab_general:"Generelt", +tab_appearance:"Utsj\u00E5nad", +tab_advanced:"Avansert", +general:"Generelt", +title:"Tittel", +preview:"Sj\u00E5 f\u00F8rebels utkast", +constrain_proportions:"Behald proporsjonar", +langdir:"Skriftretning", +langcode:"Spr\u00E5kkode", +long_desc:"Lang omtale", +style:"Stil", +classes:"Klasser", +ltr:"Venstre mot h\u00F8gre", +rtl:"H\u00F8gre mot venstre", +id:"Id", +map:"Biletekart", +swap_image:"Byt bilete", +alt_image:"Alternativt bilete", +mouseover:"for musepeikar over", +mouseout:"for musepeikar utanfor", +misc:"Anna", +example_img:"Sj\u00E5 f\u00F8rebels utkast av bilete", +missing_alt:"Er du sikker p\u00E5 at du vil fortsetje utan \u00E5 setje inn ei omtale av biletet? Utan omtale vil biletet ikkje gje meining for enkelte funksjonshemma eller for personar som bruker ein nettlesar med biletvisinga avsl\u00E5tt.", +dialog_title:"Set inn / endre bilete", +src:"Bilete-URL", +alt:"Bileteomtale", +list:"Bileteliste", +border:"Ramme", +dimensions:"Dimensjonar", +vspace:"Vertikal avstand", +hspace:"Horisontal avstand", +align:"Justering", +align_baseline:"Basislinje", +align_top:"Topp", +align_middle:"Midtstilt", +align_bottom:"Botn", +align_texttop:"Tekst topp", +align_textbottom:"Tekst botn", +align_left:"Venstre", +align_right:"H\u00F8gre", +image_list:"Liste med bilete" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advlink/css/advlink.css b/web/js/tiny_mce/plugins/advlink/css/advlink.css new file mode 100644 index 0000000..1436431 --- /dev/null +++ b/web/js/tiny_mce/plugins/advlink/css/advlink.css @@ -0,0 +1,8 @@ +.mceLinkList, .mceAnchorList, #targetlist {width:280px;} +.mceActionPanel {margin-top:7px;} +.panel_wrapper div.current {height:320px;} +#classlist, #title, #href {width:280px;} +#popupurl, #popupname {width:200px;} +#popupwidth, #popupheight, #popupleft, #popuptop {width:30px;vertical-align:middle;text-align:center;} +#id, #style, #classes, #target, #dir, #hreflang, #lang, #charset, #type, #rel, #rev, #tabindex, #accesskey {width:200px;} +#events_panel input {width:200px;} diff --git a/web/js/tiny_mce/plugins/advlink/editor_plugin.js b/web/js/tiny_mce/plugins/advlink/editor_plugin.js new file mode 100644 index 0000000..4899f7b --- /dev/null +++ b/web/js/tiny_mce/plugins/advlink/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.AdvancedLinkPlugin',{init:function(ed,url){this.editor=ed;ed.addCommand('mceAdvLink',function(){var se=ed.selection;if(se.isCollapsed()&&!ed.dom.getParent(se.getNode(),'A'))return;ed.windowManager.open({file:url+'/link.htm',width:480+parseInt(ed.getLang('advlink.delta_width',0)),height:400+parseInt(ed.getLang('advlink.delta_height',0)),inline:1},{plugin_url:url});});ed.addButton('link',{title:'advlink.link_desc',cmd:'mceAdvLink'});ed.addShortcut('ctrl+k','advlink.advlink_desc','mceAdvLink');ed.onNodeChange.add(function(ed,cm,n,co){cm.setDisabled('link',co&&n.nodeName!='A');cm.setActive('link',n.nodeName=='A'&&!n.name);});},getInfo:function(){return{longname:'Advanced link',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('advlink',tinymce.plugins.AdvancedLinkPlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advlink/editor_plugin_src.js b/web/js/tiny_mce/plugins/advlink/editor_plugin_src.js new file mode 100644 index 0000000..fc5325a --- /dev/null +++ b/web/js/tiny_mce/plugins/advlink/editor_plugin_src.js @@ -0,0 +1,58 @@ +/** + * $Id: editor_plugin_src.js 539 2008-01-14 19:08:58Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.AdvancedLinkPlugin', { + init : function(ed, url) { + this.editor = ed; + + // Register commands + ed.addCommand('mceAdvLink', function() { + var se = ed.selection; + + // No selection and not in link + if (se.isCollapsed() && !ed.dom.getParent(se.getNode(), 'A')) + return; + + ed.windowManager.open({ + file : url + '/link.htm', + width : 480 + parseInt(ed.getLang('advlink.delta_width', 0)), + height : 400 + parseInt(ed.getLang('advlink.delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + // Register buttons + ed.addButton('link', { + title : 'advlink.link_desc', + cmd : 'mceAdvLink' + }); + + ed.addShortcut('ctrl+k', 'advlink.advlink_desc', 'mceAdvLink'); + + ed.onNodeChange.add(function(ed, cm, n, co) { + cm.setDisabled('link', co && n.nodeName != 'A'); + cm.setActive('link', n.nodeName == 'A' && !n.name); + }); + }, + + getInfo : function() { + return { + longname : 'Advanced link', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('advlink', tinymce.plugins.AdvancedLinkPlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advlink/js/advlink.js b/web/js/tiny_mce/plugins/advlink/js/advlink.js new file mode 100644 index 0000000..2efc1b7 --- /dev/null +++ b/web/js/tiny_mce/plugins/advlink/js/advlink.js @@ -0,0 +1,528 @@ +/* Functions for the advlink plugin popup */ + +tinyMCEPopup.requireLangPack(); + +var templates = { + "window.open" : "window.open('${url}','${target}','${options}')" +}; + +function preinit() { + var url; + + if (url = tinyMCEPopup.getParam("external_link_list_url")) + document.write(''); +} + +function changeClass() { + var f = document.forms[0]; + + f.classes.value = getSelectValue(f, 'classlist'); +} + +function init() { + tinyMCEPopup.resizeToInnerSize(); + + var formObj = document.forms[0]; + var inst = tinyMCEPopup.editor; + var elm = inst.selection.getNode(); + var action = "insert"; + var html; + + document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser','href','file','advlink'); + document.getElementById('popupurlbrowsercontainer').innerHTML = getBrowserHTML('popupurlbrowser','popupurl','file','advlink'); + document.getElementById('linklisthrefcontainer').innerHTML = getLinkListHTML('linklisthref','href'); + document.getElementById('anchorlistcontainer').innerHTML = getAnchorListHTML('anchorlist','href'); + document.getElementById('targetlistcontainer').innerHTML = getTargetListHTML('targetlist','target'); + + // Link list + html = getLinkListHTML('linklisthref','href'); + if (html == "") + document.getElementById("linklisthrefrow").style.display = 'none'; + else + document.getElementById("linklisthrefcontainer").innerHTML = html; + + // Resize some elements + if (isVisible('hrefbrowser')) + document.getElementById('href').style.width = '260px'; + + if (isVisible('popupurlbrowser')) + document.getElementById('popupurl').style.width = '180px'; + + elm = inst.dom.getParent(elm, "A"); + if (elm != null && elm.nodeName == "A") + action = "update"; + + formObj.insert.value = tinyMCEPopup.getLang(action, 'Insert', true); + + setPopupControlsDisabled(true); + + if (action == "update") { + var href = inst.dom.getAttrib(elm, 'href'); + var onclick = inst.dom.getAttrib(elm, 'onclick'); + + // Setup form data + setFormValue('href', href); + setFormValue('title', inst.dom.getAttrib(elm, 'title')); + setFormValue('id', inst.dom.getAttrib(elm, 'id')); + setFormValue('style', inst.dom.getAttrib(elm, "style")); + setFormValue('rel', inst.dom.getAttrib(elm, 'rel')); + setFormValue('rev', inst.dom.getAttrib(elm, 'rev')); + setFormValue('charset', inst.dom.getAttrib(elm, 'charset')); + setFormValue('hreflang', inst.dom.getAttrib(elm, 'hreflang')); + setFormValue('dir', inst.dom.getAttrib(elm, 'dir')); + setFormValue('lang', inst.dom.getAttrib(elm, 'lang')); + setFormValue('tabindex', inst.dom.getAttrib(elm, 'tabindex', typeof(elm.tabindex) != "undefined" ? elm.tabindex : "")); + setFormValue('accesskey', inst.dom.getAttrib(elm, 'accesskey', typeof(elm.accesskey) != "undefined" ? elm.accesskey : "")); + setFormValue('type', inst.dom.getAttrib(elm, 'type')); + setFormValue('onfocus', inst.dom.getAttrib(elm, 'onfocus')); + setFormValue('onblur', inst.dom.getAttrib(elm, 'onblur')); + setFormValue('onclick', onclick); + setFormValue('ondblclick', inst.dom.getAttrib(elm, 'ondblclick')); + setFormValue('onmousedown', inst.dom.getAttrib(elm, 'onmousedown')); + setFormValue('onmouseup', inst.dom.getAttrib(elm, 'onmouseup')); + setFormValue('onmouseover', inst.dom.getAttrib(elm, 'onmouseover')); + setFormValue('onmousemove', inst.dom.getAttrib(elm, 'onmousemove')); + setFormValue('onmouseout', inst.dom.getAttrib(elm, 'onmouseout')); + setFormValue('onkeypress', inst.dom.getAttrib(elm, 'onkeypress')); + setFormValue('onkeydown', inst.dom.getAttrib(elm, 'onkeydown')); + setFormValue('onkeyup', inst.dom.getAttrib(elm, 'onkeyup')); + setFormValue('target', inst.dom.getAttrib(elm, 'target')); + setFormValue('classes', inst.dom.getAttrib(elm, 'class')); + + // Parse onclick data + if (onclick != null && onclick.indexOf('window.open') != -1) + parseWindowOpen(onclick); + else + parseFunction(onclick); + + // Select by the values + selectByValue(formObj, 'dir', inst.dom.getAttrib(elm, 'dir')); + selectByValue(formObj, 'rel', inst.dom.getAttrib(elm, 'rel')); + selectByValue(formObj, 'rev', inst.dom.getAttrib(elm, 'rev')); + selectByValue(formObj, 'linklisthref', href); + + if (href.charAt(0) == '#') + selectByValue(formObj, 'anchorlist', href); + + addClassesToList('classlist', 'advlink_styles'); + + selectByValue(formObj, 'classlist', inst.dom.getAttrib(elm, 'class'), true); + selectByValue(formObj, 'targetlist', inst.dom.getAttrib(elm, 'target'), true); + } else + addClassesToList('classlist', 'advlink_styles'); +} + +function checkPrefix(n) { + if (n.value && Validator.isEmail(n) && !/^\s*mailto:/i.test(n.value) && confirm(tinyMCEPopup.getLang('advlink_dlg.is_email'))) + n.value = 'mailto:' + n.value; + + if (/^\s*www./i.test(n.value) && confirm(tinyMCEPopup.getLang('advlink_dlg.is_external'))) + n.value = 'http://' + n.value; +} + +function setFormValue(name, value) { + document.forms[0].elements[name].value = value; +} + +function parseWindowOpen(onclick) { + var formObj = document.forms[0]; + + // Preprocess center code + if (onclick.indexOf('return false;') != -1) { + formObj.popupreturn.checked = true; + onclick = onclick.replace('return false;', ''); + } else + formObj.popupreturn.checked = false; + + var onClickData = parseLink(onclick); + + if (onClickData != null) { + formObj.ispopup.checked = true; + setPopupControlsDisabled(false); + + var onClickWindowOptions = parseOptions(onClickData['options']); + var url = onClickData['url']; + + formObj.popupname.value = onClickData['target']; + formObj.popupurl.value = url; + formObj.popupwidth.value = getOption(onClickWindowOptions, 'width'); + formObj.popupheight.value = getOption(onClickWindowOptions, 'height'); + + formObj.popupleft.value = getOption(onClickWindowOptions, 'left'); + formObj.popuptop.value = getOption(onClickWindowOptions, 'top'); + + if (formObj.popupleft.value.indexOf('screen') != -1) + formObj.popupleft.value = "c"; + + if (formObj.popuptop.value.indexOf('screen') != -1) + formObj.popuptop.value = "c"; + + formObj.popuplocation.checked = getOption(onClickWindowOptions, 'location') == "yes"; + formObj.popupscrollbars.checked = getOption(onClickWindowOptions, 'scrollbars') == "yes"; + formObj.popupmenubar.checked = getOption(onClickWindowOptions, 'menubar') == "yes"; + formObj.popupresizable.checked = getOption(onClickWindowOptions, 'resizable') == "yes"; + formObj.popuptoolbar.checked = getOption(onClickWindowOptions, 'toolbar') == "yes"; + formObj.popupstatus.checked = getOption(onClickWindowOptions, 'status') == "yes"; + formObj.popupdependent.checked = getOption(onClickWindowOptions, 'dependent') == "yes"; + + buildOnClick(); + } +} + +function parseFunction(onclick) { + var formObj = document.forms[0]; + var onClickData = parseLink(onclick); + + // TODO: Add stuff here +} + +function getOption(opts, name) { + return typeof(opts[name]) == "undefined" ? "" : opts[name]; +} + +function setPopupControlsDisabled(state) { + var formObj = document.forms[0]; + + formObj.popupname.disabled = state; + formObj.popupurl.disabled = state; + formObj.popupwidth.disabled = state; + formObj.popupheight.disabled = state; + formObj.popupleft.disabled = state; + formObj.popuptop.disabled = state; + formObj.popuplocation.disabled = state; + formObj.popupscrollbars.disabled = state; + formObj.popupmenubar.disabled = state; + formObj.popupresizable.disabled = state; + formObj.popuptoolbar.disabled = state; + formObj.popupstatus.disabled = state; + formObj.popupreturn.disabled = state; + formObj.popupdependent.disabled = state; + + setBrowserDisabled('popupurlbrowser', state); +} + +function parseLink(link) { + link = link.replace(new RegExp(''', 'g'), "'"); + + var fnName = link.replace(new RegExp("\\s*([A-Za-z0-9\.]*)\\s*\\(.*", "gi"), "$1"); + + // Is function name a template function + var template = templates[fnName]; + if (template) { + // Build regexp + var variableNames = template.match(new RegExp("'?\\$\\{[A-Za-z0-9\.]*\\}'?", "gi")); + var regExp = "\\s*[A-Za-z0-9\.]*\\s*\\("; + var replaceStr = ""; + for (var i=0; i'); + for (var i=0; i'; + html += ''; + + for (i=0; i' + name + ''; + } + + html += ''; + + return html; +} + +function insertAction() { + var inst = tinyMCEPopup.editor; + var elm, elementArray, i; + + elm = inst.selection.getNode(); + checkPrefix(document.forms[0].href); + + elm = inst.dom.getParent(elm, "A"); + + // Remove element if there is no href + if (!document.forms[0].href.value) { + tinyMCEPopup.execCommand("mceBeginUndoLevel"); + i = inst.selection.getBookmark(); + inst.dom.remove(elm, 1); + inst.selection.moveToBookmark(i); + tinyMCEPopup.execCommand("mceEndUndoLevel"); + tinyMCEPopup.close(); + return; + } + + tinyMCEPopup.execCommand("mceBeginUndoLevel"); + + // Create new anchor elements + if (elm == null) { + tinyMCEPopup.execCommand("CreateLink", false, "#mce_temp_url#", {skip_undo : 1}); + + elementArray = tinymce.grep(inst.dom.select("a"), function(n) {return inst.dom.getAttrib(n, 'href') == '#mce_temp_url#';}); + for (i=0; i' + tinyMCELinkList[i][0] + ''; + + html += ''; + + return html; + + // tinyMCE.debug('-- image list start --', html, '-- image list end --'); +} + +function getTargetListHTML(elm_id, target_form_element) { + var targets = tinyMCEPopup.getParam('theme_advanced_link_targets', '').split(';'); + var html = ''; + + html += ''; + + return html; +} + +// While loading +preinit(); +tinyMCEPopup.onInit.add(init); diff --git a/web/js/tiny_mce/plugins/advlink/langs/en_dlg.js b/web/js/tiny_mce/plugins/advlink/langs/en_dlg.js new file mode 100644 index 0000000..c71ffbd --- /dev/null +++ b/web/js/tiny_mce/plugins/advlink/langs/en_dlg.js @@ -0,0 +1,52 @@ +tinyMCE.addI18n('en.advlink_dlg',{ +title:"Insert/edit link", +url:"Link URL", +target:"Target", +titlefield:"Title", +is_email:"The URL you entered seems to be an email address, do you want to add the required mailto: prefix?", +is_external:"The URL you entered seems to external link, do you want to add the required http:// prefix?", +list:"Link list", +general_tab:"General", +popup_tab:"Popup", +events_tab:"Events", +advanced_tab:"Advanced", +general_props:"General properties", +popup_props:"Popup properties", +event_props:"Events", +advanced_props:"Advanced properties", +popup_opts:"Options", +anchor_names:"Anchors", +target_same:"Open in this window / frame", +target_parent:"Open in parent window / frame", +target_top:"Open in top frame (replaces all frames)", +target_blank:"Open in new window", +popup:"Javascript popup", +popup_url:"Popup URL", +popup_name:"Window name", +popup_return:"Insert 'return false'", +popup_scrollbars:"Show scrollbars", +popup_statusbar:"Show status bar", +popup_toolbar:"Show toolbars", +popup_menubar:"Show menu bar", +popup_location:"Show location bar", +popup_resizable:"Make window resizable", +popup_dependent:"Dependent (Mozilla/Firefox only)", +popup_size:"Size", +popup_position:"Position (X/Y)", +id:"Id", +style:"Style", +classes:"Classes", +target_name:"Target name", +langdir:"Language direction", +target_langcode:"Target language", +langcode:"Language code", +encoding:"Target character encoding", +mime:"Target MIME type", +rel:"Relationship page to target", +rev:"Relationship target to page", +tabindex:"Tabindex", +accesskey:"Accesskey", +ltr:"Left to right", +rtl:"Right to left", +link_list:"Link list" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advlink/langs/nb_dlg.js b/web/js/tiny_mce/plugins/advlink/langs/nb_dlg.js new file mode 100644 index 0000000..5066c68 --- /dev/null +++ b/web/js/tiny_mce/plugins/advlink/langs/nb_dlg.js @@ -0,0 +1,52 @@ +tinyMCE.addI18n('nb.advlink_dlg',{ +title:"Sett inn / rediger lenke", +url:"Lenkens URL", +target:"M\u00E5l", +titlefield:"Tittel", +is_email:"URL'en du oppga synes \u00E5 v\u00E6re en email adresse, \u00F8nsker du \u00E5 legge til den n\u00F8dvendige mailto: prefix?", +is_external:"URL'en du oppga synes \u00E5 v\u00E6re en ekstern lenke, \u00F8nsker du \u00E5 legge til den n\u00F8dvendige http:// prefix?", +list:"Lenkeliste", +general_tab:"Generelt", +popup_tab:"Popup", +events_tab:"Hendelser", +advanced_tab:"Avansert", +general_props:"Generelle egenskaper", +popup_props:"Popup-egenskaper", +event_props:"Hendelser", +advanced_props:"Generelle egenskaper", +popup_opts:"Innstillinger", +anchor_names:"Anker", +target_same:"\u00C5pne i samme vindu/ramme", +target_parent:"\u00C5pne i overordnet vindu/ramme", +target_top:"\u00C5pne i toppvindu (erstatter alle rammer)", +target_blank:"\u00C5pne i nytt vindu", +popup:"Javascript-popup", +popup_url:"Popup URL", +popup_name:"Vindunavn", +popup_return:"Sett inn \'return false\'", +popup_scrollbars:"Vis rullefelt", +popup_statusbar:"Vis statuslinje", +popup_toolbar:"Vis verkt\u00F8ylinjer", +popup_menubar:"Vis menylinje", +popup_location:"Vis plasseringslinje", +popup_resizable:"Gj\u00F8r vinduet skalerbart", +popup_dependent:"Avhengig vindu (bare i Mozilla/Firefox)", +popup_size:"St\u00F8rrelse", +popup_position:"Posisjon (X/Y)", +id:"Id", +style:"Stil", +classes:"Klasser", +target_name:"M\u00E5lnavn", +langdir:"Skriftretning", +target_langcode:"M\u00E5lspr\u00E5k", +langcode:"Spr\u00E5kkode", +encoding:"Tegnkonvertering", +mime:"M\u00E5lets MIME-type", +rel:"Sidens forhold til m\u00E5let", +rev:"M\u00E5lets forhold til siden", +tabindex:"Tabulatorindeks", +accesskey:"Hurtigtast", +ltr:"Venstre mot h\u00F8yre", +rtl:"H\u00F8yre mot venstre", +link_list:"Lenkeliste" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advlink/langs/nn_dlg.js b/web/js/tiny_mce/plugins/advlink/langs/nn_dlg.js new file mode 100644 index 0000000..c1d18ea --- /dev/null +++ b/web/js/tiny_mce/plugins/advlink/langs/nn_dlg.js @@ -0,0 +1,52 @@ +tinyMCE.addI18n('nn.advlink_dlg',{ +title:"Set inn / rediger lenkje", +url:"Lenkje-URL", +target:"M\u00E5l", +titlefield:"Tittel", +is_email:"URL-en du skreiv inn ser ut til \u00E5 vere ei e-postadresse. \u00D8nskjer du \u00E5 leggje til det obligatoriske mailto:-prefikset?", +is_external:"URL-en du skreiv inn ser ut til \u00E5 vere ei eksern lenkje. \u00D8nskjer du \u00E5 leggje til det obligatoriske http://-prefikset?", +list:"Lenkjeliste", +general_tab:"Generelt", +popup_tab:"Popup", +events_tab:"Hendingar", +advanced_tab:"Avansert", +general_props:"Generelt", +popup_props:"Popup-eigenskapar", +event_props:"Hendingar", +advanced_props:"Generelle eigenskapar", +popup_opts:"Innstillingar", +anchor_names:"Anker", +target_same:"Opne i same vindauge/ramme", +target_parent:"Opne i overordna vindauge/ramme", +target_top:"Opne i toppvindauge (erstattar alle rammer)", +target_blank:"Opne i nytt vindauge", +popup:"Javascript-popup", +popup_url:"Popup URL", +popup_name:"Namn p\u00E5 vindauge", +popup_return:"Set inn \'return false\'", +popup_scrollbars:"Vis rullefelt", +popup_statusbar:"Vis statusline", +popup_toolbar:"Vis verktyliner", +popup_menubar:"Vis menyline", +popup_location:"Vis plasseringsline", +popup_resizable:"Gjer vindauget skalerbart", +popup_dependent:"Avhengig vindu (berre i Mozilla/Firefox)", +popup_size:"Storleik", +popup_position:"Posisjon (X/Y)", +id:"Id", +style:"Stil", +classes:"Klasser", +target_name:"M\u00E5lnamn", +langdir:"Skriftretning", +target_langcode:"M\u00E5lspr\u00E5k", +langcode:"Spr\u00E5kkode", +encoding:"Teiknkonvertering", +mime:"M\u00E5let sin MIME-type", +rel:"Sida sitt forhold til m\u00E5let", +rev:"M\u00E5let sitt forhold til sida", +tabindex:"Tabulatorindeks", +accesskey:"Hurtigtast", +ltr:"Venstre mot h\u00F8gre", +rtl:"H\u00F8gre mot venstre", +link_list:"Lenkjeliste" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/advlink/link.htm b/web/js/tiny_mce/plugins/advlink/link.htm new file mode 100644 index 0000000..0e60d58 --- /dev/null +++ b/web/js/tiny_mce/plugins/advlink/link.htm @@ -0,0 +1,339 @@ + + + + {#advlink_dlg.title} + + + + + + + + + +
    + + +
    +
    +
    + {#advlink_dlg.general_props} + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
     
     
     
    + +
    +
    +
    + + + +
    +
    + {#advlink_dlg.advanced_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    + {#advlink_dlg.event_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/artworklist/editor_plugin.js b/web/js/tiny_mce/plugins/artworklist/editor_plugin.js new file mode 100644 index 0000000..3cefa84 --- /dev/null +++ b/web/js/tiny_mce/plugins/artworklist/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.ArtworkListPlugin',{init:function(ed,url){ed.addCommand('mceArtworkList',function(){ed.windowManager.open({file:'browse/artworks/'+document.getElementById("popup_id").value,width:620+parseInt(ed.getLang('artworklist.delta_width',0)),height:420+parseInt(ed.getLang('artworklist.delta_height',0)),inline:1},{plugin_url:url})});ed.addButton('artworklist',{title:'Link artwork to article',cmd:'mceArtworkList',image:url+'/img/artworklist.gif'});ed.onNodeChange.add(function(ed,cm,n){cm.setActive('artworklist',n.nodeName=='IMG')})},getInfo:function(){return{longname:'Artwork list plugin',author:'Hannes Magnusson',authorurl:'http://linpro.no',version:"0.9"}}});tinymce.PluginManager.add('artworklist',tinymce.plugins.ArtworkListPlugin)})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/artworklist/editor_plugin_src.js b/web/js/tiny_mce/plugins/artworklist/editor_plugin_src.js new file mode 100644 index 0000000..ffb2a03 --- /dev/null +++ b/web/js/tiny_mce/plugins/artworklist/editor_plugin_src.js @@ -0,0 +1,41 @@ + +(function() { + tinymce.create('tinymce.plugins.ArtworkListPlugin', { + init : function(ed, url) { + ed.addCommand('mceArtworkList', function() { + ed.windowManager.open({ + file : 'browse/artworks/' + document.getElementById("popup_id").value, + width : 620 + parseInt(ed.getLang('artworklist.delta_width', 0)), + height : 420 + parseInt(ed.getLang('artworklist.delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + // Register artworklist button + ed.addButton('artworklist', { + title : 'Link artwork to article', + cmd : 'mceArtworkList', + image : url + '/img/artworklist.gif' + }); + + // Add a node change handler, selects the button in the UI when a image is selected + ed.onNodeChange.add(function(ed, cm, n) { + cm.setActive('artworklist', n.nodeName == 'IMG'); + }); + }, + + getInfo : function() { + return { + longname : 'Artwork list plugin', + author : 'Hannes Magnusson', + authorurl : 'http://linpro.no', + version : "0.9" + }; + } + }); + + tinymce.PluginManager.add('artworklist', tinymce.plugins.ArtworkListPlugin); +})(); + diff --git a/web/js/tiny_mce/plugins/artworklist/img/artworklist.gif b/web/js/tiny_mce/plugins/artworklist/img/artworklist.gif new file mode 100644 index 0000000..9d2e89f Binary files /dev/null and b/web/js/tiny_mce/plugins/artworklist/img/artworklist.gif differ diff --git a/web/js/tiny_mce/plugins/artworklist/js/dialog.js b/web/js/tiny_mce/plugins/artworklist/js/dialog.js new file mode 100644 index 0000000..3d40d4a --- /dev/null +++ b/web/js/tiny_mce/plugins/artworklist/js/dialog.js @@ -0,0 +1,12 @@ +var ArtworklistDialog = { + init : function() { + var f = document.forms[0]; + }, + + insert : function(what) { + tinyMCEPopup.getWin().injectArtwork(what); + tinyMCEPopup.close(); + } +}; + + diff --git a/web/js/tiny_mce/plugins/autosave/editor_plugin.js b/web/js/tiny_mce/plugins/autosave/editor_plugin.js new file mode 100644 index 0000000..01a994e --- /dev/null +++ b/web/js/tiny_mce/plugins/autosave/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.AutoSavePlugin',{init:function(ed,url){var t=this;t.editor=ed;window.onbeforeunload=tinymce.plugins.AutoSavePlugin._beforeUnloadHandler;},getInfo:function(){return{longname:'Auto save',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave',version:tinymce.majorVersion+"."+tinymce.minorVersion};},'static':{_beforeUnloadHandler:function(){var msg;tinymce.each(tinyMCE.editors,function(ed){if(ed.getParam("fullscreen_is_enabled"))return;if(ed.isDirty()){msg=ed.getLang("autosave.unload_msg");return false;}});return msg;}}});tinymce.PluginManager.add('autosave',tinymce.plugins.AutoSavePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/autosave/editor_plugin_src.js b/web/js/tiny_mce/plugins/autosave/editor_plugin_src.js new file mode 100644 index 0000000..3c4325a --- /dev/null +++ b/web/js/tiny_mce/plugins/autosave/editor_plugin_src.js @@ -0,0 +1,51 @@ +/** + * $Id: editor_plugin_src.js 520 2008-01-07 16:30:32Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.AutoSavePlugin', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + + window.onbeforeunload = tinymce.plugins.AutoSavePlugin._beforeUnloadHandler; + }, + + getInfo : function() { + return { + longname : 'Auto save', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private plugin internal methods + + 'static' : { + _beforeUnloadHandler : function() { + var msg; + + tinymce.each(tinyMCE.editors, function(ed) { + if (ed.getParam("fullscreen_is_enabled")) + return; + + if (ed.isDirty()) { + msg = ed.getLang("autosave.unload_msg"); + return false; + } + }); + + return msg; + } + } + }); + + // Register plugin + tinymce.PluginManager.add('autosave', tinymce.plugins.AutoSavePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/bbcode/editor_plugin.js b/web/js/tiny_mce/plugins/bbcode/editor_plugin.js new file mode 100644 index 0000000..c56cdfd --- /dev/null +++ b/web/js/tiny_mce/plugins/bbcode/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.BBCodePlugin',{init:function(ed,url){var t=this,dialect=ed.getParam('bbcode_dialect','punbb').toLowerCase();ed.onBeforeSetContent.add(function(ed,o){o.content=t['_'+dialect+'_bbcode2html'](o.content);});ed.onPostProcess.add(function(ed,o){if(o.set)o.content=t['_'+dialect+'_bbcode2html'](o.content);if(o.get)o.content=t['_'+dialect+'_html2bbcode'](o.content);});},getInfo:function(){return{longname:'BBCode Plugin',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_punbb_html2bbcode:function(s){s=tinymce.trim(s);function rep(re,str){s=s.replace(re,str);};rep(/(.*?)<\/a>/gi,"[url=$1]$2[/url]");rep(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");rep(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");rep(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");rep(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");rep(/(.*?)<\/span>/gi,"[color=$1]$2[/color]");rep(/(.*?)<\/font>/gi,"[color=$1]$2[/color]");rep(/(.*?)<\/span>/gi,"[size=$1]$2[/size]");rep(/(.*?)<\/font>/gi,"$1");rep(//gi,"[img]$1[/img]");rep(/(.*?)<\/span>/gi,"[code]$1[/code]");rep(/(.*?)<\/span>/gi,"[quote]$1[/quote]");rep(/(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]");rep(/(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]");rep(/(.*?)<\/em>/gi,"[code][i]$1[/i][/code]");rep(/(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]");rep(/(.*?)<\/u>/gi,"[code][u]$1[/u][/code]");rep(/(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]");rep(/<\/(strong|b)>/gi,"[/b]");rep(/<(strong|b)>/gi,"[b]");rep(/<\/(em|i)>/gi,"[/i]");rep(/<(em|i)>/gi,"[i]");rep(/<\/u>/gi,"[/u]");rep(/(.*?)<\/span>/gi,"[u]$1[/u]");rep(//gi,"[u]");rep(/
    /gi,"\n");rep(//gi,"\n");rep(/
    /gi,"\n");rep(/

    /gi,"");rep(/<\/p>/gi,"\n");rep(/ /gi," ");rep(/"/gi,"\"");rep(/</gi,"<");rep(/>/gi,">");rep(/&/gi,"&");return s;},_punbb_bbcode2html:function(s){s=tinymce.trim(s);function rep(re,str){s=s.replace(re,str);};rep(/\n/gi,"
    ");rep(/\[b\]/gi,"");rep(/\[\/b\]/gi,"");rep(/\[i\]/gi,"");rep(/\[\/i\]/gi,"");rep(/\[u\]/gi,"");rep(/\[\/u\]/gi,"");rep(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,"$2");rep(/\[url\](.*?)\[\/url\]/gi,"$1");rep(/\[img\](.*?)\[\/img\]/gi,"");rep(/\[color=(.*?)\](.*?)\[\/color\]/gi,"$2");rep(/\[code\](.*?)\[\/code\]/gi,"$1 ");rep(/\[quote.*?\](.*?)\[\/quote\]/gi,"$1 ");return s;}});tinymce.PluginManager.add('bbcode',tinymce.plugins.BBCodePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/bbcode/editor_plugin_src.js b/web/js/tiny_mce/plugins/bbcode/editor_plugin_src.js new file mode 100644 index 0000000..c7fd262 --- /dev/null +++ b/web/js/tiny_mce/plugins/bbcode/editor_plugin_src.js @@ -0,0 +1,115 @@ +/** + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.BBCodePlugin', { + init : function(ed, url) { + var t = this, dialect = ed.getParam('bbcode_dialect', 'punbb').toLowerCase(); + + ed.onBeforeSetContent.add(function(ed, o) { + o.content = t['_' + dialect + '_bbcode2html'](o.content); + }); + + ed.onPostProcess.add(function(ed, o) { + if (o.set) + o.content = t['_' + dialect + '_bbcode2html'](o.content); + + if (o.get) + o.content = t['_' + dialect + '_html2bbcode'](o.content); + }); + }, + + getInfo : function() { + return { + longname : 'BBCode Plugin', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private methods + + // HTML -> BBCode in PunBB dialect + _punbb_html2bbcode : function(s) { + s = tinymce.trim(s); + + function rep(re, str) { + s = s.replace(re, str); + }; + + // example: to [b] + rep(/(.*?)<\/a>/gi,"[url=$1]$2[/url]"); + rep(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"); + rep(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"); + rep(/(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]"); + rep(/(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]"); + rep(/(.*?)<\/span>/gi,"[color=$1]$2[/color]"); + rep(/(.*?)<\/font>/gi,"[color=$1]$2[/color]"); + rep(/(.*?)<\/span>/gi,"[size=$1]$2[/size]"); + rep(/(.*?)<\/font>/gi,"$1"); + rep(//gi,"[img]$1[/img]"); + rep(/(.*?)<\/span>/gi,"[code]$1[/code]"); + rep(/(.*?)<\/span>/gi,"[quote]$1[/quote]"); + rep(/(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]"); + rep(/(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]"); + rep(/(.*?)<\/em>/gi,"[code][i]$1[/i][/code]"); + rep(/(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]"); + rep(/(.*?)<\/u>/gi,"[code][u]$1[/u][/code]"); + rep(/(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]"); + rep(/<\/(strong|b)>/gi,"[/b]"); + rep(/<(strong|b)>/gi,"[b]"); + rep(/<\/(em|i)>/gi,"[/i]"); + rep(/<(em|i)>/gi,"[i]"); + rep(/<\/u>/gi,"[/u]"); + rep(/(.*?)<\/span>/gi,"[u]$1[/u]"); + rep(//gi,"[u]"); + rep(/
    /gi,"\n"); + rep(//gi,"\n"); + rep(/
    /gi,"\n"); + rep(/

    /gi,""); + rep(/<\/p>/gi,"\n"); + rep(/ /gi," "); + rep(/"/gi,"\""); + rep(/</gi,"<"); + rep(/>/gi,">"); + rep(/&/gi,"&"); + + return s; + }, + + // BBCode -> HTML from PunBB dialect + _punbb_bbcode2html : function(s) { + s = tinymce.trim(s); + + function rep(re, str) { + s = s.replace(re, str); + }; + + // example: [b] to + rep(/\n/gi,"
    "); + rep(/\[b\]/gi,""); + rep(/\[\/b\]/gi,""); + rep(/\[i\]/gi,""); + rep(/\[\/i\]/gi,""); + rep(/\[u\]/gi,""); + rep(/\[\/u\]/gi,""); + rep(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,"$2"); + rep(/\[url\](.*?)\[\/url\]/gi,"$1"); + rep(/\[img\](.*?)\[\/img\]/gi,""); + rep(/\[color=(.*?)\](.*?)\[\/color\]/gi,"$2"); + rep(/\[code\](.*?)\[\/code\]/gi,"$1 "); + rep(/\[quote.*?\](.*?)\[\/quote\]/gi,"$1 "); + + return s; + } + }); + + // Register plugin + tinymce.PluginManager.add('bbcode', tinymce.plugins.BBCodePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/compat2x/editor_plugin.js b/web/js/tiny_mce/plugins/compat2x/editor_plugin.js new file mode 100644 index 0000000..090c94b --- /dev/null +++ b/web/js/tiny_mce/plugins/compat2x/editor_plugin.js @@ -0,0 +1 @@ +(function(){var DOM=tinymce.DOM,Event=tinymce.dom.Event,each=tinymce.each,is=tinymce.is;tinymce.create('tinymce.plugins.Compat2x',{getInfo:function(){return{longname:'Compat2x',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/compat2x',version:tinyMCE.majorVersion+"."+tinyMCE.minorVersion};}});(function(){tinymce.extend(tinyMCE,{addToLang:function(p,l){each(l,function(v,k){tinyMCE.i18n[(tinyMCE.settings.language||'en')+'.'+(p?p+'_':'')+k]=v;});},getInstanceById:function(n){return this.get(n);}});})();(function(){var EditorManager=tinymce.EditorManager;tinyMCE.instances={};tinyMCE.plugins={};tinymce.PluginManager.onAdd.add(function(pm,n,p){tinyMCE.plugins[n]=p;});tinyMCE.majorVersion=tinymce.majorVersion;tinyMCE.minorVersion=tinymce.minorVersion;tinyMCE.releaseDate=tinymce.releaseDate;tinyMCE.baseURL=tinymce.baseURL;tinyMCE.isIE=tinyMCE.isMSIE=tinymce.isIE||tinymce.isOpera;tinyMCE.isMSIE5=tinymce.isIE;tinyMCE.isMSIE5_0=tinymce.isIE;tinyMCE.isMSIE7=tinymce.isIE;tinyMCE.isGecko=tinymce.isGecko;tinyMCE.isSafari=tinymce.isWebKit;tinyMCE.isOpera=tinymce.isOpera;tinyMCE.isMac=false;tinyMCE.isNS7=false;tinyMCE.isNS71=false;tinyMCE.compat=true;TinyMCE_Engine=tinyMCE;tinymce.extend(tinyMCE,{getParam:function(n,dv){return this.activeEditor.getParam(n,dv);},addEvent:function(e,na,f,sc){tinymce.dom.Event.add(e,na,f,sc||this);},getControlHTML:function(n){return EditorManager.activeEditor.controlManager.createControl(n);},loadCSS:function(u){tinymce.DOM.loadCSS(u);},importCSS:function(doc,u){if(doc==document)this.loadCSS(u);else new tinymce.dom.DOMUtils(doc).loadCSS(u);},log:function(){console.debug.apply(console,arguments);},getLang:function(n,dv){var v=EditorManager.activeEditor.getLang(n.replace(/^lang_/g,''),dv);if(/^[0-9\-.]+$/g.test(v))return parseInt(v);return v;},isInstance:function(o){return o!=null&&typeof(o)=="object"&&o.execCommand;},triggerNodeChange:function(){EditorManager.activeEditor.nodeChanged();},regexpReplace:function(in_str,reg_exp,replace_str,opts){var re;if(in_str==null)return in_str;if(typeof(opts)=="undefined")opts='g';re=new RegExp(reg_exp,opts);return in_str.replace(re,replace_str);},trim:function(s){return tinymce.trim(s);},xmlEncode:function(s){return tinymce.DOM.encode(s);},explode:function(s,d){var o=[];tinymce.each(s.split(d),function(v){if(v!='')o.push(v);});return o;},switchClass:function(id,cls){var b;if(/^mceButton/.test(cls)){b=EditorManager.activeEditor.controlManager.get(id);if(!b)return;switch(cls){case"mceButtonNormal":b.setDisabled(false);b.setActive(false);return;case"mceButtonDisabled":b.setDisabled(true);return;case"mceButtonSelected":b.setActive(true);b.setDisabled(false);return;}}},addCSSClass:function(e,n,b){return tinymce.DOM.addClass(e,n,b);},hasCSSClass:function(e,n){return tinymce.DOM.hasClass(e,n);},removeCSSClass:function(e,n){return tinymce.DOM.removeClass(e,n);},getCSSClasses:function(){var cl=EditorManager.activeEditor.dom.getClasses(),o=[];each(cl,function(c){o.push(c['class']);});return o;},setWindowArg:function(n,v){EditorManager.activeEditor.windowManager.params[n]=v;},getWindowArg:function(n,dv){var wm=EditorManager.activeEditor.windowManager,v;v=wm.getParam(n);if(v==='')return'';return v||wm.getFeature(n)||dv;},getParentNode:function(n,f){return this._getDOM().getParent(n,f);},selectElements:function(n,na,f){var i,a=[],nl,x;for(x=0,na=na.split(',');x + + + {#emotions_dlg.title} + + + + + +

    +
    {#emotions_dlg.title}:

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {#emotions_dlg.cool}{#emotions_dlg.cry}{#emotions_dlg.embarassed}{#emotions_dlg.foot_in_mouth}
    {#emotions_dlg.frown}{#emotions_dlg.innocent}{#emotions_dlg.kiss}{#emotions_dlg.laughing}
    {#emotions_dlg.money_mouth}{#emotions_dlg.sealed}{#emotions_dlg.smile}{#emotions_dlg.surprised}
    {#emotions_dlg.tongue-out}{#emotions_dlg.undecided}{#emotions_dlg.wink}{#emotions_dlg.yell}
    +
    + + diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-cool.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-cool.gif new file mode 100644 index 0000000..ba90cc3 Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-cool.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-cry.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-cry.gif new file mode 100644 index 0000000..74d897a Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-cry.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-embarassed.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-embarassed.gif new file mode 100644 index 0000000..963a96b Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-embarassed.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-foot-in-mouth.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-foot-in-mouth.gif new file mode 100644 index 0000000..16f68cc Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-foot-in-mouth.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-frown.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-frown.gif new file mode 100644 index 0000000..716f55e Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-frown.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-innocent.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-innocent.gif new file mode 100644 index 0000000..334d49e Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-innocent.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-kiss.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-kiss.gif new file mode 100644 index 0000000..4efd549 Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-kiss.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-laughing.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-laughing.gif new file mode 100644 index 0000000..1606c11 Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-laughing.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-money-mouth.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-money-mouth.gif new file mode 100644 index 0000000..ca2451e Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-money-mouth.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-sealed.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-sealed.gif new file mode 100644 index 0000000..b33d3cc Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-sealed.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-smile.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-smile.gif new file mode 100644 index 0000000..e6a9e60 Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-smile.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-surprised.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-surprised.gif new file mode 100644 index 0000000..cb99cdd Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-surprised.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-tongue-out.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-tongue-out.gif new file mode 100644 index 0000000..2075dc1 Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-tongue-out.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-undecided.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-undecided.gif new file mode 100644 index 0000000..bef7e25 Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-undecided.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-wink.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-wink.gif new file mode 100644 index 0000000..9faf1af Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-wink.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/img/smiley-yell.gif b/web/js/tiny_mce/plugins/emotions/img/smiley-yell.gif new file mode 100644 index 0000000..648e6e8 Binary files /dev/null and b/web/js/tiny_mce/plugins/emotions/img/smiley-yell.gif differ diff --git a/web/js/tiny_mce/plugins/emotions/js/emotions.js b/web/js/tiny_mce/plugins/emotions/js/emotions.js new file mode 100644 index 0000000..c549367 --- /dev/null +++ b/web/js/tiny_mce/plugins/emotions/js/emotions.js @@ -0,0 +1,22 @@ +tinyMCEPopup.requireLangPack(); + +var EmotionsDialog = { + init : function(ed) { + tinyMCEPopup.resizeToInnerSize(); + }, + + insert : function(file, title) { + var ed = tinyMCEPopup.editor, dom = ed.dom; + + tinyMCEPopup.execCommand('mceInsertContent', false, dom.createHTML('img', { + src : tinyMCEPopup.getWindowArg('plugin_url') + '/img/' + file, + alt : ed.getLang(title), + title : ed.getLang(title), + border : 0 + })); + + tinyMCEPopup.close(); + } +}; + +tinyMCEPopup.onInit.add(EmotionsDialog.init, EmotionsDialog); diff --git a/web/js/tiny_mce/plugins/emotions/langs/en_dlg.js b/web/js/tiny_mce/plugins/emotions/langs/en_dlg.js new file mode 100644 index 0000000..3b57ad9 --- /dev/null +++ b/web/js/tiny_mce/plugins/emotions/langs/en_dlg.js @@ -0,0 +1,20 @@ +tinyMCE.addI18n('en.emotions_dlg',{ +title:"Insert emotion", +desc:"Emotions", +cool:"Cool", +cry:"Cry", +embarassed:"Embarassed", +foot_in_mouth:"Foot in mouth", +frown:"Frown", +innocent:"Innocent", +kiss:"Kiss", +laughing:"Laughing", +money_mouth:"Money mouth", +sealed:"Sealed", +smile:"Smile", +surprised:"Surprised", +tongue_out:"Tongue out", +undecided:"Undecided", +wink:"Wink", +yell:"Yell" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/emotions/langs/nb_dlg.js b/web/js/tiny_mce/plugins/emotions/langs/nb_dlg.js new file mode 100644 index 0000000..b593f7c --- /dev/null +++ b/web/js/tiny_mce/plugins/emotions/langs/nb_dlg.js @@ -0,0 +1,20 @@ +tinyMCE.addI18n('nb.emotions_dlg',{ +title:"Sett inn hum\u00F8rfjes", +desc:"Hum\u00F8rfjes", +cool:"Cool", +cry:"Gr\u00E5ter", +embarassed:"Flau", +foot_in_mouth:"Fot i munnen", +frown:"Skuffet", +innocent:"Uskyldig", +kiss:"Kyss", +laughing:"Ler", +money_mouth:"Penger i munnen", +sealed:"Hemmelig", +smile:"Glad", +surprised:"Overrasket", +tongue_out:"Rekke tunge", +undecided:"Skeptisk", +wink:"Blunke", +yell:"Skri" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/emotions/langs/nn_dlg.js b/web/js/tiny_mce/plugins/emotions/langs/nn_dlg.js new file mode 100644 index 0000000..3967fbc --- /dev/null +++ b/web/js/tiny_mce/plugins/emotions/langs/nn_dlg.js @@ -0,0 +1,20 @@ +tinyMCE.addI18n('nn.emotions_dlg',{ +title:"Set inn hum\u00F8rfjes", +desc:"Hum\u00F8rfjes", +cool:"Cool", +cry:"Gret", +embarassed:"Flau", +foot_in_mouth:"Fot i munnen", +frown:"Skuffa", +innocent:"Uskyldig", +kiss:"Kyss", +laughing:"Ler", +money_mouth:"Pengar i munnen", +sealed:"Hemmeleg", +smile:"Glad", +surprised:"Overraska", +tongue_out:"Rekkje tunge", +undecided:"Skeptisk", +wink:"Blunke", +yell:"Skri" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/example/dialog.htm b/web/js/tiny_mce/plugins/example/dialog.htm new file mode 100644 index 0000000..7c4247c --- /dev/null +++ b/web/js/tiny_mce/plugins/example/dialog.htm @@ -0,0 +1,27 @@ + + + + {#example_dlg.title} + + + + + +
    +

    Here is a example dialog.

    +

    Selected text:

    +

    Custom arg:

    + +
    +
    + +
    + +
    + +
    +
    +
    + + + diff --git a/web/js/tiny_mce/plugins/example/editor_plugin.js b/web/js/tiny_mce/plugins/example/editor_plugin.js new file mode 100644 index 0000000..cb7010d --- /dev/null +++ b/web/js/tiny_mce/plugins/example/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.PluginManager.requireLangPack('example');tinymce.create('tinymce.plugins.ExamplePlugin',{init:function(ed,url){ed.addCommand('mceExample',function(){ed.windowManager.open({file:url+'/dialog.htm',width:320+parseInt(ed.getLang('example.delta_width',0)),height:120+parseInt(ed.getLang('example.delta_height',0)),inline:1},{plugin_url:url,some_custom_arg:'custom arg'});});ed.addButton('example',{title:'example.desc',cmd:'mceExample',image:url+'/img/example.gif'});ed.onNodeChange.add(function(ed,cm,n){cm.setActive('example',n.nodeName=='IMG');});},createControl:function(n,cm){return null;},getInfo:function(){return{longname:'Example plugin',author:'Some author',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example',version:"1.0"};}});tinymce.PluginManager.add('example',tinymce.plugins.ExamplePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/example/editor_plugin_src.js b/web/js/tiny_mce/plugins/example/editor_plugin_src.js new file mode 100644 index 0000000..5050550 --- /dev/null +++ b/web/js/tiny_mce/plugins/example/editor_plugin_src.js @@ -0,0 +1,81 @@ +/** + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + // Load plugin specific language pack + tinymce.PluginManager.requireLangPack('example'); + + tinymce.create('tinymce.plugins.ExamplePlugin', { + /** + * Initializes the plugin, this will be executed after the plugin has been created. + * This call is done before the editor instance has finished it's initialization so use the onInit event + * of the editor instance to intercept that event. + * + * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in. + * @param {string} url Absolute URL to where the plugin is located. + */ + init : function(ed, url) { + // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample'); + ed.addCommand('mceExample', function() { + ed.windowManager.open({ + file : url + '/dialog.htm', + width : 320 + parseInt(ed.getLang('example.delta_width', 0)), + height : 120 + parseInt(ed.getLang('example.delta_height', 0)), + inline : 1 + }, { + plugin_url : url, // Plugin absolute URL + some_custom_arg : 'custom arg' // Custom argument + }); + }); + + // Register example button + ed.addButton('example', { + title : 'example.desc', + cmd : 'mceExample', + image : url + '/img/example.gif' + }); + + // Add a node change handler, selects the button in the UI when a image is selected + ed.onNodeChange.add(function(ed, cm, n) { + cm.setActive('example', n.nodeName == 'IMG'); + }); + }, + + /** + * Creates control instances based in the incomming name. This method is normally not + * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons + * but you sometimes need to create more complex controls like listboxes, split buttons etc then this + * method can be used to create those. + * + * @param {String} n Name of the control to create. + * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control. + * @return {tinymce.ui.Control} New control instance or null if no control was created. + */ + createControl : function(n, cm) { + return null; + }, + + /** + * Returns information about the plugin as a name/value array. + * The current keys are longname, author, authorurl, infourl and version. + * + * @return {Object} Name/value array containing information about the plugin. + */ + getInfo : function() { + return { + longname : 'Example plugin', + author : 'Some author', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example', + version : "1.0" + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/example/img/example.gif b/web/js/tiny_mce/plugins/example/img/example.gif new file mode 100644 index 0000000..1ab5da4 Binary files /dev/null and b/web/js/tiny_mce/plugins/example/img/example.gif differ diff --git a/web/js/tiny_mce/plugins/example/js/dialog.js b/web/js/tiny_mce/plugins/example/js/dialog.js new file mode 100644 index 0000000..fa83411 --- /dev/null +++ b/web/js/tiny_mce/plugins/example/js/dialog.js @@ -0,0 +1,19 @@ +tinyMCEPopup.requireLangPack(); + +var ExampleDialog = { + init : function() { + var f = document.forms[0]; + + // Get the selected contents as text and place it in the input + f.someval.value = tinyMCEPopup.editor.selection.getContent({format : 'text'}); + f.somearg.value = tinyMCEPopup.getWindowArg('some_custom_arg'); + }, + + insert : function() { + // Insert the contents from the input into the document + tinyMCEPopup.editor.execCommand('mceInsertContent', false, document.forms[0].someval.value); + tinyMCEPopup.close(); + } +}; + +tinyMCEPopup.onInit.add(ExampleDialog.init, ExampleDialog); diff --git a/web/js/tiny_mce/plugins/example/langs/en.js b/web/js/tiny_mce/plugins/example/langs/en.js new file mode 100644 index 0000000..e0784f8 --- /dev/null +++ b/web/js/tiny_mce/plugins/example/langs/en.js @@ -0,0 +1,3 @@ +tinyMCE.addI18n('en.example',{ + desc : 'This is just a template button' +}); diff --git a/web/js/tiny_mce/plugins/example/langs/en_dlg.js b/web/js/tiny_mce/plugins/example/langs/en_dlg.js new file mode 100644 index 0000000..ebcf948 --- /dev/null +++ b/web/js/tiny_mce/plugins/example/langs/en_dlg.js @@ -0,0 +1,3 @@ +tinyMCE.addI18n('en.example_dlg',{ + title : 'This is just a example title' +}); diff --git a/web/js/tiny_mce/plugins/fullpage/css/fullpage.css b/web/js/tiny_mce/plugins/fullpage/css/fullpage.css new file mode 100644 index 0000000..c39c359 --- /dev/null +++ b/web/js/tiny_mce/plugins/fullpage/css/fullpage.css @@ -0,0 +1,178 @@ +/* Hide the advanced tab */ +#advanced_tab { + display: none; +} + +#metatitle, #metakeywords, #metadescription, #metaauthor, #metacopyright { + width: 280px; +} + +#doctype, #docencoding { + width: 200px; +} + +#langcode { + width: 30px; +} + +#bgimage { + width: 220px; +} + +#fontface { + width: 240px; +} + +#leftmargin, #rightmargin, #topmargin, #bottommargin { + width: 50px; +} + +.panel_wrapper div.current { + height: 400px; +} + +#stylesheet, #style { + width: 240px; +} + +/* Head list classes */ + +.headlistwrapper { + width: 100%; +} + +.addbutton, .removebutton, .moveupbutton, .movedownbutton { + border-top: 1px solid; + border-left: 1px solid; + border-bottom: 1px solid; + border-right: 1px solid; + border-color: #F0F0EE; + cursor: default; + display: block; + width: 20px; + height: 20px; +} + +.addbutton:hover, .removebutton:hover, .moveupbutton:hover, .movedownbutton:hover { + border: 1px solid #0A246A; + background-color: #B6BDD2; +} + +.addbutton { + background-image: url('../images/add.gif'); + float: left; + margin-right: 3px; +} + +.removebutton { + background-image: url('../images/remove.gif'); + float: left; +} + +.moveupbutton { + background-image: url('../images/move_up.gif'); + float: left; + margin-right: 3px; +} + +.movedownbutton { + background-image: url('../images/move_down.gif'); + float: left; +} + +.selected { + border: 1px solid #0A246A; + background-color: #B6BDD2; +} + +.toolbar { + width: 100%; +} + +#headlist { + width: 100%; + margin-top: 3px; + font-size: 11px; +} + +#info, #title_element, #meta_element, #script_element, #style_element, #base_element, #link_element, #comment_element, #unknown_element { + display: none; +} + +#addmenu { + position: absolute; + border: 1px solid gray; + display: none; + z-index: 100; + background-color: white; +} + +#addmenu a { + display: block; + width: 100%; + line-height: 20px; + text-decoration: none; + background-color: white; +} + +#addmenu a:hover { + background-color: #B6BDD2; + color: black; +} + +#addmenu span { + padding-left: 10px; + padding-right: 10px; +} + +#updateElementPanel { + display: none; +} + +#script_element .panel_wrapper div.current { + height: 108px; +} + +#style_element .panel_wrapper div.current { + height: 108px; +} + +#link_element .panel_wrapper div.current { + height: 140px; +} + +#element_script_value { + width: 100%; + height: 100px; +} + +#element_comment_value { + width: 100%; + height: 120px; +} + +#element_style_value { + width: 100%; + height: 100px; +} + +#element_title, #element_script_src, #element_meta_name, #element_meta_content, #element_base_href, #element_link_href, #element_link_title { + width: 250px; +} + +.updateElementButton { + margin-top: 3px; +} + +/* MSIE specific styles */ + +* html .addbutton, * html .removebutton, * html .moveupbutton, * html .movedownbutton { + width: 22px; + height: 22px; +} + +textarea { + height: 55px; +} + +.panel_wrapper div.current {height:420px;} \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/fullpage/editor_plugin.js b/web/js/tiny_mce/plugins/fullpage/editor_plugin.js new file mode 100644 index 0000000..fe133a5 --- /dev/null +++ b/web/js/tiny_mce/plugins/fullpage/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.FullPagePlugin',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mceFullPageProperties',function(){ed.windowManager.open({file:url+'/fullpage.htm',width:430+parseInt(ed.getLang('fullpage.delta_width',0)),height:495+parseInt(ed.getLang('fullpage.delta_height',0)),inline:1},{plugin_url:url,head_html:t.head});});ed.addButton('fullpage',{title:'fullpage.desc',cmd:'mceFullPageProperties'});ed.onBeforeSetContent.add(t._setContent,t);ed.onSetContent.add(t._setBodyAttribs,t);ed.onGetContent.add(t._getContent,t);},getInfo:function(){return{longname:'Fullpage',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_setBodyAttribs:function(ed,o){var bdattr,i,len,kv,k,v,t,attr=this.head.match(/body(.*?)>/i);if(attr&&attr[1]){bdattr=attr[1].match(/\s*(\w+\s*=\s*".*?"|\w+\s*=\s*'.*?'|\w+\s*=\s*\w+|\w+)\s*/g);for(i=0,len=bdattr.length;i',sp);t.head=c.substring(0,sp+1);ep=c.indexOf('';t.head+='\n\n\nUntitled document\n\n\n';t.foot='\n\n';}},_getContent:function(ed,o){var t=this;o.content=tinymce.trim(t.head)+'\n'+tinymce.trim(o.content)+'\n'+tinymce.trim(t.foot);}});tinymce.PluginManager.add('fullpage',tinymce.plugins.FullPagePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/fullpage/editor_plugin_src.js b/web/js/tiny_mce/plugins/fullpage/editor_plugin_src.js new file mode 100644 index 0000000..fb3b229 --- /dev/null +++ b/web/js/tiny_mce/plugins/fullpage/editor_plugin_src.js @@ -0,0 +1,122 @@ +/** + * $Id: editor_plugin_src.js 593 2008-02-13 13:00:12Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.FullPagePlugin', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + + // Register commands + ed.addCommand('mceFullPageProperties', function() { + ed.windowManager.open({ + file : url + '/fullpage.htm', + width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)), + height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)), + inline : 1 + }, { + plugin_url : url, + head_html : t.head + }); + }); + + // Register buttons + ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'}); + + ed.onBeforeSetContent.add(t._setContent, t); + ed.onSetContent.add(t._setBodyAttribs, t); + ed.onGetContent.add(t._getContent, t); + }, + + getInfo : function() { + return { + longname : 'Fullpage', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private plugin internal methods + + _setBodyAttribs : function(ed, o) { + var bdattr, i, len, kv, k, v, t, attr = this.head.match(/body(.*?)>/i); + + if (attr && attr[1]) { + bdattr = attr[1].match(/\s*(\w+\s*=\s*".*?"|\w+\s*=\s*'.*?'|\w+\s*=\s*\w+|\w+)\s*/g); + + for(i = 0, len = bdattr.length; i < len; i++) { + kv = bdattr[i].split('='); + k = kv[0].replace(/\s/,''); + v = kv[1]; + + if (v) { + v = v.replace(/^\s+/,'').replace(/\s+$/,''); + t = v.match(/^["'](.*)["']$/); + + if (t) + v = t[1]; + } else + v = k; + + ed.dom.setAttrib(ed.getBody(), 'style', v); + } + } + }, + + _createSerializer : function() { + return new tinymce.dom.Serializer({ + dom : this.editor.dom, + apply_source_formatting : true + }); + }, + + _setContent : function(ed, o) { + var t = this, sp, ep, c = o.content; + + // Parse out head, body and footer + c = c.replace(/<(\/?)BODY/gi, '<$1body'); + sp = c.indexOf('', sp); + t.head = c.substring(0, sp + 1); + + ep = c.indexOf(' + + + {#fullpage_dlg.title} + + + + + + + + +
    + + +
    +
    +
    + {#fullpage_dlg.meta_props} + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
     
     
     
     
      + +
    +
    + +
    + {#fullpage_dlg.langprops} + + + + + + + + + + + + + + + + + + + + + + +
    + +
      + +
     
    + +
     
    +
    +
    + +
    +
    + {#fullpage_dlg.appearance_textprops} + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + + + +
     
    +
    +
    + +
    + {#fullpage_dlg.appearance_bgprops} + + + + + + + + + + +
    + + + + + +
     
    +
    + + + + + +
     
    +
    +
    + +
    + {#fullpage_dlg.appearance_marginprops} + + + + + + + + + + + + + + +
    +
    + +
    + {#fullpage_dlg.appearance_linkprops} + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    +
    + + + + + +
     
    +
    + + + + + +
     
    +
      
    +
    + +
    + {#fullpage_dlg.appearance_style} + + + + + + + + + + +
    + + + + +
     
    +
    +
    + +
    + + +
    + {#fullpage_dlg.head_elements} + +
    +
    +
    + + +
    +
    + + +
    +
    +
    + +
    +
    + +
    + {#fullpage_dlg.meta_element} + + + + + + + + + + + + + + +
    + + +
    + +
    + {#fullpage_dlg.title_element} + + + + + + +
    + + +
    + +
    + {#fullpage_dlg.script_element} + + + +
    + +
    +
    + + + + + + + + + + + + + + + + + +
    + + + + +
     
    +
    + +
    + +
    +
    + + +
    + +
    + {#fullpage_dlg.style_element} + + + +
    + +
    +
    + + + + + + + + + +
    +
    + +
    + +
    +
    + + +
    + +
    + {#fullpage_dlg.base_element} + + + + + + + + + + +
    + + +
    + + + +
    + {#fullpage_dlg.comment_element} + + + + +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/fullpage/js/fullpage.js b/web/js/tiny_mce/plugins/fullpage/js/fullpage.js new file mode 100644 index 0000000..b22d288 --- /dev/null +++ b/web/js/tiny_mce/plugins/fullpage/js/fullpage.js @@ -0,0 +1,462 @@ +tinyMCEPopup.requireLangPack(); + +var doc; + +var defaultDocTypes = + 'XHTML 1.0 Transitional=,' + + 'XHTML 1.0 Frameset=,' + + 'XHTML 1.0 Strict=,' + + 'XHTML 1.1=,' + + 'HTML 4.01 Transitional=,' + + 'HTML 4.01 Strict=,' + + 'HTML 4.01 Frameset='; + +var defaultEncodings = + 'Western european (iso-8859-1)=iso-8859-1,' + + 'Central European (iso-8859-2)=iso-8859-2,' + + 'Unicode (UTF-8)=utf-8,' + + 'Chinese traditional (Big5)=big5,' + + 'Cyrillic (iso-8859-5)=iso-8859-5,' + + 'Japanese (iso-2022-jp)=iso-2022-jp,' + + 'Greek (iso-8859-7)=iso-8859-7,' + + 'Korean (iso-2022-kr)=iso-2022-kr,' + + 'ASCII (us-ascii)=us-ascii'; + +var defaultMediaTypes = + 'all=all,' + + 'screen=screen,' + + 'print=print,' + + 'tty=tty,' + + 'tv=tv,' + + 'projection=projection,' + + 'handheld=handheld,' + + 'braille=braille,' + + 'aural=aural'; + +var defaultFontNames = 'Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,times new roman,times,serif;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times,serif;Verdana=verdana,arial,helvetica,sans-serif;Impact=impact;WingDings=wingdings'; +var defaultFontSizes = '10px,11px,12px,13px,14px,15px,16px'; + +function init() { + var f = document.forms['fullpage'], el = f.elements, e, i, p, doctypes, encodings, mediaTypes, fonts, ed = tinyMCEPopup.editor, dom = tinyMCEPopup.dom, style; + + // Setup doctype select box + doctypes = ed.getParam("fullpage_doctypes", defaultDocTypes).split(','); + for (i=0; i 1) + addSelectValue(f, 'doctypes', p[0], p[1]); + } + + // Setup fonts select box + fonts = ed.getParam("fullpage_fonts", defaultFontNames).split(';'); + for (i=0; i 1) + addSelectValue(f, 'fontface', p[0], p[1]); + } + + // Setup fontsize select box + fonts = ed.getParam("fullpage_fontsizes", defaultFontSizes).split(','); + for (i=0; i 1) { + addSelectValue(f, 'element_style_media', p[0], p[1]); + addSelectValue(f, 'element_link_media', p[0], p[1]); + } + } + + // Setup encodings select box + encodings = ed.getParam("fullpage_encodings", defaultEncodings).split(','); + for (i=0; i 1) { + addSelectValue(f, 'docencoding', p[0], p[1]); + addSelectValue(f, 'element_script_charset', p[0], p[1]); + addSelectValue(f, 'element_link_charset', p[0], p[1]); + } + } + + document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor'); + document.getElementById('link_color_pickcontainer').innerHTML = getColorPickerHTML('link_color_pick','link_color'); + //document.getElementById('hover_color_pickcontainer').innerHTML = getColorPickerHTML('hover_color_pick','hover_color'); + document.getElementById('visited_color_pickcontainer').innerHTML = getColorPickerHTML('visited_color_pick','visited_color'); + document.getElementById('active_color_pickcontainer').innerHTML = getColorPickerHTML('active_color_pick','active_color'); + document.getElementById('textcolor_pickcontainer').innerHTML = getColorPickerHTML('textcolor_pick','textcolor'); + document.getElementById('stylesheet_browsercontainer').innerHTML = getBrowserHTML('stylesheetbrowser','stylesheet','file','fullpage'); + document.getElementById('link_href_pickcontainer').innerHTML = getBrowserHTML('link_href_browser','element_link_href','file','fullpage'); + document.getElementById('script_src_pickcontainer').innerHTML = getBrowserHTML('script_src_browser','element_script_src','file','fullpage'); + document.getElementById('bgimage_pickcontainer').innerHTML = getBrowserHTML('bgimage_browser','bgimage','image','fullpage'); + + // Resize some elements + if (isVisible('stylesheetbrowser')) + document.getElementById('stylesheet').style.width = '220px'; + + if (isVisible('link_href_browser')) + document.getElementById('element_link_href').style.width = '230px'; + + if (isVisible('bgimage_browser')) + document.getElementById('bgimage').style.width = '210px'; + + // Add iframe + dom.add(document.body, 'iframe', {id : 'documentIframe', src : 'javascript:""', style : {display : 'none'}}); + doc = dom.get('documentIframe').contentWindow.document; + h = tinyMCEPopup.getWindowArg('head_html'); + + // Preprocess the HTML disable scripts and urls + h = h.replace(/ + + + + +
    + +
    + + + + + diff --git a/web/js/tiny_mce/plugins/iespell/editor_plugin.js b/web/js/tiny_mce/plugins/iespell/editor_plugin.js new file mode 100644 index 0000000..06dae75 --- /dev/null +++ b/web/js/tiny_mce/plugins/iespell/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.IESpell',{init:function(ed,url){var t=this,sp;if(!tinymce.isIE)return;t.editor=ed;ed.addCommand('mceIESpell',function(){try{sp=new ActiveXObject("ieSpell.ieSpellExtension");sp.CheckDocumentNode(ed.getDoc().documentElement);}catch(e){if(e.number==-2146827859){ed.windowManager.confirm(ed.getLang("iespell.download"),function(s){if(s)window.open('http://www.iespell.com/download.php','ieSpellDownload','');});}else ed.windowManager.alert("Error Loading ieSpell: Exception "+e.number);}});ed.addButton('iespell',{title:'iespell.iespell_desc',cmd:'mceIESpell'});},getInfo:function(){return{longname:'IESpell (IE Only)',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/iespell',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('iespell',tinymce.plugins.IESpell);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/iespell/editor_plugin_src.js b/web/js/tiny_mce/plugins/iespell/editor_plugin_src.js new file mode 100644 index 0000000..a68f69a --- /dev/null +++ b/web/js/tiny_mce/plugins/iespell/editor_plugin_src.js @@ -0,0 +1,51 @@ +/** + * $Id: editor_plugin_src.js 520 2008-01-07 16:30:32Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.IESpell', { + init : function(ed, url) { + var t = this, sp; + + if (!tinymce.isIE) + return; + + t.editor = ed; + + // Register commands + ed.addCommand('mceIESpell', function() { + try { + sp = new ActiveXObject("ieSpell.ieSpellExtension"); + sp.CheckDocumentNode(ed.getDoc().documentElement); + } catch (e) { + if (e.number == -2146827859) { + ed.windowManager.confirm(ed.getLang("iespell.download"), function(s) { + if (s) + window.open('http://www.iespell.com/download.php', 'ieSpellDownload', ''); + }); + } else + ed.windowManager.alert("Error Loading ieSpell: Exception " + e.number); + } + }); + + // Register buttons + ed.addButton('iespell', {title : 'iespell.iespell_desc', cmd : 'mceIESpell'}); + }, + + getInfo : function() { + return { + longname : 'IESpell (IE Only)', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/iespell', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('iespell', tinymce.plugins.IESpell); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/inlinepopups/editor_plugin.js b/web/js/tiny_mce/plugins/inlinepopups/editor_plugin.js new file mode 100644 index 0000000..0766b49 --- /dev/null +++ b/web/js/tiny_mce/plugins/inlinepopups/editor_plugin.js @@ -0,0 +1 @@ +(function(){var DOM=tinymce.DOM,Element=tinymce.dom.Element,Event=tinymce.dom.Event,each=tinymce.each,is=tinymce.is;tinymce.create('tinymce.plugins.InlinePopups',{init:function(ed,url){ed.onBeforeRenderUI.add(function(){ed.windowManager=new tinymce.InlineWindowManager(ed);DOM.loadCSS(url+'/skins/'+(ed.settings.inlinepopups_skin||'clearlooks2')+"/window.css");});},getInfo:function(){return{longname:'InlinePopups',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.create('tinymce.InlineWindowManager:tinymce.WindowManager',{InlineWindowManager:function(ed){var t=this;t.parent(ed);t.zIndex=300000;t.count=0;},open:function(f,p){var t=this,id,opt='',ed=t.editor,dw=0,dh=0,vp,po,mdf,clf,we,w,u;f=f||{};p=p||{};if(!f.inline)return t.parent(f,p);if(!f.type)t.bookmark=ed.selection.getBookmark('simple');id=DOM.uniqueId();vp=DOM.getViewPort();f.width=parseInt(f.width||320);f.height=parseInt(f.height||240)+(tinymce.isIE?8:0);f.min_width=parseInt(f.min_width||150);f.min_height=parseInt(f.min_height||100);f.max_width=parseInt(f.max_width||2000);f.max_height=parseInt(f.max_height||2000);f.left=f.left||Math.round(Math.max(vp.x,vp.x+(vp.w/ 2.0) - (f.width /2.0)));f.top=f.top||Math.round(Math.max(vp.y,vp.y+(vp.h/ 2.0) - (f.height /2.0)));f.movable=f.resizable=true;p.mce_width=f.width;p.mce_height=f.height;p.mce_inline=true;p.mce_window_id=id;p.mce_auto_focus=f.auto_focus;t.features=f;t.params=p;t.onOpen.dispatch(t,f,p);if(f.type){opt+=' mceModal';if(f.type)opt+=' mce'+f.type.substring(0,1).toUpperCase()+f.type.substring(1);f.resizable=false;}if(f.statusbar)opt+=' mceStatusbar';if(f.resizable)opt+=' mceResizable';if(f.minimizable)opt+=' mceMinimizable';if(f.maximizable)opt+=' mceMaximizable';if(f.movable)opt+=' mceMovable';t._addAll(DOM.doc.body,['div',{id:id,'class':ed.settings.inlinepopups_skin||'clearlooks2',style:'width:100px;height:100px'},['div',{id:id+'_wrapper','class':'mceWrapper'+opt},['div',{id:id+'_top','class':'mceTop'},['div',{'class':'mceLeft'}],['div',{'class':'mceCenter'}],['div',{'class':'mceRight'}],['span',{id:id+'_title'},f.title||'']],['div',{id:id+'_middle','class':'mceMiddle'},['div',{id:id+'_left','class':'mceLeft'}],['span',{id:id+'_content'}],['div',{id:id+'_right','class':'mceRight'}]],['div',{id:id+'_bottom','class':'mceBottom'},['div',{'class':'mceLeft'}],['div',{'class':'mceCenter'}],['div',{'class':'mceRight'}],['span',{id:id+'_status'},'Content']],['a',{'class':'mceMove',tabindex:'-1',href:'javascript:;'}],['a',{'class':'mceMin',tabindex:'-1',href:'javascript:;',onmousedown:'return false;'}],['a',{'class':'mceMax',tabindex:'-1',href:'javascript:;',onmousedown:'return false;'}],['a',{'class':'mceMed',tabindex:'-1',href:'javascript:;',onmousedown:'return false;'}],['a',{'class':'mceClose',tabindex:'-1',href:'javascript:;',onmousedown:'return false;'}],['a',{id:id+'_resize_n','class':'mceResize mceResizeN',tabindex:'-1',href:'javascript:;'}],['a',{id:id+'_resize_s','class':'mceResize mceResizeS',tabindex:'-1',href:'javascript:;'}],['a',{id:id+'_resize_w','class':'mceResize mceResizeW',tabindex:'-1',href:'javascript:;'}],['a',{id:id+'_resize_e','class':'mceResize mceResizeE',tabindex:'-1',href:'javascript:;'}],['a',{id:id+'_resize_nw','class':'mceResize mceResizeNW',tabindex:'-1',href:'javascript:;'}],['a',{id:id+'_resize_ne','class':'mceResize mceResizeNE',tabindex:'-1',href:'javascript:;'}],['a',{id:id+'_resize_sw','class':'mceResize mceResizeSW',tabindex:'-1',href:'javascript:;'}],['a',{id:id+'_resize_se','class':'mceResize mceResizeSE',tabindex:'-1',href:'javascript:;'}]]]);DOM.setStyles(id,{top:-10000,left:-10000});if(tinymce.isGecko)DOM.setStyle(id,'overflow','auto');if(!f.type){dw+=DOM.get(id+'_left').clientWidth;dw+=DOM.get(id+'_right').clientWidth;dh+=DOM.get(id+'_top').clientHeight;dh+=DOM.get(id+'_bottom').clientHeight;}DOM.setStyles(id,{top:f.top,left:f.left,width:f.width+dw,height:f.height+dh});u=f.url||f.file;if(u){if(tinymce.relaxedDomain)u+=(u.indexOf('?')==-1?'?':'&')+'mce_rdomain='+tinymce.relaxedDomain;u=tinymce._addVer(u);}if(!f.type){DOM.add(id+'_content','iframe',{id:id+'_ifr',src:'javascript:""',frameBorder:0,style:'border:0;width:10px;height:10px'});DOM.setStyles(id+'_ifr',{width:f.width,height:f.height});DOM.setAttrib(id+'_ifr','src',u);}else{DOM.add(id+'_wrapper','a',{id:id+'_ok','class':'mceButton mceOk',href:'javascript:;',onmousedown:'return false;'},'Ok');if(f.type=='confirm')DOM.add(id+'_wrapper','a',{'class':'mceButton mceCancel',href:'javascript:;',onmousedown:'return false;'},'Cancel');DOM.add(id+'_middle','div',{'class':'mceIcon'});DOM.setHTML(id+'_content',f.content.replace('\n','
    '));}mdf=Event.add(id,'mousedown',function(e){var n=e.target,w,vp;w=t.windows[id];t.focus(id);if(n.nodeName=='A'||n.nodeName=='a'){if(n.className=='mceMax'){w.oldPos=w.element.getXY();w.oldSize=w.element.getSize();vp=DOM.getViewPort();vp.w-=2;vp.h-=2;w.element.moveTo(vp.x,vp.y);w.element.resizeTo(vp.w,vp.h);DOM.setStyles(id+'_ifr',{width:vp.w-w.deltaWidth,height:vp.h-w.deltaHeight});DOM.addClass(id+'_wrapper','mceMaximized');}else if(n.className=='mceMed'){w.element.moveTo(w.oldPos.x,w.oldPos.y);w.element.resizeTo(w.oldSize.w,w.oldSize.h);w.iframeElement.resizeTo(w.oldSize.w-w.deltaWidth,w.oldSize.h-w.deltaHeight);DOM.removeClass(id+'_wrapper','mceMaximized');}else if(n.className=='mceMove')return t._startDrag(id,e,n.className);else if(DOM.hasClass(n,'mceResize'))return t._startDrag(id,e,n.className.substring(13));}});clf=Event.add(id,'click',function(e){var n=e.target;t.focus(id);if(n.nodeName=='A'||n.nodeName=='a'){switch(n.className){case'mceClose':t.close(null,id);return Event.cancel(e);case'mceButton mceOk':case'mceButton mceCancel':f.button_func(n.className=='mceButton mceOk');return Event.cancel(e);}}});t.windows=t.windows||{};w=t.windows[id]={id:id,mousedown_func:mdf,click_func:clf,element:new Element(id,{blocker:1,container:ed.getContainer()}),iframeElement:new Element(id+'_ifr'),features:f,deltaWidth:dw,deltaHeight:dh};w.iframeElement.on('focus',function(){t.focus(id);});if(t.count==0&&t.editor.getParam('dialog_type')=='modal'){DOM.add(DOM.doc.body,'div',{id:'mceModalBlocker','class':(t.editor.settings.inlinepopups_skin||'clearlooks2')+'_modalBlocker',style:{left:vp.x,top:vp.y,zIndex:t.zIndex-1}});DOM.show('mceModalBlocker');}else DOM.setStyle('mceModalBlocker','z-index',t.zIndex-1);t.focus(id);t._fixIELayout(id,1);if(DOM.get(id+'_ok'))DOM.get(id+'_ok').focus();t.count++;return w;},focus:function(id){var t=this,w=t.windows[id];w.zIndex=this.zIndex++;w.element.setStyle('zIndex',w.zIndex);w.element.update();id=id+'_wrapper';DOM.removeClass(t.lastId,'mceFocus');DOM.addClass(id,'mceFocus');t.lastId=id;},_addAll:function(te,ne){var i,n,t=this,dom=tinymce.DOM;if(is(ne,'string'))te.appendChild(dom.doc.createTextNode(ne));else if(ne.length){te=te.appendChild(dom.create(ne[0],ne[1]));for(i=2;iix){fw=w;ix=w.zIndex;}});if(fw)t.focus(fw.id);}},setTitle:function(ti,id){var e;if(e=DOM.get(id+'_title'))e.innerHTML=DOM.encode(ti);},alert:function(txt,cb,s){var t=this,w;w=t.open({title:t,type:'alert',button_func:function(s){if(cb)cb.call(s||t,s);t.close(null,w.id);},content:DOM.encode(t.editor.getLang(txt,txt)),inline:1,width:400,height:130});},confirm:function(txt,cb,s){var t=this,w;w=t.open({title:t,type:'confirm',button_func:function(s){if(cb)cb.call(s||t,s);t.close(null,w.id);},content:DOM.encode(t.editor.getLang(txt,txt)),inline:1,width:400,height:130});},_fixIELayout:function(id,s){var w,img;if(!tinymce.isIE6)return;each(['n','s','w','e','nw','ne','sw','se'],function(v){var e=DOM.get(id+'_resize_'+v);DOM.setStyles(e,{width:s?e.clientWidth:'',height:s?e.clientHeight:'',cursor:DOM.getStyle(e,'cursor',1)});DOM.setStyle(id+"_bottom",'bottom','-1px');e=0;});if(w=this.windows[id]){w.element.hide();w.element.show();each(DOM.select('div,a',id),function(e,i){if(e.currentStyle.backgroundImage!='none'){img=new Image();img.src=e.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/,'$1');}});DOM.get(id).style.filter='';}}});tinymce.PluginManager.add('inlinepopups',tinymce.plugins.InlinePopups);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/inlinepopups/editor_plugin_src.js b/web/js/tiny_mce/plugins/inlinepopups/editor_plugin_src.js new file mode 100644 index 0000000..0ef2b7d --- /dev/null +++ b/web/js/tiny_mce/plugins/inlinepopups/editor_plugin_src.js @@ -0,0 +1,601 @@ +/** + * $Id: editor_plugin_src.js 776 2008-04-08 17:00:39Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + var DOM = tinymce.DOM, Element = tinymce.dom.Element, Event = tinymce.dom.Event, each = tinymce.each, is = tinymce.is; + + tinymce.create('tinymce.plugins.InlinePopups', { + init : function(ed, url) { + // Replace window manager + ed.onBeforeRenderUI.add(function() { + ed.windowManager = new tinymce.InlineWindowManager(ed); + DOM.loadCSS(url + '/skins/' + (ed.settings.inlinepopups_skin || 'clearlooks2') + "/window.css"); + }); + }, + + getInfo : function() { + return { + longname : 'InlinePopups', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + tinymce.create('tinymce.InlineWindowManager:tinymce.WindowManager', { + InlineWindowManager : function(ed) { + var t = this; + + t.parent(ed); + t.zIndex = 300000; + t.count = 0; + }, + + open : function(f, p) { + var t = this, id, opt = '', ed = t.editor, dw = 0, dh = 0, vp, po, mdf, clf, we, w, u; + + f = f || {}; + p = p || {}; + + // Run native windows + if (!f.inline) + return t.parent(f, p); + + // Only store selection if the type is a normal window + if (!f.type) + t.bookmark = ed.selection.getBookmark('simple'); + + id = DOM.uniqueId(); + vp = DOM.getViewPort(); + f.width = parseInt(f.width || 320); + f.height = parseInt(f.height || 240) + (tinymce.isIE ? 8 : 0); + f.min_width = parseInt(f.min_width || 150); + f.min_height = parseInt(f.min_height || 100); + f.max_width = parseInt(f.max_width || 2000); + f.max_height = parseInt(f.max_height || 2000); + f.left = f.left || Math.round(Math.max(vp.x, vp.x + (vp.w / 2.0) - (f.width / 2.0))); + f.top = f.top || Math.round(Math.max(vp.y, vp.y + (vp.h / 2.0) - (f.height / 2.0))); + f.movable = f.resizable = true; + p.mce_width = f.width; + p.mce_height = f.height; + p.mce_inline = true; + p.mce_window_id = id; + p.mce_auto_focus = f.auto_focus; + + // Transpose +// po = DOM.getPos(ed.getContainer()); +// f.left -= po.x; +// f.top -= po.y; + + t.features = f; + t.params = p; + t.onOpen.dispatch(t, f, p); + + if (f.type) { + opt += ' mceModal'; + + if (f.type) + opt += ' mce' + f.type.substring(0, 1).toUpperCase() + f.type.substring(1); + + f.resizable = false; + } + + if (f.statusbar) + opt += ' mceStatusbar'; + + if (f.resizable) + opt += ' mceResizable'; + + if (f.minimizable) + opt += ' mceMinimizable'; + + if (f.maximizable) + opt += ' mceMaximizable'; + + if (f.movable) + opt += ' mceMovable'; + + // Create DOM objects + t._addAll(DOM.doc.body, + ['div', {id : id, 'class' : ed.settings.inlinepopups_skin || 'clearlooks2', style : 'width:100px;height:100px'}, + ['div', {id : id + '_wrapper', 'class' : 'mceWrapper' + opt}, + ['div', {id : id + '_top', 'class' : 'mceTop'}, + ['div', {'class' : 'mceLeft'}], + ['div', {'class' : 'mceCenter'}], + ['div', {'class' : 'mceRight'}], + ['span', {id : id + '_title'}, f.title || ''] + ], + + ['div', {id : id + '_middle', 'class' : 'mceMiddle'}, + ['div', {id : id + '_left', 'class' : 'mceLeft'}], + ['span', {id : id + '_content'}], + ['div', {id : id + '_right', 'class' : 'mceRight'}] + ], + + ['div', {id : id + '_bottom', 'class' : 'mceBottom'}, + ['div', {'class' : 'mceLeft'}], + ['div', {'class' : 'mceCenter'}], + ['div', {'class' : 'mceRight'}], + ['span', {id : id + '_status'}, 'Content'] + ], + + ['a', {'class' : 'mceMove', tabindex : '-1', href : 'javascript:;'}], + ['a', {'class' : 'mceMin', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], + ['a', {'class' : 'mceMax', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], + ['a', {'class' : 'mceMed', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], + ['a', {'class' : 'mceClose', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}], + ['a', {id : id + '_resize_n', 'class' : 'mceResize mceResizeN', tabindex : '-1', href : 'javascript:;'}], + ['a', {id : id + '_resize_s', 'class' : 'mceResize mceResizeS', tabindex : '-1', href : 'javascript:;'}], + ['a', {id : id + '_resize_w', 'class' : 'mceResize mceResizeW', tabindex : '-1', href : 'javascript:;'}], + ['a', {id : id + '_resize_e', 'class' : 'mceResize mceResizeE', tabindex : '-1', href : 'javascript:;'}], + ['a', {id : id + '_resize_nw', 'class' : 'mceResize mceResizeNW', tabindex : '-1', href : 'javascript:;'}], + ['a', {id : id + '_resize_ne', 'class' : 'mceResize mceResizeNE', tabindex : '-1', href : 'javascript:;'}], + ['a', {id : id + '_resize_sw', 'class' : 'mceResize mceResizeSW', tabindex : '-1', href : 'javascript:;'}], + ['a', {id : id + '_resize_se', 'class' : 'mceResize mceResizeSE', tabindex : '-1', href : 'javascript:;'}] + ] + ] + ); + + DOM.setStyles(id, {top : -10000, left : -10000}); + + // Fix gecko rendering bug, where the editors iframe messed with window contents + if (tinymce.isGecko) + DOM.setStyle(id, 'overflow', 'auto'); + + // Measure borders + if (!f.type) { + dw += DOM.get(id + '_left').clientWidth; + dw += DOM.get(id + '_right').clientWidth; + dh += DOM.get(id + '_top').clientHeight; + dh += DOM.get(id + '_bottom').clientHeight; + } + + // Resize window + DOM.setStyles(id, {top : f.top, left : f.left, width : f.width + dw, height : f.height + dh}); + + u = f.url || f.file; + if (u) { + if (tinymce.relaxedDomain) + u += (u.indexOf('?') == -1 ? '?' : '&') + 'mce_rdomain=' + tinymce.relaxedDomain; + + u = tinymce._addVer(u); + } + + if (!f.type) { + DOM.add(id + '_content', 'iframe', {id : id + '_ifr', src : 'javascript:""', frameBorder : 0, style : 'border:0;width:10px;height:10px'}); + DOM.setStyles(id + '_ifr', {width : f.width, height : f.height}); + DOM.setAttrib(id + '_ifr', 'src', u); + } else { + DOM.add(id + '_wrapper', 'a', {id : id + '_ok', 'class' : 'mceButton mceOk', href : 'javascript:;', onmousedown : 'return false;'}, 'Ok'); + + if (f.type == 'confirm') + DOM.add(id + '_wrapper', 'a', {'class' : 'mceButton mceCancel', href : 'javascript:;', onmousedown : 'return false;'}, 'Cancel'); + + DOM.add(id + '_middle', 'div', {'class' : 'mceIcon'}); + DOM.setHTML(id + '_content', f.content.replace('\n', '
    ')); + } + + // Register events + mdf = Event.add(id, 'mousedown', function(e) { + var n = e.target, w, vp; + + w = t.windows[id]; + t.focus(id); + + if (n.nodeName == 'A' || n.nodeName == 'a') { + if (n.className == 'mceMax') { + w.oldPos = w.element.getXY(); + w.oldSize = w.element.getSize(); + + vp = DOM.getViewPort(); + + // Reduce viewport size to avoid scrollbars + vp.w -= 2; + vp.h -= 2; + + w.element.moveTo(vp.x, vp.y); + w.element.resizeTo(vp.w, vp.h); + DOM.setStyles(id + '_ifr', {width : vp.w - w.deltaWidth, height : vp.h - w.deltaHeight}); + DOM.addClass(id + '_wrapper', 'mceMaximized'); + } else if (n.className == 'mceMed') { + // Reset to old size + w.element.moveTo(w.oldPos.x, w.oldPos.y); + w.element.resizeTo(w.oldSize.w, w.oldSize.h); + w.iframeElement.resizeTo(w.oldSize.w - w.deltaWidth, w.oldSize.h - w.deltaHeight); + + DOM.removeClass(id + '_wrapper', 'mceMaximized'); + } else if (n.className == 'mceMove') + return t._startDrag(id, e, n.className); + else if (DOM.hasClass(n, 'mceResize')) + return t._startDrag(id, e, n.className.substring(13)); + } + }); + + clf = Event.add(id, 'click', function(e) { + var n = e.target; + + t.focus(id); + + if (n.nodeName == 'A' || n.nodeName == 'a') { + switch (n.className) { + case 'mceClose': + t.close(null, id); + return Event.cancel(e); + + case 'mceButton mceOk': + case 'mceButton mceCancel': + f.button_func(n.className == 'mceButton mceOk'); + return Event.cancel(e); + } + } + }); + + // Add window + t.windows = t.windows || {}; + w = t.windows[id] = { + id : id, + mousedown_func : mdf, + click_func : clf, + element : new Element(id, {blocker : 1, container : ed.getContainer()}), + iframeElement : new Element(id + '_ifr'), + features : f, + deltaWidth : dw, + deltaHeight : dh + }; + + w.iframeElement.on('focus', function() { + t.focus(id); + }); + + // Setup blocker + if (t.count == 0 && t.editor.getParam('dialog_type') == 'modal') { + DOM.add(DOM.doc.body, 'div', { + id : 'mceModalBlocker', + 'class' : (t.editor.settings.inlinepopups_skin || 'clearlooks2') + '_modalBlocker', + style : {left : vp.x, top : vp.y, zIndex : t.zIndex - 1} + }); + + DOM.show('mceModalBlocker'); // Reduces flicker in IE + } else + DOM.setStyle('mceModalBlocker', 'z-index', t.zIndex - 1); + + t.focus(id); + t._fixIELayout(id, 1); + + // Focus ok button + if (DOM.get(id + '_ok')) + DOM.get(id + '_ok').focus(); + + t.count++; + + return w; + }, + + focus : function(id) { + var t = this, w = t.windows[id]; + + w.zIndex = this.zIndex++; + w.element.setStyle('zIndex', w.zIndex); + w.element.update(); + + id = id + '_wrapper'; + DOM.removeClass(t.lastId, 'mceFocus'); + DOM.addClass(id, 'mceFocus'); + t.lastId = id; + }, + + _addAll : function(te, ne) { + var i, n, t = this, dom = tinymce.DOM; + + if (is(ne, 'string')) + te.appendChild(dom.doc.createTextNode(ne)); + else if (ne.length) { + te = te.appendChild(dom.create(ne[0], ne[1])); + + for (i=2; i ix) { + fw = w; + ix = w.zIndex; + } + }); + + if (fw) + t.focus(fw.id); + } + }, + + setTitle : function(ti, id) { + var e; + + if (e = DOM.get(id + '_title')) + e.innerHTML = DOM.encode(ti); + }, + + alert : function(txt, cb, s) { + var t = this, w; + + w = t.open({ + title : t, + type : 'alert', + button_func : function(s) { + if (cb) + cb.call(s || t, s); + + t.close(null, w.id); + }, + content : DOM.encode(t.editor.getLang(txt, txt)), + inline : 1, + width : 400, + height : 130 + }); + }, + + confirm : function(txt, cb, s) { + var t = this, w; + + w = t.open({ + title : t, + type : 'confirm', + button_func : function(s) { + if (cb) + cb.call(s || t, s); + + t.close(null, w.id); + }, + content : DOM.encode(t.editor.getLang(txt, txt)), + inline : 1, + width : 400, + height : 130 + }); + }, + + // Internal functions + + _fixIELayout : function(id, s) { + var w, img; + + if (!tinymce.isIE6) + return; + + // Fixes the bug where hover flickers and does odd things in IE6 + each(['n','s','w','e','nw','ne','sw','se'], function(v) { + var e = DOM.get(id + '_resize_' + v); + + DOM.setStyles(e, { + width : s ? e.clientWidth : '', + height : s ? e.clientHeight : '', + cursor : DOM.getStyle(e, 'cursor', 1) + }); + + DOM.setStyle(id + "_bottom", 'bottom', '-1px'); + + e = 0; + }); + + // Fixes graphics glitch + if (w = this.windows[id]) { + // Fixes rendering bug after resize + w.element.hide(); + w.element.show(); + + // Forced a repaint of the window + //DOM.get(id).style.filter = ''; + + // IE has a bug where images used in CSS won't get loaded + // sometimes when the cache in the browser is disabled + // This fix tries to solve it by loading the images using the image object + each(DOM.select('div,a', id), function(e, i) { + if (e.currentStyle.backgroundImage != 'none') { + img = new Image(); + img.src = e.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/, '$1'); + } + }); + + DOM.get(id).style.filter = ''; + } + } + }); + + // Register plugin + tinymce.PluginManager.add('inlinepopups', tinymce.plugins.InlinePopups); +})(); + diff --git a/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif new file mode 100644 index 0000000..94abd08 Binary files /dev/null and b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif differ diff --git a/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/button.gif b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/button.gif new file mode 100644 index 0000000..e671094 Binary files /dev/null and b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/button.gif differ diff --git a/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif new file mode 100644 index 0000000..6baf64a Binary files /dev/null and b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif differ diff --git a/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif new file mode 100644 index 0000000..497307a Binary files /dev/null and b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif differ diff --git a/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif new file mode 100644 index 0000000..c894b2e Binary files /dev/null and b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif differ diff --git a/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif new file mode 100644 index 0000000..c2a2ad4 Binary files /dev/null and b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif differ diff --git a/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif new file mode 100644 index 0000000..43a735f Binary files /dev/null and b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif differ diff --git a/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.css b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.css new file mode 100644 index 0000000..4036922 --- /dev/null +++ b/web/js/tiny_mce/plugins/inlinepopups/skins/clearlooks2/window.css @@ -0,0 +1,90 @@ +/* Clearlooks 2 */ + +/* Reset */ +.clearlooks2, .clearlooks2 div, .clearlooks2 span, .clearlooks2 a {vertical-align:baseline; text-align:left; position:absolute; border:0; padding:0; margin:0; background:transparent; font-family:Arial,Verdana; font-size:11px; color:#000; text-decoration:none; font-weight:normal; width:auto; height:auto; overflow:hidden; display:block} + +/* General */ +.clearlooks2 {position:absolute; direction:ltr} +.clearlooks2 .mceWrapper {position:static} +.mceEventBlocker {position:absolute; left:0; top:0; background:url(img/horizontal.gif) no-repeat 0 -75px; width:100%; height:100%} +.clearlooks2 .mcePlaceHolder {border:1px solid #000; background:#888; top:0; left:0; opacity:0.5; filter:alpha(opacity=50)} +.clearlooks2_modalBlocker {position:absolute; left:0; top:0; width:100%; height:100%; background:#FFF; opacity:0.6; filter:alpha(opacity=60); display:none} + +/* Top */ +.clearlooks2 .mceTop, .clearlooks2 .mceTop div {top:0; width:100%; height:23px} +.clearlooks2 .mceTop .mceLeft {width:6px; background:url(img/corners.gif)} +.clearlooks2 .mceTop .mceCenter {right:6px; width:100%; height:23px; background:url(img/horizontal.gif) 12px 0; clip:rect(auto auto auto 12px)} +.clearlooks2 .mceTop .mceRight {right:0; width:6px; height:23px; background:url(img/corners.gif) -12px 0} +.clearlooks2 .mceTop span {width:100%; text-align:center; vertical-align:middle; line-height:23px; font-weight:bold} +.clearlooks2 .mceFocus .mceTop .mceLeft {background:url(img/corners.gif) -6px 0} +.clearlooks2 .mceFocus .mceTop .mceCenter {background:url(img/horizontal.gif) 0 -23px} +.clearlooks2 .mceFocus .mceTop .mceRight {background:url(img/corners.gif) -18px 0} +.clearlooks2 .mceFocus .mceTop span {color:#FFF} + +/* Middle */ +.clearlooks2 .mceMiddle, .clearlooks2 .mceMiddle div {top:0} +.clearlooks2 .mceMiddle {width:100%; height:100%; clip:rect(23px auto auto auto)} +.clearlooks2 .mceMiddle .mceLeft {left:0; width:5px; height:100%; background:url(img/vertical.gif) -5px 0} +.clearlooks2 .mceMiddle span {top:23px; left:5px; width:100%; height:100%; background:#FFF} +.clearlooks2 .mceMiddle .mceRight {right:0; width:5px; height:100%; background:url(img/vertical.gif)} + +/* Bottom */ +.clearlooks2 .mceBottom, .clearlooks2 .mceBottom div {height:6px} +.clearlooks2 .mceBottom {left:0; bottom:0; width:100%} +.clearlooks2 .mceBottom div {top:0} +.clearlooks2 .mceBottom .mceLeft {left:0; width:5px; background:url(img/corners.gif) -34px -6px} +.clearlooks2 .mceBottom .mceCenter {left:5px; width:100%; background:url(img/horizontal.gif) 0 -46px} +.clearlooks2 .mceBottom .mceRight {right:0; width:5px; background: url(img/corners.gif) -34px 0} +.clearlooks2 .mceBottom span {display:none} +.clearlooks2 .mceStatusbar .mceBottom, .clearlooks2 .mceStatusbar .mceBottom div {height:23px} +.clearlooks2 .mceStatusbar .mceBottom .mceLeft {background:url(img/corners.gif) -29px 0} +.clearlooks2 .mceStatusbar .mceBottom .mceCenter {background:url(img/horizontal.gif) 0 -52px} +.clearlooks2 .mceStatusbar .mceBottom .mceRight {background:url(img/corners.gif) -24px 0} +.clearlooks2 .mceStatusbar .mceBottom span {display:block; left:7px; font-family:Arial, Verdana; font-size:11px; line-height:23px} + +/* Actions */ +.clearlooks2 a {width:29px; height:16px; top:3px;} +.clearlooks2 .mceClose {right:6px; background:url(img/buttons.gif) -87px 0} +.clearlooks2 .mceMin {display:none; right:68px; background:url(img/buttons.gif) 0 0} +.clearlooks2 .mceMed {display:none; right:37px; background:url(img/buttons.gif) -29px 0} +.clearlooks2 .mceMax {display:none; right:37px; background:url(img/buttons.gif) -58px 0} +.clearlooks2 .mceMove {display:none;width:100%;cursor:move;background:url(img/corners.gif) no-repeat -100px -100px} +.clearlooks2 .mceMovable .mceMove {display:block} +.clearlooks2 .mceFocus .mceClose {right:6px; background:url(img/buttons.gif) -87px -16px} +.clearlooks2 .mceFocus .mceMin {right:68px; background:url(img/buttons.gif) 0 -16px} +.clearlooks2 .mceFocus .mceMed {right:37px; background:url(img/buttons.gif) -29px -16px} +.clearlooks2 .mceFocus .mceMax {right:37px; background:url(img/buttons.gif) -58px -16px} +.clearlooks2 .mceFocus .mceClose:hover {right:6px; background:url(img/buttons.gif) -87px -32px} +.clearlooks2 .mceFocus .mceClose:hover {right:6px; background:url(img/buttons.gif) -87px -32px} +.clearlooks2 .mceFocus .mceMin:hover {right:68px; background:url(img/buttons.gif) 0 -32px} +.clearlooks2 .mceFocus .mceMed:hover {right:37px; background:url(img/buttons.gif) -29px -32px} +.clearlooks2 .mceFocus .mceMax:hover {right:37px; background:url(img/buttons.gif) -58px -32px} + +/* Resize */ +.clearlooks2 .mceResize {top:auto; left:auto; display:none; width:5px; height:5px; background:url(img/horizontal.gif) no-repeat 0 -75px} +.clearlooks2 .mceResizable .mceResize {display:block} +.clearlooks2 .mceResizable .mceMin, .clearlooks2 .mceMax {display:none} +.clearlooks2 .mceMinimizable .mceMin {display:block} +.clearlooks2 .mceMaximizable .mceMax {display:block} +.clearlooks2 .mceMaximized .mceMed {display:block} +.clearlooks2 .mceMaximized .mceMax {display:none} +.clearlooks2 a.mceResizeN {top:0; left:0; width:100%; cursor:n-resize} +.clearlooks2 a.mceResizeNW {top:0; left:0; cursor:nw-resize} +.clearlooks2 a.mceResizeNE {top:0; right:0; cursor:ne-resize} +.clearlooks2 a.mceResizeW {top:0; left:0; height:100%; cursor:w-resize;} +.clearlooks2 a.mceResizeE {top:0; right:0; height:100%; cursor:e-resize} +.clearlooks2 a.mceResizeS {bottom:0; left:0; width:100%; cursor:s-resize} +.clearlooks2 a.mceResizeSW {bottom:0; left:0; cursor:sw-resize} +.clearlooks2 a.mceResizeSE {bottom:0; right:0; cursor:se-resize} + +/* Alert/Confirm */ +.clearlooks2 .mceButton {font-weight:bold; bottom:10px; width:80px; height:30px; background:url(img/button.gif); line-height:30px; vertical-align:middle; text-align:center; outline:0} +.clearlooks2 .mceMiddle .mceIcon {left:15px; top:35px; width:32px; height:32px} +.clearlooks2 .mceAlert .mceMiddle span, .clearlooks2 .mceConfirm .mceMiddle span {background:transparent;left:60px; top:35px; width:320px; height:50px; font-weight:bold; overflow:auto; white-space:normal} +.clearlooks2 a:hover {font-weight:bold;} +.clearlooks2 .mceAlert .mceMiddle, .clearlooks2 .mceConfirm .mceMiddle {background:#D6D7D5} +.clearlooks2 .mceAlert .mceOk {left:50%; top:auto; margin-left: -40px} +.clearlooks2 .mceAlert .mceIcon {background:url(img/alert.gif)} +.clearlooks2 .mceConfirm .mceOk {left:50%; top:auto; margin-left: -90px} +.clearlooks2 .mceConfirm .mceCancel {left:50%; top:auto} +.clearlooks2 .mceConfirm .mceIcon {background:url(img/confirm.gif)} \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/inlinepopups/template.htm b/web/js/tiny_mce/plugins/inlinepopups/template.htm new file mode 100644 index 0000000..b153821 --- /dev/null +++ b/web/js/tiny_mce/plugins/inlinepopups/template.htm @@ -0,0 +1,387 @@ + + + +Template for dialogs + + + + +
    +
    +
    +
    +
    +
    +
    + Blured +
    + +
    +
    + Content +
    +
    + +
    +
    +
    +
    + Statusbar text. +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + Focused +
    + +
    +
    + Content +
    +
    + +
    +
    +
    +
    + Statusbar text. +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + Statusbar +
    + +
    +
    + Content +
    +
    + +
    +
    +
    +
    + Statusbar text. +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + Statusbar, Resizable +
    + +
    +
    + Content +
    +
    + +
    +
    +
    +
    + Statusbar text. +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + Resizable, Maximizable +
    + +
    +
    + Content +
    +
    + +
    +
    +
    +
    + Statusbar text. +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + Blurred, Maximizable, Statusbar, Resizable +
    + +
    +
    + Content +
    +
    + +
    +
    +
    +
    + Statusbar text. +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + Maximized, Maximizable, Minimizable +
    + +
    +
    + Content +
    +
    + +
    +
    +
    +
    + Statusbar text. +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + Blured +
    + +
    +
    + Content +
    +
    + +
    +
    +
    +
    + Statusbar text. +
    + + + + + + + + + + + + + + +
    +
    + +
    +
    +
    +
    +
    +
    + Alert +
    + +
    +
    + + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + +
    +
    +
    + +
    +
    +
    +
    +
    + + + Ok + +
    +
    + +
    +
    +
    +
    +
    +
    + Confirm +
    + +
    +
    + + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + This is a very long error message. This is a very long error message. + +
    +
    +
    + +
    +
    +
    +
    +
    + + + Ok + Cancel + +
    +
    +
    + + + diff --git a/web/js/tiny_mce/plugins/insertbanner/editor_plugin.js b/web/js/tiny_mce/plugins/insertbanner/editor_plugin.js new file mode 100644 index 0000000..7894bc6 --- /dev/null +++ b/web/js/tiny_mce/plugins/insertbanner/editor_plugin.js @@ -0,0 +1,33 @@ + +(function() { + tinymce.create('tinymce.plugins.InsertBannerPlugin', { + init : function(ed, url) { + ed.addCommand('mceInsertBanner', function() { + return insertBannerMarkup(); + }); + + ed.addButton('insertbanner', { + title : 'Insert the banner image into the article', + cmd : 'mceInsertBanner', + image : url + '/img/insertbanner.gif' + }); + + // Add a node change handler, selects the button in the UI when a image is selected + ed.onNodeChange.add(function(ed, cm, n) { + cm.setActive('insertbanner', n.nodeName == 'IMG'); + }); + }, + + getInfo : function() { + return { + longname : 'Insert banner image plugin', + author : 'Hannes Magnusson', + authorurl : 'http://linpro.no', + version : "0.9" + }; + } + }); + + tinymce.PluginManager.add('insertbanner', tinymce.plugins.InsertBannerPlugin); +})(); + diff --git a/web/js/tiny_mce/plugins/insertbanner/editor_plugin_src.js b/web/js/tiny_mce/plugins/insertbanner/editor_plugin_src.js new file mode 100644 index 0000000..7894bc6 --- /dev/null +++ b/web/js/tiny_mce/plugins/insertbanner/editor_plugin_src.js @@ -0,0 +1,33 @@ + +(function() { + tinymce.create('tinymce.plugins.InsertBannerPlugin', { + init : function(ed, url) { + ed.addCommand('mceInsertBanner', function() { + return insertBannerMarkup(); + }); + + ed.addButton('insertbanner', { + title : 'Insert the banner image into the article', + cmd : 'mceInsertBanner', + image : url + '/img/insertbanner.gif' + }); + + // Add a node change handler, selects the button in the UI when a image is selected + ed.onNodeChange.add(function(ed, cm, n) { + cm.setActive('insertbanner', n.nodeName == 'IMG'); + }); + }, + + getInfo : function() { + return { + longname : 'Insert banner image plugin', + author : 'Hannes Magnusson', + authorurl : 'http://linpro.no', + version : "0.9" + }; + } + }); + + tinymce.PluginManager.add('insertbanner', tinymce.plugins.InsertBannerPlugin); +})(); + diff --git a/web/js/tiny_mce/plugins/insertbanner/img/insertbanner.gif b/web/js/tiny_mce/plugins/insertbanner/img/insertbanner.gif new file mode 100644 index 0000000..a815c47 Binary files /dev/null and b/web/js/tiny_mce/plugins/insertbanner/img/insertbanner.gif differ diff --git a/web/js/tiny_mce/plugins/insertdatetime/editor_plugin.js b/web/js/tiny_mce/plugins/insertdatetime/editor_plugin.js new file mode 100644 index 0000000..34d4cec --- /dev/null +++ b/web/js/tiny_mce/plugins/insertdatetime/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.InsertDateTime',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mceInsertDate',function(){var str=t._getDateTime(new Date(),ed.getParam("plugin_insertdate_dateFormat",ed.getLang('insertdatetime.date_fmt')));ed.execCommand('mceInsertContent',false,str);});ed.addCommand('mceInsertTime',function(){var str=t._getDateTime(new Date(),ed.getParam("plugin_insertdate_timeFormat",ed.getLang('insertdatetime.time_fmt')));ed.execCommand('mceInsertContent',false,str);});ed.addButton('insertdate',{title:'insertdatetime.insertdate_desc',cmd:'mceInsertDate'});ed.addButton('inserttime',{title:'insertdatetime.inserttime_desc',cmd:'mceInsertTime'});},getInfo:function(){return{longname:'Insert date/time',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/insertdatetime',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_getDateTime:function(d,fmt){var ed=this.editor;function addZeros(value,len){value=""+value;if(value.length-1){nl[ci].style.zIndex=z[fi];nl[fi].style.zIndex=z[ci];}else{if(z[ci]>0)nl[ci].style.zIndex=z[ci]-1;}}else{for(i=0;iz[ci]){fi=i;break;}}if(fi>-1){nl[ci].style.zIndex=z[fi];nl[fi].style.zIndex=z[ci];}else nl[ci].style.zIndex=z[ci]+1;}ed.execCommand('mceRepaint');},_getParentLayer:function(n){return this.editor.dom.getParent(n,function(n){return n.nodeType==1&&/^(absolute|relative|static)$/i.test(n.style.position);});},_insertLayer:function(){var ed=this.editor,p=ed.dom.getPos(ed.dom.getParent(ed.selection.getNode(),'*'));ed.dom.add(ed.getBody(),'div',{style:{position:'absolute',left:p.x,top:(p.y>20?p.y:20),width:100,height:100},'class':'mceItemVisualAid'},ed.selection.getContent()||ed.getLang('layer.content'));},_toggleAbsolute:function(){var ed=this.editor,le=this._getParentLayer(ed.selection.getNode());if(!le)le=ed.dom.getParent(ed.selection.getNode(),'DIV,P,IMG');if(le){if(le.style.position.toLowerCase()=="absolute"){ed.dom.setStyles(le,{position:'',left:'',top:'',width:'',height:''});ed.dom.removeClass(le,'mceItemVisualAid');}else{if(le.style.left=="")le.style.left=20+'px';if(le.style.top=="")le.style.top=20+'px';if(le.style.width=="")le.style.width=le.width?(le.width+'px'):'100px';if(le.style.height=="")le.style.height=le.height?(le.height+'px'):'100px';le.style.position="absolute";ed.addVisual(ed.getBody());}ed.execCommand('mceRepaint');ed.nodeChanged();}}});tinymce.PluginManager.add('layer',tinymce.plugins.Layer);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/layer/editor_plugin_src.js b/web/js/tiny_mce/plugins/layer/editor_plugin_src.js new file mode 100644 index 0000000..a72f6c3 --- /dev/null +++ b/web/js/tiny_mce/plugins/layer/editor_plugin_src.js @@ -0,0 +1,209 @@ +/** + * $Id: editor_plugin_src.js 652 2008-02-29 13:09:46Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.Layer', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + + // Register commands + ed.addCommand('mceInsertLayer', t._insertLayer, t); + + ed.addCommand('mceMoveForward', function() { + t._move(1); + }); + + ed.addCommand('mceMoveBackward', function() { + t._move(-1); + }); + + ed.addCommand('mceMakeAbsolute', function() { + t._toggleAbsolute(); + }); + + // Register buttons + ed.addButton('moveforward', {title : 'layer.forward_desc', cmd : 'mceMoveForward'}); + ed.addButton('movebackward', {title : 'layer.backward_desc', cmd : 'mceMoveBackward'}); + ed.addButton('absolute', {title : 'layer.absolute_desc', cmd : 'mceMakeAbsolute'}); + ed.addButton('insertlayer', {title : 'layer.insertlayer_desc', cmd : 'mceInsertLayer'}); + + ed.onInit.add(function() { + if (tinymce.isIE) + ed.getDoc().execCommand('2D-Position', false, true); + }); + + ed.onNodeChange.add(t._nodeChange, t); + ed.onVisualAid.add(t._visualAid, t); + }, + + getInfo : function() { + return { + longname : 'Layer', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/layer', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private methods + + _nodeChange : function(ed, cm, n) { + var le, p; + + le = this._getParentLayer(n); + p = ed.dom.getParent(n, 'DIV,P,IMG'); + + if (!p) { + cm.setDisabled('absolute', 1); + cm.setDisabled('moveforward', 1); + cm.setDisabled('movebackward', 1); + } else { + cm.setDisabled('absolute', 0); + cm.setDisabled('moveforward', !le); + cm.setDisabled('movebackward', !le); + cm.setActive('absolute', le && le.style.position.toLowerCase() == "absolute"); + } + }, + + // Private methods + + _visualAid : function(ed, e, s) { + var dom = ed.dom; + + tinymce.each(dom.select('div,p', e), function(e) { + if (/^(absolute|relative|static)$/i.test(e.style.position)) { + if (s) + dom.addClass(e, 'mceItemVisualAid'); + else + dom.removeClass(e, 'mceItemVisualAid'); + } + }); + }, + + _move : function(d) { + var ed = this.editor, i, z = [], le = this._getParentLayer(ed.selection.getNode()), ci = -1, fi = -1, nl; + + nl = []; + tinymce.walk(ed.getBody(), function(n) { + if (n.nodeType == 1 && /^(absolute|relative|static)$/i.test(n.style.position)) + nl.push(n); + }, 'childNodes'); + + // Find z-indexes + for (i=0; i -1) { + nl[ci].style.zIndex = z[fi]; + nl[fi].style.zIndex = z[ci]; + } else { + if (z[ci] > 0) + nl[ci].style.zIndex = z[ci] - 1; + } + } else { + // Move forward + + // Try find a higher one + for (i=0; i z[ci]) { + fi = i; + break; + } + } + + if (fi > -1) { + nl[ci].style.zIndex = z[fi]; + nl[fi].style.zIndex = z[ci]; + } else + nl[ci].style.zIndex = z[ci] + 1; + } + + ed.execCommand('mceRepaint'); + }, + + _getParentLayer : function(n) { + return this.editor.dom.getParent(n, function(n) { + return n.nodeType == 1 && /^(absolute|relative|static)$/i.test(n.style.position); + }); + }, + + _insertLayer : function() { + var ed = this.editor, p = ed.dom.getPos(ed.dom.getParent(ed.selection.getNode(), '*')); + + ed.dom.add(ed.getBody(), 'div', { + style : { + position : 'absolute', + left : p.x, + top : (p.y > 20 ? p.y : 20), + width : 100, + height : 100 + }, + 'class' : 'mceItemVisualAid' + }, ed.selection.getContent() || ed.getLang('layer.content')); + }, + + _toggleAbsolute : function() { + var ed = this.editor, le = this._getParentLayer(ed.selection.getNode()); + + if (!le) + le = ed.dom.getParent(ed.selection.getNode(), 'DIV,P,IMG'); + + if (le) { + if (le.style.position.toLowerCase() == "absolute") { + ed.dom.setStyles(le, { + position : '', + left : '', + top : '', + width : '', + height : '' + }); + + ed.dom.removeClass(le, 'mceItemVisualAid'); + } else { + if (le.style.left == "") + le.style.left = 20 + 'px'; + + if (le.style.top == "") + le.style.top = 20 + 'px'; + + if (le.style.width == "") + le.style.width = le.width ? (le.width + 'px') : '100px'; + + if (le.style.height == "") + le.style.height = le.height ? (le.height + 'px') : '100px'; + + le.style.position = "absolute"; + ed.addVisual(ed.getBody()); + } + + ed.execCommand('mceRepaint'); + ed.nodeChanged(); + } + } + }); + + // Register plugin + tinymce.PluginManager.add('layer', tinymce.plugins.Layer); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/media/css/content.css b/web/js/tiny_mce/plugins/media/css/content.css new file mode 100644 index 0000000..1bf6a75 --- /dev/null +++ b/web/js/tiny_mce/plugins/media/css/content.css @@ -0,0 +1,6 @@ +.mceItemFlash, .mceItemShockWave, .mceItemQuickTime, .mceItemWindowsMedia, .mceItemRealMedia {border:1px dotted #cc0000; background-position:center; background-repeat:no-repeat; background-color:#ffffcc;} +.mceItemShockWave {background-image: url(../img/shockwave.gif);} +.mceItemFlash {background-image:url(../img/flash.gif);} +.mceItemQuickTime {background-image:url(../img/quicktime.gif);} +.mceItemWindowsMedia {background-image:url(../img/windowsmedia.gif);} +.mceItemRealMedia {background-image:url(../img/realmedia.gif);} diff --git a/web/js/tiny_mce/plugins/media/css/media.css b/web/js/tiny_mce/plugins/media/css/media.css new file mode 100644 index 0000000..89c6bd5 --- /dev/null +++ b/web/js/tiny_mce/plugins/media/css/media.css @@ -0,0 +1,68 @@ +#id, #name, #hspace, #vspace, #class_name, #align { + width: 100px; +} + +#hspace, #vspace { + width: 50px; +} + +#flash_quality, #flash_align, #flash_scale, #flash_salign, #flash_wmode { + width: 100px; +} + +#flash_base, #flash_flashvars { + width: 240px; +} + +#width, #height { + width: 40px; +} + +#src, #media_type { + width: 250px; +} + +#class { + width: 120px; +} + +#prev { + margin: 0; + border: 1px solid black; + width: 99%; + height: 230px; + overflow: auto; +} + +.panel_wrapper div.current { + height: 390px; + overflow: auto; +} + +#flash_options, #shockwave_options, #qt_options, #wmp_options, #rmp_options { + display: none; +} + +.mceAddSelectValue { + background-color: #DDDDDD; +} + +#qt_starttime, #qt_endtime, #qt_fov, #qt_href, #qt_moveid, #qt_moviename, #qt_node, #qt_pan, #qt_qtsrc, #qt_qtsrcchokespeed, #qt_target, #qt_tilt, #qt_urlsubstituten, #qt_volume { + width: 70px; +} + +#wmp_balance, #wmp_baseurl, #wmp_captioningid, #wmp_currentmarker, #wmp_currentposition, #wmp_defaultframe, #wmp_playcount, #wmp_rate, #wmp_uimode, #wmp_volume { + width: 70px; +} + +#rmp_console, #rmp_numloop, #rmp_controls, #rmp_scriptcallbacks { + width: 70px; +} + +#shockwave_swvolume, #shockwave_swframe, #shockwave_swurl, #shockwave_swstretchvalign, #shockwave_swstretchhalign, #shockwave_swstretchstyle { + width: 90px; +} + +#qt_qtsrc { + width: 200px; +} diff --git a/web/js/tiny_mce/plugins/media/editor_plugin.js b/web/js/tiny_mce/plugins/media/editor_plugin.js new file mode 100644 index 0000000..4591be7 --- /dev/null +++ b/web/js/tiny_mce/plugins/media/editor_plugin.js @@ -0,0 +1 @@ +(function(){var each=tinymce.each;tinymce.create('tinymce.plugins.MediaPlugin',{init:function(ed,url){var t=this;t.editor=ed;t.url=url;function isMediaElm(n){return/^(mceItemFlash|mceItemShockWave|mceItemWindowsMedia|mceItemQuickTime|mceItemRealMedia)$/.test(n.className);};ed.addCommand('mceMedia',function(){ed.windowManager.open({file:url+'/media.htm',width:430+parseInt(ed.getLang('media.delta_width',0)),height:470+parseInt(ed.getLang('media.delta_height',0)),inline:1},{plugin_url:url});});ed.addButton('media',{title:'media.desc',cmd:'mceMedia'});ed.onNodeChange.add(function(ed,cm,n){cm.setActive('media',n.nodeName=='IMG'&&isMediaElm(n));});ed.onInit.add(function(){var lo={mceItemFlash:'flash',mceItemShockWave:'shockwave',mceItemWindowsMedia:'windowsmedia',mceItemQuickTime:'quicktime',mceItemRealMedia:'realmedia'};if(ed.settings.content_css!==false)ed.dom.loadCSS(url+"/css/content.css");if(ed.theme.onResolveName){ed.theme.onResolveName.add(function(th,o){if(o.name=='img'){each(lo,function(v,k){if(ed.dom.hasClass(o.node,k)){o.name=v;o.title=ed.dom.getAttrib(o.node,'title');return false;}});}});}if(ed&&ed.plugins.contextmenu){ed.plugins.contextmenu.onContextMenu.add(function(th,m,e){if(e.nodeName=='IMG'&&/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(e.className)){m.add({title:'media.edit',icon:'media',cmd:'mceMedia'});}});}});ed.onBeforeSetContent.add(function(ed,o){var h=o.content;h=h.replace(/]*>\s*write(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)\(\{([^\)]*)\}\);\s*<\/script>/gi,function(a,b,c){var o=t._parse(c);return''});h=h.replace(/]*)>/gi,'');h=h.replace(/]*)>/gi,'');h=h.replace(/<\/(object|embed)([^>]*)>/gi,'');h=h.replace(/]*)>/gi,function(a,b){return''});h=h.replace(/\/ class=\"mceItemParam\"><\/span>/gi,'class="mceItemParam">');o.content=h;});ed.onSetContent.add(function(){t._spansToImgs(ed.getBody());});ed.onPreProcess.add(function(ed,o){var dom=ed.dom;if(o.set){t._spansToImgs(o.node);each(dom.select('IMG',o.node),function(n){var p;if(isMediaElm(n)){p=t._parse(n.title);dom.setAttrib(n,'width',dom.getAttrib(n,'width',p.width||100));dom.setAttrib(n,'height',dom.getAttrib(n,'height',p.height||100));}});}if(o.get){each(dom.select('IMG',o.node),function(n){var ci,cb,mt;if(ed.getParam('media_use_script')){if(isMediaElm(n))n.className=n.className.replace(/mceItem/g,'mceTemp');return;}switch(n.className){case'mceItemFlash':ci='d27cdb6e-ae6d-11cf-96b8-444553540000';cb='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0';mt='application/x-shockwave-flash';break;case'mceItemShockWave':ci='166b1bca-3f9c-11cf-8075-444553540000';cb='http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0';mt='application/x-director';break;case'mceItemWindowsMedia':ci=ed.getParam('media_wmp6_compatible')?'05589fa1-c356-11ce-bf01-00aa0055595a':'6bf52a52-394a-11d3-b153-00c04f79faa6';cb='http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701';mt='application/x-mplayer2';break;case'mceItemQuickTime':ci='02bf25d5-8c17-4b23-bc80-d3488abddc6b';cb='http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0';mt='video/quicktime';break;case'mceItemRealMedia':ci='cfcdaa03-8be4-11cf-b84b-0020afbbccfa';cb='http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0';mt='audio/x-pn-realaudio-plugin';break;}if(ci){dom.replace(t._buildObj({classid:ci,codebase:cb,type:mt},n),n);}});}});ed.onPostProcess.add(function(ed,o){o.content=o.content.replace(/_value=/g,'value=');});if(ed.getParam('media_use_script')){function getAttr(s,n){n=new RegExp(n+'=\"([^\"]+)\"','g').exec(s);return n?ed.dom.decode(n[1]):'';};ed.onPostProcess.add(function(ed,o){o.content=o.content.replace(/]+>/g,function(im){var cl=getAttr(im,'class');if(/^(mceTempFlash|mceTempShockWave|mceTempWindowsMedia|mceTempQuickTime|mceTempRealMedia)$/.test(cl)){at=t._parse(getAttr(im,'title'));at.width=getAttr(im,'width');at.height=getAttr(im,'height');im='';}return im;});});}},getInfo:function(){return{longname:'Media',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_buildObj:function(o,n){var ob,ed=this.editor,dom=ed.dom,p=this._parse(n.title);p.width=o.width=dom.getAttrib(n,'width')||100;p.height=o.height=dom.getAttrib(n,'height')||100;ob=dom.create('span',{mce_name:'object',classid:"clsid:"+o.classid,codebase:o.codebase,width:o.width,height:o.height});if(p.src)p.src=ed.convertURL(p.src,'src',n);each(p,function(v,k){if(!/^(width|height|codebase|classid)$/.test(k)){if(o.type=='application/x-mplayer2'&&k=='src')k='url';dom.add(ob,'span',{mce_name:'param',name:k,'_value':v});}});dom.add(ob,'span',tinymce.extend({mce_name:'embed',type:o.type},p));return ob;},_spansToImgs:function(p){var t=this,dom=t.editor.dom,im,ci;each(dom.select('span',p),function(n){if(dom.getAttrib(n,'class')=='mceItemObject'){ci=dom.getAttrib(n,"classid").toLowerCase().replace(/\s+/g,'');switch(ci){case'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000':dom.replace(t._createImg('mceItemFlash',n),n);break;case'clsid:166b1bca-3f9c-11cf-8075-444553540000':dom.replace(t._createImg('mceItemShockWave',n),n);break;case'clsid:6bf52a52-394a-11d3-b153-00c04f79faa6':case'clsid:22d6f312-b0f6-11d0-94ab-0080c74c7e95':case'clsid:05589fa1-c356-11ce-bf01-00aa0055595a':dom.replace(t._createImg('mceItemWindowsMedia',n),n);break;case'clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b':dom.replace(t._createImg('mceItemQuickTime',n),n);break;case'clsid:cfcdaa03-8be4-11cf-b84b-0020afbbccfa':dom.replace(t._createImg('mceItemRealMedia',n),n);break;default:dom.replace(t._createImg('mceItemFlash',n),n);}return;}if(dom.getAttrib(n,'class')=='mceItemEmbed'){switch(dom.getAttrib(n,'type')){case'application/x-shockwave-flash':dom.replace(t._createImg('mceItemFlash',n),n);break;case'application/x-director':dom.replace(t._createImg('mceItemShockWave',n),n);break;case'application/x-mplayer2':dom.replace(t._createImg('mceItemWindowsMedia',n),n);break;case'video/quicktime':dom.replace(t._createImg('mceItemQuickTime',n),n);break;case'audio/x-pn-realaudio-plugin':dom.replace(t._createImg('mceItemRealMedia',n),n);break;default:dom.replace(t._createImg('mceItemFlash',n),n);}}});},_createImg:function(cl,n){var im,dom=this.editor.dom,pa={},ti='';im=dom.create('img',{src:this.url+'/img/trans.gif',width:dom.getAttrib(n,'width')||100,height:dom.getAttrib(n,'height')||100,'class':cl});each(['id','name','width','height','bgcolor','align','flashvars','src','wmode'],function(na){var v=dom.getAttrib(n,na);if(v)pa[na]=v;});each(dom.select('span',n),function(n){if(dom.hasClass(n,'mceItemParam'))pa[dom.getAttrib(n,'name')]=dom.getAttrib(n,'_value');});if(pa.movie){pa.src=pa.movie;delete pa.movie;}delete pa.width;delete pa.height;im.title=this._serialize(pa);return im;},_parse:function(s){return tinymce.util.JSON.parse('{'+s+'}');},_serialize:function(o){return tinymce.util.JSON.serialize(o).replace(/[{}]/g,'');}});tinymce.PluginManager.add('media',tinymce.plugins.MediaPlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/media/editor_plugin_src.js b/web/js/tiny_mce/plugins/media/editor_plugin_src.js new file mode 100644 index 0000000..d9df5b5 --- /dev/null +++ b/web/js/tiny_mce/plugins/media/editor_plugin_src.js @@ -0,0 +1,359 @@ +/** + * $Id: editor_plugin_src.js 763 2008-04-03 13:25:45Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + var each = tinymce.each; + + tinymce.create('tinymce.plugins.MediaPlugin', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + t.url = url; + + function isMediaElm(n) { + return /^(mceItemFlash|mceItemShockWave|mceItemWindowsMedia|mceItemQuickTime|mceItemRealMedia)$/.test(n.className); + }; + + // Register commands + ed.addCommand('mceMedia', function() { + ed.windowManager.open({ + file : url + '/media.htm', + width : 430 + parseInt(ed.getLang('media.delta_width', 0)), + height : 470 + parseInt(ed.getLang('media.delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + // Register buttons + ed.addButton('media', {title : 'media.desc', cmd : 'mceMedia'}); + + ed.onNodeChange.add(function(ed, cm, n) { + cm.setActive('media', n.nodeName == 'IMG' && isMediaElm(n)); + }); + + ed.onInit.add(function() { + var lo = { + mceItemFlash : 'flash', + mceItemShockWave : 'shockwave', + mceItemWindowsMedia : 'windowsmedia', + mceItemQuickTime : 'quicktime', + mceItemRealMedia : 'realmedia' + }; + + if (ed.settings.content_css !== false) + ed.dom.loadCSS(url + "/css/content.css"); + + if (ed.theme.onResolveName) { + ed.theme.onResolveName.add(function(th, o) { + if (o.name == 'img') { + each(lo, function(v, k) { + if (ed.dom.hasClass(o.node, k)) { + o.name = v; + o.title = ed.dom.getAttrib(o.node, 'title'); + return false; + } + }); + } + }); + } + + if (ed && ed.plugins.contextmenu) { + ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) { + if (e.nodeName == 'IMG' && /mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(e.className)) { + m.add({title : 'media.edit', icon : 'media', cmd : 'mceMedia'}); + } + }); + } + }); + + ed.onBeforeSetContent.add(function(ed, o) { + var h = o.content; + + h = h.replace(/]*>\s*write(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)\(\{([^\)]*)\}\);\s*<\/script>/gi, function(a, b, c) { + var o = t._parse(c); + + return '' + }); + + h = h.replace(/]*)>/gi, ''); + h = h.replace(/]*)>/gi, ''); + h = h.replace(/<\/(object|embed)([^>]*)>/gi, ''); + h = h.replace(/]*)>/gi, function(a, b) {return ''}); + h = h.replace(/\/ class=\"mceItemParam\"><\/span>/gi, 'class="mceItemParam">'); + + o.content = h; + }); + + ed.onSetContent.add(function() { + t._spansToImgs(ed.getBody()); + }); + + ed.onPreProcess.add(function(ed, o) { + var dom = ed.dom; + + if (o.set) { + t._spansToImgs(o.node); + + each(dom.select('IMG', o.node), function(n) { + var p; + + if (isMediaElm(n)) { + p = t._parse(n.title); + dom.setAttrib(n, 'width', dom.getAttrib(n, 'width', p.width || 100)); + dom.setAttrib(n, 'height', dom.getAttrib(n, 'height', p.height || 100)); + } + }); + } + + if (o.get) { + each(dom.select('IMG', o.node), function(n) { + var ci, cb, mt; + + if (ed.getParam('media_use_script')) { + if (isMediaElm(n)) + n.className = n.className.replace(/mceItem/g, 'mceTemp'); + + return; + } + + switch (n.className) { + case 'mceItemFlash': + ci = 'd27cdb6e-ae6d-11cf-96b8-444553540000'; + cb = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0'; + mt = 'application/x-shockwave-flash'; + break; + + case 'mceItemShockWave': + ci = '166b1bca-3f9c-11cf-8075-444553540000'; + cb = 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0'; + mt = 'application/x-director'; + break; + + case 'mceItemWindowsMedia': + ci = ed.getParam('media_wmp6_compatible') ? '05589fa1-c356-11ce-bf01-00aa0055595a' : '6bf52a52-394a-11d3-b153-00c04f79faa6'; + cb = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701'; + mt = 'application/x-mplayer2'; + break; + + case 'mceItemQuickTime': + ci = '02bf25d5-8c17-4b23-bc80-d3488abddc6b'; + cb = 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0'; + mt = 'video/quicktime'; + break; + + case 'mceItemRealMedia': + ci = 'cfcdaa03-8be4-11cf-b84b-0020afbbccfa'; + cb = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0'; + mt = 'audio/x-pn-realaudio-plugin'; + break; + } + + if (ci) { + dom.replace(t._buildObj({ + classid : ci, + codebase : cb, + type : mt + }, n), n); + } + }); + } + }); + + ed.onPostProcess.add(function(ed, o) { + o.content = o.content.replace(/_value=/g, 'value='); + }); + + if (ed.getParam('media_use_script')) { + function getAttr(s, n) { + n = new RegExp(n + '=\"([^\"]+)\"', 'g').exec(s); + + return n ? ed.dom.decode(n[1]) : ''; + }; + + ed.onPostProcess.add(function(ed, o) { + o.content = o.content.replace(/]+>/g, function(im) { + var cl = getAttr(im, 'class'); + + if (/^(mceTempFlash|mceTempShockWave|mceTempWindowsMedia|mceTempQuickTime|mceTempRealMedia)$/.test(cl)) { + at = t._parse(getAttr(im, 'title')); + at.width = getAttr(im, 'width'); + at.height = getAttr(im, 'height'); + im = ''; + } + + return im; + }); + }); + } + }, + + getInfo : function() { + return { + longname : 'Media', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private methods + + _buildObj : function(o, n) { + var ob, ed = this.editor, dom = ed.dom, p = this._parse(n.title); + + p.width = o.width = dom.getAttrib(n, 'width') || 100; + p.height = o.height = dom.getAttrib(n, 'height') || 100; + + ob = dom.create('span', { + mce_name : 'object', + classid : "clsid:" + o.classid, + codebase : o.codebase, + width : o.width, + height : o.height + }); + + if (p.src) + p.src = ed.convertURL(p.src, 'src', n); + + each (p, function(v, k) { + if (!/^(width|height|codebase|classid)$/.test(k)) { + // Use url instead of src in IE for Windows media + if (o.type == 'application/x-mplayer2' && k == 'src') + k = 'url'; + + dom.add(ob, 'span', {mce_name : 'param', name : k, '_value' : v}); + } + }); + + dom.add(ob, 'span', tinymce.extend({mce_name : 'embed', type : o.type}, p)); + + return ob; + }, + + _spansToImgs : function(p) { + var t = this, dom = t.editor.dom, im, ci; + + each(dom.select('span', p), function(n) { + // Convert object into image + if (dom.getAttrib(n, 'class') == 'mceItemObject') { + ci = dom.getAttrib(n, "classid").toLowerCase().replace(/\s+/g, ''); + + switch (ci) { + case 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000': + dom.replace(t._createImg('mceItemFlash', n), n); + break; + + case 'clsid:166b1bca-3f9c-11cf-8075-444553540000': + dom.replace(t._createImg('mceItemShockWave', n), n); + break; + + case 'clsid:6bf52a52-394a-11d3-b153-00c04f79faa6': + case 'clsid:22d6f312-b0f6-11d0-94ab-0080c74c7e95': + case 'clsid:05589fa1-c356-11ce-bf01-00aa0055595a': + dom.replace(t._createImg('mceItemWindowsMedia', n), n); + break; + + case 'clsid:02bf25d5-8c17-4b23-bc80-d3488abddc6b': + dom.replace(t._createImg('mceItemQuickTime', n), n); + break; + + case 'clsid:cfcdaa03-8be4-11cf-b84b-0020afbbccfa': + dom.replace(t._createImg('mceItemRealMedia', n), n); + break; + + default: + dom.replace(t._createImg('mceItemFlash', n), n); + } + + return; + } + + // Convert embed into image + if (dom.getAttrib(n, 'class') == 'mceItemEmbed') { + switch (dom.getAttrib(n, 'type')) { + case 'application/x-shockwave-flash': + dom.replace(t._createImg('mceItemFlash', n), n); + break; + + case 'application/x-director': + dom.replace(t._createImg('mceItemShockWave', n), n); + break; + + case 'application/x-mplayer2': + dom.replace(t._createImg('mceItemWindowsMedia', n), n); + break; + + case 'video/quicktime': + dom.replace(t._createImg('mceItemQuickTime', n), n); + break; + + case 'audio/x-pn-realaudio-plugin': + dom.replace(t._createImg('mceItemRealMedia', n), n); + break; + + default: + dom.replace(t._createImg('mceItemFlash', n), n); + } + } + }); + }, + + _createImg : function(cl, n) { + var im, dom = this.editor.dom, pa = {}, ti = ''; + + // Create image + im = dom.create('img', { + src : this.url + '/img/trans.gif', + width : dom.getAttrib(n, 'width') || 100, + height : dom.getAttrib(n, 'height') || 100, + 'class' : cl + }); + + // Setup base parameters + each(['id', 'name', 'width', 'height', 'bgcolor', 'align', 'flashvars', 'src', 'wmode'], function(na) { + var v = dom.getAttrib(n, na); + + if (v) + pa[na] = v; + }); + + // Add optional parameters + each(dom.select('span', n), function(n) { + if (dom.hasClass(n, 'mceItemParam')) + pa[dom.getAttrib(n, 'name')] = dom.getAttrib(n, '_value'); + }); + + // Use src not movie + if (pa.movie) { + pa.src = pa.movie; + delete pa.movie; + } + + delete pa.width; + delete pa.height; + + im.title = this._serialize(pa); + + return im; + }, + + _parse : function(s) { + return tinymce.util.JSON.parse('{' + s + '}'); + }, + + _serialize : function(o) { + return tinymce.util.JSON.serialize(o).replace(/[{}]/g, ''); + } + }); + + // Register plugin + tinymce.PluginManager.add('media', tinymce.plugins.MediaPlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/media/img/flash.gif b/web/js/tiny_mce/plugins/media/img/flash.gif new file mode 100644 index 0000000..cb192e6 Binary files /dev/null and b/web/js/tiny_mce/plugins/media/img/flash.gif differ diff --git a/web/js/tiny_mce/plugins/media/img/flv_player.swf b/web/js/tiny_mce/plugins/media/img/flv_player.swf new file mode 100644 index 0000000..042c2ab Binary files /dev/null and b/web/js/tiny_mce/plugins/media/img/flv_player.swf differ diff --git a/web/js/tiny_mce/plugins/media/img/quicktime.gif b/web/js/tiny_mce/plugins/media/img/quicktime.gif new file mode 100644 index 0000000..3b04991 Binary files /dev/null and b/web/js/tiny_mce/plugins/media/img/quicktime.gif differ diff --git a/web/js/tiny_mce/plugins/media/img/realmedia.gif b/web/js/tiny_mce/plugins/media/img/realmedia.gif new file mode 100644 index 0000000..fdfe0b9 Binary files /dev/null and b/web/js/tiny_mce/plugins/media/img/realmedia.gif differ diff --git a/web/js/tiny_mce/plugins/media/img/shockwave.gif b/web/js/tiny_mce/plugins/media/img/shockwave.gif new file mode 100644 index 0000000..5f235df Binary files /dev/null and b/web/js/tiny_mce/plugins/media/img/shockwave.gif differ diff --git a/web/js/tiny_mce/plugins/media/img/trans.gif b/web/js/tiny_mce/plugins/media/img/trans.gif new file mode 100644 index 0000000..3884865 Binary files /dev/null and b/web/js/tiny_mce/plugins/media/img/trans.gif differ diff --git a/web/js/tiny_mce/plugins/media/img/windowsmedia.gif b/web/js/tiny_mce/plugins/media/img/windowsmedia.gif new file mode 100644 index 0000000..ab50f2d Binary files /dev/null and b/web/js/tiny_mce/plugins/media/img/windowsmedia.gif differ diff --git a/web/js/tiny_mce/plugins/media/js/embed.js b/web/js/tiny_mce/plugins/media/js/embed.js new file mode 100644 index 0000000..f8dc810 --- /dev/null +++ b/web/js/tiny_mce/plugins/media/js/embed.js @@ -0,0 +1,73 @@ +/** + * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose. + */ + +function writeFlash(p) { + writeEmbed( + 'D27CDB6E-AE6D-11cf-96B8-444553540000', + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0', + 'application/x-shockwave-flash', + p + ); +} + +function writeShockWave(p) { + writeEmbed( + '166B1BCA-3F9C-11CF-8075-444553540000', + 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0', + 'application/x-director', + p + ); +} + +function writeQuickTime(p) { + writeEmbed( + '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B', + 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0', + 'video/quicktime', + p + ); +} + +function writeRealMedia(p) { + writeEmbed( + 'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA', + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0', + 'audio/x-pn-realaudio-plugin', + p + ); +} + +function writeWindowsMedia(p) { + p.url = p.src; + writeEmbed( + '6BF52A52-394A-11D3-B153-00C04F79FAA6', + 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701', + 'application/x-mplayer2', + p + ); +} + +function writeEmbed(cls, cb, mt, p) { + var h = '', n; + + h += ''; + + h += ''); + +function init() { + var pl = "", f, val; + var type = "flash", fe, i; + + ed = tinyMCEPopup.editor; + + tinyMCEPopup.resizeToInnerSize(); + f = document.forms[0] + + fe = ed.selection.getNode(); + if (/mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(ed.dom.getAttrib(fe, 'class'))) { + pl = fe.title; + + switch (ed.dom.getAttrib(fe, 'class')) { + case 'mceItemFlash': + type = 'flash'; + break; + + case 'mceItemFlashVideo': + type = 'flv'; + break; + + case 'mceItemShockWave': + type = 'shockwave'; + break; + + case 'mceItemWindowsMedia': + type = 'wmp'; + break; + + case 'mceItemQuickTime': + type = 'qt'; + break; + + case 'mceItemRealMedia': + type = 'rmp'; + break; + } + + document.forms[0].insert.value = ed.getLang('update', 'Insert', true); + } + + document.getElementById('filebrowsercontainer').innerHTML = getBrowserHTML('filebrowser','src','media','media'); + document.getElementById('qtsrcfilebrowsercontainer').innerHTML = getBrowserHTML('qtsrcfilebrowser','qt_qtsrc','media','media'); + document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor'); + + var html = getMediaListHTML('medialist','src','media','media'); + if (html == "") + document.getElementById("linklistrow").style.display = 'none'; + else + document.getElementById("linklistcontainer").innerHTML = html; + + // Resize some elements + if (isVisible('filebrowser')) + document.getElementById('src').style.width = '230px'; + + // Setup form + if (pl != "") { + pl = tinyMCEPopup.editor.plugins.media._parse(pl); + + switch (type) { + case "flash": + setBool(pl, 'flash', 'play'); + setBool(pl, 'flash', 'loop'); + setBool(pl, 'flash', 'menu'); + setBool(pl, 'flash', 'swliveconnect'); + setStr(pl, 'flash', 'quality'); + setStr(pl, 'flash', 'scale'); + setStr(pl, 'flash', 'salign'); + setStr(pl, 'flash', 'wmode'); + setStr(pl, 'flash', 'base'); + setStr(pl, 'flash', 'flashvars'); + break; + + case "qt": + setBool(pl, 'qt', 'loop'); + setBool(pl, 'qt', 'autoplay'); + setBool(pl, 'qt', 'cache'); + setBool(pl, 'qt', 'controller'); + setBool(pl, 'qt', 'correction'); + setBool(pl, 'qt', 'enablejavascript'); + setBool(pl, 'qt', 'kioskmode'); + setBool(pl, 'qt', 'autohref'); + setBool(pl, 'qt', 'playeveryframe'); + setBool(pl, 'qt', 'tarsetcache'); + setStr(pl, 'qt', 'scale'); + setStr(pl, 'qt', 'starttime'); + setStr(pl, 'qt', 'endtime'); + setStr(pl, 'qt', 'tarset'); + setStr(pl, 'qt', 'qtsrcchokespeed'); + setStr(pl, 'qt', 'volume'); + setStr(pl, 'qt', 'qtsrc'); + break; + + case "shockwave": + setBool(pl, 'shockwave', 'sound'); + setBool(pl, 'shockwave', 'progress'); + setBool(pl, 'shockwave', 'autostart'); + setBool(pl, 'shockwave', 'swliveconnect'); + setStr(pl, 'shockwave', 'swvolume'); + setStr(pl, 'shockwave', 'swstretchstyle'); + setStr(pl, 'shockwave', 'swstretchhalign'); + setStr(pl, 'shockwave', 'swstretchvalign'); + break; + + case "wmp": + setBool(pl, 'wmp', 'autostart'); + setBool(pl, 'wmp', 'enabled'); + setBool(pl, 'wmp', 'enablecontextmenu'); + setBool(pl, 'wmp', 'fullscreen'); + setBool(pl, 'wmp', 'invokeurls'); + setBool(pl, 'wmp', 'mute'); + setBool(pl, 'wmp', 'stretchtofit'); + setBool(pl, 'wmp', 'windowlessvideo'); + setStr(pl, 'wmp', 'balance'); + setStr(pl, 'wmp', 'baseurl'); + setStr(pl, 'wmp', 'captioningid'); + setStr(pl, 'wmp', 'currentmarker'); + setStr(pl, 'wmp', 'currentposition'); + setStr(pl, 'wmp', 'defaultframe'); + setStr(pl, 'wmp', 'playcount'); + setStr(pl, 'wmp', 'rate'); + setStr(pl, 'wmp', 'uimode'); + setStr(pl, 'wmp', 'volume'); + break; + + case "rmp": + setBool(pl, 'rmp', 'autostart'); + setBool(pl, 'rmp', 'loop'); + setBool(pl, 'rmp', 'autogotourl'); + setBool(pl, 'rmp', 'center'); + setBool(pl, 'rmp', 'imagestatus'); + setBool(pl, 'rmp', 'maintainaspect'); + setBool(pl, 'rmp', 'nojava'); + setBool(pl, 'rmp', 'prefetch'); + setBool(pl, 'rmp', 'shuffle'); + setStr(pl, 'rmp', 'console'); + setStr(pl, 'rmp', 'controls'); + setStr(pl, 'rmp', 'numloop'); + setStr(pl, 'rmp', 'scriptcallbacks'); + break; + } + + setStr(pl, null, 'src'); + setStr(pl, null, 'id'); + setStr(pl, null, 'name'); + setStr(pl, null, 'vspace'); + setStr(pl, null, 'hspace'); + setStr(pl, null, 'bgcolor'); + setStr(pl, null, 'align'); + setStr(pl, null, 'width'); + setStr(pl, null, 'height'); + + if ((val = ed.dom.getAttrib(fe, "width")) != "") + pl.width = f.width.value = val; + + if ((val = ed.dom.getAttrib(fe, "height")) != "") + pl.height = f.height.value = val; + + oldWidth = pl.width ? parseInt(pl.width) : 0; + oldHeight = pl.height ? parseInt(pl.height) : 0; + } else + oldWidth = oldHeight = 0; + + selectByValue(f, 'media_type', type); + changedType(type); + updateColor('bgcolor_pick', 'bgcolor'); + + TinyMCE_EditableSelects.init(); + generatePreview(); +} + +function insertMedia() { + var fe, f = document.forms[0], h; + + tinyMCEPopup.restoreSelection(); + + if (!AutoValidator.validate(f)) { + alert(ed.getLang('invalid_data')); + return false; + } + + f.width.value = f.width.value == "" ? 100 : f.width.value; + f.height.value = f.height.value == "" ? 100 : f.height.value; + + fe = ed.selection.getNode(); + if (fe != null && /mceItem(Flash|ShockWave|WindowsMedia|QuickTime|RealMedia)/.test(ed.dom.getAttrib(fe, 'class'))) { + switch (f.media_type.options[f.media_type.selectedIndex].value) { + case "flash": + fe.className = "mceItemFlash"; + break; + + case "flv": + fe.className = "mceItemFlashVideo"; + break; + + case "shockwave": + fe.className = "mceItemShockWave"; + break; + + case "qt": + fe.className = "mceItemQuickTime"; + break; + + case "wmp": + fe.className = "mceItemWindowsMedia"; + break; + + case "rmp": + fe.className = "mceItemRealMedia"; + break; + } + + if (fe.width != f.width.value || fe.height != f.height.height) + ed.execCommand('mceRepaint'); + + fe.title = serializeParameters(); + fe.width = f.width.value; + fe.height = f.height.value; + fe.style.width = f.width.value + (f.width.value.indexOf('%') == -1 ? 'px' : ''); + fe.style.height = f.height.value + (f.height.value.indexOf('%') == -1 ? 'px' : ''); + fe.align = f.align.options[f.align.selectedIndex].value; + } else { + h = ' 0) { + var html = ""; + + html += ''; + + return html; + } + + return ""; +} + +function getType(v) { + var fo, i, c, el, x, f = document.forms[0]; + + fo = ed.getParam("media_types", "flash=swf;flv=flv;shockwave=dcr;qt=mov,qt,mpg,mp3,mp4,mpeg;shockwave=dcr;wmp=avi,wmv,wm,asf,asx,wmx,wvx;rmp=rm,ra,ram").split(';'); + + // YouTube + if (v.match(/watch\?v=(.+)(.*)/)) { + f.width.value = '425'; + f.height.value = '350'; + f.src.value = 'http://www.youtube.com/v/' + v.match(/v=(.*)(.*)/)[0].split('=')[1]; + return 'flash'; + } + + // Google video + if (v.indexOf('http://video.google.com/videoplay?docid=') == 0) { + f.width.value = '425'; + f.height.value = '326'; + f.src.value = 'http://video.google.com/googleplayer.swf?docId=' + v.substring('http://video.google.com/videoplay?docid='.length) + '&hl=en'; + return 'flash'; + } + + for (i=0; i 0 ? s.substring(0, s.length - 1) : s; + + return s; +} + +function setBool(pl, p, n) { + if (typeof(pl[n]) == "undefined") + return; + + document.forms[0].elements[p + "_" + n].checked = pl[n]; +} + +function setStr(pl, p, n) { + var f = document.forms[0], e = f.elements[(p != null ? p + "_" : '') + n]; + + if (typeof(pl[n]) == "undefined") + return; + + if (e.type == "text") + e.value = pl[n]; + else + selectByValue(f, (p != null ? p + "_" : '') + n, pl[n]); +} + +function getBool(p, n, d, tv, fv) { + var v = document.forms[0].elements[p + "_" + n].checked; + + tv = typeof(tv) == 'undefined' ? 'true' : "'" + jsEncode(tv) + "'"; + fv = typeof(fv) == 'undefined' ? 'false' : "'" + jsEncode(fv) + "'"; + + return (v == d) ? '' : n + (v ? ':' + tv + ',' : ':' + fv + ','); +} + +function getStr(p, n, d) { + var e = document.forms[0].elements[(p != null ? p + "_" : "") + n]; + var v = e.type == "text" ? e.value : e.options[e.selectedIndex].value; + + if (n == 'src') + v = tinyMCEPopup.editor.convertURL(v, 'src', null); + + return ((n == d || v == '') ? '' : n + ":'" + jsEncode(v) + "',"); +} + +function getInt(p, n, d) { + var e = document.forms[0].elements[(p != null ? p + "_" : "") + n]; + var v = e.type == "text" ? e.value : e.options[e.selectedIndex].value; + + return ((n == d || v == '') ? '' : n + ":" + v.replace(/[^0-9]+/g, '') + ","); +} + +function jsEncode(s) { + s = s.replace(new RegExp('\\\\', 'g'), '\\\\'); + s = s.replace(new RegExp('"', 'g'), '\\"'); + s = s.replace(new RegExp("'", 'g'), "\\'"); + + return s; +} + +function generatePreview(c) { + var f = document.forms[0], p = document.getElementById('prev'), h = '', cls, pl, n, type, codebase, wp, hp, nw, nh; + + p.innerHTML = ''; + + nw = parseInt(f.width.value); + nh = parseInt(f.height.value); + + if (f.width.value != "" && f.height.value != "") { + if (f.constrain.checked) { + if (c == 'width' && oldWidth != 0) { + wp = nw / oldWidth; + nh = Math.round(wp * nh); + f.height.value = nh; + } else if (c == 'height' && oldHeight != 0) { + hp = nh / oldHeight; + nw = Math.round(hp * nw); + f.width.value = nw; + } + } + } + + if (f.width.value != "") + oldWidth = nw; + + if (f.height.value != "") + oldHeight = nh; + + // After constrain + pl = serializeParameters(); + + switch (f.media_type.options[f.media_type.selectedIndex].value) { + case "flash": + cls = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; + codebase = 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0'; + type = 'application/x-shockwave-flash'; + break; + + case "shockwave": + cls = 'clsid:166B1BCA-3F9C-11CF-8075-444553540000'; + codebase = 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0'; + type = 'application/x-director'; + break; + + case "qt": + cls = 'clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B'; + codebase = 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0'; + type = 'video/quicktime'; + break; + + case "wmp": + cls = ed.getParam('media_wmp6_compatible') ? 'clsid:05589FA1-C356-11CE-BF01-00AA0055595A' : 'clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6'; + codebase = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701'; + type = 'application/x-mplayer2'; + break; + + case "rmp": + cls = 'clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA'; + codebase = 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701'; + type = 'audio/x-pn-realaudio-plugin'; + break; + } + + if (pl == '') { + p.innerHTML = ''; + return; + } + + pl = tinyMCEPopup.editor.plugins.media._parse(pl); + + if (!pl.src) { + p.innerHTML = ''; + return; + } + + pl.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(pl.src); + pl.width = !pl.width ? 100 : pl.width; + pl.height = !pl.height ? 100 : pl.height; + pl.id = !pl.id ? 'obj' : pl.id; + pl.name = !pl.name ? 'eobj' : pl.name; + pl.align = !pl.align ? '' : pl.align; + + h += ''; + + for (n in pl) { + h += ''; + + // Add extra url parameter if it's an absolute URL + if (n == 'src' && pl[n].indexOf('://') != -1) + h += ''; + } + + h += ' + + + {#media_dlg.title} + + + + + + + + + + +
    + + +
    +
    +
    + {#media_dlg.general} + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + +
     
    +
     
    + + + + + + +
    x   
    +
    +
    + +
    + {#media_dlg.preview} + +
    +
    + +
    +
    + {#media_dlg.advanced} + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + +
     
    +
    +
    + +
    + {#media_dlg.flash_options} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + + + + + + + +
    +
    + +
    + {#media_dlg.flv_options} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    +
    + +
    + {#media_dlg.qt_options} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    +  
    + + + + + +
     
    +
    +
    + +
    + {#media_dlg.wmp_options} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    +
    + +
    + {#media_dlg.rmp_options} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    +   +
    +
    + +
    + {#media_dlg.shockwave_options} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    + + + + + +
    +
    +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/nonbreaking/editor_plugin.js b/web/js/tiny_mce/plugins/nonbreaking/editor_plugin.js new file mode 100644 index 0000000..4fce503 --- /dev/null +++ b/web/js/tiny_mce/plugins/nonbreaking/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.Nonbreaking',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mceNonBreaking',function(){ed.execCommand('mceInsertContent',false,(ed.plugins.visualchars&&ed.plugins.visualchars.state)?'·':' ');});ed.addButton('nonbreaking',{title:'nonbreaking.nonbreaking_desc',cmd:'mceNonBreaking'});if(ed.getParam('nonbreaking_force_tab')){ed.onKeyDown.add(function(ed,e){if(tinymce.isIE&&e.keyCode==9){ed.execCommand('mceNonBreaking');ed.execCommand('mceNonBreaking');ed.execCommand('mceNonBreaking');tinymce.dom.Event.cancel(e);}});}},getInfo:function(){return{longname:'Nonbreaking space',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/nonbreaking',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('nonbreaking',tinymce.plugins.Nonbreaking);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/nonbreaking/editor_plugin_src.js b/web/js/tiny_mce/plugins/nonbreaking/editor_plugin_src.js new file mode 100644 index 0000000..b723756 --- /dev/null +++ b/web/js/tiny_mce/plugins/nonbreaking/editor_plugin_src.js @@ -0,0 +1,50 @@ +/** + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.Nonbreaking', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + + // Register commands + ed.addCommand('mceNonBreaking', function() { + ed.execCommand('mceInsertContent', false, (ed.plugins.visualchars && ed.plugins.visualchars.state) ? '·' : ' '); + }); + + // Register buttons + ed.addButton('nonbreaking', {title : 'nonbreaking.nonbreaking_desc', cmd : 'mceNonBreaking'}); + + if (ed.getParam('nonbreaking_force_tab')) { + ed.onKeyDown.add(function(ed, e) { + if (tinymce.isIE && e.keyCode == 9) { + ed.execCommand('mceNonBreaking'); + ed.execCommand('mceNonBreaking'); + ed.execCommand('mceNonBreaking'); + tinymce.dom.Event.cancel(e); + } + }); + } + }, + + getInfo : function() { + return { + longname : 'Nonbreaking space', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/nonbreaking', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + + // Private methods + }); + + // Register plugin + tinymce.PluginManager.add('nonbreaking', tinymce.plugins.Nonbreaking); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/noneditable/editor_plugin.js b/web/js/tiny_mce/plugins/noneditable/editor_plugin.js new file mode 100644 index 0000000..8a1b8f0 --- /dev/null +++ b/web/js/tiny_mce/plugins/noneditable/editor_plugin.js @@ -0,0 +1 @@ +(function(){var Event=tinymce.dom.Event;tinymce.create('tinymce.plugins.NonEditablePlugin',{init:function(ed,url){var t=this,editClass,nonEditClass;t.editor=ed;editClass=ed.getParam("noneditable_editable_class","mceEditable");nonEditClass=ed.getParam("noneditable_noneditable_class","mceNonEditable");ed.onNodeChange.addToTop(function(ed,cm,n){var sc,ec;sc=ed.dom.getParent(ed.selection.getStart(),function(n){return ed.dom.hasClass(n,nonEditClass);});ec=ed.dom.getParent(ed.selection.getEnd(),function(n){return ed.dom.hasClass(n,nonEditClass);});if(sc||ec){t._setDisabled(1);return false;}else t._setDisabled(0);});},getInfo:function(){return{longname:'Non editable elements',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/noneditable',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_block:function(ed,e){var k=e.keyCode;if((k>32&&k<41)||(k>111&&k<124))return;return Event.cancel(e);},_setDisabled:function(s){var t=this,ed=t.editor;tinymce.each(ed.controlManager.controls,function(c){c.setDisabled(s);});if(s!==t.disabled){if(s){ed.onKeyDown.addToTop(t._block);ed.onKeyPress.addToTop(t._block);ed.onKeyUp.addToTop(t._block);ed.onPaste.addToTop(t._block);}else{ed.onKeyDown.remove(t._block);ed.onKeyPress.remove(t._block);ed.onKeyUp.remove(t._block);ed.onPaste.remove(t._block);}t.disabled=s;}}});tinymce.PluginManager.add('noneditable',tinymce.plugins.NonEditablePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/noneditable/editor_plugin_src.js b/web/js/tiny_mce/plugins/noneditable/editor_plugin_src.js new file mode 100644 index 0000000..77db577 --- /dev/null +++ b/web/js/tiny_mce/plugins/noneditable/editor_plugin_src.js @@ -0,0 +1,87 @@ +/** + * $Id: editor_plugin_src.js 743 2008-03-23 17:47:33Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + var Event = tinymce.dom.Event; + + tinymce.create('tinymce.plugins.NonEditablePlugin', { + init : function(ed, url) { + var t = this, editClass, nonEditClass; + + t.editor = ed; + editClass = ed.getParam("noneditable_editable_class", "mceEditable"); + nonEditClass = ed.getParam("noneditable_noneditable_class", "mceNonEditable"); + + ed.onNodeChange.addToTop(function(ed, cm, n) { + var sc, ec; + + // Block if start or end is inside a non editable element + sc = ed.dom.getParent(ed.selection.getStart(), function(n) { + return ed.dom.hasClass(n, nonEditClass); + }); + + ec = ed.dom.getParent(ed.selection.getEnd(), function(n) { + return ed.dom.hasClass(n, nonEditClass); + }); + + // Block or unblock + if (sc || ec) { + t._setDisabled(1); + return false; + } else + t._setDisabled(0); + }); + }, + + getInfo : function() { + return { + longname : 'Non editable elements', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/noneditable', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + _block : function(ed, e) { + var k = e.keyCode; + + // Don't block arrow keys, pg up/down, and F1-F12 + if ((k > 32 && k < 41) || (k > 111 && k < 124)) + return; + + return Event.cancel(e); + }, + + _setDisabled : function(s) { + var t = this, ed = t.editor; + + tinymce.each(ed.controlManager.controls, function(c) { + c.setDisabled(s); + }); + + if (s !== t.disabled) { + if (s) { + ed.onKeyDown.addToTop(t._block); + ed.onKeyPress.addToTop(t._block); + ed.onKeyUp.addToTop(t._block); + ed.onPaste.addToTop(t._block); + } else { + ed.onKeyDown.remove(t._block); + ed.onKeyPress.remove(t._block); + ed.onKeyUp.remove(t._block); + ed.onPaste.remove(t._block); + } + + t.disabled = s; + } + } + }); + + // Register plugin + tinymce.PluginManager.add('noneditable', tinymce.plugins.NonEditablePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/pagebreak/css/content.css b/web/js/tiny_mce/plugins/pagebreak/css/content.css new file mode 100644 index 0000000..c949d58 --- /dev/null +++ b/web/js/tiny_mce/plugins/pagebreak/css/content.css @@ -0,0 +1 @@ +.mcePageBreak {display:block;border:0;width:100%;height:12px;border-top:1px dotted #ccc;margin-top:15px;background:#fff url(../img/pagebreak.gif) no-repeat center top;} diff --git a/web/js/tiny_mce/plugins/pagebreak/editor_plugin.js b/web/js/tiny_mce/plugins/pagebreak/editor_plugin.js new file mode 100644 index 0000000..177ea95 --- /dev/null +++ b/web/js/tiny_mce/plugins/pagebreak/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.PageBreakPlugin',{init:function(ed,url){var pb='',cls='mcePageBreak',sep=ed.getParam('pagebreak_separator',''),pbRE;pbRE=new RegExp(sep.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(a){return'\\'+a;}),'g');ed.addCommand('mcePageBreak',function(){ed.execCommand('mceInsertContent',0,pb);});ed.addButton('pagebreak',{title:'pagebreak.desc',cmd:cls});ed.onInit.add(function(){if(ed.settings.content_css!==false)ed.dom.loadCSS(url+"/css/content.css");if(ed.theme.onResolveName){ed.theme.onResolveName.add(function(th,o){if(o.node.nodeName=='IMG'&&ed.dom.hasClass(o.node,cls))o.name='pagebreak';});}});ed.onClick.add(function(ed,e){e=e.target;if(e.nodeName==='IMG'&&ed.dom.hasClass(e,cls))ed.selection.select(e);});ed.onNodeChange.add(function(ed,cm,n){cm.setActive('pagebreak',n.nodeName==='IMG'&&ed.dom.hasClass(n,cls));});ed.onBeforeSetContent.add(function(ed,o){o.content=o.content.replace(pbRE,pb);});ed.onPostProcess.add(function(ed,o){if(o.get)o.content=o.content.replace(/]+>/g,function(im){if(im.indexOf('class="mcePageBreak')!==-1)im=sep;return im;});});},getInfo:function(){return{longname:'PageBreak',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/pagebreak',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('pagebreak',tinymce.plugins.PageBreakPlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/pagebreak/editor_plugin_src.js b/web/js/tiny_mce/plugins/pagebreak/editor_plugin_src.js new file mode 100644 index 0000000..16f5748 --- /dev/null +++ b/web/js/tiny_mce/plugins/pagebreak/editor_plugin_src.js @@ -0,0 +1,74 @@ +/** + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.PageBreakPlugin', { + init : function(ed, url) { + var pb = '', cls = 'mcePageBreak', sep = ed.getParam('pagebreak_separator', ''), pbRE; + + pbRE = new RegExp(sep.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g, function(a) {return '\\' + a;}), 'g'); + + // Register commands + ed.addCommand('mcePageBreak', function() { + ed.execCommand('mceInsertContent', 0, pb); + }); + + // Register buttons + ed.addButton('pagebreak', {title : 'pagebreak.desc', cmd : cls}); + + ed.onInit.add(function() { + if (ed.settings.content_css !== false) + ed.dom.loadCSS(url + "/css/content.css"); + + if (ed.theme.onResolveName) { + ed.theme.onResolveName.add(function(th, o) { + if (o.node.nodeName == 'IMG' && ed.dom.hasClass(o.node, cls)) + o.name = 'pagebreak'; + }); + } + }); + + ed.onClick.add(function(ed, e) { + e = e.target; + + if (e.nodeName === 'IMG' && ed.dom.hasClass(e, cls)) + ed.selection.select(e); + }); + + ed.onNodeChange.add(function(ed, cm, n) { + cm.setActive('pagebreak', n.nodeName === 'IMG' && ed.dom.hasClass(n, cls)); + }); + + ed.onBeforeSetContent.add(function(ed, o) { + o.content = o.content.replace(pbRE, pb); + }); + + ed.onPostProcess.add(function(ed, o) { + if (o.get) + o.content = o.content.replace(/]+>/g, function(im) { + if (im.indexOf('class="mcePageBreak') !== -1) + im = sep; + + return im; + }); + }); + }, + + getInfo : function() { + return { + longname : 'PageBreak', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/pagebreak', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('pagebreak', tinymce.plugins.PageBreakPlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/pagebreak/img/pagebreak.gif b/web/js/tiny_mce/plugins/pagebreak/img/pagebreak.gif new file mode 100644 index 0000000..acdf408 Binary files /dev/null and b/web/js/tiny_mce/plugins/pagebreak/img/pagebreak.gif differ diff --git a/web/js/tiny_mce/plugins/pagebreak/img/trans.gif b/web/js/tiny_mce/plugins/pagebreak/img/trans.gif new file mode 100644 index 0000000..3884865 Binary files /dev/null and b/web/js/tiny_mce/plugins/pagebreak/img/trans.gif differ diff --git a/web/js/tiny_mce/plugins/paste/blank.htm b/web/js/tiny_mce/plugins/paste/blank.htm new file mode 100644 index 0000000..fcf3217 --- /dev/null +++ b/web/js/tiny_mce/plugins/paste/blank.htm @@ -0,0 +1,22 @@ + + +blank_page + + + + + + + + + diff --git a/web/js/tiny_mce/plugins/paste/css/blank.css b/web/js/tiny_mce/plugins/paste/css/blank.css new file mode 100644 index 0000000..6b16bac --- /dev/null +++ b/web/js/tiny_mce/plugins/paste/css/blank.css @@ -0,0 +1,14 @@ +html, body {height:98%} +body { +background-color: #FFFFFF; +font-family: Verdana, Arial, Helvetica, sans-serif; +font-size: 10px; +scrollbar-3dlight-color: #F0F0EE; +scrollbar-arrow-color: #676662; +scrollbar-base-color: #F0F0EE; +scrollbar-darkshadow-color: #DDDDDD; +scrollbar-face-color: #E0E0DD; +scrollbar-highlight-color: #F0F0EE; +scrollbar-shadow-color: #F0F0EE; +scrollbar-track-color: #F5F5F5; +} diff --git a/web/js/tiny_mce/plugins/paste/css/pasteword.css b/web/js/tiny_mce/plugins/paste/css/pasteword.css new file mode 100644 index 0000000..b3be627 --- /dev/null +++ b/web/js/tiny_mce/plugins/paste/css/pasteword.css @@ -0,0 +1,3 @@ +.sourceIframe { + border: 1px solid #808080; +} diff --git a/web/js/tiny_mce/plugins/paste/editor_plugin.js b/web/js/tiny_mce/plugins/paste/editor_plugin.js new file mode 100644 index 0000000..02bb4ac --- /dev/null +++ b/web/js/tiny_mce/plugins/paste/editor_plugin.js @@ -0,0 +1 @@ +(function(){var Event=tinymce.dom.Event;tinymce.create('tinymce.plugins.PastePlugin',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mcePasteText',function(ui,v){if(ui){if((ed.getParam('paste_use_dialog',true))||(!tinymce.isIE)){ed.windowManager.open({file:url+'/pastetext.htm',width:450,height:400,inline:1},{plugin_url:url})}else t._insertText(clipboardData.getData("Text"),true)}else t._insertText(v.html,v.linebreaks)});ed.addCommand('mcePasteWord',function(ui,v){if(ui){if((ed.getParam('paste_use_dialog',true))||(!tinymce.isIE)){ed.windowManager.open({file:url+'/pasteword.htm',width:450,height:400,inline:1},{plugin_url:url})}else t._insertText(t._clipboardHTML())}else t._insertWordContent(v)});ed.addCommand('mceSelectAll',function(){ed.execCommand('selectall')});ed.addButton('pastetext',{title:'paste.paste_text_desc',cmd:'mcePasteText',ui:true});ed.addButton('pasteword',{title:'paste.paste_word_desc',cmd:'mcePasteWord',ui:true});ed.addButton('selectall',{title:'paste.selectall_desc',cmd:'mceSelectAll'});if(ed.getParam("paste_auto_cleanup_on_paste",false)){ed.onPaste.add(function(ed,e){return t._handlePasteEvent(e)})}if(ed.getParam("paste_auto_cleanup_on_paste",false)){ed.onKeyDown.add(function(ed,e){if(e.ctrlKey&&e.keyCode==86){window.setTimeout(function(){ed.execCommand("mcePasteText",true)},1);Event.cancel(e)}})}},getInfo:function(){return{longname:'Paste text/word',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste',version:tinymce.majorVersion+"."+tinymce.minorVersion}},_handlePasteEvent:function(e){var html=this._clipboardHTML(),ed=this.editor,sel=ed.selection,r;if(ed&&(r=sel.getRng())&&r.text.length>0)ed.execCommand('delete');if(html&&html.length>0)ed.execCommand('mcePasteWord',false,html);return Event.cancel(e)},_insertText:function(content,bLinebreaks){if(content&&content.length>0){if(bLinebreaks){if(this.editor.getParam("paste_create_paragraphs",true)){var rl=this.editor.getParam("paste_replace_list",'\u2122,TM,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');for(var i=0;i

    ');content=content.replace(/\r\r/g,'

    ');content=content.replace(/\n\n/g,'

    ');if((pos=content.indexOf('

    '))!=-1){this.editor.execCommand("Delete");var node=this.editor.selection.getNode();var breakElms=[];do{if(node.nodeType==1){if(node.nodeName=="TD"||node.nodeName=="BODY")break;breakElms[breakElms.length]=node}}while(node=node.parentNode);var before="",after="

    ";before+=content.substring(0,pos);for(var i=0;i";after+="<"+breakElms[(breakElms.length-1)-i].nodeName+">"}before+="

    ";content=before+content.substring(pos+7)+after}}if(this.editor.getParam("paste_create_linebreaks",true)){content=content.replace(/\r\n/g,'
    ');content=content.replace(/\r/g,'
    ');content=content.replace(/\n/g,'
    ')}}this.editor.execCommand("mceInsertRawHTML",false,content)}},_insertWordContent:function(content){var t=this,ed=t.editor;if(content&&content.length>0){var bull=String.fromCharCode(8226);var middot=String.fromCharCode(183);if(ed.getParam('paste_insert_word_content_callback'))content=ed.execCallback('paste_insert_word_content_callback','before',content);var rl=ed.getParam("paste_replace_list",'\u2122,TM,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(',');for(var i=0;i(.*?)<\/p>','gi'),'

    $1

    ')}content=content.replace(new RegExp('tab-stops: list [0-9]+.0pt">','gi'),'">'+"--list--");content=content.replace(new RegExp(bull+"(.*?)
    ","gi"),"

    "+middot+"$1

    ");content=content.replace(new RegExp('','gi'),""+bull);content=content.replace(/<\/o:p>/gi,"");content=content.replace(new RegExp('
    ]*>/gi,"");if(this.editor.getParam("paste_remove_styles",true))content=content.replace(new RegExp('<(\\w[^>]*) style="([^"]*)"([^>]*)','gi'),"<$1$3");content=content.replace(/<\/?font[^>]*>/gi,"");switch(this.editor.getParam("paste_strip_class_attributes","all")){case"all":content=content.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi,"<$1$3");break;case"mso":content=content.replace(new RegExp('<(\\w[^>]*) class="?mso([^ |>]*)([^>]*)','gi'),"<$1$3");break}content=content.replace(new RegExp('href="?'+this._reEscape(""+document.location)+'','gi'),'href="'+this.editor.documentBaseURI.getURI());content=content.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi,"<$1$3");content=content.replace(/<\\?\?xml[^>]*>/gi,"");content=content.replace(/<\/?\w+:[^>]*>/gi,"");content=content.replace(/-- page break --\s*

     <\/p>/gi,"");content=content.replace(/-- page break --/gi,"");if(!this.editor.getParam('force_p_newlines')){content=content.replace('','','gi');content=content.replace('

    ','

    ','gi')}if(!tinymce.isIE&&!this.editor.getParam('force_p_newlines')){content=content.replace(/<\/?p[^>]*>/gi,"")}content=content.replace(/<\/?div[^>]*>/gi,"");if(this.editor.getParam("paste_convert_middot_lists",true)){var div=ed.dom.create("div",null,content);var className=this.editor.getParam("paste_unindented_list_class","unIndentedList");while(this._convertMiddots(div,"--list--"));while(this._convertMiddots(div,middot,className));while(this._convertMiddots(div,bull));content=div.innerHTML}if(this.editor.getParam("paste_convert_headers_to_strong",false)){content=content.replace(/ <\/h[1-6]>/gi,'

      

    ');content=content.replace(//gi,'

    ');content=content.replace(/<\/h[1-6]>/gi,'

    ');content=content.replace(/ <\/b>/gi,'  ');content=content.replace(/^( )*/gi,'')}content=content.replace(/--list--/gi,"");if(ed.getParam('paste_insert_word_content_callback'))content=ed.execCallback('paste_insert_word_content_callback','after',content);this.editor.execCommand("mceInsertContent",false,content);if(this.editor.getParam('paste_force_cleanup_wordpaste',true)){var ed=this.editor;window.setTimeout(function(){ed.execCommand("mceCleanup")},1)}}},_reEscape:function(s){var l="?.\\*[](){}+^$:";var o="";for(var i=0;i 0) + ed.execCommand('delete'); + + if (html && html.length > 0) + ed.execCommand('mcePasteWord', false, html); + + return Event.cancel(e); + }, + + _insertText : function(content, bLinebreaks) { + if (content && content.length > 0) { + if (bLinebreaks) { + // Special paragraph treatment + if (this.editor.getParam("paste_create_paragraphs", true)) { + var rl = this.editor.getParam("paste_replace_list", '\u2122,TM,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(','); + for (var i=0; i

    '); + content = content.replace(/\r\r/g, '

    '); + content = content.replace(/\n\n/g, '

    '); + + // Has paragraphs + if ((pos = content.indexOf('

    ')) != -1) { + this.editor.execCommand("Delete"); + + var node = this.editor.selection.getNode(); + + // Get list of elements to break + var breakElms = []; + + do { + if (node.nodeType == 1) { + // Don't break tables and break at body + if (node.nodeName == "TD" || node.nodeName == "BODY") + break; + + breakElms[breakElms.length] = node; + } + } while(node = node.parentNode); + + var before = "", after = "

    "; + before += content.substring(0, pos); + + for (var i=0; i"; + after += "<" + breakElms[(breakElms.length-1)-i].nodeName + ">"; + } + + before += "

    "; + content = before + content.substring(pos+7) + after; + } + } + + if (this.editor.getParam("paste_create_linebreaks", true)) { + content = content.replace(/\r\n/g, '
    '); + content = content.replace(/\r/g, '
    '); + content = content.replace(/\n/g, '
    '); + } + } + + this.editor.execCommand("mceInsertRawHTML", false, content); + } + }, + + _insertWordContent : function(content) { + var t = this, ed = t.editor; + + if (content && content.length > 0) { + // Cleanup Word content + var bull = String.fromCharCode(8226); + var middot = String.fromCharCode(183); + + if (ed.getParam('paste_insert_word_content_callback')) + content = ed.execCallback('paste_insert_word_content_callback', 'before', content); + + var rl = ed.getParam("paste_replace_list", '\u2122,TM,\u2026,...,\u201c|\u201d,",\u2019,\',\u2013|\u2014|\u2015|\u2212,-').split(','); + for (var i=0; i(.*?)<\/p>', 'gi'), '

    $1

    '); + } + + content = content.replace(new RegExp('tab-stops: list [0-9]+.0pt">', 'gi'), '">' + "--list--"); + content = content.replace(new RegExp(bull + "(.*?)
    ", "gi"), "

    " + middot + "$1

    "); + content = content.replace(new RegExp('', 'gi'), "" + bull); // Covert to bull list + content = content.replace(/<\/o:p>/gi, ""); + content = content.replace(new RegExp('
    ]*>/gi, ""); + + if (this.editor.getParam("paste_remove_styles", true)) + content = content.replace(new RegExp('<(\\w[^>]*) style="([^"]*)"([^>]*)', 'gi'), "<$1$3"); + + content = content.replace(/<\/?font[^>]*>/gi, ""); + + // Strips class attributes. + switch (this.editor.getParam("paste_strip_class_attributes", "all")) { + case "all": + content = content.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3"); + break; + + case "mso": + content = content.replace(new RegExp('<(\\w[^>]*) class="?mso([^ |>]*)([^>]*)', 'gi'), "<$1$3"); + break; + } + + content = content.replace(new RegExp('href="?' + this._reEscape("" + document.location) + '', 'gi'), 'href="' + this.editor.documentBaseURI.getURI()); + content = content.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3"); + content = content.replace(/<\\?\?xml[^>]*>/gi, ""); + content = content.replace(/<\/?\w+:[^>]*>/gi, ""); + content = content.replace(/-- page break --\s*

     <\/p>/gi, ""); // Remove pagebreaks + content = content.replace(/-- page break --/gi, ""); // Remove pagebreaks + + // content = content.replace(/\/? */gi, "");   + // content = content.replace(/

     <\/p>/gi, ''); + + if (!this.editor.getParam('force_p_newlines')) { + content = content.replace('', '' ,'gi'); + content = content.replace('

    ', '

    ' ,'gi'); + } + + if (!tinymce.isIE && !this.editor.getParam('force_p_newlines')) { + content = content.replace(/<\/?p[^>]*>/gi, ""); + } + + content = content.replace(/<\/?div[^>]*>/gi, ""); + + // Convert all middlot lists to UL lists + if (this.editor.getParam("paste_convert_middot_lists", true)) { + var div = ed.dom.create("div", null, content); + + // Convert all middot paragraphs to li elements + var className = this.editor.getParam("paste_unindented_list_class", "unIndentedList"); + + while (this._convertMiddots(div, "--list--")) ; // bull + while (this._convertMiddots(div, middot, className)) ; // Middot + while (this._convertMiddots(div, bull)) ; // bull + + content = div.innerHTML; + } + + // Replace all headers with strong and fix some other issues + if (this.editor.getParam("paste_convert_headers_to_strong", false)) { + content = content.replace(/ <\/h[1-6]>/gi, '

      

    '); + content = content.replace(//gi, '

    '); + content = content.replace(/<\/h[1-6]>/gi, '

    '); + content = content.replace(/ <\/b>/gi, '  '); + content = content.replace(/^( )*/gi, ''); + } + + content = content.replace(/--list--/gi, ""); // Remove --list-- + + if (ed.getParam('paste_insert_word_content_callback')) + content = ed.execCallback('paste_insert_word_content_callback', 'after', content); + + // Insert cleaned content + this.editor.execCommand("mceInsertContent", false, content); + + if (this.editor.getParam('paste_force_cleanup_wordpaste', true)) { + var ed = this.editor; + + window.setTimeout(function() { + ed.execCommand("mceCleanup"); + }, 1); // Do normal cleanup detached from this thread + } + } + }, + + _reEscape : function(s) { + var l = "?.\\*[](){}+^$:"; + var o = ""; + + for (var i=0; i + + {#paste.paste_text_desc} + + + + + + +
    +
    {#paste.paste_text_desc}
    + +
    + +
    + +
    + +
    {#paste_dlg.text_title}
    + + + +
    +
    + +
    + +
    + +
    +
    +
    + + \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/paste/pasteword.htm b/web/js/tiny_mce/plugins/paste/pasteword.htm new file mode 100644 index 0000000..365f25d --- /dev/null +++ b/web/js/tiny_mce/plugins/paste/pasteword.htm @@ -0,0 +1,29 @@ + + + + {#paste.paste_word_desc} + + + + + + +
    +
    {#paste.paste_word_desc}
    + +
    {#paste_dlg.word_title}
    + +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/preview/editor_plugin.js b/web/js/tiny_mce/plugins/preview/editor_plugin.js new file mode 100644 index 0000000..766ebf8 --- /dev/null +++ b/web/js/tiny_mce/plugins/preview/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.Preview',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mcePreview',t._preview,t);ed.addButton('preview',{title:'preview.preview_desc',cmd:'mcePreview'});},getInfo:function(){return{longname:'Preview',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/preview',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_preview:function(){var ed=this.editor,win,html,c,pos,pos2,css,i,page=ed.getParam("plugin_preview_pageurl",null),w=ed.getParam("plugin_preview_width","550"),h=ed.getParam("plugin_preview_height","600");if(page){ed.windowManager.open({file:ed.getParam("plugin_preview_pageurl",null),width:w,height:h},{resizable:"yes",scrollbars:"yes",inline:1});}else{win=window.open("","mcePreview","menubar=no,toolbar=no,scrollbars=yes,resizable=yes,left=20,top=20,width="+w+",height="+h);html="";c=ed.getContent();pos=c.indexOf('',pos);pos2=c.lastIndexOf('');c=c.substring(pos+1,pos2);}html+=ed.getParam('doctype');html+='';html+='';html+=''+ed.getLang('preview.preview_desc')+'';html+='';html+='';for(i=0;i';html+='';html+='';html+=c;html+='';html+='';win.document.write(html);win.document.close();}},_onLoad:function(w,d){var t=this,nl,i,el=[],sv,ne;t._doc=d;w.writeFlash=t._writeFlash;w.writeShockWave=t._writeShockWave;w.writeQuickTime=t._writeQuickTime;w.writeRealMedia=t._writeRealMedia;w.writeWindowsMedia=t._writeWindowsMedia;w.writeEmbed=t._writeEmbed;nl=d.getElementsByTagName("script");for(i=0;i';for(n in p)h+='';h+='', pos); + pos2 = c.lastIndexOf(''); + c = c.substring(pos + 1, pos2); + } + + html += ed.getParam('doctype'); + html += ''; + html += ''; + html += '' + ed.getLang('preview.preview_desc') + ''; + html += ''; + html += ''; + + for (i=0; i'; + + html += ''; + html += ''; + html += c; + html += ''; + html += ''; + + win.document.write(html); + win.document.close(); + } + }, + + _onLoad : function(w, d) { + var t = this, nl, i, el = [], sv, ne; + + t._doc = d; + w.writeFlash = t._writeFlash; + w.writeShockWave = t._writeShockWave; + w.writeQuickTime = t._writeQuickTime; + w.writeRealMedia = t._writeRealMedia; + w.writeWindowsMedia = t._writeWindowsMedia; + w.writeEmbed = t._writeEmbed; + + nl = d.getElementsByTagName("script"); + for (i=0; i'; + + h += ' + + + + +Example of a custom preview page + + + +Editor contents:
    +
    + +
    + + + diff --git a/web/js/tiny_mce/plugins/preview/jscripts/embed.js b/web/js/tiny_mce/plugins/preview/jscripts/embed.js new file mode 100644 index 0000000..f8dc810 --- /dev/null +++ b/web/js/tiny_mce/plugins/preview/jscripts/embed.js @@ -0,0 +1,73 @@ +/** + * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose. + */ + +function writeFlash(p) { + writeEmbed( + 'D27CDB6E-AE6D-11cf-96B8-444553540000', + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0', + 'application/x-shockwave-flash', + p + ); +} + +function writeShockWave(p) { + writeEmbed( + '166B1BCA-3F9C-11CF-8075-444553540000', + 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0', + 'application/x-director', + p + ); +} + +function writeQuickTime(p) { + writeEmbed( + '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B', + 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0', + 'video/quicktime', + p + ); +} + +function writeRealMedia(p) { + writeEmbed( + 'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA', + 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0', + 'audio/x-pn-realaudio-plugin', + p + ); +} + +function writeWindowsMedia(p) { + p.url = p.src; + writeEmbed( + '6BF52A52-394A-11D3-B153-00C04F79FAA6', + 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701', + 'application/x-mplayer2', + p + ); +} + +function writeEmbed(cls, cb, mt, p) { + var h = '', n; + + h += ''; + + h += ' \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/safari/editor_plugin.js b/web/js/tiny_mce/plugins/safari/editor_plugin.js new file mode 100644 index 0000000..f722c2f --- /dev/null +++ b/web/js/tiny_mce/plugins/safari/editor_plugin.js @@ -0,0 +1 @@ +(function(){var Event=tinymce.dom.Event,grep=tinymce.grep,each=tinymce.each,inArray=tinymce.inArray,isOldWebKit=tinymce.isOldWebKit;tinymce.create('tinymce.plugins.Safari',{init:function(ed){var t=this,dom;if(!tinymce.isWebKit)return;t.editor=ed;t.webKitFontSizes=['x-small','small','medium','large','x-large','xx-large','-webkit-xxx-large'];t.namedFontSizes=['xx-small','x-small','small','medium','large','x-large','xx-large'];ed.onPaste.add(function(ed,e){function removeStyles(e){e=e.target;if(e.nodeType==1){e.style.cssText='';each(ed.dom.select('*',e),function(e){e.style.cssText='';});}};Event.add(ed.getDoc(),'DOMNodeInserted',removeStyles);window.setTimeout(function(){Event.remove(ed.getDoc(),'DOMNodeInserted',removeStyles);},0);});ed.onKeyUp.add(function(ed,e){var h,b;if(e.keyCode==46||e.keyCode==8){b=ed.getBody();h=b.innerHTML;if(b.childNodes.length==1&&!/<(img|hr)/.test(h)&&tinymce.trim(h.replace(/<[^>]+>/g,'')).length==0)ed.setContent('',{format:'raw'});}});ed.addCommand('FormatBlock',function(u,v){var dom=ed.dom,e=dom.getParent(ed.selection.getNode(),dom.isBlock);if(e)dom.replace(dom.create(v),e,1);else ed.getDoc().execCommand("FormatBlock",false,v);});ed.addCommand('mceInsertContent',function(u,v){ed.getDoc().execCommand("InsertText",false,'mce_marker');ed.getBody().innerHTML=ed.getBody().innerHTML.replace(/mce_marker/g,v+'XX');ed.selection.select(ed.dom.get('_mce_tmp'));ed.getDoc().execCommand("Delete",false,' ');});ed.onKeyPress.add(function(ed,e){if(e.keyCode==13&&(e.shiftKey||ed.settings.force_br_newlines&&ed.selection.getNode().nodeName!='LI')){t._insertBR(ed);Event.cancel(e);}});ed.addQueryValueHandler('FontSize',function(u,v){var e,v;if((e=ed.dom.getParent(ed.selection.getStart(),'span'))&&(v=e.style.fontSize))return tinymce.inArray(t.namedFontSizes,v)+1;if((e=ed.dom.getParent(ed.selection.getEnd(),'span'))&&(v=e.style.fontSize))return tinymce.inArray(t.namedFontSizes,v)+1;return ed.getDoc().queryCommandValue('FontSize');});ed.addQueryValueHandler('FontName',function(u,v){var e,v;if((e=ed.dom.getParent(ed.selection.getStart(),'span'))&&(v=e.style.fontFamily))return v.replace(/, /g,',');if((e=ed.dom.getParent(ed.selection.getEnd(),'span'))&&(v=e.style.fontFamily))return v.replace(/, /g,',');return ed.getDoc().queryCommandValue('FontName');});ed.onClick.add(function(ed,e){e=e.target;if(e.nodeName=='IMG'){t.selElm=e;ed.selection.select(e);}else t.selElm=null;});ed.onInit.add(function(){t._fixWebKitSpans();if(isOldWebKit)t._patchSafari2x(ed);});ed.onSetContent.add(function(){dom=ed.dom;each(['strong','b','em','u','strike','sub','sup','a'],function(v){each(grep(dom.select(v)).reverse(),function(n){var nn=n.nodeName.toLowerCase(),st;if(nn=='a'){if(n.name)dom.replace(dom.create('img',{mce_name:'a',name:n.name,'class':'mceItemAnchor'}),n);return;}switch(nn){case'b':case'strong':if(nn=='b')nn='strong';st='font-weight: bold;';break;case'em':st='font-style: italic;';break;case'u':st='text-decoration: underline;';break;case'sub':st='vertical-align: sub;';break;case'sup':st='vertical-align: super;';break;case'strike':st='text-decoration: line-through;';break;}dom.replace(dom.create('span',{mce_name:nn,style:st,'class':'Apple-style-span'}),n,1);});});});ed.onPreProcess.add(function(ed,o){dom=ed.dom;each(grep(o.node.getElementsByTagName('span')).reverse(),function(n){var v,bg;if(o.get){if(dom.hasClass(n,'Apple-style-span')){bg=n.style.backgroundColor;switch(dom.getAttrib(n,'mce_name')){case'font':if(!ed.settings.convert_fonts_to_spans)dom.setAttrib(n,'style','');break;case'strong':case'em':case'sub':case'sup':dom.setAttrib(n,'style','');break;case'strike':case'u':if(!ed.settings.inline_styles)dom.setAttrib(n,'style','');else dom.setAttrib(n,'mce_name','');break;default:if(!ed.settings.inline_styles)dom.setAttrib(n,'style','');}if(bg)n.style.backgroundColor=bg;}}if(dom.hasClass(n,'mceItemRemoved'))dom.remove(n,1);});});ed.onPostProcess.add(function(ed,o){o.content=o.content.replace(/
    <\/(h[1-6]|div|p|address|pre)>/g,'');o.content=o.content.replace(/ id=\"undefined\"/g,'');});},getInfo:function(){return{longname:'Safari compatibility',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/safari',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_fixWebKitSpans:function(){var t=this,ed=t.editor;if(!isOldWebKit){Event.add(ed.getDoc(),'DOMNodeInserted',function(e){e=e.target;if(e&&e.nodeType==1)t._fixAppleSpan(e);});}else{ed.onExecCommand.add(function(){each(ed.dom.select('span'),function(n){t._fixAppleSpan(n);});ed.nodeChanged();});}},_fixAppleSpan:function(e){var ed=this.editor,dom=ed.dom,fz=this.webKitFontSizes,fzn=this.namedFontSizes,s=ed.settings,st,p;if(dom.getAttrib(e,'mce_fixed'))return;if(e.nodeName=='SPAN'&&e.className=='Apple-style-span'){st=e.style;if(!s.convert_fonts_to_spans){if(st.fontSize){dom.setAttrib(e,'mce_name','font');dom.setAttrib(e,'size',inArray(fz,st.fontSize)+1);}if(st.fontFamily){dom.setAttrib(e,'mce_name','font');dom.setAttrib(e,'face',st.fontFamily);}if(st.color){dom.setAttrib(e,'mce_name','font');dom.setAttrib(e,'color',dom.toHex(st.color));}if(st.backgroundColor){dom.setAttrib(e,'mce_name','font');dom.setStyle(e,'background-color',st.backgroundColor);}}else{if(st.fontSize)dom.setStyle(e,'fontSize',fzn[inArray(fz,st.fontSize)]);}if(st.fontWeight=='bold')dom.setAttrib(e,'mce_name','strong');if(st.fontStyle=='italic')dom.setAttrib(e,'mce_name','em');if(st.textDecoration=='underline')dom.setAttrib(e,'mce_name','u');if(st.textDecoration=='line-through')dom.setAttrib(e,'mce_name','strike');if(st.verticalAlign=='super')dom.setAttrib(e,'mce_name','sup');if(st.verticalAlign=='sub')dom.setAttrib(e,'mce_name','sub');dom.setAttrib(e,'mce_fixed','1');}},_patchSafari2x:function(ed){var t=this,setContent,getNode,dom=ed.dom,lr;if(ed.windowManager.onBeforeOpen){ed.windowManager.onBeforeOpen.add(function(){r=ed.selection.getRng();});}ed.selection.select=function(n){this.getSel().setBaseAndExtent(n,0,n,1);};getNode=ed.selection.getNode;ed.selection.getNode=function(){return t.selElm||getNode.call(this);};ed.selection.getRng=function(){var t=this,s=t.getSel(),d=ed.getDoc(),r,rb,ra,di;if(s.anchorNode){r=d.createRange();try{rb=d.createRange();rb.setStart(s.anchorNode,s.anchorOffset);rb.collapse(1);ra=d.createRange();ra.setStart(s.focusNode,s.focusOffset);ra.collapse(1);di=rb.compareBoundaryPoints(rb.START_TO_END,ra)<0;r.setStart(di?s.anchorNode:s.focusNode,di?s.anchorOffset:s.focusOffset);r.setEnd(di?s.focusNode:s.anchorNode,di?s.focusOffset:s.anchorOffset);lr=r;}catch(ex){}}return r||lr;};setContent=ed.selection.setContent;ed.selection.setContent=function(h,s){var r=this.getRng(),b;try{setContent.call(this,h,s);}catch(ex){b=dom.create('body');b.innerHTML=h;each(b.childNodes,function(n){r.insertNode(n.cloneNode(true));});}};},_insertBR:function(ed){var dom=ed.dom,s=ed.selection,r=s.getRng(),br;r.insertNode(br=dom.create('br'));r.setStartAfter(br);r.setEndAfter(br);s.setRng(r);if(s.getSel().focusNode==br.previousSibling){s.select(dom.insertAfter(dom.doc.createTextNode('\u00a0'),br));s.collapse(1);}ed.getWin().scrollTo(0,dom.getPos(s.getRng().startContainer).y);}});tinymce.PluginManager.add('safari',tinymce.plugins.Safari);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/safari/editor_plugin_src.js b/web/js/tiny_mce/plugins/safari/editor_plugin_src.js new file mode 100644 index 0000000..c820353 --- /dev/null +++ b/web/js/tiny_mce/plugins/safari/editor_plugin_src.js @@ -0,0 +1,460 @@ +/** + * $Id: editor_plugin_src.js 264 2007-04-26 20:53:09Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + var Event = tinymce.dom.Event, grep = tinymce.grep, each = tinymce.each, inArray = tinymce.inArray, isOldWebKit = tinymce.isOldWebKit; + + tinymce.create('tinymce.plugins.Safari', { + init : function(ed) { + var t = this, dom; + + // Ignore on non webkit + if (!tinymce.isWebKit) + return; + + t.editor = ed; + t.webKitFontSizes = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', '-webkit-xxx-large']; + t.namedFontSizes = ['xx-small', 'x-small','small','medium','large','x-large', 'xx-large']; + + // Safari will crash if the build in createlink command is used +/* ed.addCommand('CreateLink', function(u, v) { + ed.execCommand("mceInsertContent", false, '' + ed.selection.getContent() + ''); + });*/ + + ed.onPaste.add(function(ed, e) { + function removeStyles(e) { + e = e.target; + + if (e.nodeType == 1) { + e.style.cssText = ''; + + each(ed.dom.select('*', e), function(e) { + e.style.cssText = ''; + }); + } + }; + + Event.add(ed.getDoc(), 'DOMNodeInserted', removeStyles); + + window.setTimeout(function() { + Event.remove(ed.getDoc(), 'DOMNodeInserted', removeStyles); + }, 0); + }); + + ed.onKeyUp.add(function(ed, e) { + var h, b; + + // If backspace or delete key + if (e.keyCode == 46 || e.keyCode == 8) { + b = ed.getBody(); + h = b.innerHTML; + + // If there is no text content or images or hr elements then remove everything + if (b.childNodes.length == 1 && !/<(img|hr)/.test(h) && tinymce.trim(h.replace(/<[^>]+>/g, '')).length == 0) + ed.setContent('', {format : 'raw'}); + } + }); + + // Workaround for FormatBlock bug, http://bugs.webkit.org/show_bug.cgi?id=16004 + ed.addCommand('FormatBlock', function(u, v) { + var dom = ed.dom, e = dom.getParent(ed.selection.getNode(), dom.isBlock); + + if (e) + dom.replace(dom.create(v), e, 1); + else + ed.getDoc().execCommand("FormatBlock", false, v); + }); + + // Workaround for InsertHTML bug, http://bugs.webkit.org/show_bug.cgi?id=16382 + ed.addCommand('mceInsertContent', function(u, v) { + ed.getDoc().execCommand("InsertText", false, 'mce_marker'); + ed.getBody().innerHTML = ed.getBody().innerHTML.replace(/mce_marker/g, v + 'XX'); + ed.selection.select(ed.dom.get('_mce_tmp')); + ed.getDoc().execCommand("Delete", false, ' '); + }); + + // Workaround for missing shift+enter support, http://bugs.webkit.org/show_bug.cgi?id=16973 + ed.onKeyPress.add(function(ed, e) { + if (e.keyCode == 13 && (e.shiftKey || ed.settings.force_br_newlines && ed.selection.getNode().nodeName != 'LI')) { + t._insertBR(ed); + Event.cancel(e); + } + }); + + // Safari returns incorrect values + ed.addQueryValueHandler('FontSize', function(u, v) { + var e, v; + + // Check for the real font size at the start of selection + if ((e = ed.dom.getParent(ed.selection.getStart(), 'span')) && (v = e.style.fontSize)) + return tinymce.inArray(t.namedFontSizes, v) + 1; + + // Check for the real font size at the end of selection + if ((e = ed.dom.getParent(ed.selection.getEnd(), 'span')) && (v = e.style.fontSize)) + return tinymce.inArray(t.namedFontSizes, v) + 1; + + // Return default value it's better than nothing right! + return ed.getDoc().queryCommandValue('FontSize'); + }); + + // Safari returns incorrect values + ed.addQueryValueHandler('FontName', function(u, v) { + var e, v; + + // Check for the real font name at the start of selection + if ((e = ed.dom.getParent(ed.selection.getStart(), 'span')) && (v = e.style.fontFamily)) + return v.replace(/, /g, ','); + + // Check for the real font name at the end of selection + if ((e = ed.dom.getParent(ed.selection.getEnd(), 'span')) && (v = e.style.fontFamily)) + return v.replace(/, /g, ','); + + // Return default value it's better than nothing right! + return ed.getDoc().queryCommandValue('FontName'); + }); + + // Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250 + ed.onClick.add(function(ed, e) { + e = e.target; + + if (e.nodeName == 'IMG') { + t.selElm = e; + ed.selection.select(e); + } else + t.selElm = null; + }); + +/* ed.onBeforeExecCommand.add(function(ed, c, b) { + var r = t.bookmarkRng; + + // Restore selection + if (r) { + ed.selection.setRng(r); + t.bookmarkRng = null; + //console.debug('restore', r.startContainer, r.startOffset, r.endContainer, r.endOffset); + } + });*/ + + ed.onInit.add(function() { + t._fixWebKitSpans(); + +/* ed.windowManager.onOpen.add(function() { + var r = ed.selection.getRng(); + + // Store selection if valid + if (r.startContainer != ed.getDoc()) { + t.bookmarkRng = r.cloneRange(); + //console.debug('store', r.startContainer, r.startOffset, r.endContainer, r.endOffset); + } + }); + + ed.windowManager.onClose.add(function() { + t.bookmarkRng = null; + });*/ + + if (isOldWebKit) + t._patchSafari2x(ed); + }); + + ed.onSetContent.add(function() { + dom = ed.dom; + + // Convert strong,b,em,u,strike to spans + each(['strong','b','em','u','strike','sub','sup','a'], function(v) { + each(grep(dom.select(v)).reverse(), function(n) { + var nn = n.nodeName.toLowerCase(), st; + + // Convert anchors into images + if (nn == 'a') { + if (n.name) + dom.replace(dom.create('img', {mce_name : 'a', name : n.name, 'class' : 'mceItemAnchor'}), n); + + return; + } + + switch (nn) { + case 'b': + case 'strong': + if (nn == 'b') + nn = 'strong'; + + st = 'font-weight: bold;'; + break; + + case 'em': + st = 'font-style: italic;'; + break; + + case 'u': + st = 'text-decoration: underline;'; + break; + + case 'sub': + st = 'vertical-align: sub;'; + break; + + case 'sup': + st = 'vertical-align: super;'; + break; + + case 'strike': + st = 'text-decoration: line-through;'; + break; + } + + dom.replace(dom.create('span', {mce_name : nn, style : st, 'class' : 'Apple-style-span'}), n, 1); + }); + }); + }); + + ed.onPreProcess.add(function(ed, o) { + dom = ed.dom; + + each(grep(o.node.getElementsByTagName('span')).reverse(), function(n) { + var v, bg; + + if (o.get) { + if (dom.hasClass(n, 'Apple-style-span')) { + bg = n.style.backgroundColor; + + switch (dom.getAttrib(n, 'mce_name')) { + case 'font': + if (!ed.settings.convert_fonts_to_spans) + dom.setAttrib(n, 'style', ''); + break; + + case 'strong': + case 'em': + case 'sub': + case 'sup': + dom.setAttrib(n, 'style', ''); + break; + + case 'strike': + case 'u': + if (!ed.settings.inline_styles) + dom.setAttrib(n, 'style', ''); + else + dom.setAttrib(n, 'mce_name', ''); + + break; + + default: + if (!ed.settings.inline_styles) + dom.setAttrib(n, 'style', ''); + } + + + if (bg) + n.style.backgroundColor = bg; + } + } + + if (dom.hasClass(n, 'mceItemRemoved')) + dom.remove(n, 1); + }); + }); + + ed.onPostProcess.add(function(ed, o) { + // Safari adds BR at end of all block elements + o.content = o.content.replace(/
    <\/(h[1-6]|div|p|address|pre)>/g, ''); + + // Safari adds id="undefined" to HR elements + o.content = o.content.replace(/ id=\"undefined\"/g, ''); + }); + }, + + getInfo : function() { + return { + longname : 'Safari compatibility', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/safari', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Internal methods + + _fixWebKitSpans : function() { + var t = this, ed = t.editor; + + if (!isOldWebKit) { + // Use mutator events on new WebKit + Event.add(ed.getDoc(), 'DOMNodeInserted', function(e) { + e = e.target; + + if (e && e.nodeType == 1) + t._fixAppleSpan(e); + }); + } else { + // Do post command processing in old WebKit since the browser crashes on Mutator events :( + ed.onExecCommand.add(function() { + each(ed.dom.select('span'), function(n) { + t._fixAppleSpan(n); + }); + + ed.nodeChanged(); + }); + } + }, + + _fixAppleSpan : function(e) { + var ed = this.editor, dom = ed.dom, fz = this.webKitFontSizes, fzn = this.namedFontSizes, s = ed.settings, st, p; + + if (dom.getAttrib(e, 'mce_fixed')) + return; + + // Handle Apple style spans + if (e.nodeName == 'SPAN' && e.className == 'Apple-style-span') { + st = e.style; + + if (!s.convert_fonts_to_spans) { + if (st.fontSize) { + dom.setAttrib(e, 'mce_name', 'font'); + dom.setAttrib(e, 'size', inArray(fz, st.fontSize) + 1); + } + + if (st.fontFamily) { + dom.setAttrib(e, 'mce_name', 'font'); + dom.setAttrib(e, 'face', st.fontFamily); + } + + if (st.color) { + dom.setAttrib(e, 'mce_name', 'font'); + dom.setAttrib(e, 'color', dom.toHex(st.color)); + } + + if (st.backgroundColor) { + dom.setAttrib(e, 'mce_name', 'font'); + dom.setStyle(e, 'background-color', st.backgroundColor); + } + } else { + if (st.fontSize) + dom.setStyle(e, 'fontSize', fzn[inArray(fz, st.fontSize)]); + } + + if (st.fontWeight == 'bold') + dom.setAttrib(e, 'mce_name', 'strong'); + + if (st.fontStyle == 'italic') + dom.setAttrib(e, 'mce_name', 'em'); + + if (st.textDecoration == 'underline') + dom.setAttrib(e, 'mce_name', 'u'); + + if (st.textDecoration == 'line-through') + dom.setAttrib(e, 'mce_name', 'strike'); + + if (st.verticalAlign == 'super') + dom.setAttrib(e, 'mce_name', 'sup'); + + if (st.verticalAlign == 'sub') + dom.setAttrib(e, 'mce_name', 'sub'); + + dom.setAttrib(e, 'mce_fixed', '1'); + } + }, + + _patchSafari2x : function(ed) { + var t = this, setContent, getNode, dom = ed.dom, lr; + + // Inline dialogs + if (ed.windowManager.onBeforeOpen) { + ed.windowManager.onBeforeOpen.add(function() { + r = ed.selection.getRng(); + }); + } + + // Fake select on 2.x + ed.selection.select = function(n) { + this.getSel().setBaseAndExtent(n, 0, n, 1); + }; + + getNode = ed.selection.getNode; + ed.selection.getNode = function() { + return t.selElm || getNode.call(this); + }; + + // Fake range on Safari 2.x + ed.selection.getRng = function() { + var t = this, s = t.getSel(), d = ed.getDoc(), r, rb, ra, di; + + // Fake range on Safari 2.x + if (s.anchorNode) { + r = d.createRange(); + + try { + // Setup before range + rb = d.createRange(); + rb.setStart(s.anchorNode, s.anchorOffset); + rb.collapse(1); + + // Setup after range + ra = d.createRange(); + ra.setStart(s.focusNode, s.focusOffset); + ra.collapse(1); + + // Setup start/end points by comparing locations + di = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0; + r.setStart(di ? s.anchorNode : s.focusNode, di ? s.anchorOffset : s.focusOffset); + r.setEnd(di ? s.focusNode : s.anchorNode, di ? s.focusOffset : s.anchorOffset); + + lr = r; + } catch (ex) { + // Sometimes fails, at least we tried to do it by the book. I hope Safari 2.x will go disappear soooon!!! + } + } + + return r || lr; + }; + + // Fix setContent so it works + setContent = ed.selection.setContent; + ed.selection.setContent = function(h, s) { + var r = this.getRng(), b; + + try { + setContent.call(this, h, s); + } catch (ex) { + // Workaround for Safari 2.x + b = dom.create('body'); + b.innerHTML = h; + + each(b.childNodes, function(n) { + r.insertNode(n.cloneNode(true)); + }); + } + }; + }, + + _insertBR : function(ed) { + var dom = ed.dom, s = ed.selection, r = s.getRng(), br; + + // Insert BR element + r.insertNode(br = dom.create('br')); + + // Place caret after BR + r.setStartAfter(br); + r.setEndAfter(br); + s.setRng(r); + + // Could not place caret after BR then insert an nbsp entity and move the caret + if (s.getSel().focusNode == br.previousSibling) { + s.select(dom.insertAfter(dom.doc.createTextNode('\u00a0'), br)); + s.collapse(1); + } + + // Scroll to new position, scrollIntoView can't be used due to bug: http://bugs.webkit.org/show_bug.cgi?id=16117 + ed.getWin().scrollTo(0, dom.getPos(s.getRng().startContainer).y); + } + }); + + // Register plugin + tinymce.PluginManager.add('safari', tinymce.plugins.Safari); +})(); + diff --git a/web/js/tiny_mce/plugins/save/editor_plugin.js b/web/js/tiny_mce/plugins/save/editor_plugin.js new file mode 100644 index 0000000..43af51b --- /dev/null +++ b/web/js/tiny_mce/plugins/save/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.Save',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mceSave',t._save,t);ed.addCommand('mceCancel',t._cancel,t);ed.addButton('save',{title:'save.save_desc',cmd:'mceSave'});ed.addButton('cancel',{title:'save.cancel_desc',cmd:'mceCancel'});ed.onNodeChange.add(t._nodeChange,t);ed.addShortcut('ctrl+s',ed.getLang('save.save_desc'),'mceSave');},getInfo:function(){return{longname:'Save',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_nodeChange:function(ed,cm,n){var ed=this.editor;if(ed.getParam('save_enablewhendirty')){cm.setDisabled('save',!ed.isDirty());cm.setDisabled('cancel',!ed.isDirty());}},_save:function(){var ed=this.editor,formObj,os,i,elementId;formObj=tinymce.DOM.get(ed.id).form||tinymce.DOM.getParent(ed.id,'form');if(ed.getParam("save_enablewhendirty")&&!ed.isDirty())return true;tinyMCE.triggerSave();if(os=ed.getParam("save_onsavecallback")){if(ed.execCallback('save_onsavecallback',ed)){ed.startContent=tinymce.trim(ed.getContent({format:'raw'}));ed.nodeChanged();}return;}if(formObj){ed.isNotDirty=true;if(formObj.onsubmit==null||formObj.onsubmit()!=false)formObj.submit();ed.nodeChanged();}else ed.windowManager.alert("Error: No form element found.");return true;},_cancel:function(){var ed=this.editor,os,h=tinymce.trim(ed.startContent);if(os=ed.getParam("save_oncancelcallback")){ed.execCallback('save_oncancelcallback',ed);return;}ed.setContent(h);ed.undoManager.clear();ed.nodeChanged();}});tinymce.PluginManager.add('save',tinymce.plugins.Save);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/save/editor_plugin_src.js b/web/js/tiny_mce/plugins/save/editor_plugin_src.js new file mode 100644 index 0000000..f95c65c --- /dev/null +++ b/web/js/tiny_mce/plugins/save/editor_plugin_src.js @@ -0,0 +1,100 @@ +/** + * $Id: editor_plugin_src.js 609 2008-02-18 16:19:27Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.Save', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + + // Register commands + ed.addCommand('mceSave', t._save, t); + ed.addCommand('mceCancel', t._cancel, t); + + // Register buttons + ed.addButton('save', {title : 'save.save_desc', cmd : 'mceSave'}); + ed.addButton('cancel', {title : 'save.cancel_desc', cmd : 'mceCancel'}); + + ed.onNodeChange.add(t._nodeChange, t); + ed.addShortcut('ctrl+s', ed.getLang('save.save_desc'), 'mceSave'); + }, + + getInfo : function() { + return { + longname : 'Save', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private methods + + _nodeChange : function(ed, cm, n) { + var ed = this.editor; + + if (ed.getParam('save_enablewhendirty')) { + cm.setDisabled('save', !ed.isDirty()); + cm.setDisabled('cancel', !ed.isDirty()); + } + }, + + // Private methods + + _save : function() { + var ed = this.editor, formObj, os, i, elementId; + + formObj = tinymce.DOM.get(ed.id).form || tinymce.DOM.getParent(ed.id, 'form'); + + if (ed.getParam("save_enablewhendirty") && !ed.isDirty()) + return true; + + tinyMCE.triggerSave(); + + // Use callback instead + if (os = ed.getParam("save_onsavecallback")) { + if (ed.execCallback('save_onsavecallback', ed)) { + ed.startContent = tinymce.trim(ed.getContent({format : 'raw'})); + ed.nodeChanged(); + } + + return; + } + + if (formObj) { + ed.isNotDirty = true; + + if (formObj.onsubmit == null || formObj.onsubmit() != false) + formObj.submit(); + + ed.nodeChanged(); + } else + ed.windowManager.alert("Error: No form element found."); + + return true; + }, + + _cancel : function() { + var ed = this.editor, os, h = tinymce.trim(ed.startContent); + + // Use callback instead + if (os = ed.getParam("save_oncancelcallback")) { + ed.execCallback('save_oncancelcallback', ed); + return; + } + + ed.setContent(h); + ed.undoManager.clear(); + ed.nodeChanged(); + } + }); + + // Register plugin + tinymce.PluginManager.add('save', tinymce.plugins.Save); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/searchreplace/css/searchreplace.css b/web/js/tiny_mce/plugins/searchreplace/css/searchreplace.css new file mode 100644 index 0000000..ecdf58c --- /dev/null +++ b/web/js/tiny_mce/plugins/searchreplace/css/searchreplace.css @@ -0,0 +1,6 @@ +.panel_wrapper {height:85px;} +.panel_wrapper div.current {height:85px;} + +/* IE */ +* html .panel_wrapper {height:100px;} +* html .panel_wrapper div.current {height:100px;} diff --git a/web/js/tiny_mce/plugins/searchreplace/editor_plugin.js b/web/js/tiny_mce/plugins/searchreplace/editor_plugin.js new file mode 100644 index 0000000..7fd913b --- /dev/null +++ b/web/js/tiny_mce/plugins/searchreplace/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.SearchReplacePlugin',{init:function(ed,url){function open(m){ed.windowManager.open({file:url+'/searchreplace.htm',width:420+parseInt(ed.getLang('searchreplace.delta_width',0)),height:160+parseInt(ed.getLang('searchreplace.delta_height',0)),inline:1,auto_focus:0},{mode:m,search_string:ed.selection.getContent({format:'text'}),plugin_url:url});};ed.addCommand('mceSearch',function(){open('search');});ed.addCommand('mceReplace',function(){open('replace');});ed.addButton('search',{title:'searchreplace.search_desc',cmd:'mceSearch'});ed.addButton('replace',{title:'searchreplace.replace_desc',cmd:'mceReplace'});ed.addShortcut('ctrl+f','searchreplace.search_desc','mceSearch');},getInfo:function(){return{longname:'Search/Replace',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('searchreplace',tinymce.plugins.SearchReplacePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/searchreplace/editor_plugin_src.js b/web/js/tiny_mce/plugins/searchreplace/editor_plugin_src.js new file mode 100644 index 0000000..59edc3b --- /dev/null +++ b/web/js/tiny_mce/plugins/searchreplace/editor_plugin_src.js @@ -0,0 +1,54 @@ +/** + * $Id: editor_plugin_src.js 686 2008-03-09 18:13:49Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.SearchReplacePlugin', { + init : function(ed, url) { + function open(m) { + ed.windowManager.open({ + file : url + '/searchreplace.htm', + width : 420 + parseInt(ed.getLang('searchreplace.delta_width', 0)), + height : 160 + parseInt(ed.getLang('searchreplace.delta_height', 0)), + inline : 1, + auto_focus : 0 + }, { + mode : m, + search_string : ed.selection.getContent({format : 'text'}), + plugin_url : url + }); + }; + + // Register commands + ed.addCommand('mceSearch', function() { + open('search'); + }); + + ed.addCommand('mceReplace', function() { + open('replace'); + }); + + // Register buttons + ed.addButton('search', {title : 'searchreplace.search_desc', cmd : 'mceSearch'}); + ed.addButton('replace', {title : 'searchreplace.replace_desc', cmd : 'mceReplace'}); + + ed.addShortcut('ctrl+f', 'searchreplace.search_desc', 'mceSearch'); + }, + + getInfo : function() { + return { + longname : 'Search/Replace', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('searchreplace', tinymce.plugins.SearchReplacePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/searchreplace/js/searchreplace.js b/web/js/tiny_mce/plugins/searchreplace/js/searchreplace.js new file mode 100644 index 0000000..890eb37 --- /dev/null +++ b/web/js/tiny_mce/plugins/searchreplace/js/searchreplace.js @@ -0,0 +1,117 @@ +tinyMCEPopup.requireLangPack(); + +var SearchReplaceDialog = { + init : function(ed) { + var f = document.forms[0], m = tinyMCEPopup.getWindowArg("mode"); + + this.switchMode(m); + + f[m + '_panel_searchstring'].value = tinyMCEPopup.getWindowArg("search_string"); + + // Focus input field + f[m + '_panel_searchstring'].focus(); + }, + + switchMode : function(m) { + var f, lm = this.lastMode; + + if (lm != m) { + f = document.forms[0]; + + if (lm) { + f[m + '_panel_searchstring'].value = f[lm + '_panel_searchstring'].value; + f[m + '_panel_backwardsu'].checked = f[lm + '_panel_backwardsu'].checked; + f[m + '_panel_backwardsd'].checked = f[lm + '_panel_backwardsd'].checked; + f[m + '_panel_casesensitivebox'].checked = f[lm + '_panel_casesensitivebox'].checked; + } + + mcTabs.displayTab(m + '_tab', m + '_panel'); + document.getElementById("replaceBtn").style.display = (m == "replace") ? "inline" : "none"; + document.getElementById("replaceAllBtn").style.display = (m == "replace") ? "inline" : "none"; + this.lastMode = m; + } + }, + + searchNext : function(a) { + var ed = tinyMCEPopup.editor, se = ed.selection, r = se.getRng(), f, m = this.lastMode, s, b, fl = 0, w = ed.getWin(), wm = ed.windowManager, fo = 0; + + // Get input + f = document.forms[0]; + s = f[m + '_panel_searchstring'].value; + b = f[m + '_panel_backwardsu'].checked; + ca = f[m + '_panel_casesensitivebox'].checked; + rs = f['replace_panel_replacestring'].value; + + function fix() { + // Correct Firefox graphics glitches + r = se.getRng().cloneRange(); + ed.getDoc().execCommand('SelectAll', false, null); + se.setRng(r); + }; + + function replace() { + if (tinymce.isIE) + ed.selection.getRng().duplicate().pasteHTML(rs); // Needs to be duplicated due to selection bug in IE + else + ed.getDoc().execCommand('InsertHTML', false, rs); + }; + + // IE flags + if (ca) + fl = fl | 4; + + switch (a) { + case 'all': + if (tinymce.isIE) { + while (r.findText(s, b ? -1 : 1, fl)) { + r.scrollIntoView(); + r.select(); + replace(); + fo = 1; + } + + tinyMCEPopup.storeSelection(); + } else { + while (w.find(s, ca, b, false, false, false, false)) { + replace(); + fo = 1; + } + } + + if (fo) + wm.alert(ed.getLang('searchreplace_dlg.allreplaced')); + else + wm.alert(ed.getLang('searchreplace_dlg.notfound')); + + return; + + case 'current': + replace(); + break; + } + + se.collapse(b); + r = se.getRng(); + + // Whats the point + if (!s) + return; + + if (tinymce.isIE) { + if (r.findText(s, b ? -1 : 1, fl)) { + r.scrollIntoView(); + r.select(); + } else + wm.alert(ed.getLang('searchreplace_dlg.notfound')); + + tinyMCEPopup.storeSelection(); + } else { + if (!w.find(s, ca, b, false, false, false, false)) + wm.alert(ed.getLang('searchreplace_dlg.notfound')); + else + fix(); + } + } +}; + +tinyMCEPopup.onInit.add(SearchReplaceDialog.init, SearchReplaceDialog); diff --git a/web/js/tiny_mce/plugins/searchreplace/langs/en_dlg.js b/web/js/tiny_mce/plugins/searchreplace/langs/en_dlg.js new file mode 100644 index 0000000..370959a --- /dev/null +++ b/web/js/tiny_mce/plugins/searchreplace/langs/en_dlg.js @@ -0,0 +1,16 @@ +tinyMCE.addI18n('en.searchreplace_dlg',{ +searchnext_desc:"Find again", +notfound:"The search has been completed. The search string could not be found.", +search_title:"Find", +replace_title:"Find/Replace", +allreplaced:"All occurrences of the search string were replaced.", +findwhat:"Find what", +replacewith:"Replace with", +direction:"Direction", +up:"Up", +down:"Down", +mcase:"Match case", +findnext:"Find next", +replace:"Replace", +replaceall:"Replace all" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/searchreplace/langs/nb_dlg.js b/web/js/tiny_mce/plugins/searchreplace/langs/nb_dlg.js new file mode 100644 index 0000000..670df52 --- /dev/null +++ b/web/js/tiny_mce/plugins/searchreplace/langs/nb_dlg.js @@ -0,0 +1,16 @@ +tinyMCE.addI18n('nb.searchreplace_dlg',{ +searchnext_desc:"S\u00F8k igjen", +notfound:"S\u00F8ket er avsluttet. Fant ikke s\u00F8kestrengen.", +search_title:"S\u00F8k", +replace_title:"S\u00F8k/Erstatt", +allreplaced:"Alle forekomster av s\u00F8kestrengen er erstattet.", +findwhat:"Finn hva", +replacewith:"Erstatt med", +direction:"Retning", +up:"Oppover", +down:"Nedover", +mcase:"Skill mellom store og sm\u00E5 tegn", +findnext:"Finn neste", +replace:"Erstatt", +replaceall:"Erstatt alt" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/searchreplace/langs/nn_dlg.js b/web/js/tiny_mce/plugins/searchreplace/langs/nn_dlg.js new file mode 100644 index 0000000..3bb232d --- /dev/null +++ b/web/js/tiny_mce/plugins/searchreplace/langs/nn_dlg.js @@ -0,0 +1,16 @@ +tinyMCE.addI18n('nn.searchreplace_dlg',{ +searchnext_desc:"S\u00F8k igjen", +notfound:"S\u00F8ket avslutta. Fann ikkje s\u00F8kjestrengen.", +search_title:"S\u00F8k", +replace_title:"S\u00F8k/Erstatt", +allreplaced:"Alle f\u00F8rekomstar av s\u00F8kjestrengen er erstatta.", +findwhat:"Finn kva", +replacewith:"Erstatt med", +direction:"Retning", +up:"Oppover", +down:"Nedover", +mcase:"Skill mellom store og sm\u00E5 teikn", +findnext:"Finn neste", +replace:"Erstatt", +replaceall:"Erstatt alt" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/searchreplace/searchreplace.htm b/web/js/tiny_mce/plugins/searchreplace/searchreplace.htm new file mode 100644 index 0000000..47c9e2e --- /dev/null +++ b/web/js/tiny_mce/plugins/searchreplace/searchreplace.htm @@ -0,0 +1,105 @@ + + + + {#searchreplace_dlg.replace_title} + + + + + + + + +
    + + +
    +
    + + + + + + + + + + + +
    + + + + + + + + +
    +
    + + + + + +
    +
    +
    + +
    + + + + + + + + + + + + + + + +
    + + + + + + + + +
    +
    + + + + + +
    +
    +
    + +
    + +
    +
    + + + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/spellchecker/css/content.css b/web/js/tiny_mce/plugins/spellchecker/css/content.css new file mode 100644 index 0000000..24efa02 --- /dev/null +++ b/web/js/tiny_mce/plugins/spellchecker/css/content.css @@ -0,0 +1 @@ +.mceItemHiddenSpellWord {background:url(../img/wline.gif) repeat-x bottom left; cursor:default;} diff --git a/web/js/tiny_mce/plugins/spellchecker/editor_plugin.js b/web/js/tiny_mce/plugins/spellchecker/editor_plugin.js new file mode 100644 index 0000000..9cb6799 --- /dev/null +++ b/web/js/tiny_mce/plugins/spellchecker/editor_plugin.js @@ -0,0 +1 @@ +(function(){var JSONRequest=tinymce.util.JSONRequest,each=tinymce.each,DOM=tinymce.DOM;tinymce.create('tinymce.plugins.SpellcheckerPlugin',{getInfo:function(){return{longname:'Spellchecker',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker',version:tinymce.majorVersion+"."+tinymce.minorVersion};},init:function(ed,url){var t=this,cm;t.url=url;t.editor=ed;ed.addCommand('mceSpellCheck',function(){if(!t.active){ed.setProgressState(1);t._sendRPC('checkWords',[t.selectedLang,t._getWords()],function(r){if(r.length>0){t.active=1;t._markWords(r);ed.setProgressState(0);ed.nodeChanged();}else{ed.setProgressState(0);ed.windowManager.alert('spellchecker.no_mpell');}});}else t._done();});ed.onInit.add(function(){if(ed.settings.content_css!==false)ed.dom.loadCSS(url+'/css/content.css');});ed.onClick.add(t._showMenu,t);ed.onContextMenu.add(t._showMenu,t);ed.onBeforeGetContent.add(function(){if(t.active)t._removeWords();});ed.onNodeChange.add(function(ed,cm){cm.setActive('spellchecker',t.active);});ed.onSetContent.add(function(){t._done();});ed.onBeforeGetContent.add(function(){t._done();});ed.onBeforeExecCommand.add(function(ed,cmd){if(cmd=='mceFullScreen')t._done();});t.languages={};each(ed.getParam('spellchecker_languages','+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv','hash'),function(v,k){if(k.indexOf('+')===0){k=k.substring(1);t.selectedLang=v;}t.languages[k]=v;});},createControl:function(n,cm){var t=this,c,ed=t.editor;if(n=='spellchecker'){c=cm.createSplitButton(n,{title:'spellchecker.desc',cmd:'mceSpellCheck',scope:t});c.onRenderMenu.add(function(c,m){m.add({title:'spellchecker.langs','class':'mceMenuItemTitle'}).setDisabled(1);each(t.languages,function(v,k){var o={icon:1},mi;o.onclick=function(){mi.setSelected(1);t.selectedItem.setSelected(0);t.selectedItem=mi;t.selectedLang=v;};o.title=k;mi=m.add(o);mi.setSelected(v==t.selectedLang);if(v==t.selectedLang)t.selectedItem=mi;})});return c;}},_walk:function(n,f){var d=this.editor.getDoc(),w;if(d.createTreeWalker){w=d.createTreeWalker(n,NodeFilter.SHOW_TEXT,null,false);while((n=w.nextNode())!=null)f.call(this,n);}else tinymce.walk(n,f,'childNodes');},_getSeparators:function(){var re='',i,str=this.editor.getParam('spellchecker_word_separator_chars','\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}����������������\u201d\u201c');for(i=0;i$1$2');v=v.replace(r3,'$1$2');dom.replace(dom.create('span',{'class':'mceItemHidden'},v),n);}}});se.moveToBookmark(b);},_showMenu:function(ed,e){var t=this,ed=t.editor,m=t._menu,p1,dom=ed.dom,vp=dom.getViewPort(ed.getWin());if(!m){p1=DOM.getPos(ed.getContentAreaContainer());m=ed.controlManager.createDropMenu('spellcheckermenu',{offset_x:p1.x,offset_y:p1.y,'class':'mceNoIcons'});t._menu=m;}if(dom.hasClass(e.target,'mceItemHiddenSpellWord')){m.removeAll();m.add({title:'spellchecker.wait','class':'mceMenuItemTitle'}).setDisabled(1);t._sendRPC('getSuggestions',[t.selectedLang,dom.decode(e.target.innerHTML)],function(r){m.removeAll();if(r.length>0){m.add({title:'spellchecker.sug','class':'mceMenuItemTitle'}).setDisabled(1);each(r,function(v){m.add({title:v,onclick:function(){dom.replace(ed.getDoc().createTextNode(v),e.target);t._checkDone();}});});m.addSeparator();}else m.add({title:'spellchecker.no_sug','class':'mceMenuItemTitle'}).setDisabled(1);m.add({title:'spellchecker.ignore_word',onclick:function(){dom.remove(e.target,1);t._checkDone();}});m.add({title:'spellchecker.ignore_words',onclick:function(){t._removeWords(dom.decode(e.target.innerHTML));t._checkDone();}});m.update();});ed.selection.select(e.target);p1=dom.getPos(e.target);m.showMenu(p1.x,p1.y+e.target.offsetHeight-vp.y);return tinymce.dom.Event.cancel(e);}else m.hideMenu();},_checkDone:function(){var t=this,ed=t.editor,dom=ed.dom,o;each(dom.select('span'),function(n){if(n&&dom.hasClass(n,'mceItemHiddenSpellWord')){o=true;return false;}});if(!o)t._done();},_done:function(){var t=this,la=t.active;if(t.active){t.active=0;t._removeWords();if(t._menu)t._menu.hideMenu();if(la)t.editor.nodeChanged();}},_sendRPC:function(m,p,cb){var t=this,url=t.editor.getParam("spellchecker_rpc_url","{backend}");if(url=='{backend}'){t.editor.setProgressState(0);alert('Please specify: spellchecker_rpc_url');return;}JSONRequest.sendRPC({url:url,method:m,params:p,success:cb,error:function(e,x){t.editor.setProgressState(0);t.editor.windowManager.alert(e.errstr||('Error response: '+x.responseText));}});}});tinymce.PluginManager.add('spellchecker',tinymce.plugins.SpellcheckerPlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/spellchecker/editor_plugin_src.js b/web/js/tiny_mce/plugins/spellchecker/editor_plugin_src.js new file mode 100644 index 0000000..c913c46 --- /dev/null +++ b/web/js/tiny_mce/plugins/spellchecker/editor_plugin_src.js @@ -0,0 +1,338 @@ +/** + * $Id: editor_plugin_src.js 425 2007-11-21 15:17:39Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM; + + tinymce.create('tinymce.plugins.SpellcheckerPlugin', { + getInfo : function() { + return { + longname : 'Spellchecker', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + init : function(ed, url) { + var t = this, cm; + + t.url = url; + t.editor = ed; + + // Register commands + ed.addCommand('mceSpellCheck', function() { + if (!t.active) { + ed.setProgressState(1); + t._sendRPC('checkWords', [t.selectedLang, t._getWords()], function(r) { + if (r.length > 0) { + t.active = 1; + t._markWords(r); + ed.setProgressState(0); + ed.nodeChanged(); + } else { + ed.setProgressState(0); + ed.windowManager.alert('spellchecker.no_mpell'); + } + }); + } else + t._done(); + }); + + ed.onInit.add(function() { + if (ed.settings.content_css !== false) + ed.dom.loadCSS(url + '/css/content.css'); + }); + + ed.onClick.add(t._showMenu, t); + ed.onContextMenu.add(t._showMenu, t); + ed.onBeforeGetContent.add(function() { + if (t.active) + t._removeWords(); + }); + + ed.onNodeChange.add(function(ed, cm) { + cm.setActive('spellchecker', t.active); + }); + + ed.onSetContent.add(function() { + t._done(); + }); + + ed.onBeforeGetContent.add(function() { + t._done(); + }); + + ed.onBeforeExecCommand.add(function(ed, cmd) { + if (cmd == 'mceFullScreen') + t._done(); + }); + + // Find selected language + t.languages = {}; + each(ed.getParam('spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv', 'hash'), function(v, k) { + if (k.indexOf('+') === 0) { + k = k.substring(1); + t.selectedLang = v; + } + + t.languages[k] = v; + }); + }, + + createControl : function(n, cm) { + var t = this, c, ed = t.editor; + + if (n == 'spellchecker') { + c = cm.createSplitButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t}); + + c.onRenderMenu.add(function(c, m) { + m.add({title : 'spellchecker.langs', 'class' : 'mceMenuItemTitle'}).setDisabled(1); + each(t.languages, function(v, k) { + var o = {icon : 1}, mi; + + o.onclick = function() { + mi.setSelected(1); + t.selectedItem.setSelected(0); + t.selectedItem = mi; + t.selectedLang = v; + }; + + o.title = k; + mi = m.add(o); + mi.setSelected(v == t.selectedLang); + + if (v == t.selectedLang) + t.selectedItem = mi; + }) + }); + + return c; + } + }, + + // Internal functions + + _walk : function(n, f) { + var d = this.editor.getDoc(), w; + + if (d.createTreeWalker) { + w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false); + + while ((n = w.nextNode()) != null) + f.call(this, n); + } else + tinymce.walk(n, f, 'childNodes'); + }, + + _getSeparators : function() { + var re = '', i, str = this.editor.getParam('spellchecker_word_separator_chars', '\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}\u201d\u201c'); + + // Build word separator regexp + for (i=0; i$1$2'); + v = v.replace(r3, '$1$2'); + + dom.replace(dom.create('span', {'class' : 'mceItemHidden'}, v), n); + } + } + }); + + se.moveToBookmark(b); + }, + + _showMenu : function(ed, e) { + var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin()); + + if (!m) { + p1 = DOM.getPos(ed.getContentAreaContainer()); + //p2 = DOM.getPos(ed.getContainer()); + + m = ed.controlManager.createDropMenu('spellcheckermenu', { + offset_x : p1.x, + offset_y : p1.y, + 'class' : 'mceNoIcons' + }); + + t._menu = m; + } + + if (dom.hasClass(e.target, 'mceItemHiddenSpellWord')) { + m.removeAll(); + m.add({title : 'spellchecker.wait', 'class' : 'mceMenuItemTitle'}).setDisabled(1); + + t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(e.target.innerHTML)], function(r) { + m.removeAll(); + + if (r.length > 0) { + m.add({title : 'spellchecker.sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1); + each(r, function(v) { + m.add({title : v, onclick : function() { + dom.replace(ed.getDoc().createTextNode(v), e.target); + t._checkDone(); + }}); + }); + + m.addSeparator(); + } else + m.add({title : 'spellchecker.no_sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1); + + m.add({ + title : 'spellchecker.ignore_word', + onclick : function() { + dom.remove(e.target, 1); + t._checkDone(); + } + }); + + m.add({ + title : 'spellchecker.ignore_words', + onclick : function() { + t._removeWords(dom.decode(e.target.innerHTML)); + t._checkDone(); + } + }); + + m.update(); + }); + + ed.selection.select(e.target); + p1 = dom.getPos(e.target); + m.showMenu(p1.x, p1.y + e.target.offsetHeight - vp.y); + + return tinymce.dom.Event.cancel(e); + } else + m.hideMenu(); + }, + + _checkDone : function() { + var t = this, ed = t.editor, dom = ed.dom, o; + + each(dom.select('span'), function(n) { + if (n && dom.hasClass(n, 'mceItemHiddenSpellWord')) { + o = true; + return false; + } + }); + + if (!o) + t._done(); + }, + + _done : function() { + var t = this, la = t.active; + + if (t.active) { + t.active = 0; + t._removeWords(); + + if (t._menu) + t._menu.hideMenu(); + + if (la) + t.editor.nodeChanged(); + } + }, + + _sendRPC : function(m, p, cb) { + var t = this, url = t.editor.getParam("spellchecker_rpc_url", "{backend}"); + + if (url == '{backend}') { + t.editor.setProgressState(0); + alert('Please specify: spellchecker_rpc_url'); + return; + } + + JSONRequest.sendRPC({ + url : url, + method : m, + params : p, + success : cb, + error : function(e, x) { + t.editor.setProgressState(0); + t.editor.windowManager.alert(e.errstr || ('Error response: ' + x.responseText)); + } + }); + } + }); + + // Register plugin + tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/spellchecker/img/wline.gif b/web/js/tiny_mce/plugins/spellchecker/img/wline.gif new file mode 100644 index 0000000..7d0a4db Binary files /dev/null and b/web/js/tiny_mce/plugins/spellchecker/img/wline.gif differ diff --git a/web/js/tiny_mce/plugins/style/css/props.css b/web/js/tiny_mce/plugins/style/css/props.css new file mode 100644 index 0000000..eb1f264 --- /dev/null +++ b/web/js/tiny_mce/plugins/style/css/props.css @@ -0,0 +1,13 @@ +#text_font {width:250px;} +#text_size {width:70px;} +.mceAddSelectValue {background:#DDD;} +select, #block_text_indent, #box_width, #box_height, #box_padding_top, #box_padding_right, #box_padding_bottom, #box_padding_left {width:70px;} +#box_margin_top, #box_margin_right, #box_margin_bottom, #box_margin_left, #positioning_width, #positioning_height, #positioning_zindex {width:70px;} +#positioning_placement_top, #positioning_placement_right, #positioning_placement_bottom, #positioning_placement_left {width:70px;} +#positioning_clip_top, #positioning_clip_right, #positioning_clip_bottom, #positioning_clip_left {width:70px;} +.panel_wrapper div.current {padding-top:10px;height:230px;} +.delim {border-left:1px solid gray;} +.tdelim {border-bottom:1px solid gray;} +#block_display {width:145px;} +#list_type {width:115px;} +.disabled {background:#EEE;} diff --git a/web/js/tiny_mce/plugins/style/editor_plugin.js b/web/js/tiny_mce/plugins/style/editor_plugin.js new file mode 100644 index 0000000..6ebaa91 --- /dev/null +++ b/web/js/tiny_mce/plugins/style/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.StylePlugin',{init:function(ed,url){ed.addCommand('mceStyleProps',function(){ed.windowManager.open({file:url+'/props.htm',width:480+parseInt(ed.getLang('style.delta_width',0)),height:320+parseInt(ed.getLang('style.delta_height',0)),inline:1},{plugin_url:url,style_text:ed.selection.getNode().style.cssText});});ed.addCommand('mceSetElementStyle',function(ui,v){if(e=ed.selection.getNode()){ed.dom.setAttrib(e,'style',v);ed.execCommand('mceRepaint');}});ed.onNodeChange.add(function(ed,cm,n){cm.setDisabled('styleprops',n.nodeName==='BODY');});ed.addButton('styleprops',{title:'style.desc',cmd:'mceStyleProps'});},getInfo:function(){return{longname:'Style',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('style',tinymce.plugins.StylePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/style/editor_plugin_src.js b/web/js/tiny_mce/plugins/style/editor_plugin_src.js new file mode 100644 index 0000000..6c817ce --- /dev/null +++ b/web/js/tiny_mce/plugins/style/editor_plugin_src.js @@ -0,0 +1,52 @@ +/** + * $Id: editor_plugin_src.js 787 2008-04-10 11:40:57Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.StylePlugin', { + init : function(ed, url) { + // Register commands + ed.addCommand('mceStyleProps', function() { + ed.windowManager.open({ + file : url + '/props.htm', + width : 480 + parseInt(ed.getLang('style.delta_width', 0)), + height : 320 + parseInt(ed.getLang('style.delta_height', 0)), + inline : 1 + }, { + plugin_url : url, + style_text : ed.selection.getNode().style.cssText + }); + }); + + ed.addCommand('mceSetElementStyle', function(ui, v) { + if (e = ed.selection.getNode()) { + ed.dom.setAttrib(e, 'style', v); + ed.execCommand('mceRepaint'); + } + }); + + ed.onNodeChange.add(function(ed, cm, n) { + cm.setDisabled('styleprops', n.nodeName === 'BODY'); + }); + + // Register buttons + ed.addButton('styleprops', {title : 'style.desc', cmd : 'mceStyleProps'}); + }, + + getInfo : function() { + return { + longname : 'Style', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('style', tinymce.plugins.StylePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/style/js/props.js b/web/js/tiny_mce/plugins/style/js/props.js new file mode 100644 index 0000000..cafd6b1 --- /dev/null +++ b/web/js/tiny_mce/plugins/style/js/props.js @@ -0,0 +1,641 @@ +tinyMCEPopup.requireLangPack(); + +var defaultFonts = "" + + "Arial, Helvetica, sans-serif=Arial, Helvetica, sans-serif;" + + "Times New Roman, Times, serif=Times New Roman, Times, serif;" + + "Courier New, Courier, mono=Courier New, Courier, mono;" + + "Times New Roman, Times, serif=Times New Roman, Times, serif;" + + "Georgia, Times New Roman, Times, serif=Georgia, Times New Roman, Times, serif;" + + "Verdana, Arial, Helvetica, sans-serif=Verdana, Arial, Helvetica, sans-serif;" + + "Geneva, Arial, Helvetica, sans-serif=Geneva, Arial, Helvetica, sans-serif"; + +var defaultSizes = "9;10;12;14;16;18;24;xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger"; +var defaultMeasurement = "+pixels=px;points=pt;em;in;cm;mm;picas;ems;exs;%"; +var defaultSpacingMeasurement = "pixels=px;points=pt;in;cm;mm;picas;+ems;exs;%"; +var defaultIndentMeasurement = "pixels=px;+points=pt;in;cm;mm;picas;ems;exs;%"; +var defaultWeight = "normal;bold;bolder;lighter;100;200;300;400;500;600;700;800;900"; +var defaultTextStyle = "normal;italic;oblique"; +var defaultVariant = "normal;small-caps"; +var defaultLineHeight = "normal"; +var defaultAttachment = "fixed;scroll"; +var defaultRepeat = "no-repeat;repeat;repeat-x;repeat-y"; +var defaultPosH = "left;center;right"; +var defaultPosV = "top;center;bottom"; +var defaultVAlign = "baseline;sub;super;top;text-top;middle;bottom;text-bottom"; +var defaultDisplay = "inline;block;list-item;run-in;compact;marker;table;inline-table;table-row-group;table-header-group;table-footer-group;table-row;table-column-group;table-column;table-cell;table-caption;none"; +var defaultBorderStyle = "none;solid;dashed;dotted;double;groove;ridge;inset;outset"; +var defaultBorderWidth = "thin;medium;thick"; +var defaultListType = "disc;circle;square;decimal;lower-roman;upper-roman;lower-alpha;upper-alpha;none"; + +function init() { + var ce = document.getElementById('container'), h; + + ce.style.cssText = tinyMCEPopup.getWindowArg('style_text'); + + h = getBrowserHTML('background_image_browser','background_image','image','advimage'); + document.getElementById("background_image_browser").innerHTML = h; + + document.getElementById('text_color_pickcontainer').innerHTML = getColorPickerHTML('text_color_pick','text_color'); + document.getElementById('background_color_pickcontainer').innerHTML = getColorPickerHTML('background_color_pick','background_color'); + document.getElementById('border_color_top_pickcontainer').innerHTML = getColorPickerHTML('border_color_top_pick','border_color_top'); + document.getElementById('border_color_right_pickcontainer').innerHTML = getColorPickerHTML('border_color_right_pick','border_color_right'); + document.getElementById('border_color_bottom_pickcontainer').innerHTML = getColorPickerHTML('border_color_bottom_pick','border_color_bottom'); + document.getElementById('border_color_left_pickcontainer').innerHTML = getColorPickerHTML('border_color_left_pick','border_color_left'); + + fillSelect(0, 'text_font', 'style_font', defaultFonts, ';', true); + fillSelect(0, 'text_size', 'style_font_size', defaultSizes, ';', true); + fillSelect(0, 'text_size_measurement', 'style_font_size_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'text_case', 'style_text_case', "capitalize;uppercase;lowercase", ';', true); + fillSelect(0, 'text_weight', 'style_font_weight', defaultWeight, ';', true); + fillSelect(0, 'text_style', 'style_font_style', defaultTextStyle, ';', true); + fillSelect(0, 'text_variant', 'style_font_variant', defaultVariant, ';', true); + fillSelect(0, 'text_lineheight', 'style_font_line_height', defaultLineHeight, ';', true); + fillSelect(0, 'text_lineheight_measurement', 'style_font_line_height_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'background_attachment', 'style_background_attachment', defaultAttachment, ';', true); + fillSelect(0, 'background_repeat', 'style_background_repeat', defaultRepeat, ';', true); + + fillSelect(0, 'background_hpos_measurement', 'style_background_hpos_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'background_vpos_measurement', 'style_background_vpos_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'background_hpos', 'style_background_hpos', defaultPosH, ';', true); + fillSelect(0, 'background_vpos', 'style_background_vpos', defaultPosV, ';', true); + + fillSelect(0, 'block_wordspacing', 'style_wordspacing', 'normal', ';', true); + fillSelect(0, 'block_wordspacing_measurement', 'style_wordspacing_measurement', defaultSpacingMeasurement, ';', true); + fillSelect(0, 'block_letterspacing', 'style_letterspacing', 'normal', ';', true); + fillSelect(0, 'block_letterspacing_measurement', 'style_letterspacing_measurement', defaultSpacingMeasurement, ';', true); + fillSelect(0, 'block_vertical_alignment', 'style_vertical_alignment', defaultVAlign, ';', true); + fillSelect(0, 'block_text_align', 'style_text_align', "left;right;center;justify", ';', true); + fillSelect(0, 'block_whitespace', 'style_whitespace', "normal;pre;nowrap", ';', true); + fillSelect(0, 'block_display', 'style_display', defaultDisplay, ';', true); + fillSelect(0, 'block_text_indent_measurement', 'style_text_indent_measurement', defaultIndentMeasurement, ';', true); + + fillSelect(0, 'box_width_measurement', 'style_box_width_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_height_measurement', 'style_box_height_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_float', 'style_float', 'left;right;none', ';', true); + fillSelect(0, 'box_clear', 'style_clear', 'left;right;both;none', ';', true); + fillSelect(0, 'box_padding_left_measurement', 'style_padding_left_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_padding_top_measurement', 'style_padding_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_padding_bottom_measurement', 'style_padding_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_padding_right_measurement', 'style_padding_right_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_margin_left_measurement', 'style_margin_left_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_margin_top_measurement', 'style_margin_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_margin_bottom_measurement', 'style_margin_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'box_margin_right_measurement', 'style_margin_right_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'border_style_top', 'style_border_style_top', defaultBorderStyle, ';', true); + fillSelect(0, 'border_style_right', 'style_border_style_right', defaultBorderStyle, ';', true); + fillSelect(0, 'border_style_bottom', 'style_border_style_bottom', defaultBorderStyle, ';', true); + fillSelect(0, 'border_style_left', 'style_border_style_left', defaultBorderStyle, ';', true); + + fillSelect(0, 'border_width_top', 'style_border_width_top', defaultBorderWidth, ';', true); + fillSelect(0, 'border_width_right', 'style_border_width_right', defaultBorderWidth, ';', true); + fillSelect(0, 'border_width_bottom', 'style_border_width_bottom', defaultBorderWidth, ';', true); + fillSelect(0, 'border_width_left', 'style_border_width_left', defaultBorderWidth, ';', true); + + fillSelect(0, 'border_width_top_measurement', 'style_border_width_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'border_width_right_measurement', 'style_border_width_right_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'border_width_bottom_measurement', 'style_border_width_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'border_width_left_measurement', 'style_border_width_left_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'list_type', 'style_list_type', defaultListType, ';', true); + fillSelect(0, 'list_position', 'style_list_position', "inside;outside", ';', true); + + fillSelect(0, 'positioning_type', 'style_positioning_type', "absolute;relative;static", ';', true); + fillSelect(0, 'positioning_visibility', 'style_positioning_visibility', "inherit;visible;hidden", ';', true); + + fillSelect(0, 'positioning_width_measurement', 'style_positioning_width_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_height_measurement', 'style_positioning_height_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_overflow', 'style_positioning_overflow', "visible;hidden;scroll;auto", ';', true); + + fillSelect(0, 'positioning_placement_top_measurement', 'style_positioning_placement_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_placement_right_measurement', 'style_positioning_placement_right_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_placement_bottom_measurement', 'style_positioning_placement_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_placement_left_measurement', 'style_positioning_placement_left_measurement', defaultMeasurement, ';', true); + + fillSelect(0, 'positioning_clip_top_measurement', 'style_positioning_clip_top_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_clip_right_measurement', 'style_positioning_clip_right_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_clip_bottom_measurement', 'style_positioning_clip_bottom_measurement', defaultMeasurement, ';', true); + fillSelect(0, 'positioning_clip_left_measurement', 'style_positioning_clip_left_measurement', defaultMeasurement, ';', true); + + TinyMCE_EditableSelects.init(); + setupFormData(); + showDisabledControls(); +} + +function setupFormData() { + var ce = document.getElementById('container'), f = document.forms[0], s, b, i; + + // Setup text fields + + selectByValue(f, 'text_font', ce.style.fontFamily, true, true); + selectByValue(f, 'text_size', getNum(ce.style.fontSize), true, true); + selectByValue(f, 'text_size_measurement', getMeasurement(ce.style.fontSize)); + selectByValue(f, 'text_weight', ce.style.fontWeight, true, true); + selectByValue(f, 'text_style', ce.style.fontStyle, true, true); + selectByValue(f, 'text_lineheight', getNum(ce.style.lineHeight), true, true); + selectByValue(f, 'text_lineheight_measurement', getMeasurement(ce.style.lineHeight)); + selectByValue(f, 'text_case', ce.style.textTransform, true, true); + selectByValue(f, 'text_variant', ce.style.fontVariant, true, true); + f.text_color.value = tinyMCEPopup.editor.dom.toHex(ce.style.color); + updateColor('text_color_pick', 'text_color'); + f.text_underline.checked = inStr(ce.style.textDecoration, 'underline'); + f.text_overline.checked = inStr(ce.style.textDecoration, 'overline'); + f.text_linethrough.checked = inStr(ce.style.textDecoration, 'line-through'); + f.text_blink.checked = inStr(ce.style.textDecoration, 'blink'); + + // Setup background fields + + f.background_color.value = tinyMCEPopup.editor.dom.toHex(ce.style.backgroundColor); + updateColor('background_color_pick', 'background_color'); + f.background_image.value = ce.style.backgroundImage.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1"); + selectByValue(f, 'background_repeat', ce.style.backgroundRepeat, true, true); + selectByValue(f, 'background_attachment', ce.style.backgroundAttachment, true, true); + selectByValue(f, 'background_hpos', getNum(getVal(ce.style.backgroundPosition, 0)), true, true); + selectByValue(f, 'background_hpos_measurement', getMeasurement(getVal(ce.style.backgroundPosition, 0))); + selectByValue(f, 'background_vpos', getNum(getVal(ce.style.backgroundPosition, 1)), true, true); + selectByValue(f, 'background_vpos_measurement', getMeasurement(getVal(ce.style.backgroundPosition, 1))); + + // Setup block fields + + selectByValue(f, 'block_wordspacing', getNum(ce.style.wordSpacing), true, true); + selectByValue(f, 'block_wordspacing_measurement', getMeasurement(ce.style.wordSpacing)); + selectByValue(f, 'block_letterspacing', getNum(ce.style.letterSpacing), true, true); + selectByValue(f, 'block_letterspacing_measurement', getMeasurement(ce.style.letterSpacing)); + selectByValue(f, 'block_vertical_alignment', ce.style.verticalAlign, true, true); + selectByValue(f, 'block_text_align', ce.style.textAlign, true, true); + f.block_text_indent.value = getNum(ce.style.textIndent); + selectByValue(f, 'block_text_indent_measurement', getMeasurement(ce.style.textIndent)); + selectByValue(f, 'block_whitespace', ce.style.whiteSpace, true, true); + selectByValue(f, 'block_display', ce.style.display, true, true); + + // Setup box fields + + f.box_width.value = getNum(ce.style.width); + selectByValue(f, 'box_width_measurement', getMeasurement(ce.style.width)); + + f.box_height.value = getNum(ce.style.height); + selectByValue(f, 'box_height_measurement', getMeasurement(ce.style.height)); + + if (tinymce.isGecko) + selectByValue(f, 'box_float', ce.style.cssFloat, true, true); + else + selectByValue(f, 'box_float', ce.style.styleFloat, true, true); + + selectByValue(f, 'box_clear', ce.style.clear, true, true); + + setupBox(f, ce, 'box_padding', 'padding', ''); + setupBox(f, ce, 'box_margin', 'margin', ''); + + // Setup border fields + + setupBox(f, ce, 'border_style', 'border', 'Style'); + setupBox(f, ce, 'border_width', 'border', 'Width'); + setupBox(f, ce, 'border_color', 'border', 'Color'); + + updateColor('border_color_top_pick', 'border_color_top'); + updateColor('border_color_right_pick', 'border_color_right'); + updateColor('border_color_bottom_pick', 'border_color_bottom'); + updateColor('border_color_left_pick', 'border_color_left'); + + f.elements.border_color_top.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_top.value); + f.elements.border_color_right.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_right.value); + f.elements.border_color_bottom.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_bottom.value); + f.elements.border_color_left.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_left.value); + + // Setup list fields + + selectByValue(f, 'list_type', ce.style.listStyleType, true, true); + selectByValue(f, 'list_position', ce.style.listStylePosition, true, true); + f.list_bullet_image.value = ce.style.listStyleImage.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1"); + + // Setup box fields + + selectByValue(f, 'positioning_type', ce.style.position, true, true); + selectByValue(f, 'positioning_visibility', ce.style.visibility, true, true); + selectByValue(f, 'positioning_overflow', ce.style.overflow, true, true); + f.positioning_zindex.value = ce.style.zIndex ? ce.style.zIndex : ""; + + f.positioning_width.value = getNum(ce.style.width); + selectByValue(f, 'positioning_width_measurement', getMeasurement(ce.style.width)); + + f.positioning_height.value = getNum(ce.style.height); + selectByValue(f, 'positioning_height_measurement', getMeasurement(ce.style.height)); + + setupBox(f, ce, 'positioning_placement', '', '', ['top', 'right', 'bottom', 'left']); + + s = ce.style.clip.replace(new RegExp("rect\\('?([^']*)'?\\)", 'gi'), "$1"); + s = s.replace(/,/g, ' '); + + if (!hasEqualValues([getVal(s, 0), getVal(s, 1), getVal(s, 2), getVal(s, 3)])) { + f.positioning_clip_top.value = getNum(getVal(s, 0)); + selectByValue(f, 'positioning_clip_top_measurement', getMeasurement(getVal(s, 0))); + f.positioning_clip_right.value = getNum(getVal(s, 1)); + selectByValue(f, 'positioning_clip_right_measurement', getMeasurement(getVal(s, 1))); + f.positioning_clip_bottom.value = getNum(getVal(s, 2)); + selectByValue(f, 'positioning_clip_bottom_measurement', getMeasurement(getVal(s, 2))); + f.positioning_clip_left.value = getNum(getVal(s, 3)); + selectByValue(f, 'positioning_clip_left_measurement', getMeasurement(getVal(s, 3))); + } else { + f.positioning_clip_top.value = getNum(getVal(s, 0)); + selectByValue(f, 'positioning_clip_top_measurement', getMeasurement(getVal(s, 0))); + f.positioning_clip_right.value = f.positioning_clip_bottom.value = f.positioning_clip_left.value; + } + +// setupBox(f, ce, '', 'border', 'Color'); +} + +function getMeasurement(s) { + return s.replace(/^([0-9]+)(.*)$/, "$2"); +} + +function getNum(s) { + if (new RegExp('^[0-9]+[a-z%]+$', 'gi').test(s)) + return s.replace(/[^0-9]/g, ''); + + return s; +} + +function inStr(s, n) { + return new RegExp(n, 'gi').test(s); +} + +function getVal(s, i) { + var a = s.split(' '); + + if (a.length > 1) + return a[i]; + + return ""; +} + +function setValue(f, n, v) { + if (f.elements[n].type == "text") + f.elements[n].value = v; + else + selectByValue(f, n, v, true, true); +} + +function setupBox(f, ce, fp, pr, sf, b) { + if (typeof(b) == "undefined") + b = ['Top', 'Right', 'Bottom', 'Left']; + + if (isSame(ce, pr, sf, b)) { + f.elements[fp + "_same"].checked = true; + + setValue(f, fp + "_top", getNum(ce.style[pr + b[0] + sf])); + f.elements[fp + "_top"].disabled = false; + + f.elements[fp + "_right"].value = ""; + f.elements[fp + "_right"].disabled = true; + f.elements[fp + "_bottom"].value = ""; + f.elements[fp + "_bottom"].disabled = true; + f.elements[fp + "_left"].value = ""; + f.elements[fp + "_left"].disabled = true; + + if (f.elements[fp + "_top_measurement"]) { + selectByValue(f, fp + '_top_measurement', getMeasurement(ce.style[pr + b[0] + sf])); + f.elements[fp + "_left_measurement"].disabled = true; + f.elements[fp + "_bottom_measurement"].disabled = true; + f.elements[fp + "_right_measurement"].disabled = true; + } + } else { + f.elements[fp + "_same"].checked = false; + + setValue(f, fp + "_top", getNum(ce.style[pr + b[0] + sf])); + f.elements[fp + "_top"].disabled = false; + + setValue(f, fp + "_right", getNum(ce.style[pr + b[1] + sf])); + f.elements[fp + "_right"].disabled = false; + + setValue(f, fp + "_bottom", getNum(ce.style[pr + b[2] + sf])); + f.elements[fp + "_bottom"].disabled = false; + + setValue(f, fp + "_left", getNum(ce.style[pr + b[3] + sf])); + f.elements[fp + "_left"].disabled = false; + + if (f.elements[fp + "_top_measurement"]) { + selectByValue(f, fp + '_top_measurement', getMeasurement(ce.style[pr + b[0] + sf])); + selectByValue(f, fp + '_right_measurement', getMeasurement(ce.style[pr + b[1] + sf])); + selectByValue(f, fp + '_bottom_measurement', getMeasurement(ce.style[pr + b[2] + sf])); + selectByValue(f, fp + '_left_measurement', getMeasurement(ce.style[pr + b[3] + sf])); + f.elements[fp + "_left_measurement"].disabled = false; + f.elements[fp + "_bottom_measurement"].disabled = false; + f.elements[fp + "_right_measurement"].disabled = false; + } + } +} + +function isSame(e, pr, sf, b) { + var a = [], i, x; + + if (typeof(b) == "undefined") + b = ['Top', 'Right', 'Bottom', 'Left']; + + if (typeof(sf) == "undefined" || sf == null) + sf = ""; + + a[0] = e.style[pr + b[0] + sf]; + a[1] = e.style[pr + b[1] + sf]; + a[2] = e.style[pr + b[2] + sf]; + a[3] = e.style[pr + b[3] + sf]; + + for (i=0; i 0 ? s.substring(1) : s; + + if (f.text_none.checked) + s = "none"; + + ce.style.textDecoration = s; + + // Build background styles + + ce.style.backgroundColor = f.background_color.value; + ce.style.backgroundImage = f.background_image.value != "" ? "url(" + f.background_image.value + ")" : ""; + ce.style.backgroundRepeat = f.background_repeat.value; + ce.style.backgroundAttachment = f.background_attachment.value; + + if (f.background_hpos.value != "") { + s = ""; + s += f.background_hpos.value + (isNum(f.background_hpos.value) ? f.background_hpos_measurement.value : "") + " "; + s += f.background_vpos.value + (isNum(f.background_vpos.value) ? f.background_vpos_measurement.value : ""); + ce.style.backgroundPosition = s; + } + + // Build block styles + + ce.style.wordSpacing = f.block_wordspacing.value + (isNum(f.block_wordspacing.value) ? f.block_wordspacing_measurement.value : ""); + ce.style.letterSpacing = f.block_letterspacing.value + (isNum(f.block_letterspacing.value) ? f.block_letterspacing_measurement.value : ""); + ce.style.verticalAlign = f.block_vertical_alignment.value; + ce.style.textAlign = f.block_text_align.value; + ce.style.textIndent = f.block_text_indent.value + (isNum(f.block_text_indent.value) ? f.block_text_indent_measurement.value : ""); + ce.style.whiteSpace = f.block_whitespace.value; + ce.style.display = f.block_display.value; + + // Build box styles + + ce.style.width = f.box_width.value + (isNum(f.box_width.value) ? f.box_width_measurement.value : ""); + ce.style.height = f.box_height.value + (isNum(f.box_height.value) ? f.box_height_measurement.value : ""); + ce.style.styleFloat = f.box_float.value; + + if (tinymce.isGecko) + ce.style.cssFloat = f.box_float.value; + + ce.style.clear = f.box_clear.value; + + if (!f.box_padding_same.checked) { + ce.style.paddingTop = f.box_padding_top.value + (isNum(f.box_padding_top.value) ? f.box_padding_top_measurement.value : ""); + ce.style.paddingRight = f.box_padding_right.value + (isNum(f.box_padding_right.value) ? f.box_padding_right_measurement.value : ""); + ce.style.paddingBottom = f.box_padding_bottom.value + (isNum(f.box_padding_bottom.value) ? f.box_padding_bottom_measurement.value : ""); + ce.style.paddingLeft = f.box_padding_left.value + (isNum(f.box_padding_left.value) ? f.box_padding_left_measurement.value : ""); + } else + ce.style.padding = f.box_padding_top.value + (isNum(f.box_padding_top.value) ? f.box_padding_top_measurement.value : ""); + + if (!f.box_margin_same.checked) { + ce.style.marginTop = f.box_margin_top.value + (isNum(f.box_margin_top.value) ? f.box_margin_top_measurement.value : ""); + ce.style.marginRight = f.box_margin_right.value + (isNum(f.box_margin_right.value) ? f.box_margin_right_measurement.value : ""); + ce.style.marginBottom = f.box_margin_bottom.value + (isNum(f.box_margin_bottom.value) ? f.box_margin_bottom_measurement.value : ""); + ce.style.marginLeft = f.box_margin_left.value + (isNum(f.box_margin_left.value) ? f.box_margin_left_measurement.value : ""); + } else + ce.style.margin = f.box_margin_top.value + (isNum(f.box_margin_top.value) ? f.box_margin_top_measurement.value : ""); + + // Build border styles + + if (!f.border_style_same.checked) { + ce.style.borderTopStyle = f.border_style_top.value; + ce.style.borderRightStyle = f.border_style_right.value; + ce.style.borderBottomStyle = f.border_style_bottom.value; + ce.style.borderLeftStyle = f.border_style_left.value; + } else + ce.style.borderStyle = f.border_style_top.value; + + if (!f.border_width_same.checked) { + ce.style.borderTopWidth = f.border_width_top.value + (isNum(f.border_width_top.value) ? f.border_width_top_measurement.value : ""); + ce.style.borderRightWidth = f.border_width_right.value + (isNum(f.border_width_right.value) ? f.border_width_right_measurement.value : ""); + ce.style.borderBottomWidth = f.border_width_bottom.value + (isNum(f.border_width_bottom.value) ? f.border_width_bottom_measurement.value : ""); + ce.style.borderLeftWidth = f.border_width_left.value + (isNum(f.border_width_left.value) ? f.border_width_left_measurement.value : ""); + } else + ce.style.borderWidth = f.border_width_top.value; + + if (!f.border_color_same.checked) { + ce.style.borderTopColor = f.border_color_top.value; + ce.style.borderRightColor = f.border_color_right.value; + ce.style.borderBottomColor = f.border_color_bottom.value; + ce.style.borderLeftColor = f.border_color_left.value; + } else + ce.style.borderColor = f.border_color_top.value; + + // Build list styles + + ce.style.listStyleType = f.list_type.value; + ce.style.listStylePosition = f.list_position.value; + ce.style.listStyleImage = f.list_bullet_image.value != "" ? "url(" + f.list_bullet_image.value + ")" : ""; + + // Build positioning styles + + ce.style.position = f.positioning_type.value; + ce.style.visibility = f.positioning_visibility.value; + + if (ce.style.width == "") + ce.style.width = f.positioning_width.value + (isNum(f.positioning_width.value) ? f.positioning_width_measurement.value : ""); + + if (ce.style.height == "") + ce.style.height = f.positioning_height.value + (isNum(f.positioning_height.value) ? f.positioning_height_measurement.value : ""); + + ce.style.zIndex = f.positioning_zindex.value; + ce.style.overflow = f.positioning_overflow.value; + + if (!f.positioning_placement_same.checked) { + ce.style.top = f.positioning_placement_top.value + (isNum(f.positioning_placement_top.value) ? f.positioning_placement_top_measurement.value : ""); + ce.style.right = f.positioning_placement_right.value + (isNum(f.positioning_placement_right.value) ? f.positioning_placement_right_measurement.value : ""); + ce.style.bottom = f.positioning_placement_bottom.value + (isNum(f.positioning_placement_bottom.value) ? f.positioning_placement_bottom_measurement.value : ""); + ce.style.left = f.positioning_placement_left.value + (isNum(f.positioning_placement_left.value) ? f.positioning_placement_left_measurement.value : ""); + } else { + s = f.positioning_placement_top.value + (isNum(f.positioning_placement_top.value) ? f.positioning_placement_top_measurement.value : ""); + ce.style.top = s; + ce.style.right = s; + ce.style.bottom = s; + ce.style.left = s; + } + + if (!f.positioning_clip_same.checked) { + s = "rect("; + s += (isNum(f.positioning_clip_top.value) ? f.positioning_clip_top.value + f.positioning_clip_top_measurement.value : "auto") + " "; + s += (isNum(f.positioning_clip_right.value) ? f.positioning_clip_right.value + f.positioning_clip_right_measurement.value : "auto") + " "; + s += (isNum(f.positioning_clip_bottom.value) ? f.positioning_clip_bottom.value + f.positioning_clip_bottom_measurement.value : "auto") + " "; + s += (isNum(f.positioning_clip_left.value) ? f.positioning_clip_left.value + f.positioning_clip_left_measurement.value : "auto"); + s += ")"; + + if (s != "rect(auto auto auto auto)") + ce.style.clip = s; + } else { + s = "rect("; + t = isNum(f.positioning_clip_top.value) ? f.positioning_clip_top.value + f.positioning_clip_top_measurement.value : "auto"; + s += t + " "; + s += t + " "; + s += t + " "; + s += t + ")"; + + if (s != "rect(auto auto auto auto)") + ce.style.clip = s; + } + + ce.style.cssText = ce.style.cssText; +} + +function isNum(s) { + return new RegExp('[0-9]+', 'g').test(s); +} + +function showDisabledControls() { + var f = document.forms, i, a; + + for (i=0; i 1) { + addSelectValue(f, s, p[0], p[1]); + + if (se) + selectByValue(f, s, p[1]); + } else { + addSelectValue(f, s, p[0], p[0]); + + if (se) + selectByValue(f, s, p[0]); + } + } +} + +function toggleSame(ce, pre) { + var el = document.forms[0].elements, i; + + if (ce.checked) { + el[pre + "_top"].disabled = false; + el[pre + "_right"].disabled = true; + el[pre + "_bottom"].disabled = true; + el[pre + "_left"].disabled = true; + + if (el[pre + "_top_measurement"]) { + el[pre + "_top_measurement"].disabled = false; + el[pre + "_right_measurement"].disabled = true; + el[pre + "_bottom_measurement"].disabled = true; + el[pre + "_left_measurement"].disabled = true; + } + } else { + el[pre + "_top"].disabled = false; + el[pre + "_right"].disabled = false; + el[pre + "_bottom"].disabled = false; + el[pre + "_left"].disabled = false; + + if (el[pre + "_top_measurement"]) { + el[pre + "_top_measurement"].disabled = false; + el[pre + "_right_measurement"].disabled = false; + el[pre + "_bottom_measurement"].disabled = false; + el[pre + "_left_measurement"].disabled = false; + } + } + + showDisabledControls(); +} + +function synch(fr, to) { + var f = document.forms[0]; + + f.elements[to].value = f.elements[fr].value; + + if (f.elements[fr + "_measurement"]) + selectByValue(f, to + "_measurement", f.elements[fr + "_measurement"].value); +} + +tinyMCEPopup.onInit.add(init); diff --git a/web/js/tiny_mce/plugins/style/langs/en_dlg.js b/web/js/tiny_mce/plugins/style/langs/en_dlg.js new file mode 100644 index 0000000..5026313 --- /dev/null +++ b/web/js/tiny_mce/plugins/style/langs/en_dlg.js @@ -0,0 +1,63 @@ +tinyMCE.addI18n('en.style_dlg',{ +title:"Edit CSS Style", +apply:"Apply", +text_tab:"Text", +background_tab:"Background", +block_tab:"Block", +box_tab:"Box", +border_tab:"Border", +list_tab:"List", +positioning_tab:"Positioning", +text_props:"Text", +text_font:"Font", +text_size:"Size", +text_weight:"Weight", +text_style:"Style", +text_variant:"Variant", +text_lineheight:"Line height", +text_case:"Case", +text_color:"Color", +text_decoration:"Decoration", +text_overline:"overline", +text_underline:"underline", +text_striketrough:"strikethrough", +text_blink:"blink", +text_none:"none", +background_color:"Background color", +background_image:"Background image", +background_repeat:"Repeat", +background_attachment:"Attachment", +background_hpos:"Horizontal position", +background_vpos:"Vertical position", +block_wordspacing:"Word spacing", +block_letterspacing:"Letter spacing", +block_vertical_alignment:"Vertical alignment", +block_text_align:"Text align", +block_text_indent:"Text indent", +block_whitespace:"Whitespace", +block_display:"Display", +box_width:"Width", +box_height:"Height", +box_float:"Float", +box_clear:"Clear", +padding:"Padding", +same:"Same for all", +top:"Top", +right:"Right", +bottom:"Bottom", +left:"Left", +margin:"Margin", +style:"Style", +width:"Width", +height:"Height", +color:"Color", +list_type:"Type", +bullet_image:"Bullet image", +position:"Position", +positioning_type:"Type", +visibility:"Visibility", +zindex:"Z-index", +overflow:"Overflow", +placement:"Placement", +clip:"Clip" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/style/langs/nb_dlg.js b/web/js/tiny_mce/plugins/style/langs/nb_dlg.js new file mode 100644 index 0000000..483f128 --- /dev/null +++ b/web/js/tiny_mce/plugins/style/langs/nb_dlg.js @@ -0,0 +1,63 @@ +tinyMCE.addI18n('nb.style_dlg',{ +title:"Rediger CSS-stil", +apply:"Legg til", +text_tab:"Tekst", +background_tab:"Bakgrunn", +block_tab:"Blokk", +box_tab:"Boks", +border_tab:"Ramme", +list_tab:"Liste", +positioning_tab:"Posisjon", +text_props:"Skriftegenskaper", +text_font:"Skrifttype", +text_size:"Skriftst\u00F8rrelse", +text_weight:"Skriftvekt", +text_style:"Skriftstil", +text_variant:"Variant", +text_lineheight:"Linjeh\u00F8yde", +text_case:"Kapiteler/minuskler", +text_color:"Farge", +text_decoration:"Dekorasjon", +text_overline:"Hevet skrift", +text_underline:"Senket skrift", +text_striketrough:"Gjennomstreking", +text_blink:"Blink", +text_none:"Ingen", +background_color:"Bakgrunnsfarge", +background_image:"Bakgrunnsbilde", +background_repeat:"Gjenta", +background_attachment:"Vedlegg", +background_hpos:"Horisontal posisjon", +background_vpos:"Vertikal posisjon", +block_wordspacing:"Ordmellomrom", +block_letterspacing:"Bokstavmellomrom", +block_vertical_alignment:"Vertikal justering", +block_text_align:"Justering", +block_text_indent:"Innrykk", +block_whitespace:"Mellomrom", +block_display:"Framvising", +box_width:"Bredde", +box_height:"H\u00F8yde", +box_float:"Flyt", +box_clear:"Slett", +padding:"Utfylling", +same:"Likt i alle", +top:"Topp", +right:"H\u00F8yre", +bottom:"Bunn", +left:"Venstre", +margin:"Marg", +style:"Stil", +width:"Bredde", +height:"H\u00F8yde", +color:"Farge", +list_type:"Type", +bullet_image:"Kulepunktbilde", +position:"Posisjon", +positioning_type:"Type", +visibility:"Synlighet", +zindex:"Z-indeks", +overflow:"Overfylt", +placement:"Plassering", +clip:"Klip" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/style/langs/nn_dlg.js b/web/js/tiny_mce/plugins/style/langs/nn_dlg.js new file mode 100644 index 0000000..4e09d3f --- /dev/null +++ b/web/js/tiny_mce/plugins/style/langs/nn_dlg.js @@ -0,0 +1,63 @@ +tinyMCE.addI18n('nn.style_dlg',{ +title:"Rediger CSS-stil", +apply:"Legg til", +text_tab:"Tekst", +background_tab:"Bakgrunn", +block_tab:"Blokk", +box_tab:"Boks", +border_tab:"Ramme", +list_tab:"Liste", +positioning_tab:"Posisjon", +text_props:"Eigenskapar for skrift", +text_font:"Skrifttype", +text_size:"Skriftstorleik", +text_weight:"Skriftvekt", +text_style:"Skriftstil", +text_variant:"Variant", +text_lineheight:"Linjeh\u00F8gd", +text_case:"Kapitelar/minusklar", +text_color:"Farge", +text_decoration:"Dekorasjon", +text_overline:"Heva skrift", +text_underline:"Senka skrift", +text_striketrough:"Gjennomstreking", +text_blink:"Blink", +text_none:"Ingen", +background_color:"Bakgrunnsfarge", +background_image:"Bakgrunnsbilete", +background_repeat:"Gjenta", +background_attachment:"Vedlegg", +background_hpos:"Horisontal posisjon", +background_vpos:"Vertikal posisjon", +block_wordspacing:"Ordmellomrom", +block_letterspacing:"Bokstavmellomrom", +block_vertical_alignment:"Vertikal justering", +block_text_align:"Justering", +block_text_indent:"Innrykk", +block_whitespace:"Mellomrom", +block_display:"Framsyning", +box_width:"Breidd", +box_height:"H\u00F8gd", +box_float:"Flyt", +box_clear:"Slett", +padding:"Utfylling", +same:"Likt i alle", +top:"Topp", +right:"H\u00F8gre", +bottom:"Bunn", +left:"Venstre", +margin:"Marg", +style:"Stil", +width:"Breidd", +height:"H\u00F8gd", +color:"Farge", +list_type:"Type", +bullet_image:"Kulepunktbilete", +position:"Posisjon", +positioning_type:"Type", +visibility:"Synlegheit", +zindex:"Z-indeks", +overflow:"Overfylt", +placement:"Plassering", +clip:"Klipp" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/style/props.htm b/web/js/tiny_mce/plugins/style/props.htm new file mode 100644 index 0000000..23ff916 --- /dev/null +++ b/web/js/tiny_mce/plugins/style/props.htm @@ -0,0 +1,731 @@ + + + + {#style_dlg.title} + + + + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + + +
     
    +
    + +
    + + + +
    + + + + + + +
    + +  
    +
    + +
    + + + + + +
     
    +
    {#style_dlg.text_decoration} + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + +
     
    +
    + + + + +
     
    +
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    +
    + +
    + + + + + + + + + + + + + + +
    + + + + + + +
     
    +
       
    + + + + + + +
     
    +
       
    +
    +
    + {#style_dlg.padding} + + + + + + + + + + + + + + + + + + + + + + +
     
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    +
    +
    + +
    +
    + {#style_dlg.margin} + + + + + + + + + + + + + + + + + + + + + + +
     
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    + + + + + + +
     
    +
    +
    +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#style_dlg.style} {#style_dlg.width} {#style_dlg.color}
          
    {#style_dlg.top}   + + + + + + +
     
    +
      + + + + + +
     
    +
    {#style_dlg.right}   + + + + + + +
     
    +
      + + + + + +
     
    +
    {#style_dlg.bottom}   + + + + + + +
     
    +
      + + + + + +
     
    +
    {#style_dlg.left}   + + + + + + +
     
    +
      + + + + + +
     
    +
    +
    + +
    + + + + + + + + + + + + + + + +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + +
       
    + + + + + + +
     
    +
       
    + + + + + + +
     
    +
       
    + +
    +
    + {#style_dlg.placement} + + + + + + + + + + + + + + + + + + + + + + +
     
    {#style_dlg.top} + + + + + + +
     
    +
    {#style_dlg.right} + + + + + + +
     
    +
    {#style_dlg.bottom} + + + + + + +
     
    +
    {#style_dlg.left} + + + + + + +
     
    +
    +
    +
    + +
    +
    + {#style_dlg.clip} + + + + + + + + + + + + + + + + + + + + + + +
     
    {#style_dlg.top} + + + + + + +
     
    +
    {#style_dlg.right} + + + + + + +
     
    +
    {#style_dlg.bottom} + + + + + + +
     
    +
    {#style_dlg.left} + + + + + + +
     
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + +
     
    +
    +
    + +
    + +
    +
    +
    + +
    +
    +
    + + + diff --git a/web/js/tiny_mce/plugins/table/cell.htm b/web/js/tiny_mce/plugins/table/cell.htm new file mode 100644 index 0000000..abf8577 --- /dev/null +++ b/web/js/tiny_mce/plugins/table/cell.htm @@ -0,0 +1,184 @@ + + + + {#table_dlg.cell_title} + + + + + + + + + +
    + + +
    +
    +
    + {#table_dlg.general_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + +
    +
    +
    + +
    +
    + {#table_dlg.advanced_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + + + +
     
    +
    + + + + + +
     
    +
    + + + + + +
     
    +
    +
    +
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/table/css/cell.css b/web/js/tiny_mce/plugins/table/css/cell.css new file mode 100644 index 0000000..a067ecd --- /dev/null +++ b/web/js/tiny_mce/plugins/table/css/cell.css @@ -0,0 +1,17 @@ +/* CSS file for cell dialog in the table plugin */ + +.panel_wrapper div.current { + height: 200px; +} + +.advfield { + width: 200px; +} + +#action { + margin-bottom: 3px; +} + +#class { + width: 150px; +} \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/table/css/row.css b/web/js/tiny_mce/plugins/table/css/row.css new file mode 100644 index 0000000..1f7755d --- /dev/null +++ b/web/js/tiny_mce/plugins/table/css/row.css @@ -0,0 +1,25 @@ +/* CSS file for row dialog in the table plugin */ + +.panel_wrapper div.current { + height: 200px; +} + +.advfield { + width: 200px; +} + +#action { + margin-bottom: 3px; +} + +#rowtype,#align,#valign,#class,#height { + width: 150px; +} + +#height { + width: 50px; +} + +.col2 { + padding-left: 20px; +} diff --git a/web/js/tiny_mce/plugins/table/css/table.css b/web/js/tiny_mce/plugins/table/css/table.css new file mode 100644 index 0000000..d11c3f6 --- /dev/null +++ b/web/js/tiny_mce/plugins/table/css/table.css @@ -0,0 +1,13 @@ +/* CSS file for table dialog in the table plugin */ + +.panel_wrapper div.current { + height: 245px; +} + +.advfield { + width: 200px; +} + +#class { + width: 150px; +} diff --git a/web/js/tiny_mce/plugins/table/editor_plugin.js b/web/js/tiny_mce/plugins/table/editor_plugin.js new file mode 100644 index 0000000..266b241 --- /dev/null +++ b/web/js/tiny_mce/plugins/table/editor_plugin.js @@ -0,0 +1 @@ +(function(){var each=tinymce.each;tinymce.create('tinymce.plugins.TablePlugin',{init:function(ed,url){var t=this;t.editor=ed;t.url=url;each([['table','table.desc','mceInsertTable',true],['delete_table','table.del','mceTableDelete'],['delete_col','table.delete_col_desc','mceTableDeleteCol'],['delete_row','table.delete_row_desc','mceTableDeleteRow'],['col_after','table.col_after_desc','mceTableInsertColAfter'],['col_before','table.col_before_desc','mceTableInsertColBefore'],['row_after','table.row_after_desc','mceTableInsertRowAfter'],['row_before','table.row_before_desc','mceTableInsertRowBefore'],['row_props','table.row_desc','mceTableRowProps',true],['cell_props','table.cell_desc','mceTableCellProps',true],['split_cells','table.split_cells_desc','mceTableSplitCells',true],['merge_cells','table.merge_cells_desc','mceTableMergeCells',true]],function(c){ed.addButton(c[0],{title:c[1],cmd:c[2],ui:c[3]});});ed.onInit.add(function(){if(ed&&ed.plugins.contextmenu){ed.plugins.contextmenu.onContextMenu.add(function(th,m,e){var sm,se=ed.selection,el=se.getNode()||ed.getBody();if(ed.dom.getParent(e,'td')||ed.dom.getParent(e,'th')){m.removeAll();if(el.nodeName=='A'&&!ed.dom.getAttrib(el,'name')){m.add({title:'advanced.link_desc',icon:'link',cmd:ed.plugins.advlink?'mceAdvLink':'mceLink',ui:true});m.add({title:'advanced.unlink_desc',icon:'unlink',cmd:'UnLink'});m.addSeparator();}if(el.nodeName=='IMG'&&el.className.indexOf('mceItem')==-1){m.add({title:'advanced.image_desc',icon:'image',cmd:ed.plugins.advimage?'mceAdvImage':'mceImage',ui:true});m.addSeparator();}m.add({title:'table.desc',icon:'table',cmd:'mceInsertTable',ui:true,value:{action:'insert'}});m.add({title:'table.props_desc',icon:'table_props',cmd:'mceInsertTable',ui:true});m.add({title:'table.del',icon:'delete_table',cmd:'mceTableDelete',ui:true});m.addSeparator();sm=m.addMenu({title:'table.cell'});sm.add({title:'table.cell_desc',icon:'cell_props',cmd:'mceTableCellProps',ui:true});sm.add({title:'table.split_cells_desc',icon:'split_cells',cmd:'mceTableSplitCells',ui:true});sm.add({title:'table.merge_cells_desc',icon:'merge_cells',cmd:'mceTableMergeCells',ui:true});sm=m.addMenu({title:'table.row'});sm.add({title:'table.row_desc',icon:'row_props',cmd:'mceTableRowProps',ui:true});sm.add({title:'table.row_before_desc',icon:'row_before',cmd:'mceTableInsertRowBefore'});sm.add({title:'table.row_after_desc',icon:'row_after',cmd:'mceTableInsertRowAfter'});sm.add({title:'table.delete_row_desc',icon:'delete_row',cmd:'mceTableDeleteRow'});sm.addSeparator();sm.add({title:'table.cut_row_desc',icon:'cut',cmd:'mceTableCutRow'});sm.add({title:'table.copy_row_desc',icon:'copy',cmd:'mceTableCopyRow'});sm.add({title:'table.paste_row_before_desc',icon:'paste',cmd:'mceTablePasteRowBefore'});sm.add({title:'table.paste_row_after_desc',icon:'paste',cmd:'mceTablePasteRowAfter'});sm=m.addMenu({title:'table.col'});sm.add({title:'table.col_before_desc',icon:'col_before',cmd:'mceTableInsertColBefore'});sm.add({title:'table.col_after_desc',icon:'col_after',cmd:'mceTableInsertColAfter'});sm.add({title:'table.delete_col_desc',icon:'delete_col',cmd:'mceTableDeleteCol'});}else m.add({title:'table.desc',icon:'table',cmd:'mceInsertTable',ui:true});});}});ed.onKeyDown.add(function(ed,e){if(e.keyCode==9&&ed.dom.getParent(ed.selection.getNode(),'TABLE'))ed.undoManager.add();});if(!tinymce.isIE){if(ed.getParam('table_selection',true)){ed.onClick.add(function(ed,e){e=e.target;if(e.nodeName==='TABLE')ed.selection.select(e);});}}ed.onNodeChange.add(function(ed,cm,n){var p=ed.dom.getParent(n,'td,th,caption');cm.setActive('table',n.nodeName==='TABLE'||!!p);if(p&&p.nodeName==='CAPTION')p=null;cm.setDisabled('delete_table',!p);cm.setDisabled('delete_col',!p);cm.setDisabled('delete_table',!p);cm.setDisabled('delete_row',!p);cm.setDisabled('col_after',!p);cm.setDisabled('col_before',!p);cm.setDisabled('row_after',!p);cm.setDisabled('row_before',!p);cm.setDisabled('row_props',!p);cm.setDisabled('cell_props',!p);cm.setDisabled('split_cells',!p||(parseInt(ed.dom.getAttrib(p,'colspan','1'))<2&&parseInt(ed.dom.getAttrib(p,'rowspan','1'))<2));cm.setDisabled('merge_cells',!p);});if(!tinymce.isIE){ed.onBeforeSetContent.add(function(ed,o){if(o.initial)o.content=o.content.replace(/<(td|th)([^>]+|)>\s*<\/(td|th)>/g,tinymce.isOpera?'<$1$2> ':'<$1$2>
    ');});}},execCommand:function(cmd,ui,val){var ed=this.editor,b;switch(cmd){case"mceInsertTable":case"mceTableRowProps":case"mceTableCellProps":case"mceTableSplitCells":case"mceTableMergeCells":case"mceTableInsertRowBefore":case"mceTableInsertRowAfter":case"mceTableDeleteRow":case"mceTableInsertColBefore":case"mceTableInsertColAfter":case"mceTableDeleteCol":case"mceTableCutRow":case"mceTableCopyRow":case"mceTablePasteRowBefore":case"mceTablePasteRowAfter":case"mceTableDelete":ed.execCommand('mceBeginUndoLevel');this._doExecCommand(cmd,ui,val);ed.execCommand('mceEndUndoLevel');return true;}return false;},getInfo:function(){return{longname:'Tables',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_doExecCommand:function(command,user_interface,value){var inst=this.editor,ed=inst,url=this.url;var focusElm=inst.selection.getNode();var trElm=inst.dom.getParent(focusElm,"tr");var tdElm=inst.dom.getParent(focusElm,"td,th");var tableElm=inst.dom.getParent(focusElm,"table");var doc=inst.contentWindow.document;var tableBorder=tableElm?tableElm.getAttribute("border"):"";if(trElm&&tdElm==null)tdElm=trElm.cells[0];function inArray(ar,v){for(var i=0;i0&&inArray(ar[i],v))return true;if(ar[i]==v)return true;}return false;}function select(dx,dy){var td;grid=getTableGrid(tableElm);dx=dx||0;dy=dy||0;dx=Math.max(cpos.cellindex+dx,0);dy=Math.max(cpos.rowindex+dy,0);inst.execCommand('mceRepaint');td=getCell(grid,dy,dx);if(td){inst.selection.select(td.firstChild||td);inst.selection.collapse(1);}};function makeTD(){var newTD=doc.createElement("td");if(!tinymce.isIE)newTD.innerHTML='
    ';}function getColRowSpan(td){var colspan=inst.dom.getAttrib(td,"colspan");var rowspan=inst.dom.getAttrib(td,"rowspan");colspan=colspan==""?1:parseInt(colspan);rowspan=rowspan==""?1:parseInt(rowspan);return{colspan:colspan,rowspan:rowspan};}function getCellPos(grid,td){var x,y;for(y=0;y1){for(var i=x;i1)td.rowSpan=sd.rowspan+1;lastElm=td;}deleteMarked(tableElm);}}function prevElm(node,name){while((node=node.previousSibling)!=null){if(node.nodeName==name)return node;}return null;}function nextElm(node,names){var namesAr=names.split(',');while((node=node.nextSibling)!=null){for(var i=0;i1){do{var nexttd=nextElm(td,"TD,TH");if(td._delete)td.parentNode.removeChild(td);}while((td=nexttd)!=null);}}while((tr=next)!=null);}function addRows(td_elm,tr_elm,rowspan){td_elm.rowSpan=1;var trNext=nextElm(tr_elm,"TR");for(var i=1;i';if(tinymce.isIE)trNext.insertBefore(newTD,trNext.cells(td_elm.cellIndex));else trNext.insertBefore(newTD,trNext.cells[td_elm.cellIndex]);trNext=nextElm(trNext,"TR");}}function copyRow(doc,table,tr){var grid=getTableGrid(table);var newTR=tr.cloneNode(false);var cpos=getCellPos(grid,tr.cells[0]);var lastCell=null;var tableBorder=inst.dom.getAttrib(table,"border");var tdElm=null;for(var x=0;tdElm=getCell(grid,cpos.rowindex,x);x++){var newTD=null;if(lastCell!=tdElm){for(var i=0;i';}newTD.colSpan=1;newTD.rowSpan=1;newTR.appendChild(newTD);lastCell=tdElm;}return newTR;}switch(command){case"mceTableRowProps":if(trElm==null)return true;if(user_interface){inst.windowManager.open({url:url+'/row.htm',width:400+parseInt(inst.getLang('table.rowprops_delta_width',0)),height:295+parseInt(inst.getLang('table.rowprops_delta_height',0)),inline:1},{plugin_url:url});}return true;case"mceTableCellProps":if(tdElm==null)return true;if(user_interface){inst.windowManager.open({url:url+'/cell.htm',width:400+parseInt(inst.getLang('table.cellprops_delta_width',0)),height:295+parseInt(inst.getLang('table.cellprops_delta_height',0)),inline:1},{plugin_url:url});}return true;case"mceInsertTable":if(user_interface){inst.windowManager.open({url:url+'/table.htm',width:400+parseInt(inst.getLang('table.table_delta_width',0)),height:320+parseInt(inst.getLang('table.table_delta_height',0)),inline:1},{plugin_url:url,action:value?value.action:0});}return true;case"mceTableDelete":var table=inst.dom.getParent(inst.selection.getNode(),"table");if(table){table.parentNode.removeChild(table);inst.execCommand('mceRepaint');}return true;case"mceTableSplitCells":case"mceTableMergeCells":case"mceTableInsertRowBefore":case"mceTableInsertRowAfter":case"mceTableDeleteRow":case"mceTableInsertColBefore":case"mceTableInsertColAfter":case"mceTableDeleteCol":case"mceTableCutRow":case"mceTableCopyRow":case"mceTablePasteRowBefore":case"mceTablePasteRowAfter":if(!tableElm)return true;if(trElm&&tableElm!=trElm.parentNode)tableElm=trElm.parentNode;if(tableElm&&trElm){switch(command){case"mceTableCutRow":if(!trElm||!tdElm)return true;inst.tableRowClipboard=copyRow(doc,tableElm,trElm);inst.execCommand("mceTableDeleteRow");break;case"mceTableCopyRow":if(!trElm||!tdElm)return true;inst.tableRowClipboard=copyRow(doc,tableElm,trElm);break;case"mceTablePasteRowBefore":if(!trElm||!tdElm)return true;var newTR=inst.tableRowClipboard.cloneNode(true);var prevTR=prevElm(trElm,"TR");if(prevTR!=null)trimRow(tableElm,prevTR,prevTR.cells[0],newTR);trElm.parentNode.insertBefore(newTR,trElm);break;case"mceTablePasteRowAfter":if(!trElm||!tdElm)return true;var nextTR=nextElm(trElm,"TR");var newTR=inst.tableRowClipboard.cloneNode(true);trimRow(tableElm,trElm,tdElm,newTR);if(nextTR==null)trElm.parentNode.appendChild(newTR);else nextTR.parentNode.insertBefore(newTR,nextTR);break;case"mceTableInsertRowBefore":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var newTR=doc.createElement("tr");var lastTDElm=null;cpos.rowindex--;if(cpos.rowindex<0)cpos.rowindex=0;for(var x=0;tdElm=getCell(grid,cpos.rowindex,x);x++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['rowspan']==1){var newTD=doc.createElement("td");if(!tinymce.isIE)newTD.innerHTML='
    ';newTD.colSpan=tdElm.colSpan;newTR.appendChild(newTD);}else tdElm.rowSpan=sd['rowspan']+1;lastTDElm=tdElm;}}trElm.parentNode.insertBefore(newTR,trElm);select(0,1);break;case"mceTableInsertRowAfter":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var newTR=doc.createElement("tr");var lastTDElm=null;for(var x=0;tdElm=getCell(grid,cpos.rowindex,x);x++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['rowspan']==1){var newTD=doc.createElement("td");if(!tinymce.isIE)newTD.innerHTML='
    ';newTD.colSpan=tdElm.colSpan;newTR.appendChild(newTD);}else tdElm.rowSpan=sd['rowspan']+1;lastTDElm=tdElm;}}if(newTR.hasChildNodes()){var nextTR=nextElm(trElm,"TR");if(nextTR)nextTR.parentNode.insertBefore(newTR,nextTR);else tableElm.appendChild(newTR);}select(0,1);break;case"mceTableDeleteRow":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);if(grid.length==1){inst.dom.remove(inst.dom.getParent(tableElm,"table"));return true;}var cells=trElm.cells;var nextTR=nextElm(trElm,"TR");for(var x=0;x1){var newTD=cells[x].cloneNode(true);var sd=getColRowSpan(cells[x]);newTD.rowSpan=sd.rowspan-1;var nextTD=nextTR.cells[x];if(nextTD==null)nextTR.appendChild(newTD);else nextTR.insertBefore(newTD,nextTD);}}var lastTDElm=null;for(var x=0;tdElm=getCell(grid,cpos.rowindex,x);x++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd.rowspan>1){tdElm.rowSpan=sd.rowspan-1;}else{trElm=tdElm.parentNode;if(trElm.parentNode)trElm._delete=true;}lastTDElm=tdElm;}}deleteMarked(tableElm);select(0,-1);break;case"mceTableInsertColBefore":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var lastTDElm=null;for(var y=0;tdElm=getCell(grid,y,cpos.cellindex);y++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['colspan']==1){var newTD=doc.createElement(tdElm.nodeName);if(!tinymce.isIE)newTD.innerHTML='
    ';newTD.rowSpan=tdElm.rowSpan;tdElm.parentNode.insertBefore(newTD,tdElm);}else tdElm.colSpan++;lastTDElm=tdElm;}}select();break;case"mceTableInsertColAfter":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var lastTDElm=null;for(var y=0;tdElm=getCell(grid,y,cpos.cellindex);y++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['colspan']==1){var newTD=doc.createElement(tdElm.nodeName);if(!tinymce.isIE)newTD.innerHTML='
    ';newTD.rowSpan=tdElm.rowSpan;var nextTD=nextElm(tdElm,"TD,TH");if(nextTD==null)tdElm.parentNode.appendChild(newTD);else nextTD.parentNode.insertBefore(newTD,nextTD);}else tdElm.colSpan++;lastTDElm=tdElm;}}select(1);break;case"mceTableDeleteCol":if(!trElm||!tdElm)return true;var grid=getTableGrid(tableElm);var cpos=getCellPos(grid,tdElm);var lastTDElm=null;if(grid.length>1&&grid[0].length<=1){inst.dom.remove(inst.dom.getParent(tableElm,"table"));return true;}for(var y=0;tdElm=getCell(grid,y,cpos.cellindex);y++){if(tdElm!=lastTDElm){var sd=getColRowSpan(tdElm);if(sd['colspan']>1)tdElm.colSpan=sd['colspan']-1;else{if(tdElm.parentNode)tdElm.parentNode.removeChild(tdElm);}lastTDElm=tdElm;}}select(-1);break;case"mceTableSplitCells":if(!trElm||!tdElm)return true;var spandata=getColRowSpan(tdElm);var colspan=spandata["colspan"];var rowspan=spandata["rowspan"];if(colspan>1||rowspan>1){tdElm.colSpan=1;for(var i=1;i';trElm.insertBefore(newTD,nextElm(tdElm,"TD,TH"));if(rowspan>1)addRows(newTD,trElm,rowspan);}addRows(tdElm,trElm,rowspan);}tableElm=inst.dom.getParent(inst.selection.getNode(),"table");break;case"mceTableMergeCells":var rows=[];var sel=inst.selection.getSel();var grid=getTableGrid(tableElm);if(tinymce.isIE||sel.rangeCount==1){if(user_interface){var sp=getColRowSpan(tdElm);inst.windowManager.open({url:url+'/merge_cells.htm',width:240+parseInt(inst.getLang('table.merge_cells_delta_width',0)),height:110+parseInt(inst.getLang('table.merge_cells_delta_height',0)),inline:1},{action:"update",numcols:sp.colspan,numrows:sp.rowspan,plugin_url:url});return true;}else{var numRows=parseInt(value['numrows']);var numCols=parseInt(value['numcols']);var cpos=getCellPos(grid,tdElm);if((""+numRows)=="NaN")numRows=1;if((""+numCols)=="NaN")numCols=1;var tRows=tableElm.rows;for(var y=cpos.rowindex;y0)rows[rows.length]=rowCells;var td=getCell(grid,cpos.rowindex,cpos.cellindex);each(ed.dom.select('br',td),function(e,i){if(i>0&&ed.dom.getAttrib('mce_bogus'))ed.dom.remove(e);});}}}else{var cells=[];var sel=inst.selection.getSel();var lastTR=null;var curRow=null;var x1=-1,y1=-1,x2,y2;if(sel.rangeCount<2)return true;for(var i=0;i0)rows[rows.length]=rowCells;}var curRow=[];var lastTR=null;for(var y=0;ycolSpan)colSpan=rowColSpan;lastRowSpan=-1;}var lastColSpan=-1;for(var x=0;xrowSpan)rowSpan=colRowSpan;lastColSpan=-1;}tdElm=rows[0][0];tdElm.rowSpan=rowSpan;tdElm.colSpan=colSpan;for(var y=0;y0))tdElm.innerHTML+=html;if(rows[y][x]!=tdElm&&!rows[y][x]._deleted){var cpos=getCellPos(grid,rows[y][x]);var tr=rows[y][x].parentNode;tr.removeChild(rows[y][x]);rows[y][x]._deleted=true;if(!tr.hasChildNodes()){tr.parentNode.removeChild(tr);var lastCell=null;for(var x=0;cellElm=getCell(grid,cpos.rowindex,x);x++){if(cellElm!=lastCell&&cellElm.rowSpan>1)cellElm.rowSpan--;lastCell=cellElm;}if(tdElm.rowSpan>1)tdElm.rowSpan--;}}}}each(ed.dom.select('br',tdElm),function(e,i){if(i>0&&ed.dom.getAttrib(e,'mce_bogus'))ed.dom.remove(e);});break;}tableElm=inst.dom.getParent(inst.selection.getNode(),"table");inst.addVisual(tableElm);inst.nodeChanged();}return true;}return false;}});tinymce.PluginManager.add('table',tinymce.plugins.TablePlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/table/editor_plugin_src.js b/web/js/tiny_mce/plugins/table/editor_plugin_src.js new file mode 100644 index 0000000..097890f --- /dev/null +++ b/web/js/tiny_mce/plugins/table/editor_plugin_src.js @@ -0,0 +1,1082 @@ +/** + * $Id: editor_plugin_src.js 792 2008-04-10 16:37:29Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + var each = tinymce.each; + + tinymce.create('tinymce.plugins.TablePlugin', { + init : function(ed, url) { + var t = this; + + t.editor = ed; + t.url = url; + + // Register buttons + each([ + ['table', 'table.desc', 'mceInsertTable', true], + ['delete_table', 'table.del', 'mceTableDelete'], + ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'], + ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'], + ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'], + ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'], + ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'], + ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'], + ['row_props', 'table.row_desc', 'mceTableRowProps', true], + ['cell_props', 'table.cell_desc', 'mceTableCellProps', true], + ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true], + ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true] + ], function(c) { + ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]}); + }); + + ed.onInit.add(function() { + if (ed && ed.plugins.contextmenu) { + ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) { + var sm, se = ed.selection, el = se.getNode() || ed.getBody(); + + if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th')) { + m.removeAll(); + + if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) { + m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true}); + m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'}); + m.addSeparator(); + } + + if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) { + m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true}); + m.addSeparator(); + } + + m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true, value : {action : 'insert'}}); + m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable', ui : true}); + m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete', ui : true}); + m.addSeparator(); + + // Cell menu + sm = m.addMenu({title : 'table.cell'}); + sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps', ui : true}); + sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells', ui : true}); + sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells', ui : true}); + + // Row menu + sm = m.addMenu({title : 'table.row'}); + sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps', ui : true}); + sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'}); + sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'}); + sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'}); + sm.addSeparator(); + sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'}); + sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'}); + sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}); + sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}); + + // Column menu + sm = m.addMenu({title : 'table.col'}); + sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'}); + sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'}); + sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'}); + } else + m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', ui : true}); + }); + } + }); + + // Add undo level when new rows are created using the tab key + ed.onKeyDown.add(function(ed, e) { + if (e.keyCode == 9 && ed.dom.getParent(ed.selection.getNode(), 'TABLE')) + ed.undoManager.add(); + }); + + // Select whole table is a table border is clicked + if (!tinymce.isIE) { + if (ed.getParam('table_selection', true)) { + ed.onClick.add(function(ed, e) { + e = e.target; + + if (e.nodeName === 'TABLE') + ed.selection.select(e); + }); + } + } + + ed.onNodeChange.add(function(ed, cm, n) { + var p = ed.dom.getParent(n, 'td,th,caption'); + + cm.setActive('table', n.nodeName === 'TABLE' || !!p); + if (p && p.nodeName === 'CAPTION') + p = null; + + cm.setDisabled('delete_table', !p); + cm.setDisabled('delete_col', !p); + cm.setDisabled('delete_table', !p); + cm.setDisabled('delete_row', !p); + cm.setDisabled('col_after', !p); + cm.setDisabled('col_before', !p); + cm.setDisabled('row_after', !p); + cm.setDisabled('row_before', !p); + cm.setDisabled('row_props', !p); + cm.setDisabled('cell_props', !p); + cm.setDisabled('split_cells', !p || (parseInt(ed.dom.getAttrib(p, 'colspan', '1')) < 2 && parseInt(ed.dom.getAttrib(p, 'rowspan', '1')) < 2)); + cm.setDisabled('merge_cells', !p); + }); + + // Padd empty table cells + if (!tinymce.isIE) { + ed.onBeforeSetContent.add(function(ed, o) { + if (o.initial) + o.content = o.content.replace(/<(td|th)([^>]+|)>\s*<\/(td|th)>/g, tinymce.isOpera ? '<$1$2> ' : '<$1$2>
    '); + }); + } + }, + + execCommand : function(cmd, ui, val) { + var ed = this.editor, b; + + // Is table command + switch (cmd) { + case "mceInsertTable": + case "mceTableRowProps": + case "mceTableCellProps": + case "mceTableSplitCells": + case "mceTableMergeCells": + case "mceTableInsertRowBefore": + case "mceTableInsertRowAfter": + case "mceTableDeleteRow": + case "mceTableInsertColBefore": + case "mceTableInsertColAfter": + case "mceTableDeleteCol": + case "mceTableCutRow": + case "mceTableCopyRow": + case "mceTablePasteRowBefore": + case "mceTablePasteRowAfter": + case "mceTableDelete": + ed.execCommand('mceBeginUndoLevel'); + this._doExecCommand(cmd, ui, val); + ed.execCommand('mceEndUndoLevel'); + + return true; + } + + // Pass to next handler in chain + return false; + }, + + getInfo : function() { + return { + longname : 'Tables', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/table', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + }, + + // Private plugin internal methods + + /** + * Executes the table commands. + */ + _doExecCommand : function(command, user_interface, value) { + var inst = this.editor, ed = inst, url = this.url; + var focusElm = inst.selection.getNode(); + var trElm = inst.dom.getParent(focusElm, "tr"); + var tdElm = inst.dom.getParent(focusElm, "td,th"); + var tableElm = inst.dom.getParent(focusElm, "table"); + var doc = inst.contentWindow.document; + var tableBorder = tableElm ? tableElm.getAttribute("border") : ""; + + // Get first TD if no TD found + if (trElm && tdElm == null) + tdElm = trElm.cells[0]; + + function inArray(ar, v) { + for (var i=0; i 0 && inArray(ar[i], v)) + return true; + + // Found value + if (ar[i] == v) + return true; + } + + return false; + } + + function select(dx, dy) { + var td; + + grid = getTableGrid(tableElm); + dx = dx || 0; + dy = dy || 0; + dx = Math.max(cpos.cellindex + dx, 0); + dy = Math.max(cpos.rowindex + dy, 0); + + // Recalculate grid and select + inst.execCommand('mceRepaint'); + td = getCell(grid, dy, dx); + + if (td) { + inst.selection.select(td.firstChild || td); + inst.selection.collapse(1); + } + }; + + function makeTD() { + var newTD = doc.createElement("td"); + + if (!tinymce.isIE) + newTD.innerHTML = '
    '; + } + + function getColRowSpan(td) { + var colspan = inst.dom.getAttrib(td, "colspan"); + var rowspan = inst.dom.getAttrib(td, "rowspan"); + + colspan = colspan == "" ? 1 : parseInt(colspan); + rowspan = rowspan == "" ? 1 : parseInt(rowspan); + + return {colspan : colspan, rowspan : rowspan}; + } + + function getCellPos(grid, td) { + var x, y; + + for (y=0; y 1) { // Remove due to colspan + for (var i=x; i 1) + td.rowSpan = sd.rowspan + 1; + + lastElm = td; + } + + deleteMarked(tableElm); + } + } + + function prevElm(node, name) { + while ((node = node.previousSibling) != null) { + if (node.nodeName == name) + return node; + } + + return null; + } + + function nextElm(node, names) { + var namesAr = names.split(','); + + while ((node = node.nextSibling) != null) { + for (var i=0; i 1) { + do { + var nexttd = nextElm(td, "TD,TH"); + + if (td._delete) + td.parentNode.removeChild(td); + } while ((td = nexttd) != null); + } + } while ((tr = next) != null); + } + + function addRows(td_elm, tr_elm, rowspan) { + // Add rows + td_elm.rowSpan = 1; + var trNext = nextElm(tr_elm, "TR"); + for (var i=1; i 1) { + var newTD = cells[x].cloneNode(true); + var sd = getColRowSpan(cells[x]); + + newTD.rowSpan = sd.rowspan - 1; + + var nextTD = nextTR.cells[x]; + + if (nextTD == null) + nextTR.appendChild(newTD); + else + nextTR.insertBefore(newTD, nextTD); + } + } + + // Delete cells + var lastTDElm = null; + for (var x=0; tdElm = getCell(grid, cpos.rowindex, x); x++) { + if (tdElm != lastTDElm) { + var sd = getColRowSpan(tdElm); + + if (sd.rowspan > 1) { + tdElm.rowSpan = sd.rowspan - 1; + } else { + trElm = tdElm.parentNode; + + if (trElm.parentNode) + trElm._delete = true; + } + + lastTDElm = tdElm; + } + } + + deleteMarked(tableElm); + + select(0, -1); + break; + + case "mceTableInsertColBefore": + if (!trElm || !tdElm) + return true; + + var grid = getTableGrid(tableElm); + var cpos = getCellPos(grid, tdElm); + var lastTDElm = null; + + for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) { + if (tdElm != lastTDElm) { + var sd = getColRowSpan(tdElm); + + if (sd['colspan'] == 1) { + var newTD = doc.createElement(tdElm.nodeName); + + if (!tinymce.isIE) + newTD.innerHTML = '
    '; + + newTD.rowSpan = tdElm.rowSpan; + + tdElm.parentNode.insertBefore(newTD, tdElm); + } else + tdElm.colSpan++; + + lastTDElm = tdElm; + } + } + + select(); + break; + + case "mceTableInsertColAfter": + if (!trElm || !tdElm) + return true; + + var grid = getTableGrid(tableElm); + var cpos = getCellPos(grid, tdElm); + var lastTDElm = null; + + for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) { + if (tdElm != lastTDElm) { + var sd = getColRowSpan(tdElm); + + if (sd['colspan'] == 1) { + var newTD = doc.createElement(tdElm.nodeName); + + if (!tinymce.isIE) + newTD.innerHTML = '
    '; + + newTD.rowSpan = tdElm.rowSpan; + + var nextTD = nextElm(tdElm, "TD,TH"); + if (nextTD == null) + tdElm.parentNode.appendChild(newTD); + else + nextTD.parentNode.insertBefore(newTD, nextTD); + } else + tdElm.colSpan++; + + lastTDElm = tdElm; + } + } + + select(1); + break; + + case "mceTableDeleteCol": + if (!trElm || !tdElm) + return true; + + var grid = getTableGrid(tableElm); + var cpos = getCellPos(grid, tdElm); + var lastTDElm = null; + + // Only one col, remove whole table + if (grid.length > 1 && grid[0].length <= 1) { + inst.dom.remove(inst.dom.getParent(tableElm, "table")); + return true; + } + + // Delete cells + for (var y=0; tdElm = getCell(grid, y, cpos.cellindex); y++) { + if (tdElm != lastTDElm) { + var sd = getColRowSpan(tdElm); + + if (sd['colspan'] > 1) + tdElm.colSpan = sd['colspan'] - 1; + else { + if (tdElm.parentNode) + tdElm.parentNode.removeChild(tdElm); + } + + lastTDElm = tdElm; + } + } + + select(-1); + break; + + case "mceTableSplitCells": + if (!trElm || !tdElm) + return true; + + var spandata = getColRowSpan(tdElm); + + var colspan = spandata["colspan"]; + var rowspan = spandata["rowspan"]; + + // Needs splitting + if (colspan > 1 || rowspan > 1) { + // Generate cols + tdElm.colSpan = 1; + for (var i=1; i 1) + addRows(newTD, trElm, rowspan); + } + + addRows(tdElm, trElm, rowspan); + } + + // Apply visual aids + tableElm = inst.dom.getParent(inst.selection.getNode(), "table"); + break; + + case "mceTableMergeCells": + var rows = []; + var sel = inst.selection.getSel(); + var grid = getTableGrid(tableElm); + + if (tinymce.isIE || sel.rangeCount == 1) { + if (user_interface) { + // Setup template + var sp = getColRowSpan(tdElm); + + inst.windowManager.open({ + url : url + '/merge_cells.htm', + width : 240 + parseInt(inst.getLang('table.merge_cells_delta_width', 0)), + height : 110 + parseInt(inst.getLang('table.merge_cells_delta_height', 0)), + inline : 1 + }, { + action : "update", + numcols : sp.colspan, + numrows : sp.rowspan, + plugin_url : url + }); + + return true; + } else { + var numRows = parseInt(value['numrows']); + var numCols = parseInt(value['numcols']); + var cpos = getCellPos(grid, tdElm); + + if (("" + numRows) == "NaN") + numRows = 1; + + if (("" + numCols) == "NaN") + numCols = 1; + + // Get rows and cells + var tRows = tableElm.rows; + for (var y=cpos.rowindex; y 0) + rows[rows.length] = rowCells; + + var td = getCell(grid, cpos.rowindex, cpos.cellindex); + each(ed.dom.select('br', td), function(e, i) { + if (i > 0 && ed.dom.getAttrib('mce_bogus')) + ed.dom.remove(e); + }); + } + + //return true; + } + } else { + var cells = []; + var sel = inst.selection.getSel(); + var lastTR = null; + var curRow = null; + var x1 = -1, y1 = -1, x2, y2; + + // Only one cell selected, whats the point? + if (sel.rangeCount < 2) + return true; + + // Get all selected cells + for (var i=0; i 0) + rows[rows.length] = rowCells; + } + + // Find selected cells in grid and box + var curRow = []; + var lastTR = null; + for (var y=0; y colSpan) + colSpan = rowColSpan; + + lastRowSpan = -1; + } + + // Validate vertical and get total rowspan + var lastColSpan = -1; + for (var x=0; x rowSpan) + rowSpan = colRowSpan; + + lastColSpan = -1; + } + + // Setup td + tdElm = rows[0][0]; + tdElm.rowSpan = rowSpan; + tdElm.colSpan = colSpan; + + // Merge cells + for (var y=0; y 0)) + tdElm.innerHTML += html; + + // Not current cell + if (rows[y][x] != tdElm && !rows[y][x]._deleted) { + var cpos = getCellPos(grid, rows[y][x]); + var tr = rows[y][x].parentNode; + + tr.removeChild(rows[y][x]); + rows[y][x]._deleted = true; + + // Empty TR, remove it + if (!tr.hasChildNodes()) { + tr.parentNode.removeChild(tr); + + var lastCell = null; + for (var x=0; cellElm = getCell(grid, cpos.rowindex, x); x++) { + if (cellElm != lastCell && cellElm.rowSpan > 1) + cellElm.rowSpan--; + + lastCell = cellElm; + } + + if (tdElm.rowSpan > 1) + tdElm.rowSpan--; + } + } + } + } + + // Remove all but one bogus br + each(ed.dom.select('br', tdElm), function(e, i) { + if (i > 0 && ed.dom.getAttrib(e, 'mce_bogus')) + ed.dom.remove(e); + }); + + break; + } + + tableElm = inst.dom.getParent(inst.selection.getNode(), "table"); + inst.addVisual(tableElm); + inst.nodeChanged(); + } + + return true; + } + + // Pass to next handler in chain + return false; + } + }); + + // Register plugin + tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/table/js/cell.js b/web/js/tiny_mce/plugins/table/js/cell.js new file mode 100644 index 0000000..7d7f977 --- /dev/null +++ b/web/js/tiny_mce/plugins/table/js/cell.js @@ -0,0 +1,259 @@ +tinyMCEPopup.requireLangPack(); + +var ed; + +function init() { + ed = tinyMCEPopup.editor; + tinyMCEPopup.resizeToInnerSize(); + + document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table'); + document.getElementById('bordercolor_pickcontainer').innerHTML = getColorPickerHTML('bordercolor_pick','bordercolor'); + document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor') + + var inst = ed; + var tdElm = ed.dom.getParent(ed.selection.getNode(), "td,th"); + var formObj = document.forms[0]; + var st = ed.dom.parseStyle(ed.dom.getAttrib(tdElm, "style")); + + // Get table cell data + var celltype = tdElm.nodeName.toLowerCase(); + var align = ed.dom.getAttrib(tdElm, 'align'); + var valign = ed.dom.getAttrib(tdElm, 'valign'); + var width = trimSize(getStyle(tdElm, 'width', 'width')); + var height = trimSize(getStyle(tdElm, 'height', 'height')); + var bordercolor = convertRGBToHex(getStyle(tdElm, 'bordercolor', 'borderLeftColor')); + var bgcolor = convertRGBToHex(getStyle(tdElm, 'bgcolor', 'backgroundColor')); + var className = ed.dom.getAttrib(tdElm, 'class'); + var backgroundimage = getStyle(tdElm, 'background', 'backgroundImage').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");; + var id = ed.dom.getAttrib(tdElm, 'id'); + var lang = ed.dom.getAttrib(tdElm, 'lang'); + var dir = ed.dom.getAttrib(tdElm, 'dir'); + var scope = ed.dom.getAttrib(tdElm, 'scope'); + + // Setup form + addClassesToList('class', 'table_cell_styles'); + TinyMCE_EditableSelects.init(); + + formObj.bordercolor.value = bordercolor; + formObj.bgcolor.value = bgcolor; + formObj.backgroundimage.value = backgroundimage; + formObj.width.value = width; + formObj.height.value = height; + formObj.id.value = id; + formObj.lang.value = lang; + formObj.style.value = ed.dom.serializeStyle(st); + selectByValue(formObj, 'align', align); + selectByValue(formObj, 'valign', valign); + selectByValue(formObj, 'class', className, true, true); + selectByValue(formObj, 'celltype', celltype); + selectByValue(formObj, 'dir', dir); + selectByValue(formObj, 'scope', scope); + + // Resize some elements + if (isVisible('backgroundimagebrowser')) + document.getElementById('backgroundimage').style.width = '180px'; + + updateColor('bordercolor_pick', 'bordercolor'); + updateColor('bgcolor_pick', 'bgcolor'); +} + +function updateAction() { + var el, inst = ed, tdElm, trElm, tableElm, formObj = document.forms[0]; + + tinyMCEPopup.restoreSelection(); + el = ed.selection.getNode(); + tdElm = ed.dom.getParent(el, "td,th"); + trElm = ed.dom.getParent(el, "tr"); + tableElm = ed.dom.getParent(el, "table"); + + ed.execCommand('mceBeginUndoLevel'); + + switch (getSelectValue(formObj, 'action')) { + case "cell": + var celltype = getSelectValue(formObj, 'celltype'); + var scope = getSelectValue(formObj, 'scope'); + + if (ed.getParam("accessibility_warnings")) { + if (celltype == "th" && scope == "") + var answer = confirm(ed.getLang('table_dlg.missing_scope', '', true)); + else + var answer = true; + + if (!answer) + return; + } + + updateCell(tdElm); + break; + + case "row": + var cell = trElm.firstChild; + + if (cell.nodeName != "TD" && cell.nodeName != "TH") + cell = nextCell(cell); + + do { + cell = updateCell(cell, true); + } while ((cell = nextCell(cell)) != null); + + break; + + case "all": + var rows = tableElm.getElementsByTagName("tr"); + + for (var i=0; i colLimit) { + alert(inst.getLang('table_col_limit', '', true, {cols : colLimit})); + return false; + } else if (rowLimit && rows > rowLimit) { + alert(inst.getLang('table_row_limit', '', true, {rows : rowLimit})); + return false; + } else if (cellLimit && cols * rows > cellLimit) { + alert(inst.getLang('table_cell_limit', '', true, {cells : cellLimit})); + return false; + } + + // Update table + if (action == "update") { + inst.execCommand('mceBeginUndoLevel'); + + dom.setAttrib(elm, 'cellPadding', cellpadding, true); + dom.setAttrib(elm, 'cellSpacing', cellspacing, true); + dom.setAttrib(elm, 'border', border); + dom.setAttrib(elm, 'align', align); + dom.setAttrib(elm, 'frame', frame); + dom.setAttrib(elm, 'rules', rules); + dom.setAttrib(elm, 'class', className); + dom.setAttrib(elm, 'style', style); + dom.setAttrib(elm, 'id', id); + dom.setAttrib(elm, 'summary', summary); + dom.setAttrib(elm, 'dir', dir); + dom.setAttrib(elm, 'lang', lang); + + capEl = inst.dom.select('caption', elm)[0]; + + if (capEl && !caption) + capEl.parentNode.removeChild(capEl); + + if (!capEl && caption) { + capEl = elm.ownerDocument.createElement('caption'); + + if (!tinymce.isIE) + capEl.innerHTML = '
    '; + + elm.insertBefore(capEl, elm.firstChild); + } + + if (width && /(pt|em|cm)$/.test(width)) { + dom.setStyle(elm, 'width', width); + dom.setAttrib(elm, 'width', ''); + } else { + dom.setAttrib(elm, 'width', width, true); + dom.setStyle(elm, 'width', ''); + } + + // Remove these since they are not valid XHTML + dom.setAttrib(elm, 'borderColor', ''); + dom.setAttrib(elm, 'bgColor', ''); + dom.setAttrib(elm, 'background', ''); + + if (height) { + dom.setStyle(elm, 'height', height); + dom.setAttrib(elm, 'height', ''); + } + + if (background != '') + elm.style.backgroundImage = "url('" + background + "')"; + else + elm.style.backgroundImage = ''; + +/* if (tinyMCEPopup.getParam("inline_styles")) { + if (width != '') + elm.style.width = getCSSSize(width); + }*/ + + if (bordercolor != "") { + elm.style.borderColor = bordercolor; + elm.style.borderStyle = elm.style.borderStyle == "" ? "solid" : elm.style.borderStyle; + elm.style.borderWidth = border == "" ? "1px" : border; + } else + elm.style.borderColor = ''; + + elm.style.backgroundColor = bgcolor; + elm.style.height = getCSSSize(height); + + inst.addVisual(); + + // Fix for stange MSIE align bug + //elm.outerHTML = elm.outerHTML; + + inst.nodeChanged(); + inst.execCommand('mceEndUndoLevel'); + + // Repaint if dimensions changed + if (formObj.width.value != orgTableWidth || formObj.height.value != orgTableHeight) + inst.execCommand('mceRepaint'); + + tinyMCEPopup.close(); + return true; + } + + // Create new table + html += '/g, '>'); + + return ' ' + attrib + '="' + value + '"'; +} + +function init() { + tinyMCEPopup.resizeToInnerSize(); + + document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table'); + document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table'); + document.getElementById('bordercolor_pickcontainer').innerHTML = getColorPickerHTML('bordercolor_pick','bordercolor'); + document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor'); + + var cols = 2, rows = 2, border = tinyMCEPopup.getParam('table_default_border', '0'), cellpadding = tinyMCEPopup.getParam('table_default_cellpadding', ''), cellspacing = tinyMCEPopup.getParam('table_default_cellspacing', ''); + var align = "", width = "", height = "", bordercolor = "", bgcolor = "", className = ""; + var id = "", summary = "", style = "", dir = "", lang = "", background = "", bgcolor = "", bordercolor = "", rules, frame; + var inst = tinyMCEPopup.editor, dom = inst.dom; + var formObj = document.forms[0]; + var elm = dom.getParent(inst.selection.getNode(), "table"); + + action = tinyMCEPopup.getWindowArg('action'); + + if (!action) + action = elm ? "update" : "insert"; + + if (elm && action != "insert") { + var rowsAr = elm.rows; + var cols = 0; + for (var i=0; i cols) + cols = rowsAr[i].cells.length; + + cols = cols; + rows = rowsAr.length; + + st = dom.parseStyle(dom.getAttrib(elm, "style")); + border = trimSize(getStyle(elm, 'border', 'borderWidth')); + cellpadding = dom.getAttrib(elm, 'cellpadding', ""); + cellspacing = dom.getAttrib(elm, 'cellspacing', ""); + width = trimSize(getStyle(elm, 'width', 'width')); + height = trimSize(getStyle(elm, 'height', 'height')); + bordercolor = convertRGBToHex(getStyle(elm, 'bordercolor', 'borderLeftColor')); + bgcolor = convertRGBToHex(getStyle(elm, 'bgcolor', 'backgroundColor')); + align = dom.getAttrib(elm, 'align', align); + frame = dom.getAttrib(elm, 'frame'); + rules = dom.getAttrib(elm, 'rules'); + className = tinymce.trim(dom.getAttrib(elm, 'class').replace(/mceItem.+/g, '')); + id = dom.getAttrib(elm, 'id'); + summary = dom.getAttrib(elm, 'summary'); + style = dom.serializeStyle(st); + dir = dom.getAttrib(elm, 'dir'); + lang = dom.getAttrib(elm, 'lang'); + background = getStyle(elm, 'background', 'backgroundImage').replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1"); + formObj.caption.checked = elm.getElementsByTagName('caption').length > 0; + + orgTableWidth = width; + orgTableHeight = height; + + action = "update"; + formObj.insert.value = inst.getLang('update'); + } + + addClassesToList('class', "table_styles"); + TinyMCE_EditableSelects.init(); + + // Update form + selectByValue(formObj, 'align', align); + selectByValue(formObj, 'frame', frame); + selectByValue(formObj, 'rules', rules); + selectByValue(formObj, 'class', className, true, true); + formObj.cols.value = cols; + formObj.rows.value = rows; + formObj.border.value = border; + formObj.cellpadding.value = cellpadding; + formObj.cellspacing.value = cellspacing; + formObj.width.value = width; + formObj.height.value = height; + formObj.bordercolor.value = bordercolor; + formObj.bgcolor.value = bgcolor; + formObj.id.value = id; + formObj.summary.value = summary; + formObj.style.value = style; + formObj.dir.value = dir; + formObj.lang.value = lang; + formObj.backgroundimage.value = background; + + updateColor('bordercolor_pick', 'bordercolor'); + updateColor('bgcolor_pick', 'bgcolor'); + + // Resize some elements + if (isVisible('backgroundimagebrowser')) + document.getElementById('backgroundimage').style.width = '180px'; + + // Disable some fields in update mode + if (action == "update") { + formObj.cols.disabled = true; + formObj.rows.disabled = true; + } +} + +function changedSize() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + +/* var width = formObj.width.value; + if (width != "") + st['width'] = tinyMCEPopup.getParam("inline_styles") ? getCSSSize(width) : ""; + else + st['width'] = "";*/ + + var height = formObj.height.value; + if (height != "") + st['height'] = getCSSSize(height); + else + st['height'] = ""; + + formObj.style.value = dom.serializeStyle(st); +} + +function changedBackgroundImage() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + + st['background-image'] = "url('" + formObj.backgroundimage.value + "')"; + + formObj.style.value = dom.serializeStyle(st); +} + +function changedBorder() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + + // Update border width if the element has a color + if (formObj.border.value != "" && formObj.bordercolor.value != "") + st['border-width'] = formObj.border.value + "px"; + + formObj.style.value = dom.serializeStyle(st); +} + +function changedColor() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + + st['background-color'] = formObj.bgcolor.value; + + if (formObj.bordercolor.value != "") { + st['border-color'] = formObj.bordercolor.value; + + // Add border-width if it's missing + if (!st['border-width']) + st['border-width'] = formObj.border.value == "" ? "1px" : formObj.border.value + "px"; + } + + formObj.style.value = dom.serializeStyle(st); +} + +function changedStyle() { + var formObj = document.forms[0]; + var st = dom.parseStyle(formObj.style.value); + + if (st['background-image']) + formObj.backgroundimage.value = st['background-image'].replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1"); + else + formObj.backgroundimage.value = ''; + + if (st['width']) + formObj.width.value = trimSize(st['width']); + + if (st['height']) + formObj.height.value = trimSize(st['height']); + + if (st['background-color']) { + formObj.bgcolor.value = st['background-color']; + updateColor('bgcolor_pick','bgcolor'); + } + + if (st['border-color']) { + formObj.bordercolor.value = st['border-color']; + updateColor('bordercolor_pick','bordercolor'); + } +} + +tinyMCEPopup.onInit.add(init); diff --git a/web/js/tiny_mce/plugins/table/langs/en_dlg.js b/web/js/tiny_mce/plugins/table/langs/en_dlg.js new file mode 100644 index 0000000..000332a --- /dev/null +++ b/web/js/tiny_mce/plugins/table/langs/en_dlg.js @@ -0,0 +1,74 @@ +tinyMCE.addI18n('en.table_dlg',{ +general_tab:"General", +advanced_tab:"Advanced", +general_props:"General properties", +advanced_props:"Advanced properties", +rowtype:"Row in table part", +title:"Insert/Modify table", +width:"Width", +height:"Height", +cols:"Cols", +rows:"Rows", +cellspacing:"Cellspacing", +cellpadding:"Cellpadding", +border:"Border", +align:"Alignment", +align_default:"Default", +align_left:"Left", +align_right:"Right", +align_middle:"Center", +row_title:"Table row properties", +cell_title:"Table cell properties", +cell_type:"Cell type", +valign:"Vertical alignment", +align_top:"Top", +align_bottom:"Bottom", +bordercolor:"Border color", +bgcolor:"Background color", +merge_cells_title:"Merge table cells", +id:"Id", +style:"Style", +langdir:"Language direction", +langcode:"Language code", +mime:"Target MIME type", +ltr:"Left to right", +rtl:"Right to left", +bgimage:"Background image", +summary:"Summary", +td:"Data", +th:"Header", +cell_cell:"Update current cell", +cell_row:"Update all cells in row", +cell_all:"Update all cells in table", +row_row:"Update current row", +row_odd:"Update odd rows in table", +row_even:"Update even rows in table", +row_all:"Update all rows in table", +thead:"Table Head", +tbody:"Table Body", +tfoot:"Table Foot", +scope:"Scope", +rowgroup:"Row Group", +colgroup:"Col Group", +col_limit:"You've exceeded the maximum number of columns of {$cols}.", +row_limit:"You've exceeded the maximum number of rows of {$rows}.", +cell_limit:"You've exceeded the maximum number of cells of {$cells}.", +missing_scope:"Are you sure you want to continue without specifying a scope for this table header cell. Without it, it may be difficult for some users with disabilities to understand the content or data displayed of the table.", +caption:"Table caption", +frame:"Frame", +frame_none:"none", +frame_groups:"groups", +frame_rows:"rows", +frame_cols:"cols", +frame_all:"all", +rules:"Rules", +rules_void:"void", +rules_above:"above", +rules_below:"below", +rules_hsides:"hsides", +rules_lhs:"lhs", +rules_rhs:"rhs", +rules_vsides:"vsides", +rules_box:"box", +rules_border:"border" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/table/langs/nb_dlg.js b/web/js/tiny_mce/plugins/table/langs/nb_dlg.js new file mode 100644 index 0000000..0add4d8 --- /dev/null +++ b/web/js/tiny_mce/plugins/table/langs/nb_dlg.js @@ -0,0 +1,74 @@ +tinyMCE.addI18n('nb.table_dlg',{ +general_tab:"Generelt", +advanced_tab:"Avansert", +general_props:"Generelt", +advanced_props:"Generelle egenskaper", +rowtype:"Rad i tabell", +title:"Sett inn / rediger tabell", +width:"Bredde", +height:"H\u00F8yde", +cols:"Kolonner", +rows:"Rader", +cellspacing:"Celleavstand", +cellpadding:"Cellefylling", +border:"Ramme", +align:"Justering", +align_default:"Standard", +align_left:"Venstre", +align_right:"H\u00F8yre", +align_middle:"Midtstilt", +row_title:"Radegenskaper", +cell_title:"Celleegenskaper", +cell_type:"Celletype", +valign:"Vertikal justering", +align_top:"Topp", +align_bottom:"Bunn", +bordercolor:"Rammefarge", +bgcolor:"Bakgrunn", +merge_cells_title:"Sl\u00E5 sammen celler", +id:"Id", +style:"Stil", +langdir:"Skriftretning", +langcode:"Spr\u00E5kkode", +mime:"M\u00E5lets MIME-type", +ltr:"Venstre mot h\u00F8yre", +rtl:"H\u00F8yre mot venstre", +bgimage:"Bakgrunnsbilde", +summary:"Sammendrag", +td:"Data", +th:"Overskrift", +cell_cell:"Oppdater aktuell celle", +cell_row:"Oppdater alle celler i raden", +cell_all:"Oppdater alle celler i tabellen", +row_row:"Oppdater aktuell rad", +row_odd:"Oppdater oddetallsrader", +row_even:"Oppdater partallsrader", +row_all:"Oppdater alle rader", +thead:"Tabellhode", +tbody:"Tabellkropp", +tfoot:"Tabellfot", +scope:"Omr\u00E5de", +rowgroup:"Radgruppe", +colgroup:"Kolonnegruppe", +col_limit:"Du har overskredet maksimalt antall kolonner p\u00E5 {$cols}.", +row_limit:"Du har overskredet maksimalt antall rader p\u00E5 {$rows}.", +cell_limit:"Du har overskredet maksimalt antall celler p\u00E5 {$cells}.", +missing_scope:"Er du sikker p\u00E5 at du vil fortsette uten \u00E5 angi et omr\u00E5de for denne overskrifscellen? Uten dette kan det bli vanskelig for enkelte funksjonshemmede brukere \u00E5 forst\u00E5 innholdet eller dataene som blir presentert i tabellen.", +caption:"Tabelloverskrift", +frame:"Ramme", +frame_none:"ingen", +frame_groups:"grupper", +frame_rows:"rader", +frame_cols:"kolonner", +frame_all:"alle", +rules:"Streker", +rules_void:"ingen", +rules_above:"over", +rules_below:"under", +rules_hsides:"hsider", +rules_lhs:"lhs", +rules_rhs:"rhs", +rules_vsides:"vsides", +rules_box:"boks", +rules_border:"ramme" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/table/langs/nn_dlg.js b/web/js/tiny_mce/plugins/table/langs/nn_dlg.js new file mode 100644 index 0000000..f708b2b --- /dev/null +++ b/web/js/tiny_mce/plugins/table/langs/nn_dlg.js @@ -0,0 +1,74 @@ +tinyMCE.addI18n('nn.table_dlg',{ +general_tab:"Generelt", +advanced_tab:"Avansert", +general_props:"Generelt", +advanced_props:"Generelle eigenskapar", +rowtype:"Rad i tabell", +title:"Set inn / rediger tabell", +width:"Breidd", +height:"H\u00F8gd", +cols:"Kolonner", +rows:"Rader", +cellspacing:"Celleavstand", +cellpadding:"Cellefylling", +border:"Ramme", +align:"Justering", +align_default:"Standard", +align_left:"Venstre", +align_right:"H\u00F8gre", +align_middle:"Midtstilt", +row_title:"Radeigenskapar", +cell_title:"Celleeigenskapar", +cell_type:"Celletype", +valign:"Vertikal justering", +align_top:"Topp", +align_bottom:"Botn", +bordercolor:"Rammefarge", +bgcolor:"Bakgrunn", +merge_cells_title:"Sl\u00E5 saman celler", +id:"Id", +style:"Stil", +langdir:"Skriftretning", +langcode:"Spr\u00E5kkode", +mime:"M\u00E5let sin MIME-type", +ltr:"Venstre mot h\u00F8gre", +rtl:"H\u00F8gre mot venstre", +bgimage:"Bakgrunnsbilete", +summary:"Samandrag", +td:"Data", +th:"Overskrift", +cell_cell:"Oppdater aktuell celle", +cell_row:"Oppdater alle celler i rada", +cell_all:"Oppdater alle celler i tabellen", +row_row:"Oppdater aktuell rad", +row_odd:"Oppdater oddetallrader", +row_even:"Oppdater partallrader", +row_all:"Oppdater alle rader", +thead:"Tabellhovud", +tbody:"Tabellkropp", +tfoot:"Tabellfot", +scope:"Omr\u00E5de", +rowgroup:"Radgruppe", +colgroup:"Kolonnegruppe", +col_limit:"Du har fleire enn maksimalt tal kolonner p\u00E5 {$cols}.", +row_limit:"Du har fleire enn maksimalt tal rader p\u00E5 {$rows}.", +cell_limit:"Du har fleire enn maksimalt tal celler p\u00E5 {$cells}.", +missing_scope:"Er du sikker p\u00E5 at du vil fortsetje utan \u00E5 angi eit omr\u00E5de for denne overskrifscella? Utan dette kan det bli vanskeleg for enkelte funksjonshemma brukarar \u00E5 forst\u00E5 innhaldet eller dataane som blir presenterte i tabellen.", +caption:"Tabelloverskrift", +frame:"Ramme", +frame_none:"ingen", +frame_groups:"grupper", +frame_rows:"rader", +frame_cols:"kolonnar", +frame_all:"alle", +rules:"Strekar", +rules_void:"ingen", +rules_above:"over", +rules_below:"under", +rules_hsides:"hsides", +rules_lhs:"lhs", +rules_rhs:"rhs", +rules_vsides:"vsides", +rules_box:"boks", +rules_border:"ramme" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/table/merge_cells.htm b/web/js/tiny_mce/plugins/table/merge_cells.htm new file mode 100644 index 0000000..30af106 --- /dev/null +++ b/web/js/tiny_mce/plugins/table/merge_cells.htm @@ -0,0 +1,38 @@ + + + + {#table_dlg.merge_cells_title} + + + + + + + +
    +
    + {#table_dlg.merge_cells_title} + + + + + + + + + +
    {#table_dlg.cols}:
    {#table_dlg.rows}:
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/table/row.htm b/web/js/tiny_mce/plugins/table/row.htm new file mode 100644 index 0000000..00dd356 --- /dev/null +++ b/web/js/tiny_mce/plugins/table/row.htm @@ -0,0 +1,161 @@ + + + + {#table_dlg.row_title} + + + + + + + + + +
    + + +
    +
    +
    + {#table_dlg.general_props} + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + +
    + +
    +
    +
    + +
    +
    + {#table_dlg.advanced_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + + + +
     
    +
    + + + + + +
     
    +
    +
    +
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/table/table.htm b/web/js/tiny_mce/plugins/table/table.htm new file mode 100644 index 0000000..446c909 --- /dev/null +++ b/web/js/tiny_mce/plugins/table/table.htm @@ -0,0 +1,193 @@ + + + + {#table_dlg.title} + + + + + + + + + + +
    + + +
    +
    +
    + {#table_dlg.general_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    + {#table_dlg.advanced_props} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + + +
     
    +
    + +
    + +
    + +
    + + + + + +
     
    +
    + + + + + +
     
    +
    +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/template/blank.htm b/web/js/tiny_mce/plugins/template/blank.htm new file mode 100644 index 0000000..ecde53f --- /dev/null +++ b/web/js/tiny_mce/plugins/template/blank.htm @@ -0,0 +1,12 @@ + + + blank_page + + + + + + + diff --git a/web/js/tiny_mce/plugins/template/css/template.css b/web/js/tiny_mce/plugins/template/css/template.css new file mode 100644 index 0000000..2d23a49 --- /dev/null +++ b/web/js/tiny_mce/plugins/template/css/template.css @@ -0,0 +1,23 @@ +#frmbody { + padding: 10px; + background-color: #FFF; + border: 1px solid #CCC; +} + +.frmRow { + margin-bottom: 10px; +} + +#templatesrc { + border: none; + width: 320px; + height: 240px; +} + +.title { + padding-bottom: 5px; +} + +.mceActionPanel { + padding-top: 5px; +} diff --git a/web/js/tiny_mce/plugins/template/editor_plugin.js b/web/js/tiny_mce/plugins/template/editor_plugin.js new file mode 100644 index 0000000..0f7fb01 --- /dev/null +++ b/web/js/tiny_mce/plugins/template/editor_plugin.js @@ -0,0 +1 @@ +(function(){var each=tinymce.each;tinymce.create('tinymce.plugins.TemplatePlugin',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mceTemplate',function(ui){ed.windowManager.open({file:url+'/template.htm',width:ed.getParam('template_popup_width',750),height:ed.getParam('template_popup_height',600),inline:1},{plugin_url:url});});ed.addCommand('mceInsertTemplate',t._insertTemplate,t);ed.addButton('template',{title:'template.desc',cmd:'mceTemplate'});ed.onPreProcess.add(function(ed,o){var dom=ed.dom;each(dom.select('div',o.node),function(e){if(dom.hasClass(e,'mceTmpl')){each(dom.select('*',e),function(e){if(dom.hasClass(e,ed.getParam('template_mdate_classes','mdate').replace(/\s+/g,'|')))e.innerHTML=t._getDateTime(new Date(),ed.getParam("template_mdate_format",ed.getLang("template.mdate_format")));});t._replaceVals(e);}});});},getInfo:function(){return{longname:'Template plugin',author:'Moxiecode Systems AB',authorurl:'http://www.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/template',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_insertTemplate:function(ui,v){var t=this,ed=t.editor,h,el,dom=ed.dom,sel=ed.selection.getContent();h=v.content;each(t.editor.getParam('template_replace_values'),function(v,k){if(typeof(v)!='function')h=h.replace(new RegExp('\\{\\$'+k+'\\}','g'),v);});el=dom.create('div',null,h);n=dom.select('.mceTmpl',el);if(n&&n.length>0){el=dom.create('div',null);el.appendChild(n[0].cloneNode(true));}function hasClass(n,c){return new RegExp('\\b'+c+'\\b','g').test(n.className);};each(dom.select('*',el),function(n){if(hasClass(n,ed.getParam('template_cdate_classes','cdate').replace(/\s+/g,'|')))n.innerHTML=t._getDateTime(new Date(),ed.getParam("template_cdate_format",ed.getLang("template.cdate_format")));if(hasClass(n,ed.getParam('template_mdate_classes','mdate').replace(/\s+/g,'|')))n.innerHTML=t._getDateTime(new Date(),ed.getParam("template_mdate_format",ed.getLang("template.mdate_format")));if(hasClass(n,ed.getParam('template_selected_content_classes','selcontent').replace(/\s+/g,'|')))n.innerHTML=sel;});t._replaceVals(el);ed.execCommand('mceInsertContent',false,el.innerHTML);ed.addVisual();},_replaceVals:function(e){var dom=this.editor.dom,vl=this.editor.getParam('template_replace_values');each(dom.select('*',e),function(e){each(vl,function(v,k){if(dom.hasClass(e,k)){if(typeof(vl[k])=='function')vl[k](e);}});});},_getDateTime:function(d,fmt){if(!fmt)return"";function addZeros(value,len){var i;value=""+value;if(value.length 0) { + el = dom.create('div', null); + el.appendChild(n[0].cloneNode(true)); + } + + function hasClass(n, c) { + return new RegExp('\\b' + c + '\\b', 'g').test(n.className); + }; + + each(dom.select('*', el), function(n) { + // Replace cdate + if (hasClass(n, ed.getParam('template_cdate_classes', 'cdate').replace(/\s+/g, '|'))) + n.innerHTML = t._getDateTime(new Date(), ed.getParam("template_cdate_format", ed.getLang("template.cdate_format"))); + + // Replace mdate + if (hasClass(n, ed.getParam('template_mdate_classes', 'mdate').replace(/\s+/g, '|'))) + n.innerHTML = t._getDateTime(new Date(), ed.getParam("template_mdate_format", ed.getLang("template.mdate_format"))); + + // Replace selection + if (hasClass(n, ed.getParam('template_selected_content_classes', 'selcontent').replace(/\s+/g, '|'))) + n.innerHTML = sel; + }); + + t._replaceVals(el); + + ed.execCommand('mceInsertContent', false, el.innerHTML); + ed.addVisual(); + }, + + _replaceVals : function(e) { + var dom = this.editor.dom, vl = this.editor.getParam('template_replace_values'); + + each(dom.select('*', e), function(e) { + each(vl, function(v, k) { + if (dom.hasClass(e, k)) { + if (typeof(vl[k]) == 'function') + vl[k](e); + } + }); + }); + }, + + _getDateTime : function(d, fmt) { + if (!fmt) + return ""; + + function addZeros(value, len) { + var i; + + value = "" + value; + + if (value.length < len) { + for (i=0; i<(len-value.length); i++) + value = "0" + value; + } + + return value; + } + + fmt = fmt.replace("%D", "%m/%d/%y"); + fmt = fmt.replace("%r", "%I:%M:%S %p"); + fmt = fmt.replace("%Y", "" + d.getFullYear()); + fmt = fmt.replace("%y", "" + d.getYear()); + fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2)); + fmt = fmt.replace("%d", addZeros(d.getDate(), 2)); + fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2)); + fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2)); + fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2)); + fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1)); + fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM")); + fmt = fmt.replace("%B", "" + tinyMCE.getLang("template_months_long").split(',')[d.getMonth()]); + fmt = fmt.replace("%b", "" + tinyMCE.getLang("template_months_short").split(',')[d.getMonth()]); + fmt = fmt.replace("%A", "" + tinyMCE.getLang("template_day_long").split(',')[d.getDay()]); + fmt = fmt.replace("%a", "" + tinyMCE.getLang("template_day_short").split(',')[d.getDay()]); + fmt = fmt.replace("%%", "%"); + + return fmt; + } + }); + + // Register plugin + tinymce.PluginManager.add('template', tinymce.plugins.TemplatePlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/template/js/template.js b/web/js/tiny_mce/plugins/template/js/template.js new file mode 100644 index 0000000..a8e64b1 --- /dev/null +++ b/web/js/tiny_mce/plugins/template/js/template.js @@ -0,0 +1,100 @@ +tinyMCEPopup.requireLangPack(); + +var TemplateDialog = { + preInit : function() { + var url = tinyMCEPopup.getParam("template_external_list_url"); + + if (url != null) + document.write(''); + }, + + init : function() { + var ed = tinyMCEPopup.editor, tsrc, sel, x, u; + + tsrc = ed.getParam("template_templates", false); + sel = document.getElementById('tpath'); + + // Setup external template list + if (!tsrc && typeof(tinyMCETemplateList) != 'undefined') { + for (x=0, tsrc = []; x'); + }); + }, + + selectTemplate : function(u) { + var d = window.frames['templatesrc'].document; + + if (!u) + return; + + d.body.innerHTML = this.templateHTML = this.getFileContents(u); + }, + + insert : function() { + tinyMCEPopup.execCommand('mceInsertTemplate', false, { + content : this.templateHTML, + selection : tinyMCEPopup.editor.selection.getContent() + }); + + tinyMCEPopup.close(); + }, + + getFileContents : function(u) { + var x, d, t = 'text/plain'; + + function g(s) { + x = 0; + + try { + x = new ActiveXObject(s); + } catch (s) { + } + + return x; + }; + + x = window.ActiveXObject ? g('Msxml2.XMLHTTP') || g('Microsoft.XMLHTTP') : new XMLHttpRequest(); + + // Synchronous AJAX load file + x.overrideMimeType && x.overrideMimeType(t); + x.open("GET", u, false); + x.send(null); + + return x.responseText; + } +}; + +TemplateDialog.preInit(); +tinyMCEPopup.onInit.add(TemplateDialog.init, TemplateDialog); diff --git a/web/js/tiny_mce/plugins/template/langs/en_dlg.js b/web/js/tiny_mce/plugins/template/langs/en_dlg.js new file mode 100644 index 0000000..2471c3f --- /dev/null +++ b/web/js/tiny_mce/plugins/template/langs/en_dlg.js @@ -0,0 +1,15 @@ +tinyMCE.addI18n('en.template_dlg',{ +title:"Templates", +label:"Template", +desc_label:"Description", +desc:"Insert predefined template content", +select:"Select a template", +preview:"Preview", +warning:"Warning: Updating a template with a different one may cause data loss.", +mdate_format:"%Y-%m-%d %H:%M:%S", +cdate_format:"%Y-%m-%d %H:%M:%S", +months_long:"January,February,March,April,May,June,July,August,September,October,November,December", +months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec", +day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday", +day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/template/langs/nb_dlg.js b/web/js/tiny_mce/plugins/template/langs/nb_dlg.js new file mode 100644 index 0000000..ef4e41e --- /dev/null +++ b/web/js/tiny_mce/plugins/template/langs/nb_dlg.js @@ -0,0 +1,15 @@ +tinyMCE.addI18n('nb.template_dlg',{ +title:"Maler", +label:"Mal", +desc_label:"Beskrivelse", +desc:"Sett inn forh\u00E5ndsdefinert malinnhold", +select:"Velg en mal", +preview:"Forh\u00E5ndsvisning", +warning:"Advarsel: Utskifting av en mal med en annen kan f\u00F8re til at data g\u00E5r tapt.", +mdate_format:"%Y-%m-%d %H:%M:%S", +cdate_format:"%Y-%m-%d %H:%M:%S", +months_long:"januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember", +months_short:"jan,feb,mar,apr,mai,jun,jul,aug,sep,okt,nov,des", +day_long:"s\u00F8ndag,mandag,tirsdag,onsdag,torsdag,fredag,l\u00F8rdag,s\u00F8ndag", +day_short:"s\u00F8n,man,tir,ons,tor,fre,l\u00F8r,s\u00F8n" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/template/langs/nn_dlg.js b/web/js/tiny_mce/plugins/template/langs/nn_dlg.js new file mode 100644 index 0000000..55afd4d --- /dev/null +++ b/web/js/tiny_mce/plugins/template/langs/nn_dlg.js @@ -0,0 +1,15 @@ +tinyMCE.addI18n('nn.template_dlg',{ +title:"Malar", +label:"Mal", +desc_label:"Omtale", +desc:"Set inn f\u00F8rehandsdefinert malinnhald", +select:"Vel ein mal", +preview:"Sj\u00E5 f\u00F8rebels utkast", +warning:"\u00C5tvaring: Utskifting av ein mal med ein annen kan f\u00F8re til at data g\u00E5r tapt.", +mdate_format:"%Y-%m-%d %H:%M:%S", +cdate_format:"%Y-%m-%d %H:%M:%S", +months_long:"januar,februar,mars,april,mai,juni,juli,august,september,oktober,november,desember", +months_short:"jan,feb,mar,apr,mai,jun,jul,aug,sep,okt,nov,des", +day_long:"sundag,mandag,tirsdag,onsdag,torsdag,fredag,laurdag,sundag", +day_short:"sun,man,tir,ons,tor,fre,l\u00F8r,sun" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/template/template.htm b/web/js/tiny_mce/plugins/template/template.htm new file mode 100644 index 0000000..e26a2a9 --- /dev/null +++ b/web/js/tiny_mce/plugins/template/template.htm @@ -0,0 +1,39 @@ + + + {#template_dlg.title} + + + + + + +
    +
    +
    {#template_dlg.desc}
    +
    + +
    +
    +
    +
    + {#template_dlg.preview} + +
    +
    + +
    +
    + +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/plugins/upload/editor_plugin.js b/web/js/tiny_mce/plugins/upload/editor_plugin.js new file mode 100644 index 0000000..02216ca --- /dev/null +++ b/web/js/tiny_mce/plugins/upload/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.UploadPlugin',{init:function(ed,url){ed.addCommand('mceUpload',function(){ed.windowManager.open({file:document.getElementById("popup_id").value+'/browse/',width:620+parseInt(ed.getLang('upload.delta_width',0)),height:420+parseInt(ed.getLang('upload.delta_height',0)),inline:1},{plugin_url:url})});ed.addButton('upload',{title:'Attach a file to article',cmd:'mceUpload',image:url+'/img/upload.gif'});ed.onNodeChange.add(function(ed,cm,n){cm.setActive('upload',n.nodeName=='IMG')})},getInfo:function(){return{longname:'Fileupload and browse plugin',author:'Hannes Magnusson',authorurl:'http://linpro.no',version:"0.9"}}});tinymce.PluginManager.add('upload',tinymce.plugins.UploadPlugin)})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/upload/editor_plugin_src.js b/web/js/tiny_mce/plugins/upload/editor_plugin_src.js new file mode 100644 index 0000000..e06278e --- /dev/null +++ b/web/js/tiny_mce/plugins/upload/editor_plugin_src.js @@ -0,0 +1,41 @@ + +(function() { + tinymce.create('tinymce.plugins.UploadPlugin', { + init : function(ed, url) { + ed.addCommand('mceUpload', function() { + ed.windowManager.open({ + file : document.getElementById("popup_id").value + '/browse/', + width : 620 + parseInt(ed.getLang('upload.delta_width', 0)), + height : 420 + parseInt(ed.getLang('upload.delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + // Register upload button + ed.addButton('upload', { + title : 'Attach a file to article', + cmd : 'mceUpload', + image : url + '/img/upload.gif' + }); + + // Add a node change handler, selects the button in the UI when a image is selected + ed.onNodeChange.add(function(ed, cm, n) { + cm.setActive('upload', n.nodeName == 'IMG'); + }); + }, + + getInfo : function() { + return { + longname : 'Fileupload and browse plugin', + author : 'Hannes Magnusson', + authorurl : 'http://linpro.no', + version : "0.9" + }; + } + }); + + tinymce.PluginManager.add('upload', tinymce.plugins.UploadPlugin); +})(); + diff --git a/web/js/tiny_mce/plugins/upload/img/upload.gif b/web/js/tiny_mce/plugins/upload/img/upload.gif new file mode 100644 index 0000000..9a71cee Binary files /dev/null and b/web/js/tiny_mce/plugins/upload/img/upload.gif differ diff --git a/web/js/tiny_mce/plugins/visualchars/editor_plugin.js b/web/js/tiny_mce/plugins/visualchars/editor_plugin.js new file mode 100644 index 0000000..e1e4238 --- /dev/null +++ b/web/js/tiny_mce/plugins/visualchars/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.VisualChars',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mceVisualChars',t._toggleVisualChars,t);ed.addButton('visualchars',{title:'visualchars.desc',cmd:'mceVisualChars'});ed.onBeforeGetContent.add(function(ed,o){if(t.state){t.state=true;t._toggleVisualChars();}});},getInfo:function(){return{longname:'Visual characters',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualchars',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_toggleVisualChars:function(){var t=this,ed=t.editor,nl,i,h,d=ed.getDoc(),b=ed.getBody(),nv,s=ed.selection,bo;t.state=!t.state;ed.controlManager.setActive('visualchars',t.state);if(t.state){nl=[];tinymce.walk(b,function(n){if(n.nodeType==3&&n.nodeValue&&n.nodeValue.indexOf('\u00a0')!=-1)nl.push(n);},'childNodes');for(i=0;i$1');nv=nv.replace(/\u00a0/g,'\u00b7');ed.dom.setOuterHTML(nl[i],nv,d);}}else{nl=tinymce.grep(ed.dom.select('span',b),function(n){return ed.dom.hasClass(n,'mceVisualNbsp');});for(i=0;i$1'); + nv = nv.replace(/\u00a0/g, '\u00b7'); + ed.dom.setOuterHTML(nl[i], nv, d); + } + } else { + nl = tinymce.grep(ed.dom.select('span', b), function(n) { + return ed.dom.hasClass(n, 'mceVisualNbsp'); + }); + + for (i=0; i + + + {#xhtmlxtras_dlg.title_abbr_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/acronym.htm b/web/js/tiny_mce/plugins/xhtmlxtras/acronym.htm new file mode 100644 index 0000000..03394f6 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/acronym.htm @@ -0,0 +1,149 @@ + + + + {#xhtmlxtras_dlg.title_acronym_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/attributes.htm b/web/js/tiny_mce/plugins/xhtmlxtras/attributes.htm new file mode 100644 index 0000000..27c829c --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/attributes.htm @@ -0,0 +1,154 @@ + + + + {#xhtmlxtras_dlg.attribs_title} + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.attribute_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.attribute_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    + + diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/cite.htm b/web/js/tiny_mce/plugins/xhtmlxtras/cite.htm new file mode 100644 index 0000000..11f96fa --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/cite.htm @@ -0,0 +1,149 @@ + + + + {#xhtmlxtras_dlg.title_cite_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/css/attributes.css b/web/js/tiny_mce/plugins/xhtmlxtras/css/attributes.css new file mode 100644 index 0000000..9a6a235 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/css/attributes.css @@ -0,0 +1,11 @@ +.panel_wrapper div.current { + height: 290px; +} + +#id, #style, #title, #dir, #hreflang, #lang, #classlist, #tabindex, #accesskey { + width: 200px; +} + +#events_panel input { + width: 200px; +} diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/css/popup.css b/web/js/tiny_mce/plugins/xhtmlxtras/css/popup.css new file mode 100644 index 0000000..e67114d --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/css/popup.css @@ -0,0 +1,9 @@ +input.field, select.field {width:200px;} +input.picker {width:179px; margin-left: 5px;} +input.disabled {border-color:#F2F2F2;} +img.picker {vertical-align:text-bottom; cursor:pointer;} +h1 {padding: 0 0 5px 0;} +.panel_wrapper div.current {height:160px;} +#xhtmlxtrasdel .panel_wrapper div.current, #xhtmlxtrasins .panel_wrapper div.current {height: 230px;} +a.browse span {display:block; width:20px; height:20px; background:url('../../../themes/advanced/img/icons.gif') -140px -20px;} +#datetime {width:180px;} diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/css/xhtmlxtras.css b/web/js/tiny_mce/plugins/xhtmlxtras/css/xhtmlxtras.css new file mode 100644 index 0000000..6838d90 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/css/xhtmlxtras.css @@ -0,0 +1,24 @@ +ins { + border-bottom: 1px solid green; + text-decoration: none; + color: green; +} + +del { + color: Red; + text-decoration: line-through; +} + +cite { + border-bottom: 1px dashed blue; +} + +acronym { + border-bottom: 1px dotted #CCC; + cursor: help; +} + +abbr, html\:abbr { + border-bottom: 1px dashed #CCC; + cursor: help; +} diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/del.htm b/web/js/tiny_mce/plugins/xhtmlxtras/del.htm new file mode 100644 index 0000000..a29588b --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/del.htm @@ -0,0 +1,170 @@ + + + + {#xhtmlxtras_dlg.title_del_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_general_tab} + + + + + + + + + +
    : + + + + + +
    +
    :
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + + diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/editor_plugin.js b/web/js/tiny_mce/plugins/xhtmlxtras/editor_plugin.js new file mode 100644 index 0000000..6a3270d --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/editor_plugin.js @@ -0,0 +1 @@ +(function(){tinymce.create('tinymce.plugins.XHTMLXtrasPlugin',{init:function(ed,url){ed.addCommand('mceCite',function(){ed.windowManager.open({file:url+'/cite.htm',width:350+parseInt(ed.getLang('xhtmlxtras.cite_delta_width',0)),height:250+parseInt(ed.getLang('xhtmlxtras.cite_delta_height',0)),inline:1},{plugin_url:url});});ed.addCommand('mceAcronym',function(){ed.windowManager.open({file:url+'/acronym.htm',width:350+parseInt(ed.getLang('xhtmlxtras.acronym_delta_width',0)),height:250+parseInt(ed.getLang('xhtmlxtras.acronym_delta_width',0)),inline:1},{plugin_url:url});});ed.addCommand('mceAbbr',function(){ed.windowManager.open({file:url+'/abbr.htm',width:350+parseInt(ed.getLang('xhtmlxtras.abbr_delta_width',0)),height:250+parseInt(ed.getLang('xhtmlxtras.abbr_delta_width',0)),inline:1},{plugin_url:url});});ed.addCommand('mceDel',function(){ed.windowManager.open({file:url+'/del.htm',width:340+parseInt(ed.getLang('xhtmlxtras.del_delta_width',0)),height:310+parseInt(ed.getLang('xhtmlxtras.del_delta_width',0)),inline:1},{plugin_url:url});});ed.addCommand('mceIns',function(){ed.windowManager.open({file:url+'/ins.htm',width:340+parseInt(ed.getLang('xhtmlxtras.ins_delta_width',0)),height:310+parseInt(ed.getLang('xhtmlxtras.ins_delta_width',0)),inline:1},{plugin_url:url});});ed.addCommand('mceAttributes',function(){ed.windowManager.open({file:url+'/attributes.htm',width:380,height:370,inline:1},{plugin_url:url});});ed.addButton('cite',{title:'xhtmlxtras.cite_desc',cmd:'mceCite'});ed.addButton('acronym',{title:'xhtmlxtras.acronym_desc',cmd:'mceAcronym'});ed.addButton('abbr',{title:'xhtmlxtras.abbr_desc',cmd:'mceAbbr'});ed.addButton('del',{title:'xhtmlxtras.del_desc',cmd:'mceDel'});ed.addButton('ins',{title:'xhtmlxtras.ins_desc',cmd:'mceIns'});ed.addButton('attribs',{title:'xhtmlxtras.attribs_desc',cmd:'mceAttributes'});if(tinymce.isIE){function fix(ed,o){if(o.set){o.content=o.content.replace(/]+)>/gi,'');o.content=o.content.replace(/<\/abbr>/gi,'');}};ed.onBeforeSetContent.add(fix);ed.onPostProcess.add(fix);}ed.onNodeChange.add(function(ed,cm,n,co){n=ed.dom.getParent(n,'CITE,ACRONYM,ABBR,DEL,INS');cm.setDisabled('cite',co);cm.setDisabled('acronym',co);cm.setDisabled('abbr',co);cm.setDisabled('del',co);cm.setDisabled('ins',co);cm.setDisabled('attribs',n&&n.nodeName=='BODY');if(n){cm.setDisabled(n.nodeName.toLowerCase(),0);cm.setActive(n.nodeName.toLowerCase(),1);}else{cm.setActive('cite',0);cm.setActive('acronym',0);cm.setActive('abbr',0);cm.setActive('del',0);cm.setActive('ins',0);}});},getInfo:function(){return{longname:'XHTML Xtras Plugin',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('xhtmlxtras',tinymce.plugins.XHTMLXtrasPlugin);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js b/web/js/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js new file mode 100644 index 0000000..143ed92 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/editor_plugin_src.js @@ -0,0 +1,134 @@ +/** + * $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + tinymce.create('tinymce.plugins.XHTMLXtrasPlugin', { + init : function(ed, url) { + // Register commands + ed.addCommand('mceCite', function() { + ed.windowManager.open({ + file : url + '/cite.htm', + width : 350 + parseInt(ed.getLang('xhtmlxtras.cite_delta_width', 0)), + height : 250 + parseInt(ed.getLang('xhtmlxtras.cite_delta_height', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceAcronym', function() { + ed.windowManager.open({ + file : url + '/acronym.htm', + width : 350 + parseInt(ed.getLang('xhtmlxtras.acronym_delta_width', 0)), + height : 250 + parseInt(ed.getLang('xhtmlxtras.acronym_delta_width', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceAbbr', function() { + ed.windowManager.open({ + file : url + '/abbr.htm', + width : 350 + parseInt(ed.getLang('xhtmlxtras.abbr_delta_width', 0)), + height : 250 + parseInt(ed.getLang('xhtmlxtras.abbr_delta_width', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceDel', function() { + ed.windowManager.open({ + file : url + '/del.htm', + width : 340 + parseInt(ed.getLang('xhtmlxtras.del_delta_width', 0)), + height : 310 + parseInt(ed.getLang('xhtmlxtras.del_delta_width', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceIns', function() { + ed.windowManager.open({ + file : url + '/ins.htm', + width : 340 + parseInt(ed.getLang('xhtmlxtras.ins_delta_width', 0)), + height : 310 + parseInt(ed.getLang('xhtmlxtras.ins_delta_width', 0)), + inline : 1 + }, { + plugin_url : url + }); + }); + + ed.addCommand('mceAttributes', function() { + ed.windowManager.open({ + file : url + '/attributes.htm', + width : 380, + height : 370, + inline : 1 + }, { + plugin_url : url + }); + }); + + // Register buttons + ed.addButton('cite', {title : 'xhtmlxtras.cite_desc', cmd : 'mceCite'}); + ed.addButton('acronym', {title : 'xhtmlxtras.acronym_desc', cmd : 'mceAcronym'}); + ed.addButton('abbr', {title : 'xhtmlxtras.abbr_desc', cmd : 'mceAbbr'}); + ed.addButton('del', {title : 'xhtmlxtras.del_desc', cmd : 'mceDel'}); + ed.addButton('ins', {title : 'xhtmlxtras.ins_desc', cmd : 'mceIns'}); + ed.addButton('attribs', {title : 'xhtmlxtras.attribs_desc', cmd : 'mceAttributes'}); + + if (tinymce.isIE) { + function fix(ed, o) { + if (o.set) { + o.content = o.content.replace(/]+)>/gi, ''); + o.content = o.content.replace(/<\/abbr>/gi, ''); + } + }; + + ed.onBeforeSetContent.add(fix); + ed.onPostProcess.add(fix); + } + + ed.onNodeChange.add(function(ed, cm, n, co) { + n = ed.dom.getParent(n, 'CITE,ACRONYM,ABBR,DEL,INS'); + + cm.setDisabled('cite', co); + cm.setDisabled('acronym', co); + cm.setDisabled('abbr', co); + cm.setDisabled('del', co); + cm.setDisabled('ins', co); + cm.setDisabled('attribs', n && n.nodeName == 'BODY'); + + if (n) { + cm.setDisabled(n.nodeName.toLowerCase(), 0); + cm.setActive(n.nodeName.toLowerCase(), 1); + } else { + cm.setActive('cite', 0); + cm.setActive('acronym', 0); + cm.setActive('abbr', 0); + cm.setActive('del', 0); + cm.setActive('ins', 0); + } + }); + }, + + getInfo : function() { + return { + longname : 'XHTML Xtras Plugin', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras', + version : tinymce.majorVersion + "." + tinymce.minorVersion + }; + } + }); + + // Register plugin + tinymce.PluginManager.add('xhtmlxtras', tinymce.plugins.XHTMLXtrasPlugin); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/ins.htm b/web/js/tiny_mce/plugins/xhtmlxtras/ins.htm new file mode 100644 index 0000000..0ea4838 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/ins.htm @@ -0,0 +1,170 @@ + + + + {#xhtmlxtras_dlg.title_ins_element} + + + + + + + + + + +
    + + +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_general_tab} + + + + + + + + + +
    : + + + + + +
    +
    :
    +
    +
    + {#xhtmlxtras_dlg.fieldset_attrib_tab} + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    : + +
    :
    : + +
    : + +
    +
    +
    +
    +
    + {#xhtmlxtras_dlg.fieldset_events_tab} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    :
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    + + + diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/js/abbr.js b/web/js/tiny_mce/plugins/xhtmlxtras/js/abbr.js new file mode 100644 index 0000000..e84b6a8 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/js/abbr.js @@ -0,0 +1,25 @@ + /** + * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $ + * + * @author Moxiecode - based on work by Andrew Tetlaw + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +function init() { + SXE.initElementDialog('abbr'); + if (SXE.currentAction == "update") { + SXE.showRemoveButton(); + } +} + +function insertAbbr() { + SXE.insertElement(tinymce.isIE ? 'html:abbr' : 'abbr'); + tinyMCEPopup.close(); +} + +function removeAbbr() { + SXE.removeElement('abbr'); + tinyMCEPopup.close(); +} + +tinyMCEPopup.onInit.add(init); diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/js/acronym.js b/web/js/tiny_mce/plugins/xhtmlxtras/js/acronym.js new file mode 100644 index 0000000..933d122 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/js/acronym.js @@ -0,0 +1,25 @@ + /** + * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $ + * + * @author Moxiecode - based on work by Andrew Tetlaw + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +function init() { + SXE.initElementDialog('acronym'); + if (SXE.currentAction == "update") { + SXE.showRemoveButton(); + } +} + +function insertAcronym() { + SXE.insertElement('acronym'); + tinyMCEPopup.close(); +} + +function removeAcronym() { + SXE.removeElement('acronym'); + tinyMCEPopup.close(); +} + +tinyMCEPopup.onInit.add(init); diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/js/attributes.js b/web/js/tiny_mce/plugins/xhtmlxtras/js/attributes.js new file mode 100644 index 0000000..23c7fa4 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/js/attributes.js @@ -0,0 +1,123 @@ + /** + * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $ + * + * @author Moxiecode - based on work by Andrew Tetlaw + * @copyright Copyright 2004-2006, Moxiecode Systems AB, All rights reserved. + */ + +function init() { + tinyMCEPopup.resizeToInnerSize(); + var inst = tinyMCEPopup.editor; + var dom = inst.dom; + var elm = inst.selection.getNode(); + var f = document.forms[0]; + var onclick = dom.getAttrib(elm, 'onclick'); + + setFormValue('title', dom.getAttrib(elm, 'title')); + setFormValue('id', dom.getAttrib(elm, 'id')); + setFormValue('style', dom.getAttrib(elm, "style")); + setFormValue('dir', dom.getAttrib(elm, 'dir')); + setFormValue('lang', dom.getAttrib(elm, 'lang')); + setFormValue('tabindex', dom.getAttrib(elm, 'tabindex', typeof(elm.tabindex) != "undefined" ? elm.tabindex : "")); + setFormValue('accesskey', dom.getAttrib(elm, 'accesskey', typeof(elm.accesskey) != "undefined" ? elm.accesskey : "")); + setFormValue('onfocus', dom.getAttrib(elm, 'onfocus')); + setFormValue('onblur', dom.getAttrib(elm, 'onblur')); + setFormValue('onclick', onclick); + setFormValue('ondblclick', dom.getAttrib(elm, 'ondblclick')); + setFormValue('onmousedown', dom.getAttrib(elm, 'onmousedown')); + setFormValue('onmouseup', dom.getAttrib(elm, 'onmouseup')); + setFormValue('onmouseover', dom.getAttrib(elm, 'onmouseover')); + setFormValue('onmousemove', dom.getAttrib(elm, 'onmousemove')); + setFormValue('onmouseout', dom.getAttrib(elm, 'onmouseout')); + setFormValue('onkeypress', dom.getAttrib(elm, 'onkeypress')); + setFormValue('onkeydown', dom.getAttrib(elm, 'onkeydown')); + setFormValue('onkeyup', dom.getAttrib(elm, 'onkeyup')); + className = dom.getAttrib(elm, 'class'); + + addClassesToList('classlist', 'advlink_styles'); + selectByValue(f, 'classlist', className, true); + + TinyMCE_EditableSelects.init(); +} + +function setFormValue(name, value) { + if(value && document.forms[0].elements[name]){ + document.forms[0].elements[name].value = value; + } +} + +function insertAction() { + var inst = tinyMCEPopup.editor; + var elm = inst.selection.getNode(); + + tinyMCEPopup.execCommand("mceBeginUndoLevel"); + setAllAttribs(elm); + tinyMCEPopup.execCommand("mceEndUndoLevel"); + tinyMCEPopup.close(); +} + +function setAttrib(elm, attrib, value) { + var formObj = document.forms[0]; + var valueElm = formObj.elements[attrib.toLowerCase()]; + var inst = tinyMCEPopup.editor; + var dom = inst.dom; + + if (typeof(value) == "undefined" || value == null) { + value = ""; + + if (valueElm) + value = valueElm.value; + } + + if (value != "") { + dom.setAttrib(elm, attrib.toLowerCase(), value); + + if (attrib == "style") + attrib = "style.cssText"; + + if (attrib.substring(0, 2) == 'on') + value = 'return true;' + value; + + if (attrib == "class") + attrib = "className"; + + elm[attrib]=value; + } else + elm.removeAttribute(attrib); +} + +function setAllAttribs(elm) { + var f = document.forms[0]; + + setAttrib(elm, 'title'); + setAttrib(elm, 'id'); + setAttrib(elm, 'style'); + setAttrib(elm, 'class', getSelectValue(f, 'classlist')); + setAttrib(elm, 'dir'); + setAttrib(elm, 'lang'); + setAttrib(elm, 'tabindex'); + setAttrib(elm, 'accesskey'); + setAttrib(elm, 'onfocus'); + setAttrib(elm, 'onblur'); + setAttrib(elm, 'onclick'); + setAttrib(elm, 'ondblclick'); + setAttrib(elm, 'onmousedown'); + setAttrib(elm, 'onmouseup'); + setAttrib(elm, 'onmouseover'); + setAttrib(elm, 'onmousemove'); + setAttrib(elm, 'onmouseout'); + setAttrib(elm, 'onkeypress'); + setAttrib(elm, 'onkeydown'); + setAttrib(elm, 'onkeyup'); + + // Refresh in old MSIE +// if (tinyMCE.isMSIE5) +// elm.outerHTML = elm.outerHTML; +} + +function insertAttribute() { + tinyMCEPopup.close(); +} + +tinyMCEPopup.onInit.add(init); +tinyMCEPopup.requireLangPack(); diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/js/cite.js b/web/js/tiny_mce/plugins/xhtmlxtras/js/cite.js new file mode 100644 index 0000000..c36f7fd --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/js/cite.js @@ -0,0 +1,25 @@ + /** + * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $ + * + * @author Moxiecode - based on work by Andrew Tetlaw + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +function init() { + SXE.initElementDialog('cite'); + if (SXE.currentAction == "update") { + SXE.showRemoveButton(); + } +} + +function insertCite() { + SXE.insertElement('cite'); + tinyMCEPopup.close(); +} + +function removeCite() { + SXE.removeElement('cite'); + tinyMCEPopup.close(); +} + +tinyMCEPopup.onInit.add(init); diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/js/del.js b/web/js/tiny_mce/plugins/xhtmlxtras/js/del.js new file mode 100644 index 0000000..005a619 --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/js/del.js @@ -0,0 +1,50 @@ + /** + * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $ + * + * @author Moxiecode - based on work by Andrew Tetlaw + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +function init() { + SXE.initElementDialog('del'); + if (SXE.currentAction == "update") { + setFormValue('datetime', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'datetime')); + setFormValue('cite', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'cite')); + SXE.showRemoveButton(); + } +} + +function setElementAttribs(elm) { + setAllCommonAttribs(elm); + setAttrib(elm, 'datetime'); + setAttrib(elm, 'cite'); +} + +function insertDel() { + var elm = tinyMCEPopup.editor.dom.getParent(SXE.focusElement, 'DEL'); + + tinyMCEPopup.execCommand('mceBeginUndoLevel'); + if (elm == null) { + var s = SXE.inst.selection.getContent(); + if(s.length > 0) { + tinyMCEPopup.execCommand('mceInsertContent', false, '' + s + ''); + var elementArray = tinymce.grep(SXE.inst.dom.select('del'), function(n) {return n.id == '#sxe_temp_del#';}); + for (var i=0; i 0) { + tagName = element_name; + + if (tinymce.isIE && element_name.indexOf('html:') == 0) + element_name = element_name.substring(5).toLowerCase(); + + h = '<' + tagName + ' id="#sxe_temp_' + element_name + '#">' + s + ''; + + tinyMCEPopup.execCommand('mceInsertContent', false, h); + + var elementArray = tinymce.grep(SXE.inst.dom.select(element_name), function(n) {return n.id == '#sxe_temp_' + element_name + '#';}); + for (var i=0; i -1) ? true : false; +} + +SXE.removeClass = function(elm,cl) { + if(elm.className == null || elm.className == "" || !SXE.containsClass(elm,cl)) { + return true; + } + var classNames = elm.className.split(" "); + var newClassNames = ""; + for (var x = 0, cnl = classNames.length; x < cnl; x++) { + if (classNames[x] != cl) { + newClassNames += (classNames[x] + " "); + } + } + elm.className = newClassNames.substring(0,newClassNames.length-1); //removes extra space at the end +} + +SXE.addClass = function(elm,cl) { + if(!SXE.containsClass(elm,cl)) elm.className ? elm.className += " " + cl : elm.className = cl; + return true; +} \ No newline at end of file diff --git a/web/js/tiny_mce/plugins/xhtmlxtras/js/ins.js b/web/js/tiny_mce/plugins/xhtmlxtras/js/ins.js new file mode 100644 index 0000000..b03ca1b --- /dev/null +++ b/web/js/tiny_mce/plugins/xhtmlxtras/js/ins.js @@ -0,0 +1,49 @@ + /** + * $Id: editor_plugin_src.js 42 2006-08-08 14:32:24Z spocke $ + * + * @author Moxiecode - based on work by Andrew Tetlaw + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +function init() { + SXE.initElementDialog('ins'); + if (SXE.currentAction == "update") { + setFormValue('datetime', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'datetime')); + setFormValue('cite', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'cite')); + SXE.showRemoveButton(); + } +} + +function setElementAttribs(elm) { + setAllCommonAttribs(elm); + setAttrib(elm, 'datetime'); + setAttrib(elm, 'cite'); +} + +function insertIns() { + var elm = tinyMCEPopup.editor.dom.getParent(SXE.focusElement, 'INS'); + tinyMCEPopup.execCommand('mceBeginUndoLevel'); + if (elm == null) { + var s = SXE.inst.selection.getContent(); + if(s.length > 0) { + tinyMCEPopup.execCommand('mceInsertContent', false, '' + s + ''); + var elementArray = tinymce.grep(SXE.inst.dom.select('ins'), function(n) {return n.id == '#sxe_temp_ins#';}); + for (var i=0; i + + + {#advanced_dlg.about_title} + + + + + + + +
    +
    +

    {#advanced_dlg.about_title}

    +

    Version: ()

    +

    TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor control released as Open Source under LGPL + by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.

    +

    Copyright © 2003-2008, Moxiecode Systems AB, All rights reserved.

    +

    For more information about this software visit the TinyMCE website.

    + +
    + Got Moxie? + Hosted By Sourceforge + Also on freshmeat +
    +
    + +
    +
    +

    {#advanced_dlg.about_loaded}

    + +
    +
    + +

     

    +
    +
    + +
    +
    +
    +
    + +
    +
    + +
    +
    + + diff --git a/web/js/tiny_mce/themes/advanced/anchor.htm b/web/js/tiny_mce/themes/advanced/anchor.htm new file mode 100644 index 0000000..5ba592d --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/anchor.htm @@ -0,0 +1,32 @@ + + + + {#advanced_dlg.anchor_title} + + + + + +
    + + + + + + + + +
    {#advanced_dlg.anchor_title}
    {#advanced_dlg.anchor_name}:
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/themes/advanced/charmap.htm b/web/js/tiny_mce/themes/advanced/charmap.htm new file mode 100644 index 0000000..21e84aa --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/charmap.htm @@ -0,0 +1,54 @@ + + + + {#advanced_dlg.charmap_title} + + + + + + + + + + + + + + + + + +
    {#advanced_dlg.charmap_title}
    + + + + + + + + + +
     
     
    +
    + + + + + + + + + + + + + + + + +
    HTML-Code
     
     
    NUM-Code
     
    +
    + + + diff --git a/web/js/tiny_mce/themes/advanced/color_picker.htm b/web/js/tiny_mce/themes/advanced/color_picker.htm new file mode 100644 index 0000000..21c8351 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/color_picker.htm @@ -0,0 +1,76 @@ + + + + {#advanced_dlg.colorpicker_title} + + + + + + +
    + + +
    +
    +
    + {#advanced_dlg.colorpicker_picker_title} +
    + + +
    + +
    + +
    +
    +
    +
    + +
    +
    + {#advanced_dlg.colorpicker_palette_title} +
    + +
    + +
    +
    +
    + +
    +
    + {#advanced_dlg.colorpicker_named_title} +
    + +
    + +
    + +
    + {#advanced_dlg.colorpicker_name} +
    +
    +
    +
    + +
    +
    + +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/themes/advanced/editor_template.js b/web/js/tiny_mce/themes/advanced/editor_template.js new file mode 100644 index 0000000..465a809 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/editor_template.js @@ -0,0 +1 @@ +(function(){var DOM=tinymce.DOM,Event=tinymce.dom.Event,extend=tinymce.extend,each=tinymce.each,Cookie=tinymce.util.Cookie,lastExtID,explode=tinymce.explode;tinymce.ThemeManager.requireLangPack('advanced');tinymce.create('tinymce.themes.AdvancedTheme',{controls:{bold:['bold_desc','Bold'],italic:['italic_desc','Italic'],underline:['underline_desc','Underline'],strikethrough:['striketrough_desc','Strikethrough'],justifyleft:['justifyleft_desc','JustifyLeft'],justifycenter:['justifycenter_desc','JustifyCenter'],justifyright:['justifyright_desc','JustifyRight'],justifyfull:['justifyfull_desc','JustifyFull'],bullist:['bullist_desc','InsertUnorderedList'],numlist:['numlist_desc','InsertOrderedList'],outdent:['outdent_desc','Outdent'],indent:['indent_desc','Indent'],cut:['cut_desc','Cut'],copy:['copy_desc','Copy'],paste:['paste_desc','Paste'],undo:['undo_desc','Undo'],redo:['redo_desc','Redo'],link:['link_desc','mceLink'],unlink:['unlink_desc','unlink'],image:['image_desc','mceImage'],cleanup:['cleanup_desc','mceCleanup'],help:['help_desc','mceHelp'],code:['code_desc','mceCodeEditor'],hr:['hr_desc','InsertHorizontalRule'],removeformat:['removeformat_desc','RemoveFormat'],sub:['sub_desc','subscript'],sup:['sup_desc','superscript'],forecolor:['forecolor_desc','ForeColor'],forecolorpicker:['forecolor_desc','mceForeColor'],backcolor:['backcolor_desc','HiliteColor'],backcolorpicker:['backcolor_desc','mceBackColor'],charmap:['charmap_desc','mceCharMap'],visualaid:['visualaid_desc','mceToggleVisualAid'],anchor:['anchor_desc','mceInsertAnchor'],newdocument:['newdocument_desc','mceNewDocument'],blockquote:['blockquote_desc','mceBlockQuote']},stateControls:['bold','italic','underline','strikethrough','bullist','numlist','justifyleft','justifycenter','justifyright','justifyfull','sub','sup','blockquote'],init:function(ed,url){var t=this,s,v;t.editor=ed;t.url=url;t.onResolveName=new tinymce.util.Dispatcher(this);t.settings=s=extend({theme_advanced_path:true,theme_advanced_toolbar_location:'bottom',theme_advanced_buttons1:"bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect",theme_advanced_buttons2:"bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code",theme_advanced_buttons3:"hr,removeformat,visualaid,|,sub,sup,|,charmap",theme_advanced_blockformats:"p,address,pre,h1,h2,h3,h4,h5,h6",theme_advanced_toolbar_align:"center",theme_advanced_fonts:"Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",theme_advanced_font_sizes:"1,2,3,4,5,6,7",theme_advanced_more_colors:1,theme_advanced_row_height:23,theme_advanced_resize_horizontal:1,theme_advanced_resizing_use_cookie:1},ed.settings);if((v=s.theme_advanced_path_location)&&v!='none')s.theme_advanced_statusbar_location=s.theme_advanced_path_location;if(s.theme_advanced_statusbar_location=='none')s.theme_advanced_statusbar_location=0;ed.onInit.add(function(){ed.onNodeChange.add(t._nodeChanged,t);if(ed.settings.content_css!==false)ed.dom.loadCSS(ed.baseURI.toAbsolute("themes/advanced/skins/"+ed.settings.skin+"/content.css"));});ed.onSetProgressState.add(function(ed,b,ti){var co,id=ed.id,tb;if(b){t.progressTimer=setTimeout(function(){co=ed.getContainer();co=co.insertBefore(DOM.create('DIV',{style:'position:relative'}),co.firstChild);tb=DOM.get(ed.id+'_tbl');DOM.add(co,'div',{id:id+'_blocker','class':'mceBlocker',style:{width:tb.clientWidth+2,height:tb.clientHeight+2}});DOM.add(co,'div',{id:id+'_progress','class':'mceProgress',style:{left:tb.clientWidth/ 2, top : tb.clientHeight /2}});},ti||0);}else{DOM.remove(id+'_blocker');DOM.remove(id+'_progress');clearTimeout(t.progressTimer);}});DOM.loadCSS(ed.baseURI.toAbsolute(s.editor_css||"themes/advanced/skins/"+ed.settings.skin+"/ui.css"));if(s.skin_variant)DOM.loadCSS(ed.baseURI.toAbsolute(s.editor_css||"themes/advanced/skins/"+ed.settings.skin+"/ui_"+s.skin_variant+".css"));},createControl:function(n,cf){var cd,c;if(c=cf.createControl(n))return c;switch(n){case"styleselect":return this._createStyleSelect();case"formatselect":return this._createBlockFormats();case"fontselect":return this._createFontSelect();case"fontsizeselect":return this._createFontSizeSelect();case"forecolor":return this._createForeColorMenu();case"backcolor":return this._createBackColorMenu();}if((cd=this.controls[n]))return cf.createButton(n,{title:"advanced."+cd[0],cmd:cd[1],ui:cd[2],value:cd[3]});},execCommand:function(cmd,ui,val){var f=this['_'+cmd];if(f){f.call(this,ui,val);return true;}return false;},_importClasses:function(){var ed=this.editor,c=ed.controlManager.get('styleselect');if(c.getLength()==0){each(ed.dom.getClasses(),function(o){c.add(o['class'],o['class']);});}},_createStyleSelect:function(n){var t=this,ed=t.editor,cf=ed.controlManager,c=cf.createListBox('styleselect',{title:'advanced.style_select',onselect:function(v){if(c.selectedValue===v){ed.execCommand('mceSetStyleInfo',0,{command:'removeformat'});c.select();return false;}else ed.execCommand('mceSetCSSClass',0,v);}});if(c){each(ed.getParam('theme_advanced_styles','','hash'),function(v,k){if(v)c.add(t.editor.translate(k),v);});c.onPostRender.add(function(ed,n){Event.add(n,'focus',t._importClasses,t);Event.add(n,'mousedown',t._importClasses,t);});}return c;},_createFontSelect:function(){var c,t=this,ed=t.editor;c=ed.controlManager.createListBox('fontselect',{title:'advanced.fontdefault',cmd:'FontName'});if(c){each(ed.getParam('theme_advanced_fonts',t.settings.theme_advanced_fonts,'hash'),function(v,k){c.add(ed.translate(k),v,{style:v.indexOf('dings')==-1?'font-family:'+v:''});});}return c;},_createFontSizeSelect:function(){var c,t=this,lo=["1 (8 pt)","2 (10 pt)","3 (12 pt)","4 (14 pt)","5 (18 pt)","6 (24 pt)","7 (36 pt)"],fz=[8,10,12,14,18,24,36];c=t.editor.controlManager.createListBox('fontsizeselect',{title:'advanced.font_size',cmd:'FontSize'});if(c){each(explode(t.settings.theme_advanced_font_sizes),function(v){c.add(lo[parseInt(v)-1],v,{'style':'font-size:'+fz[v-1]+'pt','class':'mceFontSize'+v});});}return c;},_createBlockFormats:function(){var c,fmts={p:'advanced.paragraph',address:'advanced.address',pre:'advanced.pre',h1:'advanced.h1',h2:'advanced.h2',h3:'advanced.h3',h4:'advanced.h4',h5:'advanced.h5',h6:'advanced.h6',div:'advanced.div',blockquote:'advanced.blockquote',code:'advanced.code',dt:'advanced.dt',dd:'advanced.dd',samp:'advanced.samp'},t=this;c=t.editor.controlManager.createListBox('formatselect',{title:'advanced.block',cmd:'FormatBlock'});if(c){each(t.editor.getParam('theme_advanced_blockformats',t.settings.theme_advanced_blockformats,'hash'),function(v,k){c.add(t.editor.translate(k!=v?k:fmts[v]),v,{'class':'mce_formatPreview mce_'+v});});}return c;},_createForeColorMenu:function(){var c,t=this,s=t.settings,o={},v;if(s.theme_advanced_more_colors){o.more_colors_func=function(){t._mceColorPicker(0,{color:c.value,func:function(co){c.setColor(co);}});};}if(v=s.theme_advanced_text_colors)o.colors=v;o.title='advanced.forecolor_desc';o.cmd='ForeColor';o.scope=this;c=t.editor.controlManager.createColorSplitButton('forecolor',o);return c;},_createBackColorMenu:function(){var c,t=this,s=t.settings,o={},v;if(s.theme_advanced_more_colors){o.more_colors_func=function(){t._mceColorPicker(0,{color:c.value,func:function(co){c.setColor(co);}});};}if(v=s.theme_advanced_background_colors)o.colors=v;o.title='advanced.backcolor_desc';o.cmd='HiliteColor';o.scope=this;c=t.editor.controlManager.createColorSplitButton('backcolor',o);return c;},renderUI:function(o){var n,ic,tb,t=this,ed=t.editor,s=t.settings,sc,p,nl;n=p=DOM.create('span',{id:ed.id+'_parent','class':'mceEditor '+ed.settings.skin+'Skin'+(s.skin_variant?' '+ed.settings.skin+'Skin'+t._ufirst(s.skin_variant):'')});if(!DOM.boxModel)n=DOM.add(n,'div',{'class':'mceOldBoxModel'});n=sc=DOM.add(n,'table',{id:ed.id+'_tbl','class':'mceLayout',cellSpacing:0,cellPadding:0});n=tb=DOM.add(n,'tbody');switch((s.theme_advanced_layout_manager||'').toLowerCase()){case"rowlayout":ic=t._rowLayout(s,tb,o);break;case"customlayout":ic=ed.execCallback("theme_advanced_custom_layout",s,tb,o,p);break;default:ic=t._simpleLayout(s,tb,o,p);}n=o.targetNode;nl=DOM.stdMode?sc.getElementsByTagName('tr'):sc.rows;DOM.addClass(nl[0],'mceFirst');DOM.addClass(nl[nl.length-1],'mceLast');each(DOM.select('tr',tb),function(n){DOM.addClass(n.firstChild,'mceFirst');DOM.addClass(n.childNodes[n.childNodes.length-1],'mceLast');});if(DOM.get(s.theme_advanced_toolbar_container))DOM.get(s.theme_advanced_toolbar_container).appendChild(p);else DOM.insertAfter(p,n);Event.add(ed.id+'_path_row','click',function(e){e=e.target;if(e.nodeName=='A'){t._sel(e.className.replace(/^.*mcePath_([0-9]+).*$/,'$1'));return Event.cancel(e);}});if(!ed.getParam('accessibility_focus')||ed.getParam('tab_focus'))Event.add(DOM.add(p,'a',{href:'#'},''),'focus',function(){tinyMCE.get(ed.id).focus();});if(s.theme_advanced_toolbar_location=='external')o.deltaHeight=0;t.deltaHeight=o.deltaHeight;o.targetNode=null;return{iframeContainer:ic,editorContainer:ed.id+'_parent',sizeContainer:sc,deltaHeight:o.deltaHeight};},getInfo:function(){return{longname:'Advanced theme',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',version:tinymce.majorVersion+"."+tinymce.minorVersion}},resizeBy:function(dw,dh){var e=DOM.get(this.editor.id+'_tbl');this.resizeTo(e.clientWidth+dw,e.clientHeight+dh);},resizeTo:function(w,h){var ed=this.editor,s=ed.settings,e=DOM.get(ed.id+'_tbl'),ifr=DOM.get(ed.id+'_ifr'),dh;w=Math.max(s.theme_advanced_resizing_min_width||100,w);h=Math.max(s.theme_advanced_resizing_min_height||100,h);w=Math.min(s.theme_advanced_resizing_max_width||0xFFFF,w);h=Math.min(s.theme_advanced_resizing_max_height||0xFFFF,h);dh=e.clientHeight-ifr.clientHeight;DOM.setStyle(ifr,'height',h-dh);DOM.setStyles(e,{width:w,height:h});},destroy:function(){var id=this.editor.id;Event.clear(id+'_resize');Event.clear(id+'_path_row');Event.clear(id+'_external_close');},_simpleLayout:function(s,tb,o,p){var t=this,ed=t.editor,lo=s.theme_advanced_toolbar_location,sl=s.theme_advanced_statusbar_location,n,ic,etb,c;if(lo=='top')t._addToolbars(tb,o);if(lo=='external'){n=c=DOM.create('div',{style:'position:relative'});n=DOM.add(n,'div',{id:ed.id+'_external','class':'mceExternalToolbar'});DOM.add(n,'a',{id:ed.id+'_external_close',href:'javascript:;','class':'mceExternalClose'});n=DOM.add(n,'table',{id:ed.id+'_tblext',cellSpacing:0,cellPadding:0});etb=DOM.add(n,'tbody');if(p.firstChild.className=='mceOldBoxModel')p.firstChild.appendChild(c);else p.insertBefore(c,p.firstChild);t._addToolbars(etb,o);ed.onMouseUp.add(function(){var e=DOM.get(ed.id+'_external');DOM.show(e);DOM.hide(lastExtID);var f=Event.add(ed.id+'_external_close','click',function(){DOM.hide(ed.id+'_external');Event.remove(ed.id+'_external_close','click',f);});DOM.show(e);DOM.setStyle(e,'top',0-DOM.getRect(ed.id+'_tblext').h-1);DOM.hide(e);DOM.show(e);e.style.filter='';lastExtID=ed.id+'_external';e=null;});}if(sl=='top')t._addStatusBar(tb,o);if(!s.theme_advanced_toolbar_container){n=DOM.add(tb,'tr');n=ic=DOM.add(n,'td',{'class':'mceIframeContainer'});}if(lo=='bottom')t._addToolbars(tb,o);if(sl=='bottom')t._addStatusBar(tb,o);return ic;},_rowLayout:function(s,tb,o){var t=this,ed=t.editor,dc,da,cf=ed.controlManager,n,ic,to,a;dc=s.theme_advanced_containers_default_class||'';da=s.theme_advanced_containers_default_align||'center';each(explode(s.theme_advanced_containers||''),function(c,i){var v=s['theme_advanced_container_'+c]||'';switch(c.toLowerCase()){case'mceeditor':n=DOM.add(tb,'tr');n=ic=DOM.add(n,'td',{'class':'mceIframeContainer'});break;case'mceelementpath':t._addStatusBar(tb,o);break;default:a=s['theme_advanced_container_'+c+'_align'].toLowerCase();a='mce'+t._ufirst(a);n=DOM.add(DOM.add(tb,'tr'),'td',{'class':'mceToolbar '+(s['theme_advanced_container_'+c+'_class']||dc)+' '+a||da});to=cf.createToolbar("toolbar"+i);t._addControls(v,to);DOM.setHTML(n,to.renderHTML());o.deltaHeight-=s.theme_advanced_row_height;}});return ic;},_addControls:function(v,tb){var t=this,s=t.settings,di,cf=t.editor.controlManager;if(s.theme_advanced_disable&&!t._disabled){di={};each(explode(s.theme_advanced_disable),function(v){di[v]=1;});t._disabled=di;}else di=t._disabled;each(explode(v),function(n){var c;if(di&&di[n])return;if(n=='tablecontrols'){each(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"],function(n){n=t.createControl(n,cf);if(n)tb.add(n);});return;}c=t.createControl(n,cf);if(c)tb.add(c);});},_addToolbars:function(c,o){var t=this,i,tb,ed=t.editor,s=t.settings,v,cf=ed.controlManager,di,n,h=[],a;a=s.theme_advanced_toolbar_align.toLowerCase();a='mce'+t._ufirst(a);n=DOM.add(DOM.add(c,'tr'),'td',{'class':'mceToolbar '+a});if(!ed.getParam('accessibility_focus')||ed.getParam('tab_focus'))h.push(DOM.createHTML('a',{href:'#',onfocus:'tinyMCE.get(\''+ed.id+'\').focus();'},''));h.push(DOM.createHTML('a',{href:'#',accesskey:'q',title:ed.getLang("advanced.toolbar_focus")},''));for(i=1;(v=s['theme_advanced_buttons'+i]);i++){tb=cf.createToolbar("toolbar"+i,{'class':'mceToolbarRow'+i});if(s['theme_advanced_buttons'+i+'_add'])v+=','+s['theme_advanced_buttons'+i+'_add'];if(s['theme_advanced_buttons'+i+'_add_before'])v=s['theme_advanced_buttons'+i+'_add_before']+','+v;t._addControls(v,tb);h.push(tb.renderHTML());o.deltaHeight-=s.theme_advanced_row_height;}h.push(DOM.createHTML('a',{href:'#',accesskey:'z',title:ed.getLang("advanced.toolbar_focus"),onfocus:'tinyMCE.getInstanceById(\''+ed.id+'\').focus();'},''));DOM.setHTML(n,h.join(''));},_addStatusBar:function(tb,o){var n,t=this,ed=t.editor,s=t.settings,r,mf,me,td;n=DOM.add(tb,'tr');n=td=DOM.add(n,'td',{'class':'mceStatusbar'});n=DOM.add(n,'div',{id:ed.id+'_path_row'},s.theme_advanced_path?ed.translate('advanced.path')+': ':' ');DOM.add(n,'a',{href:'#',accesskey:'x'});if(s.theme_advanced_resizing&&!tinymce.isOldWebKit){DOM.add(td,'a',{id:ed.id+'_resize',href:'javascript:;',onclick:"return false;",'class':'mceResize'});if(s.theme_advanced_resizing_use_cookie){ed.onPostRender.add(function(){var o=Cookie.getHash("TinyMCE_"+ed.id+"_size"),c=DOM.get(ed.id+'_tbl');if(!o)return;if(s.theme_advanced_resize_horizontal)c.style.width=Math.max(10,o.cw)+'px';c.style.height=Math.max(10,o.ch)+'px';DOM.get(ed.id+'_ifr').style.height=Math.max(10,parseInt(o.ch)+t.deltaHeight)+'px';});}ed.onPostRender.add(function(){Event.add(ed.id+'_resize','mousedown',function(e){var c,p,w,h,n,pa;c=DOM.get(ed.id+'_tbl');w=c.clientWidth;h=c.clientHeight;miw=s.theme_advanced_resizing_min_width||100;mih=s.theme_advanced_resizing_min_height||100;maw=s.theme_advanced_resizing_max_width||0xFFFF;mah=s.theme_advanced_resizing_max_height||0xFFFF;p=DOM.add(DOM.get(ed.id+'_parent'),'div',{'class':'mcePlaceHolder'});DOM.setStyles(p,{width:w,height:h});DOM.hide(c);DOM.show(p);r={x:e.screenX,y:e.screenY,w:w,h:h,dx:null,dy:null};mf=Event.add(DOM.doc,'mousemove',function(e){var w,h;r.dx=e.screenX-r.x;r.dy=e.screenY-r.y;w=Math.max(miw,r.w+r.dx);h=Math.max(mih,r.h+r.dy);w=Math.min(maw,w);h=Math.min(mah,h);if(s.theme_advanced_resize_horizontal)p.style.width=w+'px';p.style.height=h+'px';return Event.cancel(e);});me=Event.add(DOM.doc,'mouseup',function(e){var ifr;Event.remove(DOM.doc,'mousemove',mf);Event.remove(DOM.doc,'mouseup',me);c.style.display='';DOM.remove(p);if(r.dx===null)return;ifr=DOM.get(ed.id+'_ifr');if(s.theme_advanced_resize_horizontal)c.style.width=Math.max(10,r.w+r.dx)+'px';c.style.height=Math.max(10,r.h+r.dy)+'px';ifr.style.height=Math.max(10,ifr.clientHeight+r.dy)+'px';if(s.theme_advanced_resizing_use_cookie){Cookie.setHash("TinyMCE_"+ed.id+"_size",{cw:r.w+r.dx,ch:r.h+r.dy});}});return Event.cancel(e);});});}o.deltaHeight-=21;n=tb=null;},_nodeChanged:function(ed,cm,n,co){var t=this,p,de=0,v,c,s=t.settings;tinymce.each(t.stateControls,function(c){cm.setActive(c,ed.queryCommandState(t.controls[c][1]));});cm.setActive('visualaid',ed.hasVisual);cm.setDisabled('undo',!ed.undoManager.hasUndo()&&!ed.typing);cm.setDisabled('redo',!ed.undoManager.hasRedo());cm.setDisabled('outdent',!ed.queryCommandState('Outdent'));p=DOM.getParent(n,'A');if(c=cm.get('link')){if(!p||!p.name){c.setDisabled(!p&&co);c.setActive(!!p);}}if(c=cm.get('unlink')){c.setDisabled(!p&&co);c.setActive(!!p&&!p.name);}if(c=cm.get('anchor')){c.setActive(!!p&&p.name);if(tinymce.isWebKit){p=DOM.getParent(n,'IMG');c.setActive(!!p&&DOM.getAttrib(p,'mce_name')=='a');}}p=DOM.getParent(n,'IMG');if(c=cm.get('image'))c.setActive(!!p&&n.className.indexOf('mceItem')==-1);if(c=cm.get('styleselect')){if(n.className){t._importClasses();c.select(n.className);}else c.select();}if(c=cm.get('formatselect')){p=DOM.getParent(n,DOM.isBlock);if(p)c.select(p.nodeName.toLowerCase());}if(c=cm.get('fontselect'))c.select(ed.queryCommandValue('FontName'));if(c=cm.get('fontsizeselect'))c.select(ed.queryCommandValue('FontSize'));if(s.theme_advanced_path&&s.theme_advanced_statusbar_location){p=DOM.get(ed.id+'_path')||DOM.add(ed.id+'_path_row','span',{id:ed.id+'_path'});DOM.setHTML(p,'');ed.dom.getParent(n,function(n){var na=n.nodeName.toLowerCase(),u,pi,ti='';if(n.nodeType!=1||(DOM.hasClass(n,'mceItemHidden')||DOM.hasClass(n,'mceItemRemoved')))return;if(v=DOM.getAttrib(n,'mce_name'))na=v;if(tinymce.isIE&&n.scopeName!=='HTML')na=n.scopeName+':'+na;na=na.replace(/mce\:/g,'');switch(na){case'b':na='strong';break;case'i':na='em';break;case'img':if(v=DOM.getAttrib(n,'src'))ti+='src: '+v+' ';break;case'a':if(v=DOM.getAttrib(n,'name')){ti+='name: '+v+' ';na+='#'+v;}if(v=DOM.getAttrib(n,'href'))ti+='href: '+v+' ';break;case'font':if(s.convert_fonts_to_spans)na='span';if(v=DOM.getAttrib(n,'face'))ti+='font: '+v+' ';if(v=DOM.getAttrib(n,'size'))ti+='size: '+v+' ';if(v=DOM.getAttrib(n,'color'))ti+='color: '+v+' ';break;case'span':if(v=DOM.getAttrib(n,'style'))ti+='style: '+v+' ';break;}if(v=DOM.getAttrib(n,'id'))ti+='id: '+v+' ';if(v=n.className){v=v.replace(/(webkit-[\w\-]+|Apple-[\w\-]+|mceItem\w+|mceVisualAid)/g,'');if(v&&v.indexOf('mceItem')==-1){ti+='class: '+v+' ';if(DOM.isBlock(n)||na=='img'||na=='span')na+='.'+v;}}na=na.replace(/(html:)/g,'');na={name:na,node:n,title:ti};t.onResolveName.dispatch(t,na);ti=na.title;na=na.name;pi=DOM.create('a',{'href':"javascript:;",onmousedown:"return false;",title:ti,'class':'mcePath_'+(de++)},na);if(p.hasChildNodes()){p.insertBefore(DOM.doc.createTextNode(' \u00bb '),p.firstChild);p.insertBefore(pi,p.firstChild);}else p.appendChild(pi);},ed.getBody());}},_sel:function(v){this.editor.execCommand('mceSelectNodeDepth',false,v);},_mceInsertAnchor:function(ui,v){var ed=this.editor;ed.windowManager.open({url:tinymce.baseURL+'/themes/advanced/anchor.htm',width:320+parseInt(ed.getLang('advanced.anchor_delta_width',0)),height:90+parseInt(ed.getLang('advanced.anchor_delta_height',0)),inline:true},{theme_url:this.url});},_mceCharMap:function(){var ed=this.editor;ed.windowManager.open({url:tinymce.baseURL+'/themes/advanced/charmap.htm',width:550+parseInt(ed.getLang('advanced.charmap_delta_width',0)),height:250+parseInt(ed.getLang('advanced.charmap_delta_height',0)),inline:true},{theme_url:this.url});},_mceHelp:function(){var ed=this.editor;ed.windowManager.open({url:tinymce.baseURL+'/themes/advanced/about.htm',width:480,height:380,inline:true},{theme_url:this.url});},_mceColorPicker:function(u,v){var ed=this.editor;v=v||{};ed.windowManager.open({url:tinymce.baseURL+'/themes/advanced/color_picker.htm',width:375+parseInt(ed.getLang('advanced.colorpicker_delta_width',0)),height:250+parseInt(ed.getLang('advanced.colorpicker_delta_height',0)),close_previous:false,inline:true},{input_color:v.color,func:v.func,theme_url:this.url});},_mceCodeEditor:function(ui,val){var ed=this.editor;ed.windowManager.open({url:tinymce.baseURL+'/themes/advanced/source_editor.htm',width:parseInt(ed.getParam("theme_advanced_source_editor_width",720)),height:parseInt(ed.getParam("theme_advanced_source_editor_height",580)),inline:true,resizable:true,maximizable:true},{theme_url:this.url});},_mceImage:function(ui,val){var ed=this.editor;if(ed.dom.getAttrib(ed.selection.getNode(),'class').indexOf('mceItem')!=-1)return;ed.windowManager.open({url:tinymce.baseURL+'/themes/advanced/image.htm',width:355+parseInt(ed.getLang('advanced.image_delta_width',0)),height:275+parseInt(ed.getLang('advanced.image_delta_height',0)),inline:true},{theme_url:this.url});},_mceLink:function(ui,val){var ed=this.editor;ed.windowManager.open({url:tinymce.baseURL+'/themes/advanced/link.htm',width:310+parseInt(ed.getLang('advanced.link_delta_width',0)),height:200+parseInt(ed.getLang('advanced.link_delta_height',0)),inline:true},{theme_url:this.url});},_mceNewDocument:function(){var ed=this.editor;ed.windowManager.confirm('advanced.newdocument',function(s){if(s)ed.execCommand('mceSetContent',false,'');});},_mceForeColor:function(){var t=this;this._mceColorPicker(0,{color:t.fgColor,func:function(co){t.fgColor=co;t.editor.execCommand('ForeColor',false,co);}});},_mceBackColor:function(){var t=this;this._mceColorPicker(0,{color:t.bgColor,func:function(co){t.bgColor=co;t.editor.execCommand('HiliteColor',false,co);}});},_ufirst:function(s){return s.substring(0,1).toUpperCase()+s.substring(1);}});tinymce.ThemeManager.add('advanced',tinymce.themes.AdvancedTheme);}()); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/editor_template_src.js b/web/js/tiny_mce/themes/advanced/editor_template_src.js new file mode 100644 index 0000000..4369717 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/editor_template_src.js @@ -0,0 +1,1052 @@ +/** + * $Id: editor_template_src.js 793 2008-04-10 17:32:40Z spocke $ + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, each = tinymce.each, Cookie = tinymce.util.Cookie, lastExtID, explode = tinymce.explode; + + // Tell it to load theme specific language pack(s) + tinymce.ThemeManager.requireLangPack('advanced'); + + tinymce.create('tinymce.themes.AdvancedTheme', { + // Control name lookup, format: title, command + controls : { + bold : ['bold_desc', 'Bold'], + italic : ['italic_desc', 'Italic'], + underline : ['underline_desc', 'Underline'], + strikethrough : ['striketrough_desc', 'Strikethrough'], + justifyleft : ['justifyleft_desc', 'JustifyLeft'], + justifycenter : ['justifycenter_desc', 'JustifyCenter'], + justifyright : ['justifyright_desc', 'JustifyRight'], + justifyfull : ['justifyfull_desc', 'JustifyFull'], + bullist : ['bullist_desc', 'InsertUnorderedList'], + numlist : ['numlist_desc', 'InsertOrderedList'], + outdent : ['outdent_desc', 'Outdent'], + indent : ['indent_desc', 'Indent'], + cut : ['cut_desc', 'Cut'], + copy : ['copy_desc', 'Copy'], + paste : ['paste_desc', 'Paste'], + undo : ['undo_desc', 'Undo'], + redo : ['redo_desc', 'Redo'], + link : ['link_desc', 'mceLink'], + unlink : ['unlink_desc', 'unlink'], + image : ['image_desc', 'mceImage'], + cleanup : ['cleanup_desc', 'mceCleanup'], + help : ['help_desc', 'mceHelp'], + code : ['code_desc', 'mceCodeEditor'], + hr : ['hr_desc', 'InsertHorizontalRule'], + removeformat : ['removeformat_desc', 'RemoveFormat'], + sub : ['sub_desc', 'subscript'], + sup : ['sup_desc', 'superscript'], + forecolor : ['forecolor_desc', 'ForeColor'], + forecolorpicker : ['forecolor_desc', 'mceForeColor'], + backcolor : ['backcolor_desc', 'HiliteColor'], + backcolorpicker : ['backcolor_desc', 'mceBackColor'], + charmap : ['charmap_desc', 'mceCharMap'], + visualaid : ['visualaid_desc', 'mceToggleVisualAid'], + anchor : ['anchor_desc', 'mceInsertAnchor'], + newdocument : ['newdocument_desc', 'mceNewDocument'], + blockquote : ['blockquote_desc', 'mceBlockQuote'] + }, + + stateControls : ['bold', 'italic', 'underline', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'sub', 'sup', 'blockquote'], + + init : function(ed, url) { + var t = this, s, v; + + t.editor = ed; + t.url = url; + t.onResolveName = new tinymce.util.Dispatcher(this); + + // Default settings + t.settings = s = extend({ + theme_advanced_path : true, + theme_advanced_toolbar_location : 'bottom', + theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect", + theme_advanced_buttons2 : "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code", + theme_advanced_buttons3 : "hr,removeformat,visualaid,|,sub,sup,|,charmap", + theme_advanced_blockformats : "p,address,pre,h1,h2,h3,h4,h5,h6", + theme_advanced_toolbar_align : "center", + theme_advanced_fonts : "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats", + theme_advanced_font_sizes : "1,2,3,4,5,6,7", + theme_advanced_more_colors : 1, + theme_advanced_row_height : 23, + theme_advanced_resize_horizontal : 1, + theme_advanced_resizing_use_cookie : 1 + }, ed.settings); + + if ((v = s.theme_advanced_path_location) && v != 'none') + s.theme_advanced_statusbar_location = s.theme_advanced_path_location; + + if (s.theme_advanced_statusbar_location == 'none') + s.theme_advanced_statusbar_location = 0; + + // Init editor + ed.onInit.add(function() { + ed.onNodeChange.add(t._nodeChanged, t); + + if (ed.settings.content_css !== false) + ed.dom.loadCSS(ed.baseURI.toAbsolute("themes/advanced/skins/" + ed.settings.skin + "/content.css")); + }); + + ed.onSetProgressState.add(function(ed, b, ti) { + var co, id = ed.id, tb; + + if (b) { + t.progressTimer = setTimeout(function() { + co = ed.getContainer(); + co = co.insertBefore(DOM.create('DIV', {style : 'position:relative'}), co.firstChild); + tb = DOM.get(ed.id + '_tbl'); + + DOM.add(co, 'div', {id : id + '_blocker', 'class' : 'mceBlocker', style : {width : tb.clientWidth + 2, height : tb.clientHeight + 2}}); + DOM.add(co, 'div', {id : id + '_progress', 'class' : 'mceProgress', style : {left : tb.clientWidth / 2, top : tb.clientHeight / 2}}); + }, ti || 0); + } else { + DOM.remove(id + '_blocker'); + DOM.remove(id + '_progress'); + clearTimeout(t.progressTimer); + } + }); + + DOM.loadCSS(ed.baseURI.toAbsolute(s.editor_css || "themes/advanced/skins/" + ed.settings.skin + "/ui.css")); + + if (s.skin_variant) + DOM.loadCSS(ed.baseURI.toAbsolute(s.editor_css || "themes/advanced/skins/" + ed.settings.skin + "/ui_" + s.skin_variant + ".css")); + }, + + createControl : function(n, cf) { + var cd, c; + + if (c = cf.createControl(n)) + return c; + + switch (n) { + case "styleselect": + return this._createStyleSelect(); + + case "formatselect": + return this._createBlockFormats(); + + case "fontselect": + return this._createFontSelect(); + + case "fontsizeselect": + return this._createFontSizeSelect(); + + case "forecolor": + return this._createForeColorMenu(); + + case "backcolor": + return this._createBackColorMenu(); + } + + if ((cd = this.controls[n])) + return cf.createButton(n, {title : "advanced." + cd[0], cmd : cd[1], ui : cd[2], value : cd[3]}); + }, + + execCommand : function(cmd, ui, val) { + var f = this['_' + cmd]; + + if (f) { + f.call(this, ui, val); + return true; + } + + return false; + }, + + _importClasses : function() { + var ed = this.editor, c = ed.controlManager.get('styleselect'); + + if (c.getLength() == 0) { + each(ed.dom.getClasses(), function(o) { + c.add(o['class'], o['class']); + }); + } + }, + + _createStyleSelect : function(n) { + var t = this, ed = t.editor, cf = ed.controlManager, c = cf.createListBox('styleselect', { + title : 'advanced.style_select', + onselect : function(v) { + if (c.selectedValue === v) { + ed.execCommand('mceSetStyleInfo', 0, {command : 'removeformat'}); + c.select(); + return false; + } else + ed.execCommand('mceSetCSSClass', 0, v); + } + }); + + if (c) { + each(ed.getParam('theme_advanced_styles', '', 'hash'), function(v, k) { + if (v) + c.add(t.editor.translate(k), v); + }); + + c.onPostRender.add(function(ed, n) { + Event.add(n, 'focus', t._importClasses, t); + Event.add(n, 'mousedown', t._importClasses, t); + }); + } + + return c; + }, + + _createFontSelect : function() { + var c, t = this, ed = t.editor; + + c = ed.controlManager.createListBox('fontselect', {title : 'advanced.fontdefault', cmd : 'FontName'}); + if (c) { + each(ed.getParam('theme_advanced_fonts', t.settings.theme_advanced_fonts, 'hash'), function(v, k) { + c.add(ed.translate(k), v, {style : v.indexOf('dings') == -1 ? 'font-family:' + v : ''}); + }); + } + + return c; + }, + + _createFontSizeSelect : function() { + var c, t = this, lo = [ + "1 (8 pt)", + "2 (10 pt)", + "3 (12 pt)", + "4 (14 pt)", + "5 (18 pt)", + "6 (24 pt)", + "7 (36 pt)" + ], fz = [8, 10, 12, 14, 18, 24, 36]; + + c = t.editor.controlManager.createListBox('fontsizeselect', {title : 'advanced.font_size', cmd : 'FontSize'}); + if (c) { + each(explode(t.settings.theme_advanced_font_sizes), function(v) { + c.add(lo[parseInt(v) - 1], v, {'style' : 'font-size:' + fz[v - 1] + 'pt', 'class' : 'mceFontSize' + v}); + }); + } + + return c; + }, + + _createBlockFormats : function() { + var c, fmts = { + p : 'advanced.paragraph', + address : 'advanced.address', + pre : 'advanced.pre', + h1 : 'advanced.h1', + h2 : 'advanced.h2', + h3 : 'advanced.h3', + h4 : 'advanced.h4', + h5 : 'advanced.h5', + h6 : 'advanced.h6', + div : 'advanced.div', + blockquote : 'advanced.blockquote', + code : 'advanced.code', + dt : 'advanced.dt', + dd : 'advanced.dd', + samp : 'advanced.samp' + }, t = this; + + c = t.editor.controlManager.createListBox('formatselect', {title : 'advanced.block', cmd : 'FormatBlock'}); + if (c) { + each(t.editor.getParam('theme_advanced_blockformats', t.settings.theme_advanced_blockformats, 'hash'), function(v, k) { + c.add(t.editor.translate(k != v ? k : fmts[v]), v, {'class' : 'mce_formatPreview mce_' + v}); + }); + } + + return c; + }, + + _createForeColorMenu : function() { + var c, t = this, s = t.settings, o = {}, v; + + if (s.theme_advanced_more_colors) { + o.more_colors_func = function() { + t._mceColorPicker(0, { + color : c.value, + func : function(co) { + c.setColor(co); + } + }); + }; + } + + if (v = s.theme_advanced_text_colors) + o.colors = v; + + o.title = 'advanced.forecolor_desc'; + o.cmd = 'ForeColor'; + o.scope = this; + + c = t.editor.controlManager.createColorSplitButton('forecolor', o); + + return c; + }, + + _createBackColorMenu : function() { + var c, t = this, s = t.settings, o = {}, v; + + if (s.theme_advanced_more_colors) { + o.more_colors_func = function() { + t._mceColorPicker(0, { + color : c.value, + func : function(co) { + c.setColor(co); + } + }); + }; + } + + if (v = s.theme_advanced_background_colors) + o.colors = v; + + o.title = 'advanced.backcolor_desc'; + o.cmd = 'HiliteColor'; + o.scope = this; + + c = t.editor.controlManager.createColorSplitButton('backcolor', o); + + return c; + }, + + renderUI : function(o) { + var n, ic, tb, t = this, ed = t.editor, s = t.settings, sc, p, nl; + + n = p = DOM.create('span', {id : ed.id + '_parent', 'class' : 'mceEditor ' + ed.settings.skin + 'Skin' + (s.skin_variant ? ' ' + ed.settings.skin + 'Skin' + t._ufirst(s.skin_variant) : '')}); + + if (!DOM.boxModel) + n = DOM.add(n, 'div', {'class' : 'mceOldBoxModel'}); + + n = sc = DOM.add(n, 'table', {id : ed.id + '_tbl', 'class' : 'mceLayout', cellSpacing : 0, cellPadding : 0}); + n = tb = DOM.add(n, 'tbody'); + + switch ((s.theme_advanced_layout_manager || '').toLowerCase()) { + case "rowlayout": + ic = t._rowLayout(s, tb, o); + break; + + case "customlayout": + ic = ed.execCallback("theme_advanced_custom_layout", s, tb, o, p); + break; + + default: + ic = t._simpleLayout(s, tb, o, p); + } + + n = o.targetNode; + + // Add classes to first and last TRs + nl = DOM.stdMode ? sc.getElementsByTagName('tr') : sc.rows; // Quick fix for IE 8 + DOM.addClass(nl[0], 'mceFirst'); + DOM.addClass(nl[nl.length - 1], 'mceLast'); + + // Add classes to first and last TDs + each(DOM.select('tr', tb), function(n) { + DOM.addClass(n.firstChild, 'mceFirst'); + DOM.addClass(n.childNodes[n.childNodes.length - 1], 'mceLast'); + }); + + if (DOM.get(s.theme_advanced_toolbar_container)) + DOM.get(s.theme_advanced_toolbar_container).appendChild(p); + else + DOM.insertAfter(p, n); + + Event.add(ed.id + '_path_row', 'click', function(e) { + e = e.target; + + if (e.nodeName == 'A') { + t._sel(e.className.replace(/^.*mcePath_([0-9]+).*$/, '$1')); + + return Event.cancel(e); + } + }); +/* + if (DOM.get(ed.id + '_path_row')) { + Event.add(ed.id + '_tbl', 'mouseover', function(e) { + var re; + + e = e.target; + + if (e.nodeName == 'SPAN' && DOM.hasClass(e.parentNode, 'mceButton')) { + re = DOM.get(ed.id + '_path_row'); + t.lastPath = re.innerHTML; + DOM.setHTML(re, e.parentNode.title); + } + }); + + Event.add(ed.id + '_tbl', 'mouseout', function(e) { + if (t.lastPath) { + DOM.setHTML(ed.id + '_path_row', t.lastPath); + t.lastPath = 0; + } + }); + } +*/ + + if (!ed.getParam('accessibility_focus') || ed.getParam('tab_focus')) + Event.add(DOM.add(p, 'a', {href : '#'}, ''), 'focus', function() {tinyMCE.get(ed.id).focus();}); + + if (s.theme_advanced_toolbar_location == 'external') + o.deltaHeight = 0; + + t.deltaHeight = o.deltaHeight; + o.targetNode = null; + + return { + iframeContainer : ic, + editorContainer : ed.id + '_parent', + sizeContainer : sc, + deltaHeight : o.deltaHeight + }; + }, + + getInfo : function() { + return { + longname : 'Advanced theme', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + version : tinymce.majorVersion + "." + tinymce.minorVersion + } + }, + + resizeBy : function(dw, dh) { + var e = DOM.get(this.editor.id + '_tbl'); + + this.resizeTo(e.clientWidth + dw, e.clientHeight + dh); + }, + + resizeTo : function(w, h) { + var ed = this.editor, s = ed.settings, e = DOM.get(ed.id + '_tbl'), ifr = DOM.get(ed.id + '_ifr'), dh; + + // Boundery fix box + w = Math.max(s.theme_advanced_resizing_min_width || 100, w); + h = Math.max(s.theme_advanced_resizing_min_height || 100, h); + w = Math.min(s.theme_advanced_resizing_max_width || 0xFFFF, w); + h = Math.min(s.theme_advanced_resizing_max_height || 0xFFFF, h); + + // Calc difference between iframe and container + dh = e.clientHeight - ifr.clientHeight; + + // Resize iframe and container + DOM.setStyle(ifr, 'height', h - dh); + DOM.setStyles(e, {width : w, height : h}); + }, + + destroy : function() { + var id = this.editor.id; + + Event.clear(id + '_resize'); + Event.clear(id + '_path_row'); + Event.clear(id + '_external_close'); + }, + + // Internal functions + + _simpleLayout : function(s, tb, o, p) { + var t = this, ed = t.editor, lo = s.theme_advanced_toolbar_location, sl = s.theme_advanced_statusbar_location, n, ic, etb, c; + + // Create toolbar container at top + if (lo == 'top') + t._addToolbars(tb, o); + + // Create external toolbar + if (lo == 'external') { + n = c = DOM.create('div', {style : 'position:relative'}); + n = DOM.add(n, 'div', {id : ed.id + '_external', 'class' : 'mceExternalToolbar'}); + DOM.add(n, 'a', {id : ed.id + '_external_close', href : 'javascript:;', 'class' : 'mceExternalClose'}); + n = DOM.add(n, 'table', {id : ed.id + '_tblext', cellSpacing : 0, cellPadding : 0}); + etb = DOM.add(n, 'tbody'); + + if (p.firstChild.className == 'mceOldBoxModel') + p.firstChild.appendChild(c); + else + p.insertBefore(c, p.firstChild); + + t._addToolbars(etb, o); + + ed.onMouseUp.add(function() { + var e = DOM.get(ed.id + '_external'); + DOM.show(e); + + DOM.hide(lastExtID); + + var f = Event.add(ed.id + '_external_close', 'click', function() { + DOM.hide(ed.id + '_external'); + Event.remove(ed.id + '_external_close', 'click', f); + }); + + DOM.show(e); + DOM.setStyle(e, 'top', 0 - DOM.getRect(ed.id + '_tblext').h - 1); + + // Fixes IE rendering bug + DOM.hide(e); + DOM.show(e); + e.style.filter = ''; + + lastExtID = ed.id + '_external'; + + e = null; + }); + } + + if (sl == 'top') + t._addStatusBar(tb, o); + + // Create iframe container + if (!s.theme_advanced_toolbar_container) { + n = DOM.add(tb, 'tr'); + n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); + } + + // Create toolbar container at bottom + if (lo == 'bottom') + t._addToolbars(tb, o); + + if (sl == 'bottom') + t._addStatusBar(tb, o); + + return ic; + }, + + _rowLayout : function(s, tb, o) { + var t = this, ed = t.editor, dc, da, cf = ed.controlManager, n, ic, to, a; + + dc = s.theme_advanced_containers_default_class || ''; + da = s.theme_advanced_containers_default_align || 'center'; + + each(explode(s.theme_advanced_containers || ''), function(c, i) { + var v = s['theme_advanced_container_' + c] || ''; + + switch (c.toLowerCase()) { + case 'mceeditor': + n = DOM.add(tb, 'tr'); + n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'}); + break; + + case 'mceelementpath': + t._addStatusBar(tb, o); + break; + + default: + a = s['theme_advanced_container_' + c + '_align'].toLowerCase(); + a = 'mce' + t._ufirst(a); + + n = DOM.add(DOM.add(tb, 'tr'), 'td', { + 'class' : 'mceToolbar ' + (s['theme_advanced_container_' + c + '_class'] || dc) + ' ' + a || da + }); + + to = cf.createToolbar("toolbar" + i); + t._addControls(v, to); + DOM.setHTML(n, to.renderHTML()); + o.deltaHeight -= s.theme_advanced_row_height; + } + }); + + return ic; + }, + + _addControls : function(v, tb) { + var t = this, s = t.settings, di, cf = t.editor.controlManager; + + if (s.theme_advanced_disable && !t._disabled) { + di = {}; + + each(explode(s.theme_advanced_disable), function(v) { + di[v] = 1; + }); + + t._disabled = di; + } else + di = t._disabled; + + each(explode(v), function(n) { + var c; + + if (di && di[n]) + return; + + // Compatiblity with 2.x + if (n == 'tablecontrols') { + each(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"], function(n) { + n = t.createControl(n, cf); + + if (n) + tb.add(n); + }); + + return; + } + + c = t.createControl(n, cf); + + if (c) + tb.add(c); + }); + }, + + _addToolbars : function(c, o) { + var t = this, i, tb, ed = t.editor, s = t.settings, v, cf = ed.controlManager, di, n, h = [], a; + + a = s.theme_advanced_toolbar_align.toLowerCase(); + a = 'mce' + t._ufirst(a); + + n = DOM.add(DOM.add(c, 'tr'), 'td', {'class' : 'mceToolbar ' + a}); + + if (!ed.getParam('accessibility_focus') || ed.getParam('tab_focus')) + h.push(DOM.createHTML('a', {href : '#', onfocus : 'tinyMCE.get(\'' + ed.id + '\').focus();'}, '')); + + h.push(DOM.createHTML('a', {href : '#', accesskey : 'q', title : ed.getLang("advanced.toolbar_focus")}, '')); + + // Create toolbar and add the controls + for (i=1; (v = s['theme_advanced_buttons' + i]); i++) { + tb = cf.createToolbar("toolbar" + i, {'class' : 'mceToolbarRow' + i}); + + if (s['theme_advanced_buttons' + i + '_add']) + v += ',' + s['theme_advanced_buttons' + i + '_add']; + + if (s['theme_advanced_buttons' + i + '_add_before']) + v = s['theme_advanced_buttons' + i + '_add_before'] + ',' + v; + + t._addControls(v, tb); + + //n.appendChild(n = tb.render()); + h.push(tb.renderHTML()); + + o.deltaHeight -= s.theme_advanced_row_height; + } + + h.push(DOM.createHTML('a', {href : '#', accesskey : 'z', title : ed.getLang("advanced.toolbar_focus"), onfocus : 'tinyMCE.getInstanceById(\'' + ed.id + '\').focus();'}, '')); + DOM.setHTML(n, h.join('')); + }, + + _addStatusBar : function(tb, o) { + var n, t = this, ed = t.editor, s = t.settings, r, mf, me, td; + + n = DOM.add(tb, 'tr'); + n = td = DOM.add(n, 'td', {'class' : 'mceStatusbar'}); + n = DOM.add(n, 'div', {id : ed.id + '_path_row'}, s.theme_advanced_path ? ed.translate('advanced.path') + ': ' : ' '); + DOM.add(n, 'a', {href : '#', accesskey : 'x'}); + + if (s.theme_advanced_resizing && !tinymce.isOldWebKit) { + DOM.add(td, 'a', {id : ed.id + '_resize', href : 'javascript:;', onclick : "return false;", 'class' : 'mceResize'}); + + if (s.theme_advanced_resizing_use_cookie) { + ed.onPostRender.add(function() { + var o = Cookie.getHash("TinyMCE_" + ed.id + "_size"), c = DOM.get(ed.id + '_tbl'); + + if (!o) + return; + + if (s.theme_advanced_resize_horizontal) + c.style.width = Math.max(10, o.cw) + 'px'; + + c.style.height = Math.max(10, o.ch) + 'px'; + DOM.get(ed.id + '_ifr').style.height = Math.max(10, parseInt(o.ch) + t.deltaHeight) + 'px'; + }); + } + + ed.onPostRender.add(function() { + Event.add(ed.id + '_resize', 'mousedown', function(e) { + var c, p, w, h, n, pa; + + // Measure container + c = DOM.get(ed.id + '_tbl'); + w = c.clientWidth; + h = c.clientHeight; + + miw = s.theme_advanced_resizing_min_width || 100; + mih = s.theme_advanced_resizing_min_height || 100; + maw = s.theme_advanced_resizing_max_width || 0xFFFF; + mah = s.theme_advanced_resizing_max_height || 0xFFFF; + + // Setup placeholder + p = DOM.add(DOM.get(ed.id + '_parent'), 'div', {'class' : 'mcePlaceHolder'}); + DOM.setStyles(p, {width : w, height : h}); + + // Replace with placeholder + DOM.hide(c); + DOM.show(p); + + // Create internal resize obj + r = { + x : e.screenX, + y : e.screenY, + w : w, + h : h, + dx : null, + dy : null + }; + + // Start listening + mf = Event.add(DOM.doc, 'mousemove', function(e) { + var w, h; + + // Calc delta values + r.dx = e.screenX - r.x; + r.dy = e.screenY - r.y; + + // Boundery fix box + w = Math.max(miw, r.w + r.dx); + h = Math.max(mih, r.h + r.dy); + w = Math.min(maw, w); + h = Math.min(mah, h); + + // Resize placeholder + if (s.theme_advanced_resize_horizontal) + p.style.width = w + 'px'; + + p.style.height = h + 'px'; + + return Event.cancel(e); + }); + + me = Event.add(DOM.doc, 'mouseup', function(e) { + var ifr; + + // Stop listening + Event.remove(DOM.doc, 'mousemove', mf); + Event.remove(DOM.doc, 'mouseup', me); + + c.style.display = ''; + DOM.remove(p); + + if (r.dx === null) + return; + + ifr = DOM.get(ed.id + '_ifr'); + + if (s.theme_advanced_resize_horizontal) + c.style.width = Math.max(10, r.w + r.dx) + 'px'; + + c.style.height = Math.max(10, r.h + r.dy) + 'px'; + ifr.style.height = Math.max(10, ifr.clientHeight + r.dy) + 'px'; + + if (s.theme_advanced_resizing_use_cookie) { + Cookie.setHash("TinyMCE_" + ed.id + "_size", { + cw : r.w + r.dx, + ch : r.h + r.dy + }); + } + }); + + return Event.cancel(e); + }); + }); + } + + o.deltaHeight -= 21; + n = tb = null; + }, + + _nodeChanged : function(ed, cm, n, co) { + var t = this, p, de = 0, v, c, s = t.settings; + + tinymce.each(t.stateControls, function(c) { + cm.setActive(c, ed.queryCommandState(t.controls[c][1])); + }); + + cm.setActive('visualaid', ed.hasVisual); + cm.setDisabled('undo', !ed.undoManager.hasUndo() && !ed.typing); + cm.setDisabled('redo', !ed.undoManager.hasRedo()); + cm.setDisabled('outdent', !ed.queryCommandState('Outdent')); + + p = DOM.getParent(n, 'A'); + if (c = cm.get('link')) { + if (!p || !p.name) { + c.setDisabled(!p && co); + c.setActive(!!p); + } + } + + if (c = cm.get('unlink')) { + c.setDisabled(!p && co); + c.setActive(!!p && !p.name); + } + + if (c = cm.get('anchor')) { + c.setActive(!!p && p.name); + + if (tinymce.isWebKit) { + p = DOM.getParent(n, 'IMG'); + c.setActive(!!p && DOM.getAttrib(p, 'mce_name') == 'a'); + } + } + + p = DOM.getParent(n, 'IMG'); + if (c = cm.get('image')) + c.setActive(!!p && n.className.indexOf('mceItem') == -1); + + if (c = cm.get('styleselect')) { + if (n.className) { + t._importClasses(); + c.select(n.className); + } else + c.select(); + } + + if (c = cm.get('formatselect')) { + p = DOM.getParent(n, DOM.isBlock); + + if (p) + c.select(p.nodeName.toLowerCase()); + } + + if (c = cm.get('fontselect')) + c.select(ed.queryCommandValue('FontName')); + + if (c = cm.get('fontsizeselect')) + c.select(ed.queryCommandValue('FontSize')); + + if (s.theme_advanced_path && s.theme_advanced_statusbar_location) { + p = DOM.get(ed.id + '_path') || DOM.add(ed.id + '_path_row', 'span', {id : ed.id + '_path'}); + DOM.setHTML(p, ''); + + ed.dom.getParent(n, function(n) { + var na = n.nodeName.toLowerCase(), u, pi, ti = ''; + + // Ignore non element and hidden elements + if (n.nodeType != 1 || (DOM.hasClass(n, 'mceItemHidden') || DOM.hasClass(n, 'mceItemRemoved'))) + return; + + // Fake name + if (v = DOM.getAttrib(n, 'mce_name')) + na = v; + + // Handle prefix + if (tinymce.isIE && n.scopeName !== 'HTML') + na = n.scopeName + ':' + na; + + // Remove internal prefix + na = na.replace(/mce\:/g, ''); + + // Handle node name + switch (na) { + case 'b': + na = 'strong'; + break; + + case 'i': + na = 'em'; + break; + + case 'img': + if (v = DOM.getAttrib(n, 'src')) + ti += 'src: ' + v + ' '; + + break; + + case 'a': + if (v = DOM.getAttrib(n, 'name')) { + ti += 'name: ' + v + ' '; + na += '#' + v; + } + + if (v = DOM.getAttrib(n, 'href')) + ti += 'href: ' + v + ' '; + + break; + + case 'font': + if (s.convert_fonts_to_spans) + na = 'span'; + + if (v = DOM.getAttrib(n, 'face')) + ti += 'font: ' + v + ' '; + + if (v = DOM.getAttrib(n, 'size')) + ti += 'size: ' + v + ' '; + + if (v = DOM.getAttrib(n, 'color')) + ti += 'color: ' + v + ' '; + + break; + + case 'span': + if (v = DOM.getAttrib(n, 'style')) + ti += 'style: ' + v + ' '; + + break; + } + + if (v = DOM.getAttrib(n, 'id')) + ti += 'id: ' + v + ' '; + + if (v = n.className) { + v = v.replace(/(webkit-[\w\-]+|Apple-[\w\-]+|mceItem\w+|mceVisualAid)/g, ''); + + if (v && v.indexOf('mceItem') == -1) { + ti += 'class: ' + v + ' '; + + if (DOM.isBlock(n) || na == 'img' || na == 'span') + na += '.' + v; + } + } + + na = na.replace(/(html:)/g, ''); + na = {name : na, node : n, title : ti}; + t.onResolveName.dispatch(t, na); + ti = na.title; + na = na.name; + + //u = "javascript:tinymce.EditorManager.get('" + ed.id + "').theme._sel('" + (de++) + "');"; + pi = DOM.create('a', {'href' : "javascript:;", onmousedown : "return false;", title : ti, 'class' : 'mcePath_' + (de++)}, na); + + if (p.hasChildNodes()) { + p.insertBefore(DOM.doc.createTextNode(' \u00bb '), p.firstChild); + p.insertBefore(pi, p.firstChild); + } else + p.appendChild(pi); + }, ed.getBody()); + } + }, + + // Commands gets called by execCommand + + _sel : function(v) { + this.editor.execCommand('mceSelectNodeDepth', false, v); + }, + + _mceInsertAnchor : function(ui, v) { + var ed = this.editor; + + ed.windowManager.open({ + url : tinymce.baseURL + '/themes/advanced/anchor.htm', + width : 320 + parseInt(ed.getLang('advanced.anchor_delta_width', 0)), + height : 90 + parseInt(ed.getLang('advanced.anchor_delta_height', 0)), + inline : true + }, { + theme_url : this.url + }); + }, + + _mceCharMap : function() { + var ed = this.editor; + + ed.windowManager.open({ + url : tinymce.baseURL + '/themes/advanced/charmap.htm', + width : 550 + parseInt(ed.getLang('advanced.charmap_delta_width', 0)), + height : 250 + parseInt(ed.getLang('advanced.charmap_delta_height', 0)), + inline : true + }, { + theme_url : this.url + }); + }, + + _mceHelp : function() { + var ed = this.editor; + + ed.windowManager.open({ + url : tinymce.baseURL + '/themes/advanced/about.htm', + width : 480, + height : 380, + inline : true + }, { + theme_url : this.url + }); + }, + + _mceColorPicker : function(u, v) { + var ed = this.editor; + + v = v || {}; + + ed.windowManager.open({ + url : tinymce.baseURL + '/themes/advanced/color_picker.htm', + width : 375 + parseInt(ed.getLang('advanced.colorpicker_delta_width', 0)), + height : 250 + parseInt(ed.getLang('advanced.colorpicker_delta_height', 0)), + close_previous : false, + inline : true + }, { + input_color : v.color, + func : v.func, + theme_url : this.url + }); + }, + + _mceCodeEditor : function(ui, val) { + var ed = this.editor; + + ed.windowManager.open({ + url : tinymce.baseURL + '/themes/advanced/source_editor.htm', + width : parseInt(ed.getParam("theme_advanced_source_editor_width", 720)), + height : parseInt(ed.getParam("theme_advanced_source_editor_height", 580)), + inline : true, + resizable : true, + maximizable : true + }, { + theme_url : this.url + }); + }, + + _mceImage : function(ui, val) { + var ed = this.editor; + + // Internal image object like a flash placeholder + if (ed.dom.getAttrib(ed.selection.getNode(), 'class').indexOf('mceItem') != -1) + return; + + ed.windowManager.open({ + url : tinymce.baseURL + '/themes/advanced/image.htm', + width : 355 + parseInt(ed.getLang('advanced.image_delta_width', 0)), + height : 275 + parseInt(ed.getLang('advanced.image_delta_height', 0)), + inline : true + }, { + theme_url : this.url + }); + }, + + _mceLink : function(ui, val) { + var ed = this.editor; + + ed.windowManager.open({ + url : tinymce.baseURL + '/themes/advanced/link.htm', + width : 310 + parseInt(ed.getLang('advanced.link_delta_width', 0)), + height : 200 + parseInt(ed.getLang('advanced.link_delta_height', 0)), + inline : true + }, { + theme_url : this.url + }); + }, + + _mceNewDocument : function() { + var ed = this.editor; + + ed.windowManager.confirm('advanced.newdocument', function(s) { + if (s) + ed.execCommand('mceSetContent', false, ''); + }); + }, + + _mceForeColor : function() { + var t = this; + + this._mceColorPicker(0, { + color: t.fgColor, + func : function(co) { + t.fgColor = co; + t.editor.execCommand('ForeColor', false, co); + } + }); + }, + + _mceBackColor : function() { + var t = this; + + this._mceColorPicker(0, { + color: t.bgColor, + func : function(co) { + t.bgColor = co; + t.editor.execCommand('HiliteColor', false, co); + } + }); + }, + + _ufirst : function(s) { + return s.substring(0, 1).toUpperCase() + s.substring(1); + } + }); + + tinymce.ThemeManager.add('advanced', tinymce.themes.AdvancedTheme); +}()); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/image.htm b/web/js/tiny_mce/themes/advanced/image.htm new file mode 100644 index 0000000..cea51af --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/image.htm @@ -0,0 +1,86 @@ + + + + {#advanced_dlg.image_title} + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    + x +
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/themes/advanced/img/colorpicker.jpg b/web/js/tiny_mce/themes/advanced/img/colorpicker.jpg new file mode 100644 index 0000000..b4c542d Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/img/colorpicker.jpg differ diff --git a/web/js/tiny_mce/themes/advanced/img/icons.gif b/web/js/tiny_mce/themes/advanced/img/icons.gif new file mode 100644 index 0000000..ccac36f Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/img/icons.gif differ diff --git a/web/js/tiny_mce/themes/advanced/js/about.js b/web/js/tiny_mce/themes/advanced/js/about.js new file mode 100644 index 0000000..9081e1d --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/js/about.js @@ -0,0 +1,72 @@ +tinyMCEPopup.requireLangPack(); + +function init() { + var ed, tcont; + + tinyMCEPopup.resizeToInnerSize(); + ed = tinyMCEPopup.editor; + + // Give FF some time + window.setTimeout('insertHelpIFrame();', 10); + + tcont = document.getElementById('plugintablecontainer'); + document.getElementById('plugins_tab').style.display = 'none'; + + var html = ""; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + + tinymce.each(ed.plugins, function(p, n) { + var info; + + if (!p.getInfo) + return; + + html += ''; + + info = p.getInfo(); + + if (info.infourl != null && info.infourl != '') + html += ''; + else + html += ''; + + if (info.authorurl != null && info.authorurl != '') + html += ''; + else + html += ''; + + html += ''; + html += ''; + + document.getElementById('plugins_tab').style.display = ''; + + }); + + html += ''; + html += '
    ' + ed.getLang('advanced_dlg.about_plugin') + '' + ed.getLang('advanced_dlg.about_author') + '' + ed.getLang('advanced_dlg.about_version') + '
    ' + info.longname + '' + info.longname + '' + info.author + '' + info.author + '' + info.version + '
    '; + + tcont.innerHTML = html; + + tinyMCEPopup.dom.get('version').innerHTML = tinymce.majorVersion + "." + tinymce.minorVersion; + tinyMCEPopup.dom.get('date').innerHTML = tinymce.releaseDate; +} + +function insertHelpIFrame() { + var html; + + if (tinyMCEPopup.getParam('docs_url')) { + html = ''; + document.getElementById('iframecontainer').innerHTML = html; + document.getElementById('help_tab').style.display = 'block'; + } +} + +tinyMCEPopup.onInit.add(init); diff --git a/web/js/tiny_mce/themes/advanced/js/anchor.js b/web/js/tiny_mce/themes/advanced/js/anchor.js new file mode 100644 index 0000000..b5efd1e --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/js/anchor.js @@ -0,0 +1,37 @@ +tinyMCEPopup.requireLangPack(); + +var AnchorDialog = { + init : function(ed) { + var action, elm, f = document.forms[0]; + + this.editor = ed; + elm = ed.dom.getParent(ed.selection.getNode(), 'A,IMG'); + v = ed.dom.getAttrib(elm, 'name'); + + if (v) { + this.action = 'update'; + f.anchorName.value = v; + } + + f.insert.value = ed.getLang(elm ? 'update' : 'insert'); + }, + + update : function() { + var ed = this.editor; + + tinyMCEPopup.restoreSelection(); + + if (this.action != 'update') + ed.selection.collapse(1); + + // Webkit acts weird if empty inline element is inserted so we need to use a image instead + if (tinymce.isWebKit) + ed.execCommand('mceInsertContent', 0, ed.dom.createHTML('img', {mce_name : 'a', name : document.forms[0].anchorName.value, 'class' : 'mceItemAnchor'})); + else + ed.execCommand('mceInsertContent', 0, ed.dom.createHTML('a', {name : document.forms[0].anchorName.value, 'class' : 'mceItemAnchor'}, '')); + + tinyMCEPopup.close(); + } +}; + +tinyMCEPopup.onInit.add(AnchorDialog.init, AnchorDialog); diff --git a/web/js/tiny_mce/themes/advanced/js/charmap.js b/web/js/tiny_mce/themes/advanced/js/charmap.js new file mode 100644 index 0000000..8467ef6 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/js/charmap.js @@ -0,0 +1,325 @@ +tinyMCEPopup.requireLangPack(); + +var charmap = [ + [' ', ' ', true, 'no-break space'], + ['&', '&', true, 'ampersand'], + ['"', '"', true, 'quotation mark'], +// finance + ['¢', '¢', true, 'cent sign'], + ['€', '€', true, 'euro sign'], + ['£', '£', true, 'pound sign'], + ['¥', '¥', true, 'yen sign'], +// signs + ['©', '©', true, 'copyright sign'], + ['®', '®', true, 'registered sign'], + ['™', '™', true, 'trade mark sign'], + ['‰', '‰', true, 'per mille sign'], + ['µ', 'µ', true, 'micro sign'], + ['·', '·', true, 'middle dot'], + ['•', '•', true, 'bullet'], + ['…', '…', true, 'three dot leader'], + ['′', '′', true, 'minutes / feet'], + ['″', '″', true, 'seconds / inches'], + ['§', '§', true, 'section sign'], + ['¶', '¶', true, 'paragraph sign'], + ['ß', 'ß', true, 'sharp s / ess-zed'], +// quotations + ['‹', '‹', true, 'single left-pointing angle quotation mark'], + ['›', '›', true, 'single right-pointing angle quotation mark'], + ['«', '«', true, 'left pointing guillemet'], + ['»', '»', true, 'right pointing guillemet'], + ['‘', '‘', true, 'left single quotation mark'], + ['’', '’', true, 'right single quotation mark'], + ['“', '“', true, 'left double quotation mark'], + ['”', '”', true, 'right double quotation mark'], + ['‚', '‚', true, 'single low-9 quotation mark'], + ['„', '„', true, 'double low-9 quotation mark'], + ['<', '<', true, 'less-than sign'], + ['>', '>', true, 'greater-than sign'], + ['≤', '≤', true, 'less-than or equal to'], + ['≥', '≥', true, 'greater-than or equal to'], + ['–', '–', true, 'en dash'], + ['—', '—', true, 'em dash'], + ['¯', '¯', true, 'macron'], + ['‾', '‾', true, 'overline'], + ['¤', '¤', true, 'currency sign'], + ['¦', '¦', true, 'broken bar'], + ['¨', '¨', true, 'diaeresis'], + ['¡', '¡', true, 'inverted exclamation mark'], + ['¿', '¿', true, 'turned question mark'], + ['ˆ', 'ˆ', true, 'circumflex accent'], + ['˜', '˜', true, 'small tilde'], + ['°', '°', true, 'degree sign'], + ['−', '−', true, 'minus sign'], + ['±', '±', true, 'plus-minus sign'], + ['÷', '÷', true, 'division sign'], + ['⁄', '⁄', true, 'fraction slash'], + ['×', '×', true, 'multiplication sign'], + ['¹', '¹', true, 'superscript one'], + ['²', '²', true, 'superscript two'], + ['³', '³', true, 'superscript three'], + ['¼', '¼', true, 'fraction one quarter'], + ['½', '½', true, 'fraction one half'], + ['¾', '¾', true, 'fraction three quarters'], +// math / logical + ['ƒ', 'ƒ', true, 'function / florin'], + ['∫', '∫', true, 'integral'], + ['∑', '∑', true, 'n-ary sumation'], + ['∞', '∞', true, 'infinity'], + ['√', '√', true, 'square root'], + ['∼', '∼', false,'similar to'], + ['≅', '≅', false,'approximately equal to'], + ['≈', '≈', true, 'almost equal to'], + ['≠', '≠', true, 'not equal to'], + ['≡', '≡', true, 'identical to'], + ['∈', '∈', false,'element of'], + ['∉', '∉', false,'not an element of'], + ['∋', '∋', false,'contains as member'], + ['∏', '∏', true, 'n-ary product'], + ['∧', '∧', false,'logical and'], + ['∨', '∨', false,'logical or'], + ['¬', '¬', true, 'not sign'], + ['∩', '∩', true, 'intersection'], + ['∪', '∪', false,'union'], + ['∂', '∂', true, 'partial differential'], + ['∀', '∀', false,'for all'], + ['∃', '∃', false,'there exists'], + ['∅', '∅', false,'diameter'], + ['∇', '∇', false,'backward difference'], + ['∗', '∗', false,'asterisk operator'], + ['∝', '∝', false,'proportional to'], + ['∠', '∠', false,'angle'], +// undefined + ['´', '´', true, 'acute accent'], + ['¸', '¸', true, 'cedilla'], + ['ª', 'ª', true, 'feminine ordinal indicator'], + ['º', 'º', true, 'masculine ordinal indicator'], + ['†', '†', true, 'dagger'], + ['‡', '‡', true, 'double dagger'], +// alphabetical special chars + ['À', 'À', true, 'A - grave'], + ['Á', 'Á', true, 'A - acute'], + ['Â', 'Â', true, 'A - circumflex'], + ['Ã', 'Ã', true, 'A - tilde'], + ['Ä', 'Ä', true, 'A - diaeresis'], + ['Å', 'Å', true, 'A - ring above'], + ['Æ', 'Æ', true, 'ligature AE'], + ['Ç', 'Ç', true, 'C - cedilla'], + ['È', 'È', true, 'E - grave'], + ['É', 'É', true, 'E - acute'], + ['Ê', 'Ê', true, 'E - circumflex'], + ['Ë', 'Ë', true, 'E - diaeresis'], + ['Ì', 'Ì', true, 'I - grave'], + ['Í', 'Í', true, 'I - acute'], + ['Î', 'Î', true, 'I - circumflex'], + ['Ï', 'Ï', true, 'I - diaeresis'], + ['Ð', 'Ð', true, 'ETH'], + ['Ñ', 'Ñ', true, 'N - tilde'], + ['Ò', 'Ò', true, 'O - grave'], + ['Ó', 'Ó', true, 'O - acute'], + ['Ô', 'Ô', true, 'O - circumflex'], + ['Õ', 'Õ', true, 'O - tilde'], + ['Ö', 'Ö', true, 'O - diaeresis'], + ['Ø', 'Ø', true, 'O - slash'], + ['Œ', 'Œ', true, 'ligature OE'], + ['Š', 'Š', true, 'S - caron'], + ['Ù', 'Ù', true, 'U - grave'], + ['Ú', 'Ú', true, 'U - acute'], + ['Û', 'Û', true, 'U - circumflex'], + ['Ü', 'Ü', true, 'U - diaeresis'], + ['Ý', 'Ý', true, 'Y - acute'], + ['Ÿ', 'Ÿ', true, 'Y - diaeresis'], + ['Þ', 'Þ', true, 'THORN'], + ['à', 'à', true, 'a - grave'], + ['á', 'á', true, 'a - acute'], + ['â', 'â', true, 'a - circumflex'], + ['ã', 'ã', true, 'a - tilde'], + ['ä', 'ä', true, 'a - diaeresis'], + ['å', 'å', true, 'a - ring above'], + ['æ', 'æ', true, 'ligature ae'], + ['ç', 'ç', true, 'c - cedilla'], + ['è', 'è', true, 'e - grave'], + ['é', 'é', true, 'e - acute'], + ['ê', 'ê', true, 'e - circumflex'], + ['ë', 'ë', true, 'e - diaeresis'], + ['ì', 'ì', true, 'i - grave'], + ['í', 'í', true, 'i - acute'], + ['î', 'î', true, 'i - circumflex'], + ['ï', 'ï', true, 'i - diaeresis'], + ['ð', 'ð', true, 'eth'], + ['ñ', 'ñ', true, 'n - tilde'], + ['ò', 'ò', true, 'o - grave'], + ['ó', 'ó', true, 'o - acute'], + ['ô', 'ô', true, 'o - circumflex'], + ['õ', 'õ', true, 'o - tilde'], + ['ö', 'ö', true, 'o - diaeresis'], + ['ø', 'ø', true, 'o slash'], + ['œ', 'œ', true, 'ligature oe'], + ['š', 'š', true, 's - caron'], + ['ù', 'ù', true, 'u - grave'], + ['ú', 'ú', true, 'u - acute'], + ['û', 'û', true, 'u - circumflex'], + ['ü', 'ü', true, 'u - diaeresis'], + ['ý', 'ý', true, 'y - acute'], + ['þ', 'þ', true, 'thorn'], + ['ÿ', 'ÿ', true, 'y - diaeresis'], + ['Α', 'Α', true, 'Alpha'], + ['Β', 'Β', true, 'Beta'], + ['Γ', 'Γ', true, 'Gamma'], + ['Δ', 'Δ', true, 'Delta'], + ['Ε', 'Ε', true, 'Epsilon'], + ['Ζ', 'Ζ', true, 'Zeta'], + ['Η', 'Η', true, 'Eta'], + ['Θ', 'Θ', true, 'Theta'], + ['Ι', 'Ι', true, 'Iota'], + ['Κ', 'Κ', true, 'Kappa'], + ['Λ', 'Λ', true, 'Lambda'], + ['Μ', 'Μ', true, 'Mu'], + ['Ν', 'Ν', true, 'Nu'], + ['Ξ', 'Ξ', true, 'Xi'], + ['Ο', 'Ο', true, 'Omicron'], + ['Π', 'Π', true, 'Pi'], + ['Ρ', 'Ρ', true, 'Rho'], + ['Σ', 'Σ', true, 'Sigma'], + ['Τ', 'Τ', true, 'Tau'], + ['Υ', 'Υ', true, 'Upsilon'], + ['Φ', 'Φ', true, 'Phi'], + ['Χ', 'Χ', true, 'Chi'], + ['Ψ', 'Ψ', true, 'Psi'], + ['Ω', 'Ω', true, 'Omega'], + ['α', 'α', true, 'alpha'], + ['β', 'β', true, 'beta'], + ['γ', 'γ', true, 'gamma'], + ['δ', 'δ', true, 'delta'], + ['ε', 'ε', true, 'epsilon'], + ['ζ', 'ζ', true, 'zeta'], + ['η', 'η', true, 'eta'], + ['θ', 'θ', true, 'theta'], + ['ι', 'ι', true, 'iota'], + ['κ', 'κ', true, 'kappa'], + ['λ', 'λ', true, 'lambda'], + ['μ', 'μ', true, 'mu'], + ['ν', 'ν', true, 'nu'], + ['ξ', 'ξ', true, 'xi'], + ['ο', 'ο', true, 'omicron'], + ['π', 'π', true, 'pi'], + ['ρ', 'ρ', true, 'rho'], + ['ς', 'ς', true, 'final sigma'], + ['σ', 'σ', true, 'sigma'], + ['τ', 'τ', true, 'tau'], + ['υ', 'υ', true, 'upsilon'], + ['φ', 'φ', true, 'phi'], + ['χ', 'χ', true, 'chi'], + ['ψ', 'ψ', true, 'psi'], + ['ω', 'ω', true, 'omega'], +// symbols + ['ℵ', 'ℵ', false,'alef symbol'], + ['ϖ', 'ϖ', false,'pi symbol'], + ['ℜ', 'ℜ', false,'real part symbol'], + ['ϑ','ϑ', false,'theta symbol'], + ['ϒ', 'ϒ', false,'upsilon - hook symbol'], + ['℘', '℘', false,'Weierstrass p'], + ['ℑ', 'ℑ', false,'imaginary part'], +// arrows + ['←', '←', true, 'leftwards arrow'], + ['↑', '↑', true, 'upwards arrow'], + ['→', '→', true, 'rightwards arrow'], + ['↓', '↓', true, 'downwards arrow'], + ['↔', '↔', true, 'left right arrow'], + ['↵', '↵', false,'carriage return'], + ['⇐', '⇐', false,'leftwards double arrow'], + ['⇑', '⇑', false,'upwards double arrow'], + ['⇒', '⇒', false,'rightwards double arrow'], + ['⇓', '⇓', false,'downwards double arrow'], + ['⇔', '⇔', false,'left right double arrow'], + ['∴', '∴', false,'therefore'], + ['⊂', '⊂', false,'subset of'], + ['⊃', '⊃', false,'superset of'], + ['⊄', '⊄', false,'not a subset of'], + ['⊆', '⊆', false,'subset of or equal to'], + ['⊇', '⊇', false,'superset of or equal to'], + ['⊕', '⊕', false,'circled plus'], + ['⊗', '⊗', false,'circled times'], + ['⊥', '⊥', false,'perpendicular'], + ['⋅', '⋅', false,'dot operator'], + ['⌈', '⌈', false,'left ceiling'], + ['⌉', '⌉', false,'right ceiling'], + ['⌊', '⌊', false,'left floor'], + ['⌋', '⌋', false,'right floor'], + ['⟨', '〈', false,'left-pointing angle bracket'], + ['⟩', '〉', false,'right-pointing angle bracket'], + ['◊', '◊', true,'lozenge'], + ['♠', '♠', false,'black spade suit'], + ['♣', '♣', true, 'black club suit'], + ['♥', '♥', true, 'black heart suit'], + ['♦', '♦', true, 'black diamond suit'], + [' ', ' ', false,'en space'], + [' ', ' ', false,'em space'], + [' ', ' ', false,'thin space'], + ['‌', '‌', false,'zero width non-joiner'], + ['‍', '‍', false,'zero width joiner'], + ['‎', '‎', false,'left-to-right mark'], + ['‏', '‏', false,'right-to-left mark'], + ['­', '­', false,'soft hyphen'] +]; + +tinyMCEPopup.onInit.add(function() { + tinyMCEPopup.dom.setHTML('charmapView', renderCharMapHTML()); +}); + +function renderCharMapHTML() { + var charsPerRow = 20, tdWidth=20, tdHeight=20, i; + var html = ''; + var cols=-1; + + for (i=0; i' + + '' + + charmap[i][1] + + ''; + if ((cols+1) % charsPerRow == 0) + html += ''; + } + } + + if (cols % charsPerRow > 0) { + var padd = charsPerRow - (cols % charsPerRow); + for (var i=0; i '; + } + + html += '
    '; + + return html; +} + +function insertChar(chr) { + tinyMCEPopup.execCommand('mceInsertContent', false, '&#' + chr + ';'); + + // Refocus in window + if (tinyMCEPopup.isWindow) + window.focus(); + + tinyMCEPopup.editor.focus(); + tinyMCEPopup.close(); +} + +function previewChar(codeA, codeB, codeN) { + var elmA = document.getElementById('codeA'); + var elmB = document.getElementById('codeB'); + var elmV = document.getElementById('codeV'); + var elmN = document.getElementById('codeN'); + + if (codeA=='#160;') { + elmV.innerHTML = '__'; + } else { + elmV.innerHTML = '&' + codeA; + } + + elmB.innerHTML = '&' + codeA; + elmA.innerHTML = '&' + codeB; + elmN.innerHTML = codeN; +} diff --git a/web/js/tiny_mce/themes/advanced/js/color_picker.js b/web/js/tiny_mce/themes/advanced/js/color_picker.js new file mode 100644 index 0000000..da833dc --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/js/color_picker.js @@ -0,0 +1,245 @@ +tinyMCEPopup.requireLangPack(); + +var detail = 50, strhex = "0123456789abcdef", i, isMouseDown = false, isMouseOver = false; + +var colors = [ + "#000000","#000033","#000066","#000099","#0000cc","#0000ff","#330000","#330033", + "#330066","#330099","#3300cc","#3300ff","#660000","#660033","#660066","#660099", + "#6600cc","#6600ff","#990000","#990033","#990066","#990099","#9900cc","#9900ff", + "#cc0000","#cc0033","#cc0066","#cc0099","#cc00cc","#cc00ff","#ff0000","#ff0033", + "#ff0066","#ff0099","#ff00cc","#ff00ff","#003300","#003333","#003366","#003399", + "#0033cc","#0033ff","#333300","#333333","#333366","#333399","#3333cc","#3333ff", + "#663300","#663333","#663366","#663399","#6633cc","#6633ff","#993300","#993333", + "#993366","#993399","#9933cc","#9933ff","#cc3300","#cc3333","#cc3366","#cc3399", + "#cc33cc","#cc33ff","#ff3300","#ff3333","#ff3366","#ff3399","#ff33cc","#ff33ff", + "#006600","#006633","#006666","#006699","#0066cc","#0066ff","#336600","#336633", + "#336666","#336699","#3366cc","#3366ff","#666600","#666633","#666666","#666699", + "#6666cc","#6666ff","#996600","#996633","#996666","#996699","#9966cc","#9966ff", + "#cc6600","#cc6633","#cc6666","#cc6699","#cc66cc","#cc66ff","#ff6600","#ff6633", + "#ff6666","#ff6699","#ff66cc","#ff66ff","#009900","#009933","#009966","#009999", + "#0099cc","#0099ff","#339900","#339933","#339966","#339999","#3399cc","#3399ff", + "#669900","#669933","#669966","#669999","#6699cc","#6699ff","#999900","#999933", + "#999966","#999999","#9999cc","#9999ff","#cc9900","#cc9933","#cc9966","#cc9999", + "#cc99cc","#cc99ff","#ff9900","#ff9933","#ff9966","#ff9999","#ff99cc","#ff99ff", + "#00cc00","#00cc33","#00cc66","#00cc99","#00cccc","#00ccff","#33cc00","#33cc33", + "#33cc66","#33cc99","#33cccc","#33ccff","#66cc00","#66cc33","#66cc66","#66cc99", + "#66cccc","#66ccff","#99cc00","#99cc33","#99cc66","#99cc99","#99cccc","#99ccff", + "#cccc00","#cccc33","#cccc66","#cccc99","#cccccc","#ccccff","#ffcc00","#ffcc33", + "#ffcc66","#ffcc99","#ffcccc","#ffccff","#00ff00","#00ff33","#00ff66","#00ff99", + "#00ffcc","#00ffff","#33ff00","#33ff33","#33ff66","#33ff99","#33ffcc","#33ffff", + "#66ff00","#66ff33","#66ff66","#66ff99","#66ffcc","#66ffff","#99ff00","#99ff33", + "#99ff66","#99ff99","#99ffcc","#99ffff","#ccff00","#ccff33","#ccff66","#ccff99", + "#ccffcc","#ccffff","#ffff00","#ffff33","#ffff66","#ffff99","#ffffcc","#ffffff" +]; + +var named = { + '#F0F8FF':'AliceBlue','#FAEBD7':'AntiqueWhite','#00FFFF':'Aqua','#7FFFD4':'Aquamarine','#F0FFFF':'Azure','#F5F5DC':'Beige', + '#FFE4C4':'Bisque','#000000':'Black','#FFEBCD':'BlanchedAlmond','#0000FF':'Blue','#8A2BE2':'BlueViolet','#A52A2A':'Brown', + '#DEB887':'BurlyWood','#5F9EA0':'CadetBlue','#7FFF00':'Chartreuse','#D2691E':'Chocolate','#FF7F50':'Coral','#6495ED':'CornflowerBlue', + '#FFF8DC':'Cornsilk','#DC143C':'Crimson','#00FFFF':'Cyan','#00008B':'DarkBlue','#008B8B':'DarkCyan','#B8860B':'DarkGoldenRod', + '#A9A9A9':'DarkGray','#A9A9A9':'DarkGrey','#006400':'DarkGreen','#BDB76B':'DarkKhaki','#8B008B':'DarkMagenta','#556B2F':'DarkOliveGreen', + '#FF8C00':'Darkorange','#9932CC':'DarkOrchid','#8B0000':'DarkRed','#E9967A':'DarkSalmon','#8FBC8F':'DarkSeaGreen','#483D8B':'DarkSlateBlue', + '#2F4F4F':'DarkSlateGray','#2F4F4F':'DarkSlateGrey','#00CED1':'DarkTurquoise','#9400D3':'DarkViolet','#FF1493':'DeepPink','#00BFFF':'DeepSkyBlue', + '#696969':'DimGray','#696969':'DimGrey','#1E90FF':'DodgerBlue','#B22222':'FireBrick','#FFFAF0':'FloralWhite','#228B22':'ForestGreen', + '#FF00FF':'Fuchsia','#DCDCDC':'Gainsboro','#F8F8FF':'GhostWhite','#FFD700':'Gold','#DAA520':'GoldenRod','#808080':'Gray','#808080':'Grey', + '#008000':'Green','#ADFF2F':'GreenYellow','#F0FFF0':'HoneyDew','#FF69B4':'HotPink','#CD5C5C':'IndianRed','#4B0082':'Indigo','#FFFFF0':'Ivory', + '#F0E68C':'Khaki','#E6E6FA':'Lavender','#FFF0F5':'LavenderBlush','#7CFC00':'LawnGreen','#FFFACD':'LemonChiffon','#ADD8E6':'LightBlue', + '#F08080':'LightCoral','#E0FFFF':'LightCyan','#FAFAD2':'LightGoldenRodYellow','#D3D3D3':'LightGray','#D3D3D3':'LightGrey','#90EE90':'LightGreen', + '#FFB6C1':'LightPink','#FFA07A':'LightSalmon','#20B2AA':'LightSeaGreen','#87CEFA':'LightSkyBlue','#778899':'LightSlateGray','#778899':'LightSlateGrey', + '#B0C4DE':'LightSteelBlue','#FFFFE0':'LightYellow','#00FF00':'Lime','#32CD32':'LimeGreen','#FAF0E6':'Linen','#FF00FF':'Magenta','#800000':'Maroon', + '#66CDAA':'MediumAquaMarine','#0000CD':'MediumBlue','#BA55D3':'MediumOrchid','#9370D8':'MediumPurple','#3CB371':'MediumSeaGreen','#7B68EE':'MediumSlateBlue', + '#00FA9A':'MediumSpringGreen','#48D1CC':'MediumTurquoise','#C71585':'MediumVioletRed','#191970':'MidnightBlue','#F5FFFA':'MintCream','#FFE4E1':'MistyRose','#FFE4B5':'Moccasin', + '#FFDEAD':'NavajoWhite','#000080':'Navy','#FDF5E6':'OldLace','#808000':'Olive','#6B8E23':'OliveDrab','#FFA500':'Orange','#FF4500':'OrangeRed','#DA70D6':'Orchid', + '#EEE8AA':'PaleGoldenRod','#98FB98':'PaleGreen','#AFEEEE':'PaleTurquoise','#D87093':'PaleVioletRed','#FFEFD5':'PapayaWhip','#FFDAB9':'PeachPuff', + '#CD853F':'Peru','#FFC0CB':'Pink','#DDA0DD':'Plum','#B0E0E6':'PowderBlue','#800080':'Purple','#FF0000':'Red','#BC8F8F':'RosyBrown','#4169E1':'RoyalBlue', + '#8B4513':'SaddleBrown','#FA8072':'Salmon','#F4A460':'SandyBrown','#2E8B57':'SeaGreen','#FFF5EE':'SeaShell','#A0522D':'Sienna','#C0C0C0':'Silver', + '#87CEEB':'SkyBlue','#6A5ACD':'SlateBlue','#708090':'SlateGray','#708090':'SlateGrey','#FFFAFA':'Snow','#00FF7F':'SpringGreen', + '#4682B4':'SteelBlue','#D2B48C':'Tan','#008080':'Teal','#D8BFD8':'Thistle','#FF6347':'Tomato','#40E0D0':'Turquoise','#EE82EE':'Violet', + '#F5DEB3':'Wheat','#FFFFFF':'White','#F5F5F5':'WhiteSmoke','#FFFF00':'Yellow','#9ACD32':'YellowGreen' +}; + +function init() { + var inputColor = convertRGBToHex(tinyMCEPopup.getWindowArg('input_color')); + + tinyMCEPopup.resizeToInnerSize(); + + generatePicker(); + + if (inputColor) { + changeFinalColor(inputColor); + + col = convertHexToRGB(inputColor); + + if (col) + updateLight(col.r, col.g, col.b); + } +} + +function insertAction() { + var color = document.getElementById("color").value, f = tinyMCEPopup.getWindowArg('func'); + + tinyMCEPopup.restoreSelection(); + + if (f) + f(color); + + tinyMCEPopup.close(); +} + +function showColor(color, name) { + if (name) + document.getElementById("colorname").innerHTML = name; + + document.getElementById("preview").style.backgroundColor = color; + document.getElementById("color").value = color.toLowerCase(); +} + +function convertRGBToHex(col) { + var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi"); + + if (!col) + return col; + + var rgb = col.replace(re, "$1,$2,$3").split(','); + if (rgb.length == 3) { + r = parseInt(rgb[0]).toString(16); + g = parseInt(rgb[1]).toString(16); + b = parseInt(rgb[2]).toString(16); + + r = r.length == 1 ? '0' + r : r; + g = g.length == 1 ? '0' + g : g; + b = b.length == 1 ? '0' + b : b; + + return "#" + r + g + b; + } + + return col; +} + +function convertHexToRGB(col) { + if (col.indexOf('#') != -1) { + col = col.replace(new RegExp('[^0-9A-F]', 'gi'), ''); + + r = parseInt(col.substring(0, 2), 16); + g = parseInt(col.substring(2, 4), 16); + b = parseInt(col.substring(4, 6), 16); + + return {r : r, g : g, b : b}; + } + + return null; +} + +function generatePicker() { + var el = document.getElementById('light'), h = '', i; + + for (i = 0; i < detail; i++){ + h += '
    '; + } + + el.innerHTML = h; +} + +function generateWebColors() { + var el = document.getElementById('webcolors'), h = '', i; + + if (el.className == 'generated') + return; + + h += '' + + ''; + + for (i=0; i' + + '' + + ''; + if ((i+1) % 18 == 0) + h += ''; + } + + h += '
    '; + + el.innerHTML = h; + el.className = 'generated'; +} + +function generateNamedColors() { + var el = document.getElementById('namedcolors'), h = '', n, v, i = 0; + + if (el.className == 'generated') + return; + + for (n in named) { + v = named[n]; + h += '' + } + + el.innerHTML = h; + el.className = 'generated'; +} + +function dechex(n) { + return strhex.charAt(Math.floor(n / 16)) + strhex.charAt(n % 16); +} + +function computeColor(e) { + var x, y, partWidth, partDetail, imHeight, r, g, b, coef, i, finalCoef, finalR, finalG, finalB; + + x = e.offsetX ? e.offsetX : (e.target ? e.clientX - e.target.x : 0); + y = e.offsetY ? e.offsetY : (e.target ? e.clientY - e.target.y : 0); + + partWidth = document.getElementById('colors').width / 6; + partDetail = detail / 2; + imHeight = document.getElementById('colors').height; + + r = (x >= 0)*(x < partWidth)*255 + (x >= partWidth)*(x < 2*partWidth)*(2*255 - x * 255 / partWidth) + (x >= 4*partWidth)*(x < 5*partWidth)*(-4*255 + x * 255 / partWidth) + (x >= 5*partWidth)*(x < 6*partWidth)*255; + g = (x >= 0)*(x < partWidth)*(x * 255 / partWidth) + (x >= partWidth)*(x < 3*partWidth)*255 + (x >= 3*partWidth)*(x < 4*partWidth)*(4*255 - x * 255 / partWidth); + b = (x >= 2*partWidth)*(x < 3*partWidth)*(-2*255 + x * 255 / partWidth) + (x >= 3*partWidth)*(x < 5*partWidth)*255 + (x >= 5*partWidth)*(x < 6*partWidth)*(6*255 - x * 255 / partWidth); + + coef = (imHeight - y) / imHeight; + r = 128 + (r - 128) * coef; + g = 128 + (g - 128) * coef; + b = 128 + (b - 128) * coef; + + changeFinalColor('#' + dechex(r) + dechex(g) + dechex(b)); + updateLight(r, g, b); +} + +function updateLight(r, g, b) { + var i, partDetail = detail / 2, finalCoef, finalR, finalG, finalB, color; + + for (i=0; i=0) && (i'); + }, + + init : function() { + var f = document.forms[0], ed = tinyMCEPopup.editor; + + // Setup browse button + document.getElementById('srcbrowsercontainer').innerHTML = getBrowserHTML('srcbrowser','src','image','theme_advanced_image'); + if (isVisible('srcbrowser')) + document.getElementById('src').style.width = '180px'; + + e = ed.selection.getNode(); + + this.fillFileList('image_list', 'tinyMCEImageList'); + + if (e.nodeName == 'IMG') { + f.src.value = ed.dom.getAttrib(e, 'src'); + f.alt.value = ed.dom.getAttrib(e, 'alt'); + f.border.value = this.getAttrib(e, 'border'); + f.vspace.value = this.getAttrib(e, 'vspace'); + f.hspace.value = this.getAttrib(e, 'hspace'); + f.width.value = ed.dom.getAttrib(e, 'width'); + f.height.value = ed.dom.getAttrib(e, 'height'); + f.insert.value = ed.getLang('update'); + this.styleVal = ed.dom.getAttrib(e, 'style'); + selectByValue(f, 'image_list', f.src.value); + selectByValue(f, 'align', this.getAttrib(e, 'align')); + this.updateStyle(); + } + }, + + fillFileList : function(id, l) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl; + + l = window[l]; + + if (l && l.length > 0) { + lst.options[lst.options.length] = new Option('', ''); + + tinymce.each(l, function(o) { + lst.options[lst.options.length] = new Option(o[0], o[1]); + }); + } else + dom.remove(dom.getParent(id, 'tr')); + }, + + update : function() { + var f = document.forms[0], nl = f.elements, ed = tinyMCEPopup.editor, args = {}, el; + + tinyMCEPopup.restoreSelection(); + + if (f.src.value === '') { + if (ed.selection.getNode().nodeName == 'IMG') { + ed.dom.remove(ed.selection.getNode()); + ed.execCommand('mceRepaint'); + } + + tinyMCEPopup.close(); + return; + } + + if (!ed.settings.inline_styles) { + args = tinymce.extend(args, { + vspace : nl.vspace.value, + hspace : nl.hspace.value, + border : nl.border.value, + align : getSelectValue(f, 'align') + }); + } else + args.style = this.styleVal; + + tinymce.extend(args, { + src : f.src.value, + alt : f.alt.value, + width : f.width.value, + height : f.height.value + }); + + el = ed.selection.getNode(); + + if (el && el.nodeName == 'IMG') { + ed.dom.setAttribs(el, args); + } else { + ed.execCommand('mceInsertContent', false, '', {skip_undo : 1}); + ed.dom.setAttribs('__mce_tmp', args); + ed.dom.setAttrib('__mce_tmp', 'id', ''); + ed.undoManager.add(); + } + + tinyMCEPopup.close(); + }, + + updateStyle : function() { + var dom = tinyMCEPopup.dom, st, v, f = document.forms[0]; + + if (tinyMCEPopup.editor.settings.inline_styles) { + st = tinyMCEPopup.dom.parseStyle(this.styleVal); + + // Handle align + v = getSelectValue(f, 'align'); + if (v) { + if (v == 'left' || v == 'right') { + st['float'] = v; + delete st['vertical-align']; + } else { + st['vertical-align'] = v; + delete st['float']; + } + } else { + delete st['float']; + delete st['vertical-align']; + } + + // Handle border + v = f.border.value; + if (v || v == '0') { + if (v == '0') + st['border'] = '0'; + else + st['border'] = v + 'px solid black'; + } else + delete st['border']; + + // Handle hspace + v = f.hspace.value; + if (v) { + delete st['margin']; + st['margin-left'] = v + 'px'; + st['margin-right'] = v + 'px'; + } else { + delete st['margin-left']; + delete st['margin-right']; + } + + // Handle vspace + v = f.vspace.value; + if (v) { + delete st['margin']; + st['margin-top'] = v + 'px'; + st['margin-bottom'] = v + 'px'; + } else { + delete st['margin-top']; + delete st['margin-bottom']; + } + + // Merge + st = tinyMCEPopup.dom.parseStyle(dom.serializeStyle(st)); + this.styleVal = dom.serializeStyle(st); + } + }, + + getAttrib : function(e, at) { + var ed = tinyMCEPopup.editor, dom = ed.dom, v, v2; + + if (ed.settings.inline_styles) { + switch (at) { + case 'align': + if (v = dom.getStyle(e, 'float')) + return v; + + if (v = dom.getStyle(e, 'vertical-align')) + return v; + + break; + + case 'hspace': + v = dom.getStyle(e, 'margin-left') + v2 = dom.getStyle(e, 'margin-right'); + if (v && v == v2) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + + case 'vspace': + v = dom.getStyle(e, 'margin-top') + v2 = dom.getStyle(e, 'margin-bottom'); + if (v && v == v2) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + + case 'border': + v = 0; + + tinymce.each(['top', 'right', 'bottom', 'left'], function(sv) { + sv = dom.getStyle(e, 'border-' + sv + '-width'); + + // False or not the same as prev + if (!sv || (sv != v && v !== 0)) { + v = 0; + return false; + } + + if (sv) + v = sv; + }); + + if (v) + return parseInt(v.replace(/[^0-9]/g, '')); + + break; + } + } + + if (v = dom.getAttrib(e, at)) + return v; + + return ''; + }, + + resetImageData : function() { + var f = document.forms[0]; + + f.width.value = f.height.value = ""; + }, + + updateImageData : function() { + var f = document.forms[0], t = ImageDialog; + + if (f.width.value == "") + f.width.value = t.preloadImg.width; + + if (f.height.value == "") + f.height.value = t.preloadImg.height; + }, + + getImageData : function() { + var f = document.forms[0]; + + this.preloadImg = new Image(); + this.preloadImg.onload = this.updateImageData; + this.preloadImg.onerror = this.resetImageData; + this.preloadImg.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(f.src.value); + } +}; + +ImageDialog.preInit(); +tinyMCEPopup.onInit.add(ImageDialog.init, ImageDialog); diff --git a/web/js/tiny_mce/themes/advanced/js/link.js b/web/js/tiny_mce/themes/advanced/js/link.js new file mode 100644 index 0000000..2974878 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/js/link.js @@ -0,0 +1,155 @@ +tinyMCEPopup.requireLangPack(); + +var LinkDialog = { + preInit : function() { + var url; + + if (url = tinyMCEPopup.getParam("external_link_list_url")) + document.write(''); + }, + + init : function() { + var f = document.forms[0], ed = tinyMCEPopup.editor; + + // Setup browse button + document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser', 'href', 'file', 'theme_advanced_link'); + if (isVisible('hrefbrowser')) + document.getElementById('href').style.width = '180px'; + + this.fillClassList('class_list'); + this.fillFileList('link_list', 'tinyMCELinkList'); + this.fillTargetList('target_list'); + + if (e = ed.dom.getParent(ed.selection.getNode(), 'A')) { + f.href.value = ed.dom.getAttrib(e, 'href'); + f.linktitle.value = ed.dom.getAttrib(e, 'title'); + f.insert.value = ed.getLang('update'); + selectByValue(f, 'link_list', f.href.value); + selectByValue(f, 'target_list', ed.dom.getAttrib(e, 'target')); + selectByValue(f, 'class_list', ed.dom.getAttrib(e, 'class')); + } + }, + + update : function() { + var f = document.forms[0], ed = tinyMCEPopup.editor, e, b; + + tinyMCEPopup.restoreSelection(); + e = ed.dom.getParent(ed.selection.getNode(), 'A'); + + // Remove element if there is no href + if (!f.href.value) { + if (e) { + tinyMCEPopup.execCommand("mceBeginUndoLevel"); + b = ed.selection.getBookmark(); + ed.dom.remove(e, 1); + ed.selection.moveToBookmark(b); + tinyMCEPopup.execCommand("mceEndUndoLevel"); + tinyMCEPopup.close(); + return; + } + } + + tinyMCEPopup.execCommand("mceBeginUndoLevel"); + + // Create new anchor elements + if (e == null) { + tinyMCEPopup.execCommand("CreateLink", false, "#mce_temp_url#", {skip_undo : 1}); + + tinymce.each(ed.dom.select("a"), function(n) { + if (ed.dom.getAttrib(n, 'href') == '#mce_temp_url#') { + e = n; + + ed.dom.setAttribs(e, { + href : f.href.value, + title : f.linktitle.value, + target : f.target_list ? f.target_list.options[f.target_list.selectedIndex].value : null, + 'class' : f.class_list ? f.class_list.options[f.class_list.selectedIndex].value : null + }); + } + }); + } else { + ed.dom.setAttribs(e, { + href : f.href.value, + title : f.linktitle.value, + target : f.target_list ? f.target_list.options[f.target_list.selectedIndex].value : null, + 'class' : f.class_list ? f.class_list.options[f.class_list.selectedIndex].value : null + }); + } + + // Don't move caret if selection was image + if (e.childNodes.length != 1 || e.firstChild.nodeName != 'IMG') { + ed.focus(); + ed.selection.select(e); + ed.selection.collapse(0); + tinyMCEPopup.storeSelection(); + } + + tinyMCEPopup.execCommand("mceEndUndoLevel"); + tinyMCEPopup.close(); + }, + + checkPrefix : function(n) { + if (n.value && Validator.isEmail(n) && !/^\s*mailto:/i.test(n.value) && confirm(tinyMCEPopup.getLang('advanced_dlg.link_is_email'))) + n.value = 'mailto:' + n.value; + + if (/^\s*www./i.test(n.value) && confirm(tinyMCEPopup.getLang('advanced_dlg.link_is_external'))) + n.value = 'http://' + n.value; + }, + + fillFileList : function(id, l) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl; + + l = window[l]; + + if (l && l.length > 0) { + lst.options[lst.options.length] = new Option('', ''); + + tinymce.each(l, function(o) { + lst.options[lst.options.length] = new Option(o[0], o[1]); + }); + } else + dom.remove(dom.getParent(id, 'tr')); + }, + + fillClassList : function(id) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl; + + if (v = tinyMCEPopup.getParam('theme_advanced_styles')) { + cl = []; + + tinymce.each(v.split(';'), function(v) { + var p = v.split('='); + + cl.push({'title' : p[0], 'class' : p[1]}); + }); + } else + cl = tinyMCEPopup.editor.dom.getClasses(); + + if (cl.length > 0) { + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), ''); + + tinymce.each(cl, function(o) { + lst.options[lst.options.length] = new Option(o.title || o['class'], o['class']); + }); + } else + dom.remove(dom.getParent(id, 'tr')); + }, + + fillTargetList : function(id) { + var dom = tinyMCEPopup.dom, lst = dom.get(id), v; + + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), ''); + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_same'), '_self'); + lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_blank'), '_blank'); + + if (v = tinyMCEPopup.getParam('theme_advanced_link_targets')) { + tinymce.each(v.split(','), function(v) { + v = v.split('='); + lst.options[lst.options.length] = new Option(v[0], v[1]); + }); + } + } +}; + +LinkDialog.preInit(); +tinyMCEPopup.onInit.add(LinkDialog.init, LinkDialog); diff --git a/web/js/tiny_mce/themes/advanced/js/source_editor.js b/web/js/tiny_mce/themes/advanced/js/source_editor.js new file mode 100644 index 0000000..af2231c --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/js/source_editor.js @@ -0,0 +1,62 @@ +tinyMCEPopup.requireLangPack(); +tinyMCEPopup.onInit.add(onLoadInit); + +function saveContent() { + tinyMCEPopup.editor.setContent(document.getElementById('htmlSource').value); + tinyMCEPopup.close(); +} + +function onLoadInit() { + tinyMCEPopup.resizeToInnerSize(); + + // Remove Gecko spellchecking + if (tinymce.isGecko) + document.body.spellcheck = tinyMCEPopup.editor.getParam("gecko_spellcheck"); + + document.getElementById('htmlSource').value = tinyMCEPopup.editor.getContent(); + + if (tinyMCEPopup.editor.getParam("theme_advanced_source_editor_wrap", true)) { + setWrap('soft'); + document.getElementById('wraped').checked = true; + } + + resizeInputs(); +} + +function setWrap(val) { + var v, n, s = document.getElementById('htmlSource'); + + s.wrap = val; + + if (!tinymce.isIE) { + v = s.value; + n = s.cloneNode(false); + n.setAttribute("wrap", val); + s.parentNode.replaceChild(n, s); + n.value = v; + } +} + +function toggleWordWrap(elm) { + if (elm.checked) + setWrap('soft'); + else + setWrap('off'); +} + +var wHeight=0, wWidth=0, owHeight=0, owWidth=0; + +function resizeInputs() { + var el = document.getElementById('htmlSource'); + + if (!tinymce.isIE) { + wHeight = self.innerHeight - 65; + wWidth = self.innerWidth - 16; + } else { + wHeight = document.body.clientHeight - 70; + wWidth = document.body.clientWidth - 16; + } + + el.style.height = Math.abs(wHeight) + 'px'; + el.style.width = Math.abs(wWidth) + 'px'; +} diff --git a/web/js/tiny_mce/themes/advanced/langs/en.js b/web/js/tiny_mce/themes/advanced/langs/en.js new file mode 100644 index 0000000..69694b1 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/langs/en.js @@ -0,0 +1,62 @@ +tinyMCE.addI18n('en.advanced',{ +style_select:"Styles", +font_size:"Font size", +fontdefault:"Font family", +block:"Format", +paragraph:"Paragraph", +div:"Div", +address:"Address", +pre:"Preformatted", +h1:"Heading 1", +h2:"Heading 2", +h3:"Heading 3", +h4:"Heading 4", +h5:"Heading 5", +h6:"Heading 6", +blockquote:"Blockquote", +code:"Code", +samp:"Code sample", +dt:"Definition term ", +dd:"Definition description", +bold_desc:"Bold (Ctrl+B)", +italic_desc:"Italic (Ctrl+I)", +underline_desc:"Underline (Ctrl+U)", +striketrough_desc:"Strikethrough", +justifyleft_desc:"Align left", +justifycenter_desc:"Align center", +justifyright_desc:"Align right", +justifyfull_desc:"Align full", +bullist_desc:"Unordered list", +numlist_desc:"Ordered list", +outdent_desc:"Outdent", +indent_desc:"Indent", +undo_desc:"Undo (Ctrl+Z)", +redo_desc:"Redo (Ctrl+Y)", +link_desc:"Insert/edit link", +unlink_desc:"Unlink", +image_desc:"Insert/edit image", +cleanup_desc:"Cleanup messy code", +code_desc:"Edit HTML Source", +sub_desc:"Subscript", +sup_desc:"Superscript", +hr_desc:"Insert horizontal ruler", +removeformat_desc:"Remove formatting", +custom1_desc:"Your custom description here", +forecolor_desc:"Select text color", +backcolor_desc:"Select background color", +charmap_desc:"Insert custom character", +visualaid_desc:"Toggle guidelines/invisible elements", +anchor_desc:"Insert/edit anchor", +cut_desc:"Cut", +copy_desc:"Copy", +paste_desc:"Paste", +image_props_desc:"Image properties", +newdocument_desc:"New document", +help_desc:"Help", +blockquote_desc:"Blockquote", +clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\r\nDo you want more information about this issue?", +path:"Path", +newdocument:"Are you sure you want clear all contents?", +toolbar_focus:"Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X", +more_colors:"More colors" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/langs/en_dlg.js b/web/js/tiny_mce/themes/advanced/langs/en_dlg.js new file mode 100644 index 0000000..9d124d7 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/langs/en_dlg.js @@ -0,0 +1,51 @@ +tinyMCE.addI18n('en.advanced_dlg',{ +about_title:"About TinyMCE", +about_general:"About", +about_help:"Help", +about_license:"License", +about_plugins:"Plugins", +about_plugin:"Plugin", +about_author:"Author", +about_version:"Version", +about_loaded:"Loaded plugins", +anchor_title:"Insert/edit anchor", +anchor_name:"Anchor name", +code_title:"HTML Source Editor", +code_wordwrap:"Word wrap", +colorpicker_title:"Select a color", +colorpicker_picker_tab:"Picker", +colorpicker_picker_title:"Color picker", +colorpicker_palette_tab:"Palette", +colorpicker_palette_title:"Palette colors", +colorpicker_named_tab:"Named", +colorpicker_named_title:"Named colors", +colorpicker_color:"Color:", +colorpicker_name:"Name:", +charmap_title:"Select custom character", +image_title:"Insert/edit image", +image_src:"Image URL", +image_alt:"Image description", +image_list:"Image list", +image_border:"Border", +image_dimensions:"Dimensions", +image_vspace:"Vertical space", +image_hspace:"Horizontal space", +image_align:"Alignment", +image_align_baseline:"Baseline", +image_align_top:"Top", +image_align_middle:"Middle", +image_align_bottom:"Bottom", +image_align_texttop:"Text top", +image_align_textbottom:"Text bottom", +image_align_left:"Left", +image_align_right:"Right", +link_title:"Insert/edit link", +link_url:"Link URL", +link_target:"Target", +link_target_same:"Open link in the same window", +link_target_blank:"Open link in a new window", +link_titlefield:"Title", +link_is_email:"The URL you entered seems to be an email address, do you want to add the required mailto: prefix?", +link_is_external:"The URL you entered seems to external link, do you want to add the required http:// prefix?", +link_list:"Link list" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/langs/nb.js b/web/js/tiny_mce/themes/advanced/langs/nb.js new file mode 100644 index 0000000..582462b --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/langs/nb.js @@ -0,0 +1,62 @@ +tinyMCE.addI18n('nb.advanced',{ +style_select:"Stiler", +font_size:"Skriftst\u00F8rrelse", +fontdefault:"Skriftfamilie", +block:"Format", +paragraph:"Avsnitt", +div:"Div", +address:"Adresse", +pre:"Pre-formatert", +h1:"Overskrift 1", +h2:"Overskrift 2", +h3:"Overskrift 3", +h4:"Overskrift 4", +h5:"Overskrift 5", +h6:"Overskrift 6", +blockquote:"Innrykkinnrykk", +code:"Kode", +samp:"Kodeeksempel", +dt:"Definisjonsuttrykk", +dd:"Definisjonsbeskrivelse", +bold_desc:"Fet", +italic_desc:"Kursiv", +underline_desc:"Understreking", +striketrough_desc:"Gjennomstreking", +justifyleft_desc:"Venstrejuster", +justifycenter_desc:"Midtstill", +justifyright_desc:"H\u00F8yrejuster", +justifyfull_desc:"Blokkjuster", +bullist_desc:"Punktliste", +numlist_desc:"Nummerliste", +outdent_desc:"Reduser innrykk", +indent_desc:"\u00D8k innrykk", +undo_desc:"Angre", +redo_desc:"Gj\u00F8r om", +link_desc:"Sett inn / endre lenke", +unlink_desc:"Fjern lenke", +image_desc:"Sett inn / endre bilde", +cleanup_desc:"Rens ukurant kode", +code_desc:"Redigere HTML-koden", +sub_desc:"Senket skrift", +sup_desc:"Hevet skrift", +hr_desc:"Sett inn horisontal linje", +removeformat_desc:"Fjern formatering", +custom1_desc:"Beskrivelse av spesialfunksjon", +forecolor_desc:"Velg skriftfarge", +backcolor_desc:"Velg bakgrunnsfarge", +charmap_desc:"Sett inn spesialtegn", +visualaid_desc:"Sl\u00E5 av/p\u00E5 usynlige elementer", +anchor_desc:"Sett inn / endre anker", +cut_desc:"Klipp ut", +copy_desc:"Kopier", +paste_desc:"Lim inn", +image_props_desc:"Bildeegenskaper", +newdocument_desc:"Nytt dokument", +help_desc:"Hjelp", +blockquote_desc:"Innrykk", +clipboard_msg:"Klipp ut / Kopier /Lim inn fungerer ikke i Mozilla og Firefox. \r\n Vil du vite mer om dette?", +path:"Sti", +newdocument:"Er du sikker p\u00E5 at du vil slette alt innhold?", +toolbar_focus:"Skift til verkt\u00F8yknapper - Alt+Q, Skift til editor - Alt-Z, Skift til elementsti - Alt-", +more_colors:"Flere farger" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/langs/nb_dlg.js b/web/js/tiny_mce/themes/advanced/langs/nb_dlg.js new file mode 100644 index 0000000..59f3751 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/langs/nb_dlg.js @@ -0,0 +1,51 @@ +tinyMCE.addI18n('nb.advanced_dlg',{ +about_title:"Om TinyMCE", +about_general:"Om", +about_help:"Hjelp", +about_license:"Lisens", +about_plugins:"Programtillegg", +about_plugin:"Programtillegg", +about_author:"Utvikler", +about_version:"Versjon", +about_loaded:"Lastede programtillegg", +anchor_title:"Sett inn / endre anker", +anchor_name:"Ankernavn", +code_title:"HTML-editor", +code_wordwrap:"Tekstbryting", +colorpicker_title:"Velg en farge", +colorpicker_picker_tab:"Velg farge", +colorpicker_picker_title:"Fargevalg", +colorpicker_palette_tab:"Palett", +colorpicker_palette_title:"Palettfarger", +colorpicker_named_tab:"Navnevalg", +colorpicker_named_title:"Fargenavn", +colorpicker_color:"Farge:", +colorpicker_name:"Navn:", +charmap_title:"Velg spesialtegn", +image_title:"Sett inn / endre bilde", +image_src:"Bildets URL", +image_alt:"Bildebeskrivelse", +image_list:"Bildeliste", +image_border:"Ramme", +image_dimensions:"Dimensjoner", +image_vspace:"Vertikal avstand", +image_hspace:"Horisontal avstand", +image_align:"Justering", +image_align_baseline:"Bunnlinje", +image_align_top:"Topp", +image_align_middle:"Midtstilt", +image_align_bottom:"Bunn", +image_align_texttop:"Teksttopp", +image_align_textbottom:"Tekstbunn", +image_align_left:"Venstre", +image_align_right:"H\u00F8yre", +link_title:"Sett inn /endre lenke", +link_url:"Lenkens URL", +link_target:"M\u00E5lside", +link_target_same:"\u00C5pne i dette vinduet", +link_target_blank:"\u00C5pne i nytt vindu", +link_titlefield:"Tittel", +link_is_email:"Nettadressen du skrev inn ser ut til \u00E5 v\u00E6re en e-postadresse. \u00D8nsker du \u00E5 legge til det p\u00E5krevde mailto:-prefikset?", +link_is_external:"Nettadressen du skrev inn ser ut til \u00E5 v\u00E6re en ekstern nettadresse. \u00D8nsker du \u00E5 legge til det p\u00E5krevde http://-prefikset?", +link_list:"Lenkeliste" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/langs/nn.js b/web/js/tiny_mce/themes/advanced/langs/nn.js new file mode 100644 index 0000000..ccd721a --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/langs/nn.js @@ -0,0 +1,62 @@ +tinyMCE.addI18n('nn.advanced',{ +style_select:"Stilar", +font_size:"Skriftstorleik", +fontdefault:"Skriftfamilie", +block:"Format", +paragraph:"Avsnitt", +div:"Div", +address:"Adresse", +pre:"Pre-formatert", +h1:"Overskrift 1", +h2:"Overskrift 2", +h3:"Overskrift 3", +h4:"Overskrift 4", +h5:"Overskrift 5", +h6:"Overskrift 6", +blockquote:"Innrykk", +code:"Kode", +samp:"Kodeeksempel", +dt:"Definisjonsuttrykk", +dd:"Definisjonsbeskrivelse", +bold_desc:"Feit", +italic_desc:"Kursiv", +underline_desc:"Understreking", +striketrough_desc:"Gjennomstreking", +justifyleft_desc:"Venstrejustert", +justifycenter_desc:"Midtstilt", +justifyright_desc:"H\u00F8grejustert", +justifyfull_desc:"Blokkjustert", +bullist_desc:"Punktliste", +numlist_desc:"Nummerliste", +outdent_desc:"Reduser innrykk", +indent_desc:"Auk innrykk", +undo_desc:"Angre", +redo_desc:"Gjer om", +link_desc:"Set inn / endre lenkje", +unlink_desc:"Fjern lenkje", +image_desc:"Set inn / endre bilete", +cleanup_desc:"Rens grisete kode", +code_desc:"Redigere HTML-koden", +sub_desc:"Senka skrift", +sup_desc:"Heva skrift", +hr_desc:"Set inn horisontal linje", +removeformat_desc:"Fjern formatering", +custom1_desc:"Din spesialfunksjondefinisjon her", +forecolor_desc:"Vel skriftfarge", +backcolor_desc:"Vel bakgrunnsfarge", +charmap_desc:"Set inn spesialteikn", +visualaid_desc:"Sl\u00E5 av/p\u00E5 usynlige element", +anchor_desc:"Set inn / endre anker", +cut_desc:"Klipp ut", +copy_desc:"Kopier", +paste_desc:"Lim inn", +image_props_desc:"Eigenskaper for bilete", +newdocument_desc:"Nytt dokument", +help_desc:"Hjelp", +blockquote_desc:"Innrykk", +clipboard_msg:"Klipp ut / Kopier /Lim inn fungerer ikkje i Mozilla og Firefox. \r\n Vil du vite meir om dette?", +path:"Sti", +newdocument:"Er du sikker p\u00E5 at du vil slette alt innhald?", +toolbar_focus:"Skift til verktyknappar - Alt+Q, Skift til editor - Alt-Z, Skift til elementsti - Alt-", +more_colors:"Fleire fargar" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/langs/nn_dlg.js b/web/js/tiny_mce/themes/advanced/langs/nn_dlg.js new file mode 100644 index 0000000..d03b087 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/langs/nn_dlg.js @@ -0,0 +1,51 @@ +tinyMCE.addI18n('nn.advanced_dlg',{ +about_title:"Om TinyMCE", +about_general:"Om", +about_help:"Hjelp", +about_license:"Lisens", +about_plugins:"Programtillegg", +about_plugin:"Programtillegg", +about_author:"Utviklar", +about_version:"Versjon", +about_loaded:"Lasta programtillegg", +anchor_title:"Set inn / endre anker", +anchor_name:"Ankernamn", +code_title:"HTML-editor", +code_wordwrap:"Tekstbryting", +colorpicker_title:"Vel ein farge", +colorpicker_picker_tab:"Vel farge", +colorpicker_picker_title:"Fargeval", +colorpicker_palette_tab:"Palett", +colorpicker_palette_title:"Palettfargar", +colorpicker_named_tab:"Namneval", +colorpicker_named_title:"Fargenamn", +colorpicker_color:"Farge:", +colorpicker_name:"Namn:", +charmap_title:"Vel spesialteikn", +image_title:"Set inn / endre bilete", +image_src:"Bilete-URL", +image_alt:"Bileteomtale", +image_list:"Liste med bilete", +image_border:"Ramme", +image_dimensions:"Dimensjonar", +image_vspace:"Vertikal avstand", +image_hspace:"Horisontal avstand", +image_align:"Justering", +image_align_baseline:"Botnlinje", +image_align_top:"Topp", +image_align_middle:"Midtstilt", +image_align_bottom:"Botn", +image_align_texttop:"Teksttopp", +image_align_textbottom:"Tekstbotn", +image_align_left:"Venstre", +image_align_right:"H\u00F8gre", +link_title:"Set inn / endre lenkje", +link_url:"Lenkje-URL", +link_target:"Vindauge", +link_target_same:"Opne i dette vindauget", +link_target_blank:"Opne i nytt vindauget", +link_titlefield:"Tittel", +link_is_email:"Nettadressa du skreiv inn ser ut til \u00E5 vere ein e-postadresse. \u00D8nskjer du \u00E5 leggje til det obligatoriske mailto:-prefikset?", +link_is_external:"Nettadressa du skreiv inn ser ut til \u00E5 vere ein ekstern nettadresse. \u00D8nskjer du \u00E5 leggje til det obligatoriske http://-prefikset?", +link_list:"Lenkjeliste" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/link.htm b/web/js/tiny_mce/themes/advanced/link.htm new file mode 100644 index 0000000..68c1dab --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/link.htm @@ -0,0 +1,64 @@ + + + + {#advanced_dlg.link_title} + + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    +
    +
    + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/themes/advanced/skins/default/content.css b/web/js/tiny_mce/themes/advanced/skins/default/content.css new file mode 100644 index 0000000..348b621 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/skins/default/content.css @@ -0,0 +1,27 @@ +body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:2px;} +body {background:#FFF;} +body.mceForceColors {background:#FFF; color:#000;} +h1 {font-size: 2em} +h2 {font-size: 1.5em} +h3 {font-size: 1.17em} +h4 {font-size: 1em} +h5 {font-size: .83em} +h6 {font-size: .75em} +.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;} +a.mceItemAnchor {width:12px; line-height:6px; overflow:hidden; padding-left:12px; background:url(img/items.gif) no-repeat bottom left;} +img.mceItemAnchor {width:12px; height:12px; background:url(img/items.gif) no-repeat;} +img {border:0;} +table {cursor:default} +table td, table th {cursor:text} + +/* IE */ +* html body { +scrollbar-3dlight-color:#F0F0EE; +scrollbar-arrow-color:#676662; +scrollbar-base-color:#F0F0EE; +scrollbar-darkshadow-color:#DDD; +scrollbar-face-color:#E0E0DD; +scrollbar-highlight-color:#F0F0EE; +scrollbar-shadow-color:#F0F0EE; +scrollbar-track-color:#F5F5F5; +} diff --git a/web/js/tiny_mce/themes/advanced/skins/default/dialog.css b/web/js/tiny_mce/themes/advanced/skins/default/dialog.css new file mode 100644 index 0000000..c944a60 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/skins/default/dialog.css @@ -0,0 +1,114 @@ +/* Generic */ +body { +font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; +scrollbar-3dlight-color:#F0F0EE; +scrollbar-arrow-color:#676662; +scrollbar-base-color:#F0F0EE; +scrollbar-darkshadow-color:#DDDDDD; +scrollbar-face-color:#E0E0DD; +scrollbar-highlight-color:#F0F0EE; +scrollbar-shadow-color:#F0F0EE; +scrollbar-track-color:#F5F5F5; +background:#F0F0EE; +padding:0; +margin:8px 8px 0 8px; +} + +html {background:#F0F0EE;} +td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +textarea {resize:none;outline:none;} +a:link, a:visited {color:black;} +a:hover {color:#2B6FB6;} + +/* Forms */ +fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;} +legend {color:#2B6FB6; font-weight:bold;} +label.msg {display:none;} +label.invalid {color:#EE0000; display:inline;} +input.invalid {border:1px solid #EE0000;} +input {background:#FFF; border:1px solid #CCC;} +input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +input, select, textarea {border:1px solid #808080;} +input.radio {border:1px none #000000; background:transparent; vertical-align:middle;} +input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;} +.input_noborder {border:0;} + +/* Buttons */ +#insert, #cancel, input.button, .updateButton { +border:0; margin:0; padding:0; +font-weight:bold; +width:94px; height:26px; +background:url(img/buttons.png) 0 -26px; +cursor:pointer; +padding-bottom:2px; +} + +#insert {background:url(img/buttons.png) 0 -52px;} +#cancel {background:url(img/buttons.png) 0 0;} + +/* Browse */ +a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;} +.mceOldBoxModel a.browse span {width:22px; height:20px;} +a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;} +a.browse span.disabled {border:1px solid white; -moz-opacity:0.3; opacity:0.3; filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);} +a.browse:hover span.disabled {border:1px solid white; background-color:transparent;} +a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;} +.mceOldBoxModel a.pickcolor span {width:21px; height:17px;} +a.pickcolor:hover span {background-color:#B2BBD0;} +a.pickcolor:hover span.disabled {} + +/* Charmap */ +table.charmap {border:1px solid #AAA; text-align:center} +td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;} +#charmap a {display:block; color:#000; text-decoration:none; border:0} +#charmap a:hover {background:#CCC;color:#2B6FB6} +#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center} +#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center} + +/* Source */ +.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;} +.mceActionPanel {margin-top:5px;} + +/* Tabs classes */ +.tabs {width:100%; height:18px; line-height:normal; background:url(img/tabs.gif) repeat-x 0 -72px;} +.tabs ul {margin:0; padding:0; list-style:none;} +.tabs li {float:left; background:url(img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;} +.tabs li.current {background:url(img/tabs.gif) no-repeat 0 -18px; margin-right:2px;} +.tabs span {float:left; display:block; background:url(img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;} +.tabs .current span {background:url(img/tabs.gif) no-repeat right -54px;} +.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;} +.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;} + +/* Panels */ +.panel_wrapper div.panel {display:none;} +.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;} +.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;} + +/* Columns */ +.column {float:left;} +.properties {width:100%;} +.properties .column1 {} +.properties .column2 {text-align:left;} + +/* Titles */ +h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;} +h3 {font-size:14px;} +.title {font-size:12px; font-weight:bold; color:#2B6FB6;} + +/* Dialog specific */ +#link .panel_wrapper, #link div.current {height:125px;} +#image .panel_wrapper, #image div.current {height:200px;} +#plugintable thead {font-weight:bold; background:#DDD;} +#plugintable, #about #plugintable td {border:1px solid #919B9C;} +#plugintable {width:96%; margin-top:10px;} +#pluginscontainer {height:290px; overflow:auto;} +#colorpicker #preview {float:right; width:50px; height:14px;line-height:1px; border:1px solid black; margin-left:5px;} +#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;} +#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;} +#colorpicker #light div {overflow:hidden;} +#colorpicker #previewblock {float:right; padding-left:10px; height:20px;} +#colorpicker .panel_wrapper div.current {height:175px;} +#colorpicker #namedcolors {width:150px;} +#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;} +#colorpicker #colornamecontainer {margin-top:5px;} +#colorpicker #picker_panel fieldset {margin:auto;width:325px;} \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/skins/default/img/buttons.png b/web/js/tiny_mce/themes/advanced/skins/default/img/buttons.png new file mode 100644 index 0000000..7dd5841 Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/default/img/buttons.png differ diff --git a/web/js/tiny_mce/themes/advanced/skins/default/img/items.gif b/web/js/tiny_mce/themes/advanced/skins/default/img/items.gif new file mode 100644 index 0000000..2eafd79 Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/default/img/items.gif differ diff --git a/web/js/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif b/web/js/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif new file mode 100644 index 0000000..85e31df Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif differ diff --git a/web/js/tiny_mce/themes/advanced/skins/default/img/menu_check.gif b/web/js/tiny_mce/themes/advanced/skins/default/img/menu_check.gif new file mode 100644 index 0000000..adfdddc Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/default/img/menu_check.gif differ diff --git a/web/js/tiny_mce/themes/advanced/skins/default/img/progress.gif b/web/js/tiny_mce/themes/advanced/skins/default/img/progress.gif new file mode 100644 index 0000000..5bb90fd Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/default/img/progress.gif differ diff --git a/web/js/tiny_mce/themes/advanced/skins/default/img/tabs.gif b/web/js/tiny_mce/themes/advanced/skins/default/img/tabs.gif new file mode 100644 index 0000000..ce4be63 Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/default/img/tabs.gif differ diff --git a/web/js/tiny_mce/themes/advanced/skins/default/ui.css b/web/js/tiny_mce/themes/advanced/skins/default/ui.css new file mode 100644 index 0000000..7e202a7 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/skins/default/ui.css @@ -0,0 +1,215 @@ +/* Reset */ +.defaultSkin table, .defaultSkin tbody, .defaultSkin a, .defaultSkin img, .defaultSkin tr, .defaultSkin div, .defaultSkin td, .defaultSkin iframe, .defaultSkin span, .defaultSkin *, .defaultSkin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left} +.defaultSkin a:hover, .defaultSkin a:link, .defaultSkin a:visited, .defaultSkin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000} +.defaultSkin table td {vertical-align:middle} + +/* Containers */ +.defaultSkin table {background:#F0F0EE} +.defaultSkin iframe {display:block; background:#FFF} +.defaultSkin .mceToolbar {height:26px} +.defaultSkin .mceLeft {text-align:left} +.defaultSkin .mceRight {text-align:right} + +/* External */ +.defaultSkin .mceExternalToolbar {position:absolute; border:1px solid #CCC; border-bottom:0; display:none;} +.defaultSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;} +.defaultSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0} + +/* Layout */ +.defaultSkin table.mceLayout {border:0; border-left:1px solid #CCC; border-right:1px solid #CCC} +.defaultSkin table.mceLayout tr.mceFirst td {border-top:1px solid #CCC} +.defaultSkin table.mceLayout tr.mceLast td {border-bottom:1px solid #CCC} +.defaultSkin table.mceToolbar, .defaultSkin tr.mceFirst .mceToolbar tr td, .defaultSkin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0;} +.defaultSkin td.mceToolbar {padding-top:1px; vertical-align:top} +.defaultSkin .mceIframeContainer {border-top:1px solid #CCC; border-bottom:1px solid #CCC} +.defaultSkin .mceStatusbar {font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; display:block; height:20px} +.defaultSkin .mceStatusbar div {float:left; margin:2px} +.defaultSkin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize} +.defaultSkin .mceStatusbar a:hover {text-decoration:underline} +.defaultSkin table.mceToolbar {margin-left:3px} +.defaultSkin span.mceIcon, .defaultSkin img.mceIcon {display:block; width:20px; height:20px} +.defaultSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} +.defaultSkin td.mceCenter {text-align:center;} +.defaultSkin td.mceCenter table {margin:0 auto; text-align:left;} +.defaultSkin td.mceRight table {margin:0 0 0 auto;} + +/* Button */ +.defaultSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px; margin-right:1px} +.defaultSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0} +.defaultSkin a.mceButtonActive, .defaultSkin a.mceButtonSelected {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSkin .mceButtonDisabled .mceIcon {opacity:0.3; filter:alpha(opacity=30)} +.defaultSkin .mceButtonLabeled {width:auto} +.defaultSkin .mceButtonLabeled span.mceIcon {float:left} +.defaultSkin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica} +.defaultSkin .mceButtonDisabled .mceButtonLabel {color:#888} + +/* Separator */ +.defaultSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:2px 2px 0 4px} + +/* ListBox */ +.defaultSkin .mceListBox {direction:ltr} +.defaultSkin .mceListBox, .defaultSkin .mceListBox a {display:block} +.defaultSkin .mceListBox .mceText {padding-left:4px; width:70px; text-align:left; border:1px solid #CCC; border-right:0; background:#FFF; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden} +.defaultSkin .mceListBox .mceOpen {width:9px; height:20px; background:url(../../img/icons.gif) -741px 0; margin-right:2px; border:1px solid #CCC;} +.defaultSkin table.mceListBoxEnabled:hover .mceText, .defaultSkin .mceListBoxHover .mceText, .defaultSkin .mceListBoxSelected .mceText {border:1px solid #A2ABC0; border-right:0; background:#FFF} +.defaultSkin table.mceListBoxEnabled:hover .mceOpen, .defaultSkin .mceListBoxHover .mceOpen, .defaultSkin .mceListBoxSelected .mceOpen {background-color:#FFF; border:1px solid #A2ABC0} +.defaultSkin .mceListBoxDisabled a.mceText {color:gray; background-color:transparent;} +.defaultSkin .mceListBoxMenu {overflow:auto; overflow-x:hidden} +.defaultSkin .mceOldBoxModel .mceListBox .mceText {height:22px} +.defaultSkin .mceOldBoxModel .mceListBox .mceOpen {width:11px; height:22px;} +.defaultSkin select.mceNativeListBox {font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:7pt; background:#F0F0EE; border:1px solid gray; margin-right:2px;} + +/* SplitButton */ +.defaultSkin .mceSplitButton {width:32px; height:20px; direction:ltr} +.defaultSkin .mceSplitButton a, .defaultSkin .mceSplitButton span {height:20px; display:block} +.defaultSkin .mceSplitButton a.mceAction {width:20px; border:1px solid #F0F0EE; border-right:0;} +.defaultSkin .mceSplitButton span.mceAction {width:20px; background:url(../../img/icons.gif) 20px 20px;} +.defaultSkin .mceSplitButton a.mceOpen {width:9px; border:1px solid #F0F0EE;} +.defaultSkin .mceSplitButton span.mceOpen {width:9px; background:url(../../img/icons.gif) -741px 0;} +.defaultSkin table.mceSplitButtonEnabled:hover a.mceAction, .defaultSkin .mceSplitButtonHover a.mceAction, .defaultSkin .mceSplitButtonSelected a.mceAction {border:1px solid #0A246A; border-right:0; background-color:#B2BBD0} +.defaultSkin table.mceSplitButtonEnabled:hover a.mceOpen, .defaultSkin .mceSplitButtonHover a.mceOpen, .defaultSkin .mceSplitButtonSelected a.mceOpen {border:1px solid #0A246A;} +.defaultSkin table.mceSplitButtonEnabled:hover span.mceOpen, .defaultSkin .mceSplitButtonHover span.mceOpen, .defaultSkin .mceSplitButtonSelected span.mceOpen {background-color:#B2BBD0} +.defaultSkin .mceSplitButtonDisabled .mceAction, .defaultSkin .mceSplitButtonDisabled span.mceOpen {opacity:0.3; filter:alpha(opacity=30)} +.defaultSkin .mceSplitButtonActive a.mceAction {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSkin .mceSplitButtonActive a.mceOpen {border-left:0;} + +/* ColorSplitButton */ +.defaultSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray} +.defaultSkin .mceColorSplitMenu td {padding:2px} +.defaultSkin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080} +.defaultSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px} +.defaultSkin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF} +.defaultSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2} +.defaultSkin a.mceMoreColors:hover {border:1px solid #0A246A} +.defaultSkin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a} +.defaultSkin .mce_forecolor span.mceAction, .defaultSkin .mce_backcolor span.mceAction {overflow:hidden; height:16px} + +/* Menu */ +.defaultSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #D4D0C8} +.defaultSkin .mceNoIcons span.mceIcon {width:0;} +.defaultSkin .mceNoIcons a .mceText {padding-left:10px} +.defaultSkin .mceMenu table {background:#FFF} +.defaultSkin .mceMenu a, .defaultSkin .mceMenu span, .defaultSkin .mceMenu {display:block} +.defaultSkin .mceMenu td {height:20px} +.defaultSkin .mceMenu a {position:relative;padding:3px 0 4px 0} +.defaultSkin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block} +.defaultSkin .mceMenu span.mceText, .defaultSkin .mceMenu .mcePreview {font-size:11px} +.defaultSkin .mceMenu pre.mceText {font-family:Monospace} +.defaultSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;} +.defaultSkin .mceMenu .mceMenuItemEnabled a:hover, .defaultSkin .mceMenu .mceMenuItemActive {background-color:#dbecf3} +.defaultSkin td.mceMenuItemSeparator {background:#DDD; height:1px} +.defaultSkin .mceMenuItemTitle a {border:0; background:#EEE; border-bottom:1px solid #DDD} +.defaultSkin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px} +.defaultSkin .mceMenuItemDisabled .mceText {color:#888} +.defaultSkin .mceMenuItemSelected .mceIcon {background:url(img/menu_check.gif)} +.defaultSkin .mceNoIcons .mceMenuItemSelected a {background:url(img/menu_arrow.gif) no-repeat -6px center} +.defaultSkin .mceMenu span.mceMenuLine {display:none} +.defaultSkin .mceMenuItemSub a {background:url(img/menu_arrow.gif) no-repeat top right;} + +/* Progress,Resize */ +.defaultSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; filter:alpha(opacity=50); background:#FFF} +.defaultSkin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px} +.defaultSkin .mcePlaceHolder {border:1px dotted gray} + +/* Formats */ +.defaultSkin .mce_formatPreview a {font-size:10px} +.defaultSkin .mce_p span.mceText {} +.defaultSkin .mce_address span.mceText {font-style:italic} +.defaultSkin .mce_pre span.mceText {font-family:monospace} +.defaultSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em} +.defaultSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em} +.defaultSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em} +.defaultSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em} +.defaultSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em} +.defaultSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em} + +/* Theme */ +.defaultSkin span.mce_bold {background-position:0 0} +.defaultSkin span.mce_italic {background-position:-60px 0} +.defaultSkin span.mce_underline {background-position:-140px 0} +.defaultSkin span.mce_strikethrough {background-position:-120px 0} +.defaultSkin span.mce_undo {background-position:-160px 0} +.defaultSkin span.mce_redo {background-position:-100px 0} +.defaultSkin span.mce_cleanup {background-position:-40px 0} +.defaultSkin span.mce_bullist {background-position:-20px 0} +.defaultSkin span.mce_numlist {background-position:-80px 0} +.defaultSkin span.mce_justifyleft {background-position:-460px 0} +.defaultSkin span.mce_justifyright {background-position:-480px 0} +.defaultSkin span.mce_justifycenter {background-position:-420px 0} +.defaultSkin span.mce_justifyfull {background-position:-440px 0} +.defaultSkin span.mce_anchor {background-position:-200px 0} +.defaultSkin span.mce_indent {background-position:-400px 0} +.defaultSkin span.mce_outdent {background-position:-540px 0} +.defaultSkin span.mce_link {background-position:-500px 0} +.defaultSkin span.mce_unlink {background-position:-640px 0} +.defaultSkin span.mce_sub {background-position:-600px 0} +.defaultSkin span.mce_sup {background-position:-620px 0} +.defaultSkin span.mce_removeformat {background-position:-580px 0} +.defaultSkin span.mce_newdocument {background-position:-520px 0} +.defaultSkin span.mce_image {background-position:-380px 0} +.defaultSkin span.mce_help {background-position:-340px 0} +.defaultSkin span.mce_code {background-position:-260px 0} +.defaultSkin span.mce_hr {background-position:-360px 0} +.defaultSkin span.mce_visualaid {background-position:-660px 0} +.defaultSkin span.mce_charmap {background-position:-240px 0} +.defaultSkin span.mce_paste {background-position:-560px 0} +.defaultSkin span.mce_copy {background-position:-700px 0} +.defaultSkin span.mce_cut {background-position:-680px 0} +.defaultSkin span.mce_blockquote {background-position:-220px 0} +.defaultSkin .mce_forecolor span.mceAction {background-position:-720px 0} +.defaultSkin .mce_backcolor span.mceAction {background-position:-760px 0} +.defaultSkin span.mce_forecolorpicker {background-position:-720px 0} +.defaultSkin span.mce_backcolorpicker {background-position:-760px 0} + +/* Plugins */ +.defaultSkin span.mce_advhr {background-position:-0px -20px} +.defaultSkin span.mce_ltr {background-position:-20px -20px} +.defaultSkin span.mce_rtl {background-position:-40px -20px} +.defaultSkin span.mce_emotions {background-position:-60px -20px} +.defaultSkin span.mce_fullpage {background-position:-80px -20px} +.defaultSkin span.mce_fullscreen {background-position:-100px -20px} +.defaultSkin span.mce_iespell {background-position:-120px -20px} +.defaultSkin span.mce_insertdate {background-position:-140px -20px} +.defaultSkin span.mce_inserttime {background-position:-160px -20px} +.defaultSkin span.mce_absolute {background-position:-180px -20px} +.defaultSkin span.mce_backward {background-position:-200px -20px} +.defaultSkin span.mce_forward {background-position:-220px -20px} +.defaultSkin span.mce_insert_layer {background-position:-240px -20px} +.defaultSkin span.mce_insertlayer {background-position:-260px -20px} +.defaultSkin span.mce_movebackward {background-position:-280px -20px} +.defaultSkin span.mce_moveforward {background-position:-300px -20px} +.defaultSkin span.mce_media {background-position:-320px -20px} +.defaultSkin span.mce_nonbreaking {background-position:-340px -20px} +.defaultSkin span.mce_pastetext {background-position:-360px -20px} +.defaultSkin span.mce_pasteword {background-position:-380px -20px} +.defaultSkin span.mce_selectall {background-position:-400px -20px} +.defaultSkin span.mce_preview {background-position:-420px -20px} +.defaultSkin span.mce_print {background-position:-440px -20px} +.defaultSkin span.mce_cancel {background-position:-460px -20px} +.defaultSkin span.mce_save {background-position:-480px -20px} +.defaultSkin span.mce_replace {background-position:-500px -20px} +.defaultSkin span.mce_search {background-position:-520px -20px} +.defaultSkin span.mce_styleprops {background-position:-560px -20px} +.defaultSkin span.mce_table {background-position:-580px -20px} +.defaultSkin span.mce_cell_props {background-position:-600px -20px} +.defaultSkin span.mce_delete_table {background-position:-620px -20px} +.defaultSkin span.mce_delete_col {background-position:-640px -20px} +.defaultSkin span.mce_delete_row {background-position:-660px -20px} +.defaultSkin span.mce_col_after {background-position:-680px -20px} +.defaultSkin span.mce_col_before {background-position:-700px -20px} +.defaultSkin span.mce_row_after {background-position:-720px -20px} +.defaultSkin span.mce_row_before {background-position:-740px -20px} +.defaultSkin span.mce_merge_cells {background-position:-760px -20px} +.defaultSkin span.mce_table_props {background-position:-980px -20px} +.defaultSkin span.mce_row_props {background-position:-780px -20px} +.defaultSkin span.mce_split_cells {background-position:-800px -20px} +.defaultSkin span.mce_template {background-position:-820px -20px} +.defaultSkin span.mce_visualchars {background-position:-840px -20px} +.defaultSkin span.mce_abbr {background-position:-860px -20px} +.defaultSkin span.mce_acronym {background-position:-880px -20px} +.defaultSkin span.mce_attribs {background-position:-900px -20px} +.defaultSkin span.mce_cite {background-position:-920px -20px} +.defaultSkin span.mce_del {background-position:-940px -20px} +.defaultSkin span.mce_ins {background-position:-960px -20px} +.defaultSkin span.mce_pagebreak {background-position:0 -40px} +.defaultSkin .mce_spellchecker span.mceAction {background-position:-540px -20px} diff --git a/web/js/tiny_mce/themes/advanced/skins/o2k7/content.css b/web/js/tiny_mce/themes/advanced/skins/o2k7/content.css new file mode 100644 index 0000000..d08cd8b --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/skins/o2k7/content.css @@ -0,0 +1,27 @@ +body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;} +body {background:#FFF;} +body.mceForceColors {background:#FFF; color:#000;} +h1 {font-size: 2em} +h2 {font-size: 1.5em} +h3 {font-size: 1.17em} +h4 {font-size: 1em} +h5 {font-size: .83em} +h6 {font-size: .75em} +.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;} +a.mceItemAnchor {width:12px; line-height:6px; overflow:hidden; padding-left:12px; background:url(../default/img/items.gif) no-repeat bottom left;} +img.mceItemAnchor {width:12px; height:12px; background:url(../default/img/items.gif) no-repeat;} +img {border:0;} +table {cursor:default} +table td, table th {cursor:text} + +/* IE */ +* html body { +scrollbar-3dlight-color:#F0F0EE; +scrollbar-arrow-color:#676662; +scrollbar-base-color:#F0F0EE; +scrollbar-darkshadow-color:#DDD; +scrollbar-face-color:#E0E0DD; +scrollbar-highlight-color:#F0F0EE; +scrollbar-shadow-color:#F0F0EE; +scrollbar-track-color:#F5F5F5; +} diff --git a/web/js/tiny_mce/themes/advanced/skins/o2k7/dialog.css b/web/js/tiny_mce/themes/advanced/skins/o2k7/dialog.css new file mode 100644 index 0000000..e36042e --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/skins/o2k7/dialog.css @@ -0,0 +1,113 @@ +/* Generic */ +body { +font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; +scrollbar-3dlight-color:#F0F0EE; +scrollbar-arrow-color:#676662; +scrollbar-base-color:#F0F0EE; +scrollbar-darkshadow-color:#DDDDDD; +scrollbar-face-color:#E0E0DD; +scrollbar-highlight-color:#F0F0EE; +scrollbar-shadow-color:#F0F0EE; +scrollbar-track-color:#F5F5F5; +background:#F0F0EE; +padding:0; +margin:8px 8px 0 8px; +} + +html {background:#F0F0EE;} +td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +textarea {resize:none;outline:none;} +a:link, a:visited {color:black;} +a:hover {color:#2B6FB6;} + +/* Forms */ +fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;} +legend {color:#2B6FB6; font-weight:bold;} +label.msg {display:none;} +label.invalid {color:#EE0000; display:inline;} +input.invalid {border:1px solid #EE0000;} +input {background:#FFF; border:1px solid #CCC;} +input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +input, select, textarea {border:1px solid #808080;} +input.radio {border:1px none #000000; background:transparent; vertical-align:middle;} +input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;} +.input_noborder {border:0;} + +/* Buttons */ +#insert, #cancel, input.button, .updateButton { +border:0; margin:0; padding:0; +font-weight:bold; +width:94px; height:26px; +background:url(../default/img/buttons.png) 0 -26px; +cursor:pointer; +padding-bottom:2px; +} + +#insert {background:url(../default/img/buttons.png) 0 -52px;} +#cancel {background:url(../default/img/buttons.png) 0 0;} + +/* Browse */ +a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;} +.mceOldBoxModel a.browse span {width:22px; height:20px;} +a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;} +a.browse span.disabled {border:1px solid white; -moz-opacity:0.3; opacity:0.3; filter:progid:DXImageTransform.Microsoft.Alpha(opacity=30);} +a.browse:hover span.disabled {border:1px solid white; background-color:transparent;} +a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;} +.mceOldBoxModel a.pickcolor span {width:21px; height:17px;} +a.pickcolor:hover span {background-color:#B2BBD0;} +a.pickcolor:hover span.disabled {} + +/* Charmap */ +table.charmap {border:1px solid #AAA; text-align:center} +td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;} +#charmap a {display:block; color:#000; text-decoration:none; border:0} +#charmap a:hover {background:#CCC;color:#2B6FB6} +#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center} +#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center} + +/* Source */ +.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;} +.mceActionPanel {margin-top:5px;} + +/* Tabs classes */ +.tabs {width:100%; height:18px; line-height:normal; background:url(../default/img/tabs.gif) repeat-x 0 -72px;} +.tabs ul {margin:0; padding:0; list-style:none;} +.tabs li {float:left; background:url(../default/img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;} +.tabs li.current {background:url(../default/img/tabs.gif) no-repeat 0 -18px; margin-right:2px;} +.tabs span {float:left; display:block; background:url(../default/img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;} +.tabs .current span {background:url(../default/img/tabs.gif) no-repeat right -54px;} +.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;} +.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;} + +/* Panels */ +.panel_wrapper div.panel {display:none;} +.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;} +.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;} + +/* Columns */ +.column {float:left;} +.properties {width:100%;} +.properties .column1 {} +.properties .column2 {text-align:left;} + +/* Titles */ +h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;} +h3 {font-size:14px;} +.title {font-size:12px; font-weight:bold; color:#2B6FB6;} + +/* Dialog specific */ +#link .panel_wrapper, #link div.current {height:125px;} +#image .panel_wrapper, #image div.current {height:200px;} +#plugintable thead {font-weight:bold; background:#DDD;} +#plugintable, #about #plugintable td {border:1px solid #919B9C;} +#plugintable {width:96%; margin-top:10px;} +#pluginscontainer {height:290px; overflow:auto;} +#colorpicker #preview {float:right; width:50px; height:14px;line-height:1px; border:1px solid black; margin-left:5px;} +#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;} +#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;} +#colorpicker #light div {overflow:hidden;} +#colorpicker #previewblock {float:right; padding-left:10px; height:20px;} +#colorpicker .panel_wrapper div.current {height:175px;} +#colorpicker #namedcolors {width:150px;} +#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;} +#colorpicker #colornamecontainer {margin-top:5px;} diff --git a/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png b/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png new file mode 100644 index 0000000..12cfb41 Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png differ diff --git a/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png b/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png new file mode 100644 index 0000000..8996c74 Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png differ diff --git a/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png b/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png new file mode 100644 index 0000000..bd5d255 Binary files /dev/null and b/web/js/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png differ diff --git a/web/js/tiny_mce/themes/advanced/skins/o2k7/ui.css b/web/js/tiny_mce/themes/advanced/skins/o2k7/ui.css new file mode 100644 index 0000000..0da56e9 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/skins/o2k7/ui.css @@ -0,0 +1,215 @@ +/* Reset */ +.o2k7Skin table, .o2k7Skin tbody, .o2k7Skin a, .o2k7Skin img, .o2k7Skin tr, .o2k7Skin div, .o2k7Skin td, .o2k7Skin iframe, .o2k7Skin span, .o2k7Skin *, .o2k7Skin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left} +.o2k7Skin a:hover, .o2k7Skin a:link, .o2k7Skin a:visited, .o2k7Skin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000} +.o2k7Skin table td {vertical-align:middle} + +/* Containers */ +.o2k7Skin table {background:#E5EFFD} +.o2k7Skin iframe {display:block; background:#FFF} +.o2k7Skin .mceToolbar {height:26px} + +/* External */ +.o2k7Skin .mceExternalToolbar {position:absolute; border:1px solid #ABC6DD; border-bottom:0; display:none} +.o2k7Skin .mceExternalToolbar td.mceToolbar {padding-right:13px;} +.o2k7Skin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0} + +/* Layout */ +.o2k7Skin table.mceLayout {border:0; border-left:1px solid #ABC6DD; border-right:1px solid #ABC6DD} +.o2k7Skin table.mceLayout tr.mceFirst td {border-top:1px solid #ABC6DD} +.o2k7Skin table.mceLayout tr.mceLast td {border-bottom:1px solid #ABC6DD} +.o2k7Skin table.mceToolbar, .o2k7Skin tr.mceFirst .mceToolbar tr td, .o2k7Skin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0} +.o2k7Skin .mceIframeContainer {border-top:1px solid #ABC6DD; border-bottom:1px solid #ABC6DD} +.o2k7Skin .mceStatusbar {display:block; font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; height:20px} +.o2k7Skin .mceStatusbar div {float:left; padding:2px} +.o2k7Skin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize} +.o2k7Skin .mceStatusbar a:hover {text-decoration:underline} +.o2k7Skin table.mceToolbar {margin-left:3px} +.o2k7Skin .mceToolbar .mceToolbarStart span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px; margin-left:3px;} +.o2k7Skin .mceToolbar td.mceFirst span {margin:0} +.o2k7Skin .mceToolbar .mceToolbarEnd span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px} +.o2k7Skin .mceToolbar .mceToolbarEndListBox span, .o2k7Skin .mceToolbar .mceToolbarStartListBox span {display:none} +.o2k7Skin span.mceIcon, .o2k7Skin img.mceIcon {display:block; width:20px; height:20px} +.o2k7Skin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} +.o2k7Skin td.mceCenter {text-align:center;} +.o2k7Skin td.mceCenter table {margin:0 auto; text-align:left;} +.o2k7Skin td.mceRight table {margin:0 0 0 auto;} + +/* Button */ +.o2k7Skin .mceButton {display:block; background:url(img/button_bg.png); width:22px; height:22px} +.o2k7Skin a.mceButton span, .o2k7Skin a.mceButton img {margin-left:1px} +.o2k7Skin .mceOldBoxModel a.mceButton span, .o2k7Skin .mceOldBoxModel a.mceButton img {margin:0 0 0 1px} +.o2k7Skin a.mceButtonEnabled:hover {background-color:#B2BBD0; background-position:0 -22px} +.o2k7Skin a.mceButtonActive, .o2k7Skin a.mceButtonSelected {background-position:0 -44px} +.o2k7Skin .mceButtonDisabled .mceIcon {opacity:0.3; filter:alpha(opacity=30)} +.o2k7Skin .mceButtonLabeled {width:auto} +.o2k7Skin .mceButtonLabeled span.mceIcon {float:left} +.o2k7Skin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica} +.o2k7Skin .mceButtonDisabled .mceButtonLabel {color:#888} + +/* Separator */ +.o2k7Skin .mceSeparator {display:block; background:url(img/button_bg.png) -22px 0; width:5px; height:22px} + +/* ListBox */ +.o2k7Skin .mceListBox {margin-left:3px} +.o2k7Skin .mceListBox, .o2k7Skin .mceListBox a {display:block} +.o2k7Skin .mceListBox .mceText {padding-left:4px; text-align:left; width:70px; border:1px solid #b3c7e1; border-right:0; background:#eaf2fb; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden} +.o2k7Skin .mceListBox .mceOpen {width:14px; height:22px; background:url(img/button_bg.png) -66px 0} +.o2k7Skin table.mceListBoxEnabled:hover .mceText, .o2k7Skin .mceListBoxHover .mceText, .o2k7Skin .mceListBoxSelected .mceText {background:#FFF} +.o2k7Skin table.mceListBoxEnabled:hover .mceOpen, .o2k7Skin .mceListBoxHover .mceOpen, .o2k7Skin .mceListBoxSelected .mceOpen {background-position:-66px -22px} +.o2k7Skin .mceListBoxDisabled .mceText {color:gray} +.o2k7Skin .mceListBoxMenu {overflow:auto; overflow-x:hidden} +.o2k7Skin .mceOldBoxModel .mceListBox .mceText {height:22px} +.o2k7Skin select.mceListBox {font-family:Tahoma,Verdana,Arial,Helvetica; font-size:12px; border:1px solid #b3c7e1; background:#FFF;} + +/* SplitButton */ +.o2k7Skin .mceSplitButton, .o2k7Skin .mceSplitButton a, .o2k7Skin .mceSplitButton span {display:block; height:22px} +.o2k7Skin .mceSplitButton {background:url(img/button_bg.png)} +.o2k7Skin .mceSplitButton a.mceAction {width:22px} +.o2k7Skin .mceSplitButton span.mceAction {width:22px; background:url(../../img/icons.gif) 20px 20px} +.o2k7Skin .mceSplitButton a.mceOpen {width:10px} +.o2k7Skin .mceSplitButton span.mceOpen {width:10px; background:url(img/button_bg.png) -44px 0} +.o2k7Skin table.mceSplitButtonEnabled:hover a.mceAction, .o2k7Skin .mceSplitButtonHover a.mceAction, .o2k7Skin .mceSplitButtonSelected {background:url(img/button_bg.png) 0 -22px} +.o2k7Skin table.mceSplitButtonEnabled:hover span.mceOpen, .o2k7Skin .mceSplitButtonHover span.mceOpen, .o2k7Skin .mceSplitButtonSelected span.mceOpen {background-position:-44px -44px} +.o2k7Skin .mceSplitButtonDisabled .mceAction {opacity:0.3; filter:alpha(opacity=30)} +.o2k7Skin .mceSplitButtonActive {background-position:0 -44px} + +/* ColorSplitButton */ +.o2k7Skin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray} +.o2k7Skin .mceColorSplitMenu td {padding:2px} +.o2k7Skin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080} +.o2k7Skin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px} +.o2k7Skin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF} +.o2k7Skin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2} +.o2k7Skin a.mceMoreColors:hover {border:1px solid #0A246A} +.o2k7Skin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a;overflow:hidden} +.o2k7Skin .mce_forecolor span.mceAction, .o2k7Skin .mce_backcolor span.mceAction {height:15px;overflow:hidden} + +/* Menu */ +.o2k7Skin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #ABC6DD} +.o2k7Skin .mceNoIcons span.mceIcon {width:0;} +.o2k7Skin .mceNoIcons a .mceText {padding-left:10px} +.o2k7Skin .mceMenu table {background:#FFF} +.o2k7Skin .mceMenu a, .o2k7Skin .mceMenu span, .o2k7Skin .mceMenu {display:block} +.o2k7Skin .mceMenu td {height:20px} +.o2k7Skin .mceMenu a {position:relative;padding:3px 0 4px 0} +.o2k7Skin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block} +.o2k7Skin .mceMenu span.mceText, .o2k7Skin .mceMenu .mcePreview {font-size:11px} +.o2k7Skin .mceMenu pre.mceText {font-family:Monospace} +.o2k7Skin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;} +.o2k7Skin .mceMenu .mceMenuItemEnabled a:hover, .o2k7Skin .mceMenu .mceMenuItemActive {background-color:#dbecf3} +.o2k7Skin td.mceMenuItemSeparator {background:#DDD; height:1px} +.o2k7Skin .mceMenuItemTitle a {border:0; background:#E5EFFD; border-bottom:1px solid #ABC6DD} +.o2k7Skin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px} +.o2k7Skin .mceMenuItemDisabled .mceText {color:#888} +.o2k7Skin .mceMenuItemSelected .mceIcon {background:url(../default/img/menu_check.gif)} +.o2k7Skin .mceNoIcons .mceMenuItemSelected a {background:url(../default/img/menu_arrow.gif) no-repeat -6px center} +.o2k7Skin .mceMenu span.mceMenuLine {display:none} +.o2k7Skin .mceMenuItemSub a {background:url(../default/img/menu_arrow.gif) no-repeat top right;} + +/* Progress,Resize */ +.o2k7Skin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; filter:alpha(opacity=50); background:#FFF} +.o2k7Skin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(../default/img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px} +.o2k7Skin .mcePlaceHolder {border:1px dotted gray} + +/* Formats */ +.o2k7Skin .mce_formatPreview a {font-size:10px} +.o2k7Skin .mce_p span.mceText {} +.o2k7Skin .mce_address span.mceText {font-style:italic} +.o2k7Skin .mce_pre span.mceText {font-family:monospace} +.o2k7Skin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em} +.o2k7Skin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em} +.o2k7Skin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em} +.o2k7Skin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em} +.o2k7Skin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em} +.o2k7Skin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em} + +/* Theme */ +.o2k7Skin span.mce_bold {background-position:0 0} +.o2k7Skin span.mce_italic {background-position:-60px 0} +.o2k7Skin span.mce_underline {background-position:-140px 0} +.o2k7Skin span.mce_strikethrough {background-position:-120px 0} +.o2k7Skin span.mce_undo {background-position:-160px 0} +.o2k7Skin span.mce_redo {background-position:-100px 0} +.o2k7Skin span.mce_cleanup {background-position:-40px 0} +.o2k7Skin span.mce_bullist {background-position:-20px 0} +.o2k7Skin span.mce_numlist {background-position:-80px 0} +.o2k7Skin span.mce_justifyleft {background-position:-460px 0} +.o2k7Skin span.mce_justifyright {background-position:-480px 0} +.o2k7Skin span.mce_justifycenter {background-position:-420px 0} +.o2k7Skin span.mce_justifyfull {background-position:-440px 0} +.o2k7Skin span.mce_anchor {background-position:-200px 0} +.o2k7Skin span.mce_indent {background-position:-400px 0} +.o2k7Skin span.mce_outdent {background-position:-540px 0} +.o2k7Skin span.mce_link {background-position:-500px 0} +.o2k7Skin span.mce_unlink {background-position:-640px 0} +.o2k7Skin span.mce_sub {background-position:-600px 0} +.o2k7Skin span.mce_sup {background-position:-620px 0} +.o2k7Skin span.mce_removeformat {background-position:-580px 0} +.o2k7Skin span.mce_newdocument {background-position:-520px 0} +.o2k7Skin span.mce_image {background-position:-380px 0} +.o2k7Skin span.mce_help {background-position:-340px 0} +.o2k7Skin span.mce_code {background-position:-260px 0} +.o2k7Skin span.mce_hr {background-position:-360px 0} +.o2k7Skin span.mce_visualaid {background-position:-660px 0} +.o2k7Skin span.mce_charmap {background-position:-240px 0} +.o2k7Skin span.mce_paste {background-position:-560px 0} +.o2k7Skin span.mce_copy {background-position:-700px 0} +.o2k7Skin span.mce_cut {background-position:-680px 0} +.o2k7Skin span.mce_blockquote {background-position:-220px 0} +.o2k7Skin .mce_forecolor span.mceAction {background-position:-720px 0} +.o2k7Skin .mce_backcolor span.mceAction {background-position:-760px 0} +.o2k7Skin span.mce_forecolorpicker {background-position:-720px 0} +.o2k7Skin span.mce_backcolorpicker {background-position:-760px 0} + +/* Plugins */ +.o2k7Skin span.mce_advhr {background-position:-0px -20px} +.o2k7Skin span.mce_ltr {background-position:-20px -20px} +.o2k7Skin span.mce_rtl {background-position:-40px -20px} +.o2k7Skin span.mce_emotions {background-position:-60px -20px} +.o2k7Skin span.mce_fullpage {background-position:-80px -20px} +.o2k7Skin span.mce_fullscreen {background-position:-100px -20px} +.o2k7Skin span.mce_iespell {background-position:-120px -20px} +.o2k7Skin span.mce_insertdate {background-position:-140px -20px} +.o2k7Skin span.mce_inserttime {background-position:-160px -20px} +.o2k7Skin span.mce_absolute {background-position:-180px -20px} +.o2k7Skin span.mce_backward {background-position:-200px -20px} +.o2k7Skin span.mce_forward {background-position:-220px -20px} +.o2k7Skin span.mce_insert_layer {background-position:-240px -20px} +.o2k7Skin span.mce_insertlayer {background-position:-260px -20px} +.o2k7Skin span.mce_movebackward {background-position:-280px -20px} +.o2k7Skin span.mce_moveforward {background-position:-300px -20px} +.o2k7Skin span.mce_media {background-position:-320px -20px} +.o2k7Skin span.mce_nonbreaking {background-position:-340px -20px} +.o2k7Skin span.mce_pastetext {background-position:-360px -20px} +.o2k7Skin span.mce_pasteword {background-position:-380px -20px} +.o2k7Skin span.mce_selectall {background-position:-400px -20px} +.o2k7Skin span.mce_preview {background-position:-420px -20px} +.o2k7Skin span.mce_print {background-position:-440px -20px} +.o2k7Skin span.mce_cancel {background-position:-460px -20px} +.o2k7Skin span.mce_save {background-position:-480px -20px} +.o2k7Skin span.mce_replace {background-position:-500px -20px} +.o2k7Skin span.mce_search {background-position:-520px -20px} +.o2k7Skin span.mce_styleprops {background-position:-560px -20px} +.o2k7Skin span.mce_table {background-position:-580px -20px} +.o2k7Skin span.mce_cell_props {background-position:-600px -20px} +.o2k7Skin span.mce_delete_table {background-position:-620px -20px} +.o2k7Skin span.mce_delete_col {background-position:-640px -20px} +.o2k7Skin span.mce_delete_row {background-position:-660px -20px} +.o2k7Skin span.mce_col_after {background-position:-680px -20px} +.o2k7Skin span.mce_col_before {background-position:-700px -20px} +.o2k7Skin span.mce_row_after {background-position:-720px -20px} +.o2k7Skin span.mce_row_before {background-position:-740px -20px} +.o2k7Skin span.mce_merge_cells {background-position:-760px -20px} +.o2k7Skin span.mce_table_props {background-position:-980px -20px} +.o2k7Skin span.mce_row_props {background-position:-780px -20px} +.o2k7Skin span.mce_split_cells {background-position:-800px -20px} +.o2k7Skin span.mce_template {background-position:-820px -20px} +.o2k7Skin span.mce_visualchars {background-position:-840px -20px} +.o2k7Skin span.mce_abbr {background-position:-860px -20px} +.o2k7Skin span.mce_acronym {background-position:-880px -20px} +.o2k7Skin span.mce_attribs {background-position:-900px -20px} +.o2k7Skin span.mce_cite {background-position:-920px -20px} +.o2k7Skin span.mce_del {background-position:-940px -20px} +.o2k7Skin span.mce_ins {background-position:-960px -20px} +.o2k7Skin span.mce_pagebreak {background-position:0 -40px} +.o2k7Skin .mce_spellchecker span.mceAction {background-position:-540px -20px} diff --git a/web/js/tiny_mce/themes/advanced/skins/o2k7/ui_black.css b/web/js/tiny_mce/themes/advanced/skins/o2k7/ui_black.css new file mode 100644 index 0000000..a42a727 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/skins/o2k7/ui_black.css @@ -0,0 +1,8 @@ +/* Black */ +.o2k7SkinBlack .mceToolbar .mceToolbarStart span, .o2k7SkinBlack .mceToolbar .mceToolbarEnd span, .o2k7SkinBlack .mceButton, .o2k7SkinBlack .mceSplitButton, .o2k7SkinBlack .mceSeparator, .o2k7SkinBlack .mceSplitButton span.mceOpen, .o2k7SkinBlack .mceListBox .mceOpen {background-image:url(img/button_bg_black.png)} +.o2k7SkinBlack table, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack .mceMenuItemTitle span.mceText, .o2k7SkinBlack .mceStatusbar div, .o2k7SkinBlack .mceStatusbar span, .o2k7SkinBlack .mceStatusbar a {background:#535353; color:#FFF} +.o2k7SkinBlack table.mceListBoxEnabled .mceText, o2k7SkinBlack .mceListBox .mceText {background:#FFF; border:1px solid #CBCFD4; border-bottom-color:#989FA9; border-right:0} +.o2k7SkinBlack table.mceListBoxEnabled:hover .mceText, .o2k7Skin .mceListBoxHover .mceText, .o2k7Skin .mceListBoxSelected .mceText {background:#FFF; border:1px solid #FFBD69; border-right:0} +.o2k7SkinBlack .mceExternalToolbar, .o2k7SkinBlack .mceListBox .mceText, .o2k7SkinBlack div.mceMenu, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceFirst td, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceLast td, .o2k7SkinBlack .mceIframeContainer {border-color: #535353;} +.o2k7SkinBlack table.mceSplitButtonEnabled:hover a.mceAction, .o2k7Skin .mceSplitButtonHover a.mceAction, .o2k7Skin .mceSplitButtonSelected {background-image:url(img/button_bg_black.png)} +.o2k7SkinBlack .mceMenu .mceMenuItemEnabled a:hover, .o2k7Skin .mceMenu .mceMenuItemActive {background-color:#FFE7A1} \ No newline at end of file diff --git a/web/js/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css b/web/js/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css new file mode 100644 index 0000000..548b1b8 --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css @@ -0,0 +1,5 @@ +/* Silver */ +.o2k7SkinSilver .mceToolbar .mceToolbarStart span, .o2k7SkinSilver .mceButton, .o2k7SkinSilver .mceSplitButton, .o2k7SkinSilver .mceSeparator, .o2k7SkinSilver .mceSplitButton span.mceOpen, .o2k7SkinSilver .mceListBox .mceOpen {background-image:url(img/button_bg_silver.png)} +.o2k7SkinSilver table, .o2k7SkinSilver .mceMenuItemTitle a {background:#eee} +.o2k7SkinSilver .mceListBox .mceText {background:#FFF} +.o2k7SkinSilver .mceExternalToolbar, .o2k7SkinSilver .mceListBox .mceText, .o2k7SkinSilver div.mceMenu, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceFirst td, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceLast td, .o2k7SkinSilver .mceIframeContainer {border-color: #bbb} diff --git a/web/js/tiny_mce/themes/advanced/source_editor.htm b/web/js/tiny_mce/themes/advanced/source_editor.htm new file mode 100644 index 0000000..60f482d --- /dev/null +++ b/web/js/tiny_mce/themes/advanced/source_editor.htm @@ -0,0 +1,32 @@ + + + + {#advanced_dlg.code_title} + + + + + +
    +
    {#advanced_dlg.code_title}
    + +
    + +
    + +
    + + + +
    +
    + +
    + +
    + +
    +
    +
    + + diff --git a/web/js/tiny_mce/themes/simple/editor_template.js b/web/js/tiny_mce/themes/simple/editor_template.js new file mode 100644 index 0000000..3a25c04 --- /dev/null +++ b/web/js/tiny_mce/themes/simple/editor_template.js @@ -0,0 +1 @@ +(function(){var DOM=tinymce.DOM;tinymce.ThemeManager.requireLangPack('simple');tinymce.create('tinymce.themes.SimpleTheme',{init:function(ed,url){var t=this,states=['Bold','Italic','Underline','Strikethrough','InsertUnorderedList','InsertOrderedList'],s=ed.settings;t.editor=ed;ed.onInit.add(function(){ed.onNodeChange.add(function(ed,cm){tinymce.each(states,function(c){cm.get(c.toLowerCase()).setActive(ed.queryCommandState(c));});});ed.dom.loadCSS(url+"/skins/"+s.skin+"/content.css");});DOM.loadCSS((s.editor_css?ed.baseURI.toAbsolute(s.editor_css):'')||url+"/skins/"+s.skin+"/ui.css");},renderUI:function(o){var t=this,n=o.targetNode,ic,tb,ed=t.editor,cf=ed.controlManager,sc;n=DOM.insertAfter(DOM.create('span',{id:ed.id+'_container','class':'mceEditor '+ed.settings.skin+'SimpleSkin'}),n);n=sc=DOM.add(n,'table',{cellPadding:0,cellSpacing:0,'class':'mceLayout'});n=tb=DOM.add(n,'tbody');n=DOM.add(tb,'tr');n=ic=DOM.add(DOM.add(n,'td'),'div',{'class':'mceIframeContainer'});n=DOM.add(DOM.add(tb,'tr',{'class':'last'}),'td',{'class':'mceToolbar mceLast',align:'center'});tb=t.toolbar=cf.createToolbar("tools1");tb.add(cf.createButton('bold',{title:'simple.bold_desc',cmd:'Bold'}));tb.add(cf.createButton('italic',{title:'simple.italic_desc',cmd:'Italic'}));tb.add(cf.createButton('underline',{title:'simple.underline_desc',cmd:'Underline'}));tb.add(cf.createButton('strikethrough',{title:'simple.striketrough_desc',cmd:'Strikethrough'}));tb.add(cf.createSeparator());tb.add(cf.createButton('undo',{title:'simple.undo_desc',cmd:'Undo'}));tb.add(cf.createButton('redo',{title:'simple.redo_desc',cmd:'Redo'}));tb.add(cf.createSeparator());tb.add(cf.createButton('cleanup',{title:'simple.cleanup_desc',cmd:'mceCleanup'}));tb.add(cf.createSeparator());tb.add(cf.createButton('insertunorderedlist',{title:'simple.bullist_desc',cmd:'InsertUnorderedList'}));tb.add(cf.createButton('insertorderedlist',{title:'simple.numlist_desc',cmd:'InsertOrderedList'}));tb.renderTo(n);return{iframeContainer:ic,editorContainer:ed.id+'_container',sizeContainer:sc,deltaHeight:-20};},getInfo:function(){return{longname:'Simple theme',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.ThemeManager.add('simple',tinymce.themes.SimpleTheme);})(); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/simple/editor_template_src.js b/web/js/tiny_mce/themes/simple/editor_template_src.js new file mode 100644 index 0000000..adc4492 --- /dev/null +++ b/web/js/tiny_mce/themes/simple/editor_template_src.js @@ -0,0 +1,85 @@ +/** + * $Id: editor_template_src.js 752 2008-03-27 21:51:25Z spocke $ + * + * This file is meant to showcase how to create a simple theme. The advanced + * theme is more suitable for production use. + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +(function() { + var DOM = tinymce.DOM; + + // Tell it to load theme specific language pack(s) + tinymce.ThemeManager.requireLangPack('simple'); + + tinymce.create('tinymce.themes.SimpleTheme', { + init : function(ed, url) { + var t = this, states = ['Bold', 'Italic', 'Underline', 'Strikethrough', 'InsertUnorderedList', 'InsertOrderedList'], s = ed.settings; + + t.editor = ed; + + ed.onInit.add(function() { + ed.onNodeChange.add(function(ed, cm) { + tinymce.each(states, function(c) { + cm.get(c.toLowerCase()).setActive(ed.queryCommandState(c)); + }); + }); + + ed.dom.loadCSS(url + "/skins/" + s.skin + "/content.css"); + }); + + DOM.loadCSS((s.editor_css ? ed.baseURI.toAbsolute(s.editor_css) : '') || url + "/skins/" + s.skin + "/ui.css"); + }, + + renderUI : function(o) { + var t = this, n = o.targetNode, ic, tb, ed = t.editor, cf = ed.controlManager, sc; + + n = DOM.insertAfter(DOM.create('span', {id : ed.id + '_container', 'class' : 'mceEditor ' + ed.settings.skin + 'SimpleSkin'}), n); + n = sc = DOM.add(n, 'table', {cellPadding : 0, cellSpacing : 0, 'class' : 'mceLayout'}); + n = tb = DOM.add(n, 'tbody'); + + // Create iframe container + n = DOM.add(tb, 'tr'); + n = ic = DOM.add(DOM.add(n, 'td'), 'div', {'class' : 'mceIframeContainer'}); + + // Create toolbar container + n = DOM.add(DOM.add(tb, 'tr', {'class' : 'last'}), 'td', {'class' : 'mceToolbar mceLast', align : 'center'}); + + // Create toolbar + tb = t.toolbar = cf.createToolbar("tools1"); + tb.add(cf.createButton('bold', {title : 'simple.bold_desc', cmd : 'Bold'})); + tb.add(cf.createButton('italic', {title : 'simple.italic_desc', cmd : 'Italic'})); + tb.add(cf.createButton('underline', {title : 'simple.underline_desc', cmd : 'Underline'})); + tb.add(cf.createButton('strikethrough', {title : 'simple.striketrough_desc', cmd : 'Strikethrough'})); + tb.add(cf.createSeparator()); + tb.add(cf.createButton('undo', {title : 'simple.undo_desc', cmd : 'Undo'})); + tb.add(cf.createButton('redo', {title : 'simple.redo_desc', cmd : 'Redo'})); + tb.add(cf.createSeparator()); + tb.add(cf.createButton('cleanup', {title : 'simple.cleanup_desc', cmd : 'mceCleanup'})); + tb.add(cf.createSeparator()); + tb.add(cf.createButton('insertunorderedlist', {title : 'simple.bullist_desc', cmd : 'InsertUnorderedList'})); + tb.add(cf.createButton('insertorderedlist', {title : 'simple.numlist_desc', cmd : 'InsertOrderedList'})); + tb.renderTo(n); + + return { + iframeContainer : ic, + editorContainer : ed.id + '_container', + sizeContainer : sc, + deltaHeight : -20 + }; + }, + + getInfo : function() { + return { + longname : 'Simple theme', + author : 'Moxiecode Systems AB', + authorurl : 'http://tinymce.moxiecode.com', + version : tinymce.majorVersion + "." + tinymce.minorVersion + } + } + }); + + tinymce.ThemeManager.add('simple', tinymce.themes.SimpleTheme); +})(); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/simple/img/icons.gif b/web/js/tiny_mce/themes/simple/img/icons.gif new file mode 100644 index 0000000..16af141 Binary files /dev/null and b/web/js/tiny_mce/themes/simple/img/icons.gif differ diff --git a/web/js/tiny_mce/themes/simple/langs/en.js b/web/js/tiny_mce/themes/simple/langs/en.js new file mode 100644 index 0000000..9f08f10 --- /dev/null +++ b/web/js/tiny_mce/themes/simple/langs/en.js @@ -0,0 +1,11 @@ +tinyMCE.addI18n('en.simple',{ +bold_desc:"Bold (Ctrl+B)", +italic_desc:"Italic (Ctrl+I)", +underline_desc:"Underline (Ctrl+U)", +striketrough_desc:"Strikethrough", +bullist_desc:"Unordered list", +numlist_desc:"Ordered list", +undo_desc:"Undo (Ctrl+Z)", +redo_desc:"Redo (Ctrl+Y)", +cleanup_desc:"Cleanup messy code" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/simple/langs/nb.js b/web/js/tiny_mce/themes/simple/langs/nb.js new file mode 100644 index 0000000..9038c37 --- /dev/null +++ b/web/js/tiny_mce/themes/simple/langs/nb.js @@ -0,0 +1,11 @@ +tinyMCE.addI18n('nb.simple',{ +bold_desc:"Fet", +italic_desc:"Kursiv", +underline_desc:"Understreking", +striketrough_desc:"Gjennomstreking", +bullist_desc:"Punktliste", +numlist_desc:"Nummerliste", +undo_desc:"Angre (Ctrl+Z)", +redo_desc:"Gj\u00F8r om (Ctrl + Y)", +cleanup_desc:"Rens ukurant kode" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/simple/langs/nn.js b/web/js/tiny_mce/themes/simple/langs/nn.js new file mode 100644 index 0000000..63fc36f --- /dev/null +++ b/web/js/tiny_mce/themes/simple/langs/nn.js @@ -0,0 +1,11 @@ +tinyMCE.addI18n('nn.simple',{ +bold_desc:"Feit", +italic_desc:"Kursiv", +underline_desc:"Understreking", +striketrough_desc:"Gjennomstreking", +bullist_desc:"Punktliste", +numlist_desc:"Nummerliste", +undo_desc:"Angre", +redo_desc:"Gjer om", +cleanup_desc:"Rens grisete kode" +}); \ No newline at end of file diff --git a/web/js/tiny_mce/themes/simple/skins/default/content.css b/web/js/tiny_mce/themes/simple/skins/default/content.css new file mode 100644 index 0000000..2506c80 --- /dev/null +++ b/web/js/tiny_mce/themes/simple/skins/default/content.css @@ -0,0 +1,25 @@ +body, td, pre { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10px; +} + +body { + background-color: #FFFFFF; +} + +.mceVisualAid { + border: 1px dashed #BBBBBB; +} + +/* MSIE specific */ + +* html body { + scrollbar-3dlight-color: #F0F0EE; + scrollbar-arrow-color: #676662; + scrollbar-base-color: #F0F0EE; + scrollbar-darkshadow-color: #DDDDDD; + scrollbar-face-color: #E0E0DD; + scrollbar-highlight-color: #F0F0EE; + scrollbar-shadow-color: #F0F0EE; + scrollbar-track-color: #F5F5F5; +} diff --git a/web/js/tiny_mce/themes/simple/skins/default/ui.css b/web/js/tiny_mce/themes/simple/skins/default/ui.css new file mode 100644 index 0000000..1cf64b8 --- /dev/null +++ b/web/js/tiny_mce/themes/simple/skins/default/ui.css @@ -0,0 +1,32 @@ +/* Reset */ +.defaultSimpleSkin table, .defaultSimpleSkin tbody, .defaultSimpleSkin a, .defaultSimpleSkin img, .defaultSimpleSkin tr, .defaultSimpleSkin div, .defaultSimpleSkin td, .defaultSimpleSkin iframe, .defaultSimpleSkin span, .defaultSimpleSkin * {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000} + +/* Containers */ +.defaultSimpleSkin {position:relative} +.defaultSimpleSkin table.mceLayout {background:#F0F0EE; border:1px solid #CCC;} +.defaultSimpleSkin iframe {display:block; background:#FFF; border-bottom:1px solid #CCC;} +.defaultSimpleSkin .mceToolbar {height:24px;} + +/* Layout */ +.defaultSimpleSkin span.mceIcon, .defaultSimpleSkin img.mceIcon {display:block; width:20px; height:20px} +.defaultSimpleSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} + +/* Button */ +.defaultSimpleSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px} +.defaultSimpleSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0} +.defaultSimpleSkin a.mceButtonActive {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSimpleSkin .mceButtonDisabled span {opacity:0.3; filter:alpha(opacity=30)} + +/* Separator */ +.defaultSimpleSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:0 2px 0 4px} + +/* Theme */ +.defaultSimpleSkin span.mce_bold {background-position:0 0} +.defaultSimpleSkin span.mce_italic {background-position:-60px 0} +.defaultSimpleSkin span.mce_underline {background-position:-140px 0} +.defaultSimpleSkin span.mce_strikethrough {background-position:-120px 0} +.defaultSimpleSkin span.mce_undo {background-position:-160px 0} +.defaultSimpleSkin span.mce_redo {background-position:-100px 0} +.defaultSimpleSkin span.mce_cleanup {background-position:-40px 0} +.defaultSimpleSkin span.mce_insertunorderedlist {background-position:-20px 0} +.defaultSimpleSkin span.mce_insertorderedlist {background-position:-80px 0} diff --git a/web/js/tiny_mce/themes/simple/skins/o2k7/content.css b/web/js/tiny_mce/themes/simple/skins/o2k7/content.css new file mode 100644 index 0000000..595809f --- /dev/null +++ b/web/js/tiny_mce/themes/simple/skins/o2k7/content.css @@ -0,0 +1,17 @@ +body, td, pre {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} + +body {background: #FFF;} +.mceVisualAid {border: 1px dashed #BBB;} + +/* IE */ + +* html body { +scrollbar-3dlight-color: #F0F0EE; +scrollbar-arrow-color: #676662; +scrollbar-base-color: #F0F0EE; +scrollbar-darkshadow-color: #DDDDDD; +scrollbar-face-color: #E0E0DD; +scrollbar-highlight-color: #F0F0EE; +scrollbar-shadow-color: #F0F0EE; +scrollbar-track-color: #F5F5F5; +} diff --git a/web/js/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png b/web/js/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png new file mode 100644 index 0000000..527e349 Binary files /dev/null and b/web/js/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png differ diff --git a/web/js/tiny_mce/themes/simple/skins/o2k7/ui.css b/web/js/tiny_mce/themes/simple/skins/o2k7/ui.css new file mode 100644 index 0000000..bfae96e --- /dev/null +++ b/web/js/tiny_mce/themes/simple/skins/o2k7/ui.css @@ -0,0 +1,35 @@ +/* Reset */ +.o2k7SimpleSkin table, .o2k7SimpleSkin tbody, .o2k7SimpleSkin a, .o2k7SimpleSkin img, .o2k7SimpleSkin tr, .o2k7SimpleSkin div, .o2k7SimpleSkin td, .o2k7SimpleSkin iframe, .o2k7SimpleSkin span, .o2k7SimpleSkin * {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000} + +/* Containers */ +.o2k7SimpleSkin {position:relative} +.o2k7SimpleSkin table.mceLayout {background:#E5EFFD; border:1px solid #ABC6DD;} +.o2k7SimpleSkin iframe {display:block; background:#FFF; border-bottom:1px solid #ABC6DD;} +.o2k7SimpleSkin .mceToolbar {height:26px;} + +/* Layout */ +.o2k7SimpleSkin .mceToolbar .mceToolbarStart span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px; } +.o2k7SimpleSkin .mceToolbar .mceToolbarEnd span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px} +.o2k7SimpleSkin span.mceIcon, .o2k7SimpleSkin img.mceIcon {display:block; width:20px; height:20px} +.o2k7SimpleSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} + +/* Button */ +.o2k7SimpleSkin .mceButton {display:block; background:url(img/button_bg.png); width:22px; height:22px} +.o2k7SimpleSkin a.mceButton span, .o2k7SimpleSkin a.mceButton img {margin:1px 0 0 1px} +.o2k7SimpleSkin a.mceButtonEnabled:hover {background-color:#B2BBD0; background-position:0 -22px} +.o2k7SimpleSkin a.mceButtonActive {background-position:0 -44px} +.o2k7SimpleSkin .mceButtonDisabled span {opacity:0.3; filter:alpha(opacity=30)} + +/* Separator */ +.o2k7SimpleSkin .mceSeparator {display:block; background:url(img/button_bg.png) -22px 0; width:5px; height:22px} + +/* Theme */ +.o2k7SimpleSkin span.mce_bold {background-position:0 0} +.o2k7SimpleSkin span.mce_italic {background-position:-60px 0} +.o2k7SimpleSkin span.mce_underline {background-position:-140px 0} +.o2k7SimpleSkin span.mce_strikethrough {background-position:-120px 0} +.o2k7SimpleSkin span.mce_undo {background-position:-160px 0} +.o2k7SimpleSkin span.mce_redo {background-position:-100px 0} +.o2k7SimpleSkin span.mce_cleanup {background-position:-40px 0} +.o2k7SimpleSkin span.mce_insertunorderedlist {background-position:-20px 0} +.o2k7SimpleSkin span.mce_insertorderedlist {background-position:-80px 0} diff --git a/web/js/tiny_mce/tiny_mce.js b/web/js/tiny_mce/tiny_mce.js new file mode 100644 index 0000000..ebf8c32 --- /dev/null +++ b/web/js/tiny_mce/tiny_mce.js @@ -0,0 +1 @@ +var tinymce={majorVersion:'3',minorVersion:'0.7',releaseDate:'2008-04-14',_init:function(){var t=this,d=document,w=window,na=navigator,ua=na.userAgent,i,nl,n,base;t.isOpera=w.opera&&opera.buildNumber;t.isWebKit=/WebKit/.test(ua);t.isOldWebKit=t.isWebKit&&!w.getSelection().getRangeAt;t.isIE=!t.isWebKit&&!t.isOpera&&(/MSIE/gi).test(ua)&&(/Explorer/gi).test(na.appName);t.isIE6=t.isIE&&/MSIE [56]/.test(ua);t.isGecko=!t.isWebKit&&/Gecko/.test(ua);t.isMac=ua.indexOf('Mac')!=-1;if(w.tinyMCEPreInit){t.suffix=tinyMCEPreInit.suffix;t.baseURL=tinyMCEPreInit.base;return;}t.suffix='';nl=d.getElementsByTagName('base');for(i=0;i=items.length){for(i=0;i=items.length||base[i]!=items[i]){bp=i+1;break;}}}if(base.length=base.length||base[i]!=items[i]){bp=i+1;break;}}}if(bp==1)return path;for(i=0;i=0;i--){if(path[i].length==0||path[i]==".")continue;if(path[i]=='..'){nb++;continue;}if(nb>0){nb--;continue;}o.push(path[i]);}i=base.length-nb;if(i<=0)return'/'+o.reverse().join('/');return'/'+base.slice(0,i).join('/')+'/'+o.reverse().join('/');},getURI:function(nh){var s,t=this;if(!t.source||nh){s='';if(!nh){if(t.protocol)s+=t.protocol+'://';if(t.userInfo)s+=t.userInfo+'@';if(t.host)s+=t.host;if(t.port)s+=':'+t.port;}if(t.path)s+=t.path;if(t.query)s+='?'+t.query;if(t.anchor)s+='#'+t.anchor;t.source=s;}return t.source;}});})();(function(){var each=tinymce.each;tinymce.create('static tinymce.util.Cookie',{getHash:function(n){var v=this.get(n),h;if(v){each(v.split('&'),function(v){v=v.split('=');h=h||{};h[unescape(v[0])]=unescape(v[1]);});}return h;},setHash:function(n,v,e,p,d,s){var o='';each(v,function(v,k){o+=(!o?'':'&')+escape(k)+'='+escape(v);});this.set(n,o,e,p,d,s);},get:function(n){var c=document.cookie,e,p=n+"=",b;if(!c)return;b=c.indexOf("; "+p);if(b==-1){b=c.indexOf(p);if(b!=0)return null;}else b+=2;e=c.indexOf(";",b);if(e==-1)e=c.length;return unescape(c.substring(b+p.length,e));},set:function(n,v,e,p,d,s){document.cookie=n+"="+escape(v)+((e)?"; expires="+e.toGMTString():"")+((p)?"; path="+escape(p):"")+((d)?"; domain="+d:"")+((s)?"; secure":"");},remove:function(n,p){var d=new Date();d.setTime(d.getTime()-1000);this.set(n,'',d,p,d);}});})();tinymce.create('static tinymce.util.JSON',{serialize:function(o){var i,v,s=tinymce.util.JSON.serialize,t;if(o==null)return'null';t=typeof o;if(t=='string'){v='\bb\tt\nn\ff\rr\""\'\'\\\\';return'"'+o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'])/g,function(a,b){i=v.indexOf(b);if(i+1)return'\\'+v.charAt(i+1);a=b.charCodeAt().toString(16);return'\\u'+'0000'.substring(a.length)+a;})+'"';}if(t=='object'){if(o instanceof Array){for(i=0,v='[';i0?',':'')+s(o[i]);return v+']';}v='{';for(i in o)v+=typeof o[i]!='function'?(v.length>1?',"':'"')+i+'":'+s(o[i]):'';return v+'}';}return''+o;},parse:function(s){try{return eval('('+s+')');}catch(ex){}}});tinymce.create('static tinymce.util.XHR',{send:function(o){var x,t,w=window,c=0;o.scope=o.scope||this;o.success_scope=o.success_scope||o.scope;o.error_scope=o.error_scope||o.scope;o.async=o.async===false?false:true;o.data=o.data||'';function get(s){x=0;try{x=new ActiveXObject(s);}catch(ex){}return x;};x=w.XMLHttpRequest?new XMLHttpRequest():get('Microsoft.XMLHTTP')||get('Msxml2.XMLHTTP');if(x){if(x.overrideMimeType)x.overrideMimeType(o.content_type);x.open(o.type||(o.data?'POST':'GET'),o.url,o.async);if(o.content_type)x.setRequestHeader('Content-Type',o.content_type);x.send(o.data);t=w.setInterval(function(){if(x.readyState==4||c++>10000){w.clearInterval(t);if(o.success&&c<10000&&x.status==200)o.success.call(o.success_scope,''+x.responseText,x,o);else if(o.error)o.error.call(o.error_scope,c>10000?'TIMED_OUT':'GENERAL',x,o);x=null;}},10);}}});(function(){var extend=tinymce.extend,JSON=tinymce.util.JSON,XHR=tinymce.util.XHR;tinymce.create('tinymce.util.JSONRequest',{JSONRequest:function(s){this.settings=extend({},s);this.count=0;},send:function(o){var ecb=o.error,scb=o.success;o=extend(this.settings,o);o.success=function(c,x){c=JSON.parse(c);if(typeof(c)=='undefined'){c={error:'JSON Parse error.'};}if(c.error)ecb.call(o.error_scope||o.scope,c.error,x);else scb.call(o.success_scope||o.scope,c.result);};o.error=function(ty,x){ecb.call(o.error_scope||o.scope,ty,x);};o.data=JSON.serialize({id:o.id||'c'+(this.count++),method:o.method,params:o.params});o.content_type='application/json';XHR.send(o);},'static':{sendRPC:function(o){return new tinymce.util.JSONRequest().send(o);}}});}());(function(){var each=tinymce.each,is=tinymce.is;var isWebKit=tinymce.isWebKit,isIE=tinymce.isIE;tinymce.create('tinymce.dom.DOMUtils',{doc:null,root:null,files:null,listeners:{},pixelStyles:/^(top|left|bottom|right|width|height|borderWidth)$/,cache:{},idPattern:/^#[\w]+$/,elmPattern:/^[\w_*]+$/,elmClassPattern:/^([\w_]*)\.([\w_]+)$/,DOMUtils:function(d,s){var t=this;t.doc=d;t.win=window;t.files={};t.cssFlicker=false;t.counter=0;t.boxModel=!tinymce.isIE||d.compatMode=="CSS1Compat";t.stdMode=d.documentMode===8;this.settings=s=tinymce.extend({keep_values:false,hex_colors:1,process_html:1},s);if(tinymce.isIE6){try{d.execCommand('BackgroundImageCache',false,true);}catch(e){t.cssFlicker=true;}}tinymce.addUnload(t.destroy,t);},getRoot:function(){var t=this,s=t.settings;return(s&&t.get(s.root_element))||t.doc.body;},getViewPort:function(w){var d,b;w=!w?this.win:w;d=w.document;b=this.boxModel?d.documentElement:d.body;return{x:w.pageXOffset||b.scrollLeft,y:w.pageYOffset||b.scrollTop,w:w.innerWidth||b.clientWidth,h:w.innerHeight||b.clientHeight};},getRect:function(e){var p,t=this,w,h;e=t.get(e);p=t.getPos(e);w=t.getStyle(e,'width');h=t.getStyle(e,'height');if(w.indexOf('px')===-1)w=0;if(h.indexOf('px')===-1)h=0;return{x:p.x,y:p.y,w:parseInt(w)||e.offsetWidth||e.clientWidth,h:parseInt(h)||e.offsetHeight||e.clientHeight};},getParent:function(n,f,r){var na,se=this.settings;n=this.get(n);if(se.strict_root)r=r||this.getRoot();if(is(f,'string')){na=f.toUpperCase();f=function(n){var s=false;if(n.nodeType==1&&na==='*'){s=true;return false;}each(na.split(','),function(v){if(n.nodeType==1&&((se.strict&&n.nodeName.toUpperCase()==v)||n.nodeName==v)){s=true;return false;}});return s;};}while(n){if(n==r)return null;if(f(n))return n;n=n.parentNode;}return null;},get:function(e){var n;if(this.doc&&typeof(e)=='string'){n=e;e=this.doc.getElementById(e);if(e&&e.id!==n)return this.doc.getElementsByName(n)[1];}return e;},select:function(pa,s){var t=this,cs,c,pl,o=[],x,i,l,n;s=t.get(s)||t.doc;if(s.querySelectorAll){if(s!=t.doc){i=s.id;s.id='_mc_tmp';pa='#_mc_tmp '+pa;}l=tinymce.grep(s.querySelectorAll(pa));s.id=i;return l;}if(t.settings.strict){function get(s,n){return s.getElementsByTagName(n.toLowerCase());};}else{function get(s,n){return s.getElementsByTagName(n);};}if(t.elmPattern.test(pa)){x=get(s,pa);for(i=0,l=x.length;i=0;i--)cs+='}, '+(i?'n':'s')+');';cs+='})';t.cache[pa]=cs=eval(cs);}cs(isIE?collectIE:collect,s);});each(o,function(n){if(isIE)n.removeAttribute('mce_save');else delete n.mce_save;});return o;},add:function(p,n,a,h,c){var t=this;return this.run(p,function(p){var e,k;e=is(n,'string')?t.doc.createElement(n):n;if(a){for(k in a){if(a.hasOwnProperty(k)&&!is(a[k],'object'))t.setAttrib(e,k,''+a[k]);}if(a.style&&!is(a.style,'string')){each(a.style,function(v,n){t.setStyle(e,n,v);});}}if(h){if(h.nodeType)e.appendChild(h);else t.setHTML(e,h);}return!c?p.appendChild(e):e;});},create:function(n,a,h){return this.add(this.doc.createElement(n),n,a,h,1);},createHTML:function(n,a,h){var o='',t=this,k;o+='<'+n;for(k in a){if(a.hasOwnProperty(k))o+=' '+k+'="'+t.encode(a[k])+'"';}if(tinymce.is(h))return o+'>'+h+'';return o+' />';},remove:function(n,k){return this.run(n,function(n){var p,g;p=n.parentNode;if(!p)return null;if(k){each(n.childNodes,function(c){p.insertBefore(c.cloneNode(true),n);});}return p.removeChild(n);});},setStyle:function(n,na,v){var t=this;return t.run(n,function(e){var s,i;s=e.style;na=na.replace(/-(\D)/g,function(a,b){return b.toUpperCase();});if(t.pixelStyles.test(na)&&(tinymce.is(v,'number')||/^[\-0-9\.]+$/.test(v)))v+='px';switch(na){case'opacity':if(isIE){s.filter=v===''?'':"alpha(opacity="+(v*100)+")";if(!n.currentStyle||!n.currentStyle.hasLayout)s.display='inline-block';}s[na]=s['-moz-opacity']=s['-khtml-opacity']=v||'';break;case'float':isIE?s.styleFloat=v:s.cssFloat=v;break;default:s[na]=v||'';}if(t.settings.update_styles)t.setAttrib(e,'mce_style');});},getStyle:function(n,na,c){n=this.get(n);if(!n)return false;if(this.doc.defaultView&&c){na=na.replace(/[A-Z]/g,function(a){return'-'+a;});try{return this.doc.defaultView.getComputedStyle(n,null).getPropertyValue(na);}catch(ex){return null;}}na=na.replace(/-(\D)/g,function(a,b){return b.toUpperCase();});if(na=='float')na=isIE?'styleFloat':'cssFloat';if(n.currentStyle&&c)return n.currentStyle[na];return n.style[na];},setStyles:function(e,o){var t=this,s=t.settings,ol;ol=s.update_styles;s.update_styles=0;each(o,function(v,n){t.setStyle(e,n,v);});s.update_styles=ol;if(s.update_styles)t.setAttrib(e,s.cssText);},setAttrib:function(e,n,v){var t=this;if(t.settings.strict)n=n.toLowerCase();return this.run(e,function(e){var s=t.settings;switch(n){case"style":if(s.keep_values&&/^(| )(top|left|bottom|right|width|height)/i.test(v)){if(v)e.setAttribute('mce_style',v,2);else e.removeAttribute('mce_style',2);}e.style.cssText=v;break;case"class":e.className=v||'';break;case"src":case"href":if(s.keep_values){if(s.url_converter)v=s.url_converter.call(s.url_converter_scope||t,v,n,e);t.setAttrib(e,'mce_'+n,v,2);}break;}if(is(v)&&v!==null&&v.length!==0)e.setAttribute(n,''+v,2);else e.removeAttribute(n,2);});},setAttribs:function(e,o){var t=this;return this.run(e,function(e){each(o,function(v,n){t.setAttrib(e,n,v);});});},getAttrib:function(e,n,dv){var v,t=this;e=t.get(e);if(!e||e.nodeType!==1)return false;if(!is(dv))dv="";if(/^(src|href|style|coords)$/.test(n)){v=e.getAttribute("mce_"+n);if(v)return v;}v=e.getAttribute(n,2);if(!v){switch(n){case'class':v=e.className;break;default:if(isIE&&n==='name'&&e.nodeName==='A'){v=e.name;break;}v=e.attributes[n];v=v&&is(v.nodeValue)?v.nodeValue:v;}}switch(n){case'style':v=v||e.style.cssText;if(v){v=t.serializeStyle(t.parseStyle(v));if(t.settings.keep_values&&/^(| )(top|left|bottom|right|width|height)/i.test(v))e.setAttribute('mce_style',v);}break;}if(isWebKit&&n==="class"&&v)v=v.replace(/(apple|webkit)\-[a-z\-]+/gi,'');if(isIE){switch(n){case'rowspan':case'colspan':if(v===1)v='';break;case'size':if(v==='+0')v='';break;case'hspace':if(v===-1)v='';break;case'tabindex':if(v===32768)v='';break;case'shape':v=v.toLowerCase();break;default:if(n.indexOf('on')===0&&v)v=(''+v).replace(/^function\s+anonymous\(\)\s+\{\s+(.*)\s+\}$/,'$1');}}return(v&&v!='')?''+v:dv;},getPos:function(n){var t=this,x=0,y=0,e,d=t.doc,r;n=t.get(n);if(n&&isIE){n=n.getBoundingClientRect();e=t.boxModel?d.documentElement:d.body;x=t.getStyle(t.select('html')[0],'borderWidth');x=(x=='medium'||t.boxModel&&!t.isIE6)&&2||x;n.top+=t.win.self!=t.win.top?2:0;return{x:n.left+e.scrollLeft-x,y:n.top+e.scrollTop-x};}r=n;while(r){x+=r.offsetLeft||0;y+=r.offsetTop||0;r=r.offsetParent;}r=n;while(r){if(!/^table-row|inline.*/i.test(t.getStyle(r,"display",1))){x-=r.scrollLeft||0;y-=r.scrollTop||0;}r=r.parentNode;if(r==d.body)break;}return{x:x,y:y};},parseStyle:function(st){var t=this,s=t.settings,o={};if(!st)return o;function compress(p,s,ot){var t,r,b,l;t=o[p+'-top'+s];if(!t)return;r=o[p+'-right'+s];if(t!=r)return;b=o[p+'-bottom'+s];if(r!=b)return;l=o[p+'-left'+s];if(b!=l)return;o[ot]=l;delete o[p+'-top'+s];delete o[p+'-right'+s];delete o[p+'-bottom'+s];delete o[p+'-left'+s];};function compress2(ta,a,b,c){var t;t=o[a];if(!t)return;t=o[b];if(!t)return;t=o[c];if(!t)return;o[ta]=o[a]+' '+o[b]+' '+o[c];delete o[a];delete o[b];delete o[c];};each(st.split(';'),function(v){var sv,ur=[];if(v){v=v.replace(/url\([^\)]+\)/g,function(v){ur.push(v);return'url('+ur.length+')';});v=v.split(':');sv=tinymce.trim(v[1]);sv=sv.replace(/url\(([^\)]+)\)/g,function(a,b){return ur[parseInt(b)-1];});sv=sv.replace(/rgb\([^\)]+\)/g,function(v){return t.toHex(v);});if(s.url_converter){sv=sv.replace(/url\([\'\"]?([^\)\'\"]+)[\'\"]?\)/g,function(x,c){return'url('+t.encode(s.url_converter.call(s.url_converter_scope||t,t.decode(c),'style',null))+')';});}o[tinymce.trim(v[0]).toLowerCase()]=sv;}});compress("border","","border");compress("border","-width","border-width");compress("border","-color","border-color");compress("border","-style","border-style");compress("padding","","padding");compress("margin","","margin");compress2('border','border-width','border-style','border-color');if(isIE){if(o.border=='medium none')o.border='';}return o;},serializeStyle:function(o){var s='';each(o,function(v,k){if(k&&v){switch(k){case'color':case'background-color':v=v.toLowerCase();break;}s+=(s?' ':'')+k+': '+v+';';}});return s;},loadCSS:function(u){var t=this,d=t.doc;if(!u)u='';each(u.split(','),function(u){if(t.files[u])return;t.files[u]=true;t.add(t.select('head')[0],'link',{rel:'stylesheet',href:tinymce._addVer(u)});});},addClass:function(e,c){return this.run(e,function(e){var o;if(!c)return 0;if(this.hasClass(e,c))return e.className;o=this.removeClass(e,c);return e.className=(o!=''?(o+' '):'')+c;});},removeClass:function(e,c){var t=this,re;return t.run(e,function(e){var v;if(t.hasClass(e,c)){if(!re)re=new RegExp("(^|\\s+)"+c+"(\\s+|$)","g");v=e.className.replace(re,' ');return e.className=tinymce.trim(v!=' '?v:'');}return e.className;});},hasClass:function(n,c){n=this.get(n);if(!n||!c)return false;return(' '+n.className+' ').indexOf(' '+c+' ')!==-1;},show:function(e){return this.setStyle(e,'display','block');},hide:function(e){return this.setStyle(e,'display','none');},isHidden:function(e){e=this.get(e);return e.style.display=='none'||this.getStyle(e,'display')=='none';},uniqueId:function(p){return(!p?'mce_':p)+(this.counter++);},setHTML:function(e,h){var t=this;return this.run(e,function(e){var x,i,nl,n,p,x;h=t.processHTML(h);if(isIE){function set(){try{e.innerHTML='
    '+h;e.removeChild(e.firstChild);}catch(ex){while(e.firstChild)e.firstChild.removeNode();x=t.create('div');x.innerHTML='
    '+h;each(x.childNodes,function(n,i){if(i)e.appendChild(n);});}};if(t.settings.fix_ie_paragraphs)h=h.replace(/

    <\/p>|]+)><\/p>|/gi,' 

    ');set();if(t.settings.fix_ie_paragraphs){nl=e.getElementsByTagName("p");for(i=nl.length-1,x=0;i>=0;i--){n=nl[i];if(!n.hasChildNodes()){if(!n.mce_keep){x=1;break;}n.removeAttribute('mce_keep');}}}if(x){h=h.replace(/]+)>|

    /g,'');h=h.replace(/<\/p>/g,'');set();if(t.settings.fix_ie_paragraphs){nl=e.getElementsByTagName("DIV");for(i=nl.length-1;i>=0;i--){n=nl[i];if(n.mce_tmp){p=t.doc.createElement('p');n.cloneNode(false).outerHTML.replace(/([a-z0-9\-_]+)=/gi,function(a,b){var v;if(b!=='mce_tmp'){v=n.getAttribute(b);if(!v&&b==='class')v=n.className;p.setAttribute(b,v);}});for(x=0;x|]+)>/gi,'<$1b$2>');h=h.replace(/<(\/?)em>|]+)>/gi,'<$1i$2>');}else if(isIE)h=h.replace(/'/g,''');h=h.replace(/]+)\/>|/gi,'');if(s.keep_values){if(h.indexOf('/g,'';bi=s.body_id||'tinymce';if(bi.indexOf('=')!=-1){bi=t.getParam('body_id','','hash');bi=bi[t.id]||bi;}bc=s.body_class||'';if(bc.indexOf('=')!=-1){bc=t.getParam('body_class','','hash');bc=bc[t.id]||'';}t.iframeHTML+='';if(tinymce.relaxedDomain){if(isIE)u='javascript:(function(){document.open();document.domain="'+document.domain+'";var ed = window.parent.tinyMCE.get("'+t.id+'");document.write(ed.iframeHTML);document.close();ed.setupIframe();})()';else if(tinymce.isOpera)u='javascript:(function(){document.open();document.domain="'+document.domain+'";document.close();ed.setupIframe();})()';}n=DOM.add(o.iframeContainer,'iframe',{id:t.id+"_ifr",src:u||'javascript:""',frameBorder:'0',style:{width:'100%',height:h}});t.contentAreaContainer=o.iframeContainer;DOM.get(o.editorContainer).style.display=t.orgDisplay;DOM.get(t.id).style.display='none';if(tinymce.isOldWebKit){Event.add(n,'load',t.setupIframe,t);n.src=tinymce.baseURL+'/plugins/safari/blank.htm';}else{if(!isIE||!tinymce.relaxedDomain)t.setupIframe();e=n=o=null;}},setupIframe:function(){var t=this,s=t.settings,e=DOM.get(t.id),d=t.getDoc(),h,b;if(!isIE||!tinymce.relaxedDomain){d.open();d.write(t.iframeHTML);d.close();}if(!isIE){try{d.designMode='On';}catch(ex){}}if(isIE){b=t.getBody();DOM.hide(b);b.contentEditable=true;DOM.show(b);}t.dom=new tinymce.DOM.DOMUtils(t.getDoc(),{keep_values:true,url_converter:t.convertURL,url_converter_scope:t,hex_colors:s.force_hex_style_colors,class_filter:s.class_filter,update_styles:1,fix_ie_paragraphs:1});t.serializer=new tinymce.dom.Serializer({entity_encoding:s.entity_encoding,entities:s.entities,valid_elements:s.verify_html===false?'*[*]':s.valid_elements,extended_valid_elements:s.extended_valid_elements,valid_child_elements:s.valid_child_elements,invalid_elements:s.invalid_elements,fix_table_elements:s.fix_table_elements,fix_list_elements:s.fix_list_elements,fix_content_duplication:s.fix_content_duplication,convert_fonts_to_spans:s.convert_fonts_to_spans,font_size_classes:s.font_size_classes,font_size_style_values:s.font_size_style_values,apply_source_formatting:s.apply_source_formatting,remove_linebreaks:s.remove_linebreaks,dom:t.dom});t.selection=new tinymce.dom.Selection(t.dom,t.getWin(),t.serializer);t.forceBlocks=new tinymce.ForceBlocks(t,{forced_root_block:s.forced_root_block});t.editorCommands=new tinymce.EditorCommands(t);t.serializer.onPreProcess.add(function(se,o){return t.onPreProcess.dispatch(t,o,se);});t.serializer.onPostProcess.add(function(se,o){return t.onPostProcess.dispatch(t,o,se);});t.onPreInit.dispatch(t);if(!s.gecko_spellcheck)t.getBody().spellcheck=0;t._addEvents();t.controlManager.onPostRender.dispatch(t,t.controlManager);t.onPostRender.dispatch(t);if(s.directionality)t.getBody().dir=s.directionality;if(s.nowrap)t.getBody().style.whiteSpace="nowrap";if(s.auto_resize)t.onNodeChange.add(t.resizeToContent,t);if(s.custom_elements){function handleCustom(ed,o){each(explode(s.custom_elements),function(v){var n;if(v.indexOf('~')===0){v=v.substring(1);n='span';}else n='div';o.content=o.content.replace(new RegExp('<('+v+')([^>]*)>','g'),'<'+n+' mce_name="$1"$2>');o.content=o.content.replace(new RegExp('','g'),'');});};t.onBeforeSetContent.add(handleCustom);t.onPostProcess.add(function(ed,o){if(o.set)handleCustom(ed,o)});}if(s.handle_node_change_callback){t.onNodeChange.add(function(ed,cm,n){t.execCallback('handle_node_change_callback',t.id,n,-1,-1,true,t.selection.isCollapsed());});}if(s.save_callback){t.onSaveContent.add(function(ed,o){var h=t.execCallback('save_callback',t.id,o.content,t.getBody());if(h)o.content=h;});}if(s.onchange_callback){t.onChange.add(function(ed,l){t.execCallback('onchange_callback',t,l);});}if(s.convert_newlines_to_brs){t.onBeforeSetContent.add(function(ed,o){if(o.initial)o.content=o.content.replace(/\r?\n/g,'
    ');});}if(s.fix_nesting&&isIE){t.onBeforeSetContent.add(function(ed,o){o.content=t._fixNesting(o.content);});}if(s.preformatted){t.onPostProcess.add(function(ed,o){o.content=o.content.replace(/^\s*/,'');o.content=o.content.replace(/<\/pre>\s*$/,'');if(o.set)o.content='

    '+o.content+'
    ';});}if(s.verify_css_classes){t.serializer.attribValueFilter=function(n,v){var s,cl;if(n=='class'){if(!t.classesRE){cl=t.dom.getClasses();if(cl.length>0){s='';each(cl,function(o){s+=(s?'|':'')+o['class'];});t.classesRE=new RegExp('('+s+')','gi');}}return!t.classesRE||/(\bmceItem\w+\b|\bmceTemp\w+\b)/g.test(v)||t.classesRE.test(v)?v:'';}return v;};}if(s.convert_fonts_to_spans)t._convertFonts();if(s.inline_styles)t._convertInlineElements();if(s.cleanup_callback){t.onBeforeSetContent.add(function(ed,o){o.content=t.execCallback('cleanup_callback','insert_to_editor',o.content,o);});t.onPreProcess.add(function(ed,o){if(o.set)t.execCallback('cleanup_callback','insert_to_editor_dom',o.node,o);if(o.get)t.execCallback('cleanup_callback','get_from_editor_dom',o.node,o);});t.onPostProcess.add(function(ed,o){if(o.set)o.content=t.execCallback('cleanup_callback','insert_to_editor',o.content,o);if(o.get)o.content=t.execCallback('cleanup_callback','get_from_editor',o.content,o);});}if(s.save_callback){t.onGetContent.add(function(ed,o){if(o.save)o.content=t.execCallback('save_callback',t.id,o.content,t.getBody());});}if(s.handle_event_callback){t.onEvent.add(function(ed,e,o){if(t.execCallback('handle_event_callback',e,ed,o)===false)Event.cancel(e);});}t.onSetContent.add(function(){t.addVisual(t.getBody());});if(s.padd_empty_editor){t.onPostProcess.add(function(ed,o){o.content=o.content.replace(/^

    ( |#160;|\s|\u00a0)<\/p>$/,'');});}if(isGecko){try{d.designMode='Off';d.designMode='On';}catch(ex){}}setTimeout(function(){if(t.removed)return;t.load({initial:true,format:(s.cleanup_on_startup?'html':'raw')});t.startContent=t.getContent({format:'raw'});t.undoManager.add({initial:true});t.initialized=true;t.onInit.dispatch(t);t.execCallback('setupcontent_callback',t.id,t.getBody(),t.getDoc());t.execCallback('init_instance_callback',t);t.focus(true);t.nodeChanged({initial:1});if(s.content_css){tinymce.each(explode(s.content_css),function(u){t.dom.loadCSS(t.documentBaseURI.toAbsolute(u));});}if(s.auto_focus){setTimeout(function(){var ed=EditorManager.get(s.auto_focus);ed.selection.select(ed.getBody(),1);ed.selection.collapse(1);ed.getWin().focus();},100);}},1);e=null;},focus:function(sf){var oed,t=this;if(!sf){t.getWin().focus();}if(EditorManager.activeEditor!=t){if((oed=EditorManager.activeEditor)!=null)oed.onDeactivate.dispatch(oed,t);t.onActivate.dispatch(t,oed);}EditorManager._setActive(t);},execCallback:function(n){var t=this,f=t.settings[n],s;if(!f)return;if(t.callbackLookup&&(s=t.callbackLookup[n])){f=s.func;s=s.scope;}if(is(f,'string')){s=f.replace(/\.\w+$/,'');s=s?tinymce.resolve(s):0;f=tinymce.resolve(f);t.callbackLookup=t.callbackLookup||{};t.callbackLookup[n]={func:f,scope:s};}return f.apply(s||t,Array.prototype.slice.call(arguments,1));},translate:function(s){var c=this.settings.language,i18n=EditorManager.i18n;if(!s)return'';return i18n[c+'.'+s]||s.replace(/{\#([^}]+)\}/g,function(a,b){return i18n[c+'.'+b]||'{#'+b+'}';});},getLang:function(n,dv){return EditorManager.i18n[this.settings.language+'.'+n]||(is(dv)?dv:'{#'+n+'}');},getParam:function(n,dv,ty){var tr=tinymce.trim,v=is(this.settings[n])?this.settings[n]:dv,o;if(ty==='hash'){o={};if(is(v,'string')){each(v.indexOf('=')>0?v.split(/[;,](?![^=;,]*(?:[;,]|$))/):v.split(','),function(v){v=v.split('=');if(v.length>1)o[tr(v[0])]=tr(v[1]);else o[tr(v[0])]=tr(v);});}else o=v;return o;}return v;},nodeChanged:function(o){var t=this,s=t.selection,n=s.getNode()||t.getBody();if(t.initialized){t.onNodeChange.dispatch(t,o?o.controlManager||t.controlManager:t.controlManager,isIE&&n.ownerDocument!=t.getDoc()?t.getBody():n,s.isCollapsed(),o);}},addButton:function(n,s){var t=this;t.buttons=t.buttons||{};t.buttons[n]=s;},addCommand:function(n,f,s){this.execCommands[n]={func:f,scope:s||this};},addQueryStateHandler:function(n,f,s){this.queryStateCommands[n]={func:f,scope:s||this};},addQueryValueHandler:function(n,f,s){this.queryValueCommands[n]={func:f,scope:s||this};},addShortcut:function(pa,desc,cmd_func,sc){var t=this,c;if(!t.settings.custom_shortcuts)return false;t.shortcuts=t.shortcuts||{};if(is(cmd_func,'string')){c=cmd_func;cmd_func=function(){t.execCommand(c,false,null);};}if(is(cmd_func,'object')){c=cmd_func;cmd_func=function(){t.execCommand(c[0],c[1],c[2]);};}each(explode(pa),function(pa){var o={func:cmd_func,scope:sc||this,desc:desc,alt:false,ctrl:false,shift:false};each(explode(pa,'+'),function(v){switch(v){case'alt':case'ctrl':case'shift':o[v]=true;break;default:o.charCode=v.charCodeAt(0);o.keyCode=v.toUpperCase().charCodeAt(0);}});t.shortcuts[(o.ctrl?'ctrl':'')+','+(o.alt?'alt':'')+','+(o.shift?'shift':'')+','+o.keyCode]=o;});return true;},execCommand:function(cmd,ui,val,a){var t=this,s=0,o,st;if(!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd)&&(!a||!a.skip_focus))t.focus();o={};t.onBeforeExecCommand.dispatch(t,cmd,ui,val,o);if(o.terminate)return false;if(t.execCallback('execcommand_callback',t.id,t.selection.getNode(),cmd,ui,val)){t.onExecCommand.dispatch(t,cmd,ui,val,a);return true;}if(o=t.execCommands[cmd]){st=o.func.call(o.scope,ui,val);if(st!==true){t.onExecCommand.dispatch(t,cmd,ui,val,a);return st;}}each(t.plugins,function(p){if(p.execCommand&&p.execCommand(cmd,ui,val)){t.onExecCommand.dispatch(t,cmd,ui,val,a);s=1;return false;}});if(s)return true;if(t.theme.execCommand&&t.theme.execCommand(cmd,ui,val)){t.onExecCommand.dispatch(t,cmd,ui,val,a);return true;}if(t.editorCommands.execCommand(cmd,ui,val)){t.onExecCommand.dispatch(t,cmd,ui,val,a);return true;}t.getDoc().execCommand(cmd,ui,val);t.onExecCommand.dispatch(t,cmd,ui,val,a);},queryCommandState:function(c){var t=this,o,s;if(t._isHidden())return;if(o=t.queryStateCommands[c]){s=o.func.call(o.scope);if(s!==true)return s;}o=t.editorCommands.queryCommandState(c);if(o!==-1)return o;try{return this.getDoc().queryCommandState(c);}catch(ex){}},queryCommandValue:function(c){var t=this,o,s;if(t._isHidden())return;if(o=t.queryValueCommands[c]){s=o.func.call(o.scope);if(s!==true)return s;}o=t.editorCommands.queryCommandValue(c);if(is(o))return o;try{return this.getDoc().queryCommandValue(c);}catch(ex){}},show:function(){var t=this;DOM.show(t.getContainer());DOM.hide(t.id);t.load();},hide:function(){var t=this,d=t.getDoc();if(isIE&&d)d.execCommand('SelectAll');t.save();DOM.hide(t.getContainer());DOM.setStyle(t.id,'display',t.orgDisplay);},isHidden:function(){return!DOM.isHidden(this.id);},setProgressState:function(b,ti,o){this.onSetProgressState.dispatch(this,b,ti,o);return b;},resizeToContent:function(){var t=this;DOM.setStyle(t.id+"_ifr",'height',t.getBody().scrollHeight);},load:function(o){var t=this,e=t.getElement(),h;o=o||{};o.load=true;h=t.setContent(is(e.value)?e.value:e.innerHTML,o);o.element=e;if(!o.no_events)t.onLoadContent.dispatch(t,o);o.element=e=null;return h;},save:function(o){var t=this,e=t.getElement(),h,f;if(!t.initialized)return;o=o||{};o.save=true;o.element=e;h=o.content=t.getContent(o);if(!o.no_events)t.onSaveContent.dispatch(t,o);h=o.content;if(!/TEXTAREA|INPUT/i.test(e.nodeName)){e.innerHTML=h;if(f=DOM.getParent(t.id,'form')){each(f.elements,function(e){if(e.name==t.id){e.value=h;return false;}});}}else e.value=h;o.element=e=null;return h;},setContent:function(h,o){var t=this;o=o||{};o.format=o.format||'html';o.set=true;o.content=h;if(!o.no_events)t.onBeforeSetContent.dispatch(t,o);if(!tinymce.isIE&&(h.length===0||/^\s+$/.test(h))){o.content=t.dom.setHTML(t.getBody(),'
    ',1);o.format='raw';}o.content=t.dom.setHTML(t.getBody(),tinymce.trim(o.content));if(o.format!='raw'&&t.settings.cleanup){o.getInner=true;o.content=t.dom.setHTML(t.getBody(),t.serializer.serialize(t.getBody(),o));}if(!o.no_events)t.onSetContent.dispatch(t,o);return o.content;},getContent:function(o){var t=this,h;o=o||{};o.format=o.format||'html';o.get=true;if(!o.no_events)t.onBeforeGetContent.dispatch(t,o);if(o.format!='raw'&&t.settings.cleanup){o.getInner=true;h=t.serializer.serialize(t.getBody(),o);}else h=t.getBody().innerHTML;h=h.replace(/^\s*|\s*$/g,'');o={content:h};t.onGetContent.dispatch(t,o);return o.content;},isDirty:function(){var t=this;return tinymce.trim(t.startContent)!=tinymce.trim(t.getContent({format:'raw',no_events:1}))&&!t.isNotDirty;},getContainer:function(){var t=this;if(!t.container)t.container=DOM.get(t.editorContainer||t.id+'_parent');return t.container;},getContentAreaContainer:function(){return this.contentAreaContainer;},getElement:function(){return DOM.get(this.settings.content_element||this.id);},getWin:function(){var t=this,e;if(!t.contentWindow){e=DOM.get(t.id+"_ifr");if(e)t.contentWindow=e.contentWindow;}return t.contentWindow;},getDoc:function(){var t=this,w;if(!t.contentDocument){w=t.getWin();if(w)t.contentDocument=w.document;}return t.contentDocument;},getBody:function(){return this.bodyElement||this.getDoc().body;},convertURL:function(u,n,e){var t=this,s=t.settings;if(s.urlconverter_callback)return t.execCallback('urlconverter_callback',u,e,true,n);if(!s.convert_urls||(e&&e.nodeName=='LINK')||u.indexOf('file:')===0)return u;if(s.relative_urls)return t.documentBaseURI.toRelative(u);u=t.documentBaseURI.toAbsolute(u,s.remove_script_host);return u;},addVisual:function(e){var t=this,s=t.settings;e=e||t.getBody();if(!is(t.hasVisual))t.hasVisual=s.visual;each(t.dom.select('table,a',e),function(e){var v;switch(e.nodeName){case'TABLE':v=t.dom.getAttrib(e,'border');if(!v||v=='0'){if(t.hasVisual)t.dom.addClass(e,s.visual_table_class);else t.dom.removeClass(e,s.visual_table_class);}return;case'A':v=t.dom.getAttrib(e,'name');if(v){if(t.hasVisual)t.dom.addClass(e,'mceItemAnchor');else t.dom.removeClass(e,'mceItemAnchor');}return;}});t.onVisualAid.dispatch(t,e,t.hasVisual);},remove:function(){var t=this,e=t.getContainer();t.removed=1;t.hide();t.execCallback('remove_instance_callback',t);t.onRemove.dispatch(t);t.onExecCommand.listeners=[];EditorManager.remove(t);DOM.remove(e);},destroy:function(s){var t=this;if(t.destroyed)return;if(!s){tinymce.removeUnload(t.destroy);tinyMCE.onBeforeUnload.remove(t._beforeUnload);if(t.theme.destroy)t.theme.destroy();t.controlManager.destroy();t.selection.destroy();t.dom.destroy();if(!t.settings.content_editable){Event.clear(t.getWin());Event.clear(t.getDoc());}Event.clear(t.getBody());Event.clear(t.formElement);}if(t.formElement){t.formElement.submit=t.formElement._mceOldSubmit;t.formElement._mceOldSubmit=null;}t.contentAreaContainer=t.formElement=t.container=t.settings.content_element=t.bodyElement=t.contentDocument=t.contentWindow=null;if(t.selection)t.selection=t.selection.win=t.selection.dom=t.selection.dom.doc=null;t.destroyed=1;},_addEvents:function(){var t=this,i,s=t.settings,lo={mouseup:'onMouseUp',mousedown:'onMouseDown',click:'onClick',keyup:'onKeyUp',keydown:'onKeyDown',keypress:'onKeyPress',submit:'onSubmit',reset:'onReset',contextmenu:'onContextMenu',dblclick:'onDblClick',paste:'onPaste'};function eventHandler(e,o){var ty=e.type;if(t.removed)return;if(t.onEvent.dispatch(t,e,o)!==false){t[lo[e.fakeType||e.type]].dispatch(t,e,o);}};each(lo,function(v,k){switch(k){case'contextmenu':if(tinymce.isOpera){Event.add(t.getDoc(),'mousedown',function(e){if(e.ctrlKey){e.fakeType='contextmenu';eventHandler(e);}});}else Event.add(t.getDoc(),k,eventHandler);break;case'paste':Event.add(t.getBody(),k,function(e){var tx,h,el,r;if(e.clipboardData)tx=e.clipboardData.getData('text/plain');else if(tinymce.isIE)tx=t.getWin().clipboardData.getData('Text');eventHandler(e,{text:tx,html:h});});break;case'submit':case'reset':Event.add(t.getElement().form||DOM.getParent(t.id,'form'),k,eventHandler);break;default:Event.add(s.content_editable?t.getBody():t.getDoc(),k,eventHandler);}});Event.add(s.content_editable?t.getBody():(isGecko?t.getDoc():t.getWin()),'focus',function(e){t.focus(true);});if(tinymce.isGecko){Event.add(t.getDoc(),'DOMNodeInserted',function(e){var v;e=e.target;if(e.nodeType===1&&e.nodeName==='IMG'&&(v=e.getAttribute('mce_src')))e.src=t.documentBaseURI.toAbsolute(v);});}if(isGecko){function setOpts(){var t=this,d=t.getDoc(),s=t.settings;if(isGecko){if(t._isHidden()){try{if(!s.content_editable)d.designMode='On';}catch(ex){}}try{d.execCommand("styleWithCSS",0,false);}catch(ex){if(!t._isHidden())d.execCommand("useCSS",0,true);}if(!s.table_inline_editing)try{d.execCommand('enableInlineTableEditing',false,false);}catch(ex){}if(!s.object_resizing)try{d.execCommand('enableObjectResizing',false,false);}catch(ex){}}};t.onBeforeExecCommand.add(setOpts);t.onMouseDown.add(setOpts);}t.onMouseUp.add(t.nodeChanged);t.onClick.add(t.nodeChanged);t.onKeyUp.add(function(ed,e){if((e.keyCode>=33&&e.keyCode<=36)||(e.keyCode>=37&&e.keyCode<=40)||e.keyCode==13||e.keyCode==45||e.keyCode==46||e.keyCode==8||e.ctrlKey)t.nodeChanged();});t.onReset.add(function(){t.setContent(t.startContent,{format:'raw'});});if(t.getParam('tab_focus')){function tabCancel(ed,e){if(e.keyCode===9)return Event.cancel(e);};function tabHandler(ed,e){var x,i,f,el,v;function find(d){f=DOM.getParent(ed.id,'form');el=f.elements;if(f){each(el,function(e,i){if(e.id==ed.id){x=i;return false;}});if(d>0){for(i=x+1;i=0;i--){if(el[i].type!='hidden')return el[i];}}}return null;};if(e.keyCode===9){v=explode(ed.getParam('tab_focus'));if(v.length==1){v[1]=v[0];v[0]=':prev';}if(e.shiftKey){if(v[0]==':prev')el=find(-1);else el=DOM.get(v[0]);}else{if(v[1]==':next')el=find(1);else el=DOM.get(v[1]);}if(el){if(ed=EditorManager.get(el.id||el.name))ed.focus();else window.setTimeout(function(){window.focus();el.focus();},10);return Event.cancel(e);}}};t.onKeyUp.add(tabCancel);if(isGecko){t.onKeyPress.add(tabHandler);t.onKeyDown.add(tabCancel);}else t.onKeyDown.add(tabHandler);}if(s.custom_shortcuts){if(s.custom_undo_redo_keyboard_shortcuts){t.addShortcut('ctrl+z',t.getLang('undo_desc'),'Undo');t.addShortcut('ctrl+y',t.getLang('redo_desc'),'Redo');}if(isGecko){t.addShortcut('ctrl+b',t.getLang('bold_desc'),'Bold');t.addShortcut('ctrl+i',t.getLang('italic_desc'),'Italic');t.addShortcut('ctrl+u',t.getLang('underline_desc'),'Underline');}for(i=1;i<=6;i++)t.addShortcut('ctrl+'+i,'',['FormatBlock',false,'']);t.addShortcut('ctrl+7','',['FormatBlock',false,'

    ']);t.addShortcut('ctrl+8','',['FormatBlock',false,'

    ']);t.addShortcut('ctrl+9','',['FormatBlock',false,'
    ']);function find(e){var v=null;if(!e.altKey&&!e.ctrlKey&&!e.metaKey)return v;each(t.shortcuts,function(o){if(o.ctrl!=e.ctrlKey&&(!tinymce.isMac||o.ctrl==e.metaKey))return;if(o.alt!=e.altKey)return;if(o.shift!=e.shiftKey)return;if(e.keyCode==o.keyCode||(e.charCode&&e.charCode==o.charCode)){v=o;return false;}});return v;};t.onKeyUp.add(function(ed,e){var o=find(e);if(o)return Event.cancel(e);});t.onKeyPress.add(function(ed,e){var o=find(e);if(o)return Event.cancel(e);});t.onKeyDown.add(function(ed,e){var o=find(e);if(o){o.func.call(o.scope);return Event.cancel(e);}});}if(tinymce.isIE){Event.add(t.getDoc(),'controlselect',function(e){var re=t.resizeInfo,cb;e=e.target;if(e.nodeName!=='IMG')return;if(re)Event.remove(re.node,re.ev,re.cb);if(!t.dom.hasClass(e,'mceItemNoResize')){ev='resizeend';cb=Event.add(e,ev,function(e){var v;e=e.target;if(v=t.dom.getStyle(e,'width')){t.dom.setAttrib(e,'width',v.replace(/[^0-9%]+/g,''));t.dom.setStyle(e,'width','');}if(v=t.dom.getStyle(e,'height')){t.dom.setAttrib(e,'height',v.replace(/[^0-9%]+/g,''));t.dom.setStyle(e,'height','');}});}else{ev='resizestart';cb=Event.add(e,'resizestart',Event.cancel,Event);}re=t.resizeInfo={node:e,ev:ev,cb:cb};});t.onKeyDown.add(function(ed,e){switch(e.keyCode){case 8:if(t.selection.getRng().item){t.selection.getRng().item(0).removeNode();return Event.cancel(e);}}});}if(tinymce.isOpera){t.onClick.add(function(ed,e){Event.prevent(e);});}if(s.custom_undo_redo){function addUndo(){t.undoManager.typing=0;t.undoManager.add();};if(tinymce.isIE){Event.add(t.getWin(),'blur',function(e){var n;if(t.selection){n=t.selection.getNode();if(!t.removed&&n.ownerDocument&&n.ownerDocument!=t.getDoc())addUndo();}});}else{Event.add(t.getDoc(),'blur',function(){if(t.selection&&!t.removed)addUndo();});}t.onMouseDown.add(addUndo);t.onKeyUp.add(function(ed,e){if((e.keyCode>=33&&e.keyCode<=36)||(e.keyCode>=37&&e.keyCode<=40)||e.keyCode==13||e.keyCode==45||e.ctrlKey){t.undoManager.typing=0;t.undoManager.add();}});t.onKeyDown.add(function(ed,e){if((e.keyCode>=33&&e.keyCode<=36)||(e.keyCode>=37&&e.keyCode<=40)||e.keyCode==13||e.keyCode==45){if(t.undoManager.typing){t.undoManager.add();t.undoManager.typing=0;}return;}if(!t.undoManager.typing){t.undoManager.add();t.undoManager.typing=1;}});}},_convertInlineElements:function(){var t=this,s=t.settings,dom=t.dom,v,e,na,st,sp;function convert(ed,o){if(!s.inline_styles)return;if(o.get){each(t.dom.select('table,u,strike',o.node),function(n){switch(n.nodeName){case'TABLE':if(v=dom.getAttrib(n,'height')){dom.setStyle(n,'height',v);dom.setAttrib(n,'height','');}break;case'U':case'STRIKE':n.style.textDecoration=n.nodeName=='U'?'underline':'line-through';dom.setAttrib(n,'mce_style','');dom.setAttrib(n,'mce_name','span');break;}});}else if(o.set){each(t.dom.select('table,span',o.node).reverse(),function(n){if(n.nodeName=='TABLE'){if(v=dom.getStyle(n,'height'))dom.setAttrib(n,'height',v.replace(/[^0-9%]+/g,''));}else{if(n.style.textDecoration=='underline')na='u';else if(n.style.textDecoration=='line-through')na='strike';else na='';if(na){n.style.textDecoration='';dom.setAttrib(n,'mce_style','');e=dom.create(na,{style:dom.getAttrib(n,'style')});dom.replace(e,n,1);}}});}};t.onPreProcess.add(convert);if(!s.cleanup_on_startup){t.onSetContent.add(function(ed,o){if(o.initial)convert(t,{node:t.getBody(),set:1});});}},_convertFonts:function(){var t=this,s=t.settings,dom=t.dom,fz,fzn,sl,cl;if(!s.inline_styles)return;fz=[8,10,12,14,18,24,36];fzn=['xx-small','x-small','small','medium','large','x-large','xx-large'];if(sl=s.font_size_style_values)sl=explode(sl);if(cl=s.font_size_classes)cl=explode(cl);function convertToFonts(no){var n,f,nl,x,i,v,st;if(tinymce.isWebKit||!s.inline_styles)return;nl=t.dom.select('span',no);for(x=nl.length-1;x>=0;x--){n=nl[x];f=dom.create('font',{color:dom.toHex(dom.getStyle(n,'color')),face:dom.getStyle(n,'fontFamily'),style:dom.getAttrib(n,'style'),'class':dom.getAttrib(n,'class')});st=f.style;if(st.color||st.fontFamily){st.color=st.fontFamily='';dom.setAttrib(f,'mce_style','');}if(sl){i=inArray(sl,dom.getStyle(n,'fontSize'));if(i!=-1){dom.setAttrib(f,'size',''+(i+1||1));f.style.fontSize='';}}else if(cl){i=inArray(cl,dom.getAttrib(n,'class'));v=dom.getStyle(n,'fontSize');if(i==-1&&v.indexOf('pt')>0)i=inArray(fz,parseInt(v));if(i==-1)i=inArray(fzn,v);if(i!=-1){dom.setAttrib(f,'size',''+(i+1||1));f.style.fontSize='';}}if(f.color||f.face||f.size){f.style.fontFamily='';dom.setAttrib(f,'mce_style','');dom.replace(f,n,1);}f=n=null;}};t.onSetContent.add(function(ed,o){convertToFonts(ed.getBody());});t.onPreProcess.add(function(ed,o){var n,sp,nl,x;if(!s.inline_styles)return;if(o.get){nl=t.dom.select('font',o.node);for(x=nl.length-1;x>=0;x--){n=nl[x];sp=dom.create('span',{style:dom.getAttrib(n,'style'),'class':dom.getAttrib(n,'class')});dom.setStyles(sp,{fontFamily:dom.getAttrib(n,'face'),color:dom.getAttrib(n,'color'),backgroundColor:n.style.backgroundColor});if(n.size){if(sl)dom.setStyle(sp,'fontSize',sl[parseInt(n.size)-1]);else dom.setAttrib(sp,'class',cl[parseInt(n.size)-1]);}dom.setAttrib(sp,'mce_style','');dom.replace(sp,n,1);}}});},_isHidden:function(){var s;if(!isGecko)return 0;s=this.selection.getSel();return(!s||!s.rangeCount||s.rangeCount==0);},_fixNesting:function(s){var d=[],i;s=s.replace(/<(\/)?([^\s>]+)[^>]*?>/g,function(a,b,c){var e;if(b==='/'){if(!d.length)return'';if(c!==d[d.length-1].tag){for(i=d.length-1;i>=0;i--){if(d[i].tag===c){d[i].close=1;break;}}return'';}else{d.pop();if(d.length&&d[d.length-1].close){a=a+'';d.pop();}}}else{if(/^(br|hr|input|meta|img|link|param)$/i.test(c))return a;if(/\/>$/.test(a))return a;d.push({tag:c});}return a;});for(i=d.length-1;i>=0;i--)s+='';return s;}});})();(function(){var each=tinymce.each,isIE=tinymce.isIE,isGecko=tinymce.isGecko,isOpera=tinymce.isOpera,isWebKit=tinymce.isWebKit;tinymce.create('tinymce.EditorCommands',{EditorCommands:function(ed){this.editor=ed;},execCommand:function(cmd,ui,val){var t=this,ed=t.editor,f;switch(cmd){case'Cut':case'Copy':case'Paste':try{ed.getDoc().execCommand(cmd,ui,val);}catch(ex){if(isGecko){ed.windowManager.confirm(ed.getLang('clipboard_msg'),function(s){if(s)window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html','mceExternal');});}else ed.windowManager.alert(ed.getLang('clipboard_no_support'));}return true;case'mceResetDesignMode':case'mceBeginUndoLevel':return true;case'unlink':t.UnLink();return true;case'JustifyLeft':case'JustifyCenter':case'JustifyRight':case'JustifyFull':t.mceJustify(cmd,cmd.substring(7).toLowerCase());return true;case'mceEndUndoLevel':case'mceAddUndoLevel':ed.undoManager.add();return true;default:f=this[cmd];if(f){f.call(this,ui,val);return true;}}return false;},Indent:function(){var ed=this.editor,d=ed.dom,s=ed.selection,e,iv,iu;iv=ed.settings.indentation;iu=/[a-z%]+$/i.exec(iv);iv=parseInt(iv);if(ed.settings.inline_styles&&(!this.queryStateInsertUnorderedList()&&!this.queryStateInsertOrderedList())){each(this._getSelectedBlocks(),function(e){d.setStyle(e,'paddingLeft',(parseInt(e.style.paddingLeft||0)+iv)+iu);});return;}ed.getDoc().execCommand('Indent',false,null);if(isIE){d.getParent(s.getNode(),function(n){if(n.nodeName=='BLOCKQUOTE'){n.dir=n.style.cssText='';}});}},Outdent:function(){var ed=this.editor,d=ed.dom,s=ed.selection,e,v,iv,iu;iv=ed.settings.indentation;iu=/[a-z%]+$/i.exec(iv);iv=parseInt(iv);if(ed.settings.inline_styles&&(!this.queryStateInsertUnorderedList()&&!this.queryStateInsertOrderedList())){each(this._getSelectedBlocks(),function(e){v=Math.max(0,parseInt(e.style.paddingLeft||0)-iv);d.setStyle(e,'paddingLeft',v?v+iu:'');});return;}ed.getDoc().execCommand('Outdent',false,null);},mceSetAttribute:function(u,v){var ed=this.editor,d=ed.dom,e;if(e=d.getParent(ed.selection.getNode(),d.isBlock))d.setAttrib(e,v.name,v.value);},mceSetContent:function(u,v){this.editor.setContent(v);},mceToggleVisualAid:function(){var ed=this.editor;ed.hasVisual=!ed.hasVisual;ed.addVisual();},mceReplaceContent:function(u,v){var s=this.editor.selection;s.setContent(v.replace(/\{\$selection\}/g,s.getContent({format:'text'})));},mceInsertLink:function(u,v){var ed=this.editor,s=ed.selection,e=ed.dom.getParent(s.getNode(),'A');if(tinymce.is(v,'string'))v={href:v};function set(e){each(v,function(v,k){ed.dom.setAttrib(e,k,v);});};if(!e){ed.execCommand('CreateLink',false,'javascript:mctmp(0);');each(ed.dom.select('a'),function(e){if(e.href=='javascript:mctmp(0);')set(e);});}else{if(v.href)set(e);else ed.dom.remove(e,1);}},UnLink:function(){var ed=this.editor,s=ed.selection;if(s.isCollapsed())s.select(s.getNode());ed.getDoc().execCommand('unlink',false,null);s.collapse(0);},FontName:function(u,v){var t=this,ed=t.editor,s=ed.selection,e;if(!v){if(s.isCollapsed())s.select(s.getNode());t.RemoveFormat();}else ed.getDoc().execCommand('FontName',false,v);},queryCommandValue:function(c){var f=this['queryValue'+c];if(f)return f.call(this,c);return false;},queryCommandState:function(cmd){var f;switch(cmd){case'JustifyLeft':case'JustifyCenter':case'JustifyRight':case'JustifyFull':return this.queryStateJustify(cmd,cmd.substring(7).toLowerCase());default:if(f=this['queryState'+cmd])return f.call(this,cmd);}return-1;},_queryState:function(c){try{return this.editor.getDoc().queryCommandState(c);}catch(ex){}},_queryVal:function(c){try{return this.editor.getDoc().queryCommandValue(c);}catch(ex){}},queryValueFontSize:function(){var ed=this.editor,v=0,p;if(isOpera||isWebKit){if(p=ed.dom.getParent(ed.selection.getNode(),'FONT'))v=p.size;return v;}return this._queryVal('FontSize');},queryValueFontName:function(){var ed=this.editor,v=0,p;if(p=ed.dom.getParent(ed.selection.getNode(),'FONT'))v=p.face;if(!v)v=this._queryVal('FontName');return v;},mceJustify:function(c,v){var ed=this.editor,se=ed.selection,n=se.getNode(),nn=n.nodeName,bl,nb,dom=ed.dom,rm;if(ed.settings.inline_styles&&this.queryStateJustify(c,v))rm=1;bl=dom.getParent(n,ed.dom.isBlock);if(nn=='IMG'){if(v=='full')return;if(rm){if(v=='center')dom.setStyle(n.parentNode,'textAlign','');dom.setStyle(n,'float','');this.mceRepaint();return;}if(v=='center'){if(/^(TD|TH)$/.test(bl.nodeName))bl=0;if(!bl||bl.childNodes.length>1){nb=dom.create('p');nb.appendChild(n.cloneNode(false));if(bl)dom.insertAfter(nb,bl);else dom.insertAfter(nb,n);dom.remove(n);n=nb.firstChild;bl=nb;}dom.setStyle(bl,'textAlign',v);dom.setStyle(n,'float','');}else{dom.setStyle(n,'float',v);dom.setStyle(n.parentNode,'textAlign','');}this.mceRepaint();return;}if(ed.settings.inline_styles&&ed.settings.forced_root_block){if(rm)v='';each(this._getSelectedBlocks(dom.getParent(se.getStart(),dom.isBlock),dom.getParent(se.getEnd(),dom.isBlock)),function(e){dom.setAttrib(e,'align','');dom.setStyle(e,'textAlign',v=='full'?'justify':v);});return;}else if(!rm)ed.getDoc().execCommand(c,false,null);if(ed.settings.inline_styles){if(rm){dom.getParent(ed.selection.getNode(),function(n){if(n.style&&n.style.textAlign)dom.setStyle(n,'textAlign','');});return;}each(dom.select('*'),function(n){var v=n.align;if(v){if(v=='full')v='justify';dom.setStyle(n,'textAlign',v);dom.setAttrib(n,'align','');}});}},mceSetCSSClass:function(u,v){this.mceSetStyleInfo(0,{command:'setattrib',name:'class',value:v});},getSelectedElement:function(){var t=this,ed=t.editor,dom=ed.dom,se=ed.selection,r=se.getRng(),r1,r2,sc,ec,so,eo,e,sp,ep,re;if(se.isCollapsed()||r.item)return se.getNode();re=ed.settings.merge_styles_invalid_parents;if(tinymce.is(re,'string'))re=new RegExp(re,'i');if(isIE){r1=r.duplicate();r1.collapse(true);sc=r1.parentElement();r2=r.duplicate();r2.collapse(false);ec=r2.parentElement();if(sc!=ec){r1.move('character',1);sc=r1.parentElement();}if(sc==ec){r1=r.duplicate();r1.moveToElementText(sc);if(r1.compareEndPoints('StartToStart',r)==0&&r1.compareEndPoints('EndToEnd',r)==0)return re&&re.test(sc.nodeName)?null:sc;}}else{function getParent(n){return dom.getParent(n,function(n){return n.nodeType==1;});};sc=r.startContainer;ec=r.endContainer;so=r.startOffset;eo=r.endOffset;if(!r.collapsed){if(sc==ec){if(so-eo<2){if(sc.hasChildNodes()){sp=sc.childNodes[so];return re&&re.test(sp.nodeName)?null:sp;}}}}if(sc.nodeType!=3||ec.nodeType!=3)return null;if(so==0){sp=getParent(sc);if(sp&&sp.firstChild!=sc)sp=null;}if(so==sc.nodeValue.length){e=sc.nextSibling;if(e&&e.nodeType==1)sp=sc.nextSibling;}if(eo==0){e=ec.previousSibling;if(e&&e.nodeType==1)ep=e;}if(eo==ec.nodeValue.length){ep=getParent(ec);if(ep&&ep.lastChild!=ec)ep=null;}if(sp==ep)return re&&sp&&re.test(sp.nodeName)?null:sp;}return null;},InsertHorizontalRule:function(){if(isGecko||isIE)this.editor.selection.setContent('
    ');else this.editor.getDoc().execCommand('InsertHorizontalRule',false,'');},RemoveFormat:function(){var t=this,ed=t.editor,s=ed.selection,b;if(isWebKit)s.setContent(s.getContent({format:'raw'}).replace(/(<(span|b|i|strong|em|strike) [^>]+>|<(span|b|i|strong|em|strike)>|<\/(span|b|i|strong|em|strike)>|)/g,''),{format:'raw'});else ed.getDoc().execCommand('RemoveFormat',false,null);t.mceSetStyleInfo(0,{command:'removeformat'});ed.addVisual();},mceSetStyleInfo:function(u,v){var t=this,ed=t.editor,d=ed.getDoc(),dom=ed.dom,e,b,s=ed.selection,nn=v.wrapper||'span',b=s.getBookmark(),re;function set(n,e){if(n.nodeType==1){switch(v.command){case'setattrib':return dom.setAttrib(n,v.name,v.value);case'setstyle':return dom.setStyle(n,v.name,v.value);case'removeformat':return dom.setAttrib(n,'class','');}}};re=ed.settings.merge_styles_invalid_parents;if(tinymce.is(re,'string'))re=new RegExp(re,'i');if(e=t.getSelectedElement())set(e,1);else{d.execCommand('FontName',false,'__');each(isWebKit?dom.select('span'):dom.select('font'),function(n){var sp,e;if(dom.getAttrib(n,'face')=='__'||n.style.fontFamily==='__'){sp=dom.create(nn,{mce_new:'1'});set(sp);each(n.childNodes,function(n){sp.appendChild(n.cloneNode(true));});dom.replace(sp,n);}});}each(dom.select(nn).reverse(),function(n){var p=n.parentNode;if(!dom.getAttrib(n,'mce_new')){p=dom.getParent(n,function(n){return n.nodeType==1&&dom.getAttrib(n,'mce_new');});if(p)dom.remove(n,1);}});each(dom.select(nn).reverse(),function(n){var p=n.parentNode;if(!p||!dom.getAttrib(n,'mce_new'))return;if(p.nodeName==nn.toUpperCase()&&p.childNodes.length==1)return dom.remove(p,1);if(n.nodeType==1&&(!re||!re.test(p.nodeName))&&p.childNodes.length==1){set(p);dom.setAttrib(n,'class','');}});each(dom.select(nn).reverse(),function(n){if(dom.getAttrib(n,'mce_new')||(dom.getAttribs(n).length<=1&&n.className==='')){if(!dom.getAttrib(n,'class')&&!dom.getAttrib(n,'style'))return dom.remove(n,1);dom.setAttrib(n,'mce_new','');}});s.moveToBookmark(b);},queryStateJustify:function(c,v){var ed=this.editor,n=ed.selection.getNode(),dom=ed.dom;if(n&&n.nodeName=='IMG'){if(dom.getStyle(n,'float')==v)return 1;return n.parentNode.style.textAlign==v;}n=dom.getParent(ed.selection.getStart(),function(n){return n.nodeType==1&&n.style.textAlign;});if(v=='full')v='justify';if(ed.settings.inline_styles)return(n&&n.style.textAlign==v);return this._queryState(c);},HiliteColor:function(ui,val){var t=this,ed=t.editor,d=ed.getDoc();function set(s){if(!isGecko)return;try{d.execCommand("styleWithCSS",0,s);}catch(ex){d.execCommand("useCSS",0,!s);}};if(isGecko||isOpera){set(true);d.execCommand('hilitecolor',false,val);set(false);}else d.execCommand('BackColor',false,val);},Undo:function(){var ed=this.editor;if(ed.settings.custom_undo_redo){ed.undoManager.undo();ed.nodeChanged();}else ed.getDoc().execCommand('Undo',false,null);},Redo:function(){var ed=this.editor;if(ed.settings.custom_undo_redo){ed.undoManager.redo();ed.nodeChanged();}else ed.getDoc().execCommand('Redo',false,null);},FormatBlock:function(ui,val){var t=this,ed=t.editor;val=ed.settings.forced_root_block?(val||'

    '):val;if(/^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/.test(ed.selection.getNode().nodeName))t.mceRemoveNode();if(val.indexOf('<')==-1)val='<'+val+'>';if(tinymce.isGecko)val=val.replace(/<(div|blockquote|code|dt|dd|dl|samp)>/gi,'$1');ed.getDoc().execCommand('FormatBlock',false,val);},mceCleanup:function(){var ed=this.editor,s=ed.selection,b=s.getBookmark();ed.setContent(ed.getContent());s.moveToBookmark(b);},mceRemoveNode:function(ui,val){var ed=this.editor,s=ed.selection,b,n=val||s.getNode();if(n==ed.getBody())return;b=s.getBookmark();ed.dom.remove(n,1);s.moveToBookmark(b);ed.nodeChanged();},mceSelectNodeDepth:function(ui,val){var ed=this.editor,s=ed.selection,c=0;ed.dom.getParent(s.getNode(),function(n){if(n.nodeType==1&&c++==val){s.select(n);ed.nodeChanged();return false;}},ed.getBody());},mceSelectNode:function(u,v){this.editor.selection.select(v);},mceInsertContent:function(ui,val){this.editor.selection.setContent(val);},mceInsertRawHTML:function(ui,val){var ed=this.editor;ed.selection.setContent('tiny_mce_marker');ed.setContent(ed.getContent().replace(/tiny_mce_marker/g,val));},mceRepaint:function(){var s,b,e=this.editor;if(tinymce.isGecko){try{s=e.selection;b=s.getBookmark(true);if(s.getSel())s.getSel().selectAllChildren(e.getBody());s.collapse(true);s.moveToBookmark(b);}catch(ex){}}},queryStateUnderline:function(){var ed=this.editor,n=ed.selection.getNode();if(n&&n.nodeName=='A')return false;return this._queryState('Underline');},queryStateOutdent:function(){var ed=this.editor,n;if(ed.settings.inline_styles){if((n=ed.dom.getParent(ed.selection.getStart(),ed.dom.isBlock))&&parseInt(n.style.paddingLeft)>0)return true;if((n=ed.dom.getParent(ed.selection.getEnd(),ed.dom.isBlock))&&parseInt(n.style.paddingLeft)>0)return true;}else return!!ed.dom.getParent(ed.selection.getNode(),'BLOCKQUOTE');return this.queryStateInsertUnorderedList()||this.queryStateInsertOrderedList();},queryStateInsertUnorderedList:function(){return this.editor.dom.getParent(this.editor.selection.getNode(),'UL');},queryStateInsertOrderedList:function(){return this.editor.dom.getParent(this.editor.selection.getNode(),'OL');},queryStatemceBlockQuote:function(){return!!this.editor.dom.getParent(this.editor.selection.getStart(),function(n){return n.nodeName==='BLOCKQUOTE';});},mceBlockQuote:function(){var t=this,ed=t.editor,s=ed.selection,dom=ed.dom,sb,eb,n,bm,bq,r,bq2,i,nl;function getBQ(e){return dom.getParent(e,function(n){return n.nodeName==='BLOCKQUOTE';});};sb=dom.getParent(s.getStart(),dom.isBlock);eb=dom.getParent(s.getEnd(),dom.isBlock);if(bq=getBQ(sb)){if(sb!=eb||sb.childNodes.length>1||(sb.childNodes.length==1&&sb.firstChild.nodeName!='BR'))bm=s.getBookmark();if(getBQ(eb)){bq2=bq.cloneNode(false);while(n=eb.nextSibling)bq2.appendChild(n.parentNode.removeChild(n));}if(bq2)dom.insertAfter(bq2,bq);nl=t._getSelectedBlocks(sb,eb);for(i=nl.length-1;i>=0;i--){dom.insertAfter(nl[i],bq);}if(/^\s*$/.test(bq.innerHTML))dom.remove(bq,1);if(bq2&&/^\s*$/.test(bq2.innerHTML))dom.remove(bq2,1);if(!bm){if(!isIE){r=ed.getDoc().createRange();r.setStart(sb,0);r.setEnd(sb,0);s.setRng(r);}else{s.select(sb);s.collapse(0);if(dom.getParent(s.getStart(),dom.isBlock)!=sb){r=s.getRng();r.move('character',-1);r.select();}}}else t.editor.selection.moveToBookmark(bm);return;}if(isIE&&!sb&&!eb){t.editor.getDoc().execCommand('Indent');n=getBQ(s.getNode());n.style.margin=n.dir='';return;}if(!sb||!eb)return;if(sb!=eb||sb.childNodes.length>1||(sb.childNodes.length==1&&sb.firstChild.nodeName!='BR'))bm=s.getBookmark();each(t._getSelectedBlocks(getBQ(s.getStart()),getBQ(s.getEnd())),function(e){if(e.nodeName=='BLOCKQUOTE'&&!bq){bq=e;return;}if(!bq){bq=dom.create('blockquote');e.parentNode.insertBefore(bq,e);}if(e.nodeName=='BLOCKQUOTE'&&bq){n=e.firstChild;while(n){bq.appendChild(n.cloneNode(true));n=n.nextSibling;}dom.remove(e);return;}bq.appendChild(dom.remove(e));});if(!bm){if(!isIE){r=ed.getDoc().createRange();r.setStart(sb,0);r.setEnd(sb,0);s.setRng(r);}else{s.select(sb);s.collapse(1);}}else s.moveToBookmark(bm);},_getSelectedBlocks:function(st,en){var ed=this.editor,dom=ed.dom,s=ed.selection,sb,eb,n,bl=[];sb=dom.getParent(st||s.getStart(),dom.isBlock);eb=dom.getParent(en||s.getEnd(),dom.isBlock);if(sb)bl.push(sb);if(sb&&eb&&sb!=eb){n=sb;while((n=n.nextSibling)&&n!=eb){if(dom.isBlock(n))bl.push(n);}}if(eb&&sb!=eb)bl.push(eb);return bl;}});})();tinymce.create('tinymce.UndoManager',{index:0,data:null,typing:0,UndoManager:function(ed){var t=this,Dispatcher=tinymce.util.Dispatcher;t.editor=ed;t.data=[];t.onAdd=new Dispatcher(this);t.onUndo=new Dispatcher(this);t.onRedo=new Dispatcher(this);},add:function(l){var t=this,i,ed=t.editor,b,s=ed.settings,la;l=l||{};l.content=l.content||ed.getContent({format:'raw',no_events:1});l.content=l.content.replace(/^\s*|\s*$/g,'');la=t.data[t.index>0?t.index-1:0];if(!l.initial&&la&&l.content==la.content)return null;if(s.custom_undo_redo_levels){if(t.data.length>s.custom_undo_redo_levels){for(i=0;i0){if(t.index==t.data.length&&t.index>1){i=t.index;t.typing=0;if(!t.add())t.index=i;--t.index;}l=t.data[--t.index];ed.setContent(l.content,{format:'raw'});ed.selection.moveToBookmark(l.bookmark);t.onUndo.dispatch(t,l);}return l;},redo:function(){var t=this,ed=t.editor,l=null;if(t.index','gi');t.rePadd=new RegExp(']+)><\\\/p>|]+)\\\/>|]+)>\\s+<\\\/p>|

    <\\\/p>||

    \\s+<\\\/p>'.replace(/p/g,elm),'gi');t.reNbsp2BR1=new RegExp(']+)>[\\s\\u00a0]+<\\\/p>|

    [\\s\\u00a0]+<\\\/p>'.replace(/p/g,elm),'gi');t.reNbsp2BR2=new RegExp(']+)>( | )<\\\/p>|

    ( | )<\\\/p>'.replace(/p/g,elm),'gi');t.reBR2Nbsp=new RegExp(']+)>\\s*
    \\s*<\\\/p>|

    \\s*
    \\s*<\\\/p>'.replace(/p/g,elm),'gi');t.reTrailBr=new RegExp('\\s*
    \\s*<\\\/p>'.replace(/p/g,elm),'gi');function padd(ed,o){if(isOpera)o.content=o.content.replace(t.reOpera,'');o.content=o.content.replace(t.rePadd,'<'+elm+'$1$2$3$4$5$6>\u00a0');if(!isIE&&!isOpera&&o.set){o.content=o.content.replace(t.reNbsp2BR1,'<'+elm+'$1$2>
    ');o.content=o.content.replace(t.reNbsp2BR2,'<'+elm+'$1$2>
    ');}else{o.content=o.content.replace(t.reBR2Nbsp,'<'+elm+'$1$2>\u00a0');o.content=o.content.replace(t.reTrailBr,'');}};ed.onBeforeSetContent.add(padd);ed.onPostProcess.add(padd);if(s.forced_root_block){ed.onInit.add(t.forceRoots,t);ed.onSetContent.add(t.forceRoots,t);ed.onBeforeGetContent.add(t.forceRoots,t);}},setup:function(){var t=this,ed=t.editor,s=ed.settings;if(s.forced_root_block){ed.onKeyUp.add(t.forceRoots,t);ed.onPreProcess.add(t.forceRoots,t);}if(s.force_br_newlines){if(isIE){ed.onKeyPress.add(function(ed,e){var n,s=ed.selection;if(e.keyCode==13&&s.getNode().nodeName!='LI'){s.setContent('
    ',{format:'raw'});n=ed.dom.get('__');n.removeAttribute('id');s.select(n);s.collapse();return Event.cancel(e);}});}return;}if(!isIE&&s.force_p_newlines){ed.onKeyPress.add(function(ed,e){if(e.keyCode==13&&!e.shiftKey){if(!t.insertPara(e))Event.cancel(e);}});if(isGecko){ed.onKeyDown.add(function(ed,e){if((e.keyCode==8||e.keyCode==46)&&!e.shiftKey)t.backspaceDelete(e,e.keyCode==8);});}}function ren(rn,na){var ne=ed.dom.create(na);each(rn.attributes,function(a){if(a.specified&&a.nodeValue)ne.setAttribute(a.nodeName.toLowerCase(),a.nodeValue);});each(rn.childNodes,function(n){ne.appendChild(n.cloneNode(true));});rn.parentNode.replaceChild(ne,rn);return ne;};if(isIE&&s.element!='P'){ed.onKeyPress.add(function(ed,e){t.lastElm=ed.selection.getNode().nodeName;});ed.onKeyUp.add(function(ed,e){var bl,sel=ed.selection,n=sel.getNode(),b=ed.getBody();if(b.childNodes.length===1&&n.nodeName=='P'){n=ren(n,s.element);sel.select(n);sel.collapse();ed.nodeChanged();}else if(e.keyCode==13&&!e.shiftKey&&t.lastElm!='P'){bl=ed.dom.getParent(n,'P');if(bl){ren(bl,s.element);ed.nodeChanged();}}});}},find:function(n,t,s){var ed=this.editor,w=ed.getDoc().createTreeWalker(n,4,null,false),c=-1;while(n=w.nextNode()){c++;if(t==0&&n==s)return c;if(t==1&&c==s)return n;}return-1;},forceRoots:function(ed,e){var t=this,ed=t.editor,b=ed.getBody(),d=ed.getDoc(),se=ed.selection,s=se.getSel(),r=se.getRng(),si=-2,ei,so,eo,tr,c=-0xFFFFFF;var nx,bl,bp,sp,le,nl=b.childNodes,i;if(e&&e.keyCode==13)return true;for(i=nl.length-1;i>=0;i--){nx=nl[i];if(nx.nodeType==3||(!t.dom.isBlock(nx)&&nx.nodeType!=8)){if(!bl){if(nx.nodeType!=3||/[^\s]/g.test(nx.nodeValue)){if(si==-2&&r){if(!isIE){so=r.startOffset;eo=r.endOffset;si=t.find(b,0,r.startContainer);ei=t.find(b,0,r.endContainer);}else{tr=d.body.createTextRange();tr.moveToElementText(b);tr.collapse(1);bp=tr.move('character',c)*-1;tr=r.duplicate();tr.collapse(1);sp=tr.move('character',c)*-1;tr=r.duplicate();tr.collapse(0);le=(tr.move('character',c)*-1)-sp;si=sp-bp;ei=le;}}bl=ed.dom.create(ed.settings.forced_root_block);bl.appendChild(nx.cloneNode(1));nx.parentNode.replaceChild(bl,nx);}}else{if(bl.hasChildNodes())bl.insertBefore(nx,bl.firstChild);else bl.appendChild(nx);}}else bl=null;}if(si!=-2){if(!isIE){bl=d.getElementsByTagName(ed.settings.element)[0];r=d.createRange();if(si!=-1)r.setStart(t.find(b,1,si),so);else r.setStart(bl,0);if(ei!=-1)r.setEnd(t.find(b,1,ei),eo);else r.setEnd(bl,0);if(s){s.removeAllRanges();s.addRange(r);}}else{try{r=s.createRange();r.moveToElementText(b);r.collapse(1);r.moveStart('character',si);r.moveEnd('character',ei);r.select();}catch(ex){}}}},getParentBlock:function(n){var d=this.dom;return d.getParent(n,d.isBlock);},insertPara:function(e){var t=this,ed=t.editor,dom=ed.dom,d=ed.getDoc(),se=ed.settings,s=ed.selection.getSel(),r=s.getRangeAt(0),b=d.body;var rb,ra,dir,sn,so,en,eo,sb,eb,bn,bef,aft,sc,ec,n,vp=dom.getViewPort(ed.getWin()),y,ch;function isEmpty(n){n=n.innerHTML;n=n.replace(/<(img|hr|table)/gi,'-');n=n.replace(/<[^>]+>/g,'');return n.replace(/[ \t\r\n]+/g,'')=='';};rb=d.createRange();rb.setStart(s.anchorNode,s.anchorOffset);rb.collapse(true);ra=d.createRange();ra.setStart(s.focusNode,s.focusOffset);ra.collapse(true);dir=rb.compareBoundaryPoints(rb.START_TO_END,ra)<0;sn=dir?s.anchorNode:s.focusNode;so=dir?s.anchorOffset:s.focusOffset;en=dir?s.focusNode:s.anchorNode;eo=dir?s.focusOffset:s.anchorOffset;if(sn===en&&/^(TD|TH)$/.test(sn.nodeName)){dom.remove(sn.firstChild);ed.dom.add(sn,se.element,null,'
    ');aft=ed.dom.add(sn,se.element,null,'
    ');r=d.createRange();r.selectNodeContents(aft);r.collapse(1);ed.selection.setRng(r);return false;}if(sn==b&&en==b&&b.firstChild&&ed.dom.isBlock(b.firstChild)){sn=en=sn.firstChild;so=eo=0;rb=d.createRange();rb.setStart(sn,0);ra=d.createRange();ra.setStart(en,0);}sn=sn.nodeName=="HTML"?d.body:sn;sn=sn.nodeName=="BODY"?sn.firstChild:sn;en=en.nodeName=="HTML"?d.body:en;en=en.nodeName=="BODY"?en.firstChild:en;sb=t.getParentBlock(sn);eb=t.getParentBlock(en);bn=sb?sb.nodeName:se.element;if(t.dom.getParent(sb,function(n){return/OL|UL|PRE/.test(n.nodeName);}))return true;if(sb&&(sb.nodeName=='CAPTION'||/absolute|relative|static/gi.test(sb.style.position))){bn=se.element;sb=null;}if(eb&&(eb.nodeName=='CAPTION'||/absolute|relative|static/gi.test(eb.style.position))){bn=se.element;eb=null;}if(/(TD|TABLE|TH|CAPTION)/.test(bn)||(sb&&bn=="DIV"&&/left|right/gi.test(sb.style.cssFloat))){bn=se.element;sb=eb=null;}bef=(sb&&sb.nodeName==bn)?sb.cloneNode(0):ed.dom.create(bn);aft=(eb&&eb.nodeName==bn)?eb.cloneNode(0):ed.dom.create(bn);aft.removeAttribute('id');if(/^(H[1-6])$/.test(bn)&&sn.nodeValue&&so==sn.nodeValue.length)aft=ed.dom.create(se.element);n=sc=sn;do{if(n==b||n.nodeType==9||t.dom.isBlock(n)||/(TD|TABLE|TH|CAPTION)/.test(n.nodeName))break;sc=n;}while((n=n.previousSibling?n.previousSibling:n.parentNode));n=ec=en;do{if(n==b||n.nodeType==9||t.dom.isBlock(n)||/(TD|TABLE|TH|CAPTION)/.test(n.nodeName))break;ec=n;}while((n=n.nextSibling?n.nextSibling:n.parentNode));if(sc.nodeName==bn)rb.setStart(sc,0);else rb.setStartBefore(sc);rb.setEnd(sn,so);bef.appendChild(rb.cloneContents()||d.createTextNode(''));try{ra.setEndAfter(ec);}catch(ex){}ra.setStart(en,eo);aft.appendChild(ra.cloneContents()||d.createTextNode(''));r=d.createRange();if(!sc.previousSibling&&sc.parentNode.nodeName==bn){r.setStartBefore(sc.parentNode);}else{if(rb.startContainer.nodeName==bn&&rb.startOffset==0)r.setStartBefore(rb.startContainer);else r.setStart(rb.startContainer,rb.startOffset);}if(!ec.nextSibling&&ec.parentNode.nodeName==bn)r.setEndAfter(ec.parentNode);else r.setEnd(ra.endContainer,ra.endOffset);r.deleteContents();if(isOpera)ed.getWin().scrollTo(0,vp.y);if(bef.firstChild&&bef.firstChild.nodeName==bn)bef.innerHTML=bef.firstChild.innerHTML;if(aft.firstChild&&aft.firstChild.nodeName==bn)aft.innerHTML=aft.firstChild.innerHTML;if(isEmpty(bef))bef.innerHTML='
    ';if(isEmpty(aft))aft.innerHTML=isOpera?' ':'
    ';if(isOpera){r.insertNode(bef);r.insertNode(aft);}else{r.insertNode(aft);r.insertNode(bef);}aft.normalize();bef.normalize();r=d.createRange();r.selectNodeContents(aft);r.collapse(1);s.removeAllRanges();s.addRange(r);y=ed.dom.getPos(aft).y;ch=aft.clientHeight;if(yvp.y+vp.h){ed.getWin().scrollTo(0,y'); + tinymce.ScriptLoader.markDone(u); + } + } + }, + + pickColor : function(e, element_id) { + this.execCommand('mceColorPicker', true, { + color : document.getElementById(element_id).value, + func : function(c) { + document.getElementById(element_id).value = c; + + try { + document.getElementById(element_id).onchange(); + } catch (ex) { + // Try fire event, ignore errors + } + } + }); + }, + + openBrowser : function(element_id, type, option) { + tinyMCEPopup.restoreSelection(); + this.editor.execCallback('file_browser_callback', element_id, document.getElementById(element_id).value, type, window); + }, + + close : function() { + var t = this; + + // To avoid domain relaxing issue in Opera + function close() { + t.editor.windowManager.close(window, t.id); + tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup + }; + + if (tinymce.isOpera) + t.getWin().setTimeout(close, 0); + else + close(); + }, + + // Internal functions + + _restoreSelection : function() { + var e = window.event.srcElement; + + if (e.nodeName == 'INPUT' && (e.type == 'submit' || e.type == 'button')) + tinyMCEPopup.restoreSelection(); + }, + +/* _restoreSelection : function() { + var e = window.event.srcElement; + + // If user focus a non text input or textarea + if ((e.nodeName != 'INPUT' && e.nodeName != 'TEXTAREA') || e.type != 'text') + tinyMCEPopup.restoreSelection(); + },*/ + + _onDOMLoaded : function() { + var t = this, ti = document.title, bm, h; + + // Translate page + h = document.body.innerHTML; + + // Replace a=x with a="x" in IE + if (tinymce.isIE) + h = h.replace(/ (value|title|alt)=([^"][^\s>]+)/gi, ' $1="$2"') + + document.dir = t.editor.getParam('directionality',''); + document.body.innerHTML = t.editor.translate(h); + document.title = ti = t.editor.translate(ti); + document.body.style.display = ''; + + // Restore selection in IE when focus is placed on a non textarea or input element of the type text + if (tinymce.isIE) + document.attachEvent('onmouseup', tinyMCEPopup._restoreSelection); + + t.restoreSelection(); + t.resizeToInnerSize(); + + // Set inline title + if (!t.isWindow) + t.editor.windowManager.setTitle(ti, t.id); + else + window.focus(); + + if (!tinymce.isIE && !t.isWindow) { + tinymce.dom.Event._add(document, 'focus', function() { + t.editor.windowManager.focus(t.id) + }); + } + + // Patch for accessibility + tinymce.each(t.dom.select('select'), function(e) { + e.onkeydown = tinyMCEPopup._accessHandler; + }); + + // Call onInit + // Init must be called before focus so the selection won't get lost by the focus call + tinymce.each(t.listeners, function(o) { + o.func.call(o.scope, t.editor); + }); + + // Move focus to window + if (t.getWindowArg('mce_auto_focus', true)) { + window.focus(); + + // Focus element with mceFocus class + tinymce.each(document.forms, function(f) { + tinymce.each(f.elements, function(e) { + if (t.dom.hasClass(e, 'mceFocus') && !e.disabled) { + e.focus(); + return false; // Break loop + } + }); + }); + } + + document.onkeyup = tinyMCEPopup._closeWinKeyHandler; + }, + + _accessHandler : function(e) { + e = e || window.event; + + if (e.keyCode == 13 || e.keyCode == 32) { + e = e.target || e.srcElement; + + if (e.onchange) + e.onchange(); + + return tinymce.dom.Event.cancel(e); + } + }, + + _closeWinKeyHandler : function(e) { + e = e || window.event; + + if (e.keyCode == 27) + tinyMCEPopup.close(); + }, + + _wait : function() { + var t = this, ti; + + if (tinymce.isIE && document.location.protocol != 'https:') { + // Fake DOMContentLoaded on IE + document.write(''; + + bi = s.body_id || 'tinymce'; + if (bi.indexOf('=') != -1) { + bi = t.getParam('body_id', '', 'hash'); + bi = bi[t.id] || bi; + } + + bc = s.body_class || ''; + if (bc.indexOf('=') != -1) { + bc = t.getParam('body_class', '', 'hash'); + bc = bc[t.id] || ''; + } + + t.iframeHTML += ''; + + // Domain relaxing enabled, then set document domain + if (tinymce.relaxedDomain) { + // We need to write the contents here in IE since multiple writes messes up refresh button and back button + if (isIE) + u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";var ed = window.parent.tinyMCE.get("' + t.id + '");document.write(ed.iframeHTML);document.close();ed.setupIframe();})()'; + else if (tinymce.isOpera) + u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";document.close();ed.setupIframe();})()'; + } + + // Create iframe + n = DOM.add(o.iframeContainer, 'iframe', { + id : t.id + "_ifr", + src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7 + frameBorder : '0', + style : { + width : '100%', + height : h + } + }); + + t.contentAreaContainer = o.iframeContainer; + DOM.get(o.editorContainer).style.display = t.orgDisplay; + DOM.get(t.id).style.display = 'none'; + + // Safari 2.x requires us to wait for the load event and load a real HTML doc + if (tinymce.isOldWebKit) { + Event.add(n, 'load', t.setupIframe, t); + n.src = tinymce.baseURL + '/plugins/safari/blank.htm'; + } else { + if (!isIE || !tinymce.relaxedDomain) + t.setupIframe(); + + e = n = o = null; // Cleanup + } + }, + + setupIframe : function() { + var t = this, s = t.settings, e = DOM.get(t.id), d = t.getDoc(), h, b; + + // Setup iframe body + if (!isIE || !tinymce.relaxedDomain) { + d.open(); + d.write(t.iframeHTML); + d.close(); + } + + // Design mode needs to be added here Ctrl+A will fail otherwise + if (!isIE) { + try { + d.designMode = 'On'; + } catch (ex) { + // Will fail on Gecko if the editor is placed in an hidden container element + // The design mode will be set ones the editor is focused + } + } + + // IE needs to use contentEditable or it will display non secure items for HTTPS + if (isIE) { + // It will not steal focus if we hide it while setting contentEditable + b = t.getBody(); + DOM.hide(b); + b.contentEditable = true; + DOM.show(b); + } + + // Setup objects + t.dom = new tinymce.DOM.DOMUtils(t.getDoc(), { + keep_values : true, + url_converter : t.convertURL, + url_converter_scope : t, + hex_colors : s.force_hex_style_colors, + class_filter : s.class_filter, + update_styles : 1, + fix_ie_paragraphs : 1 + }); + + t.serializer = new tinymce.dom.Serializer({ + entity_encoding : s.entity_encoding, + entities : s.entities, + valid_elements : s.verify_html === false ? '*[*]' : s.valid_elements, + extended_valid_elements : s.extended_valid_elements, + valid_child_elements : s.valid_child_elements, + invalid_elements : s.invalid_elements, + fix_table_elements : s.fix_table_elements, + fix_list_elements : s.fix_list_elements, + fix_content_duplication : s.fix_content_duplication, + convert_fonts_to_spans : s.convert_fonts_to_spans, + font_size_classes : s.font_size_classes, + font_size_style_values : s.font_size_style_values, + apply_source_formatting : s.apply_source_formatting, + remove_linebreaks : s.remove_linebreaks, + dom : t.dom + }); + + t.selection = new tinymce.dom.Selection(t.dom, t.getWin(), t.serializer); + t.forceBlocks = new tinymce.ForceBlocks(t, { + forced_root_block : s.forced_root_block + }); + t.editorCommands = new tinymce.EditorCommands(t); + + // Pass through + t.serializer.onPreProcess.add(function(se, o) { + return t.onPreProcess.dispatch(t, o, se); + }); + + t.serializer.onPostProcess.add(function(se, o) { + return t.onPostProcess.dispatch(t, o, se); + }); + + t.onPreInit.dispatch(t); + + if (!s.gecko_spellcheck) + t.getBody().spellcheck = 0; + + t._addEvents(); + + t.controlManager.onPostRender.dispatch(t, t.controlManager); + t.onPostRender.dispatch(t); + + if (s.directionality) + t.getBody().dir = s.directionality; + + if (s.nowrap) + t.getBody().style.whiteSpace = "nowrap"; + + if (s.auto_resize) + t.onNodeChange.add(t.resizeToContent, t); + + if (s.custom_elements) { + function handleCustom(ed, o) { + each(explode(s.custom_elements), function(v) { + var n; + + if (v.indexOf('~') === 0) { + v = v.substring(1); + n = 'span'; + } else + n = 'div'; + + o.content = o.content.replace(new RegExp('<(' + v + ')([^>]*)>', 'g'), '<' + n + ' mce_name="$1"$2>'); + o.content = o.content.replace(new RegExp('', 'g'), ''); + }); + }; + + t.onBeforeSetContent.add(handleCustom); + t.onPostProcess.add(function(ed, o) { + if (o.set) + handleCustom(ed, o) + }); + } + + if (s.handle_node_change_callback) { + t.onNodeChange.add(function(ed, cm, n) { + t.execCallback('handle_node_change_callback', t.id, n, -1, -1, true, t.selection.isCollapsed()); + }); + } + + if (s.save_callback) { + t.onSaveContent.add(function(ed, o) { + var h = t.execCallback('save_callback', t.id, o.content, t.getBody()); + + if (h) + o.content = h; + }); + } + + if (s.onchange_callback) { + t.onChange.add(function(ed, l) { + t.execCallback('onchange_callback', t, l); + }); + } + + if (s.convert_newlines_to_brs) { + t.onBeforeSetContent.add(function(ed, o) { + if (o.initial) + o.content = o.content.replace(/\r?\n/g, '
    '); + }); + } + + if (s.fix_nesting && isIE) { + t.onBeforeSetContent.add(function(ed, o) { + o.content = t._fixNesting(o.content); + }); + } + + if (s.preformatted) { + t.onPostProcess.add(function(ed, o) { + o.content = o.content.replace(/^\s*/, ''); + o.content = o.content.replace(/<\/pre>\s*$/, ''); + + if (o.set) + o.content = '

    ' + o.content + '
    '; + }); + } + + if (s.verify_css_classes) { + t.serializer.attribValueFilter = function(n, v) { + var s, cl; + + if (n == 'class') { + // Build regexp for classes + if (!t.classesRE) { + cl = t.dom.getClasses(); + + if (cl.length > 0) { + s = ''; + + each (cl, function(o) { + s += (s ? '|' : '') + o['class']; + }); + + t.classesRE = new RegExp('(' + s + ')', 'gi'); + } + } + + return !t.classesRE || /(\bmceItem\w+\b|\bmceTemp\w+\b)/g.test(v) || t.classesRE.test(v) ? v : ''; + } + + return v; + }; + } + + if (s.convert_fonts_to_spans) + t._convertFonts(); + + if (s.inline_styles) + t._convertInlineElements(); + + if (s.cleanup_callback) { + t.onBeforeSetContent.add(function(ed, o) { + o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o); + }); + + t.onPreProcess.add(function(ed, o) { + if (o.set) + t.execCallback('cleanup_callback', 'insert_to_editor_dom', o.node, o); + + if (o.get) + t.execCallback('cleanup_callback', 'get_from_editor_dom', o.node, o); + }); + + t.onPostProcess.add(function(ed, o) { + if (o.set) + o.content = t.execCallback('cleanup_callback', 'insert_to_editor', o.content, o); + + if (o.get) + o.content = t.execCallback('cleanup_callback', 'get_from_editor', o.content, o); + }); + } + + if (s.save_callback) { + t.onGetContent.add(function(ed, o) { + if (o.save) + o.content = t.execCallback('save_callback', t.id, o.content, t.getBody()); + }); + } + + if (s.handle_event_callback) { + t.onEvent.add(function(ed, e, o) { + if (t.execCallback('handle_event_callback', e, ed, o) === false) + Event.cancel(e); + }); + } + + t.onSetContent.add(function() { + // Safari needs some time, it will crash the browser when a link is created otherwise + // I think this crash issue is resolved in the latest 3.0.4 + //window.setTimeout(function() { + t.addVisual(t.getBody()); + //}, 1); + }); + + // Remove empty contents + if (s.padd_empty_editor) { + t.onPostProcess.add(function(ed, o) { + o.content = o.content.replace(/^

    ( |#160;|\s|\u00a0)<\/p>$/, ''); + }); + } + + if (isGecko) { + try { + // Design mode must be set here once again to fix a bug where + // Ctrl+A/Delete/Backspace didn't work if the editor was added using mceAddControl then removed then added again + d.designMode = 'Off'; + d.designMode = 'On'; + } catch (ex) { + // Will fail on Gecko if the editor is placed in an hidden container element + // The design mode will be set ones the editor is focused + } + } + + // A small timeout was needed since firefox will remove. Bug: #1838304 + setTimeout(function () { + if (t.removed) + return; + + t.load({initial : true, format : (s.cleanup_on_startup ? 'html' : 'raw')}); + t.startContent = t.getContent({format : 'raw'}); + t.undoManager.add({initial : true}); + t.initialized = true; + + t.onInit.dispatch(t); + t.execCallback('setupcontent_callback', t.id, t.getBody(), t.getDoc()); + t.execCallback('init_instance_callback', t); + t.focus(true); + t.nodeChanged({initial : 1}); + + // Load specified content CSS last + if (s.content_css) { + tinymce.each(explode(s.content_css), function(u) { + t.dom.loadCSS(t.documentBaseURI.toAbsolute(u)); + }); + } + + // Handle auto focus + if (s.auto_focus) { + setTimeout(function () { + var ed = EditorManager.get(s.auto_focus); + + ed.selection.select(ed.getBody(), 1); + ed.selection.collapse(1); + ed.getWin().focus(); + }, 100); + } + }, 1); + + e = null; + }, + + + focus : function(sf) { + var oed, t = this; + + if (!sf) { + t.getWin().focus(); + + } + + if (EditorManager.activeEditor != t) { + if ((oed = EditorManager.activeEditor) != null) + oed.onDeactivate.dispatch(oed, t); + + t.onActivate.dispatch(t, oed); + } + + EditorManager._setActive(t); + }, + + execCallback : function(n) { + var t = this, f = t.settings[n], s; + + if (!f) + return; + + // Look through lookup + if (t.callbackLookup && (s = t.callbackLookup[n])) { + f = s.func; + s = s.scope; + } + + if (is(f, 'string')) { + s = f.replace(/\.\w+$/, ''); + s = s ? tinymce.resolve(s) : 0; + f = tinymce.resolve(f); + t.callbackLookup = t.callbackLookup || {}; + t.callbackLookup[n] = {func : f, scope : s}; + } + + return f.apply(s || t, Array.prototype.slice.call(arguments, 1)); + }, + + translate : function(s) { + var c = this.settings.language, i18n = EditorManager.i18n; + + if (!s) + return ''; + + return i18n[c + '.' + s] || s.replace(/{\#([^}]+)\}/g, function(a, b) { + return i18n[c + '.' + b] || '{#' + b + '}'; + }); + }, + + getLang : function(n, dv) { + return EditorManager.i18n[this.settings.language + '.' + n] || (is(dv) ? dv : '{#' + n + '}'); + }, + + getParam : function(n, dv, ty) { + var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o; + + if (ty === 'hash') { + o = {}; + + if (is(v, 'string')) { + each(v.indexOf('=') > 0 ? v.split(/[;,](?![^=;,]*(?:[;,]|$))/) : v.split(','), function(v) { + v = v.split('='); + + if (v.length > 1) + o[tr(v[0])] = tr(v[1]); + else + o[tr(v[0])] = tr(v); + }); + } else + o = v; + + return o; + } + + return v; + }, + + nodeChanged : function(o) { + var t = this, s = t.selection, n = s.getNode() || t.getBody(); + + // Fix for bug #1896577 it seems that this can not be fired while the editor is loading + if (t.initialized) { + t.onNodeChange.dispatch( + t, + o ? o.controlManager || t.controlManager : t.controlManager, + isIE && n.ownerDocument != t.getDoc() ? t.getBody() : n, // Fix for IE initial state + s.isCollapsed(), + o + ); + } + }, + + addButton : function(n, s) { + var t = this; + + t.buttons = t.buttons || {}; + t.buttons[n] = s; + }, + + addCommand : function(n, f, s) { + this.execCommands[n] = {func : f, scope : s || this}; + }, + + addQueryStateHandler : function(n, f, s) { + this.queryStateCommands[n] = {func : f, scope : s || this}; + }, + + addQueryValueHandler : function(n, f, s) { + this.queryValueCommands[n] = {func : f, scope : s || this}; + }, + + addShortcut : function(pa, desc, cmd_func, sc) { + var t = this, c; + + if (!t.settings.custom_shortcuts) + return false; + + t.shortcuts = t.shortcuts || {}; + + if (is(cmd_func, 'string')) { + c = cmd_func; + + cmd_func = function() { + t.execCommand(c, false, null); + }; + } + + if (is(cmd_func, 'object')) { + c = cmd_func; + + cmd_func = function() { + t.execCommand(c[0], c[1], c[2]); + }; + } + + each(explode(pa), function(pa) { + var o = { + func : cmd_func, + scope : sc || this, + desc : desc, + alt : false, + ctrl : false, + shift : false + }; + + each(explode(pa, '+'), function(v) { + switch (v) { + case 'alt': + case 'ctrl': + case 'shift': + o[v] = true; + break; + + default: + o.charCode = v.charCodeAt(0); + o.keyCode = v.toUpperCase().charCodeAt(0); + } + }); + + t.shortcuts[(o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode] = o; + }); + + return true; + }, + + execCommand : function(cmd, ui, val, a) { + var t = this, s = 0, o, st; + + if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd) && (!a || !a.skip_focus)) + t.focus(); + + o = {}; + t.onBeforeExecCommand.dispatch(t, cmd, ui, val, o); + if (o.terminate) + return false; + + // Comamnd callback + if (t.execCallback('execcommand_callback', t.id, t.selection.getNode(), cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return true; + } + + // Registred commands + if (o = t.execCommands[cmd]) { + st = o.func.call(o.scope, ui, val); + + // Fall through on true + if (st !== true) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return st; + } + } + + // Plugin commands + each(t.plugins, function(p) { + if (p.execCommand && p.execCommand(cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + s = 1; + return false; + } + }); + + if (s) + return true; + + // Theme commands + if (t.theme.execCommand && t.theme.execCommand(cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return true; + } + + // Editor commands + if (t.editorCommands.execCommand(cmd, ui, val)) { + t.onExecCommand.dispatch(t, cmd, ui, val, a); + return true; + } + + // Browser commands + t.getDoc().execCommand(cmd, ui, val); + t.onExecCommand.dispatch(t, cmd, ui, val, a); + }, + + queryCommandState : function(c) { + var t = this, o, s; + + // Is hidden then return undefined + if (t._isHidden()) + return; + + // Registred commands + if (o = t.queryStateCommands[c]) { + s = o.func.call(o.scope); + + // Fall though on true + if (s !== true) + return s; + } + + // Registred commands + o = t.editorCommands.queryCommandState(c); + if (o !== -1) + return o; + + // Browser commands + try { + return this.getDoc().queryCommandState(c); + } catch (ex) { + // Fails sometimes see bug: 1896577 + } + }, + + queryCommandValue : function(c) { + var t = this, o, s; + + // Is hidden then return undefined + if (t._isHidden()) + return; + + // Registred commands + if (o = t.queryValueCommands[c]) { + s = o.func.call(o.scope); + + // Fall though on true + if (s !== true) + return s; + } + + // Registred commands + o = t.editorCommands.queryCommandValue(c); + if (is(o)) + return o; + + // Browser commands + try { + return this.getDoc().queryCommandValue(c); + } catch (ex) { + // Fails sometimes see bug: 1896577 + } + }, + + show : function() { + var t = this; + + DOM.show(t.getContainer()); + DOM.hide(t.id); + t.load(); + }, + + hide : function() { + var t = this, d = t.getDoc(); + + // Fixed bug where IE has a blinking cursor left from the editor + if (isIE && d) + d.execCommand('SelectAll'); + + // We must save before we hide so Safari doesn't crash + t.save(); + DOM.hide(t.getContainer()); + DOM.setStyle(t.id, 'display', t.orgDisplay); + }, + + isHidden : function() { + return !DOM.isHidden(this.id); + }, + + setProgressState : function(b, ti, o) { + this.onSetProgressState.dispatch(this, b, ti, o); + + return b; + }, + + resizeToContent : function() { + var t = this; + + DOM.setStyle(t.id + "_ifr", 'height', t.getBody().scrollHeight); + }, + + load : function(o) { + var t = this, e = t.getElement(), h; + + o = o || {}; + o.load = true; + + h = t.setContent(is(e.value) ? e.value : e.innerHTML, o); + o.element = e; + + if (!o.no_events) + t.onLoadContent.dispatch(t, o); + + o.element = e = null; + + return h; + }, + + save : function(o) { + var t = this, e = t.getElement(), h, f; + + if (!t.initialized) + return; + + o = o || {}; + o.save = true; + + o.element = e; + h = o.content = t.getContent(o); + + if (!o.no_events) + t.onSaveContent.dispatch(t, o); + + h = o.content; + + if (!/TEXTAREA|INPUT/i.test(e.nodeName)) { + e.innerHTML = h; + + // Update hidden form element + if (f = DOM.getParent(t.id, 'form')) { + each(f.elements, function(e) { + if (e.name == t.id) { + e.value = h; + return false; + } + }); + } + } else + e.value = h; + + o.element = e = null; + + return h; + }, + + setContent : function(h, o) { + var t = this; + + o = o || {}; + o.format = o.format || 'html'; + o.set = true; + o.content = h; + + if (!o.no_events) + t.onBeforeSetContent.dispatch(t, o); + + // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content + // It will also be impossible to place the caret in the editor unless there is a BR element present + if (!tinymce.isIE && (h.length === 0 || /^\s+$/.test(h))) { + o.content = t.dom.setHTML(t.getBody(), '
    ', 1); + o.format = 'raw'; + } + + o.content = t.dom.setHTML(t.getBody(), tinymce.trim(o.content)); + + if (o.format != 'raw' && t.settings.cleanup) { + o.getInner = true; + o.content = t.dom.setHTML(t.getBody(), t.serializer.serialize(t.getBody(), o)); + } + + if (!o.no_events) + t.onSetContent.dispatch(t, o); + + return o.content; + }, + + getContent : function(o) { + var t = this, h; + + o = o || {}; + o.format = o.format || 'html'; + o.get = true; + + if (!o.no_events) + t.onBeforeGetContent.dispatch(t, o); + + if (o.format != 'raw' && t.settings.cleanup) { + o.getInner = true; + h = t.serializer.serialize(t.getBody(), o); + } else + h = t.getBody().innerHTML; + + h = h.replace(/^\s*|\s*$/g, ''); + o = {content : h}; + t.onGetContent.dispatch(t, o); + + return o.content; + }, + + isDirty : function() { + var t = this; + + return tinymce.trim(t.startContent) != tinymce.trim(t.getContent({format : 'raw', no_events : 1})) && !t.isNotDirty; + }, + + getContainer : function() { + var t = this; + + if (!t.container) + t.container = DOM.get(t.editorContainer || t.id + '_parent'); + + return t.container; + }, + + getContentAreaContainer : function() { + return this.contentAreaContainer; + }, + + getElement : function() { + return DOM.get(this.settings.content_element || this.id); + }, + + getWin : function() { + var t = this, e; + + if (!t.contentWindow) { + e = DOM.get(t.id + "_ifr"); + + if (e) + t.contentWindow = e.contentWindow; + } + + return t.contentWindow; + }, + + getDoc : function() { + var t = this, w; + + if (!t.contentDocument) { + w = t.getWin(); + + if (w) + t.contentDocument = w.document; + } + + return t.contentDocument; + }, + + getBody : function() { + return this.bodyElement || this.getDoc().body; + }, + + convertURL : function(u, n, e) { + var t = this, s = t.settings; + + // Use callback instead + if (s.urlconverter_callback) + return t.execCallback('urlconverter_callback', u, e, true, n); + + // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs + if (!s.convert_urls || (e && e.nodeName == 'LINK') || u.indexOf('file:') === 0) + return u; + + // Convert to relative + if (s.relative_urls) + return t.documentBaseURI.toRelative(u); + + // Convert to absolute + u = t.documentBaseURI.toAbsolute(u, s.remove_script_host); + + return u; + }, + + addVisual : function(e) { + var t = this, s = t.settings; + + e = e || t.getBody(); + + if (!is(t.hasVisual)) + t.hasVisual = s.visual; + + each(t.dom.select('table,a', e), function(e) { + var v; + + switch (e.nodeName) { + case 'TABLE': + v = t.dom.getAttrib(e, 'border'); + + if (!v || v == '0') { + if (t.hasVisual) + t.dom.addClass(e, s.visual_table_class); + else + t.dom.removeClass(e, s.visual_table_class); + } + + return; + + case 'A': + v = t.dom.getAttrib(e, 'name'); + + if (v) { + if (t.hasVisual) + t.dom.addClass(e, 'mceItemAnchor'); + else + t.dom.removeClass(e, 'mceItemAnchor'); + } + + return; + } + }); + + t.onVisualAid.dispatch(t, e, t.hasVisual); + }, + + remove : function() { + var t = this, e = t.getContainer(); + + t.removed = 1; // Cancels post remove event execution + t.hide(); + + t.execCallback('remove_instance_callback', t); + t.onRemove.dispatch(t); + + // Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command + t.onExecCommand.listeners = []; + + EditorManager.remove(t); + DOM.remove(e); + }, + + destroy : function(s) { + var t = this; + + // One time is enough + if (t.destroyed) + return; + + if (!s) { + tinymce.removeUnload(t.destroy); + tinyMCE.onBeforeUnload.remove(t._beforeUnload); + + // Manual destroy + if (t.theme.destroy) + t.theme.destroy(); + + // Destroy controls, selection and dom + t.controlManager.destroy(); + t.selection.destroy(); + t.dom.destroy(); + + // Remove all events + + // Don't clear the window or document if content editable + // is enabled since other instances might still be present + if (!t.settings.content_editable) { + Event.clear(t.getWin()); + Event.clear(t.getDoc()); + } + + Event.clear(t.getBody()); + Event.clear(t.formElement); + } + + if (t.formElement) { + t.formElement.submit = t.formElement._mceOldSubmit; + t.formElement._mceOldSubmit = null; + } + + t.contentAreaContainer = t.formElement = t.container = t.settings.content_element = t.bodyElement = t.contentDocument = t.contentWindow = null; + + if (t.selection) + t.selection = t.selection.win = t.selection.dom = t.selection.dom.doc = null; + + t.destroyed = 1; + }, + + // Internal functions + + _addEvents : function() { + // 'focus', 'blur', 'dblclick', 'beforedeactivate', submit, reset + var t = this, i, s = t.settings, lo = { + mouseup : 'onMouseUp', + mousedown : 'onMouseDown', + click : 'onClick', + keyup : 'onKeyUp', + keydown : 'onKeyDown', + keypress : 'onKeyPress', + submit : 'onSubmit', + reset : 'onReset', + contextmenu : 'onContextMenu', + dblclick : 'onDblClick', + paste : 'onPaste' // Doesn't work in all browsers yet + }; + + function eventHandler(e, o) { + var ty = e.type; + + // Don't fire events when it's removed + if (t.removed) + return; + + // Generic event handler + if (t.onEvent.dispatch(t, e, o) !== false) { + // Specific event handler + t[lo[e.fakeType || e.type]].dispatch(t, e, o); + } + }; + + // Add DOM events + each(lo, function(v, k) { + switch (k) { + case 'contextmenu': + if (tinymce.isOpera) { + // Fake contextmenu on Opera + Event.add(t.getDoc(), 'mousedown', function(e) { + if (e.ctrlKey) { + e.fakeType = 'contextmenu'; + eventHandler(e); + } + }); + } else + Event.add(t.getDoc(), k, eventHandler); + break; + + case 'paste': + Event.add(t.getBody(), k, function(e) { + var tx, h, el, r; + + // Get plain text data + if (e.clipboardData) + tx = e.clipboardData.getData('text/plain'); + else if (tinymce.isIE) + tx = t.getWin().clipboardData.getData('Text'); + + // Get HTML data + /*if (tinymce.isIE) { + el = DOM.add(DOM.doc.body, 'div', {style : 'visibility:hidden;overflow:hidden;position:absolute;width:1px;height:1px'}); + r = DOM.doc.body.createTextRange(); + r.moveToElementText(el); + r.execCommand('Paste'); + h = el.innerHTML; + DOM.remove(el); + }*/ + + eventHandler(e, {text : tx, html : h}); + }); + break; + + case 'submit': + case 'reset': + Event.add(t.getElement().form || DOM.getParent(t.id, 'form'), k, eventHandler); + break; + + default: + Event.add(s.content_editable ? t.getBody() : t.getDoc(), k, eventHandler); + } + }); + + Event.add(s.content_editable ? t.getBody() : (isGecko ? t.getDoc() : t.getWin()), 'focus', function(e) { + t.focus(true); + }); + + + // Fixes bug where a specified document_base_uri could result in broken images + // This will also fix drag drop of images in Gecko + if (tinymce.isGecko) { + // Convert all images to absolute URLs +/* t.onSetContent.add(function(ed, o) { + each(ed.dom.select('img'), function(e) { + var v; + + if (v = e.getAttribute('mce_src')) + e.src = t.documentBaseURI.toAbsolute(v); + }) + });*/ + + Event.add(t.getDoc(), 'DOMNodeInserted', function(e) { + var v; + + e = e.target; + + if (e.nodeType === 1 && e.nodeName === 'IMG' && (v = e.getAttribute('mce_src'))) + e.src = t.documentBaseURI.toAbsolute(v); + }); + } + + // Set various midas options in Gecko + if (isGecko) { + function setOpts() { + var t = this, d = t.getDoc(), s = t.settings; + + if (isGecko) { + if (t._isHidden()) { + try { + if (!s.content_editable) + d.designMode = 'On'; + } catch (ex) { + // Fails if it's hidden + } + } + + try { + // Try new Gecko method + d.execCommand("styleWithCSS", 0, false); + } catch (ex) { + // Use old method + if (!t._isHidden()) + d.execCommand("useCSS", 0, true); + } + + if (!s.table_inline_editing) + try {d.execCommand('enableInlineTableEditing', false, false);} catch (ex) {} + + if (!s.object_resizing) + try {d.execCommand('enableObjectResizing', false, false);} catch (ex) {} + } + }; + + t.onBeforeExecCommand.add(setOpts); + t.onMouseDown.add(setOpts); + } + + // Add node change handlers + t.onMouseUp.add(t.nodeChanged); + t.onClick.add(t.nodeChanged); + t.onKeyUp.add(function(ed, e) { + if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.keyCode == 46 || e.keyCode == 8 || e.ctrlKey) + t.nodeChanged(); + }); + + // Add reset handler + t.onReset.add(function() { + t.setContent(t.startContent, {format : 'raw'}); + }); + + if (t.getParam('tab_focus')) { + function tabCancel(ed, e) { + if (e.keyCode === 9) + return Event.cancel(e); + }; + + function tabHandler(ed, e) { + var x, i, f, el, v; + + function find(d) { + f = DOM.getParent(ed.id, 'form'); + el = f.elements; + + if (f) { + each(el, function(e, i) { + if (e.id == ed.id) { + x = i; + return false; + } + }); + + if (d > 0) { + for (i = x + 1; i < el.length; i++) { + if (el[i].type != 'hidden') + return el[i]; + } + } else { + for (i = x - 1; i >= 0; i--) { + if (el[i].type != 'hidden') + return el[i]; + } + } + } + + return null; + }; + + if (e.keyCode === 9) { + v = explode(ed.getParam('tab_focus')); + + if (v.length == 1) { + v[1] = v[0]; + v[0] = ':prev'; + } + + // Find element to focus + if (e.shiftKey) { + if (v[0] == ':prev') + el = find(-1); + else + el = DOM.get(v[0]); + } else { + if (v[1] == ':next') + el = find(1); + else + el = DOM.get(v[1]); + } + + if (el) { + if (ed = EditorManager.get(el.id || el.name)) + ed.focus(); + else + window.setTimeout(function() {window.focus();el.focus();}, 10); + + return Event.cancel(e); + } + } + }; + + t.onKeyUp.add(tabCancel); + + if (isGecko) { + t.onKeyPress.add(tabHandler); + t.onKeyDown.add(tabCancel); + } else + t.onKeyDown.add(tabHandler); + } + + // Add shortcuts + if (s.custom_shortcuts) { + if (s.custom_undo_redo_keyboard_shortcuts) { + t.addShortcut('ctrl+z', t.getLang('undo_desc'), 'Undo'); + t.addShortcut('ctrl+y', t.getLang('redo_desc'), 'Redo'); + } + + // Add default shortcuts for gecko + if (isGecko) { + t.addShortcut('ctrl+b', t.getLang('bold_desc'), 'Bold'); + t.addShortcut('ctrl+i', t.getLang('italic_desc'), 'Italic'); + t.addShortcut('ctrl+u', t.getLang('underline_desc'), 'Underline'); + } + + // BlockFormat shortcuts keys + for (i=1; i<=6; i++) + t.addShortcut('ctrl+' + i, '', ['FormatBlock', false, '']); + + t.addShortcut('ctrl+7', '', ['FormatBlock', false, '

    ']); + t.addShortcut('ctrl+8', '', ['FormatBlock', false, '

    ']); + t.addShortcut('ctrl+9', '', ['FormatBlock', false, '
    ']); + + function find(e) { + var v = null; + + if (!e.altKey && !e.ctrlKey && !e.metaKey) + return v; + + each(t.shortcuts, function(o) { + if (o.ctrl != e.ctrlKey && (!tinymce.isMac || o.ctrl == e.metaKey)) + return; + + if (o.alt != e.altKey) + return; + + if (o.shift != e.shiftKey) + return; + + if (e.keyCode == o.keyCode || (e.charCode && e.charCode == o.charCode)) { + v = o; + return false; + } + }); + + return v; + }; + + t.onKeyUp.add(function(ed, e) { + var o = find(e); + + if (o) + return Event.cancel(e); + }); + + t.onKeyPress.add(function(ed, e) { + var o = find(e); + + if (o) + return Event.cancel(e); + }); + + t.onKeyDown.add(function(ed, e) { + var o = find(e); + + if (o) { + o.func.call(o.scope); + return Event.cancel(e); + } + }); + } + + if (tinymce.isIE) { + // Fix so resize will only update the width and height attributes not the styles of an image + // It will also block mceItemNoResize items + Event.add(t.getDoc(), 'controlselect', function(e) { + var re = t.resizeInfo, cb; + + e = e.target; + + // Don't do this action for non image elements + if (e.nodeName !== 'IMG') + return; + + if (re) + Event.remove(re.node, re.ev, re.cb); + + if (!t.dom.hasClass(e, 'mceItemNoResize')) { + ev = 'resizeend'; + cb = Event.add(e, ev, function(e) { + var v; + + e = e.target; + + if (v = t.dom.getStyle(e, 'width')) { + t.dom.setAttrib(e, 'width', v.replace(/[^0-9%]+/g, '')); + t.dom.setStyle(e, 'width', ''); + } + + if (v = t.dom.getStyle(e, 'height')) { + t.dom.setAttrib(e, 'height', v.replace(/[^0-9%]+/g, '')); + t.dom.setStyle(e, 'height', ''); + } + }); + } else { + ev = 'resizestart'; + cb = Event.add(e, 'resizestart', Event.cancel, Event); + } + + re = t.resizeInfo = { + node : e, + ev : ev, + cb : cb + }; + }); + + t.onKeyDown.add(function(ed, e) { + switch (e.keyCode) { + case 8: + // Fix IE control + backspace browser bug + if (t.selection.getRng().item) { + t.selection.getRng().item(0).removeNode(); + return Event.cancel(e); + } + } + }); + } + + if (tinymce.isOpera) { + t.onClick.add(function(ed, e) { + Event.prevent(e); + }); + } + + // Add custom undo/redo handlers + if (s.custom_undo_redo) { + function addUndo() { + t.undoManager.typing = 0; + t.undoManager.add(); + }; + + // Add undo level on editor blur + if (tinymce.isIE) { + Event.add(t.getWin(), 'blur', function(e) { + var n; + + // Check added for fullscreen bug + if (t.selection) { + n = t.selection.getNode(); + + // Add undo level is selection was lost to another document + if (!t.removed && n.ownerDocument && n.ownerDocument != t.getDoc()) + addUndo(); + } + }); + } else { + Event.add(t.getDoc(), 'blur', function() { + if (t.selection && !t.removed) + addUndo(); + }); + } + + t.onMouseDown.add(addUndo); + + t.onKeyUp.add(function(ed, e) { + if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45 || e.ctrlKey) { + t.undoManager.typing = 0; + t.undoManager.add(); + } + }); + + t.onKeyDown.add(function(ed, e) { + // Is caracter positon keys + if ((e.keyCode >= 33 && e.keyCode <= 36) || (e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13 || e.keyCode == 45) { + if (t.undoManager.typing) { + t.undoManager.add(); + t.undoManager.typing = 0; + } + + return; + } + + if (!t.undoManager.typing) { + t.undoManager.add(); + t.undoManager.typing = 1; + } + }); + } + }, + + _convertInlineElements : function() { + var t = this, s = t.settings, dom = t.dom, v, e, na, st, sp; + + function convert(ed, o) { + if (!s.inline_styles) + return; + + if (o.get) { + each(t.dom.select('table,u,strike', o.node), function(n) { + switch (n.nodeName) { + case 'TABLE': + if (v = dom.getAttrib(n, 'height')) { + dom.setStyle(n, 'height', v); + dom.setAttrib(n, 'height', ''); + } + break; + + case 'U': + case 'STRIKE': + //sp = dom.create('span', {style : dom.getAttrib(n, 'style')}); + n.style.textDecoration = n.nodeName == 'U' ? 'underline' : 'line-through'; + dom.setAttrib(n, 'mce_style', ''); + dom.setAttrib(n, 'mce_name', 'span'); + break; + } + }); + } else if (o.set) { + each(t.dom.select('table,span', o.node).reverse(), function(n) { + if (n.nodeName == 'TABLE') { + if (v = dom.getStyle(n, 'height')) + dom.setAttrib(n, 'height', v.replace(/[^0-9%]+/g, '')); + } else { + // Convert spans to elements + if (n.style.textDecoration == 'underline') + na = 'u'; + else if (n.style.textDecoration == 'line-through') + na = 'strike'; + else + na = ''; + + if (na) { + n.style.textDecoration = ''; + dom.setAttrib(n, 'mce_style', ''); + + e = dom.create(na, { + style : dom.getAttrib(n, 'style') + }); + + dom.replace(e, n, 1); + } + } + }); + } + }; + + t.onPreProcess.add(convert); + + if (!s.cleanup_on_startup) { + t.onSetContent.add(function(ed, o) { + if (o.initial) + convert(t, {node : t.getBody(), set : 1}); + }); + } + }, + + _convertFonts : function() { + var t = this, s = t.settings, dom = t.dom, fz, fzn, sl, cl; + + // No need + if (!s.inline_styles) + return; + + // Font pt values and font size names + fz = [8, 10, 12, 14, 18, 24, 36]; + fzn = ['xx-small', 'x-small','small','medium','large','x-large', 'xx-large']; + + if (sl = s.font_size_style_values) + sl = explode(sl); + + if (cl = s.font_size_classes) + cl = explode(cl); + + function convertToFonts(no) { + var n, f, nl, x, i, v, st; + + // Convert spans to fonts on non WebKit browsers + if (tinymce.isWebKit || !s.inline_styles) + return; + + nl = t.dom.select('span', no); + for (x = nl.length - 1; x >= 0; x--) { + n = nl[x]; + + f = dom.create('font', { + color : dom.toHex(dom.getStyle(n, 'color')), + face : dom.getStyle(n, 'fontFamily'), + style : dom.getAttrib(n, 'style'), + 'class' : dom.getAttrib(n, 'class') + }); + + // Clear color and font family + st = f.style; + if (st.color || st.fontFamily) { + st.color = st.fontFamily = ''; + dom.setAttrib(f, 'mce_style', ''); // Remove cached style data + } + + if (sl) { + i = inArray(sl, dom.getStyle(n, 'fontSize')); + + if (i != -1) { + dom.setAttrib(f, 'size', '' + (i + 1 || 1)); + f.style.fontSize = ''; + } + } else if (cl) { + i = inArray(cl, dom.getAttrib(n, 'class')); + v = dom.getStyle(n, 'fontSize'); + + if (i == -1 && v.indexOf('pt') > 0) + i = inArray(fz, parseInt(v)); + + if (i == -1) + i = inArray(fzn, v); + + if (i != -1) { + dom.setAttrib(f, 'size', '' + (i + 1 || 1)); + f.style.fontSize = ''; + } + } + + if (f.color || f.face || f.size) { + f.style.fontFamily = ''; + dom.setAttrib(f, 'mce_style', ''); + dom.replace(f, n, 1); + } + + f = n = null; + } + }; + + // Run on setup + t.onSetContent.add(function(ed, o) { + convertToFonts(ed.getBody()); + }); + + // Run on cleanup + t.onPreProcess.add(function(ed, o) { + var n, sp, nl, x; + + // Keep unit tests happy + if (!s.inline_styles) + return; + + if (o.get) { + nl = t.dom.select('font', o.node); + for (x = nl.length - 1; x >= 0; x--) { + n = nl[x]; + + sp = dom.create('span', { + style : dom.getAttrib(n, 'style'), + 'class' : dom.getAttrib(n, 'class') + }); + + dom.setStyles(sp, { + fontFamily : dom.getAttrib(n, 'face'), + color : dom.getAttrib(n, 'color'), + backgroundColor : n.style.backgroundColor + }); + + if (n.size) { + if (sl) + dom.setStyle(sp, 'fontSize', sl[parseInt(n.size) - 1]); + else + dom.setAttrib(sp, 'class', cl[parseInt(n.size) - 1]); + } + + dom.setAttrib(sp, 'mce_style', ''); + dom.replace(sp, n, 1); + } + } + }); + }, + + _isHidden : function() { + var s; + + if (!isGecko) + return 0; + + // Weird, wheres that cursor selection? + s = this.selection.getSel(); + return (!s || !s.rangeCount || s.rangeCount == 0); + }, + + // Fix for bug #1867292 + _fixNesting : function(s) { + var d = [], i; + + s = s.replace(/<(\/)?([^\s>]+)[^>]*?>/g, function(a, b, c) { + var e; + + // Handle end element + if (b === '/') { + if (!d.length) + return ''; + + if (c !== d[d.length - 1].tag) { + for (i=d.length - 1; i>=0; i--) { + if (d[i].tag === c) { + d[i].close = 1; + break; + } + } + + return ''; + } else { + d.pop(); + + if (d.length && d[d.length - 1].close) { + a = a + ''; + d.pop(); + } + } + } else { + // Ignore these + if (/^(br|hr|input|meta|img|link|param)$/i.test(c)) + return a; + + // Ignore closed ones + if (/\/>$/.test(a)) + return a; + + d.push({tag : c}); // Push start element + } + + return a; + }); + + // End all open tags + for (i=d.length - 1; i>=0; i--) + s += ''; + + return s; + } + + }); +})(); + +/* file:jscripts/tiny_mce/classes/EditorCommands.js */ + +(function() { + var each = tinymce.each, isIE = tinymce.isIE, isGecko = tinymce.isGecko, isOpera = tinymce.isOpera, isWebKit = tinymce.isWebKit; + + tinymce.create('tinymce.EditorCommands', { + EditorCommands : function(ed) { + this.editor = ed; + }, + + execCommand : function(cmd, ui, val) { + var t = this, ed = t.editor, f; + + switch (cmd) { + case 'Cut': + case 'Copy': + case 'Paste': + try { + ed.getDoc().execCommand(cmd, ui, val); + } catch (ex) { + if (isGecko) { + ed.windowManager.confirm(ed.getLang('clipboard_msg'), function(s) { + if (s) + window.open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', 'mceExternal'); + }); + } else + ed.windowManager.alert(ed.getLang('clipboard_no_support')); + } + + return true; + + // Ignore these + case 'mceResetDesignMode': + case 'mceBeginUndoLevel': + return true; + + // Ignore these + case 'unlink': + t.UnLink(); + return true; + + // Bundle these together + case 'JustifyLeft': + case 'JustifyCenter': + case 'JustifyRight': + case 'JustifyFull': + t.mceJustify(cmd, cmd.substring(7).toLowerCase()); + return true; + + case 'mceEndUndoLevel': + case 'mceAddUndoLevel': + ed.undoManager.add(); + return true; + + default: + f = this[cmd]; + + if (f) { + f.call(this, ui, val); + return true; + } + } + + return false; + }, + + Indent : function() { + var ed = this.editor, d = ed.dom, s = ed.selection, e, iv, iu; + + // Setup indent level + iv = ed.settings.indentation; + iu = /[a-z%]+$/i.exec(iv); + iv = parseInt(iv); + + if (ed.settings.inline_styles && (!this.queryStateInsertUnorderedList() && !this.queryStateInsertOrderedList())) { + each(this._getSelectedBlocks(), function(e) { + d.setStyle(e, 'paddingLeft', (parseInt(e.style.paddingLeft || 0) + iv) + iu); + }); + + return; + } + + ed.getDoc().execCommand('Indent', false, null); + + if (isIE) { + d.getParent(s.getNode(), function(n) { + if (n.nodeName == 'BLOCKQUOTE') { + n.dir = n.style.cssText = ''; + } + }); + } + }, + + Outdent : function() { + var ed = this.editor, d = ed.dom, s = ed.selection, e, v, iv, iu; + + // Setup indent level + iv = ed.settings.indentation; + iu = /[a-z%]+$/i.exec(iv); + iv = parseInt(iv); + + if (ed.settings.inline_styles && (!this.queryStateInsertUnorderedList() && !this.queryStateInsertOrderedList())) { + each(this._getSelectedBlocks(), function(e) { + v = Math.max(0, parseInt(e.style.paddingLeft || 0) - iv); + d.setStyle(e, 'paddingLeft', v ? v + iu : ''); + }); + + return; + } + + ed.getDoc().execCommand('Outdent', false, null); + }, + + mceSetAttribute : function(u, v) { + var ed = this.editor, d = ed.dom, e; + + if (e = d.getParent(ed.selection.getNode(), d.isBlock)) + d.setAttrib(e, v.name, v.value); + }, + + mceSetContent : function(u, v) { + this.editor.setContent(v); + }, + + mceToggleVisualAid : function() { + var ed = this.editor; + + ed.hasVisual = !ed.hasVisual; + ed.addVisual(); + }, + + mceReplaceContent : function(u, v) { + var s = this.editor.selection; + + s.setContent(v.replace(/\{\$selection\}/g, s.getContent({format : 'text'}))); + }, + + mceInsertLink : function(u, v) { + var ed = this.editor, s = ed.selection, e = ed.dom.getParent(s.getNode(), 'A'); + + if (tinymce.is(v, 'string')) + v = {href : v}; + + function set(e) { + each(v, function(v, k) { + ed.dom.setAttrib(e, k, v); + }); + }; + + if (!e) { + ed.execCommand('CreateLink', false, 'javascript:mctmp(0);'); + each(ed.dom.select('a'), function(e) { + if (e.href == 'javascript:mctmp(0);') + set(e); + }); + } else { + if (v.href) + set(e); + else + ed.dom.remove(e, 1); + } + }, + + UnLink : function() { + var ed = this.editor, s = ed.selection; + + if (s.isCollapsed()) + s.select(s.getNode()); + + ed.getDoc().execCommand('unlink', false, null); + s.collapse(0); + }, + + FontName : function(u, v) { + var t = this, ed = t.editor, s = ed.selection, e; + + if (!v) { + if (s.isCollapsed()) + s.select(s.getNode()); + + t.RemoveFormat(); + } else + ed.getDoc().execCommand('FontName', false, v); + }, + + queryCommandValue : function(c) { + var f = this['queryValue' + c]; + + if (f) + return f.call(this, c); + + return false; + }, + + queryCommandState : function(cmd) { + var f; + + switch (cmd) { + // Bundle these together + case 'JustifyLeft': + case 'JustifyCenter': + case 'JustifyRight': + case 'JustifyFull': + return this.queryStateJustify(cmd, cmd.substring(7).toLowerCase()); + + default: + if (f = this['queryState' + cmd]) + return f.call(this, cmd); + } + + return -1; + }, + + _queryState : function(c) { + try { + return this.editor.getDoc().queryCommandState(c); + } catch (ex) { + // Ignore exception + } + }, + + _queryVal : function(c) { + try { + return this.editor.getDoc().queryCommandValue(c); + } catch (ex) { + // Ignore exception + } + }, + + queryValueFontSize : function() { + var ed = this.editor, v = 0, p; + + if (isOpera || isWebKit) { + if (p = ed.dom.getParent(ed.selection.getNode(), 'FONT')) + v = p.size; + + return v; + } + + return this._queryVal('FontSize'); + }, + + queryValueFontName : function() { + var ed = this.editor, v = 0, p; + + if (p = ed.dom.getParent(ed.selection.getNode(), 'FONT')) + v = p.face; + + if (!v) + v = this._queryVal('FontName'); + + return v; + }, + + mceJustify : function(c, v) { + var ed = this.editor, se = ed.selection, n = se.getNode(), nn = n.nodeName, bl, nb, dom = ed.dom, rm; + + if (ed.settings.inline_styles && this.queryStateJustify(c, v)) + rm = 1; + + bl = dom.getParent(n, ed.dom.isBlock); + + if (nn == 'IMG') { + if (v == 'full') + return; + + if (rm) { + if (v == 'center') + dom.setStyle(n.parentNode, 'textAlign', ''); + + dom.setStyle(n, 'float', ''); + this.mceRepaint(); + return; + } + + if (v == 'center') { + // Do not change table elements + if (/^(TD|TH)$/.test(bl.nodeName)) + bl = 0; + + if (!bl || bl.childNodes.length > 1) { + nb = dom.create('p'); + nb.appendChild(n.cloneNode(false)); + + if (bl) + dom.insertAfter(nb, bl); + else + dom.insertAfter(nb, n); + + dom.remove(n); + n = nb.firstChild; + bl = nb; + } + + dom.setStyle(bl, 'textAlign', v); + dom.setStyle(n, 'float', ''); + } else { + dom.setStyle(n, 'float', v); + dom.setStyle(n.parentNode, 'textAlign', ''); + } + + this.mceRepaint(); + return; + } + + // Handle the alignment outselfs, less quirks in all browsers + if (ed.settings.inline_styles && ed.settings.forced_root_block) { + if (rm) + v = ''; + + each(this._getSelectedBlocks(dom.getParent(se.getStart(), dom.isBlock), dom.getParent(se.getEnd(), dom.isBlock)), function(e) { + dom.setAttrib(e, 'align', ''); + dom.setStyle(e, 'textAlign', v == 'full' ? 'justify' : v); + }); + + return; + } else if (!rm) + ed.getDoc().execCommand(c, false, null); + + if (ed.settings.inline_styles) { + if (rm) { + dom.getParent(ed.selection.getNode(), function(n) { + if (n.style && n.style.textAlign) + dom.setStyle(n, 'textAlign', ''); + }); + + return; + } + + each(dom.select('*'), function(n) { + var v = n.align; + + if (v) { + if (v == 'full') + v = 'justify'; + + dom.setStyle(n, 'textAlign', v); + dom.setAttrib(n, 'align', ''); + } + }); + } + }, + + mceSetCSSClass : function(u, v) { + this.mceSetStyleInfo(0, {command : 'setattrib', name : 'class', value : v}); + }, + + getSelectedElement : function() { + var t = this, ed = t.editor, dom = ed.dom, se = ed.selection, r = se.getRng(), r1, r2, sc, ec, so, eo, e, sp, ep, re; + + if (se.isCollapsed() || r.item) + return se.getNode(); + + // Setup regexp + re = ed.settings.merge_styles_invalid_parents; + if (tinymce.is(re, 'string')) + re = new RegExp(re, 'i'); + + if (isIE) { + r1 = r.duplicate(); + r1.collapse(true); + sc = r1.parentElement(); + + r2 = r.duplicate(); + r2.collapse(false); + ec = r2.parentElement(); + + if (sc != ec) { + r1.move('character', 1); + sc = r1.parentElement(); + } + + if (sc == ec) { + r1 = r.duplicate(); + r1.moveToElementText(sc); + + if (r1.compareEndPoints('StartToStart', r) == 0 && r1.compareEndPoints('EndToEnd', r) == 0) + return re && re.test(sc.nodeName) ? null : sc; + } + } else { + function getParent(n) { + return dom.getParent(n, function(n) {return n.nodeType == 1;}); + }; + + sc = r.startContainer; + ec = r.endContainer; + so = r.startOffset; + eo = r.endOffset; + + if (!r.collapsed) { + if (sc == ec) { + if (so - eo < 2) { + if (sc.hasChildNodes()) { + sp = sc.childNodes[so]; + return re && re.test(sp.nodeName) ? null : sp; + } + } + } + } + + if (sc.nodeType != 3 || ec.nodeType != 3) + return null; + + if (so == 0) { + sp = getParent(sc); + + if (sp && sp.firstChild != sc) + sp = null; + } + + if (so == sc.nodeValue.length) { + e = sc.nextSibling; + + if (e && e.nodeType == 1) + sp = sc.nextSibling; + } + + if (eo == 0) { + e = ec.previousSibling; + + if (e && e.nodeType == 1) + ep = e; + } + + if (eo == ec.nodeValue.length) { + ep = getParent(ec); + + if (ep && ep.lastChild != ec) + ep = null; + } + + // Same element + if (sp == ep) + return re && sp && re.test(sp.nodeName) ? null : sp; + } + + return null; + }, + + InsertHorizontalRule : function() { + // Fix for Gecko
    issue and IE bug rep(/(.*?)<\/a>/gi,"[url=$1]$2[/url]"); + if (isGecko || isIE) + this.editor.selection.setContent('
    '); + else + this.editor.getDoc().execCommand('InsertHorizontalRule', false, ''); + }, + + RemoveFormat : function() { + var t = this, ed = t.editor, s = ed.selection, b; + + // Safari breaks tables + if (isWebKit) + s.setContent(s.getContent({format : 'raw'}).replace(/(<(span|b|i|strong|em|strike) [^>]+>|<(span|b|i|strong|em|strike)>|<\/(span|b|i|strong|em|strike)>|)/g, ''), {format : 'raw'}); + else + ed.getDoc().execCommand('RemoveFormat', false, null); + + t.mceSetStyleInfo(0, {command : 'removeformat'}); + ed.addVisual(); + }, + + mceSetStyleInfo : function(u, v) { + var t = this, ed = t.editor, d = ed.getDoc(), dom = ed.dom, e, b, s = ed.selection, nn = v.wrapper || 'span', b = s.getBookmark(), re; + + function set(n, e) { + if (n.nodeType == 1) { + switch (v.command) { + case 'setattrib': + return dom.setAttrib(n, v.name, v.value); + + case 'setstyle': + return dom.setStyle(n, v.name, v.value); + + case 'removeformat': + return dom.setAttrib(n, 'class', ''); + } + } + }; + + // Setup regexp + re = ed.settings.merge_styles_invalid_parents; + if (tinymce.is(re, 'string')) + re = new RegExp(re, 'i'); + + // Set style info on selected element + if (e = t.getSelectedElement()) + set(e, 1); + else { + // Generate wrappers and set styles on them + d.execCommand('FontName', false, '__'); + each(isWebKit ? dom.select('span') : dom.select('font'), function(n) { + var sp, e; + + if (dom.getAttrib(n, 'face') == '__' || n.style.fontFamily === '__') { + sp = dom.create(nn, {mce_new : '1'}); + + set(sp); + + each (n.childNodes, function(n) { + sp.appendChild(n.cloneNode(true)); + }); + + dom.replace(sp, n); + } + }); + } + + // Remove wrappers inside new ones + each(dom.select(nn).reverse(), function(n) { + var p = n.parentNode; + + // Check if it's an old span in a new wrapper + if (!dom.getAttrib(n, 'mce_new')) { + // Find new wrapper + p = dom.getParent(n, function(n) { + return n.nodeType == 1 && dom.getAttrib(n, 'mce_new'); + }); + + if (p) + dom.remove(n, 1); + } + }); + + // Merge wrappers with parent wrappers + each(dom.select(nn).reverse(), function(n) { + var p = n.parentNode; + + if (!p || !dom.getAttrib(n, 'mce_new')) + return; + + // Has parent of the same type and only child + if (p.nodeName == nn.toUpperCase() && p.childNodes.length == 1) + return dom.remove(p, 1); + + // Has parent that is more suitable to have the class and only child + if (n.nodeType == 1 && (!re || !re.test(p.nodeName)) && p.childNodes.length == 1) { + set(p); // Set style info on parent instead + dom.setAttrib(n, 'class', ''); + } + }); + + // Remove empty wrappers + each(dom.select(nn).reverse(), function(n) { + if (dom.getAttrib(n, 'mce_new') || (dom.getAttribs(n).length <= 1 && n.className === '')) { + if (!dom.getAttrib(n, 'class') && !dom.getAttrib(n, 'style')) + return dom.remove(n, 1); + + dom.setAttrib(n, 'mce_new', ''); // Remove mce_new marker + } + }); + + s.moveToBookmark(b); + }, + + queryStateJustify : function(c, v) { + var ed = this.editor, n = ed.selection.getNode(), dom = ed.dom; + + if (n && n.nodeName == 'IMG') { + if (dom.getStyle(n, 'float') == v) + return 1; + + return n.parentNode.style.textAlign == v; + } + + n = dom.getParent(ed.selection.getStart(), function(n) { + return n.nodeType == 1 && n.style.textAlign; + }); + + if (v == 'full') + v = 'justify'; + + if (ed.settings.inline_styles) + return (n && n.style.textAlign == v); + + return this._queryState(c); + }, + + HiliteColor : function(ui, val) { + var t = this, ed = t.editor, d = ed.getDoc(); + + function set(s) { + if (!isGecko) + return; + + try { + // Try new Gecko method + d.execCommand("styleWithCSS", 0, s); + } catch (ex) { + // Use old + d.execCommand("useCSS", 0, !s); + } + }; + + if (isGecko || isOpera) { + set(true); + d.execCommand('hilitecolor', false, val); + set(false); + } else + d.execCommand('BackColor', false, val); + }, + + Undo : function() { + var ed = this.editor; + + if (ed.settings.custom_undo_redo) { + ed.undoManager.undo(); + ed.nodeChanged(); + } else + ed.getDoc().execCommand('Undo', false, null); + }, + + Redo : function() { + var ed = this.editor; + + if (ed.settings.custom_undo_redo) { + ed.undoManager.redo(); + ed.nodeChanged(); + } else + ed.getDoc().execCommand('Redo', false, null); + }, + + FormatBlock : function(ui, val) { + var t = this, ed = t.editor; + + val = ed.settings.forced_root_block ? (val || '

    ') : val; + + if (/^(P|DIV|H[1-6]|ADDRESS|BLOCKQUOTE|PRE)$/.test(ed.selection.getNode().nodeName)) + t.mceRemoveNode(); + + if (val.indexOf('<') == -1) + val = '<' + val + '>'; + + if (tinymce.isGecko) + val = val.replace(/<(div|blockquote|code|dt|dd|dl|samp)>/gi, '$1'); + + ed.getDoc().execCommand('FormatBlock', false, val); + }, + + mceCleanup : function() { + var ed = this.editor, s = ed.selection, b = s.getBookmark(); + ed.setContent(ed.getContent()); + s.moveToBookmark(b); + }, + + mceRemoveNode : function(ui, val) { + var ed = this.editor, s = ed.selection, b, n = val || s.getNode(); + + // Make sure that the body node isn't removed + if (n == ed.getBody()) + return; + + b = s.getBookmark(); + ed.dom.remove(n, 1); + s.moveToBookmark(b); + ed.nodeChanged(); + }, + + mceSelectNodeDepth : function(ui, val) { + var ed = this.editor, s = ed.selection, c = 0; + + ed.dom.getParent(s.getNode(), function(n) { + if (n.nodeType == 1 && c++ == val) { + s.select(n); + ed.nodeChanged(); + return false; + } + }, ed.getBody()); + }, + + mceSelectNode : function(u, v) { + this.editor.selection.select(v); + }, + + mceInsertContent : function(ui, val) { + this.editor.selection.setContent(val); + }, + + mceInsertRawHTML : function(ui, val) { + var ed = this.editor; + + ed.selection.setContent('tiny_mce_marker'); + ed.setContent(ed.getContent().replace(/tiny_mce_marker/g, val)); + }, + + mceRepaint : function() { + var s, b, e = this.editor; + + if (tinymce.isGecko) { + try { + s = e.selection; + b = s.getBookmark(true); + + if (s.getSel()) + s.getSel().selectAllChildren(e.getBody()); + + s.collapse(true); + s.moveToBookmark(b); + } catch (ex) { + // Ignore + } + } + }, + + queryStateUnderline : function() { + var ed = this.editor, n = ed.selection.getNode(); + + if (n && n.nodeName == 'A') + return false; + + return this._queryState('Underline'); + }, + + queryStateOutdent : function() { + var ed = this.editor, n; + + if (ed.settings.inline_styles) { + if ((n = ed.dom.getParent(ed.selection.getStart(), ed.dom.isBlock)) && parseInt(n.style.paddingLeft) > 0) + return true; + + if ((n = ed.dom.getParent(ed.selection.getEnd(), ed.dom.isBlock)) && parseInt(n.style.paddingLeft) > 0) + return true; + } else + return !!ed.dom.getParent(ed.selection.getNode(), 'BLOCKQUOTE'); + + return this.queryStateInsertUnorderedList() || this.queryStateInsertOrderedList(); + }, + + queryStateInsertUnorderedList : function() { + return this.editor.dom.getParent(this.editor.selection.getNode(), 'UL'); + }, + + queryStateInsertOrderedList : function() { + return this.editor.dom.getParent(this.editor.selection.getNode(), 'OL'); + }, + + queryStatemceBlockQuote : function() { + return !!this.editor.dom.getParent(this.editor.selection.getStart(), function(n) {return n.nodeName === 'BLOCKQUOTE';}); + }, + + mceBlockQuote : function() { + var t = this, ed = t.editor, s = ed.selection, dom = ed.dom, sb, eb, n, bm, bq, r, bq2, i, nl; + + function getBQ(e) { + return dom.getParent(e, function(n) {return n.nodeName === 'BLOCKQUOTE';}); + }; + + // Get start/end block + sb = dom.getParent(s.getStart(), dom.isBlock); + eb = dom.getParent(s.getEnd(), dom.isBlock); + + // Remove blockquote(s) + if (bq = getBQ(sb)) { + if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR')) + bm = s.getBookmark(); + + // Move all elements after the end block into new bq + if (getBQ(eb)) { + bq2 = bq.cloneNode(false); + + while (n = eb.nextSibling) + bq2.appendChild(n.parentNode.removeChild(n)); + } + + // Add new bq after + if (bq2) + dom.insertAfter(bq2, bq); + + // Move all selected blocks after the current bq + nl = t._getSelectedBlocks(sb, eb); + for (i = nl.length - 1; i >= 0; i--) { + dom.insertAfter(nl[i], bq); + } + + // Empty bq, then remove it + if (/^\s*$/.test(bq.innerHTML)) + dom.remove(bq, 1); // Keep children so boomark restoration works correctly + + // Empty bq, then remote it + if (bq2 && /^\s*$/.test(bq2.innerHTML)) + dom.remove(bq2, 1); // Keep children so boomark restoration works correctly + + if (!bm) { + // Move caret inside empty block element + if (!isIE) { + r = ed.getDoc().createRange(); + r.setStart(sb, 0); + r.setEnd(sb, 0); + s.setRng(r); + } else { + s.select(sb); + s.collapse(0); + + // IE misses the empty block some times element so we must move back the caret + if (dom.getParent(s.getStart(), dom.isBlock) != sb) { + r = s.getRng(); + r.move('character', -1); + r.select(); + } + } + } else + t.editor.selection.moveToBookmark(bm); + + return; + } + + // Since IE can start with a totally empty document we need to add the first bq and paragraph + if (isIE && !sb && !eb) { + t.editor.getDoc().execCommand('Indent'); + n = getBQ(s.getNode()); + n.style.margin = n.dir = ''; // IE adds margin and dir to bq + return; + } + + if (!sb || !eb) + return; + + // If empty paragraph node then do not use bookmark + if (sb != eb || sb.childNodes.length > 1 || (sb.childNodes.length == 1 && sb.firstChild.nodeName != 'BR')) + bm = s.getBookmark(); + + // Move selected block elements into a bq + each(t._getSelectedBlocks(getBQ(s.getStart()), getBQ(s.getEnd())), function(e) { + // Found existing BQ add to this one + if (e.nodeName == 'BLOCKQUOTE' && !bq) { + bq = e; + return; + } + + // No BQ found, create one + if (!bq) { + bq = dom.create('blockquote'); + e.parentNode.insertBefore(bq, e); + } + + // Add children from existing BQ + if (e.nodeName == 'BLOCKQUOTE' && bq) { + n = e.firstChild; + + while (n) { + bq.appendChild(n.cloneNode(true)); + n = n.nextSibling; + } + + dom.remove(e); + return; + } + + // Add non BQ element to BQ + bq.appendChild(dom.remove(e)); + }); + + if (!bm) { + // Move caret inside empty block element + if (!isIE) { + r = ed.getDoc().createRange(); + r.setStart(sb, 0); + r.setEnd(sb, 0); + s.setRng(r); + } else { + s.select(sb); + s.collapse(1); + } + } else + s.moveToBookmark(bm); + }, +/* + _mceBlockQuote : function() { + var t = this, s = t.editor.selection, b = s.getBookmark(), bq, dom = t.editor.dom; + + function findBQ(e) { + return dom.getParent(e, function(n) {return n.nodeName === 'BLOCKQUOTE';}); + }; + + // Remove blockquote(s) + if (findBQ(s.getStart())) { + each(t._getSelectedBlocks(findBQ(s.getStart()), findBQ(s.getEnd())), function(e) { + // Found BQ lets remove it + if (e.nodeName == 'BLOCKQUOTE') + dom.remove(e, 1); + }); + + t.editor.selection.moveToBookmark(b); + return; + } + + each(t._getSelectedBlocks(findBQ(s.getStart()), findBQ(s.getEnd())), function(e) { + var n; + + // Found existing BQ add to this one + if (e.nodeName == 'BLOCKQUOTE' && !bq) { + bq = e; + return; + } + + // No BQ found, create one + if (!bq) { + bq = dom.create('blockquote'); + e.parentNode.insertBefore(bq, e); + } + + // Add children from existing BQ + if (e.nodeName == 'BLOCKQUOTE' && bq) { + n = e.firstChild; + + while (n) { + bq.appendChild(n.cloneNode(true)); + n = n.nextSibling; + } + + dom.remove(e); + + return; + } + + // Add non BQ element to BQ + bq.appendChild(dom.remove(e)); + }); + + t.editor.selection.moveToBookmark(b); + }, +*/ + _getSelectedBlocks : function(st, en) { + var ed = this.editor, dom = ed.dom, s = ed.selection, sb, eb, n, bl = []; + + sb = dom.getParent(st || s.getStart(), dom.isBlock); + eb = dom.getParent(en || s.getEnd(), dom.isBlock); + + if (sb) + bl.push(sb); + + if (sb && eb && sb != eb) { + n = sb; + + while ((n = n.nextSibling) && n != eb) { + if (dom.isBlock(n)) + bl.push(n); + } + } + + if (eb && sb != eb) + bl.push(eb); + + return bl; + } + }); +})(); + + +/* file:jscripts/tiny_mce/classes/UndoManager.js */ + +tinymce.create('tinymce.UndoManager', { + index : 0, + data : null, + typing : 0, + + UndoManager : function(ed) { + var t = this, Dispatcher = tinymce.util.Dispatcher; + + t.editor = ed; + t.data = []; + t.onAdd = new Dispatcher(this); + t.onUndo = new Dispatcher(this); + t.onRedo = new Dispatcher(this); + }, + + add : function(l) { + var t = this, i, ed = t.editor, b, s = ed.settings, la; + + l = l || {}; + l.content = l.content || ed.getContent({format : 'raw', no_events : 1}); + + // Add undo level if needed + l.content = l.content.replace(/^\s*|\s*$/g, ''); + la = t.data[t.index > 0 ? t.index - 1 : 0]; + if (!l.initial && la && l.content == la.content) + return null; + + // Time to compress + if (s.custom_undo_redo_levels) { + if (t.data.length > s.custom_undo_redo_levels) { + for (i = 0; i < t.data.length - 1; i++) + t.data[i] = t.data[i + 1]; + + t.data.length--; + t.index = t.data.length; + } + } + + if (s.custom_undo_redo_restore_selection && !l.initial) + l.bookmark = b = l.bookmark || ed.selection.getBookmark(); + + if (t.index < t.data.length && t.data[t.index].initial) + t.index++; + + // Only initial marked undo levels should be allowed as first item + // This to workaround a bug with Firefox and the blur event + if (t.data.length === 0 && !l.initial) + return null; + + // Add level + t.data.length = t.index + 1; + t.data[t.index++] = l; + + if (l.initial) + t.index = 0; + + // Set initial bookmark use first real undo level + if (t.data.length == 2 && t.data[0].initial) + t.data[0].bookmark = b; + + t.onAdd.dispatch(t, l); + ed.isNotDirty = 0; + + //console.dir(t.data); + + return l; + }, + + undo : function() { + var t = this, ed = t.editor, l = l, i; + + if (t.typing) { + t.add(); + t.typing = 0; + } + + if (t.index > 0) { + // If undo on last index then take snapshot + if (t.index == t.data.length && t.index > 1) { + i = t.index; + t.typing = 0; + + if (!t.add()) + t.index = i; + + --t.index; + } + + l = t.data[--t.index]; + ed.setContent(l.content, {format : 'raw'}); + ed.selection.moveToBookmark(l.bookmark); + + t.onUndo.dispatch(t, l); + } + + return l; + }, + + redo : function() { + var t = this, ed = t.editor, l = null; + + if (t.index < t.data.length - 1) { + l = t.data[++t.index]; + ed.setContent(l.content, {format : 'raw'}); + ed.selection.moveToBookmark(l.bookmark); + + t.onRedo.dispatch(t, l); + } + + return l; + }, + + clear : function() { + var t = this; + + t.data = []; + t.index = 0; + t.typing = 0; + t.add({initial : true}); + }, + + hasUndo : function() { + return this.index != 0 || this.typing; + }, + + hasRedo : function() { + return this.index < this.data.length - 1; + } + + }); +/* file:jscripts/tiny_mce/classes/ForceBlocks.js */ + +(function() { + // Shorten names + var Event, isIE, isGecko, isOpera, each, extend; + + Event = tinymce.dom.Event; + isIE = tinymce.isIE; + isGecko = tinymce.isGecko; + isOpera = tinymce.isOpera; + each = tinymce.each; + extend = tinymce.extend; + + tinymce.create('tinymce.ForceBlocks', { + ForceBlocks : function(ed) { + var t = this, s = ed.settings, elm; + + t.editor = ed; + t.dom = ed.dom; + elm = (s.forced_root_block || 'p').toLowerCase(); + s.element = elm.toUpperCase(); + + ed.onPreInit.add(t.setup, t); + + t.reOpera = new RegExp('(\\u00a0| | )<\/' + elm + '>', 'gi'); + t.rePadd = new RegExp(']+)><\\\/p>|]+)\\\/>|]+)>\\s+<\\\/p>|

    <\\\/p>||

    \\s+<\\\/p>'.replace(/p/g, elm), 'gi'); + t.reNbsp2BR1 = new RegExp(']+)>[\\s\\u00a0]+<\\\/p>|

    [\\s\\u00a0]+<\\\/p>'.replace(/p/g, elm), 'gi'); + t.reNbsp2BR2 = new RegExp(']+)>( | )<\\\/p>|

    ( | )<\\\/p>'.replace(/p/g, elm), 'gi'); + t.reBR2Nbsp = new RegExp(']+)>\\s*
    \\s*<\\\/p>|

    \\s*
    \\s*<\\\/p>'.replace(/p/g, elm), 'gi'); + t.reTrailBr = new RegExp('\\s*
    \\s*<\\\/p>'.replace(/p/g, elm), 'gi'); + + function padd(ed, o) { + if (isOpera) + o.content = o.content.replace(t.reOpera, ''); + + o.content = o.content.replace(t.rePadd, '<' + elm + '$1$2$3$4$5$6>\u00a0'); + + if (!isIE && !isOpera && o.set) { + // Use   instead of BR in padded paragraphs + o.content = o.content.replace(t.reNbsp2BR1, '<' + elm + '$1$2>
    '); + o.content = o.content.replace(t.reNbsp2BR2, '<' + elm + '$1$2>
    '); + } else { + o.content = o.content.replace(t.reBR2Nbsp, '<' + elm + '$1$2>\u00a0'); + o.content = o.content.replace(t.reTrailBr, ''); + } + }; + + ed.onBeforeSetContent.add(padd); + ed.onPostProcess.add(padd); + + if (s.forced_root_block) { + ed.onInit.add(t.forceRoots, t); + ed.onSetContent.add(t.forceRoots, t); + ed.onBeforeGetContent.add(t.forceRoots, t); + } + }, + + setup : function() { + var t = this, ed = t.editor, s = ed.settings; + + // Force root blocks when typing and when getting output + if (s.forced_root_block) { + ed.onKeyUp.add(t.forceRoots, t); + ed.onPreProcess.add(t.forceRoots, t); + } + + if (s.force_br_newlines) { + // Force IE to produce BRs on enter + if (isIE) { + ed.onKeyPress.add(function(ed, e) { + var n, s = ed.selection; + + if (e.keyCode == 13 && s.getNode().nodeName != 'LI') { + s.setContent('
    ', {format : 'raw'}); + n = ed.dom.get('__'); + n.removeAttribute('id'); + s.select(n); + s.collapse(); + return Event.cancel(e); + } + }); + } + + return; + } + + if (!isIE && s.force_p_newlines) { +/* ed.onPreProcess.add(function(ed, o) { + each(ed.dom.select('br', o.node), function(n) { + var p = n.parentNode; + + // Replace


    with

     

    + if (p && p.nodeName == 'p' && (p.childNodes.length == 1 || p.lastChild == n)) { + p.replaceChild(ed.getDoc().createTextNode('\u00a0'), n); + } + }); + });*/ + + ed.onKeyPress.add(function(ed, e) { + if (e.keyCode == 13 && !e.shiftKey) { + if (!t.insertPara(e)) + Event.cancel(e); + } + }); + + if (isGecko) { + ed.onKeyDown.add(function(ed, e) { + if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey) + t.backspaceDelete(e, e.keyCode == 8); + }); + } + } + + function ren(rn, na) { + var ne = ed.dom.create(na); + + each(rn.attributes, function(a) { + if (a.specified && a.nodeValue) + ne.setAttribute(a.nodeName.toLowerCase(), a.nodeValue); + }); + + each(rn.childNodes, function(n) { + ne.appendChild(n.cloneNode(true)); + }); + + rn.parentNode.replaceChild(ne, rn); + + return ne; + }; + + // Replaces IE:s auto generated paragraphs with the specified element name + if (isIE && s.element != 'P') { + ed.onKeyPress.add(function(ed, e) { + t.lastElm = ed.selection.getNode().nodeName; + }); + + ed.onKeyUp.add(function(ed, e) { + var bl, sel = ed.selection, n = sel.getNode(), b = ed.getBody(); + + if (b.childNodes.length === 1 && n.nodeName == 'P') { + n = ren(n, s.element); + sel.select(n); + sel.collapse(); + ed.nodeChanged(); + } else if (e.keyCode == 13 && !e.shiftKey && t.lastElm != 'P') { + bl = ed.dom.getParent(n, 'P'); + + if (bl) { + ren(bl, s.element); + ed.nodeChanged(); + } + } + }); + } + }, + + find : function(n, t, s) { + var ed = this.editor, w = ed.getDoc().createTreeWalker(n, 4, null, false), c = -1; + + while (n = w.nextNode()) { + c++; + + // Index by node + if (t == 0 && n == s) + return c; + + // Node by index + if (t == 1 && c == s) + return n; + } + + return -1; + }, + + forceRoots : function(ed, e) { + var t = this, ed = t.editor, b = ed.getBody(), d = ed.getDoc(), se = ed.selection, s = se.getSel(), r = se.getRng(), si = -2, ei, so, eo, tr, c = -0xFFFFFF; + var nx, bl, bp, sp, le, nl = b.childNodes, i; + + // Fix for bug #1863847 + if (e && e.keyCode == 13) + return true; + + // Wrap non blocks into blocks + for (i = nl.length - 1; i >= 0; i--) { + nx = nl[i]; + + // Is text or non block element + if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8)) { + if (!bl) { + // Create new block but ignore whitespace + if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) { + // Store selection + if (si == -2 && r) { + if (!isIE) { + so = r.startOffset; + eo = r.endOffset; + si = t.find(b, 0, r.startContainer); + ei = t.find(b, 0, r.endContainer); + } else { + tr = d.body.createTextRange(); + tr.moveToElementText(b); + tr.collapse(1); + bp = tr.move('character', c) * -1; + + tr = r.duplicate(); + tr.collapse(1); + sp = tr.move('character', c) * -1; + + tr = r.duplicate(); + tr.collapse(0); + le = (tr.move('character', c) * -1) - sp; + + si = sp - bp; + ei = le; + } + } + + bl = ed.dom.create(ed.settings.forced_root_block); + bl.appendChild(nx.cloneNode(1)); + nx.parentNode.replaceChild(bl, nx); + } + } else { + if (bl.hasChildNodes()) + bl.insertBefore(nx, bl.firstChild); + else + bl.appendChild(nx); + } + } else + bl = null; // Time to create new block + } + + // Restore selection + if (si != -2) { + if (!isIE) { + bl = d.getElementsByTagName(ed.settings.element)[0]; + r = d.createRange(); + + // Select last location or generated block + if (si != -1) + r.setStart(t.find(b, 1, si), so); + else + r.setStart(bl, 0); + + // Select last location or generated block + if (ei != -1) + r.setEnd(t.find(b, 1, ei), eo); + else + r.setEnd(bl, 0); + + if (s) { + s.removeAllRanges(); + s.addRange(r); + } + } else { + try { + r = s.createRange(); + r.moveToElementText(b); + r.collapse(1); + r.moveStart('character', si); + r.moveEnd('character', ei); + r.select(); + } catch (ex) { + // Ignore + } + } + } + }, + + getParentBlock : function(n) { + var d = this.dom; + + return d.getParent(n, d.isBlock); + }, + + insertPara : function(e) { + var t = this, ed = t.editor, dom = ed.dom, d = ed.getDoc(), se = ed.settings, s = ed.selection.getSel(), r = s.getRangeAt(0), b = d.body; + var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n, vp = dom.getViewPort(ed.getWin()), y, ch; + + function isEmpty(n) { + n = n.innerHTML; + n = n.replace(/<(img|hr|table)/gi, '-'); // Keep these convert them to - chars + n = n.replace(/<[^>]+>/g, ''); // Remove all tags + + return n.replace(/[ \t\r\n]+/g, '') == ''; + }; + + // If root blocks are forced then use Operas default behavior since it's really good +// Removed due to bug: #1853816 +// if (se.forced_root_block && isOpera) +// return true; + + // Setup before range + rb = d.createRange(); + + // If is before the first block element and in body, then move it into first block element + rb.setStart(s.anchorNode, s.anchorOffset); + rb.collapse(true); + + // Setup after range + ra = d.createRange(); + + // If is before the first block element and in body, then move it into first block element + ra.setStart(s.focusNode, s.focusOffset); + ra.collapse(true); + + // Setup start/end points + dir = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0; + sn = dir ? s.anchorNode : s.focusNode; + so = dir ? s.anchorOffset : s.focusOffset; + en = dir ? s.focusNode : s.anchorNode; + eo = dir ? s.focusOffset : s.anchorOffset; + + // If selection is in empty table cell + if (sn === en && /^(TD|TH)$/.test(sn.nodeName)) { + dom.remove(sn.firstChild); // Remove BR + + // Create two new block elements + ed.dom.add(sn, se.element, null, '
    '); + aft = ed.dom.add(sn, se.element, null, '
    '); + + // Move caret into the last one + r = d.createRange(); + r.selectNodeContents(aft); + r.collapse(1); + ed.selection.setRng(r); + + return false; + } + + // If the caret is in an invalid location in FF we need to move it into the first block + if (sn == b && en == b && b.firstChild && ed.dom.isBlock(b.firstChild)) { + sn = en = sn.firstChild; + so = eo = 0; + rb = d.createRange(); + rb.setStart(sn, 0); + ra = d.createRange(); + ra.setStart(en, 0); + } + + // Never use body as start or end node + sn = sn.nodeName == "HTML" ? d.body : sn; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes + sn = sn.nodeName == "BODY" ? sn.firstChild : sn; + en = en.nodeName == "HTML" ? d.body : en; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes + en = en.nodeName == "BODY" ? en.firstChild : en; + + // Get start and end blocks + sb = t.getParentBlock(sn); + eb = t.getParentBlock(en); + bn = sb ? sb.nodeName : se.element; // Get block name to create + + // Return inside list use default browser behavior + if (t.dom.getParent(sb, function(n) { return /OL|UL|PRE/.test(n.nodeName); })) + return true; + + // If caption or absolute layers then always generate new blocks within + if (sb && (sb.nodeName == 'CAPTION' || /absolute|relative|static/gi.test(sb.style.position))) { + bn = se.element; + sb = null; + } + + // If caption or absolute layers then always generate new blocks within + if (eb && (eb.nodeName == 'CAPTION' || /absolute|relative|static/gi.test(eb.style.position))) { + bn = se.element; + eb = null; + } + + // Use P instead + if (/(TD|TABLE|TH|CAPTION)/.test(bn) || (sb && bn == "DIV" && /left|right/gi.test(sb.style.cssFloat))) { + bn = se.element; + sb = eb = null; + } + + // Setup new before and after blocks + bef = (sb && sb.nodeName == bn) ? sb.cloneNode(0) : ed.dom.create(bn); + aft = (eb && eb.nodeName == bn) ? eb.cloneNode(0) : ed.dom.create(bn); + + // Remove id from after clone + aft.removeAttribute('id'); + + // Is header and cursor is at the end, then force paragraph under + if (/^(H[1-6])$/.test(bn) && sn.nodeValue && so == sn.nodeValue.length) + aft = ed.dom.create(se.element); + + // Find start chop node + n = sc = sn; + do { + if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName)) + break; + + sc = n; + } while ((n = n.previousSibling ? n.previousSibling : n.parentNode)); + + // Find end chop node + n = ec = en; + do { + if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName)) + break; + + ec = n; + } while ((n = n.nextSibling ? n.nextSibling : n.parentNode)); + + // Place first chop part into before block element + if (sc.nodeName == bn) + rb.setStart(sc, 0); + else + rb.setStartBefore(sc); + + rb.setEnd(sn, so); + bef.appendChild(rb.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari + + // Place secnd chop part within new block element + try { + ra.setEndAfter(ec); + } catch(ex) { + //console.debug(s.focusNode, s.focusOffset); + } + + ra.setStart(en, eo); + aft.appendChild(ra.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari + + // Create range around everything + r = d.createRange(); + if (!sc.previousSibling && sc.parentNode.nodeName == bn) { + r.setStartBefore(sc.parentNode); + } else { + if (rb.startContainer.nodeName == bn && rb.startOffset == 0) + r.setStartBefore(rb.startContainer); + else + r.setStart(rb.startContainer, rb.startOffset); + } + + if (!ec.nextSibling && ec.parentNode.nodeName == bn) + r.setEndAfter(ec.parentNode); + else + r.setEnd(ra.endContainer, ra.endOffset); + + // Delete and replace it with new block elements + r.deleteContents(); + + if (isOpera) + ed.getWin().scrollTo(0, vp.y); + + // Never wrap blocks in blocks + if (bef.firstChild && bef.firstChild.nodeName == bn) + bef.innerHTML = bef.firstChild.innerHTML; + + if (aft.firstChild && aft.firstChild.nodeName == bn) + aft.innerHTML = aft.firstChild.innerHTML; + + // Padd empty blocks + if (isEmpty(bef)) + bef.innerHTML = '
    '; + + if (isEmpty(aft)) + aft.innerHTML = isOpera ? ' ' : '
    '; // Extra space for Opera so that the caret can move there + + // Opera needs this one backwards + if (isOpera) { + r.insertNode(bef); + r.insertNode(aft); + } else { + r.insertNode(aft); + r.insertNode(bef); + } + + // Normalize + aft.normalize(); + bef.normalize(); + + // Move cursor and scroll into view + r = d.createRange(); + r.selectNodeContents(aft); + r.collapse(1); + s.removeAllRanges(); + s.addRange(r); + + // scrollIntoView seems to scroll the parent window in most browsers now including FF 3.0b4 so it's time to stop using it and do it our selfs + y = ed.dom.getPos(aft).y; + ch = aft.clientHeight; + + // Is element within viewport + if (y < vp.y || y + ch > vp.y + vp.h) { + ed.getWin().scrollTo(0, y < vp.y ? y : y - vp.h + ch); + //console.debug('SCROLL!', 'vp.y: ' + vp.y, 'y' + y, 'vp.h' + vp.h, 'clientHeight' + aft.clientHeight, 'yyy: ' + (y < vp.y ? y : y - vp.h + aft.clientHeight)); + } + + return false; + }, + + backspaceDelete : function(e, bs) { + var t = this, ed = t.editor, b = ed.getBody(), n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn; + + // The caret sometimes gets stuck in Gecko if you delete empty paragraphs + // This workaround removes the element by hand and moves the caret to the previous element + if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) { + if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) { + // Find previous block element + n = sc; + while ((n = n.previousSibling) && !ed.dom.isBlock(n)) ; + + if (n) { + if (sc != b.firstChild) { + // Find last text node + w = ed.dom.doc.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false); + while (tn = w.nextNode()) + n = tn; + + // Place caret at the end of last text node + r = ed.getDoc().createRange(); + r.setStart(n, n.nodeValue ? n.nodeValue.length : 0); + r.setEnd(n, n.nodeValue ? n.nodeValue.length : 0); + se.setRng(r); + + // Remove the target container + ed.dom.remove(sc); + } + + return Event.cancel(e); + } + } + } + + // Gecko generates BR elements here and there, we don't like those so lets remove them + function handler(e) { + e = e.target; + + // A new BR was created in a block element, remove it + if (e && e.parentNode && e.nodeName == 'BR' && (n = t.getParentBlock(e))) { + Event.remove(b, 'DOMNodeInserted', handler); + + // Only remove BR elements that got inserted in the middle of the text + if (e.previousSibling || e.nextSibling) + ed.dom.remove(e); + } + }; + + // Listen for new nodes + Event._add(b, 'DOMNodeInserted', handler); + + // Remove listener + window.setTimeout(function() { + Event._remove(b, 'DOMNodeInserted', handler); + }, 1); + } + }); +})(); + +/* file:jscripts/tiny_mce/classes/ControlManager.js */ + +(function() { + // Shorten names + var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, extend = tinymce.extend; + + tinymce.create('tinymce.ControlManager', { + ControlManager : function(ed, s) { + var t = this, i; + + s = s || {}; + t.editor = ed; + t.controls = {}; + t.onAdd = new tinymce.util.Dispatcher(t); + t.onPostRender = new tinymce.util.Dispatcher(t); + t.prefix = s.prefix || ed.id + '_'; + t._cls = {}; + + t.onPostRender.add(function() { + each(t.controls, function(c) { + c.postRender(); + }); + }); + }, + + get : function(id) { + return this.controls[this.prefix + id] || this.controls[id]; + }, + + setActive : function(id, s) { + var c = null; + + if (c = this.get(id)) + c.setActive(s); + + return c; + }, + + setDisabled : function(id, s) { + var c = null; + + if (c = this.get(id)) + c.setDisabled(s); + + return c; + }, + + add : function(c) { + var t = this; + + if (c) { + t.controls[c.id] = c; + t.onAdd.dispatch(c, t); + } + + return c; + }, + + createControl : function(n) { + var c, t = this, ed = t.editor; + + each(ed.plugins, function(p) { + if (p.createControl) { + c = p.createControl(n, t); + + if (c) + return false; + } + }); + + switch (n) { + case "|": + case "separator": + return t.createSeparator(); + } + + if (!c && ed.buttons && (c = ed.buttons[n])) + return t.createButton(n, c); + + return t.add(c); + }, + + createDropMenu : function(id, s, cc) { + var t = this, ed = t.editor, c, bm, v, cls; + + s = extend({ + 'class' : 'mceDropDown', + constrain : ed.settings.constrain_menus + }, s); + + s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin'; + if (v = ed.getParam('skin_variant')) + s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1); + + id = t.prefix + id; + cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu; + c = t.controls[id] = new cls(id, s); + c.onAddItem.add(function(c, o) { + var s = o.settings; + + s.title = ed.getLang(s.title, s.title); + + if (!s.onclick) { + s.onclick = function(v) { + ed.execCommand(s.cmd, s.ui || false, s.value); + }; + } + }); + + ed.onRemove.add(function() { + c.destroy(); + }); + + // Fix for bug #1897785, #1898007 + if (tinymce.isIE) { + c.onShowMenu.add(function() { + var s = ed.selection, n = s.getNode(); + + if (n.nodeName == 'IMG') + bm = s.getBookmark(); + else + bm = 0; + }); + + c.onHideMenu.add(function() { + if (bm) + ed.selection.moveToBookmark(bm); + }); + } + + return t.add(c); + }, + + createListBox : function(id, s, cc) { + var t = this, ed = t.editor, cmd, c, cls; + + if (t.get(id)) + return null; + + s.title = ed.translate(s.title); + s.scope = s.scope || ed; + + if (!s.onselect) { + s.onselect = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + s = extend({ + title : s.title, + 'class' : 'mce_' + id, + scope : s.scope, + control_manager : t + }, s); + + id = t.prefix + id; + + if (ed.settings.use_native_selects) + c = new tinymce.ui.NativeListBox(id, s); + else { + cls = cc || t._cls.listbox || tinymce.ui.ListBox; + c = new cls(id, s); + } + + t.controls[id] = c; + + // Fix focus problem in Safari + if (tinymce.isWebKit) { + c.onPostRender.add(function(c, n) { + // Store bookmark on mousedown + Event.add(n, 'mousedown', function() { + ed.bookmark = ed.selection.getBookmark('simple'); + }); + + // Restore on focus, since it might be lost + Event.add(n, 'focus', function() { + ed.selection.moveToBookmark(ed.bookmark); + ed.bookmark = null; + }); + }); + } + + if (c.hideMenu) + ed.onMouseDown.add(c.hideMenu, c); + + return t.add(c); + }, + + createButton : function(id, s, cc) { + var t = this, ed = t.editor, o, c, cls; + + if (t.get(id)) + return null; + + s.title = ed.translate(s.title); + s.label = ed.translate(s.label); + s.scope = s.scope || ed; + + if (!s.onclick && !s.menu_button) { + s.onclick = function() { + ed.execCommand(s.cmd, s.ui || false, s.value); + }; + } + + s = extend({ + title : s.title, + 'class' : 'mce_' + id, + unavailable_prefix : ed.getLang('unavailable', ''), + scope : s.scope, + control_manager : t + }, s); + + id = t.prefix + id; + + if (s.menu_button) { + cls = cc || t._cls.menubutton || tinymce.ui.MenuButton; + c = new cls(id, s); + ed.onMouseDown.add(c.hideMenu, c); + } else { + cls = t._cls.button || tinymce.ui.Button; + c = new cls(id, s); + } + + return t.add(c); + }, + + createMenuButton : function(id, s) { + s = s || {}; + s.menu_button = 1; + + return this.createButton(id, s); + }, + + createSplitButton : function(id, s, cc) { + var t = this, ed = t.editor, cmd, c, cls; + + if (t.get(id)) + return null; + + s.title = ed.translate(s.title); + s.scope = s.scope || ed; + + if (!s.onclick) { + s.onclick = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + if (!s.onselect) { + s.onselect = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + s = extend({ + title : s.title, + 'class' : 'mce_' + id, + scope : s.scope, + control_manager : t + }, s); + + id = t.prefix + id; + cls = cc || t._cls.splitbutton || tinymce.ui.SplitButton; + c = t.add(new cls(id, s)); + ed.onMouseDown.add(c.hideMenu, c); + + return c; + }, + + createColorSplitButton : function(id, s, cc) { + var t = this, ed = t.editor, cmd, c, cls; + + if (t.get(id)) + return null; + + s.title = ed.translate(s.title); + s.scope = s.scope || ed; + + if (!s.onclick) { + s.onclick = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + if (!s.onselect) { + s.onselect = function(v) { + ed.execCommand(s.cmd, s.ui || false, v || s.value); + }; + } + + s = extend({ + title : s.title, + 'class' : 'mce_' + id, + 'menu_class' : ed.getParam('skin') + 'Skin', + scope : s.scope, + more_colors_title : ed.getLang('more_colors') + }, s); + + id = t.prefix + id; + cls = cc || t._cls.colorsplitbutton || tinymce.ui.ColorSplitButton; + c = new cls(id, s); + ed.onMouseDown.add(c.hideMenu, c); + + // Remove the menu element when the editor is removed + ed.onRemove.add(function() { + c.destroy(); + }); + + return t.add(c); + }, + + createToolbar : function(id, s, cc) { + var c, t = this, cls; + + id = t.prefix + id; + cls = cc || t._cls.toolbar || tinymce.ui.Toolbar; + c = new cls(id, s); + + if (t.get(id)) + return null; + + return t.add(c); + }, + + createSeparator : function(cc) { + var cls = cc || this._cls.separator || tinymce.ui.Separator; + + return new cls(); + }, + + setControlType : function(n, c) { + return this._cls[n.toLowerCase()] = c; + }, + + destroy : function() { + each(this.controls, function(c) { + c.destroy(); + }); + + this.controls = null; + } + + }); +})(); + +/* file:jscripts/tiny_mce/classes/WindowManager.js */ + +(function() { + var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera; + + tinymce.create('tinymce.WindowManager', { + WindowManager : function(ed) { + var t = this; + + t.editor = ed; + t.onOpen = new Dispatcher(t); + t.onClose = new Dispatcher(t); + t.params = {}; + t.features = {}; + }, + + open : function(s, p) { + var t = this, f = '', x, y, mo = t.editor.settings.dialog_type == 'modal', w, sw, sh, vp = tinymce.DOM.getViewPort(), u; + + // Default some options + s = s || {}; + p = p || {}; + sw = isOpera ? vp.w : screen.width; // Opera uses windows inside the Opera window + sh = isOpera ? vp.h : screen.height; + s.name = s.name || 'mc_' + new Date().getTime(); + s.width = parseInt(s.width || 320); + s.height = parseInt(s.height || 240); + s.resizable = true; + s.left = s.left || parseInt(sw / 2.0) - (s.width / 2.0); + s.top = s.top || parseInt(sh / 2.0) - (s.height / 2.0); + p.inline = false; + p.mce_width = s.width; + p.mce_height = s.height; + p.mce_auto_focus = s.auto_focus; + + if (mo) { + if (isIE) { + s.center = true; + s.help = false; + s.dialogWidth = s.width + 'px'; + s.dialogHeight = s.height + 'px'; + s.scroll = s.scrollbars || false; + } else + s.modal = s.alwaysRaised = s.dialog = s.centerscreen = s.dependent = true; + } + + // Build features string + each(s, function(v, k) { + if (tinymce.is(v, 'boolean')) + v = v ? 'yes' : 'no'; + + if (!/^(name|url)$/.test(k)) { + if (isIE && mo) + f += (f ? ';' : '') + k + ':' + v; + else + f += (f ? ',' : '') + k + '=' + v; + } + }); + + t.features = s; + t.params = p; + t.onOpen.dispatch(t, s, p); + + u = s.url || s.file; + if (tinymce.relaxedDomain) + u += (u.indexOf('?') == -1 ? '?' : '&') + 'mce_rdomain=' + tinymce.relaxedDomain; + + u = tinymce._addVer(u); + + try { + if (isIE && mo) { + w = 1; + window.showModalDialog(u, window, f); + } else + w = window.open(u, s.name, f); + } catch (ex) { + // Ignore + } + + if (!w) + alert(t.editor.getLang('popup_blocked')); + }, + + close : function(w) { + w.close(); + this.onClose.dispatch(this); + }, + + createInstance : function(cl, a, b, c, d, e) { + var f = tinymce.resolve(cl); + + return new f(a, b, c, d, e); + }, + + confirm : function(t, cb, s) { + cb.call(s || this, confirm(this._decode(this.editor.getLang(t, t)))); + }, + + alert : function(tx, cb, s) { + var t = this; + + alert(t._decode(t.editor.getLang(tx, tx))); + + if (cb) + cb.call(s || t); + }, + + // Internal functions + + _decode : function(s) { + return tinymce.DOM.decode(s).replace(/\\n/g, '\n'); + } + + }); +}()); \ No newline at end of file diff --git a/web/js/tiny_mce/utils/editable_selects.js b/web/js/tiny_mce/utils/editable_selects.js new file mode 100644 index 0000000..9b40922 --- /dev/null +++ b/web/js/tiny_mce/utils/editable_selects.js @@ -0,0 +1,61 @@ +/** + * $Id: editable_selects.js 520 2008-01-07 16:30:32Z spocke $ + * + * Makes select boxes editable. + * + * @author Moxiecode + * @copyright Copyright 2004-2008, Moxiecode Systems AB, All rights reserved. + */ + +var TinyMCE_EditableSelects = { + editSelectElm : null, + + init : function() { + var nl = document.getElementsByTagName("select"), i, d = document, o; + + for (i=0; i'; + h += ''; + + return h; +} + +function updateColor(img_id, form_element_id) { + document.getElementById(img_id).style.backgroundColor = document.forms[0].elements[form_element_id].value; +} + +function setBrowserDisabled(id, state) { + var img = document.getElementById(id); + var lnk = document.getElementById(id + "_link"); + + if (lnk) { + if (state) { + lnk.setAttribute("realhref", lnk.getAttribute("href")); + lnk.removeAttribute("href"); + tinyMCEPopup.dom.addClass(img, 'disabled'); + } else { + if (lnk.getAttribute("realhref")) + lnk.setAttribute("href", lnk.getAttribute("realhref")); + + tinyMCEPopup.dom.removeClass(img, 'disabled'); + } + } +} + +function getBrowserHTML(id, target_form_element, type, prefix) { + var option = prefix + "_" + type + "_browser_callback", cb, html; + + cb = tinyMCEPopup.getParam(option, tinyMCEPopup.getParam("file_browser_callback")); + + if (!cb) + return ""; + + html = ""; + html += ''; + html += ''; + + return html; +} + +function openBrowser(img_id, target_form_element, type, option) { + var img = document.getElementById(img_id); + + if (img.className != "mceButtonDisabled") + tinyMCEPopup.openBrowser(target_form_element, type, option); +} + +function selectByValue(form_obj, field_name, value, add_custom, ignore_case) { + if (!form_obj || !form_obj.elements[field_name]) + return; + + var sel = form_obj.elements[field_name]; + + var found = false; + for (var i=0; i parseInt(v)) + st = this.mark(f, n); + } + } + + return st; + }, + + hasClass : function(n, c, d) { + return new RegExp('\\b' + c + (d ? '[0-9]+' : '') + '\\b', 'g').test(n.className); + }, + + getNum : function(n, c) { + c = n.className.match(new RegExp('\\b' + c + '([0-9]+)\\b', 'g'))[0]; + c = c.replace(/[^0-9]/g, ''); + + return c; + }, + + addClass : function(n, c, b) { + var o = this.removeClass(n, c); + n.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c; + }, + + removeClass : function(n, c) { + c = n.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' '); + return n.className = c != ' ' ? c : ''; + }, + + tags : function(f, s) { + return f.getElementsByTagName(s); + }, + + mark : function(f, n) { + var s = this.settings; + + this.addClass(n, s.invalid_cls); + this.markLabels(f, n, s.invalid_cls); + + return false; + }, + + markLabels : function(f, n, ic) { + var nl, i; + + nl = this.tags(f, "label"); + for (i=0; i
    ' + + '' + + '' + + '' + + '
    StatusTestMessage
    '; + this.logsummary = $('logsummary') + this.loglines = $('loglines'); + }, + _toHTML: function(txt) { + return txt.escapeHTML().replace(/\n/g,"
    "); + }, + addLinksToResults: function(){ + $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log + td.title = "Run only this test" + Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;}); + }); + $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log + td.title = "Run all tests" + Event.observe(td, 'click', function(){ window.location.search = "";}); + }); + } +} + +Test.Unit.Runner = Class.create(); +Test.Unit.Runner.prototype = { + initialize: function(testcases) { + this.options = Object.extend({ + testLog: 'testlog' + }, arguments[1] || {}); + this.options.resultsURL = this.parseResultsURLQueryParameter(); + this.options.tests = this.parseTestsQueryParameter(); + if (this.options.testLog) { + this.options.testLog = $(this.options.testLog) || null; + } + if(this.options.tests) { + this.tests = []; + for(var i = 0; i < this.options.tests.length; i++) { + if(/^test/.test(this.options.tests[i])) { + this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"])); + } + } + } else { + if (this.options.test) { + this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])]; + } else { + this.tests = []; + for(var testcase in testcases) { + if(/^test/.test(testcase)) { + this.tests.push( + new Test.Unit.Testcase( + this.options.context ? ' -> ' + this.options.titles[testcase] : testcase, + testcases[testcase], testcases["setup"], testcases["teardown"] + )); + } + } + } + } + this.currentTest = 0; + this.logger = new Test.Unit.Logger(this.options.testLog); + setTimeout(this.runTests.bind(this), 1000); + }, + parseResultsURLQueryParameter: function() { + return window.location.search.parseQuery()["resultsURL"]; + }, + parseTestsQueryParameter: function(){ + if (window.location.search.parseQuery()["tests"]){ + return window.location.search.parseQuery()["tests"].split(','); + }; + }, + // Returns: + // "ERROR" if there was an error, + // "FAILURE" if there was a failure, or + // "SUCCESS" if there was neither + getResult: function() { + var hasFailure = false; + for(var i=0;i 0) { + return "ERROR"; + } + if (this.tests[i].failures > 0) { + hasFailure = true; + } + } + if (hasFailure) { + return "FAILURE"; + } else { + return "SUCCESS"; + } + }, + postResults: function() { + if (this.options.resultsURL) { + new Ajax.Request(this.options.resultsURL, + { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false }); + } + }, + runTests: function() { + var test = this.tests[this.currentTest]; + if (!test) { + // finished! + this.postResults(); + this.logger.summary(this.summary()); + return; + } + if(!test.isWaiting) { + this.logger.start(test.name); + } + test.run(); + if(test.isWaiting) { + this.logger.message("Waiting for " + test.timeToWait + "ms"); + setTimeout(this.runTests.bind(this), test.timeToWait || 1000); + } else { + this.logger.finish(test.status(), test.summary()); + this.currentTest++; + // tail recursive, hopefully the browser will skip the stackframe + this.runTests(); + } + }, + summary: function() { + var assertions = 0; + var failures = 0; + var errors = 0; + var messages = []; + for(var i=0;i 0) return 'failed'; + if (this.errors > 0) return 'error'; + return 'passed'; + }, + assert: function(expression) { + var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"'; + try { expression ? this.pass() : + this.fail(message); } + catch(e) { this.error(e); } + }, + assertEqual: function(expected, actual) { + var message = arguments[2] || "assertEqual"; + try { (expected == actual) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertInspect: function(expected, actual) { + var message = arguments[2] || "assertInspect"; + try { (expected == actual.inspect()) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertEnumEqual: function(expected, actual) { + var message = arguments[2] || "assertEnumEqual"; + try { $A(expected).length == $A(actual).length && + expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ? + this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + + ', actual ' + Test.Unit.inspect(actual)); } + catch(e) { this.error(e); } + }, + assertNotEqual: function(expected, actual) { + var message = arguments[2] || "assertNotEqual"; + try { (expected != actual) ? this.pass() : + this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertIdentical: function(expected, actual) { + var message = arguments[2] || "assertIdentical"; + try { (expected === actual) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertNotIdentical: function(expected, actual) { + var message = arguments[2] || "assertNotIdentical"; + try { !(expected === actual) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertNull: function(obj) { + var message = arguments[1] || 'assertNull' + try { (obj==null) ? this.pass() : + this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); } + catch(e) { this.error(e); } + }, + assertMatch: function(expected, actual) { + var message = arguments[2] || 'assertMatch'; + var regex = new RegExp(expected); + try { (regex.exec(actual)) ? this.pass() : + this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertHidden: function(element) { + var message = arguments[1] || 'assertHidden'; + this.assertEqual("none", element.style.display, message); + }, + assertNotNull: function(object) { + var message = arguments[1] || 'assertNotNull'; + this.assert(object != null, message); + }, + assertType: function(expected, actual) { + var message = arguments[2] || 'assertType'; + try { + (actual.constructor == expected) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + (actual.constructor) + '"'); } + catch(e) { this.error(e); } + }, + assertNotOfType: function(expected, actual) { + var message = arguments[2] || 'assertNotOfType'; + try { + (actual.constructor != expected) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + (actual.constructor) + '"'); } + catch(e) { this.error(e); } + }, + assertInstanceOf: function(expected, actual) { + var message = arguments[2] || 'assertInstanceOf'; + try { + (actual instanceof expected) ? this.pass() : + this.fail(message + ": object was not an instance of the expected type"); } + catch(e) { this.error(e); } + }, + assertNotInstanceOf: function(expected, actual) { + var message = arguments[2] || 'assertNotInstanceOf'; + try { + !(actual instanceof expected) ? this.pass() : + this.fail(message + ": object was an instance of the not expected type"); } + catch(e) { this.error(e); } + }, + assertRespondsTo: function(method, obj) { + var message = arguments[2] || 'assertRespondsTo'; + try { + (obj[method] && typeof obj[method] == 'function') ? this.pass() : + this.fail(message + ": object doesn't respond to [" + method + "]"); } + catch(e) { this.error(e); } + }, + assertReturnsTrue: function(method, obj) { + var message = arguments[2] || 'assertReturnsTrue'; + try { + var m = obj[method]; + if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)]; + m() ? this.pass() : + this.fail(message + ": method returned false"); } + catch(e) { this.error(e); } + }, + assertReturnsFalse: function(method, obj) { + var message = arguments[2] || 'assertReturnsFalse'; + try { + var m = obj[method]; + if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)]; + !m() ? this.pass() : + this.fail(message + ": method returned true"); } + catch(e) { this.error(e); } + }, + assertRaise: function(exceptionName, method) { + var message = arguments[2] || 'assertRaise'; + try { + method(); + this.fail(message + ": exception expected but none was raised"); } + catch(e) { + ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e); + } + }, + assertElementsMatch: function() { + var expressions = $A(arguments), elements = $A(expressions.shift()); + if (elements.length != expressions.length) { + this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions'); + return false; + } + elements.zip(expressions).all(function(pair, index) { + var element = $(pair.first()), expression = pair.last(); + if (element.match(expression)) return true; + this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect()); + }.bind(this)) && this.pass(); + }, + assertElementMatches: function(element, expression) { + this.assertElementsMatch([element], expression); + }, + benchmark: function(operation, iterations) { + var startAt = new Date(); + (iterations || 1).times(operation); + var timeTaken = ((new Date())-startAt); + this.info((arguments[2] || 'Operation') + ' finished ' + + iterations + ' iterations in ' + (timeTaken/1000)+'s' ); + return timeTaken; + }, + _isVisible: function(element) { + element = $(element); + if(!element.parentNode) return true; + this.assertNotNull(element); + if(element.style && Element.getStyle(element, 'display') == 'none') + return false; + + return this._isVisible(element.parentNode); + }, + assertNotVisible: function(element) { + this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1])); + }, + assertVisible: function(element) { + this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1])); + }, + benchmark: function(operation, iterations) { + var startAt = new Date(); + (iterations || 1).times(operation); + var timeTaken = ((new Date())-startAt); + this.info((arguments[2] || 'Operation') + ' finished ' + + iterations + ' iterations in ' + (timeTaken/1000)+'s' ); + return timeTaken; + } +} + +Test.Unit.Testcase = Class.create(); +Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), { + initialize: function(name, test, setup, teardown) { + Test.Unit.Assertions.prototype.initialize.bind(this)(); + this.name = name; + + if(typeof test == 'string') { + test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,'); + test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)'); + this.test = function() { + eval('with(this){'+test+'}'); + } + } else { + this.test = test || function() {}; + } + + this.setup = setup || function() {}; + this.teardown = teardown || function() {}; + this.isWaiting = false; + this.timeToWait = 1000; + }, + wait: function(time, nextPart) { + this.isWaiting = true; + this.test = nextPart; + this.timeToWait = time; + }, + run: function() { + try { + try { + if (!this.isWaiting) this.setup.bind(this)(); + this.isWaiting = false; + this.test.bind(this)(); + } finally { + if(!this.isWaiting) { + this.teardown.bind(this)(); + } + } + } + catch(e) { this.error(e); } + } +}); + +// *EXPERIMENTAL* BDD-style testing to please non-technical folk +// This draws many ideas from RSpec http://rspec.rubyforge.org/ + +Test.setupBDDExtensionMethods = function(){ + var METHODMAP = { + shouldEqual: 'assertEqual', + shouldNotEqual: 'assertNotEqual', + shouldEqualEnum: 'assertEnumEqual', + shouldBeA: 'assertType', + shouldNotBeA: 'assertNotOfType', + shouldBeAn: 'assertType', + shouldNotBeAn: 'assertNotOfType', + shouldBeNull: 'assertNull', + shouldNotBeNull: 'assertNotNull', + + shouldBe: 'assertReturnsTrue', + shouldNotBe: 'assertReturnsFalse', + shouldRespondTo: 'assertRespondsTo' + }; + var makeAssertion = function(assertion, args, object) { + this[assertion].apply(this,(args || []).concat([object])); + } + + Test.BDDMethods = {}; + $H(METHODMAP).each(function(pair) { + Test.BDDMethods[pair.key] = function() { + var args = $A(arguments); + var scope = args.shift(); + makeAssertion.apply(scope, [pair.value, args, this]); }; + }); + + [Array.prototype, String.prototype, Number.prototype, Boolean.prototype].each( + function(p){ Object.extend(p, Test.BDDMethods) } + ); +} + +Test.context = function(name, spec, log){ + Test.setupBDDExtensionMethods(); + + var compiledSpec = {}; + var titles = {}; + for(specName in spec) { + switch(specName){ + case "setup": + case "teardown": + compiledSpec[specName] = spec[specName]; + break; + default: + var testName = 'test'+specName.gsub(/\s+/,'-').camelize(); + var body = spec[specName].toString().split('\n').slice(1); + if(/^\{/.test(body[0])) body = body.slice(1); + body.pop(); + body = body.map(function(statement){ + return statement.strip() + }); + compiledSpec[testName] = body.join('\n'); + titles[testName] = specName; + } + } + new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name }); +}; \ No newline at end of file diff --git a/web/js/wz_tooltip.js b/web/js/wz_tooltip.js new file mode 100644 index 0000000..2026b2f --- /dev/null +++ b/web/js/wz_tooltip.js @@ -0,0 +1,1239 @@ +/* This notice must be untouched at all times. +Copyright (c) 2002-2008 Walter Zorn. All rights reserved. + +wz_tooltip.js v. 5.1 + +The latest version is available at +http://www.walterzorn.com +or http://www.devira.com +or http://www.walterzorn.de + +Created 1.12.2002 by Walter Zorn (Web: http://www.walterzorn.com ) +Last modified: 10.4.2008 + +Easy-to-use cross-browser tooltips. +Just include the script at the beginning of the section, and invoke +Tip('Tooltip text') from the desired HTML onmouseover eventhandlers, +and UnTip(), usually from the onmouseout eventhandlers, to hide the tip. +No container DIV required. +By default, width and height of tooltips are automatically adapted to content. +Is even capable of dynamically converting arbitrary HTML elements to tooltips +by calling TagToTip('ID_of_HTML_element_to_be_converted') instead of Tip(), +which means you can put important, search-engine-relevant stuff into tooltips. +Appearance & behaviour of tooltips can be individually configured +via commands passed to Tip() or TagToTip(). + +Tab Width: 4 +LICENSE: LGPL + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License (LGPL) as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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. + +For more details on the GNU Lesser General Public License, +see http://www.gnu.org/copyleft/lesser.html +*/ + +var config = new Object(); + + +//=================== GLOBAL TOOPTIP CONFIGURATION =========================// +var tt_Debug = true // false or true - recommended: false once you release your page to the public +var tt_Enabled = true // Allows to (temporarily) suppress tooltips, e.g. by providing the user with a button that sets this global variable to false +var TagsToTip = true // false or true - if true, HTML elements to be converted to tooltips via TagToTip() are automatically hidden; + // if false, you should hide those HTML elements yourself + +// For each of the following config variables there exists a command, which is +// just the variablename in uppercase, to be passed to Tip() or TagToTip() to +// configure tooltips individually. Individual commands override global +// configuration. Order of commands is arbitrary. +// Example: onmouseover="Tip('Tooltip text', LEFT, true, BGCOLOR, '#FF9900', FADEIN, 400)" + +config. Above = false // false or true - tooltip above mousepointer +config. BgColor = '#E2E7FF' // Background colour (HTML colour value, in quotes) +config. BgImg = '' // Path to background image, none if empty string '' +config. BorderColor = '#003099' +config. BorderStyle = 'solid' // Any permitted CSS value, but I recommend 'solid', 'dotted' or 'dashed' +config. BorderWidth = 1 +config. CenterMouse = false // false or true - center the tip horizontally below (or above) the mousepointer +config. ClickClose = false // false or true - close tooltip if the user clicks somewhere +config. ClickSticky = false // false or true - make tooltip sticky if user left-clicks on the hovered element while the tooltip is active +config. CloseBtn = false // false or true - closebutton in titlebar +config. CloseBtnColors = ['#990000', '#FFFFFF', '#DD3333', '#FFFFFF'] // [Background, text, hovered background, hovered text] - use empty strings '' to inherit title colours +config. CloseBtnText = ' X ' // Close button text (may also be an image tag) +config. CopyContent = true // When converting a HTML element to a tooltip, copy only the element's content, rather than converting the element by its own +config. Delay = 400 // Time span in ms until tooltip shows up +config. Duration = 0 // Time span in ms after which the tooltip disappears; 0 for infinite duration, < 0 for delay in ms _after_ the onmouseout until the tooltip disappears +config. FadeIn = 0 // Fade-in duration in ms, e.g. 400; 0 for no animation +config. FadeOut = 0 +config. FadeInterval = 30 // Duration of each fade step in ms (recommended: 30) - shorter is smoother but causes more CPU-load +config. Fix = null // Fixated position - x- an y-oordinates in brackets, e.g. [210, 480], or null for no fixation +config. FollowMouse = true // false or true - tooltip follows the mouse +config. FontColor = '#000044' +config. FontFace = 'Verdana,Geneva,sans-serif' +config. FontSize = '8pt' // E.g. '9pt' or '12px' - unit is mandatory +config. FontWeight = 'normal' // 'normal' or 'bold'; +config. Height = 0 // Tooltip height; 0 for automatic adaption to tooltip content, < 0 (e.g. -100) for a maximum for automatic adaption +config. JumpHorz = false // false or true - jump horizontally to other side of mouse if tooltip would extend past clientarea boundary +config. JumpVert = true // false or true - jump vertically " +config. Left = false // false or true - tooltip on the left of the mouse +config. OffsetX = 14 // Horizontal offset of left-top corner from mousepointer +config. OffsetY = 8 // Vertical offset +config. Opacity = 100 // Integer between 0 and 100 - opacity of tooltip in percent +config. Padding = 3 // Spacing between border and content +config. Shadow = false // false or true +config. ShadowColor = '#C0C0C0' +config. ShadowWidth = 5 +config. Sticky = false // false or true - fixate tip, ie. don't follow the mouse and don't hide on mouseout +config. TextAlign = 'left' // 'left', 'right' or 'justify' +config. Title = '' // Default title text applied to all tips (no default title: empty string '') +config. TitleAlign = 'left' // 'left' or 'right' - text alignment inside the title bar +config. TitleBgColor = '' // If empty string '', BorderColor will be used +config. TitleFontColor = '#FFFFFF' // Color of title text - if '', BgColor (of tooltip body) will be used +config. TitleFontFace = '' // If '' use FontFace (boldified) +config. TitleFontSize = '' // If '' use FontSize +config. TitlePadding = 2 +config. Width = 0 // Tooltip width; 0 for automatic adaption to tooltip content; < -1 (e.g. -240) for a maximum width for that automatic adaption; + // -1: tooltip width confined to the width required for the titlebar +//======= END OF TOOLTIP CONFIG, DO NOT CHANGE ANYTHING BELOW ==============// + + + + +//===================== PUBLIC =============================================// +function Tip() +{ + tt_Tip(arguments, null); +} +function TagToTip() +{ + var t2t = tt_GetElt(arguments[0]); + if(t2t) + tt_Tip(arguments, t2t); +} +function UnTip() +{ + tt_OpReHref(); + if(tt_aV[DURATION] < 0) + tt_tDurt.Timer("tt_HideInit()", -tt_aV[DURATION], true); + else if(!(tt_aV[STICKY] && (tt_iState & 0x2))) + tt_HideInit(); +} + +//================== PUBLIC PLUGIN API =====================================// +// Extension eventhandlers currently supported: +// OnLoadConfig, OnCreateContentString, OnSubDivsCreated, OnShow, OnMoveBefore, +// OnMoveAfter, OnHideInit, OnHide, OnKill + +var tt_aElt = new Array(10), // Container DIV, outer title & body DIVs, inner title & body TDs, closebutton SPAN, shadow DIVs, and IFRAME to cover windowed elements in IE +tt_aV = new Array(), // Caches and enumerates config data for currently active tooltip +tt_sContent, // Inner tooltip text or HTML +tt_scrlX = 0, tt_scrlY = 0, +tt_musX, tt_musY, +tt_over, +tt_x, tt_y, tt_w, tt_h; // Position, width and height of currently displayed tooltip + +function tt_Extension() +{ + tt_ExtCmdEnum(); + tt_aExt[tt_aExt.length] = this; + return this; +} +function tt_SetTipPos(x, y) +{ + var css = tt_aElt[0].style; + + tt_x = x; + tt_y = y; + css.left = x + "px"; + css.top = y + "px"; + if(tt_ie56) + { + var ifrm = tt_aElt[tt_aElt.length - 1]; + if(ifrm) + { + ifrm.style.left = css.left; + ifrm.style.top = css.top; + } + } +} +function tt_HideInit() +{ + if(tt_iState) + { + tt_ExtCallFncs(0, "HideInit"); + tt_iState &= ~0x4; + if(tt_flagOpa && tt_aV[FADEOUT]) + { + tt_tFade.EndTimer(); + if(tt_opa) + { + var n = Math.round(tt_aV[FADEOUT] / (tt_aV[FADEINTERVAL] * (tt_aV[OPACITY] / tt_opa))); + tt_Fade(tt_opa, tt_opa, 0, n); + return; + } + } + tt_tHide.Timer("tt_Hide();", 1, false); + } +} +function tt_Hide() +{ + if(tt_db && tt_iState) + { + tt_OpReHref(); + if(tt_iState & 0x2) + { + tt_aElt[0].style.visibility = "hidden"; + tt_ExtCallFncs(0, "Hide"); + } + tt_tShow.EndTimer(); + tt_tHide.EndTimer(); + tt_tDurt.EndTimer(); + tt_tFade.EndTimer(); + if(!tt_op && !tt_ie) + { + tt_tWaitMov.EndTimer(); + tt_bWait = false; + } + if(tt_aV[CLICKCLOSE] || tt_aV[CLICKSTICKY]) + tt_RemEvtFnc(document, "mouseup", tt_OnLClick); + tt_ExtCallFncs(0, "Kill"); + // In case of a TagToTip tooltip, hide converted DOM node and + // re-insert it into document + if(tt_t2t && !tt_aV[COPYCONTENT]) + { + tt_t2t.style.display = "none"; + tt_MovDomNode(tt_t2t, tt_aElt[6], tt_t2tDad); + } + tt_iState = 0; + tt_over = null; + tt_ResetMainDiv(); + if(tt_aElt[tt_aElt.length - 1]) + tt_aElt[tt_aElt.length - 1].style.display = "none"; + } +} +function tt_GetElt(id) +{ + return(document.getElementById ? document.getElementById(id) + : document.all ? document.all[id] + : null); +} +function tt_GetDivW(el) +{ + return(el ? (el.offsetWidth || el.style.pixelWidth || 0) : 0); +} +function tt_GetDivH(el) +{ + return(el ? (el.offsetHeight || el.style.pixelHeight || 0) : 0); +} +function tt_GetScrollX() +{ + return(window.pageXOffset || (tt_db ? (tt_db.scrollLeft || 0) : 0)); +} +function tt_GetScrollY() +{ + return(window.pageYOffset || (tt_db ? (tt_db.scrollTop || 0) : 0)); +} +function tt_GetClientW() +{ + return(document.body && (typeof(document.body.clientWidth) != tt_u) ? document.body.clientWidth + : (typeof(window.innerWidth) != tt_u) ? window.innerWidth + : tt_db ? (tt_db.clientWidth || 0) + : 0); +} +function tt_GetClientH() +{ + // Exactly this order seems to yield correct values in all major browsers + return(document.body && (typeof(document.body.clientHeight) != tt_u) ? document.body.clientHeight + : (typeof(window.innerHeight) != tt_u) ? window.innerHeight + : tt_db ? (tt_db.clientHeight || 0) + : 0); +} +function tt_GetEvtX(e) +{ + return (e ? ((typeof(e.pageX) != tt_u) ? e.pageX : (e.clientX + tt_scrlX)) : 0); +} +function tt_GetEvtY(e) +{ + return (e ? ((typeof(e.pageY) != tt_u) ? e.pageY : (e.clientY + tt_scrlY)) : 0); +} +function tt_AddEvtFnc(el, sEvt, PFnc) +{ + if(el) + { + if(el.addEventListener) + el.addEventListener(sEvt, PFnc, false); + else + el.attachEvent("on" + sEvt, PFnc); + } +} +function tt_RemEvtFnc(el, sEvt, PFnc) +{ + if(el) + { + if(el.removeEventListener) + el.removeEventListener(sEvt, PFnc, false); + else + el.detachEvent("on" + sEvt, PFnc); + } +} + +//====================== PRIVATE ===========================================// +var tt_aExt = new Array(), // Array of extension objects + +tt_db, tt_op, tt_ie, tt_ie56, tt_bBoxOld, // Browser flags +tt_body, +tt_ovr_, // HTML element the mouse is currently over +tt_flagOpa, // Opacity support: 1=IE, 2=Khtml, 3=KHTML, 4=Moz, 5=W3C +tt_maxPosX, tt_maxPosY, +tt_iState = 0, // Tooltip active |= 1, shown |= 2, move with mouse |= 4 +tt_opa, // Currently applied opacity +tt_bJmpVert, tt_bJmpHorz,// Tip temporarily on other side of mouse +tt_t2t, tt_t2tDad, // Tag converted to tip, and its parent element in the document +tt_elDeHref, // The tag from which we've removed the href attribute +// Timer +tt_tShow = new Number(0), tt_tHide = new Number(0), tt_tDurt = new Number(0), +tt_tFade = new Number(0), tt_tWaitMov = new Number(0), +tt_bWait = false, +tt_u = "undefined"; + + +function tt_Init() +{ + tt_MkCmdEnum(); + // Send old browsers instantly to hell + if(!tt_Browser() || !tt_MkMainDiv()) + return; + tt_IsW3cBox(); + tt_OpaSupport(); + tt_AddEvtFnc(window, "scroll", tt_OnScrl); + // IE doesn't fire onscroll event when switching to fullscreen; + // fix suggested by Yoav Karpeles 14.2.2008 + tt_AddEvtFnc(window, "resize", tt_OnScrl); + tt_AddEvtFnc(document, "mousemove", tt_Move); + // In Debug mode we search for TagToTip() calls in order to notify + // the user if they've forgotten to set the TagsToTip config flag + if(TagsToTip || tt_Debug) + tt_SetOnloadFnc(); + // Ensure the tip be hidden when the page unloads + tt_AddEvtFnc(window, "unload", tt_Hide); +} +// Creates command names by translating config variable names to upper case +function tt_MkCmdEnum() +{ + var n = 0; + for(var i in config) + eval("window." + i.toString().toUpperCase() + " = " + n++); + tt_aV.length = n; +} +function tt_Browser() +{ + var n, nv, n6, w3c; + + n = navigator.userAgent.toLowerCase(), + nv = navigator.appVersion; + tt_op = (document.defaultView && typeof(eval("w" + "indow" + "." + "o" + "p" + "er" + "a")) != tt_u); + tt_ie = n.indexOf("msie") != -1 && document.all && !tt_op; + if(tt_ie) + { + var ieOld = (!document.compatMode || document.compatMode == "BackCompat"); + tt_db = !ieOld ? document.documentElement : (document.body || null); + if(tt_db) + tt_ie56 = parseFloat(nv.substring(nv.indexOf("MSIE") + 5)) >= 5.5 + && typeof document.body.style.maxHeight == tt_u; + } + else + { + tt_db = document.documentElement || document.body || + (document.getElementsByTagName ? document.getElementsByTagName("body")[0] + : null); + if(!tt_op) + { + n6 = document.defaultView && typeof document.defaultView.getComputedStyle != tt_u; + w3c = !n6 && document.getElementById; + } + } + tt_body = (document.getElementsByTagName ? document.getElementsByTagName("body")[0] + : (document.body || null)); + if(tt_ie || n6 || tt_op || w3c) + { + if(tt_body && tt_db) + { + if(document.attachEvent || document.addEventListener) + return true; + } + else + tt_Err("wz_tooltip.js must be included INSIDE the body section," + + " immediately after the opening tag.", false); + } + tt_db = null; + return false; +} +function tt_MkMainDiv() +{ + // Create the tooltip DIV + if(tt_body.insertAdjacentHTML) + tt_body.insertAdjacentHTML("afterBegin", tt_MkMainDivHtm()); + else if(typeof tt_body.innerHTML != tt_u && document.createElement && tt_body.appendChild) + tt_body.appendChild(tt_MkMainDivDom()); + if(window.tt_GetMainDivRefs /* FireFox Alzheimer */ && tt_GetMainDivRefs()) + return true; + tt_db = null; + return false; +} +function tt_MkMainDivHtm() +{ + return('
    ' + + (tt_ie56 ? ('') + : '')); +} +function tt_MkMainDivDom() +{ + var el = document.createElement("div"); + if(el) + el.id = "WzTtDiV"; + return el; +} +function tt_GetMainDivRefs() +{ + tt_aElt[0] = tt_GetElt("WzTtDiV"); + if(tt_ie56 && tt_aElt[0]) + { + tt_aElt[tt_aElt.length - 1] = tt_GetElt("WzTtIfRm"); + if(!tt_aElt[tt_aElt.length - 1]) + tt_aElt[0] = null; + } + if(tt_aElt[0]) + { + var css = tt_aElt[0].style; + + css.visibility = "hidden"; + css.position = "absolute"; + css.overflow = "hidden"; + return true; + } + return false; +} +function tt_ResetMainDiv() +{ + var w = (window.screen && screen.width) ? screen.width : 10000; + + tt_SetTipPos(-w, 0); + tt_aElt[0].innerHTML = ""; + tt_aElt[0].style.width = (w - 1) + "px"; + tt_h = 0; +} +function tt_IsW3cBox() +{ + var css = tt_aElt[0].style; + + css.padding = "10px"; + css.width = "40px"; + tt_bBoxOld = (tt_GetDivW(tt_aElt[0]) == 40); + css.padding = "0px"; + tt_ResetMainDiv(); +} +function tt_OpaSupport() +{ + var css = tt_body.style; + + tt_flagOpa = (typeof(css.filter) != tt_u) ? 1 + : (typeof(css.KhtmlOpacity) != tt_u) ? 2 + : (typeof(css.KHTMLOpacity) != tt_u) ? 3 + : (typeof(css.MozOpacity) != tt_u) ? 4 + : (typeof(css.opacity) != tt_u) ? 5 + : 0; +} +// Ported from http://dean.edwards.name/weblog/2006/06/again/ +// (Dean Edwards et al.) +function tt_SetOnloadFnc() +{ + tt_AddEvtFnc(document, "DOMContentLoaded", tt_HideSrcTags); + tt_AddEvtFnc(window, "load", tt_HideSrcTags); + if(tt_body.attachEvent) + tt_body.attachEvent("onreadystatechange", + function() { + if(tt_body.readyState == "complete") + tt_HideSrcTags(); + } ); + if(/WebKit|KHTML/i.test(navigator.userAgent)) + { + var t = setInterval(function() { + if(/loaded|complete/.test(document.readyState)) + { + clearInterval(t); + tt_HideSrcTags(); + } + }, 10); + } +} +function tt_HideSrcTags() +{ + if(!window.tt_HideSrcTags || window.tt_HideSrcTags.done) + return; + window.tt_HideSrcTags.done = true; + if(!tt_HideSrcTagsRecurs(tt_body)) + tt_Err("There are HTML elements to be converted to tooltips.\nIf you" + + " want these HTML elements to be automatically hidden, you" + + " must edit wz_tooltip.js, and set TagsToTip in the global" + + " tooltip configuration to true.", true); +} +function tt_HideSrcTagsRecurs(dad) +{ + var ovr, asT2t; + // Walk the DOM tree for tags that have an onmouseover or onclick attribute + // containing a TagToTip('...') call. + // (.childNodes first since .children is bugous in Safari) + var a = dad.childNodes || dad.children || null; + + for(var i = a ? a.length : 0; i;) + {--i; + if(!tt_HideSrcTagsRecurs(a[i])) + return false; + ovr = a[i].getAttribute ? (a[i].getAttribute("onmouseover") || a[i].getAttribute("onclick")) + : (typeof a[i].onmouseover == "function") ? (a[i].onmouseover || a[i].onclick) + : null; + if(ovr) + { + asT2t = ovr.toString().match(/TagToTip\s*\(\s*'[^'.]+'\s*[\),]/); + if(asT2t && asT2t.length) + { + if(!tt_HideSrcTag(asT2t[0])) + return false; + } + } + } + return true; +} +function tt_HideSrcTag(sT2t) +{ + var id, el; + + // The ID passed to the found TagToTip() call identifies an HTML element + // to be converted to a tooltip, so hide that element + id = sT2t.replace(/.+'([^'.]+)'.+/, "$1"); + el = tt_GetElt(id); + if(el) + { + if(tt_Debug && !TagsToTip) + return false; + else + el.style.display = "none"; + } + else + tt_Err("Invalid ID\n'" + id + "'\npassed to TagToTip()." + + " There exists no HTML element with that ID.", true); + return true; +} +function tt_Tip(arg, t2t) +{ + if(!tt_db) + return; + if(tt_iState) + tt_Hide(); + if(!tt_Enabled) + return; + tt_t2t = t2t; + if(!tt_ReadCmds(arg)) + return; + tt_iState = 0x1 | 0x4; + tt_AdaptConfig1(); + tt_MkTipContent(arg); + tt_MkTipSubDivs(); + tt_FormatTip(); + tt_bJmpVert = false; + tt_bJmpHorz = false; + tt_maxPosX = tt_GetClientW() + tt_scrlX - tt_w - 1; + tt_maxPosY = tt_GetClientH() + tt_scrlY - tt_h - 1; + tt_AdaptConfig2(); + // Ensure the tip be shown and positioned before the first onmousemove + tt_OverInit(); + tt_ShowInit(); + tt_Move(); +} +function tt_ReadCmds(a) +{ + var i; + + // First load the global config values, to initialize also values + // for which no command is passed + i = 0; + for(var j in config) + tt_aV[i++] = config[j]; + // Then replace each cached config value for which a command is + // passed (ensure the # of command args plus value args be even) + if(a.length & 1) + { + for(i = a.length - 1; i > 0; i -= 2) + tt_aV[a[i - 1]] = a[i]; + return true; + } + tt_Err("Incorrect call of Tip() or TagToTip().\n" + + "Each command must be followed by a value.", true); + return false; +} +function tt_AdaptConfig1() +{ + tt_ExtCallFncs(0, "LoadConfig"); + // Inherit unspecified title formattings from body + if(!tt_aV[TITLEBGCOLOR].length) + tt_aV[TITLEBGCOLOR] = tt_aV[BORDERCOLOR]; + if(!tt_aV[TITLEFONTCOLOR].length) + tt_aV[TITLEFONTCOLOR] = tt_aV[BGCOLOR]; + if(!tt_aV[TITLEFONTFACE].length) + tt_aV[TITLEFONTFACE] = tt_aV[FONTFACE]; + if(!tt_aV[TITLEFONTSIZE].length) + tt_aV[TITLEFONTSIZE] = tt_aV[FONTSIZE]; + if(tt_aV[CLOSEBTN]) + { + // Use title colours for non-specified closebutton colours + if(!tt_aV[CLOSEBTNCOLORS]) + tt_aV[CLOSEBTNCOLORS] = new Array("", "", "", ""); + for(var i = 4; i;) + {--i; + if(!tt_aV[CLOSEBTNCOLORS][i].length) + tt_aV[CLOSEBTNCOLORS][i] = (i & 1) ? tt_aV[TITLEFONTCOLOR] : tt_aV[TITLEBGCOLOR]; + } + // Enforce titlebar be shown + if(!tt_aV[TITLE].length) + tt_aV[TITLE] = " "; + } + // Circumvents broken display of images and fade-in flicker in Geckos < 1.8 + if(tt_aV[OPACITY] == 100 && typeof tt_aElt[0].style.MozOpacity != tt_u && !Array.every) + tt_aV[OPACITY] = 99; + // Smartly shorten the delay for fade-in tooltips + if(tt_aV[FADEIN] && tt_flagOpa && tt_aV[DELAY] > 100) + tt_aV[DELAY] = Math.max(tt_aV[DELAY] - tt_aV[FADEIN], 100); +} +function tt_AdaptConfig2() +{ + if(tt_aV[CENTERMOUSE]) + { + tt_aV[OFFSETX] -= ((tt_w - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0)) >> 1); + tt_aV[JUMPHORZ] = false; + } +} +// Expose content globally so extensions can modify it +function tt_MkTipContent(a) +{ + if(tt_t2t) + { + if(tt_aV[COPYCONTENT]) + tt_sContent = tt_t2t.innerHTML; + else + tt_sContent = ""; + } + else + tt_sContent = a[0]; + tt_ExtCallFncs(0, "CreateContentString"); +} +function tt_MkTipSubDivs() +{ + var sCss = 'position:relative;margin:0px;padding:0px;border-width:0px;left:0px;top:0px;line-height:normal;width:auto;', + sTbTrTd = ' cellspacing="0" cellpadding="0" border="0" style="' + sCss + '">' + + '' + + tt_aV[TITLE] + + '' + + (tt_aV[CLOSEBTN] ? + ('') + : '') + + '
    ' + + '' + + tt_aV[CLOSEBTNTEXT] + + '
    ') + : '') + + '
    ' + + '' + + tt_sContent + + '
    ' + + (tt_aV[SHADOW] + ? ('
    ' + + '
    ') + : '') + ); + tt_GetSubDivRefs(); + // Convert DOM node to tip + if(tt_t2t && !tt_aV[COPYCONTENT]) + { + // Store the tag's parent element so we can restore that DOM branch + // once the tooltip is hidden + tt_t2tDad = tt_t2t.parentNode || tt_t2t.parentElement || tt_t2t.offsetParent || null; + if(tt_t2tDad) + { + tt_MovDomNode(tt_t2t, tt_t2tDad, tt_aElt[6]); + tt_t2t.style.display = "block"; + } + } + tt_ExtCallFncs(0, "SubDivsCreated"); +} +function tt_GetSubDivRefs() +{ + var aId = new Array("WzTiTl", "WzTiTlTb", "WzTiTlI", "WzClOsE", "WzBoDy", "WzBoDyI", "WzTtShDwB", "WzTtShDwR"); + + for(var i = aId.length; i; --i) + tt_aElt[i] = tt_GetElt(aId[i - 1]); +} +function tt_FormatTip() +{ + var css, w, h, pad = tt_aV[PADDING], padT, wBrd = tt_aV[BORDERWIDTH], + iOffY, iOffSh, iAdd = (pad + wBrd) << 1; + + //--------- Title DIV ---------- + if(tt_aV[TITLE].length) + { + padT = tt_aV[TITLEPADDING]; + css = tt_aElt[1].style; + css.background = tt_aV[TITLEBGCOLOR]; + css.paddingTop = css.paddingBottom = padT + "px"; + css.paddingLeft = css.paddingRight = (padT + 2) + "px"; + css = tt_aElt[3].style; + css.color = tt_aV[TITLEFONTCOLOR]; + if(tt_aV[WIDTH] == -1) + css.whiteSpace = "nowrap"; + css.fontFamily = tt_aV[TITLEFONTFACE]; + css.fontSize = tt_aV[TITLEFONTSIZE]; + css.fontWeight = "bold"; + css.textAlign = tt_aV[TITLEALIGN]; + // Close button DIV + if(tt_aElt[4]) + { + css = tt_aElt[4].style; + css.background = tt_aV[CLOSEBTNCOLORS][0]; + css.color = tt_aV[CLOSEBTNCOLORS][1]; + css.fontFamily = tt_aV[TITLEFONTFACE]; + css.fontSize = tt_aV[TITLEFONTSIZE]; + css.fontWeight = "bold"; + } + if(tt_aV[WIDTH] > 0) + tt_w = tt_aV[WIDTH]; + else + { + tt_w = tt_GetDivW(tt_aElt[3]) + tt_GetDivW(tt_aElt[4]); + // Some spacing between title DIV and closebutton + if(tt_aElt[4]) + tt_w += pad; + // Restrict auto width to max width + if(tt_aV[WIDTH] < -1 && tt_w > -tt_aV[WIDTH]) + tt_w = -tt_aV[WIDTH]; + } + // Ensure the top border of the body DIV be covered by the title DIV + iOffY = -wBrd; + } + else + { + tt_w = 0; + iOffY = 0; + } + + //-------- Body DIV ------------ + css = tt_aElt[5].style; + css.top = iOffY + "px"; + if(wBrd) + { + css.borderColor = tt_aV[BORDERCOLOR]; + css.borderStyle = tt_aV[BORDERSTYLE]; + css.borderWidth = wBrd + "px"; + } + if(tt_aV[BGCOLOR].length) + css.background = tt_aV[BGCOLOR]; + if(tt_aV[BGIMG].length) + css.backgroundImage = "url(" + tt_aV[BGIMG] + ")"; + css.padding = pad + "px"; + css.textAlign = tt_aV[TEXTALIGN]; + if(tt_aV[HEIGHT]) + { + css.overflow = "auto"; + if(tt_aV[HEIGHT] > 0) + css.height = (tt_aV[HEIGHT] + iAdd) + "px"; + else + tt_h = iAdd - tt_aV[HEIGHT]; + } + // TD inside body DIV + css = tt_aElt[6].style; + css.color = tt_aV[FONTCOLOR]; + css.fontFamily = tt_aV[FONTFACE]; + css.fontSize = tt_aV[FONTSIZE]; + css.fontWeight = tt_aV[FONTWEIGHT]; + css.background = ""; + css.textAlign = tt_aV[TEXTALIGN]; + if(tt_aV[WIDTH] > 0) + w = tt_aV[WIDTH]; + // Width like title (if existent) + else if(tt_aV[WIDTH] == -1 && tt_w) + w = tt_w; + else + { + // Measure width of the body's inner TD, as some browsers would expand + // the container and outer body DIV to 100% + w = tt_GetDivW(tt_aElt[6]); + // Restrict auto width to max width + if(tt_aV[WIDTH] < -1 && w > -tt_aV[WIDTH]) + w = -tt_aV[WIDTH]; + } + if(w > tt_w) + tt_w = w; + tt_w += iAdd; + + //--------- Shadow DIVs ------------ + if(tt_aV[SHADOW]) + { + tt_w += tt_aV[SHADOWWIDTH]; + iOffSh = Math.floor((tt_aV[SHADOWWIDTH] * 4) / 3); + // Bottom shadow + css = tt_aElt[7].style; + css.top = iOffY + "px"; + css.left = iOffSh + "px"; + css.width = (tt_w - iOffSh - tt_aV[SHADOWWIDTH]) + "px"; + css.height = tt_aV[SHADOWWIDTH] + "px"; + css.background = tt_aV[SHADOWCOLOR]; + // Right shadow + css = tt_aElt[8].style; + css.top = iOffSh + "px"; + css.left = (tt_w - tt_aV[SHADOWWIDTH]) + "px"; + css.width = tt_aV[SHADOWWIDTH] + "px"; + css.background = tt_aV[SHADOWCOLOR]; + } + else + iOffSh = 0; + + //-------- Container DIV ------- + tt_SetTipOpa(tt_aV[FADEIN] ? 0 : tt_aV[OPACITY]); + tt_FixSize(iOffY, iOffSh); +} +// Fixate the size so it can't dynamically change while the tooltip is moving. +function tt_FixSize(iOffY, iOffSh) +{ + var wIn, wOut, h, add, pad = tt_aV[PADDING], wBrd = tt_aV[BORDERWIDTH], i; + + tt_aElt[0].style.width = tt_w + "px"; + tt_aElt[0].style.pixelWidth = tt_w; + wOut = tt_w - ((tt_aV[SHADOW]) ? tt_aV[SHADOWWIDTH] : 0); + // Body + wIn = wOut; + if(!tt_bBoxOld) + wIn -= (pad + wBrd) << 1; + tt_aElt[5].style.width = wIn + "px"; + // Title + if(tt_aElt[1]) + { + wIn = wOut - ((tt_aV[TITLEPADDING] + 2) << 1); + if(!tt_bBoxOld) + wOut = wIn; + tt_aElt[1].style.width = wOut + "px"; + tt_aElt[2].style.width = wIn + "px"; + } + // Max height specified + if(tt_h) + { + h = tt_GetDivH(tt_aElt[5]); + if(h > tt_h) + { + if(!tt_bBoxOld) + tt_h -= (pad + wBrd) << 1; + tt_aElt[5].style.height = tt_h + "px"; + } + } + tt_h = tt_GetDivH(tt_aElt[0]) + iOffY; + // Right shadow + if(tt_aElt[8]) + tt_aElt[8].style.height = (tt_h - iOffSh) + "px"; + i = tt_aElt.length - 1; + if(tt_aElt[i]) + { + tt_aElt[i].style.width = tt_w + "px"; + tt_aElt[i].style.height = tt_h + "px"; + } +} +function tt_DeAlt(el) +{ + var aKid; + + if(el) + { + if(el.alt) + el.alt = ""; + if(el.title) + el.title = ""; + aKid = el.childNodes || el.children || null; + if(aKid) + { + for(var i = aKid.length; i;) + tt_DeAlt(aKid[--i]); + } + } +} +// This hack removes the native tooltips over links in Opera +function tt_OpDeHref(el) +{ + if(!tt_op) + return; + if(tt_elDeHref) + tt_OpReHref(); + while(el) + { + if(el.hasAttribute("href")) + { + el.t_href = el.getAttribute("href"); + el.t_stats = window.status; + el.removeAttribute("href"); + el.style.cursor = "hand"; + tt_AddEvtFnc(el, "mousedown", tt_OpReHref); + window.status = el.t_href; + tt_elDeHref = el; + break; + } + el = el.parentElement; + } +} +function tt_OpReHref() +{ + if(tt_elDeHref) + { + tt_elDeHref.setAttribute("href", tt_elDeHref.t_href); + tt_RemEvtFnc(tt_elDeHref, "mousedown", tt_OpReHref); + window.status = tt_elDeHref.t_stats; + tt_elDeHref = null; + } +} +function tt_OverInit() +{ + if(window.event) + tt_over = window.event.target || window.event.srcElement; + else + tt_over = tt_ovr_; + tt_DeAlt(tt_over); + tt_OpDeHref(tt_over); +} +function tt_ShowInit() +{ + tt_tShow.Timer("tt_Show()", tt_aV[DELAY], true); + if(tt_aV[CLICKCLOSE] || tt_aV[CLICKSTICKY]) + tt_AddEvtFnc(document, "mouseup", tt_OnLClick); +} +function tt_Show() +{ + var css = tt_aElt[0].style; + + // Override the z-index of the topmost wz_dragdrop.js D&D item + css.zIndex = Math.max((window.dd && dd.z) ? (dd.z + 2) : 0, 1010); + if(tt_aV[STICKY] || !tt_aV[FOLLOWMOUSE]) + tt_iState &= ~0x4; + if(tt_aV[DURATION] > 0) + tt_tDurt.Timer("tt_HideInit()", tt_aV[DURATION], true); + tt_ExtCallFncs(0, "Show") + css.visibility = "visible"; + tt_iState |= 0x2; + if(tt_aV[FADEIN]) + tt_Fade(0, 0, tt_aV[OPACITY], Math.round(tt_aV[FADEIN] / tt_aV[FADEINTERVAL])); + tt_ShowIfrm(); +} +function tt_ShowIfrm() +{ + if(tt_ie56) + { + var ifrm = tt_aElt[tt_aElt.length - 1]; + if(ifrm) + { + var css = ifrm.style; + css.zIndex = tt_aElt[0].style.zIndex - 1; + css.display = "block"; + } + } +} +function tt_Move(e) +{ + if(e) + tt_ovr_ = e.target || e.srcElement; + e = e || window.event; + if(e) + { + tt_musX = tt_GetEvtX(e); + tt_musY = tt_GetEvtY(e); + } + if(tt_iState & 0x04) + { + // Prevent jam of mousemove events + if(!tt_op && !tt_ie) + { + if(tt_bWait) + return; + tt_bWait = true; + tt_tWaitMov.Timer("tt_bWait = false;", 1, true); + } + if(tt_aV[FIX]) + { + var iY = tt_aV[FIX][1]; + // For a fixed tip to be positioned above the mouse, use the + // bottom edge as anchor + // (recommended by Christophe Rebeschini, 31.1.2008) + if(tt_aV[ABOVE]) + iY -= tt_h; + tt_iState &= ~0x4; + tt_SetTipPos(tt_aV[FIX][0], tt_aV[FIX][1]); + } + else if(!tt_ExtCallFncs(e, "MoveBefore")) + tt_SetTipPos(tt_Pos(0), tt_Pos(1)); + tt_ExtCallFncs([tt_musX, tt_musY], "MoveAfter") + } +} +function tt_Pos(iDim) +{ + var iX, bJmpMode, cmdAlt, cmdOff, cx, iMax, iScrl, iMus, bJmp; + + // Map values according to dimension to calculate + if(iDim) + { + bJmpMode = tt_aV[JUMPVERT]; + cmdAlt = ABOVE; + cmdOff = OFFSETY; + cx = tt_h; + iMax = tt_maxPosY; + iScrl = tt_scrlY; + iMus = tt_musY; + bJmp = tt_bJmpVert; + } + else + { + bJmpMode = tt_aV[JUMPHORZ]; + cmdAlt = LEFT; + cmdOff = OFFSETX; + cx = tt_w; + iMax = tt_maxPosX; + iScrl = tt_scrlX; + iMus = tt_musX; + bJmp = tt_bJmpHorz; + } + if(bJmpMode) + { + if(tt_aV[cmdAlt] && (!bJmp || tt_CalcPosAlt(iDim) >= iScrl + 16)) + iX = tt_PosAlt(iDim); + else if(!tt_aV[cmdAlt] && bJmp && tt_CalcPosDef(iDim) > iMax - 16) + iX = tt_PosAlt(iDim); + else + iX = tt_PosDef(iDim); + } + else + { + iX = iMus; + if(tt_aV[cmdAlt]) + iX -= cx + tt_aV[cmdOff] - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0); + else + iX += tt_aV[cmdOff]; + } + // Prevent tip from extending past clientarea boundary + if(iX > iMax) + iX = bJmpMode ? tt_PosAlt(iDim) : iMax; + // In case of insufficient space on both sides, ensure the left/upper part + // of the tip be visible + if(iX < iScrl) + iX = bJmpMode ? tt_PosDef(iDim) : iScrl; + return iX; +} +function tt_PosDef(iDim) +{ + if(iDim) + tt_bJmpVert = tt_aV[ABOVE]; + else + tt_bJmpHorz = tt_aV[LEFT]; + return tt_CalcPosDef(iDim); +} +function tt_PosAlt(iDim) +{ + if(iDim) + tt_bJmpVert = !tt_aV[ABOVE]; + else + tt_bJmpHorz = !tt_aV[LEFT]; + return tt_CalcPosAlt(iDim); +} +function tt_CalcPosDef(iDim) +{ + return iDim ? (tt_musY + tt_aV[OFFSETY]) : (tt_musX + tt_aV[OFFSETX]); +} +function tt_CalcPosAlt(iDim) +{ + var cmdOff = iDim ? OFFSETY : OFFSETX; + var dx = tt_aV[cmdOff] - (tt_aV[SHADOW] ? tt_aV[SHADOWWIDTH] : 0); + if(tt_aV[cmdOff] > 0 && dx <= 0) + dx = 1; + return((iDim ? (tt_musY - tt_h) : (tt_musX - tt_w)) - dx); +} +function tt_Fade(a, now, z, n) +{ + if(n) + { + now += Math.round((z - now) / n); + if((z > a) ? (now >= z) : (now <= z)) + now = z; + else + tt_tFade.Timer("tt_Fade(" + + a + "," + now + "," + z + "," + (n - 1) + + ")", + tt_aV[FADEINTERVAL], + true); + } + now ? tt_SetTipOpa(now) : tt_Hide(); +} +function tt_SetTipOpa(opa) +{ + // To circumvent the opacity nesting flaws of IE, we set the opacity + // for each sub-DIV separately, rather than for the container DIV. + tt_SetOpa(tt_aElt[5], opa); + if(tt_aElt[1]) + tt_SetOpa(tt_aElt[1], opa); + if(tt_aV[SHADOW]) + { + opa = Math.round(opa * 0.8); + tt_SetOpa(tt_aElt[7], opa); + tt_SetOpa(tt_aElt[8], opa); + } +} +function tt_OnScrl() +{ + tt_scrlX = tt_GetScrollX(); + tt_scrlY = tt_GetScrollY(); +} +function tt_OnCloseBtnOver(iOver) +{ + var css = tt_aElt[4].style; + + iOver <<= 1; + css.background = tt_aV[CLOSEBTNCOLORS][iOver]; + css.color = tt_aV[CLOSEBTNCOLORS][iOver + 1]; +} +function tt_OnLClick(e) +{ + // Ignore right-clicks + e = e || window.event; + if(!((e.button && e.button & 2) || (e.which && e.which == 3))) + { + if(tt_aV[CLICKSTICKY] && (tt_iState & 0x4)) + { + tt_aV[STICKY] = true; + tt_iState &= ~0x4; + } + else if(tt_aV[CLICKCLOSE]) + tt_HideInit(); + } +} +function tt_Int(x) +{ + var y; + + return(isNaN(y = parseInt(x)) ? 0 : y); +} +Number.prototype.Timer = function(s, iT, bUrge) +{ + if(!this.value || bUrge) + this.value = window.setTimeout(s, iT); +} +Number.prototype.EndTimer = function() +{ + if(this.value) + { + window.clearTimeout(this.value); + this.value = 0; + } +} +function tt_SetOpa(el, opa) +{ + var css = el.style; + + tt_opa = opa; + if(tt_flagOpa == 1) + { + if(opa < 100) + { + // Hacks for bugs of IE: + // 1.) Once a CSS filter has been applied, fonts are no longer + // anti-aliased, so we store the previous 'non-filter' to be + // able to restore it + if(typeof(el.filtNo) == tt_u) + el.filtNo = css.filter; + // 2.) A DIV cannot be made visible in a single step if an + // opacity < 100 has been applied while the DIV was hidden + var bVis = css.visibility != "hidden"; + // 3.) In IE6, applying an opacity < 100 has no effect if the + // element has no layout (position, size, zoom, ...) + css.zoom = "100%"; + if(!bVis) + css.visibility = "visible"; + css.filter = "alpha(opacity=" + opa + ")"; + if(!bVis) + css.visibility = "hidden"; + } + else if(typeof(el.filtNo) != tt_u) + // Restore 'non-filter' + css.filter = el.filtNo; + } + else + { + opa /= 100.0; + switch(tt_flagOpa) + { + case 2: + css.KhtmlOpacity = opa; break; + case 3: + css.KHTMLOpacity = opa; break; + case 4: + css.MozOpacity = opa; break; + case 5: + css.opacity = opa; break; + } + } +} +function tt_MovDomNode(el, dadFrom, dadTo) +{ + if(dadFrom) + dadFrom.removeChild(el); + if(dadTo) + dadTo.appendChild(el); +} +function tt_Err(sErr, bIfDebug) +{ + if(tt_Debug || !bIfDebug) + alert("Tooltip Script Error Message:\n\n" + sErr); +} + +//============ EXTENSION (PLUGIN) MANAGER ===============// +function tt_ExtCmdEnum() +{ + var s; + + // Add new command(s) to the commands enum + for(var i in config) + { + s = "window." + i.toString().toUpperCase(); + if(eval("typeof(" + s + ") == tt_u")) + { + eval(s + " = " + tt_aV.length); + tt_aV[tt_aV.length] = null; + } + } +} +function tt_ExtCallFncs(arg, sFnc) +{ + var b = false; + for(var i = tt_aExt.length; i;) + {--i; + var fnc = tt_aExt[i]["On" + sFnc]; + // Call the method the extension has defined for this event + if(fnc && fnc(arg)) + b = true; + } + return b; +} + +tt_Init(); diff --git a/web/reakfavicon.ico b/web/reakfavicon.ico new file mode 100644 index 0000000..1495ee6 Binary files /dev/null and b/web/reakfavicon.ico differ diff --git a/web/reaktor.php b/web/reaktor.php new file mode 100644 index 0000000..8c67bac --- /dev/null +++ b/web/reaktor.php @@ -0,0 +1,21 @@ + + * @author Russ Flynn + * @copyright 2008 Linpro AS + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + */ + +define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..')); +define('SF_APP', 'reaktor'); +define('SF_ENVIRONMENT', 'prod'); +define('SF_DEBUG', false); + +require_once SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php'; + +sfContext::getInstance()->getController()->dispatch(); \ No newline at end of file diff --git a/web/robots.txt b/web/robots.txt new file mode 100644 index 0000000..6e5949b --- /dev/null +++ b/web/robots.txt @@ -0,0 +1,12 @@ +# NOTE! We do not want any robots to index the development server. However, we do want this +# in the production environment, which this file must be updated when it comes to it + +# +# Address all robots by using wildcard +# +User-agent: * + +# +# Do not index any of the pages +# +Disallow: / diff --git a/web/sf/calendar/calendar-setup.js b/web/sf/calendar/calendar-setup.js new file mode 100644 index 0000000..0af6a90 --- /dev/null +++ b/web/sf/calendar/calendar-setup.js @@ -0,0 +1,203 @@ +/* Copyright Mihai Bazon, 2002, 2003 | http://dynarch.com/mishoo/ + * --------------------------------------------------------------------------- + * + * The DHTML Calendar + * + * Details and latest version at: + * http://dynarch.com/mishoo/calendar.epl + * + * This script is distributed under the GNU Lesser General Public License. + * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html + * + * This file defines helper functions for setting up the calendar. They are + * intended to help non-programmers get a working calendar on their site + * quickly. This script should not be seen as part of the calendar. It just + * shows you what one can do with the calendar, while in the same time + * providing a quick and simple method for setting it up. If you need + * exhaustive customization of the calendar creation process feel free to + * modify this code to suit your needs (this is recommended and much better + * than modifying calendar.js itself). + */ + +// $Id: calendar-setup.js 3016 2006-12-11 12:49:54Z chtito $ + +/** + * This function "patches" an input field (or other element) to use a calendar + * widget for date selection. + * + * The "params" is a single object that can have the following properties: + * + * prop. name | description + * ------------------------------------------------------------------------------------------------- + * inputField | the ID of an input field to store the date + * displayArea | the ID of a DIV or other element to show the date + * button | ID of a button or other element that will trigger the calendar + * eventName | event that will trigger the calendar, without the "on" prefix (default: "click") + * ifFormat | date format that will be stored in the input field + * daFormat | the date format that will be used to display the date in displayArea + * singleClick | (true/false) wether the calendar is in single click mode or not (default: true) + * firstDay | numeric: 0 to 6. "0" means display Sunday first, "1" means display Monday first, etc. + * align | alignment (default: "Br"); if you don't know what's this see the calendar documentation + * range | array with 2 elements. Default: [1900, 2999] -- the range of years available + * weekNumbers | (true/false) if it's true (default) the calendar will display week numbers + * flat | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID + * flatCallback | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar) + * disableFunc | function that receives a JS Date object and should return true if that date has to be disabled in the calendar + * onSelect | function that gets called when a date is selected. You don't _have_ to supply this (the default is generally okay) + * onClose | function that gets called when the calendar is closed. [default] + * onUpdate | function that gets called after the date is updated in the input field. Receives a reference to the calendar. + * date | the date that the calendar will be initially displayed to + * showsTime | default: false; if true the calendar will include a time selector + * timeFormat | the time format; can be "12" or "24", default is "12" + * electric | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close + * step | configures the step of the years in drop-down boxes; default: 2 + * position | configures the calendar absolute position; default: null + * cache | if "true" (but default: "false") it will reuse the same calendar object, where possible + * showOthers | if "true" (but default: "false") it will show days from other months too + * + * None of them is required, they all have default values. However, if you + * pass none of "inputField", "displayArea" or "button" you'll get a warning + * saying "nothing to setup". + */ +Calendar.setup = function (params) { + function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } }; + + param_default("inputField", null); + param_default("displayArea", null); + param_default("button", null); + param_default("eventName", "click"); + param_default("ifFormat", "%Y/%m/%d"); + param_default("daFormat", "%Y/%m/%d"); + param_default("singleClick", true); + param_default("disableFunc", null); + param_default("dateStatusFunc", params["disableFunc"]); // takes precedence if both are defined + param_default("dateTooltipFunc", null); + param_default("dateText", null); + param_default("firstDay", null); + param_default("align", "Br"); + param_default("range", [0000, 2999]); + param_default("weekNumbers", true); + param_default("flat", null); + param_default("flatCallback", null); + param_default("onSelect", null); + param_default("onClose", null); + param_default("onUpdate", null); + param_default("date", null); + param_default("showsTime", false); + param_default("timeFormat", "24"); + param_default("electric", true); + param_default("step", 2); + param_default("position", null); + param_default("cache", false); + param_default("showOthers", false); + param_default("multiple", null); + + var tmp = ["inputField", "displayArea", "button"]; + for (var i in tmp) { + if (typeof params[tmp[i]] == "string") { + params[tmp[i]] = document.getElementById(params[tmp[i]]); + } + } + if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) { + alert("Calendar.setup:\n Nothing to setup (no fields found). Please check your code"); + return false; + } + + function onSelect(cal) { + var p = cal.params; + var update = (cal.dateClicked || p.electric); + if (update && p.inputField) { + p.inputField.value = cal.date.print(p.ifFormat); + if (typeof p.inputField.onchange == "function") + p.inputField.onchange(); + } + if (update && p.displayArea) + p.displayArea.innerHTML = cal.date.print(p.daFormat); + if (update && typeof p.onUpdate == "function") + p.onUpdate(cal); + if (update && p.flat) { + if (typeof p.flatCallback == "function") + p.flatCallback(cal); + } + if (update && p.singleClick && cal.dateClicked) + cal.callCloseHandler(); + }; + + if (params.flat != null) { + if (typeof params.flat == "string") + params.flat = document.getElementById(params.flat); + if (!params.flat) { + alert("Calendar.setup:\n Flat specified but can't find parent."); + return false; + } + var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect); + cal.setDateToolTipHandler(params.dateTooltipFunc); + cal.showsOtherMonths = params.showOthers; + cal.showsTime = params.showsTime; + cal.time24 = (params.timeFormat == "24"); + cal.params = params; + cal.weekNumbers = params.weekNumbers; + cal.setRange(params.range[0], params.range[1]); + cal.setDateStatusHandler(params.dateStatusFunc); + cal.getDateText = params.dateText; + if (params.ifFormat) { + cal.setDateFormat(params.ifFormat); + } + if (params.inputField && typeof params.inputField.value == "string") { + cal.parseDate(params.inputField.value); + } + cal.create(params.flat); + cal.show(); + return false; + } + + var triggerEl = params.button || params.displayArea || params.inputField; + triggerEl["on" + params.eventName] = function() { + var dateEl = params.inputField || params.displayArea; + var dateFmt = params.inputField ? params.ifFormat : params.daFormat; + var mustCreate = false; + var cal = window.calendar; + if (dateEl) + params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt); + if (!(cal && params.cache)) { + window.calendar = cal = new Calendar(params.firstDay, + params.date, + params.onSelect || onSelect, + params.onClose || function(cal) { cal.hide(); }); + cal.setDateToolTipHandler(params.dateTooltipFunc); + cal.showsTime = params.showsTime; + cal.time24 = (params.timeFormat == "24"); + cal.weekNumbers = params.weekNumbers; + mustCreate = true; + } else { + if (params.date) + cal.setDate(params.date); + cal.hide(); + } + if (params.multiple) { + cal.multiple = {}; + for (var i = params.multiple.length; --i >= 0;) { + var d = params.multiple[i]; + var ds = d.print("%Y%m%d"); + cal.multiple[ds] = d; + } + } + cal.showsOtherMonths = params.showOthers; + cal.yearStep = params.step; + cal.setRange(params.range[0], params.range[1]); + cal.params = params; + cal.setDateStatusHandler(params.dateStatusFunc); + cal.getDateText = params.dateText; + cal.setDateFormat(dateFmt); + if (mustCreate) + cal.create(); + cal.refresh(); + if (!params.position) + cal.showAtElement(params.button || params.displayArea || params.inputField, params.align); + else + cal.showAt(params.position[0], params.position[1]); + return false; + }; + + return cal; +}; diff --git a/web/sf/calendar/calendar-system.css b/web/sf/calendar/calendar-system.css new file mode 100644 index 0000000..d9e47aa --- /dev/null +++ b/web/sf/calendar/calendar-system.css @@ -0,0 +1,252 @@ +/* The main calendar widget. DIV containing a table. */ + +.calendar { + position: relative; + display: none; + border: 1px solid; + border-color: #fff #000 #000 #fff; + font-size: 11px; + cursor: default; + background: Window; + color: WindowText; + font-family: tahoma,verdana,sans-serif; + z-index: 10; +} + +.calendar table { + border: 1px solid; + border-color: #fff #000 #000 #fff; + font-size: 11px; + cursor: default; + background: Window; + color: WindowText; + font-family: tahoma,verdana,sans-serif; +} + +/* Header part -- contains navigation buttons and day names. */ + +.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ + text-align: center; + padding: 1px; + border: 1px solid; + border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; + background: ButtonFace; +} + +.calendar .nav { + background: ButtonFace url(menuarrow.gif) no-repeat 100% 100%; +} + +.calendar thead .title { /* This holds the current "month, year" */ + font-weight: bold; + padding: 1px; + border: 1px solid #000; + background: ActiveCaption; + color: CaptionText; + text-align: center; +} + +.calendar thead .headrow { /* Row containing navigation buttons */ +} + +.calendar thead .daynames { /* Row containing the day names */ +} + +.calendar thead .name { /* Cells containing the day names */ + border-bottom: 1px solid ButtonShadow; + padding: 2px; + text-align: center; + background: ButtonFace; + color: ButtonText; +} + +.calendar thead .weekend { /* How a weekend day name shows in header */ + color: #f00; +} + +.calendar thead .hilite { /* How do the buttons in header appear when hover */ + border: 2px solid; + padding: 0px; + border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; +} + +.calendar thead .active { /* Active (pressed) buttons in header */ + border-width: 1px; + padding: 2px 0px 0px 2px; + border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; +} + +/* The body part -- contains all the days in month. */ + +.calendar tbody .day { /* Cells containing month days dates */ + width: 2em; + text-align: right; + padding: 2px 4px 2px 2px; +} +.calendar tbody .day.othermonth { + font-size: 80%; + color: #aaa; +} +.calendar tbody .day.othermonth.oweekend { + color: #faa; +} + +.calendar table .wn { + padding: 2px 3px 2px 2px; + border-right: 1px solid ButtonShadow; + background: ButtonFace; + color: ButtonText; +} + +.calendar tbody .rowhilite td { + background: Highlight; + color: HighlightText; +} + +.calendar tbody td.hilite { /* Hovered cells */ + padding: 1px 3px 1px 1px; + border-top: 1px solid #fff; + border-right: 1px solid #000; + border-bottom: 1px solid #000; + border-left: 1px solid #fff; +} + +.calendar tbody td.active { /* Active (pressed) cells */ + padding: 2px 2px 0px 2px; + border: 1px solid; + border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; +} + +.calendar tbody td.selected { /* Cell showing selected date */ + font-weight: bold; + border: 1px solid; + border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; + padding: 2px 2px 0px 2px; + background: ButtonFace; + color: ButtonText; +} + +.calendar tbody td.weekend { /* Cells showing weekend days */ + color: #f00; +} + +.calendar tbody td.today { /* Cell showing today date */ + font-weight: bold; + color: #00f; +} + +.calendar tbody td.disabled { color: GrayText; } + +.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ + visibility: hidden; +} + +.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ + display: none; +} + +/* The footer part -- status bar and "Close" button */ + +.calendar tfoot .footrow { /* The in footer (only one right now) */ +} + +.calendar tfoot .ttip { /* Tooltip (status bar) cell */ + background: ButtonFace; + padding: 1px; + border: 1px solid; + border-color: ButtonShadow ButtonHighlight ButtonHighlight ButtonShadow; + color: ButtonText; + text-align: center; +} + +.calendar tfoot .hilite { /* Hover style for buttons in footer */ + border-top: 1px solid #fff; + border-right: 1px solid #000; + border-bottom: 1px solid #000; + border-left: 1px solid #fff; + padding: 1px; + background: #e4e0d8; +} + +.calendar tfoot .active { /* Active (pressed) style for buttons in footer */ + padding: 2px 0px 0px 2px; + border-top: 1px solid #000; + border-right: 1px solid #fff; + border-bottom: 1px solid #fff; + border-left: 1px solid #000; +} + +/* Combo boxes (menus that display months/years for direct selection) */ + +.calendar .combo { + position: absolute; + display: none; + width: 4em; + top: 0px; + left: 0px; + cursor: default; + border: 1px solid; + border-color: ButtonHighlight ButtonShadow ButtonShadow ButtonHighlight; + background: Menu; + color: MenuText; + font-size: 90%; + padding: 1px; + z-index: 100; +} + +.calendar .combo .label, +.calendar .combo .label-IEfix { + text-align: center; + padding: 1px; +} + +.calendar .combo .label-IEfix { + width: 4em; +} + +.calendar .combo .active { + padding: 0px; + border: 1px solid #000; +} + +.calendar .combo .hilite { + background: Highlight; + color: HighlightText; +} + +.calendar td.time { + border-top: 1px solid ButtonShadow; + padding: 1px 0px; + text-align: center; + background-color: ButtonFace; +} + +.calendar td.time .hour, +.calendar td.time .minute, +.calendar td.time .ampm { + padding: 0px 3px 0px 4px; + border: 1px solid #889; + font-weight: bold; + background-color: Menu; +} + +.calendar td.time .ampm { + text-align: center; +} + +.calendar td.time .colon { + padding: 0px 2px 0px 3px; + font-weight: bold; +} + +.calendar td.time span.hilite { + border-color: #000; + background-color: Highlight; + color: HighlightText; +} + +.calendar td.time span.active { + border-color: #f00; + background-color: #000; + color: #0f0; +} diff --git a/web/sf/calendar/calendar.js b/web/sf/calendar/calendar.js new file mode 100644 index 0000000..c11899a --- /dev/null +++ b/web/sf/calendar/calendar.js @@ -0,0 +1,1809 @@ +/* Copyright Mihai Bazon, 2002-2005 | www.bazon.net/mishoo + * ----------------------------------------------------------- + * + * The DHTML Calendar, version 1.0 "It is happening again" + * + * Details and latest version at: + * www.dynarch.com/projects/calendar + * + * This script is developed by Dynarch.com. Visit us at www.dynarch.com. + * + * This script is distributed under the GNU Lesser General Public License. + * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html + */ + +// $Id: calendar.js 3060 2006-12-17 06:06:52Z chtito $ + +/** The Calendar object constructor. */ +Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) { + // member variables + this.activeDiv = null; + this.currentDateEl = null; + this.getDateStatus = null; + this.getDateToolTip = null; + this.getDateText = null; + this.timeout = null; + this.onSelected = onSelected || null; + this.onClose = onClose || null; + this.dragging = false; + this.hidden = false; + this.minYear = 1970; + this.maxYear = 2050; + this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"]; + this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"]; + this.isPopup = true; + this.weekNumbers = true; + this.firstDayOfWeek = typeof firstDayOfWeek == "number" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc. + this.showsOtherMonths = false; + this.dateStr = dateStr; + this.ar_days = null; + this.showsTime = false; + this.time24 = true; + this.yearStep = 2; + this.hiliteToday = true; + this.multiple = null; + // HTML elements + this.table = null; + this.element = null; + this.tbody = null; + this.firstdayname = null; + // Combo boxes + this.monthsCombo = null; + this.yearsCombo = null; + this.hilitedMonth = null; + this.activeMonth = null; + this.hilitedYear = null; + this.activeYear = null; + // Information + this.dateClicked = false; + + // one-time initializations + if (typeof Calendar._SDN == "undefined") { + // table of short day names + if (typeof Calendar._SDN_len == "undefined") + Calendar._SDN_len = 3; + var ar = new Array(); + for (var i = 8; i > 0;) { + ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len); + } + Calendar._SDN = ar; + // table of short month names + if (typeof Calendar._SMN_len == "undefined") + Calendar._SMN_len = 3; + ar = new Array(); + for (var i = 12; i > 0;) { + ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len); + } + Calendar._SMN = ar; + } +}; + +// ** constants + +/// "static", needed for event handlers. +Calendar._C = null; + +/// detect a special case of "web browser" +Calendar.is_ie = ( /msie/i.test(navigator.userAgent) && + !/opera/i.test(navigator.userAgent) ); + +Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) ); + +/// detect Opera browser +Calendar.is_opera = /opera/i.test(navigator.userAgent); + +/// detect KHTML-based browsers +Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent); + +// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate +// library, at some point. + +Calendar.getAbsolutePos = function(el) { + var SL = 0, ST = 0; + var is_div = /^div$/i.test(el.tagName); + if (is_div && el.scrollLeft) + SL = el.scrollLeft; + if (is_div && el.scrollTop) + ST = el.scrollTop; + var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST }; + if (el.offsetParent) { + var tmp = this.getAbsolutePos(el.offsetParent); + r.x += tmp.x; + r.y += tmp.y; + } + return r; +}; + +Calendar.isRelated = function (el, evt) { + var related = evt.relatedTarget; + if (!related) { + var type = evt.type; + if (type == "mouseover") { + related = evt.fromElement; + } else if (type == "mouseout") { + related = evt.toElement; + } + } + while (related) { + if (related == el) { + return true; + } + related = related.parentNode; + } + return false; +}; + +Calendar.removeClass = function(el, className) { + if (!(el && el.className)) { + return; + } + var cls = el.className.split(" "); + var ar = new Array(); + for (var i = cls.length; i > 0;) { + if (cls[--i] != className) { + ar[ar.length] = cls[i]; + } + } + el.className = ar.join(" "); +}; + +Calendar.addClass = function(el, className) { + Calendar.removeClass(el, className); + el.className += " " + className; +}; + +// FIXME: the following 2 functions totally suck, are useless and should be replaced immediately. +Calendar.getElement = function(ev) { + var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget; + while (f.nodeType != 1 || /^div$/i.test(f.tagName)) + f = f.parentNode; + return f; +}; + +Calendar.getTargetElement = function(ev) { + var f = Calendar.is_ie ? window.event.srcElement : ev.target; + while (f.nodeType != 1) + f = f.parentNode; + return f; +}; + +Calendar.stopEvent = function(ev) { + ev || (ev = window.event); + if (Calendar.is_ie) { + ev.cancelBubble = true; + ev.returnValue = false; + } else { + ev.preventDefault(); + ev.stopPropagation(); + } + return false; +}; + +Calendar.addEvent = function(el, evname, func) { + if (el.attachEvent) { // IE + el.attachEvent("on" + evname, func); + } else if (el.addEventListener) { // Gecko / W3C + el.addEventListener(evname, func, true); + } else { + el["on" + evname] = func; + } +}; + +Calendar.removeEvent = function(el, evname, func) { + if (el.detachEvent) { // IE + el.detachEvent("on" + evname, func); + } else if (el.removeEventListener) { // Gecko / W3C + el.removeEventListener(evname, func, true); + } else { + el["on" + evname] = null; + } +}; + +Calendar.createElement = function(type, parent) { + var el = null; + if (document.createElementNS) { + // use the XHTML namespace; IE won't normally get here unless + // _they_ "fix" the DOM2 implementation. + el = document.createElementNS("http://www.w3.org/1999/xhtml", type); + } else { + el = document.createElement(type); + } + if (typeof parent != "undefined") { + parent.appendChild(el); + } + return el; +}; + +// END: UTILITY FUNCTIONS + +// BEGIN: CALENDAR STATIC FUNCTIONS + +/** Internal -- adds a set of events to make some element behave like a button. */ +Calendar._add_evs = function(el) { + with (Calendar) { + addEvent(el, "mouseover", dayMouseOver); + addEvent(el, "mousedown", dayMouseDown); + addEvent(el, "mouseout", dayMouseOut); + if (is_ie) { + addEvent(el, "dblclick", dayMouseDblClick); + el.setAttribute("unselectable", true); + } + } +}; + +Calendar.findMonth = function(el) { + if (typeof el.month != "undefined") { + return el; + } else if (typeof el.parentNode.month != "undefined") { + return el.parentNode; + } + return null; +}; + +Calendar.findYear = function(el) { + if (typeof el.year != "undefined") { + return el; + } else if (typeof el.parentNode.year != "undefined") { + return el.parentNode; + } + return null; +}; + +Calendar.showMonthsCombo = function () { + var cal = Calendar._C; + if (!cal) { + return false; + } + var cal = cal; + var cd = cal.activeDiv; + var mc = cal.monthsCombo; + if (cal.hilitedMonth) { + Calendar.removeClass(cal.hilitedMonth, "hilite"); + } + if (cal.activeMonth) { + Calendar.removeClass(cal.activeMonth, "active"); + } + var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()]; + Calendar.addClass(mon, "active"); + cal.activeMonth = mon; + var s = mc.style; + s.display = "block"; + if (cd.navtype < 0) + s.left = cd.offsetLeft + "px"; + else { + var mcw = mc.offsetWidth; + if (typeof mcw == "undefined") + // Konqueror brain-dead techniques + mcw = 50; + s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px"; + } + s.top = (cd.offsetTop + cd.offsetHeight) + "px"; +}; + +Calendar.showYearsCombo = function (fwd) { + var cal = Calendar._C; + if (!cal) { + return false; + } + var cal = cal; + var cd = cal.activeDiv; + var yc = cal.yearsCombo; + if (cal.hilitedYear) { + Calendar.removeClass(cal.hilitedYear, "hilite"); + } + if (cal.activeYear) { + Calendar.removeClass(cal.activeYear, "active"); + } + cal.activeYear = null; + var Y = cal.date.getFullYear() + (fwd ? 1 : -1); + var yr = yc.firstChild; + var show = false; + for (var i = 12; i > 0; --i) { + if (Y >= cal.minYear && Y <= cal.maxYear) { + yr.innerHTML = Y; + yr.year = Y; + yr.style.display = "block"; + show = true; + } else { + yr.style.display = "none"; + } + yr = yr.nextSibling; + Y += fwd ? cal.yearStep : -cal.yearStep; + } + if (show) { + var s = yc.style; + s.display = "block"; + if (cd.navtype < 0) + s.left = cd.offsetLeft + "px"; + else { + var ycw = yc.offsetWidth; + if (typeof ycw == "undefined") + // Konqueror brain-dead techniques + ycw = 50; + s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px"; + } + s.top = (cd.offsetTop + cd.offsetHeight) + "px"; + } +}; + +// event handlers + +Calendar.tableMouseUp = function(ev) { + var cal = Calendar._C; + if (!cal) { + return false; + } + if (cal.timeout) { + clearTimeout(cal.timeout); + } + var el = cal.activeDiv; + if (!el) { + return false; + } + var target = Calendar.getTargetElement(ev); + ev || (ev = window.event); + Calendar.removeClass(el, "active"); + if (target == el || target.parentNode == el) { + Calendar.cellClick(el, ev); + } + var mon = Calendar.findMonth(target); + var date = null; + if (mon) { + date = new Date(cal.date); + if (mon.month != date.getMonth()) { + date.setMonth(mon.month); + cal.setDate(date); + cal.dateClicked = false; + cal.callHandler(); + } + } else { + var year = Calendar.findYear(target); + if (year) { + date = new Date(cal.date); + if (year.year != date.getFullYear()) { + date.setFullYear(year.year); + cal.setDate(date); + cal.dateClicked = false; + cal.callHandler(); + } + } + } + with (Calendar) { + removeEvent(document, "mouseup", tableMouseUp); + removeEvent(document, "mouseover", tableMouseOver); + removeEvent(document, "mousemove", tableMouseOver); + cal._hideCombos(); + _C = null; + return stopEvent(ev); + } +}; + +Calendar.tableMouseOver = function (ev) { + var cal = Calendar._C; + if (!cal) { + return; + } + var el = cal.activeDiv; + var target = Calendar.getTargetElement(ev); + if (target == el || target.parentNode == el) { + Calendar.addClass(el, "hilite active"); + Calendar.addClass(el.parentNode, "rowhilite"); + } else { + if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2))) + Calendar.removeClass(el, "active"); + Calendar.removeClass(el, "hilite"); + Calendar.removeClass(el.parentNode, "rowhilite"); + } + ev || (ev = window.event); + if (el.navtype == 50 && target != el) { + var pos = Calendar.getAbsolutePos(el); + var w = el.offsetWidth; + var x = ev.clientX; + var dx; + var decrease = true; + if (x > pos.x + w) { + dx = x - pos.x - w; + decrease = false; + } else + dx = pos.x - x; + + if (dx < 0) dx = 0; + var range = el._range; + var current = el._current; + var count = Math.floor(dx / 10) % range.length; + for (var i = range.length; --i >= 0;) + if (range[i] == current) + break; + while (count-- > 0) + if (decrease) { + if (--i < 0) + i = range.length - 1; + } else if ( ++i >= range.length ) + i = 0; + var newval = range[i]; + el.innerHTML = newval; + + cal.onUpdateTime(); + } + var mon = Calendar.findMonth(target); + if (mon) { + if (mon.month != cal.date.getMonth()) { + if (cal.hilitedMonth) { + Calendar.removeClass(cal.hilitedMonth, "hilite"); + } + Calendar.addClass(mon, "hilite"); + cal.hilitedMonth = mon; + } else if (cal.hilitedMonth) { + Calendar.removeClass(cal.hilitedMonth, "hilite"); + } + } else { + if (cal.hilitedMonth) { + Calendar.removeClass(cal.hilitedMonth, "hilite"); + } + var year = Calendar.findYear(target); + if (year) { + if (year.year != cal.date.getFullYear()) { + if (cal.hilitedYear) { + Calendar.removeClass(cal.hilitedYear, "hilite"); + } + Calendar.addClass(year, "hilite"); + cal.hilitedYear = year; + } else if (cal.hilitedYear) { + Calendar.removeClass(cal.hilitedYear, "hilite"); + } + } else if (cal.hilitedYear) { + Calendar.removeClass(cal.hilitedYear, "hilite"); + } + } + return Calendar.stopEvent(ev); +}; + +Calendar.tableMouseDown = function (ev) { + if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) { + return Calendar.stopEvent(ev); + } +}; + +Calendar.calDragIt = function (ev) { + var cal = Calendar._C; + if (!(cal && cal.dragging)) { + return false; + } + var posX; + var posY; + if (Calendar.is_ie) { + posY = window.event.clientY + document.body.scrollTop; + posX = window.event.clientX + document.body.scrollLeft; + } else { + posX = ev.pageX; + posY = ev.pageY; + } + cal.hideShowCovered(); + var st = cal.element.style; + st.left = (posX - cal.xOffs) + "px"; + st.top = (posY - cal.yOffs) + "px"; + return Calendar.stopEvent(ev); +}; + +Calendar.calDragEnd = function (ev) { + var cal = Calendar._C; + if (!cal) { + return false; + } + cal.dragging = false; + with (Calendar) { + removeEvent(document, "mousemove", calDragIt); + removeEvent(document, "mouseup", calDragEnd); + tableMouseUp(ev); + } + cal.hideShowCovered(); +}; + +Calendar.dayMouseDown = function(ev) { + var el = Calendar.getElement(ev); + if (el.disabled) { + return false; + } + var cal = el.calendar; + cal.activeDiv = el; + Calendar._C = cal; + if (el.navtype != 300) with (Calendar) { + if (el.navtype == 50) { + el._current = el.innerHTML; + addEvent(document, "mousemove", tableMouseOver); + } else + addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver); + addClass(el, "hilite active"); + addEvent(document, "mouseup", tableMouseUp); + } else if (cal.isPopup) { + cal._dragStart(ev); + } + if (el.navtype == -1 || el.navtype == 1) { + if (cal.timeout) clearTimeout(cal.timeout); + cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250); + } else if (el.navtype == -2 || el.navtype == 2) { + if (cal.timeout) clearTimeout(cal.timeout); + cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250); + } else { + cal.timeout = null; + } + return Calendar.stopEvent(ev); +}; + +Calendar.dayMouseDblClick = function(ev) { + Calendar.cellClick(Calendar.getElement(ev), ev || window.event); + if (Calendar.is_ie) { + document.selection.empty(); + } +}; + +Calendar.dayMouseOver = function(ev) { + var el = Calendar.getElement(ev); + if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) { + return false; + } + if (el.ttip) { + if (el.ttip.substr(0, 1) == "_") { + el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1); + } + el.calendar.tooltips.innerHTML = el.ttip; + } + if (el.navtype != 300) { + Calendar.addClass(el, "hilite"); + if (el.caldate) { + Calendar.addClass(el.parentNode, "rowhilite"); + var cal = el.calendar; + if (cal && cal.getDateToolTip) { + var d = el.caldate; + window.status = d; + el.title = cal.getDateToolTip(d, d.getFullYear(), d.getMonth(), d.getDate()); + } + } + } + return Calendar.stopEvent(ev); +}; + +Calendar.dayMouseOut = function(ev) { + with (Calendar) { + var el = getElement(ev); + if (isRelated(el, ev) || _C || el.disabled) + return false; + removeClass(el, "hilite"); + if (el.caldate) + removeClass(el.parentNode, "rowhilite"); + if (el.calendar) + el.calendar.tooltips.innerHTML = _TT["SEL_DATE"]; + // return stopEvent(ev); + } +}; + +/** + * A generic "click" handler :) handles all types of buttons defined in this + * calendar. + */ +Calendar.cellClick = function(el, ev) { + var cal = el.calendar; + var closing = false; + var newdate = false; + var date = null; + if (typeof el.navtype == "undefined") { + if (cal.currentDateEl) { + Calendar.removeClass(cal.currentDateEl, "selected"); + Calendar.addClass(el, "selected"); + closing = (cal.currentDateEl == el); + if (!closing) { + cal.currentDateEl = el; + } + } + cal.date.setDateOnly(el.caldate); + date = cal.date; + var other_month = !(cal.dateClicked = !el.otherMonth); + if (!other_month && !cal.currentDateEl && cal.multiple) + cal._toggleMultipleDate(new Date(date)); + else + newdate = !el.disabled; + // a date was clicked + if (other_month) + cal._init(cal.firstDayOfWeek, date); + } else { + if (el.navtype == 200) { + Calendar.removeClass(el, "hilite"); + cal.callCloseHandler(); + return; + } + date = new Date(cal.date); + if (el.navtype == 0) + date.setDateOnly(new Date()); // TODAY + // unless "today" was clicked, we assume no date was clicked so + // the selected handler will know not to close the calenar when + // in single-click mode. + // cal.dateClicked = (el.navtype == 0); + cal.dateClicked = false; + var year = date.getFullYear(); + var mon = date.getMonth(); + function setMonth(m) { + var day = date.getDate(); + var max = date.getMonthDays(m); + if (day > max) { + date.setDate(max); + } + date.setMonth(m); + }; + switch (el.navtype) { + case 400: + Calendar.removeClass(el, "hilite"); + var text = Calendar._TT["ABOUT"]; + if (typeof text != "undefined") { + text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : ""; + } else { + // FIXME: this should be removed as soon as lang files get updated! + text = "Help and about box text is not translated into this language.\n" + + "If you know this language and you feel generous please update\n" + + "the corresponding file in \"lang\" subdir to match calendar-en.js\n" + + "and send it back to to get it into the distribution ;-)\n\n" + + "Thank you!\n" + + "http://dynarch.com/mishoo/calendar.epl\n"; + } + alert(text); + return; + case -2: + if (year > cal.minYear) { + date.setFullYear(year - 1); + } + break; + case -1: + if (mon > 0) { + setMonth(mon - 1); + } else if (year-- > cal.minYear) { + date.setFullYear(year); + setMonth(11); + } + break; + case 1: + if (mon < 11) { + setMonth(mon + 1); + } else if (year < cal.maxYear) { + date.setFullYear(year + 1); + setMonth(0); + } + break; + case 2: + if (year < cal.maxYear) { + date.setFullYear(year + 1); + } + break; + case 100: + cal.setFirstDayOfWeek(el.fdow); + return; + case 50: + var range = el._range; + var current = el.innerHTML; + for (var i = range.length; --i >= 0;) + if (range[i] == current) + break; + if (ev && ev.shiftKey) { + if (--i < 0) + i = range.length - 1; + } else if ( ++i >= range.length ) + i = 0; + var newval = range[i]; + el.innerHTML = newval; + cal.onUpdateTime(); + return; + case 0: + // TODAY will bring us here + if ((typeof cal.getDateStatus == "function") && + cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) { + return false; + } + break; + } + if (!date.equalsTo(cal.date)) { + cal.setDate(date); + newdate = true; + } else if (el.navtype == 0) + newdate = closing = true; + } + if (newdate) { + ev && cal.callHandler(); + } + if (closing) { + Calendar.removeClass(el, "hilite"); + ev && cal.callCloseHandler(); + } +}; + +// END: CALENDAR STATIC FUNCTIONS + +// BEGIN: CALENDAR OBJECT FUNCTIONS + +/** + * This function creates the calendar inside the given parent. If _par is + * null than it creates a popup calendar inside the BODY element. If _par is + * an element, be it BODY, then it creates a non-popup calendar (still + * hidden). Some properties need to be set before calling this function. + */ +Calendar.prototype.create = function (_par) { + var parent = null; + if (! _par) { + // default parent is the document body, in which case we create + // a popup calendar. + parent = document.getElementsByTagName("body")[0]; + this.isPopup = true; + } else { + parent = _par; + this.isPopup = false; + } + this.date = this.dateStr ? new Date(this.dateStr) : new Date(); + + var table = Calendar.createElement("table"); + this.table = table; + table.cellSpacing = 0; + table.cellPadding = 0; + table.calendar = this; + Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown); + + var div = Calendar.createElement("div"); + this.element = div; + div.className = "calendar"; + if (this.isPopup) { + div.style.position = "absolute"; + div.style.display = "none"; + } + div.appendChild(table); + + var thead = Calendar.createElement("thead", table); + var cell = null; + var row = null; + + var cal = this; + var hh = function (text, cs, navtype) { + cell = Calendar.createElement("td", row); + cell.colSpan = cs; + cell.className = "button"; + if (navtype != 0 && Math.abs(navtype) <= 2) + cell.className += " nav"; + Calendar._add_evs(cell); + cell.calendar = cal; + cell.navtype = navtype; + cell.innerHTML = "
    " + text + "
    "; + return cell; + }; + + row = Calendar.createElement("tr", thead); + var title_length = 6; + (this.isPopup) && --title_length; + (this.weekNumbers) && ++title_length; + + hh("?", 1, 400).ttip = Calendar._TT["INFO"]; + this.title = hh("", title_length, 300); + this.title.className = "title"; + if (this.isPopup) { + this.title.ttip = Calendar._TT["DRAG_TO_MOVE"]; + this.title.style.cursor = "move"; + hh("×", 1, 200).ttip = Calendar._TT["CLOSE"]; + } + + row = Calendar.createElement("tr", thead); + row.className = "headrow"; + + this._nav_py = hh("«", 1, -2); + this._nav_py.ttip = Calendar._TT["PREV_YEAR"]; + + this._nav_pm = hh("‹", 1, -1); + this._nav_pm.ttip = Calendar._TT["PREV_MONTH"]; + + this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0); + this._nav_now.ttip = Calendar._TT["GO_TODAY"]; + + this._nav_nm = hh("›", 1, 1); + this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"]; + + this._nav_ny = hh("»", 1, 2); + this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"]; + + // day names + row = Calendar.createElement("tr", thead); + row.className = "daynames"; + if (this.weekNumbers) { + cell = Calendar.createElement("td", row); + cell.className = "name wn"; + cell.innerHTML = Calendar._TT["WK"]; + } + for (var i = 7; i > 0; --i) { + cell = Calendar.createElement("td", row); + if (!i) { + cell.navtype = 100; + cell.calendar = this; + Calendar._add_evs(cell); + } + } + this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild; + this._displayWeekdays(); + + var tbody = Calendar.createElement("tbody", table); + this.tbody = tbody; + + for (i = 6; i > 0; --i) { + row = Calendar.createElement("tr", tbody); + if (this.weekNumbers) { + cell = Calendar.createElement("td", row); + } + for (var j = 7; j > 0; --j) { + cell = Calendar.createElement("td", row); + cell.calendar = this; + Calendar._add_evs(cell); + } + } + + if (this.showsTime) { + row = Calendar.createElement("tr", tbody); + row.className = "time"; + + cell = Calendar.createElement("td", row); + cell.className = "time"; + cell.colSpan = 2; + cell.innerHTML = Calendar._TT["TIME"] || " "; + + cell = Calendar.createElement("td", row); + cell.className = "time"; + cell.colSpan = this.weekNumbers ? 4 : 3; + + (function(){ + function makeTimePart(className, init, range_start, range_end) { + var part = Calendar.createElement("span", cell); + part.className = className; + part.innerHTML = init; + part.calendar = cal; + part.ttip = Calendar._TT["TIME_PART"]; + part.navtype = 50; + part._range = []; + if (typeof range_start != "number") + part._range = range_start; + else { + for (var i = range_start; i <= range_end; ++i) { + var txt; + if (i < 10 && range_end >= 10) txt = '0' + i; + else txt = '' + i; + part._range[part._range.length] = txt; + } + } + Calendar._add_evs(part); + return part; + }; + var hrs = cal.date.getHours(); + var mins = cal.date.getMinutes(); + var t12 = !cal.time24; + var pm = (hrs > 12); + if (t12 && pm) hrs -= 12; + var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23); + var span = Calendar.createElement("span", cell); + span.innerHTML = ":"; + span.className = "colon"; + var M = makeTimePart("minute", mins, 0, 59); + var AP = null; + cell = Calendar.createElement("td", row); + cell.className = "time"; + cell.colSpan = 2; + if (t12) + AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]); + else + cell.innerHTML = " "; + + cal.onSetTime = function() { + var pm, hrs = this.date.getHours(), + mins = this.date.getMinutes(); + if (t12) { + pm = (hrs >= 12); + if (pm) hrs -= 12; + if (hrs == 0) hrs = 12; + AP.innerHTML = pm ? "pm" : "am"; + } + H.innerHTML = (hrs < 10) ? ("0" + hrs) : hrs; + M.innerHTML = (mins < 10) ? ("0" + mins) : mins; + }; + + cal.onUpdateTime = function() { + var date = this.date; + var h = parseInt(H.innerHTML, 10); + if (t12) { + if (/pm/i.test(AP.innerHTML) && h < 12) + h += 12; + else if (/am/i.test(AP.innerHTML) && h == 12) + h = 0; + } + var d = date.getDate(); + var m = date.getMonth(); + var y = date.getFullYear(); + date.setHours(h); + date.setMinutes(parseInt(M.innerHTML, 10)); + date.setFullYear(y); + date.setMonth(m); + date.setDate(d); + this.dateClicked = false; + this.callHandler(); + }; + })(); + } else { + this.onSetTime = this.onUpdateTime = function() {}; + } + + var tfoot = Calendar.createElement("tfoot", table); + + row = Calendar.createElement("tr", tfoot); + row.className = "footrow"; + + cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300); + cell.className = "ttip"; + if (this.isPopup) { + cell.ttip = Calendar._TT["DRAG_TO_MOVE"]; + cell.style.cursor = "move"; + } + this.tooltips = cell; + + div = Calendar.createElement("div", this.element); + this.monthsCombo = div; + div.className = "combo"; + for (i = 0; i < Calendar._MN.length; ++i) { + var mn = Calendar.createElement("div"); + mn.className = Calendar.is_ie ? "label-IEfix" : "label"; + mn.month = i; + mn.innerHTML = Calendar._SMN[i]; + div.appendChild(mn); + } + + div = Calendar.createElement("div", this.element); + this.yearsCombo = div; + div.className = "combo"; + for (i = 12; i > 0; --i) { + var yr = Calendar.createElement("div"); + yr.className = Calendar.is_ie ? "label-IEfix" : "label"; + div.appendChild(yr); + } + + this._init(this.firstDayOfWeek, this.date); + parent.appendChild(this.element); +}; + +/** keyboard navigation, only for popup calendars */ +Calendar._keyEvent = function(ev) { + var cal = window._dynarch_popupCalendar; + if (!cal || cal.multiple) + return false; + (Calendar.is_ie) && (ev = window.event); + var act = (Calendar.is_ie || ev.type == "keypress"), + K = ev.keyCode; + if (ev.ctrlKey) { + switch (K) { + case 37: // KEY left + act && Calendar.cellClick(cal._nav_pm); + break; + case 38: // KEY up + act && Calendar.cellClick(cal._nav_py); + break; + case 39: // KEY right + act && Calendar.cellClick(cal._nav_nm); + break; + case 40: // KEY down + act && Calendar.cellClick(cal._nav_ny); + break; + default: + return false; + } + } else switch (K) { + case 32: // KEY space (now) + Calendar.cellClick(cal._nav_now); + break; + case 27: // KEY esc + act && cal.callCloseHandler(); + break; + case 37: // KEY left + case 38: // KEY up + case 39: // KEY right + case 40: // KEY down + if (act) { + var prev, x, y, ne, el, step; + prev = K == 37 || K == 38; + step = (K == 37 || K == 39) ? 1 : 7; + function setVars() { + el = cal.currentDateEl; + var p = el.pos; + x = p & 15; + y = p >> 4; + ne = cal.ar_days[y][x]; + };setVars(); + function prevMonth() { + var date = new Date(cal.date); + date.setDate(date.getDate() - step); + cal.setDate(date); + }; + function nextMonth() { + var date = new Date(cal.date); + date.setDate(date.getDate() + step); + cal.setDate(date); + }; + while (1) { + switch (K) { + case 37: // KEY left + if (--x >= 0) + ne = cal.ar_days[y][x]; + else { + x = 6; + K = 38; + continue; + } + break; + case 38: // KEY up + if (--y >= 0) + ne = cal.ar_days[y][x]; + else { + prevMonth(); + setVars(); + } + break; + case 39: // KEY right + if (++x < 7) + ne = cal.ar_days[y][x]; + else { + x = 0; + K = 40; + continue; + } + break; + case 40: // KEY down + if (++y < cal.ar_days.length) + ne = cal.ar_days[y][x]; + else { + nextMonth(); + setVars(); + } + break; + } + break; + } + if (ne) { + if (!ne.disabled) + Calendar.cellClick(ne); + else if (prev) + prevMonth(); + else + nextMonth(); + } + } + break; + case 13: // KEY enter + if (act) + Calendar.cellClick(cal.currentDateEl, ev); + break; + default: + return false; + } + return Calendar.stopEvent(ev); +}; + +/** + * (RE)Initializes the calendar to the given date and firstDayOfWeek + */ +Calendar.prototype._init = function (firstDayOfWeek, date) { + var today = new Date(), + TY = today.getFullYear(), + TM = today.getMonth(), + TD = today.getDate(); + this.table.style.visibility = "hidden"; + var year = date.getFullYear(); + if (year < this.minYear) { + year = this.minYear; + date.setFullYear(year); + } else if (year > this.maxYear) { + year = this.maxYear; + date.setFullYear(year); + } + this.firstDayOfWeek = firstDayOfWeek; + this.date = new Date(date); + var month = date.getMonth(); + var mday = date.getDate(); + var no_days = date.getMonthDays(); + + // calendar voodoo for computing the first day that would actually be + // displayed in the calendar, even if it's from the previous month. + // WARNING: this is magic. ;-) + date.setDate(1); + var day1 = (date.getDay() - this.firstDayOfWeek) % 7; + if (day1 < 0) + day1 += 7; + date.setDate(-day1); + date.setDate(date.getDate() + 1); + + var row = this.tbody.firstChild; + var MN = Calendar._SMN[month]; + var ar_days = this.ar_days = new Array(); + var weekend = Calendar._TT["WEEKEND"]; + var dates = this.multiple ? (this.datesCells = {}) : null; + for (var i = 0; i < 6; ++i, row = row.nextSibling) { + var cell = row.firstChild; + if (this.weekNumbers) { + cell.className = "day wn"; + cell.innerHTML = date.getWeekNumber(); + cell = cell.nextSibling; + } + row.className = "daysrow"; + var hasdays = false, iday, dpos = ar_days[i] = []; + for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) { + iday = date.getDate(); + var wday = date.getDay(); + cell.className = "day"; + cell.pos = i << 4 | j; + dpos[j] = cell; + var current_month = (date.getMonth() == month); + if (!current_month) { + if (this.showsOtherMonths) { + cell.className += " othermonth"; + cell.otherMonth = true; + } else { + cell.className = "emptycell"; + cell.innerHTML = " "; + cell.disabled = true; + continue; + } + } else { + cell.otherMonth = false; + hasdays = true; + } + cell.disabled = false; + cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday; + if (dates) + dates[date.print("%Y%m%d")] = cell; + if (this.getDateStatus) { + var status = this.getDateStatus(date, year, month, iday); + if (status === true) { + cell.className += " disabled"; + cell.disabled = true; + } else { + if (/disabled/i.test(status)) + cell.disabled = true; + cell.className += " " + status; + } + } + if (!cell.disabled) { + cell.caldate = new Date(date); + cell.ttip = "_"; + if (!this.multiple && current_month + && iday == mday && this.hiliteToday) { + cell.className += " selected"; + this.currentDateEl = cell; + } + if (date.getFullYear() == TY && + date.getMonth() == TM && + iday == TD) { + cell.className += " today"; + cell.ttip += Calendar._TT["PART_TODAY"]; + } + if (weekend.indexOf(wday.toString()) != -1) + cell.className += cell.otherMonth ? " oweekend" : " weekend"; + } + } + if (!(hasdays || this.showsOtherMonths)) + row.className = "emptyrow"; + } + this.title.innerHTML = Calendar._MN[month] + ", " + year; + this.onSetTime(); + this.table.style.visibility = "visible"; + this._initMultipleDates(); + // PROFILE + // this.tooltips.innerHTML = "Generated in " + ((new Date()) - today) + " ms"; +}; + +Calendar.prototype._initMultipleDates = function() { + if (this.multiple) { + for (var i in this.multiple) { + var cell = this.datesCells[i]; + var d = this.multiple[i]; + if (!d) + continue; + if (cell) + cell.className += " selected"; + } + } +}; + +Calendar.prototype._toggleMultipleDate = function(date) { + if (this.multiple) { + var ds = date.print("%Y%m%d"); + var cell = this.datesCells[ds]; + if (cell) { + var d = this.multiple[ds]; + if (!d) { + Calendar.addClass(cell, "selected"); + this.multiple[ds] = date; + } else { + Calendar.removeClass(cell, "selected"); + delete this.multiple[ds]; + } + } + } +}; + +Calendar.prototype.setDateToolTipHandler = function (unaryFunction) { + this.getDateToolTip = unaryFunction; +}; + +/** + * Calls _init function above for going to a certain date (but only if the + * date is different than the currently selected one). + */ +Calendar.prototype.setDate = function (date) { + if (!date.equalsTo(this.date)) { + this._init(this.firstDayOfWeek, date); + } +}; + +/** + * Refreshes the calendar. Useful if the "disabledHandler" function is + * dynamic, meaning that the list of disabled date can change at runtime. + * Just * call this function if you think that the list of disabled dates + * should * change. + */ +Calendar.prototype.refresh = function () { + this._init(this.firstDayOfWeek, this.date); +}; + +/** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */ +Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) { + this._init(firstDayOfWeek, this.date); + this._displayWeekdays(); +}; + +/** + * Allows customization of what dates are enabled. The "unaryFunction" + * parameter must be a function object that receives the date (as a JS Date + * object) and returns a boolean value. If the returned value is true then + * the passed date will be marked as disabled. + */ +Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) { + this.getDateStatus = unaryFunction; +}; + +/** Customization of allowed year range for the calendar. */ +Calendar.prototype.setRange = function (a, z) { + this.minYear = a; + this.maxYear = z; +}; + +/** Calls the first user handler (selectedHandler). */ +Calendar.prototype.callHandler = function () { + if (this.onSelected) { + this.onSelected(this, this.date.print(this.dateFormat)); + } +}; + +/** Calls the second user handler (closeHandler). */ +Calendar.prototype.callCloseHandler = function () { + if (this.onClose) { + this.onClose(this); + } + this.hideShowCovered(); +}; + +/** Removes the calendar object from the DOM tree and destroys it. */ +Calendar.prototype.destroy = function () { + var el = this.element.parentNode; + el.removeChild(this.element); + Calendar._C = null; + window._dynarch_popupCalendar = null; +}; + +/** + * Moves the calendar element to a different section in the DOM tree (changes + * its parent). + */ +Calendar.prototype.reparent = function (new_parent) { + var el = this.element; + el.parentNode.removeChild(el); + new_parent.appendChild(el); +}; + +// This gets called when the user presses a mouse button anywhere in the +// document, if the calendar is shown. If the click was outside the open +// calendar this function closes it. +Calendar._checkCalendar = function(ev) { + var calendar = window._dynarch_popupCalendar; + if (!calendar) { + return false; + } + var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev); + for (; el != null && el != calendar.element; el = el.parentNode); + if (el == null) { + // calls closeHandler which should hide the calendar. + window._dynarch_popupCalendar.callCloseHandler(); + return Calendar.stopEvent(ev); + } +}; + +/** Shows the calendar. */ +Calendar.prototype.show = function () { + var rows = this.table.getElementsByTagName("tr"); + for (var i = rows.length; i > 0;) { + var row = rows[--i]; + Calendar.removeClass(row, "rowhilite"); + var cells = row.getElementsByTagName("td"); + for (var j = cells.length; j > 0;) { + var cell = cells[--j]; + Calendar.removeClass(cell, "hilite"); + Calendar.removeClass(cell, "active"); + } + } + this.element.style.display = "block"; + this.hidden = false; + if (this.isPopup) { + window._dynarch_popupCalendar = this; + Calendar.addEvent(document, "keydown", Calendar._keyEvent); + Calendar.addEvent(document, "keypress", Calendar._keyEvent); + Calendar.addEvent(document, "mousedown", Calendar._checkCalendar); + } + this.hideShowCovered(); +}; + +/** + * Hides the calendar. Also removes any "hilite" from the class of any TD + * element. + */ +Calendar.prototype.hide = function () { + if (this.isPopup) { + Calendar.removeEvent(document, "keydown", Calendar._keyEvent); + Calendar.removeEvent(document, "keypress", Calendar._keyEvent); + Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar); + } + this.element.style.display = "none"; + this.hidden = true; + this.hideShowCovered(); +}; + +/** + * Shows the calendar at a given absolute position (beware that, depending on + * the calendar element style -- position property -- this might be relative + * to the parent's containing rectangle). + */ +Calendar.prototype.showAt = function (x, y) { + var s = this.element.style; + s.left = x + "px"; + s.top = y + "px"; + this.show(); +}; + +/** Shows the calendar near a given element. */ +Calendar.prototype.showAtElement = function (el, opts) { + var self = this; + var p = Calendar.getAbsolutePos(el); + if (!opts || typeof opts != "string") { + this.showAt(p.x, p.y + el.offsetHeight); + return true; + } + function fixPosition(box) { + if (box.x < 0) + box.x = 0; + if (box.y < 0) + box.y = 0; + var cp = document.createElement("div"); + var s = cp.style; + s.position = "absolute"; + s.right = s.bottom = s.width = s.height = "0px"; + document.body.appendChild(cp); + var br = Calendar.getAbsolutePos(cp); + document.body.removeChild(cp); + if (Calendar.is_ie) { + br.y += document.body.scrollTop; + br.x += document.body.scrollLeft; + } else { + br.y += window.scrollY; + br.x += window.scrollX; + } + var tmp = box.x + box.width - br.x; + if (tmp > 0) box.x -= tmp; + tmp = box.y + box.height - br.y; + if (tmp > 0) box.y -= tmp; + }; + this.element.style.display = "block"; + Calendar.continuation_for_the_fucking_khtml_browser = function() { + var w = self.element.offsetWidth; + var h = self.element.offsetHeight; + self.element.style.display = "none"; + var valign = opts.substr(0, 1); + var halign = "l"; + if (opts.length > 1) { + halign = opts.substr(1, 1); + } + // vertical alignment + switch (valign) { + case "T": p.y -= h; break; + case "B": p.y += el.offsetHeight; break; + case "C": p.y += (el.offsetHeight - h) / 2; break; + case "t": p.y += el.offsetHeight - h; break; + case "b": break; // already there + } + // horizontal alignment + switch (halign) { + case "L": p.x -= w; break; + case "R": p.x += el.offsetWidth; break; + case "C": p.x += (el.offsetWidth - w) / 2; break; + case "l": p.x += el.offsetWidth - w; break; + case "r": break; // already there + } + p.width = w; + p.height = h + 40; + self.monthsCombo.style.display = "none"; + fixPosition(p); + self.showAt(p.x, p.y); + }; + if (Calendar.is_khtml) + setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10); + else + Calendar.continuation_for_the_fucking_khtml_browser(); +}; + +/** Customizes the date format. */ +Calendar.prototype.setDateFormat = function (str) { + this.dateFormat = str; +}; + +/** Customizes the tooltip date format. */ +Calendar.prototype.setTtDateFormat = function (str) { + this.ttDateFormat = str; +}; + +/** + * Tries to identify the date represented in a string. If successful it also + * calls this.setDate which moves the calendar to the given date. + */ +Calendar.prototype.parseDate = function(str, fmt) { + if (!fmt) + fmt = this.dateFormat; + this.setDate(Date.parseDate(str, fmt)); +}; + +Calendar.prototype.hideShowCovered = function () { + if (!Calendar.is_ie && !Calendar.is_opera) + return; + function getVisib(obj){ + var value = obj.style.visibility; + if (!value) { + if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C + if (!Calendar.is_khtml) + value = document.defaultView. + getComputedStyle(obj, "").getPropertyValue("visibility"); + else + value = ''; + } else if (obj.currentStyle) { // IE + value = obj.currentStyle.visibility; + } else + value = ''; + } + return value; + }; + + var tags = new Array("applet", "iframe", "select"); + var el = this.element; + + var p = Calendar.getAbsolutePos(el); + var EX1 = p.x; + var EX2 = el.offsetWidth + EX1; + var EY1 = p.y; + var EY2 = el.offsetHeight + EY1; + + for (var k = tags.length; k > 0; ) { + var ar = document.getElementsByTagName(tags[--k]); + var cc = null; + + for (var i = ar.length; i > 0;) { + cc = ar[--i]; + + p = Calendar.getAbsolutePos(cc); + var CX1 = p.x; + var CX2 = cc.offsetWidth + CX1; + var CY1 = p.y; + var CY2 = cc.offsetHeight + CY1; + + if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) { + if (!cc.__msh_save_visibility) { + cc.__msh_save_visibility = getVisib(cc); + } + cc.style.visibility = cc.__msh_save_visibility; + } else { + if (!cc.__msh_save_visibility) { + cc.__msh_save_visibility = getVisib(cc); + } + cc.style.visibility = "hidden"; + } + } + } +}; + +/** Internal function; it displays the bar with the names of the weekday. */ +Calendar.prototype._displayWeekdays = function () { + var fdow = this.firstDayOfWeek; + var cell = this.firstdayname; + var weekend = Calendar._TT["WEEKEND"]; + for (var i = 0; i < 7; ++i) { + cell.className = "day name"; + var realday = (i + fdow) % 7; + if (i) { + cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]); + cell.navtype = 100; + cell.calendar = this; + cell.fdow = realday; + Calendar._add_evs(cell); + } + if (weekend.indexOf(realday.toString()) != -1) { + Calendar.addClass(cell, "weekend"); + } + cell.innerHTML = Calendar._SDN[(i + fdow) % 7]; + cell = cell.nextSibling; + } +}; + +/** Internal function. Hides all combo boxes that might be displayed. */ +Calendar.prototype._hideCombos = function () { + this.monthsCombo.style.display = "none"; + this.yearsCombo.style.display = "none"; +}; + +/** Internal function. Starts dragging the element. */ +Calendar.prototype._dragStart = function (ev) { + if (this.dragging) { + return; + } + this.dragging = true; + var posX; + var posY; + if (Calendar.is_ie) { + posY = window.event.clientY + document.body.scrollTop; + posX = window.event.clientX + document.body.scrollLeft; + } else { + posY = ev.clientY + window.scrollY; + posX = ev.clientX + window.scrollX; + } + var st = this.element.style; + this.xOffs = posX - parseInt(st.left); + this.yOffs = posY - parseInt(st.top); + with (Calendar) { + addEvent(document, "mousemove", calDragIt); + addEvent(document, "mouseup", calDragEnd); + } +}; + +// BEGIN: DATE OBJECT PATCHES + +/** Adds the number of days array to the Date object. */ +Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31); + +/** Constants used for time computations */ +Date.SECOND = 1000 /* milliseconds */; +Date.MINUTE = 60 * Date.SECOND; +Date.HOUR = 60 * Date.MINUTE; +Date.DAY = 24 * Date.HOUR; +Date.WEEK = 7 * Date.DAY; + +Date.parseDate = function(str, fmt) { + var today = new Date(); + var y = 0; + var m = -1; + var d = 0; + var a = str.split(/\W+/); + var b = fmt.match(/%./g); + var i = 0, j = 0; + var hr = 0; + var min = 0; + for (i = 0; i < a.length; ++i) { + if (!a[i]) + continue; + switch (b[i]) { + case "%d": + case "%e": + d = parseInt(a[i], 10); + break; + + case "%m": + m = parseInt(a[i], 10) - 1; + break; + + case "%Y": + case "%y": + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + break; + + case "%b": + case "%B": + for (j = 0; j < 12; ++j) { + if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } + } + break; + + case "%H": + case "%I": + case "%k": + case "%l": + hr = parseInt(a[i], 10); + break; + + case "%P": + case "%p": + if (/pm/i.test(a[i]) && hr < 12) + hr += 12; + else if (/am/i.test(a[i]) && hr >= 12) + hr -= 12; + break; + + case "%M": + min = parseInt(a[i], 10); + break; + } + } + if (isNaN(y)) y = today.getFullYear(); + if (isNaN(m)) m = today.getMonth(); + if (isNaN(d)) d = today.getDate(); + if (isNaN(hr)) hr = today.getHours(); + if (isNaN(min)) min = today.getMinutes(); + if (y != 0 && m != -1 && d != 0) + return new Date(y, m, d, hr, min, 0); + y = 0; m = -1; d = 0; + for (i = 0; i < a.length; ++i) { + if (a[i].search(/[a-zA-Z]+/) != -1) { + var t = -1; + for (j = 0; j < 12; ++j) { + if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } + } + if (t != -1) { + if (m != -1) { + d = m+1; + } + m = t; + } + } else if (parseInt(a[i], 10) <= 12 && m == -1) { + m = a[i]-1; + } else if (parseInt(a[i], 10) > 31 && y == 0) { + y = parseInt(a[i], 10); + (y < 100) && (y += (y > 29) ? 1900 : 2000); + } else if (d == 0) { + d = a[i]; + } + } + if (y == 0) + y = today.getFullYear(); + if (m != -1 && d != 0) + return new Date(y, m, d, hr, min, 0); + return today; +}; + +/** Returns the number of days in the current month */ +Date.prototype.getMonthDays = function(month) { + var year = this.getFullYear(); + if (typeof month == "undefined") { + month = this.getMonth(); + } + if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) { + return 29; + } else { + return Date._MD[month]; + } +}; + +/** Returns the number of day in the year. */ +Date.prototype.getDayOfYear = function() { + var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0); + var time = now - then; + return Math.floor(time / Date.DAY); +}; + +/** Returns the number of the week in year, as defined in ISO 8601. */ +Date.prototype.getWeekNumber = function() { + var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); + var DoW = d.getDay(); + d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu + var ms = d.valueOf(); // GMT + d.setMonth(0); + d.setDate(4); // Thu in Week 1 + return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1; +}; + +/** Checks date and time equality */ +Date.prototype.equalsTo = function(date) { + return ((this.getFullYear() == date.getFullYear()) && + (this.getMonth() == date.getMonth()) && + (this.getDate() == date.getDate()) && + (this.getHours() == date.getHours()) && + (this.getMinutes() == date.getMinutes())); +}; + +/** Set only the year, month, date parts (keep existing time) */ +Date.prototype.setDateOnly = function(date) { + var tmp = new Date(date); + this.setDate(1); + this.setFullYear(tmp.getFullYear()); + this.setMonth(tmp.getMonth()); + this.setDate(tmp.getDate()); +}; + +/** Prints the date in a string according to the given format. */ +Date.prototype.print = function (str) { + var m = this.getMonth(); + var d = this.getDate(); + var y = this.getFullYear(); + var wn = this.getWeekNumber(); + var w = this.getDay(); + var s = {}; + var hr = this.getHours(); + var pm = (hr >= 12); + var ir = (pm) ? (hr - 12) : hr; + var dy = this.getDayOfYear(); + if (ir == 0) + ir = 12; + var min = this.getMinutes(); + var sec = this.getSeconds(); + s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N] + s["%A"] = Calendar._DN[w]; // full weekday name + s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N] + s["%B"] = Calendar._MN[m]; // full month name + // FIXME: %c : preferred date and time representation for the current locale + s["%C"] = 1 + Math.floor(y / 100); // the century number + s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31) + s["%e"] = d; // the day of the month (range 1 to 31) + // FIXME: %D : american date style: %m/%d/%y + // FIXME: %E, %F, %G, %g, %h (man strftime) + s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format) + s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format) + s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366) + s["%k"] = hr; // hour, range 0 to 23 (24h format) + s["%l"] = ir; // hour, range 1 to 12 (12h format) + s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12 + s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59 + s["%n"] = "\n"; // a newline character + s["%p"] = pm ? "PM" : "AM"; + s["%P"] = pm ? "pm" : "am"; + // FIXME: %r : the time in am/pm notation %I:%M:%S %p + // FIXME: %R : the time in 24-hour notation %H:%M + s["%s"] = Math.floor(this.getTime() / 1000); + s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59 + s["%t"] = "\t"; // a tab character + // FIXME: %T : the time in 24-hour notation (%H:%M:%S) + s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn; + s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON) + s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) + // FIXME: %x : preferred date representation for the current locale without the time + // FIXME: %X : preferred time representation for the current locale without the date + s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) + s["%Y"] = y; // year with the century + s["%%"] = "%"; // a literal '%' character + + var re = /%./g; + if (!Calendar.is_ie5 && !Calendar.is_khtml) { + str = str.replace(re, function (par) { return s[par]; }); + return str; + } + + var a = str.match(re); + for (var i = 0; i < a.length; i++) { + var tmp = s[a[i]]; + if (tmp) { + re = new RegExp(a[i], 'g'); + str = str.replace(re, tmp); + } + } + + return str; +}; + +Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear; +Date.prototype.setFullYear = function(y) { + var d = new Date(this); + d.__msh_oldSetFullYear(y); + if (d.getMonth() != this.getMonth()) + this.setDate(28); + this.__msh_oldSetFullYear(y); +}; + +// END: DATE OBJECT PATCHES + + +// global object that remembers the calendar +window._dynarch_popupCalendar = null; diff --git a/web/sf/calendar/lang/calendar-af.js b/web/sf/calendar/lang/calendar-af.js new file mode 100644 index 0000000..aeda581 --- /dev/null +++ b/web/sf/calendar/lang/calendar-af.js @@ -0,0 +1,39 @@ +// ** I18N Afrikaans +Calendar._DN = new Array +("Sondag", + "Maandag", + "Dinsdag", + "Woensdag", + "Donderdag", + "Vrydag", + "Saterdag", + "Sondag"); +Calendar._MN = new Array +("Januarie", + "Februarie", + "Maart", + "April", + "Mei", + "Junie", + "Julie", + "Augustus", + "September", + "Oktober", + "November", + "Desember"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["TOGGLE"] = "Verander eerste dag van die week"; +Calendar._TT["PREV_YEAR"] = "Vorige jaar (hou vir keuselys)"; +Calendar._TT["PREV_MONTH"] = "Vorige maand (hou vir keuselys)"; +Calendar._TT["GO_TODAY"] = "Gaan na vandag"; +Calendar._TT["NEXT_MONTH"] = "Volgende maand (hou vir keuselys)"; +Calendar._TT["NEXT_YEAR"] = "Volgende jaar (hou vir keuselys)"; +Calendar._TT["SEL_DATE"] = "Kies datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Sleep om te skuif"; +Calendar._TT["PART_TODAY"] = " (vandag)"; +Calendar._TT["MON_FIRST"] = "Vertoon Maandag eerste"; +Calendar._TT["SUN_FIRST"] = "Display Sunday first"; +Calendar._TT["CLOSE"] = "Close"; +Calendar._TT["TODAY"] = "Today"; diff --git a/web/sf/calendar/lang/calendar-bg.js b/web/sf/calendar/lang/calendar-bg.js new file mode 100644 index 0000000..696ba43 --- /dev/null +++ b/web/sf/calendar/lang/calendar-bg.js @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar BG language +// Author: Mihai Bazon, +// Translator: Valentin Sheiretsky, +// Encoding: utf8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Неделя", + "Понеделник", + "Вторник", + "Сряда", + "Четвъртък", + "Петък", + "Събота", + "Неделя"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Нед", + "Пон", + "Вто", + "Сря", + "Чет", + "Пет", + "Съб", + "Нед"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Януари", + "Февруари", + "Март", + "Април", + "Май", + "Юни", + "Юли", + "Август", + "Септември", + "Октомври", + "Ноември", + "Декември"); + +// short month names +Calendar._SMN = new Array +("Яну", + "Фев", + "Мар", + "Апр", + "Май", + "Юни", + "Юли", + "Авг", + "Сеп", + "Окт", + "Ное", + "Дек"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Информация за календара"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Предна година (задръжте за меню)"; +Calendar._TT["PREV_MONTH"] = "Преден месец (задръжте за меню)"; +Calendar._TT["GO_TODAY"] = "Изберете днес"; +Calendar._TT["NEXT_MONTH"] = "Следващ месец (задръжте за меню)"; +Calendar._TT["NEXT_YEAR"] = "Следваща година (задръжте за меню)"; +Calendar._TT["SEL_DATE"] = "Изберете дата"; +Calendar._TT["DRAG_TO_MOVE"] = "Преместване"; +Calendar._TT["PART_TODAY"] = " (днес)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s като първи ден"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Затворете"; +Calendar._TT["TODAY"] = "Днес"; +Calendar._TT["TIME_PART"] = "(Shift-)Click или drag за да промените стойността"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%A - %e %B %Y"; + +Calendar._TT["WK"] = "Седм"; +Calendar._TT["TIME"] = "Час:"; diff --git a/web/sf/calendar/lang/calendar-ca.js b/web/sf/calendar/lang/calendar-ca.js new file mode 100644 index 0000000..9e363f3 --- /dev/null +++ b/web/sf/calendar/lang/calendar-ca.js @@ -0,0 +1,125 @@ +// ** I18N + +// Calendar CA language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Diumenge", + "Dilluns", + "Dimarts", + "Dimecres", + "Dijous", + "Divendres", + "Dissabte", + "Diumenge"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Diu", + "Dil", + "Dmt", + "Dmc", + "Dij", + "Div", + "Dis", + "Diu"); + +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Gener", + "Febrer", + "Març", + "Abril", + "Maig", + "Juny", + "Juliol", + "Agost", + "Setembre", + "Octubre", + "Novembre", + "Desembre"); + +// short month names +Calendar._SMN = new Array +("Gen", + "Feb", + "Mar", + "Abr", + "Mai", + "Jun", + "Jul", + "Ago", + "Set", + "Oct", + "Nov", + "Des"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Sobre el calendari"; + +Calendar._TT["ABOUT"] = +"DHTML Selector de Data/Hora\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Sel.lecció de Dates:\n" + +"- Fes servir els botons \xab, \xbb per sel.leccionar l'any\n" + +"- Fes servir els botons " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " per se.lecciconar el mes\n" + +"- Manté el ratolí apretat en qualsevol dels anteriors per sel.lecció ràpida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- claca en qualsevol de les parts de la hora per augmentar-les\n" + +"- o Shift-click per decrementar-la\n" + +"- or click and arrastra per sel.lecció ràpida."; + +Calendar._TT["PREV_YEAR"] = "Any anterior (Mantenir per menu)"; +Calendar._TT["PREV_MONTH"] = "Mes anterior (Mantenir per menu)"; +Calendar._TT["GO_TODAY"] = "Anar a avui"; +Calendar._TT["NEXT_MONTH"] = "Mes següent (Mantenir per menu)"; +Calendar._TT["NEXT_YEAR"] = "Any següent (Mantenir per menu)"; +Calendar._TT["SEL_DATE"] = "Sel.leccionar data"; +Calendar._TT["DRAG_TO_MOVE"] = "Arrastrar per moure"; +Calendar._TT["PART_TODAY"] = " (avui)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Mostra %s primer"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Tanca"; +Calendar._TT["TODAY"] = "Avui"; +Calendar._TT["TIME_PART"] = "(Shift-)Click a arrastra per canviar el valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "st"; +Calendar._TT["TIME"] = "Hora:"; diff --git a/web/sf/calendar/lang/calendar-cs.js b/web/sf/calendar/lang/calendar-cs.js new file mode 100644 index 0000000..6a65fd5 --- /dev/null +++ b/web/sf/calendar/lang/calendar-cs.js @@ -0,0 +1,72 @@ +/* + calendar-cs.js + language: Czech + encoding: utf-8 + author: Mishal (mishal AT mishal DOT cz) + (opraven formát dnů, měsíců + kosmetické změny :-)) + Lubos Jerabek (xnet@seznam.cz) + Jan Uhlir (espinosa@centrum.cz) +*/ + +// ** I18N +Calendar._DN = new Array('neděle','pondělí','úterý','středa','čtvrtek','pátek','sobota','neděle'); +Calendar._SDN = new Array('ne','po','út','st','čt','pá','so','ne'); +Calendar._MN = new Array('leden','únor','březen','duben','květen','červen','červenec','srpen','září','říjen','listopad','prosinec'); +Calendar._SMN = new Array('led','úno','bře','dub','kvě','črn','čvc','srp','zář','říj','lis','pro'); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O komponentě kalendář"; +Calendar._TT["TOGGLE"] = "Změna prvního dne v týdnu"; +Calendar._TT["PREV_YEAR"] = "Předchozí rok (přidrž pro menu)"; +Calendar._TT["PREV_MONTH"] = "Předchozí měsíc (přidrž pro menu)"; +Calendar._TT["GO_TODAY"] = "Dnešní datum"; +Calendar._TT["NEXT_MONTH"] = "Další měsíc (přidrž pro menu)"; +Calendar._TT["NEXT_YEAR"] = "Další rok (přidrž pro menu)"; +Calendar._TT["SEL_DATE"] = "Vyber datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Chyť a táhni, pro přesun"; +Calendar._TT["PART_TODAY"] = " (dnes)"; +Calendar._TT["MON_FIRST"] = "Ukaž jako první Pondělí"; +//Calendar._TT["SUN_FIRST"] = "Ukaž jako první Neděli"; + +Calendar._TT["ABOUT"] = +"DHTML Kalendář\n" + +"(c) dynarch.com 2002-2005 / Autor: Mihai Bazon\n" + // don't translate this this ;-) +"Aktuální verzi najdete na: http://www.dynarch.com/projects/calendar/\n" + +"Distribuováno pod licencí GNU LGPL. Viz. http://gnu.org/licenses/lgpl.html" + +"\n\n" + +"Výběr datumu:\n" + +"- Použijte \xab, \xbb tlačítka k výběru roku\n" + +"- Použijte tlačítka " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " k výběru měsíce\n" + +"- Podržte tlačítko myši na jakémkoliv z těchto tlačítek pro rychlejší výběr."; + +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Výběr času:\n" + +"- Klikněte na jakoukoliv z částí výběru času pro zvýšení.\n" + +"- nebo shift-click pro snížení\n" + +"- nebo klikněte a táhněte pro rychlejší výběr."; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Zobraz %s první"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zavřít"; +Calendar._TT["TODAY"] = "Dnes"; +Calendar._TT["TIME_PART"] = "(Shift-)Klikni nebo táhni pro změnu hodnoty"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "d.m.yy"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "týden"; +Calendar._TT["TIME"] = "Čas:"; + diff --git a/web/sf/calendar/lang/calendar-da.js b/web/sf/calendar/lang/calendar-da.js new file mode 100644 index 0000000..5b8b807 --- /dev/null +++ b/web/sf/calendar/lang/calendar-da.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar DA language +// Author: Michael Thingmand Henriksen, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Søndag", +"Mandag", +"Tirsdag", +"Onsdag", +"Torsdag", +"Fredag", +"Lørdag", +"Søndag"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Søn", +"Man", +"Tir", +"Ons", +"Tor", +"Fre", +"Lør", +"Søn"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Januar", +"Februar", +"Marts", +"April", +"Maj", +"Juni", +"Juli", +"August", +"September", +"Oktober", +"November", +"December"); + +// short month names +Calendar._SMN = new Array +("Jan", +"Feb", +"Mar", +"Apr", +"Maj", +"Jun", +"Jul", +"Aug", +"Sep", +"Okt", +"Nov", +"Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Om Kalenderen"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For den seneste version besøg: http://www.dynarch.com/projects/calendar/\n"; + +"Distribueret under GNU LGPL. Se http://gnu.org/licenses/lgpl.html for detajler." + +"\n\n" + +"Valg af dato:\n" + +"- Brug \xab, \xbb knapperne for at vælge år\n" + +"- Brug " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " knapperne for at vælge måned\n" + +"- Hold knappen på musen nede på knapperne ovenfor for hurtigere valg."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Valg af tid:\n" + +"- Klik på en vilkårlig del for større værdi\n" + +"- eller Shift-klik for for mindre værdi\n" + +"- eller klik og træk for hurtigere valg."; + +Calendar._TT["PREV_YEAR"] = "Ét år tilbage (hold for menu)"; +Calendar._TT["PREV_MONTH"] = "Én måned tilbage (hold for menu)"; +Calendar._TT["GO_TODAY"] = "Gå til i dag"; +Calendar._TT["NEXT_MONTH"] = "Én måned frem (hold for menu)"; +Calendar._TT["NEXT_YEAR"] = "Ét år frem (hold for menu)"; +Calendar._TT["SEL_DATE"] = "Vælg dag"; +Calendar._TT["DRAG_TO_MOVE"] = "Træk vinduet"; +Calendar._TT["PART_TODAY"] = " (i dag)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Vis %s først"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Luk"; +Calendar._TT["TODAY"] = "I dag"; +Calendar._TT["TIME_PART"] = "(Shift-)klik eller træk for at ændre værdi"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "Uge"; +Calendar._TT["TIME"] = "Tid:"; diff --git a/web/sf/calendar/lang/calendar-de.js b/web/sf/calendar/lang/calendar-de.js new file mode 100644 index 0000000..1269b62 --- /dev/null +++ b/web/sf/calendar/lang/calendar-de.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Sonntag", + "Montag", + "Dienstag", + "Mittwoch", + "Donnerstag", + "Freitag", + "Samstag", + "Sonntag"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("So", + "Mo", + "Di", + "Mi", + "Do", + "Fr", + "Sa", + "So"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Januar", + "Februar", + "M\u00e4rz", + "April", + "Mai", + "Juni", + "Juli", + "August", + "September", + "Oktober", + "November", + "Dezember"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "M\u00e4r", + "Apr", + "Mai", + "Jun", + "Jul", + "Aug", + "Sep", + "Okt", + "Nov", + "Dez"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "\u00DCber dieses Kalendarmodul"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Datum ausw\u00e4hlen:\n" + +"- Benutzen Sie die \xab, \xbb Buttons um das Jahr zu w\u00e4hlen\n" + +"- Benutzen Sie die " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " Buttons um den Monat zu w\u00e4hlen\n" + +"- F\u00fcr eine Schnellauswahl halten Sie die Maustaste \u00fcber diesen Buttons fest."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Zeit ausw\u00e4hlen:\n" + +"- Klicken Sie auf die Teile der Uhrzeit, um diese zu erh\u00F6hen\n" + +"- oder klicken Sie mit festgehaltener Shift-Taste um diese zu verringern\n" + +"- oder klicken und festhalten f\u00fcr Schnellauswahl."; + +Calendar._TT["PREV_YEAR"] = "Voriges Jahr (Schnellauswahl: festhalten)"; +Calendar._TT["PREV_MONTH"] = "Voriger Monat (Schnellauswahl: festhalten)"; +Calendar._TT["GO_TODAY"] = "Heute ausw\u00e4hlen"; +Calendar._TT["NEXT_MONTH"] = "N\u00e4chst. Monat (Schnellauswahl: festhalten)"; +Calendar._TT["NEXT_YEAR"] = "N\u00e4chst. Jahr (Schnellauswahl: festhalten)"; +Calendar._TT["SEL_DATE"] = "Datum ausw\u00e4hlen"; +Calendar._TT["DRAG_TO_MOVE"] = "Zum Bewegen festhalten"; +Calendar._TT["PART_TODAY"] = " (Heute)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Woche beginnt mit %s "; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Schlie\u00dfen"; +Calendar._TT["TODAY"] = "Heute"; +Calendar._TT["TIME_PART"] = "(Shift-)Klick oder Festhalten und Ziehen um den Wert zu \u00e4ndern"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Zeit:"; diff --git a/web/sf/calendar/lang/calendar-el.js b/web/sf/calendar/lang/calendar-el.js new file mode 100644 index 0000000..89ffcc2 --- /dev/null +++ b/web/sf/calendar/lang/calendar-el.js @@ -0,0 +1,103 @@ +// ** I18N +Calendar._DN = new Array +("Κυριακή", + "Δευτέρα", + "Τρίτη", + "Τετάρτη", + "Πέμπτη", + "Παρασκευή", + "Σάββατο", + "Κυριακή"); + +Calendar._SDN = new Array +("Κυ", + "Δε", + "Tρ", + "Τε", + "Πε", + "Πα", + "Σα", + "Κυ"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +Calendar._MN = new Array +("Ιανουάριος", + "Φεβρουάριος", + "Μάρτιος", + "Απρίλιος", + "Μάϊος", + "Ιούνιος", + "Ιούλιος", + "Αύγουστος", + "Σεπτέμβριος", + "Οκτώβριος", + "Νοέμβριος", + "Δεκέμβριος"); + +Calendar._SMN = new Array +("Ιαν", + "Φεβ", + "Μαρ", + "Απρ", + "Μαι", + "Ιουν", + "Ιουλ", + "Αυγ", + "Σεπ", + "Οκτ", + "Νοε", + "Δεκ"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Για το ημερολόγιο"; + +Calendar._TT["ABOUT"] = +"Επιλογέας ημερομηνίας/ώρας σε DHTML\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Για τελευταία έκδοση: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Επιλογή ημερομηνίας:\n" + +"- Χρησιμοποιείστε τα κουμπιά \xab, \xbb για επιλογή έτους\n" + +"- Χρησιμοποιείστε τα κουμπιά " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " για επιλογή μήνα\n" + +"- Κρατήστε κουμπί ποντικού πατημένο στα παραπάνω κουμπιά για πιο γρήγορη επιλογή."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Επιλογή ώρας:\n" + +"- Κάντε κλικ σε ένα από τα μέρη της ώρας για αύξηση\n" + +"- ή Shift-κλικ για μείωση\n" + +"- ή κλικ και μετακίνηση για πιο γρήγορη επιλογή."; +Calendar._TT["TOGGLE"] = "Μπάρα πρώτης ημέρας της εβδομάδας"; +Calendar._TT["PREV_YEAR"] = "Προηγ. έτος (κρατήστε για το μενού)"; +Calendar._TT["PREV_MONTH"] = "Προηγ. μήνας (κρατήστε για το μενού)"; +Calendar._TT["GO_TODAY"] = "Σήμερα"; +Calendar._TT["NEXT_MONTH"] = "Επόμενος μήνας (κρατήστε για το μενού)"; +Calendar._TT["NEXT_YEAR"] = "Επόμενο έτος (κρατήστε για το μενού)"; +Calendar._TT["SEL_DATE"] = "Επιλέξτε ημερομηνία"; +Calendar._TT["DRAG_TO_MOVE"] = "Σύρτε για να μετακινήσετε"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["PART_TODAY"] = " (σήμερα)"; +Calendar._TT["MON_FIRST"] = "Εμφάνιση Δευτέρας πρώτα"; +Calendar._TT["SUN_FIRST"] = "Εμφάνιση Κυριακής πρώτα"; +Calendar._TT["CLOSE"] = "Κλείσιμο"; +Calendar._TT["TODAY"] = "Σήμερα"; +Calendar._TT["TIME_PART"] = "(Shift-)κλικ ή μετακίνηση για αλλαγή"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "dd-mm-y"; +Calendar._TT["TT_DATE_FORMAT"] = "D, d M"; + +Calendar._TT["WK"] = "εβδ"; + diff --git a/web/sf/calendar/lang/calendar-en.js b/web/sf/calendar/lang/calendar-en.js new file mode 100644 index 0000000..0dbde79 --- /dev/null +++ b/web/sf/calendar/lang/calendar-en.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "About the calendar"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)"; +Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)"; +Calendar._TT["GO_TODAY"] = "Go Today"; +Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)"; +Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)"; +Calendar._TT["SEL_DATE"] = "Select date"; +Calendar._TT["DRAG_TO_MOVE"] = "Drag to move"; +Calendar._TT["PART_TODAY"] = " (today)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Close"; +Calendar._TT["TODAY"] = "Today"; +Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Time:"; diff --git a/web/sf/calendar/lang/calendar-es.js b/web/sf/calendar/lang/calendar-es.js new file mode 100644 index 0000000..11d0b53 --- /dev/null +++ b/web/sf/calendar/lang/calendar-es.js @@ -0,0 +1,129 @@ +// ** I18N + +// Calendar ES (spanish) language +// Author: Mihai Bazon, +// Updater: Servilio Afre Puentes +// Updated: 2004-06-03 +// Encoding: utf-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domingo", + "Lunes", + "Martes", + "Miércoles", + "Jueves", + "Viernes", + "Sábado", + "Domingo"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dom", + "Lun", + "Mar", + "Mié", + "Jue", + "Vie", + "Sáb", + "Dom"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Enero", + "Febrero", + "Marzo", + "Abril", + "Mayo", + "Junio", + "Julio", + "Agosto", + "Septiembre", + "Octubre", + "Noviembre", + "Diciembre"); + +// short month names +Calendar._SMN = new Array +("Ene", + "Feb", + "Mar", + "Abr", + "May", + "Jun", + "Jul", + "Ago", + "Sep", + "Oct", + "Nov", + "Dic"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Acerca del calendario"; + +Calendar._TT["ABOUT"] = +"Selector DHTML de Fecha/Hora\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Para conseguir la última versión visite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuido bajo licencia GNU LGPL. Visite http://gnu.org/licenses/lgpl.html para más detalles." + +"\n\n" + +"Selección de fecha:\n" + +"- Use los botones \xab, \xbb para seleccionar el año\n" + +"- Use los botones " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionar el mes\n" + +"- Mantenga pulsado el ratón en cualquiera de estos botones para una selección rápida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selección de hora:\n" + +"- Pulse en cualquiera de las partes de la hora para incrementarla\n" + +"- o pulse las mayúsculas mientras hace clic para decrementarla\n" + +"- o haga clic y arrastre el ratón para una selección más rápida."; + +Calendar._TT["PREV_YEAR"] = "Año anterior (mantener para menú)"; +Calendar._TT["PREV_MONTH"] = "Mes anterior (mantener para menú)"; +Calendar._TT["GO_TODAY"] = "Ir a hoy"; +Calendar._TT["NEXT_MONTH"] = "Mes siguiente (mantener para menú)"; +Calendar._TT["NEXT_YEAR"] = "Año siguiente (mantener para menú)"; +Calendar._TT["SEL_DATE"] = "Seleccionar fecha"; +Calendar._TT["DRAG_TO_MOVE"] = "Arrastrar para mover"; +Calendar._TT["PART_TODAY"] = " (hoy)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Hacer %s primer día de la semana"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Cerrar"; +Calendar._TT["TODAY"] = "Hoy"; +Calendar._TT["TIME_PART"] = "(Mayúscula-)Clic o arrastre para cambiar valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y"; + +Calendar._TT["WK"] = "sem"; +Calendar._TT["TIME"] = "Hora:"; diff --git a/web/sf/calendar/lang/calendar-eu.js b/web/sf/calendar/lang/calendar-eu.js new file mode 100644 index 0000000..18deb33 --- /dev/null +++ b/web/sf/calendar/lang/calendar-eu.js @@ -0,0 +1,129 @@ +// ** I18N + +// Calendar EU (basque) language +// Author: Xabier Bayon +// Updater: Xabier Bayon +// Updated: 2005-04-05 +// Encoding: utf-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Igandea", + "Astelehena", + "Asteartea", + "Asteazkena", + "Osteguna", + "Ostirala", + "Larunbata", + "Igandea"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Ig", + "Al", + "Ar", + "Az", + "Os", + "Ol", + "La", + "Ig"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Urtarrila", + "Otsaila", + "Martxoa", + "Apirila", + "Maiatza", + "Ekaina", + "Uztaila", + "Abuztua", + "Iraila", + "Urria", + "Azaroa", + "Abendua"); + +// short month names +Calendar._SMN = new Array +("Urt", + "Ots", + "Mar", + "Apr", + "Mai", + "Eka", + "Uzt", + "Abu", + "Ira", + "Urr", + "Aza", + "Abe"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Egutegiari buruz"; + +Calendar._TT["ABOUT"] = +"Data/ordua DHTML hautatzailea\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Bertsio berriena eskuratzeko: http://www.dynarch.com/projects/calendar/\n" + +"GNU LGPL baimenpean banatua. http://gnu.org/licenses/lgpl.html orrira joan zehaztasun gehiagotarako." + +"\n\n" + +"Data nola aukeratu:\n" + +"- \xab, \xbb botoiak erabili urtea aukeratzeko\n" + +"- " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " botoiak erabili hilabetea aukeratzeko\n" + +"- Aukera azkar burutzeko saguaren botoia sakatuta mantendu."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Ordua nola aukeratu:\n" + +"- Orduan sakatu gehitzeko\n" + +"- Maiuskula sakatuta ordu kopurua gutxituko da\n" + +"- Saguaren botoia sakatu eta arrastatuz arinago burutuko da."; + +Calendar._TT["PREV_YEAR"] = "Aurreko urtea (Menurako mantendu)"; +Calendar._TT["PREV_MONTH"] = "Aurreko hilabetea (Menurako mantendu)"; +Calendar._TT["GO_TODAY"] = "Gaurkora jo"; +Calendar._TT["NEXT_MONTH"] = "Hurrengo hilabetea (Menurako mantendu)"; +Calendar._TT["NEXT_YEAR"] = "Hurrengo urtea (Menurako mantendu)"; +Calendar._TT["SEL_DATE"] = "Data aukeratu"; +Calendar._TT["DRAG_TO_MOVE"] = "Mugitzeko arrastatu"; +Calendar._TT["PART_TODAY"] = " (gaur)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s asteko lehenengo eguna bihurtu"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Itxi"; +Calendar._TT["TODAY"] = "Gaur"; +Calendar._TT["TIME_PART"] = "(Mayúscula-)Clic o arrastre para cambiar valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y/%m/%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%Yko %Bren %e, %A"; + +Calendar._TT["WK"] = "ast"; +Calendar._TT["TIME"] = "Ordua:"; diff --git a/web/sf/calendar/lang/calendar-fi.js b/web/sf/calendar/lang/calendar-fi.js new file mode 100644 index 0000000..b4270ea --- /dev/null +++ b/web/sf/calendar/lang/calendar-fi.js @@ -0,0 +1,112 @@ +// ** I18N + +// Calendar FI language (Finnish, Suomi) +// Author: Jarno Käyhkö, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// full day names +Calendar._DN = new Array +("Sunnuntai", + "Maanantai", + "Tiistai", + "Keskiviikko", + "Torstai", + "Perjantai", + "Lauantai", + "Sunnuntai"); + +// short day names +Calendar._SDN = new Array +("Su", + "Ma", + "Ti", + "Ke", + "To", + "Pe", + "La", + "Su"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Tammikuu", + "Helmikuu", + "Maaliskuu", + "Huhtikuu", + "Toukokuu", + "Kesäkuu", + "Heinäkuu", + "Elokuu", + "Syyskuu", + "Lokakuu", + "Marraskuu", + "Joulukuu"); + +// short month names +Calendar._SMN = new Array +("Tam", + "Hel", + "Maa", + "Huh", + "Tou", + "Kes", + "Hei", + "Elo", + "Syy", + "Lok", + "Mar", + "Jou"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Tietoja kalenterista"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Uusin versio osoitteessa: http://www.dynarch.com/projects/calendar/\n" + +"Julkaistu GNU LGPL lisenssin alaisuudessa. Lisätietoja osoitteessa http://gnu.org/licenses/lgpl.html" + +"\n\n" + +"Päivämäärä valinta:\n" + +"- Käytä \xab, \xbb painikkeita valitaksesi vuosi\n" + +"- Käytä " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " painikkeita valitaksesi kuukausi\n" + +"- Pitämällä hiiren painiketta minkä tahansa yllä olevan painikkeen kohdalla, saat näkyviin valikon nopeampaan siirtymiseen."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Ajan valinta:\n" + +"- Klikkaa kellonajan numeroita lisätäksesi aikaa\n" + +"- tai pitämällä Shift-näppäintä pohjassa saat aikaa taaksepäin\n" + +"- tai klikkaa ja pidä hiiren painike pohjassa sekä liikuta hiirtä muuttaaksesi aikaa nopeasti eteen- ja taaksepäin."; + +Calendar._TT["PREV_YEAR"] = "Edell. vuosi (paina hetki, näet valikon)"; +Calendar._TT["PREV_MONTH"] = "Edell. kuukausi (paina hetki, näet valikon)"; +Calendar._TT["GO_TODAY"] = "Siirry tähän päivään"; +Calendar._TT["NEXT_MONTH"] = "Seur. kuukausi (paina hetki, näet valikon)"; +Calendar._TT["NEXT_YEAR"] = "Seur. vuosi (paina hetki, näet valikon)"; +Calendar._TT["SEL_DATE"] = "Valitse päivämäärä"; +Calendar._TT["DRAG_TO_MOVE"] = "Siirrä kalenterin paikkaa"; +Calendar._TT["PART_TODAY"] = " (tänään)"; +Calendar._TT["MON_FIRST"] = "Näytä maanantai ensimmäisenä"; +Calendar._TT["SUN_FIRST"] = "Näytä sunnuntai ensimmäisenä"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Sulje"; +Calendar._TT["TODAY"] = "Tänään"; +Calendar._TT["TIME_PART"] = "(Shift-) Klikkaa tai liikuta muuttaaksesi aikaa"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%d.%m.%Y"; + +Calendar._TT["WK"] = "Vko"; diff --git a/web/sf/calendar/lang/calendar-fr.js b/web/sf/calendar/lang/calendar-fr.js new file mode 100644 index 0000000..4b535bc --- /dev/null +++ b/web/sf/calendar/lang/calendar-fr.js @@ -0,0 +1,129 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// Translator: André Liechti, (2006-01-04) from scratch for version 1.x + +// full day names +Calendar._DN = new Array +("Dimanche", + "Lundi", + "Mardi", + "Mercredi", + "Jeudi", + "Vendredi", + "Samedi", + "Dimanche"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dim", + "Lun", + "Mar", + "Mer", + "Jeu", + "Ven", + "Sam", + "Dim"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Janvier", + "Février", + "Mars", + "Avril", + "Mai", + "Juin", + "Juillet", + "Août", + "Septembre", + "Octobre", + "Novembre", + "Décembre"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Fév", + "Mar", + "Avr", + "Mai", + "Juin", + "Juil", + "Aou", + "Sep", + "Oct", + "Nov", + "Déc"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "À propos du calendrier"; + +Calendar._TT["ABOUT"] = +"Sélecteur DHTML de date/heure\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Pour la version actuelle, visitez: http://www.dynarch.com/projects/calendar/\n" + +"Distribué sous licence GNU LGPL. Voir http://gnu.org/licenses/lgpl.html pour les détails." + "\n(licence traduite en français: http://www.rodage.org/lgpl.fr.html)" + +"\n\n" + +"Sélection de la date:\n" + +"- Utiliser les boutons \xab, \xbb pour sélectionner l'année\n" + +"- Utiliser les boutons " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pour sélectionner le mois\n" + +"- En conservant pressé le bouton de la souris sur l'un de ces boutons, la sélection devient plus rapide."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Sélection de l\'heure:\n" + +"- Cliquer sur l'une des parties du temps pour l'augmenter\n" + +"- ou Maj-clic pour le diminuer\n" + +"- ou faire un cliquer-déplacer horizontal pour une modification plus rapide."; + +Calendar._TT["PREV_YEAR"] = "Année préc. (maintenir pour afficher menu)"; +Calendar._TT["PREV_MONTH"] = "Mois préc. (maintenir pour afficher menu)"; +Calendar._TT["GO_TODAY"] = "Atteindre la date du jour"; +Calendar._TT["NEXT_MONTH"] = "Mois suiv. (maintenir pour afficher menu)"; +Calendar._TT["NEXT_YEAR"] = "Année suiv. (maintenir pour afficher menu)"; +Calendar._TT["SEL_DATE"] = "Sélectionner une date"; +Calendar._TT["DRAG_TO_MOVE"] = "Glisser pour déplacer"; +Calendar._TT["PART_TODAY"] = " (aujourd'hui)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Afficher %s en premier"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Fermer"; +Calendar._TT["TODAY"] = "Aujourd'hui"; +Calendar._TT["TIME_PART"] = "(Maj-)Clic ou glisser pour changer la valeur"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %e %B"; + +Calendar._TT["WK"] = "sem."; +Calendar._TT["TIME"] = "Heure:"; diff --git a/web/sf/calendar/lang/calendar-he.js b/web/sf/calendar/lang/calendar-he.js new file mode 100644 index 0000000..7861217 --- /dev/null +++ b/web/sf/calendar/lang/calendar-he.js @@ -0,0 +1,123 @@ +// ** I18N + +// Calendar EN language +// Author: Idan Sofer, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("ראשון", + "שני", + "שלישי", + "רביעי", + "חמישי", + "שישי", + "שבת", + "ראשון"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("א", + "ב", + "ג", + "ד", + "ה", + "ו", + "ש", + "א"); + +// full month names +Calendar._MN = new Array +("ינואר", + "פברואר", + "מרץ", + "אפריל", + "מאי", + "יוני", + "יולי", + "אוגוסט", + "ספטמבר", + "אוקטובר", + "נובמבר", + "דצמבר"); + +// short month names +Calendar._SMN = new Array +("ינא", + "פבר", + "מרץ", + "אפר", + "מאי", + "יונ", + "יול", + "אוג", + "ספט", + "אוק", + "נוב", + "דצמ"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "אודות השנתון"; + +Calendar._TT["ABOUT"] = +"בחרן תאריך/שעה DHTML\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"הגירסא האחרונה זמינה ב: http://www.dynarch.com/projects/calendar/\n" + +"מופץ תחת זיכיון ה GNU LGPL. עיין ב http://gnu.org/licenses/lgpl.html לפרטים נוספים." + +"\n\n" + +בחירת תאריך:\n" + +"- השתמש בכפתורים \xab, \xbb לבחירת שנה\n" + +"- השתמש בכפתורים " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " לבחירת חודש\n" + +"- החזק העכבר לחוץ מעל הכפתורים המוזכרים לעיל לבחירה מהירה יותר."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"בחירת זמן:\n" + +"- לחץ על כל אחד מחלקי הזמן כדי להוסיף\n" + +"- או shift בשילוב עם לחיצה כדי להחסיר\n" + +"- או לחץ וגרור לפעולה מהירה יותר."; + +Calendar._TT["PREV_YEAR"] = "שנה קודמת - החזק לקבלת תפריט"; +Calendar._TT["PREV_MONTH"] = "חודש קודם - החזק לקבלת תפריט"; +Calendar._TT["GO_TODAY"] = "עבור להיום"; +Calendar._TT["NEXT_MONTH"] = "חודש הבא - החזק לתפריט"; +Calendar._TT["NEXT_YEAR"] = "שנה הבאה - החזק לתפריט"; +Calendar._TT["SEL_DATE"] = "בחר תאריך"; +Calendar._TT["DRAG_TO_MOVE"] = "גרור להזזה"; +Calendar._TT["PART_TODAY"] = " )היום("; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "הצג %s קודם"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "6"; + +Calendar._TT["CLOSE"] = "סגור"; +Calendar._TT["TODAY"] = "היום"; +Calendar._TT["TIME_PART"] = "(שיפט-)לחץ וגרור כדי לשנות ערך"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "שעה::"; diff --git a/web/sf/calendar/lang/calendar-hr.js b/web/sf/calendar/lang/calendar-hr.js new file mode 100644 index 0000000..dc43fc1 --- /dev/null +++ b/web/sf/calendar/lang/calendar-hr.js @@ -0,0 +1,64 @@ +/* Croatian language file for the DHTML Calendar version 0.9.2 +* Author Krunoslav Zubrinic , June 2003. +* Feel free to use this script under the terms of the GNU Lesser General +* Public License, as long as you do not remove or alter this notice. +*/ +Calendar._DN = new Array +("Nedjelja", + "Ponedjeljak", + "Utorak", + "Srijeda", + "Četvrtak", + "Petak", + "Subota", + "Nedjelja"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +Calendar._MN = new Array +("Siječanj", + "Veljača", + "Ožujak", + "Travanj", + "Svibanj", + "Lipanj", + "Srpanj", + "Kolovoz", + "Rujan", + "Listopad", + "Studeni", + "Prosinac"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["TOGGLE"] = "Promjeni dan s kojim počinje tjedan"; +Calendar._TT["PREV_YEAR"] = "Prethodna godina (dugi pritisak za meni)"; +Calendar._TT["PREV_MONTH"] = "Prethodni mjesec (dugi pritisak za meni)"; +Calendar._TT["GO_TODAY"] = "Idi na tekući dan"; +Calendar._TT["NEXT_MONTH"] = "Slijedeći mjesec (dugi pritisak za meni)"; +Calendar._TT["NEXT_YEAR"] = "Slijedeća godina (dugi pritisak za meni)"; +Calendar._TT["SEL_DATE"] = "Izaberite datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Pritisni i povuci za promjenu pozicije"; +Calendar._TT["PART_TODAY"] = " (today)"; +Calendar._TT["MON_FIRST"] = "Prikaži ponedjeljak kao prvi dan"; +Calendar._TT["SUN_FIRST"] = "Prikaži nedjelju kao prvi dan"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zatvori"; +Calendar._TT["TODAY"] = "Danas"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "dd-mm-y"; +Calendar._TT["TT_DATE_FORMAT"] = "DD, dd.mm.y"; + +Calendar._TT["WK"] = "Tje"; \ No newline at end of file diff --git a/web/sf/calendar/lang/calendar-hu.js b/web/sf/calendar/lang/calendar-hu.js new file mode 100644 index 0000000..2eea8c4 --- /dev/null +++ b/web/sf/calendar/lang/calendar-hu.js @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar HU language +// Author: ??? +// Modifier: KARASZI Istvan, +// Encoding: utf8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Vasárnap", + "Hétfő", + "Kedd", + "Szerda", + "Csütörtök", + "Péntek", + "Szombat", + "Vasárnap"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("v", + "h", + "k", + "sze", + "cs", + "p", + "szo", + "v"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("január", + "február", + "március", + "április", + "május", + "június", + "július", + "augusztus", + "szeptember", + "október", + "november", + "december"); + +// short month names +Calendar._SMN = new Array +("jan", + "feb", + "már", + "ápr", + "máj", + "jún", + "júl", + "aug", + "sze", + "okt", + "nov", + "dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "A kalendáriumról"; + +Calendar._TT["ABOUT"] = +"DHTML dátum/idő kiválasztó\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"a legfrissebb verzió megtalálható: http://www.dynarch.com/projects/calendar/\n" + +"GNU LGPL alatt terjesztve. Lásd a http://gnu.org/licenses/lgpl.html oldalt a részletekhez." + +"\n\n" + +"Dátum választás:\n" + +"- használja a \xab, \xbb gombokat az év kiválasztásához\n" + +"- használja a " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " gombokat a hónap kiválasztásához\n" + +"- tartsa lenyomva az egérgombot a gyors választáshoz."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Idő választás:\n" + +"- kattintva növelheti az időt\n" + +"- shift-tel kattintva csökkentheti\n" + +"- lenyomva tartva és húzva gyorsabban kiválaszthatja."; + +Calendar._TT["PREV_YEAR"] = "Előző év (tartsa nyomva a menühöz)"; +Calendar._TT["PREV_MONTH"] = "Előző hónap (tartsa nyomva a menühöz)"; +Calendar._TT["GO_TODAY"] = "Mai napra ugrás"; +Calendar._TT["NEXT_MONTH"] = "Köv. hónap (tartsa nyomva a menühöz)"; +Calendar._TT["NEXT_YEAR"] = "Köv. év (tartsa nyomva a menühöz)"; +Calendar._TT["SEL_DATE"] = "Válasszon dátumot"; +Calendar._TT["DRAG_TO_MOVE"] = "Húzza a mozgatáshoz"; +Calendar._TT["PART_TODAY"] = " (ma)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s legyen a hét első napja"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Bezár"; +Calendar._TT["TODAY"] = "Ma"; +Calendar._TT["TIME_PART"] = "(Shift-)Klikk vagy húzás az érték változtatásához"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%b %e, %a"; + +Calendar._TT["WK"] = "hét"; +Calendar._TT["TIME"] = "idő:"; diff --git a/web/sf/calendar/lang/calendar-it.js b/web/sf/calendar/lang/calendar-it.js new file mode 100644 index 0000000..d6e7909 --- /dev/null +++ b/web/sf/calendar/lang/calendar-it.js @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Translator: Fabio Di Bernardini, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domenica", + "Lunedì", + "Martedì", + "Mercoledì", + "Giovedì", + "Venerdì", + "Sabato", + "Domenica"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dom", + "Lun", + "Mar", + "Mer", + "Gio", + "Ven", + "Sab", + "Dom"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Gennaio", + "Febbraio", + "Marzo", + "Aprile", + "Maggio", + "Giugno", + "Luglio", + "Augosto", + "Settembre", + "Ottobre", + "Novembre", + "Dicembre"); + +// short month names +Calendar._SMN = new Array +("Gen", + "Feb", + "Mar", + "Apr", + "Mag", + "Giu", + "Lug", + "Ago", + "Set", + "Ott", + "Nov", + "Dic"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Informazioni sul calendario"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Per gli aggiornamenti: http://www.dynarch.com/projects/calendar/\n" + +"Distribuito sotto licenza GNU LGPL. Vedi http://gnu.org/licenses/lgpl.html per i dettagli." + +"\n\n" + +"Selezione data:\n" + +"- Usa \xab, \xbb per selezionare l'anno\n" + +"- Usa " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " per i mesi\n" + +"- Tieni premuto a lungo il mouse per accedere alle funzioni di selezione veloce."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selezione orario:\n" + +"- Clicca sul numero per incrementarlo\n" + +"- o Shift+click per decrementarlo\n" + +"- o click e sinistra o destra per variarlo."; + +Calendar._TT["PREV_YEAR"] = "Anno prec.(clicca a lungo per il menù)"; +Calendar._TT["PREV_MONTH"] = "Mese prec. (clicca a lungo per il menù)"; +Calendar._TT["GO_TODAY"] = "Oggi"; +Calendar._TT["NEXT_MONTH"] = "Pross. mese (clicca a lungo per il menù)"; +Calendar._TT["NEXT_YEAR"] = "Pross. anno (clicca a lungo per il menù)"; +Calendar._TT["SEL_DATE"] = "Seleziona data"; +Calendar._TT["DRAG_TO_MOVE"] = "Trascina per spostarlo"; +Calendar._TT["PART_TODAY"] = " (oggi)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Mostra prima %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Chiudi"; +Calendar._TT["TODAY"] = "Oggi"; +Calendar._TT["TIME_PART"] = "(Shift-)Click o trascina per cambiare il valore"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a:%b:%e"; + +Calendar._TT["WK"] = "set"; +Calendar._TT["TIME"] = "Ora:"; diff --git a/web/sf/calendar/lang/calendar-ja.js b/web/sf/calendar/lang/calendar-ja.js new file mode 100644 index 0000000..422bb82 --- /dev/null +++ b/web/sf/calendar/lang/calendar-ja.js @@ -0,0 +1,135 @@ +// ** I18N + +// Calendar JA language +// Author: AKIMOTO, Hiroki, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// FYI: Locale identifiers for Japanese/Japan are a bit confusing. Use 'ja'. +// 'ja' Japanese, Language Code +// 'JP' Japan, Country Code +// So, 'ja-JP' locale means Japanese in Japan, however, there are no other +// countries Japanese primarily used so usually '-JP' is omittable. +// Not a small amount of internationalized software use 'jp' in mistake, +// but as you see now that the locale name 'ja' is the right one. + +// full day names +Calendar._DN = new Array +("日", + "月", + "火", + "水", + "木", + "金", + "土", + "日"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("日", + "月", + "火", + "水", + "木", + "金", + "土", + "日"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("1月", + "2月", + "3月", + "4月", + "5月", + "6月", + "7月", + "8月", + "9月", + "10月", + "11月", + "12月"); + +// short month names +Calendar._SMN = new Array +("1月", + "2月", + "3月", + "4月", + "5月", + "6月", + "7月", + "8月", + "9月", + "10月", + "11月", + "12月"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "このカレンダーについて"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"最新版の情報: http://www.dynarch.com/projects/calendar/\n" + +"GNU LGPL で配布されています。 詳細は http://gnu.org/licenses/lgpl.html をご覧ください。" + +"\n\n" + +"日付の選択:\n" + +"- ボタン \xab, \xbb で年を選択します\n" + +"- ボタン " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " で月を選択します\n" + +"- 上記ボタンでマウスを押したままにすると、より大きな移動ができます"; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "前年"; +Calendar._TT["PREV_MONTH"] = "前月"; +Calendar._TT["GO_TODAY"] = "今日"; +Calendar._TT["NEXT_MONTH"] = "翌月"; +Calendar._TT["NEXT_YEAR"] = "翌年"; +Calendar._TT["SEL_DATE"] = "日付選択"; +Calendar._TT["DRAG_TO_MOVE"] = "ウィンドウの移動"; +Calendar._TT["PART_TODAY"] = " (今日)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s曜日を週の先頭に"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "閉じる"; +Calendar._TT["TODAY"] = "今日"; +Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%m月 %d日 (%a)"; + +Calendar._TT["WK"] = "週"; +Calendar._TT["TIME"] = "Time:"; diff --git a/web/sf/calendar/lang/calendar-ko.js b/web/sf/calendar/lang/calendar-ko.js new file mode 100644 index 0000000..f885157 --- /dev/null +++ b/web/sf/calendar/lang/calendar-ko.js @@ -0,0 +1,134 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Translation: Yourim Yi +// Encoding: EUC-KR +// lang : ko +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names + +Calendar._DN = new Array +("일요일", + "월요일", + "화요일", + "수요일", + "목요일", + "금요일", + "토요일", + "일요일"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("일", + "월", + "화", + "수", + "목", + "금", + "토", + "일"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("1월", + "2월", + "3월", + "4월", + "5월", + "6월", + "7월", + "8월", + "9월", + "10월", + "11월", + "12월"); + +// short month names +Calendar._SMN = new Array +("1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "calendar 에 대해서"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"\n"+ +"최신 버전을 받으시려면 http://www.dynarch.com/projects/calendar/ 에 방문하세요\n" + +"\n"+ +"GNU LGPL 라이센스로 배포됩니다. \n"+ +"라이센스에 대한 자세한 내용은 http://gnu.org/licenses/lgpl.html 을 읽으세요." + +"\n\n" + +"날짜 선택:\n" + +"- 연도를 선택하려면 \xab, \xbb 버튼을 사용합니다\n" + +"- 달을 선택하려면 " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " 버튼을 누르세요\n" + +"- 계속 누르고 있으면 위 값들을 빠르게 선택하실 수 있습니다."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"시간 선택:\n" + +"- 마우스로 누르면 시간이 증가합니다\n" + +"- Shift 키와 함께 누르면 감소합니다\n" + +"- 누른 상태에서 마우스를 움직이면 좀 더 빠르게 값이 변합니다.\n"; + +Calendar._TT["PREV_YEAR"] = "지난 해 (길게 누르면 목록)"; +Calendar._TT["PREV_MONTH"] = "지난 달 (길게 누르면 목록)"; +Calendar._TT["GO_TODAY"] = "오늘 날짜로"; +Calendar._TT["NEXT_MONTH"] = "다음 달 (길게 누르면 목록)"; +Calendar._TT["NEXT_YEAR"] = "다음 해 (길게 누르면 목록)"; +Calendar._TT["SEL_DATE"] = "날짜를 선택하세요"; +Calendar._TT["DRAG_TO_MOVE"] = "마우스 드래그로 이동 하세요"; +Calendar._TT["PART_TODAY"] = " (오늘)"; +Calendar._TT["MON_FIRST"] = "월요일을 한 주의 시작 요일로"; +Calendar._TT["SUN_FIRST"] = "일요일을 한 주의 시작 요일로"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "닫기"; +Calendar._TT["TODAY"] = "오늘"; +Calendar._TT["TIME_PART"] = "(Shift-)클릭 또는 드래그 하세요"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%b/%e [%a]"; + +Calendar._TT["WK"] = "주"; diff --git a/web/sf/calendar/lang/calendar-lt.js b/web/sf/calendar/lang/calendar-lt.js new file mode 100644 index 0000000..850c1df --- /dev/null +++ b/web/sf/calendar/lang/calendar-lt.js @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar LT language +// Author: Martynas Majeris, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Sekmadienis", + "Pirmadienis", + "Antradienis", + "Trečiadienis", + "Ketvirtadienis", + "Pentadienis", + "Šeštadienis", + "Sekmadienis"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Sek", + "Pir", + "Ant", + "Tre", + "Ket", + "Pen", + "Šeš", + "Sek"); + +// full month names +Calendar._MN = new Array +("Sausis", + "Vasaris", + "Kovas", + "Balandis", + "Gegužė", + "Birželis", + "Liepa", + "Rugpjūtis", + "Rugsėjis", + "Spalis", + "Lapkritis", + "Gruodis"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// short month names +Calendar._SMN = new Array +("Sau", + "Vas", + "Kov", + "Bal", + "Geg", + "Bir", + "Lie", + "Rgp", + "Rgs", + "Spa", + "Lap", + "Gru"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Apie kalendorių"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Naujausią versiją rasite: http://www.dynarch.com/projects/calendar/\n" + +"Platinamas pagal GNU LGPL licenciją. Aplankykite http://gnu.org/licenses/lgpl.html" + +"\n\n" + +"Datos pasirinkimas:\n" + +"- Metų pasirinkimas: \xab, \xbb\n" + +"- Mėnesio pasirinkimas: " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + "\n" + +"- Nuspauskite ir laikykite pelės klavišą greitesniam pasirinkimui."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Laiko pasirinkimas:\n" + +"- Spustelkite ant valandų arba minučių - skaičius padidės vienetu.\n" + +"- Jei spausite kartu su Shift, skaičius sumažės.\n" + +"- Greitam pasirinkimui spustelkite ir pajudinkite pelę."; + +Calendar._TT["PREV_YEAR"] = "Ankstesni metai (laikykite, jei norite meniu)"; +Calendar._TT["PREV_MONTH"] = "Ankstesnis mėnuo (laikykite, jei norite meniu)"; +Calendar._TT["GO_TODAY"] = "Pasirinkti šiandieną"; +Calendar._TT["NEXT_MONTH"] = "Kitas mėnuo (laikykite, jei norite meniu)"; +Calendar._TT["NEXT_YEAR"] = "Kiti metai (laikykite, jei norite meniu)"; +Calendar._TT["SEL_DATE"] = "Pasirinkite datą"; +Calendar._TT["DRAG_TO_MOVE"] = "Tempkite"; +Calendar._TT["PART_TODAY"] = " (šiandien)"; +Calendar._TT["MON_FIRST"] = "Pirma savaitės diena - pirmadienis"; +Calendar._TT["SUN_FIRST"] = "Pirma savaitės diena - sekmadienis"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Uždaryti"; +Calendar._TT["TODAY"] = "Šiandien"; +Calendar._TT["TIME_PART"] = "Spustelkite arba tempkite jei norite pakeisti"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %Y-%m-%d"; + +Calendar._TT["WK"] = "sav"; diff --git a/web/sf/calendar/lang/calendar-lv.js b/web/sf/calendar/lang/calendar-lv.js new file mode 100644 index 0000000..e8488e4 --- /dev/null +++ b/web/sf/calendar/lang/calendar-lv.js @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar LV language +// Author: Juris Valdovskis, +// Encoding: utf8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Svētdiena", + "Pirmdiena", + "Otrdiena", + "Trešdiena", + "Ceturdiena", + "Piektdiena", + "Sestdiena", + "Svētdiena"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Sv", + "Pr", + "Ot", + "Tr", + "Ce", + "Pk", + "Se", + "Sv"); + + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Janvāris", + "Februāris", + "Marts", + "Aprīlis", + "Maijs", + "Jūnijs", + "Jūlijs", + "Augusts", + "Septembris", + "Oktobris", + "Novembris", + "Decembris"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Mai", + "Jūn", + "Jūl", + "Aug", + "Sep", + "Okt", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Par kalendāru"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Datuma izvēle:\n" + +"- Izmanto \xab, \xbb pogas, lai izvēlētos gadu\n" + +"- Izmanto " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + "pogas, lai izvēlētos mēnesi\n" + +"- Turi nospiestu peles pogu uz jebkuru no augstāk minētajām pogām, lai paātrinātu izvēli."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Laika izvēle:\n" + +"- Uzklikšķini uz jebkuru no laika daļām, lai palielinātu to\n" + +"- vai Shift-klikšķis, lai samazinātu to\n" + +"- vai noklikšķini un velc uz attiecīgo virzienu lai mainītu ātrāk."; + +Calendar._TT["PREV_YEAR"] = "Iepr. gads (turi izvēlnei)"; +Calendar._TT["PREV_MONTH"] = "Iepr. mēnesis (turi izvēlnei)"; +Calendar._TT["GO_TODAY"] = "Šodien"; +Calendar._TT["NEXT_MONTH"] = "Nākošais mēnesis (turi izvēlnei)"; +Calendar._TT["NEXT_YEAR"] = "Nākošais gads (turi izvēlnei)"; +Calendar._TT["SEL_DATE"] = "Izvēlies datumu"; +Calendar._TT["DRAG_TO_MOVE"] = "Velc, lai pārvietotu"; +Calendar._TT["PART_TODAY"] = " (šodien)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Attēlot %s kā pirmo"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "1,7"; + +Calendar._TT["CLOSE"] = "Aizvērt"; +Calendar._TT["TODAY"] = "Šodien"; +Calendar._TT["TIME_PART"] = "(Shift-)Klikšķis vai pārvieto, lai mainītu"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Laiks:"; diff --git a/web/sf/calendar/lang/calendar-nl.js b/web/sf/calendar/lang/calendar-nl.js new file mode 100644 index 0000000..084b066 --- /dev/null +++ b/web/sf/calendar/lang/calendar-nl.js @@ -0,0 +1,76 @@ +// ** I18N +Calendar._DN = new Array +("Zondag", + "Maandag", + "Dinsdag", + "Woensdag", + "Donderdag", + "Vrijdag", + "Zaterdag", + "Zondag"); + +Calendar._SDN_len = 2; + +Calendar._MN = new Array +("Januari", + "Februari", + "Maart", + "April", + "Mei", + "Juni", + "Juli", + "Augustus", + "September", + "Oktober", + "November", + "December"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Info"; + +Calendar._TT["ABOUT"] = +"DHTML Datum/Tijd Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + +"Ga voor de meest recente versie naar: http://www.dynarch.com/projects/calendar/\n" + +"Verspreid onder de GNU LGPL. Zie http://gnu.org/licenses/lgpl.html voor details." + +"\n\n" + +"Datum selectie:\n" + +"- Gebruik de \xab \xbb knoppen om een jaar te selecteren\n" + +"- Gebruik de " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " knoppen om een maand te selecteren\n" + +"- Houd de muis ingedrukt op de genoemde knoppen voor een snellere selectie."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Tijd selectie:\n" + +"- Klik op een willekeurig onderdeel van het tijd gedeelte om het te verhogen\n" + +"- of Shift-klik om het te verlagen\n" + +"- of klik en sleep voor een snellere selectie."; + +//Calendar._TT["TOGGLE"] = "Selecteer de eerste week-dag"; +Calendar._TT["PREV_YEAR"] = "Vorig jaar (ingedrukt voor menu)"; +Calendar._TT["PREV_MONTH"] = "Vorige maand (ingedrukt voor menu)"; +Calendar._TT["GO_TODAY"] = "Ga naar Vandaag"; +Calendar._TT["NEXT_MONTH"] = "Volgende maand (ingedrukt voor menu)"; +Calendar._TT["NEXT_YEAR"] = "Volgend jaar (ingedrukt voor menu)"; +Calendar._TT["SEL_DATE"] = "Selecteer datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Klik en sleep om te verplaatsen"; +Calendar._TT["PART_TODAY"] = " (vandaag)"; +//Calendar._TT["MON_FIRST"] = "Toon Maandag eerst"; +//Calendar._TT["SUN_FIRST"] = "Toon Zondag eerst"; + +Calendar._TT["DAY_FIRST"] = "Toon %s eerst"; + +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Sluiten"; +Calendar._TT["TODAY"] = "(vandaag)"; +Calendar._TT["TIME_PART"] = "(Shift-)Klik of sleep om de waarde te veranderen"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b %Y"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Tijd:"; + +Calendar._SMN_len = 3; +Calendar._FD = 0; diff --git a/web/sf/calendar/lang/calendar-no.js b/web/sf/calendar/lang/calendar-no.js new file mode 100644 index 0000000..3b3041c --- /dev/null +++ b/web/sf/calendar/lang/calendar-no.js @@ -0,0 +1,129 @@ +// ** I18N + +// Calendar NO language +// Author: Daniel Holmen, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Søndag", + "Mandag", + "Tirsdag", + "Onsdag", + "Torsdag", + "Fredag", + "Lørdag", + "Søndag"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Søn", + "Man", + "Tir", + "Ons", + "Tor", + "Fre", + "Lør", + "Søn"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Januar", + "Februar", + "Mars", + "April", + "Mai", + "Juni", + "Juli", + "August", + "September", + "Oktober", + "November", + "Desember"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Mai", + "Jun", + "Jul", + "Aug", + "Sep", + "Okt", + "Nov", + "Des"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Om kalenderen"; + +Calendar._TT["ABOUT"] = +"DHTML Dato-/Tidsvelger\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For nyeste versjon, gå til: http://www.dynarch.com/projects/calendar/\n" + +"Distribuert under GNU LGPL. Se http://gnu.org/licenses/lgpl.html for detaljer." + +"\n\n" + +"Datovalg:\n" + +"- Bruk knappene \xab og \xbb for å velge år\n" + +"- Bruk knappene " + String.fromCharCode(0x2039) + " og " + String.fromCharCode(0x203a) + " for å velge måned\n" + +"- Hold inne musknappen eller knappene over for raskere valg."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Tidsvalg:\n" + +"- Klikk på en av tidsdelene for å øke den\n" + +"- eller Shift-klikk for å senke verdien\n" + +"- eller klikk-og-dra for raskere valg.."; + +Calendar._TT["PREV_YEAR"] = "Forrige. år (hold for meny)"; +Calendar._TT["PREV_MONTH"] = "Forrige. måned (hold for meny)"; +Calendar._TT["GO_TODAY"] = "Gå til idag"; +Calendar._TT["NEXT_MONTH"] = "Neste måned (hold for meny)"; +Calendar._TT["NEXT_YEAR"] = "Neste år (hold for meny)"; +Calendar._TT["SEL_DATE"] = "Velg dato"; +Calendar._TT["DRAG_TO_MOVE"] = "Dra for å flytte"; +Calendar._TT["PART_TODAY"] = " (idag)"; +Calendar._TT["MON_FIRST"] = "Vis mandag først"; +Calendar._TT["SUN_FIRST"] = "Vis søndag først"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Vis %s først"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0"; + +Calendar._TT["CLOSE"] = "Lukk"; +Calendar._TT["TODAY"] = "Idag"; +Calendar._TT["TIME_PART"] = "(Shift-)Klikk eller dra for å endre verdi"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "uke"; +Calendar._TT["TIME"] = "Tid:"; \ No newline at end of file diff --git a/web/sf/calendar/lang/calendar-pl.js b/web/sf/calendar/lang/calendar-pl.js new file mode 100644 index 0000000..c054771 --- /dev/null +++ b/web/sf/calendar/lang/calendar-pl.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar PL language +// Author: Krzychu Danek, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Niedziela", + "Poniedziałek", + "Wtorek", + "Środa", + "Czwartek", + "Piątek", + "Sobota", + "Niedziela"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("N", + "Pon", + "Wt", + "Śr", + "Czw", + "Pi", + "So", + "N"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Styczeń", + "Luty", + "Marzec", + "Kwiecień", + "Maj", + "Czerwiec", + "Lipiec", + "Sierpień", + "Wrzesień", + "Październik", + "Listopad", + "Grudzień"); + +// short month names +Calendar._SMN = new Array +("Sty", + "Lut", + "Mar", + "Kwi", + "Maj", + "Cze", + "Lip", + "Sie", + "Wrz", + "Paź", + "Lis", + "Gru"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O kalendarzu"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Wybór daty:\n" + +"- aby wybrać rok użyj przycisków \xab, \xbb\n" + +"- aby wybrać miesiąc użyj przycisków " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + "\n" + +"- aby przyspieszyć wybór przytrzymaj wciśnięty przycisk myszy nad ww. przyciskami."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Wybór czasu:\n" + +"- aby zwiększyć wartość kliknij na dowolnym elemencie selekcji czasu\n" + +"- aby zmniejszyć wartość użyj dodatkowo klawisza Shift\n" + +"- możesz również poruszać myszkę w lewo i prawo wraz z wciśniętym lewym klawiszem."; + +Calendar._TT["PREV_YEAR"] = "Poprz. rok (przytrzymaj dla menu)"; +Calendar._TT["PREV_MONTH"] = "Poprz. miesiąc (przytrzymaj dla menu)"; +Calendar._TT["GO_TODAY"] = "Pokaż dziś"; +Calendar._TT["NEXT_MONTH"] = "Nast. miesiąc (przytrzymaj dla menu)"; +Calendar._TT["NEXT_YEAR"] = "Nast. rok (przytrzymaj dla menu)"; +Calendar._TT["SEL_DATE"] = "Wybierz datę"; +Calendar._TT["DRAG_TO_MOVE"] = "Przesuń okienko"; +Calendar._TT["PART_TODAY"] = " (dziś)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Pokaż dzień %s jako pierwszy"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zamknij"; +Calendar._TT["TODAY"] = "Dziś"; +Calendar._TT["TIME_PART"] = "(Shift-)klik | drag, aby zmienić wartość"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Czas:"; diff --git a/web/sf/calendar/lang/calendar-pt.js b/web/sf/calendar/lang/calendar-pt.js new file mode 100644 index 0000000..29505d1 --- /dev/null +++ b/web/sf/calendar/lang/calendar-pt.js @@ -0,0 +1,130 @@ +// ** I18N + +// Calendar pt_BR language +// Author: Adalberto Machado, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domingo", + "Segunda", + "Terca", + "Quarta", + "Quinta", + "Sexta", + "Sabado", + "Domingo"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dom", + "Seg", + "Ter", + "Qua", + "Qui", + "Sex", + "Sab", + "Dom"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Janeiro", + "Fevereiro", + "Marco", + "Abril", + "Maio", + "Junho", + "Julho", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Dezembro"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Fev", + "Mar", + "Abr", + "Mai", + "Jun", + "Jul", + "Ago", + "Set", + "Out", + "Nov", + "Dez"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Sobre o calendario"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Ultima versao visite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuido sobre GNU LGPL. Veja http://gnu.org/licenses/lgpl.html para detalhes." + +"\n\n" + +"Selecao de data:\n" + +"- Use os botoes \xab, \xbb para selecionar o ano\n" + +"- Use os botoes " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para selecionar o mes\n" + +"- Segure o botao do mouse em qualquer um desses botoes para selecao rapida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selecao de hora:\n" + +"- Clique em qualquer parte da hora para incrementar\n" + +"- ou Shift-click para decrementar\n" + +"- ou clique e segure para selecao rapida."; + +Calendar._TT["PREV_YEAR"] = "Ant. ano (segure para menu)"; +Calendar._TT["PREV_MONTH"] = "Ant. mes (segure para menu)"; +Calendar._TT["GO_TODAY"] = "Hoje"; +Calendar._TT["NEXT_MONTH"] = "Prox. mes (segure para menu)"; +Calendar._TT["NEXT_YEAR"] = "Prox. ano (segure para menu)"; +Calendar._TT["SEL_DATE"] = "Selecione a data"; +Calendar._TT["DRAG_TO_MOVE"] = "Arraste para mover"; +Calendar._TT["PART_TODAY"] = " (hoje)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Mostre %s primeiro"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Fechar"; +Calendar._TT["TODAY"] = "Hoje"; +Calendar._TT["TIME_PART"] = "(Shift-)Click ou arraste para mudar valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b"; + +Calendar._TT["WK"] = "sm"; +Calendar._TT["TIME"] = "Hora:"; + +Calendar._SMN_len = 3; + diff --git a/web/sf/calendar/lang/calendar-pt_BR.js b/web/sf/calendar/lang/calendar-pt_BR.js new file mode 100644 index 0000000..c0ec001 --- /dev/null +++ b/web/sf/calendar/lang/calendar-pt_BR.js @@ -0,0 +1,112 @@ +// ** I18N + +// Calendar pt-BR language +// Author: Fernando Dourado, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domingo", + "Segunda", + "Terça", + "Quarta", + "Quinta", + "Sexta", + "Sabádo", + "Domingo"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +// [No changes using default values] + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Janeiro", + "Fevereiro", + "Março", + "Abril", + "Maio", + "Junho", + "Julho", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Dezembro"); + +// short month names +// [No changes using default values] + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Sobre o calendário"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Translate to portuguese Brazil (pt-BR) by Fernando Dourado (fernando.dourado@ig.com.br)\n" + +"Tradução para o português Brasil (pt-BR) por Fernando Dourado (fernando.dourado@ig.com.br)" + +"\n\n" + +"Selecionar data:\n" + +"- Use as teclas \xab, \xbb para selecionar o ano\n" + +"- Use as teclas " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para selecionar o mês\n" + +"- Clique e segure com o mouse em qualquer botão para selecionar rapidamente."; + +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selecionar hora:\n" + +"- Clique em qualquer uma das partes da hora para aumentar\n" + +"- ou Shift-clique para diminuir\n" + +"- ou clique e arraste para selecionar rapidamente."; + +Calendar._TT["PREV_YEAR"] = "Ano anterior (clique e segure para menu)"; +Calendar._TT["PREV_MONTH"] = "Mês anterior (clique e segure para menu)"; +Calendar._TT["GO_TODAY"] = "Ir para a data atual"; +Calendar._TT["NEXT_MONTH"] = "Próximo mês (clique e segure para menu)"; +Calendar._TT["NEXT_YEAR"] = "Próximo ano (clique e segure para menu)"; +Calendar._TT["SEL_DATE"] = "Selecione uma data"; +Calendar._TT["DRAG_TO_MOVE"] = "Clique e segure para mover"; +Calendar._TT["PART_TODAY"] = " (hoje)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Exibir %s primeiro"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Fechar"; +Calendar._TT["TODAY"] = "Hoje"; +Calendar._TT["TIME_PART"] = "(Shift-)Clique ou arraste para mudar o valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%d de %B de %Y"; + +Calendar._TT["WK"] = "sem"; +Calendar._TT["TIME"] = "Hora:"; + diff --git a/web/sf/calendar/lang/calendar-ro.js b/web/sf/calendar/lang/calendar-ro.js new file mode 100644 index 0000000..5113df5 --- /dev/null +++ b/web/sf/calendar/lang/calendar-ro.js @@ -0,0 +1,72 @@ +// ** I18N +Calendar._DN = new Array +("Duminică", + "Luni", + "Marţi", + "Miercuri", + "Joi", + "Vineri", + "Sâmbătă", + "Duminică"); +Calendar._SDN_len = 2; + + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +Calendar._MN = new Array +("Ianuarie", + "Februarie", + "Martie", + "Aprilie", + "Mai", + "Iunie", + "Iulie", + "August", + "Septembrie", + "Octombrie", + "Noiembrie", + "Decembrie"); + +// tooltips +Calendar._TT = {}; + +Calendar._TT["INFO"] = "Despre calendar"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Pentru ultima versiune vizitaţi: http://www.dynarch.com/projects/calendar/\n" + +"Distribuit sub GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Selecţia datei:\n" + +"- Folosiţi butoanele \xab, \xbb pentru a selecta anul\n" + +"- Folosiţi butoanele " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pentru a selecta luna\n" + +"- Tineţi butonul mouse-ului apăsat pentru selecţie mai rapidă."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selecţia orei:\n" + +"- Click pe ora sau minut pentru a mări valoarea cu 1\n" + +"- Sau Shift-Click pentru a micşora valoarea cu 1\n" + +"- Sau Click şi drag pentru a selecta mai repede."; + +Calendar._TT["PREV_YEAR"] = "Anul precedent (lung pt menu)"; +Calendar._TT["PREV_MONTH"] = "Luna precedentă (lung pt menu)"; +Calendar._TT["GO_TODAY"] = "Data de azi"; +Calendar._TT["NEXT_MONTH"] = "Luna următoare (lung pt menu)"; +Calendar._TT["NEXT_YEAR"] = "Anul următor (lung pt menu)"; +Calendar._TT["SEL_DATE"] = "Selectează data"; +Calendar._TT["DRAG_TO_MOVE"] = "Trage pentru a mişca"; +Calendar._TT["PART_TODAY"] = " (astăzi)"; +Calendar._TT["DAY_FIRST"] = "Afişează %s prima zi"; +Calendar._TT["WEEKEND"] = "0,6"; +Calendar._TT["CLOSE"] = "Închide"; +Calendar._TT["TODAY"] = "Astăzi"; +Calendar._TT["TIME_PART"] = "(Shift-)Click sau drag pentru a selecta"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %d %B"; + +Calendar._TT["WK"] = "spt"; +Calendar._TT["TIME"] = "Ora:"; diff --git a/web/sf/calendar/lang/calendar-ru.js b/web/sf/calendar/lang/calendar-ru.js new file mode 100644 index 0000000..6274cc8 --- /dev/null +++ b/web/sf/calendar/lang/calendar-ru.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar RU language +// Translation: Sly Golovanov, http://golovanov.net, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("воскресенье", + "понедельник", + "вторник", + "среда", + "четверг", + "пятница", + "суббота", + "воскресенье"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("вск", + "пон", + "втр", + "срд", + "чет", + "пят", + "суб", + "вск"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("январь", + "февраль", + "март", + "апрель", + "май", + "июнь", + "июль", + "август", + "сентябрь", + "октябрь", + "ноябрь", + "декабрь"); + +// short month names +Calendar._SMN = new Array +("янв", + "фев", + "мар", + "апр", + "май", + "июн", + "июл", + "авг", + "сен", + "окт", + "ноя", + "дек"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "О календаре..."; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Как выбрать дату:\n" + +"- При помощи кнопок \xab, \xbb можно выбрать год\n" + +"- При помощи кнопок " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " можно выбрать месяц\n" + +"- Подержите эти кнопки нажатыми, чтобы появилось меню быстрого выбора."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Как выбрать время:\n" + +"- При клике на часах или минутах они увеличиваются\n" + +"- при клике с нажатой клавишей Shift они уменьшаются\n" + +"- если нажать и двигать мышкой влево/вправо, они будут меняться быстрее."; + +Calendar._TT["PREV_YEAR"] = "На год назад (удерживать для меню)"; +Calendar._TT["PREV_MONTH"] = "На месяц назад (удерживать для меню)"; +Calendar._TT["GO_TODAY"] = "Сегодня"; +Calendar._TT["NEXT_MONTH"] = "На месяц вперед (удерживать для меню)"; +Calendar._TT["NEXT_YEAR"] = "На год вперед (удерживать для меню)"; +Calendar._TT["SEL_DATE"] = "Выберите дату"; +Calendar._TT["DRAG_TO_MOVE"] = "Перетаскивайте мышкой"; +Calendar._TT["PART_TODAY"] = " (сегодня)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Первый день недели будет %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Закрыть"; +Calendar._TT["TODAY"] = "Сегодня"; +Calendar._TT["TIME_PART"] = "(Shift-)клик или нажать и двигать"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%e %b, %a"; + +Calendar._TT["WK"] = "нед"; +Calendar._TT["TIME"] = "Время:"; diff --git a/web/sf/calendar/lang/calendar-sk.js b/web/sf/calendar/lang/calendar-sk.js new file mode 100644 index 0000000..b9f3fef --- /dev/null +++ b/web/sf/calendar/lang/calendar-sk.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Nedeľa", + "Pondelok", + "Utorok", + "Streda", + "Štvrtok", + "Piatok", + "Sobota", + "Nedeľa"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Ne", + "Po", + "Ut", + "St", + "Št", + "Pi", + "So", + "Ne"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Január", + "Február", + "Marec", + "Apríl", + "Máj", + "Jún", + "Júl", + "August", + "September", + "Október", + "November", + "December"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Máj", + "Jún", + "Júl", + "Aug", + "Sep", + "Okt", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O kalendári"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Autor: Mihai Bazon\n" + // don't translate this this ;-) +"Poslednú verziu nájdete na: http://www.dynarch.com/projects/calendar/\n" + +"Distribuované pod licenciou GNU LGPL /http://gnu.org/licenses/lgpl.html/" + +"\n\n" + +"Výber dátumu:\n" + +"- Použite tlačidlá \xab, \xbb pre výber roku\n" + +"- Použite tlačidlá " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pre výber mesiaca\n" + +"- Podrž tlačidlo myši nad akýmkoľvek tlačidlom pre rýchlejší výber."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Výber času:\n" + +"- Kliknutie na niektorú položku času ju zväčší\n" + +"- Shift-kliknutie ju zmenší\n" + +"- ak necháte tlačítko myši stlačené, posúvaním meníte hodnotu."; + +Calendar._TT["PREV_YEAR"] = "Predošlý rok (podržte pre menu)"; +Calendar._TT["PREV_MONTH"] = "Predošlý mesiac (podržte pre menu)"; +Calendar._TT["GO_TODAY"] = "Prejsť na dnešok"; +Calendar._TT["NEXT_MONTH"] = "Nasled. mesiac (podržte pre menu)"; +Calendar._TT["NEXT_YEAR"] = "Nasled. rok (podržte pre menu)"; +Calendar._TT["SEL_DATE"] = "Vyberte dátum"; +Calendar._TT["DRAG_TO_MOVE"] = "Podržaním tlačítka zmeňte polohu"; +Calendar._TT["PART_TODAY"] = " (dnes)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Zobraz %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zavrieť"; +Calendar._TT["TODAY"] = "Dnes"; +Calendar._TT["TIME_PART"] = "(Shift-)klik/ťahanie zmení hodnotu"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "týž"; +Calendar._TT["TIME"] = "Čas:"; diff --git a/web/sf/calendar/lang/calendar-sl.js b/web/sf/calendar/lang/calendar-sl.js new file mode 100644 index 0000000..144fb20 --- /dev/null +++ b/web/sf/calendar/lang/calendar-sl.js @@ -0,0 +1,109 @@ +/* Slovenian language file for the DHTML Calendar version 0.9.2 +* Author David Milost , January 2004. +* Feel free to use this script under the terms of the GNU Lesser General +* Public License, as long as you do not remove or alter this notice. +*/ + // full day names +Calendar._DN = new Array +("Nedelja", + "Ponedeljek", + "Torek", + "Sreda", + "Četrtek", + "Petek", + "Sobota", + "Nedelja"); + // short day names + Calendar._SDN = new Array +("Ned", + "Pon", + "Tor", + "Sre", + "Čet", + "Pet", + "Sob", + "Ned"); +// short month names + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Maj", + "Jun", + "Jul", + "Avg", + "Sep", + "Okt", + "Nov", + "Dec"); + // full month names +Calendar._MN = new Array +("Januar", + "Februar", + "Marec", + "April", + "Maj", + "Junij", + "Julij", + "Avgust", + "September", + "Oktober", + "November", + "December"); + +// tooltips +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O koledarju"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Za zadnjo verzijo pojdine na naslov: http://www.dynarch.com/projects/calendar/\n" + +"Distribuirano pod GNU LGPL. Poglejte http://gnu.org/licenses/lgpl.html za podrobnosti." + +"\n\n" + +"Izbor datuma:\n" + +"- Uporabite \xab, \xbb gumbe za izbor leta\n" + +"- Uporabite " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " gumbe za izbor meseca\n" + +"- Zadržite klik na kateremkoli od zgornjih gumbov za hiter izbor."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Izbor ćasa:\n" + +"- Kliknite na katerikoli del ćasa za poveć. le-tega\n" + +"- ali Shift-click za zmanj. le-tega\n" + +"- ali kliknite in povlecite za hiter izbor."; + +Calendar._TT["TOGGLE"] = "Spremeni dan s katerim se prićne teden"; +Calendar._TT["PREV_YEAR"] = "Predhodnje leto (dolg klik za meni)"; +Calendar._TT["PREV_MONTH"] = "Predhodnji mesec (dolg klik za meni)"; +Calendar._TT["GO_TODAY"] = "Pojdi na tekoći dan"; +Calendar._TT["NEXT_MONTH"] = "Naslednji mesec (dolg klik za meni)"; +Calendar._TT["NEXT_YEAR"] = "Naslednje leto (dolg klik za meni)"; +Calendar._TT["SEL_DATE"] = "Izberite datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Pritisni in povleci za spremembo pozicije"; +Calendar._TT["PART_TODAY"] = " (danes)"; +Calendar._TT["MON_FIRST"] = "Prikaži ponedeljek kot prvi dan"; +Calendar._TT["SUN_FIRST"] = "Prikaži nedeljo kot prvi dan"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zapri"; +Calendar._TT["TODAY"] = "Danes"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "Ted"; \ No newline at end of file diff --git a/web/sf/calendar/lang/calendar-sq.js b/web/sf/calendar/lang/calendar-sq.js new file mode 100644 index 0000000..1bb13c5 --- /dev/null +++ b/web/sf/calendar/lang/calendar-sq.js @@ -0,0 +1,104 @@ +// Calendar ALBANIAN language +//author Rigels Gordani rige@hotmail.com + +// ditet +Calendar._DN = new Array +("E Diele", +"E Hene", +"E Marte", +"E Merkure", +"E Enjte", +"E Premte", +"E Shtune", +"E Diele"); + +//ditet shkurt +Calendar._SDN = new Array +("Die", +"Hen", +"Mar", +"Mer", +"Enj", +"Pre", +"Sht", +"Die"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// muajt +Calendar._MN = new Array +("Janar", +"Shkurt", +"Mars", +"Prill", +"Maj", +"Qeshor", +"Korrik", +"Gusht", +"Shtator", +"Tetor", +"Nentor", +"Dhjetor"); + +// muajte shkurt +Calendar._SMN = new Array +("Jan", +"Shk", +"Mar", +"Pri", +"Maj", +"Qes", +"Kor", +"Gus", +"Sht", +"Tet", +"Nen", +"Dhj"); + +// ndihmesa +Calendar._TT = {}; +Calendar._TT["INFO"] = "Per kalendarin"; + +Calendar._TT["ABOUT"] = +"Zgjedhes i ores/dates ne DHTML \n" + +"\n\n" +"Zgjedhja e Dates:\n" + +"- Perdor butonat \xab, \xbb per te zgjedhur vitin\n" + +"- Perdor butonat" + String.fromCharCode(0x2039) + ", " + +String.fromCharCode(0x203a) + +" per te zgjedhur muajin\n" + +"- Mbani shtypur butonin e mousit per nje zgjedje me te shpejte."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Zgjedhja e kohes:\n" + +"- Kliko tek ndonje nga pjeset e ores per ta rritur ate\n" + +"- ose kliko me Shift per ta zvogeluar ate\n" + +"- ose cliko dhe terhiq per zgjedhje me te shpejte."; + +Calendar._TT["PREV_YEAR"] = "Viti i shkuar (prit per menune)"; +Calendar._TT["PREV_MONTH"] = "Muaji i shkuar (prit per menune)"; +Calendar._TT["GO_TODAY"] = "Sot"; +Calendar._TT["NEXT_MONTH"] = "Muaji i ardhshem (prit per menune)"; +Calendar._TT["NEXT_YEAR"] = "Viti i ardhshem (prit per menune)"; +Calendar._TT["SEL_DATE"] = "Zgjidh daten"; +Calendar._TT["DRAG_TO_MOVE"] = "Terhiqe per te levizur"; +Calendar._TT["PART_TODAY"] = " (sot)"; + +// "%s" eshte dita e pare e javes +// %s do te zevendesohet me emrin e dite +Calendar._TT["DAY_FIRST"] = "Trego te %s te paren"; + + +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Mbyll"; +Calendar._TT["TODAY"] = "Sot"; +Calendar._TT["TIME_PART"] = "Kliko me (Shift-)ose terhiqe per te ndryshuar vleren"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "Java"; +Calendar._TT["TIME"] = "Koha:"; + diff --git a/web/sf/calendar/lang/calendar-sr.js b/web/sf/calendar/lang/calendar-sr.js new file mode 100644 index 0000000..56191f8 Binary files /dev/null and b/web/sf/calendar/lang/calendar-sr.js differ diff --git a/web/sf/calendar/lang/calendar-sv.js b/web/sf/calendar/lang/calendar-sv.js new file mode 100644 index 0000000..8f1a7e5 --- /dev/null +++ b/web/sf/calendar/lang/calendar-sv.js @@ -0,0 +1,132 @@ +// ** I18N + +// Calendar SV language (Swedish, svenska) +// Author: Mihai Bazon, +// Translation team: +// Translator: Leonard Norrgård +// Last translator: Emil Ljungdahl +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("söndag", + "måndag", + "tisdag", + "onsdag", + "torsdag", + "fredag", + "lördag", + "söndag"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("sön", + "mån", + "tis", + "ons", + "tor", + "fre", + "lör", + "sön"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("januari", + "februari", + "mars", + "april", + "maj", + "juni", + "juli", + "augusti", + "september", + "oktober", + "november", + "december"); + +// short month names +Calendar._SMN = new Array +("jan", + "feb", + "mar", + "apr", + "maj", + "jun", + "jul", + "aug", + "sep", + "okt", + "nov", + "dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Om kalendern"; + +Calendar._TT["ABOUT"] = +"DHTML Datum/tid-väljare\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"För senaste version gå till: http://www.dynarch.com/projects/calendar/\n" + +"Distribueras under GNU LGPL. Se http://gnu.org/licenses/lgpl.html för detaljer." + +"\n\n" + +"Val av datum:\n" + +"- Använd knapparna \xab, \xbb för att välja år\n" + +"- Använd knapparna " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " för att välja månad\n" + +"- Håll musknappen nedtryckt på någon av ovanstående knappar för snabbare val."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Val av tid:\n" + +"- Klicka på en del av tiden för att öka den delen\n" + +"- eller skift-klicka för att minska den\n" + +"- eller klicka och drag för snabbare val."; + +Calendar._TT["PREV_YEAR"] = "Föregående år (håll för menu)"; +Calendar._TT["PREV_MONTH"] = "Föregående månad (håll för menu)"; +Calendar._TT["GO_TODAY"] = "Gå till dagens datum"; +Calendar._TT["NEXT_MONTH"] = "Följande månad (håll för menu)"; +Calendar._TT["NEXT_YEAR"] = "Följande år (håll för menu)"; +Calendar._TT["SEL_DATE"] = "Välj datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Drag för att flytta"; +Calendar._TT["PART_TODAY"] = " (idag)"; +Calendar._TT["MON_FIRST"] = "Visa måndag först"; +Calendar._TT["SUN_FIRST"] = "Visa söndag först"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Visa %s först"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0"; + +Calendar._TT["CLOSE"] = "Stäng"; +Calendar._TT["TODAY"] = "Idag"; +Calendar._TT["TIME_PART"] = "(Skift-)klicka eller drag för att ändra tid"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%A %d %b %Y"; + +Calendar._TT["WK"] = "vecka"; +Calendar._TT["TIME"] = "Tid:"; diff --git a/web/sf/calendar/lang/calendar-tr.js b/web/sf/calendar/lang/calendar-tr.js new file mode 100644 index 0000000..b99710e --- /dev/null +++ b/web/sf/calendar/lang/calendar-tr.js @@ -0,0 +1,73 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// Turkish Translation by Nuri AKMAN +// Location: Ankara/TURKEY +// e-mail : nuriakman@hotmail.com +// Date : April, 9 2003 +// +// Note: if Turkish Characters does not shown on you screen +// please include falowing line your html code: +// +// +// +////////////////////////////////////////////////////////////////////////////////////////////// + +// ** I18N +Calendar._DN = new Array +("Pazar", + "Pazartesi", + "Salı", + "Çarşamba", + "Perşembe", + "Cuma", + "Cumartesi", + "Pazar"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +Calendar._MN = new Array +("Ocak", + "Şubat", + "Mart", + "Nisan", + "Mayıs", + "Haziran", + "Temmuz", + "Ağustos", + "Eylül", + "Ekim", + "Kasım", + "Aralık"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["TOGGLE"] = "Haftanın ilk gününü kaydır"; +Calendar._TT["PREV_YEAR"] = "Önceki Yıl (Menü için basılı tutunuz)"; +Calendar._TT["PREV_MONTH"] = "Önceki Ay (Menü için basılı tutunuz)"; +Calendar._TT["GO_TODAY"] = "Bugün'e git"; +Calendar._TT["NEXT_MONTH"] = "Sonraki Ay (Menü için basılı tutunuz)"; +Calendar._TT["NEXT_YEAR"] = "Sonraki Yıl (Menü için basılı tutunuz)"; +Calendar._TT["SEL_DATE"] = "Tarih seçiniz"; +Calendar._TT["DRAG_TO_MOVE"] = "Taşımak için sürükleyiniz"; +Calendar._TT["PART_TODAY"] = " (bugün)"; +Calendar._TT["MON_FIRST"] = "Takvim Pazartesi gününden başlasın"; +Calendar._TT["SUN_FIRST"] = "Takvim Pazar gününden başlasın"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Display %s first"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Kapat"; +Calendar._TT["TODAY"] = "Bugün"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "dd-mm-y"; +Calendar._TT["TT_DATE_FORMAT"] = "d MM y, DD"; + +Calendar._TT["WK"] = "Hafta"; diff --git a/web/sf/calendar/lang/calendar-zh.js b/web/sf/calendar/lang/calendar-zh.js new file mode 100644 index 0000000..c26d31e --- /dev/null +++ b/web/sf/calendar/lang/calendar-zh.js @@ -0,0 +1,123 @@ +// ** I18N + +// Calendar ZH language +// Author: muziq, +// Encoding: GB2312 or GBK +// Distributed under the same terms as the calendar itself. + +// full day names +Calendar._DN = new Array +("星期日", + "星期一", + "星期二", + "星期三", + "星期四", + "星期五", + "星期六", + "星期日"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("日", + "一", + "二", + "三", + "四", + "五", + "六", + "日"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("一月", + "二月", + "三月", + "四月", + "五月", + "六月", + "七月", + "八月", + "九月", + "十月", + "十一月", + "十二月"); + +// short month names +Calendar._SMN = new Array +("一月", + "二月", + "三月", + "四月", + "五月", + "六月", + "七月", + "八月", + "九月", + "十月", + "十一月", + "十二月"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "帮助"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"选择日期:\n" + +"- 点击 \xab, \xbb 按钮选择年份\n" + +"- 点击 " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " 按钮选择月份\n" + +"- 长按以上按钮可从菜单中快速选择年份或月份"; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"选择时间:\n" + +"- 点击小时或分钟可使改数值加一\n" + +"- 按住Shift键点击小时或分钟可使改数值减一\n" + +"- 点击拖动鼠标可进行快速选择"; + +Calendar._TT["PREV_YEAR"] = "上一年 (按住出菜单)"; +Calendar._TT["PREV_MONTH"] = "上一月 (按住出菜单)"; +Calendar._TT["GO_TODAY"] = "转到今日"; +Calendar._TT["NEXT_MONTH"] = "下一月 (按住出菜单)"; +Calendar._TT["NEXT_YEAR"] = "下一年 (按住出菜单)"; +Calendar._TT["SEL_DATE"] = "选择日期"; +Calendar._TT["DRAG_TO_MOVE"] = "拖动"; +Calendar._TT["PART_TODAY"] = " (今日)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "最左边显示%s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "关闭"; +Calendar._TT["TODAY"] = "今日"; +Calendar._TT["TIME_PART"] = "(Shift-)点击鼠标或拖动改变值"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %b %e日"; + +Calendar._TT["WK"] = "周"; +Calendar._TT["TIME"] = "时间:"; diff --git a/web/sf/calendar/skins/aqua/active-bg.gif b/web/sf/calendar/skins/aqua/active-bg.gif new file mode 100644 index 0000000..d608c54 Binary files /dev/null and b/web/sf/calendar/skins/aqua/active-bg.gif differ diff --git a/web/sf/calendar/skins/aqua/dark-bg.gif b/web/sf/calendar/skins/aqua/dark-bg.gif new file mode 100644 index 0000000..1dea48a Binary files /dev/null and b/web/sf/calendar/skins/aqua/dark-bg.gif differ diff --git a/web/sf/calendar/skins/aqua/hover-bg.gif b/web/sf/calendar/skins/aqua/hover-bg.gif new file mode 100644 index 0000000..fbf94fc Binary files /dev/null and b/web/sf/calendar/skins/aqua/hover-bg.gif differ diff --git a/web/sf/calendar/skins/aqua/menuarrow.gif b/web/sf/calendar/skins/aqua/menuarrow.gif new file mode 100644 index 0000000..40c0aad Binary files /dev/null and b/web/sf/calendar/skins/aqua/menuarrow.gif differ diff --git a/web/sf/calendar/skins/aqua/normal-bg.gif b/web/sf/calendar/skins/aqua/normal-bg.gif new file mode 100644 index 0000000..bdb5068 Binary files /dev/null and b/web/sf/calendar/skins/aqua/normal-bg.gif differ diff --git a/web/sf/calendar/skins/aqua/rowhover-bg.gif b/web/sf/calendar/skins/aqua/rowhover-bg.gif new file mode 100644 index 0000000..7715342 Binary files /dev/null and b/web/sf/calendar/skins/aqua/rowhover-bg.gif differ diff --git a/web/sf/calendar/skins/aqua/status-bg.gif b/web/sf/calendar/skins/aqua/status-bg.gif new file mode 100644 index 0000000..857108c Binary files /dev/null and b/web/sf/calendar/skins/aqua/status-bg.gif differ diff --git a/web/sf/calendar/skins/aqua/theme.css b/web/sf/calendar/skins/aqua/theme.css new file mode 100644 index 0000000..f6829d1 --- /dev/null +++ b/web/sf/calendar/skins/aqua/theme.css @@ -0,0 +1,242 @@ +/* Distributed as part of The Coolest DHTML Calendar + Author: Mihai Bazon, www.bazon.net/mishoo + Copyright Dynarch.com 2005, www.dynarch.com +*/ + +/* The main calendar widget. DIV containing a table. */ + +div.calendar { position: relative; } + +.calendar, .calendar table { + border: 1px solid #bdb2bf; + font-size: 11px; + color: #000; + cursor: default; + background: url("normal-bg.gif"); + font-family: "trebuchet ms",verdana,tahoma,sans-serif; + border-collapse: separate; +} + +.calendar td +{ + background: url("normal-bg.gif"); +} + +.calendar { + border-color: #797979; +} + +/* Header part -- contains navigation buttons and day names. */ + +.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ + text-align: center; /* They are the navigation buttons */ + padding: 2px; /* Make the buttons seem like they're pressing */ + background: url("title-bg.gif") repeat-x 0 100%; color: #000; + font-weight: bold; +} + +.calendar .nav { + font-family: verdana,tahoma,sans-serif; +} + +.calendar .nav div { + background: transparent url("menuarrow.gif") no-repeat 100% 100%; +} + +.calendar thead tr { background: url("title-bg.gif") repeat-x 0 100%; color: #000; } + +.calendar thead .title { /* This holds the current "month, year" */ + font-weight: bold; /* Pressing it will take you to the current date */ + text-align: center; + padding: 2px; + background: url("title-bg.gif") repeat-x 0 100%; color: #000; +} + +.calendar thead .headrow { /* Row containing navigation buttons */ +} + +.calendar thead .name { /* Cells containing the day names */ + border-bottom: 1px solid #797979; + padding: 2px; + text-align: center; + color: #000; +} + +.calendar thead .weekend { /* How a weekend day name shows in header */ + color: #c44; +} + +.calendar thead .hilite { /* How do the buttons in header appear when hover */ + background: url("hover-bg.gif"); + border-bottom: 1px solid #797979; + padding: 2px 2px 1px 2px; +} + +.calendar thead .active { /* Active (pressed) buttons in header */ + background: url("active-bg.gif"); color: #fff; + padding: 3px 1px 0px 3px; + border-bottom: 1px solid #797979; +} + +.calendar thead .daynames { /* Row containing the day names */ + background: url("dark-bg.gif"); +} + +/* The body part -- contains all the days in month. */ + +.calendar tbody .day { /* Cells containing month days dates */ + font-family: verdana,tahoma,sans-serif; + width: 2em; + color: #000; + text-align: right; + padding: 2px 4px 2px 2px; +} +.calendar tbody .day.othermonth { + font-size: 80%; + color: #999; +} +.calendar tbody .day.othermonth.oweekend { + color: #f99; +} + +.calendar table .wn { + padding: 2px 3px 2px 2px; + border-right: 1px solid #797979; + background: url("dark-bg.gif"); +} + +.calendar tbody .rowhilite td, +.calendar tbody .rowhilite td.wn { + background: url("rowhover-bg.gif"); +} + +.calendar tbody td.today { font-weight: bold; /* background: url("today-bg.gif") no-repeat 70% 50%; */ } + +.calendar tbody td.hilite { /* Hovered cells */ + background: url("hover-bg.gif"); + padding: 1px 3px 1px 1px; + border: 1px solid #bbb; +} + +.calendar tbody td.active { /* Active (pressed) cells */ + padding: 2px 2px 0px 2px; +} + +.calendar tbody td.weekend { /* Cells showing weekend days */ + color: #c44; +} + +.calendar tbody td.selected { /* Cell showing selected date */ + font-weight: bold; + border: 1px solid #797979; + padding: 1px 3px 1px 1px; + background: url("active-bg.gif"); color: #fff; +} + +.calendar tbody .disabled { color: #999; } + +.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ + visibility: hidden; +} + +.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ + display: none; +} + +/* The footer part -- status bar and "Close" button */ + +.calendar tfoot .footrow { /* The in footer (only one right now) */ + text-align: center; + background: #565; + color: #fff; +} + +.calendar tfoot .ttip { /* Tooltip (status bar) cell */ + padding: 2px; + background: url("status-bg.gif") repeat-x 0 0; color: #000; +} + +.calendar tfoot .hilite { /* Hover style for buttons in footer */ + background: #afa; + border: 1px solid #084; + color: #000; + padding: 1px; +} + +.calendar tfoot .active { /* Active (pressed) style for buttons in footer */ + background: #7c7; + padding: 2px 0px 0px 2px; +} + +/* Combo boxes (menus that display months/years for direct selection) */ + +.calendar .combo { + position: absolute; + display: none; + top: 0px; + left: 0px; + width: 4em; + cursor: default; + border-width: 0 1px 1px 1px; + border-style: solid; + border-color: #797979; + background: url("normal-bg.gif"); color: #000; + z-index: 100; + font-size: 90%; +} + +.calendar .combo .label, +.calendar .combo .label-IEfix { + text-align: center; + padding: 1px; +} + +.calendar .combo .label-IEfix { + width: 4em; +} + +.calendar .combo .hilite { + background: url("hover-bg.gif"); color: #000; +} + +.calendar .combo .active { + background: url("active-bg.gif"); color: #fff; + font-weight: bold; +} + +.calendar td.time { + border-top: 1px solid #797979; + padding: 1px 0px; + text-align: center; + background: url("dark-bg.gif"); +} + +.calendar td.time .hour, +.calendar td.time .minute, +.calendar td.time .ampm { + padding: 0px 5px 0px 6px; + font-weight: bold; + background: url("normal-bg.gif"); color: #000; +} + +.calendar td.time .hour, +.calendar td.time .minute { + font-family: monospace; +} + +.calendar td.time .ampm { + text-align: center; +} + +.calendar td.time .colon { + padding: 0px 2px 0px 3px; + font-weight: bold; +} + +.calendar td.time span.hilite { + background: url("hover-bg.gif"); color: #000; +} + +.calendar td.time span.active { + background: url("active-bg.gif"); color: #fff; +} diff --git a/web/sf/calendar/skins/aqua/title-bg.gif b/web/sf/calendar/skins/aqua/title-bg.gif new file mode 100644 index 0000000..6a541b3 Binary files /dev/null and b/web/sf/calendar/skins/aqua/title-bg.gif differ diff --git a/web/sf/calendar/skins/aqua/today-bg.gif b/web/sf/calendar/skins/aqua/today-bg.gif new file mode 100644 index 0000000..7161538 Binary files /dev/null and b/web/sf/calendar/skins/aqua/today-bg.gif differ diff --git a/web/sf/images/sf_admin/add.png b/web/sf/images/sf_admin/add.png new file mode 100644 index 0000000..323edb0 Binary files /dev/null and b/web/sf/images/sf_admin/add.png differ diff --git a/web/sf/images/sf_admin/cancel.png b/web/sf/images/sf_admin/cancel.png new file mode 100644 index 0000000..744df79 Binary files /dev/null and b/web/sf/images/sf_admin/cancel.png differ diff --git a/web/sf/images/sf_admin/date.png b/web/sf/images/sf_admin/date.png new file mode 100644 index 0000000..c245f1b Binary files /dev/null and b/web/sf/images/sf_admin/date.png differ diff --git a/web/sf/images/sf_admin/default_icon.png b/web/sf/images/sf_admin/default_icon.png new file mode 100644 index 0000000..3103c92 Binary files /dev/null and b/web/sf/images/sf_admin/default_icon.png differ diff --git a/web/sf/images/sf_admin/delete.png b/web/sf/images/sf_admin/delete.png new file mode 100644 index 0000000..3ba9615 Binary files /dev/null and b/web/sf/images/sf_admin/delete.png differ diff --git a/web/sf/images/sf_admin/delete_icon.png b/web/sf/images/sf_admin/delete_icon.png new file mode 100644 index 0000000..73e8638 Binary files /dev/null and b/web/sf/images/sf_admin/delete_icon.png differ diff --git a/web/sf/images/sf_admin/edit.png b/web/sf/images/sf_admin/edit.png new file mode 100644 index 0000000..62ac3a5 Binary files /dev/null and b/web/sf/images/sf_admin/edit.png differ diff --git a/web/sf/images/sf_admin/edit_icon.png b/web/sf/images/sf_admin/edit_icon.png new file mode 100644 index 0000000..62ac3a5 Binary files /dev/null and b/web/sf/images/sf_admin/edit_icon.png differ diff --git a/web/sf/images/sf_admin/error.png b/web/sf/images/sf_admin/error.png new file mode 100644 index 0000000..84b465a Binary files /dev/null and b/web/sf/images/sf_admin/error.png differ diff --git a/web/sf/images/sf_admin/filter.png b/web/sf/images/sf_admin/filter.png new file mode 100644 index 0000000..3187e59 Binary files /dev/null and b/web/sf/images/sf_admin/filter.png differ diff --git a/web/sf/images/sf_admin/first.png b/web/sf/images/sf_admin/first.png new file mode 100644 index 0000000..aa27b55 Binary files /dev/null and b/web/sf/images/sf_admin/first.png differ diff --git a/web/sf/images/sf_admin/help.png b/web/sf/images/sf_admin/help.png new file mode 100644 index 0000000..64e7412 Binary files /dev/null and b/web/sf/images/sf_admin/help.png differ diff --git a/web/sf/images/sf_admin/last.png b/web/sf/images/sf_admin/last.png new file mode 100644 index 0000000..6f8ce77 Binary files /dev/null and b/web/sf/images/sf_admin/last.png differ diff --git a/web/sf/images/sf_admin/list.png b/web/sf/images/sf_admin/list.png new file mode 100644 index 0000000..8965e34 Binary files /dev/null and b/web/sf/images/sf_admin/list.png differ diff --git a/web/sf/images/sf_admin/next.png b/web/sf/images/sf_admin/next.png new file mode 100644 index 0000000..c02a9b5 Binary files /dev/null and b/web/sf/images/sf_admin/next.png differ diff --git a/web/sf/images/sf_admin/ok.png b/web/sf/images/sf_admin/ok.png new file mode 100644 index 0000000..a24d605 Binary files /dev/null and b/web/sf/images/sf_admin/ok.png differ diff --git a/web/sf/images/sf_admin/previous.png b/web/sf/images/sf_admin/previous.png new file mode 100644 index 0000000..6cf3ac1 Binary files /dev/null and b/web/sf/images/sf_admin/previous.png differ diff --git a/web/sf/images/sf_admin/reset.png b/web/sf/images/sf_admin/reset.png new file mode 100644 index 0000000..e6e51a1 Binary files /dev/null and b/web/sf/images/sf_admin/reset.png differ diff --git a/web/sf/images/sf_admin/save.png b/web/sf/images/sf_admin/save.png new file mode 100644 index 0000000..a24d605 Binary files /dev/null and b/web/sf/images/sf_admin/save.png differ diff --git a/web/sf/images/sf_admin/tick.png b/web/sf/images/sf_admin/tick.png new file mode 100644 index 0000000..a9925a0 Binary files /dev/null and b/web/sf/images/sf_admin/tick.png differ diff --git a/web/sf/prototype/css/input_auto_complete_tag.css b/web/sf/prototype/css/input_auto_complete_tag.css new file mode 100644 index 0000000..1029e1a --- /dev/null +++ b/web/sf/prototype/css/input_auto_complete_tag.css @@ -0,0 +1,34 @@ +div.auto_complete +{ + width: 350px; + background: #fff; +} + +div.auto_complete ul +{ + width: 100%; + margin: 0; + padding: 0; + list-style-type: none; + border: 1px solid #bbb; +} + +div.auto_complete ul li +{ + margin: 0; + padding: 3px; + border-bottom: 1px solid #eee; + list-style-type: none; +} + +div.auto_complete ul li.selected +{ + background-color: #ffb; +} + +div.auto_complete ul strong.highlight +{ + margin: 0; + padding: 0; + color: #800; +} diff --git a/web/sf/prototype/js/builder.js b/web/sf/prototype/js/builder.js new file mode 100644 index 0000000..199afc1 --- /dev/null +++ b/web/sf/prototype/js/builder.js @@ -0,0 +1,131 @@ +// script.aculo.us builder.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 + +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +var Builder = { + NODEMAP: { + AREA: 'map', + CAPTION: 'table', + COL: 'table', + COLGROUP: 'table', + LEGEND: 'fieldset', + OPTGROUP: 'select', + OPTION: 'select', + PARAM: 'object', + TBODY: 'table', + TD: 'table', + TFOOT: 'table', + TH: 'table', + THEAD: 'table', + TR: 'table' + }, + // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, + // due to a Firefox bug + node: function(elementName) { + elementName = elementName.toUpperCase(); + + // try innerHTML approach + var parentTag = this.NODEMAP[elementName] || 'div'; + var parentElement = document.createElement(parentTag); + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" + elementName + ">"; + } catch(e) {} + var element = parentElement.firstChild || null; + + // see if browser added wrapping tags + if(element && (element.tagName.toUpperCase() != elementName)) + element = element.getElementsByTagName(elementName)[0]; + + // fallback to createElement approach + if(!element) element = document.createElement(elementName); + + // abort if nothing could be created + if(!element) return; + + // attributes (or text) + if(arguments[1]) + if(this._isStringOrNumber(arguments[1]) || + (arguments[1] instanceof Array)) { + this._children(element, arguments[1]); + } else { + var attrs = this._attributes(arguments[1]); + if(attrs.length) { + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" +elementName + " " + + attrs + ">"; + } catch(e) {} + element = parentElement.firstChild || null; + // workaround firefox 1.0.X bug + if(!element) { + element = document.createElement(elementName); + for(attr in arguments[1]) + element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; + } + if(element.tagName.toUpperCase() != elementName) + element = parentElement.getElementsByTagName(elementName)[0]; + } + } + + // text, or array of children + if(arguments[2]) + this._children(element, arguments[2]); + + return element; + }, + _text: function(text) { + return document.createTextNode(text); + }, + + ATTR_MAP: { + 'className': 'class', + 'htmlFor': 'for' + }, + + _attributes: function(attributes) { + var attrs = []; + for(attribute in attributes) + attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) + + '="' + attributes[attribute].toString().escapeHTML() + '"'); + return attrs.join(" "); + }, + _children: function(element, children) { + if(typeof children=='object') { // array can hold nodes and text + children.flatten().each( function(e) { + if(typeof e=='object') + element.appendChild(e) + else + if(Builder._isStringOrNumber(e)) + element.appendChild(Builder._text(e)); + }); + } else + if(Builder._isStringOrNumber(children)) + element.appendChild(Builder._text(children)); + }, + _isStringOrNumber: function(param) { + return(typeof param=='string' || typeof param=='number'); + }, + build: function(html) { + var element = this.node('div'); + $(element).update(html.strip()); + return element.down(); + }, + dump: function(scope) { + if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope + + var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " + + "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " + + "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+ + "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+ + "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+ + "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/); + + tags.each( function(tag){ + scope[tag] = function() { + return Builder.node.apply(Builder, [tag].concat($A(arguments))); + } + }); + } +} diff --git a/web/sf/prototype/js/controls.js b/web/sf/prototype/js/controls.js new file mode 100644 index 0000000..46f2cc1 --- /dev/null +++ b/web/sf/prototype/js/controls.js @@ -0,0 +1,835 @@ +// script.aculo.us controls.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 + +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005, 2006 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = {} +Autocompleter.Base = function() {}; +Autocompleter.Base.prototype = { + baseInitialize: function(element, update, options) { + this.element = $(element); + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + + if(this.setOptions) + this.setOptions(options); + else + this.options = options || {}; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, { + setHeight: false, + offsetTop: element.offsetHeight + }); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if(typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (navigator.appVersion.indexOf('MSIE')>0) && + (navigator.userAgent.indexOf('Opera')<0) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + ''); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index-- + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(true); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++ + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var lastTokenPos = this.findLastToken(); + if (lastTokenPos != -1) { + var newValue = this.element.value.substr(0, lastTokenPos + 1); + var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value; + } else { + this.element.value = value; + } + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if(this.update.firstChild && this.update.down().childNodes) { + this.entryCount = + this.update.down().childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + this.index = 0; + + if(this.entryCount==1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + if(this.getToken().length>=this.options.minChars) { + this.startIndicator(); + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + }, + + getToken: function() { + var tokenPos = this.findLastToken(); + if (tokenPos != -1) + var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); + else + var ret = this.element.value; + + return /\n/.test(ret) ? '' : ret; + }, + + findLastToken: function() { + var lastTokenPos = -1; + + for (var i=0; i lastTokenPos) + lastTokenPos = thisTokenPos; + } + return lastTokenPos; + } +} + +Ajax.Autocompleter = Class.create(); +Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } + +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(); +Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) + return "
      " + ret.join('') + "
    "; + } + }, options || {}); + } +}); + +// AJAX in-place editor +// +// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +} + +Ajax.InPlaceEditor = Class.create(); +Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; +Ajax.InPlaceEditor.prototype = { + initialize: function(element, url, options) { + this.url = url; + this.element = $(element); + + this.options = Object.extend({ + paramName: "value", + okButton: true, + okText: "ok", + cancelLink: true, + cancelText: "cancel", + savingText: "Saving...", + clickToEditText: "Click to edit", + okText: "ok", + rows: 1, + onComplete: function(transport, element) { + new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); + }, + onFailure: function(transport) { + alert("Error communicating with the server: " + transport.responseText.stripTags()); + }, + callback: function(form) { + return Form.serialize(form); + }, + handleLineBreaks: true, + loadingText: 'Loading...', + savingClassName: 'inplaceeditor-saving', + loadingClassName: 'inplaceeditor-loading', + formClassName: 'inplaceeditor-form', + highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, + highlightendcolor: "#FFFFFF", + externalControl: null, + submitOnBlur: false, + ajaxOptions: {}, + evalScripts: false + }, options || {}); + + if(!this.options.formId && this.element.id) { + this.options.formId = this.element.id + "-inplaceeditor"; + if ($(this.options.formId)) { + // there's already a form with that name, don't specify an id + this.options.formId = null; + } + } + + if (this.options.externalControl) { + this.options.externalControl = $(this.options.externalControl); + } + + this.originalBackground = Element.getStyle(this.element, 'background-color'); + if (!this.originalBackground) { + this.originalBackground = "transparent"; + } + + this.element.title = this.options.clickToEditText; + + this.onclickListener = this.enterEditMode.bindAsEventListener(this); + this.mouseoverListener = this.enterHover.bindAsEventListener(this); + this.mouseoutListener = this.leaveHover.bindAsEventListener(this); + Event.observe(this.element, 'click', this.onclickListener); + Event.observe(this.element, 'mouseover', this.mouseoverListener); + Event.observe(this.element, 'mouseout', this.mouseoutListener); + if (this.options.externalControl) { + Event.observe(this.options.externalControl, 'click', this.onclickListener); + Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); + Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); + } + }, + enterEditMode: function(evt) { + if (this.saving) return; + if (this.editing) return; + this.editing = true; + this.onEnterEditMode(); + if (this.options.externalControl) { + Element.hide(this.options.externalControl); + } + Element.hide(this.element); + this.createForm(); + this.element.parentNode.insertBefore(this.form, this.element); + if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField); + // stop the event to avoid a page refresh in Safari + if (evt) { + Event.stop(evt); + } + return false; + }, + createForm: function() { + this.form = document.createElement("form"); + this.form.id = this.options.formId; + Element.addClassName(this.form, this.options.formClassName) + this.form.onsubmit = this.onSubmit.bind(this); + + this.createEditField(); + + if (this.options.textarea) { + var br = document.createElement("br"); + this.form.appendChild(br); + } + + if (this.options.okButton) { + okButton = document.createElement("input"); + okButton.type = "submit"; + okButton.value = this.options.okText; + okButton.className = 'editor_ok_button'; + this.form.appendChild(okButton); + } + + if (this.options.cancelLink) { + cancelLink = document.createElement("a"); + cancelLink.href = "#"; + cancelLink.appendChild(document.createTextNode(this.options.cancelText)); + cancelLink.onclick = this.onclickCancel.bind(this); + cancelLink.className = 'editor_cancel'; + this.form.appendChild(cancelLink); + } + }, + hasHTMLLineBreaks: function(string) { + if (!this.options.handleLineBreaks) return false; + return string.match(/
    /i); + }, + convertHTMLLineBreaks: function(string) { + return string.replace(/
    /gi, "\n").replace(//gi, "\n").replace(/<\/p>/gi, "\n").replace(/

    /gi, ""); + }, + createEditField: function() { + var text; + if(this.options.loadTextURL) { + text = this.options.loadingText; + } else { + text = this.getText(); + } + + var obj = this; + + if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { + this.options.textarea = false; + var textField = document.createElement("input"); + textField.obj = this; + textField.type = "text"; + textField.name = this.options.paramName; + textField.value = text; + textField.style.backgroundColor = this.options.highlightcolor; + textField.className = 'editor_field'; + var size = this.options.size || this.options.cols || 0; + if (size != 0) textField.size = size; + if (this.options.submitOnBlur) + textField.onblur = this.onSubmit.bind(this); + this.editField = textField; + } else { + this.options.textarea = true; + var textArea = document.createElement("textarea"); + textArea.obj = this; + textArea.name = this.options.paramName; + textArea.value = this.convertHTMLLineBreaks(text); + textArea.rows = this.options.rows; + textArea.cols = this.options.cols || 40; + textArea.className = 'editor_field'; + if (this.options.submitOnBlur) + textArea.onblur = this.onSubmit.bind(this); + this.editField = textArea; + } + + if(this.options.loadTextURL) { + this.loadExternalText(); + } + this.form.appendChild(this.editField); + }, + getText: function() { + return this.element.innerHTML; + }, + loadExternalText: function() { + Element.addClassName(this.form, this.options.loadingClassName); + this.editField.disabled = true; + new Ajax.Request( + this.options.loadTextURL, + Object.extend({ + asynchronous: true, + onComplete: this.onLoadedExternalText.bind(this) + }, this.options.ajaxOptions) + ); + }, + onLoadedExternalText: function(transport) { + Element.removeClassName(this.form, this.options.loadingClassName); + this.editField.disabled = false; + this.editField.value = transport.responseText.stripTags(); + Field.scrollFreeActivate(this.editField); + }, + onclickCancel: function() { + this.onComplete(); + this.leaveEditMode(); + return false; + }, + onFailure: function(transport) { + this.options.onFailure(transport); + if (this.oldInnerHTML) { + this.element.innerHTML = this.oldInnerHTML; + this.oldInnerHTML = null; + } + return false; + }, + onSubmit: function() { + // onLoading resets these so we need to save them away for the Ajax call + var form = this.form; + var value = this.editField.value; + + // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... + // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... + // to be displayed indefinitely + this.onLoading(); + + if (this.options.evalScripts) { + new Ajax.Request( + this.url, Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this), + asynchronous:true, + evalScripts:true + }, this.options.ajaxOptions)); + } else { + new Ajax.Updater( + { success: this.element, + // don't update on failure (this could be an option) + failure: null }, + this.url, Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this) + }, this.options.ajaxOptions)); + } + // stop the event to avoid a page refresh in Safari + if (arguments.length > 1) { + Event.stop(arguments[0]); + } + return false; + }, + onLoading: function() { + this.saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + showSaving: function() { + this.oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + Element.addClassName(this.element, this.options.savingClassName); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + }, + removeForm: function() { + if(this.form) { + if (this.form.parentNode) Element.remove(this.form); + this.form = null; + } + }, + enterHover: function() { + if (this.saving) return; + this.element.style.backgroundColor = this.options.highlightcolor; + if (this.effect) { + this.effect.cancel(); + } + Element.addClassName(this.element, this.options.hoverClassName) + }, + leaveHover: function() { + if (this.options.backgroundColor) { + this.element.style.backgroundColor = this.oldBackground; + } + Element.removeClassName(this.element, this.options.hoverClassName) + if (this.saving) return; + this.effect = new Effect.Highlight(this.element, { + startcolor: this.options.highlightcolor, + endcolor: this.options.highlightendcolor, + restorecolor: this.originalBackground + }); + }, + leaveEditMode: function() { + Element.removeClassName(this.element, this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + if (this.options.externalControl) { + Element.show(this.options.externalControl); + } + this.editing = false; + this.saving = false; + this.oldInnerHTML = null; + this.onLeaveEditMode(); + }, + onComplete: function(transport) { + this.leaveEditMode(); + this.options.onComplete.bind(this)(transport, this.element); + }, + onEnterEditMode: function() {}, + onLeaveEditMode: function() {}, + dispose: function() { + if (this.oldInnerHTML) { + this.element.innerHTML = this.oldInnerHTML; + } + this.leaveEditMode(); + Event.stopObserving(this.element, 'click', this.onclickListener); + Event.stopObserving(this.element, 'mouseover', this.mouseoverListener); + Event.stopObserving(this.element, 'mouseout', this.mouseoutListener); + if (this.options.externalControl) { + Event.stopObserving(this.options.externalControl, 'click', this.onclickListener); + Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener); + Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener); + } + } +}; + +Ajax.InPlaceCollectionEditor = Class.create(); +Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype); +Object.extend(Ajax.InPlaceCollectionEditor.prototype, { + createEditField: function() { + if (!this.cached_selectTag) { + var selectTag = document.createElement("select"); + var collection = this.options.collection || []; + var optionTag; + collection.each(function(e,i) { + optionTag = document.createElement("option"); + optionTag.value = (e instanceof Array) ? e[0] : e; + if((typeof this.options.value == 'undefined') && + ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true; + if(this.options.value==optionTag.value) optionTag.selected = true; + optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e)); + selectTag.appendChild(optionTag); + }.bind(this)); + this.cached_selectTag = selectTag; + } + + this.editField = this.cached_selectTag; + if(this.options.loadTextURL) this.loadExternalText(); + this.form.appendChild(this.editField); + this.options.callback = function(form, value) { + return "value=" + encodeURIComponent(value); + } + } +}); + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create(); +Form.Element.DelayedObserver.prototype = { + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}; diff --git a/web/sf/prototype/js/dragdrop.js b/web/sf/prototype/js/dragdrop.js new file mode 100644 index 0000000..32c91bc --- /dev/null +++ b/web/sf/prototype/js/dragdrop.js @@ -0,0 +1,944 @@ +// script.aculo.us dragdrop.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 + +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +if(typeof Effect == 'undefined') + throw("dragdrop.js requires including script.aculo.us' effects.js library"); + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || {}); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if((typeof containment == 'object') && + (containment.constructor == Array)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var affected = []; + + if(this.last_active) this.deactivate(this.last_active); + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) { + drop = Droppables.findDeepestChild(affected); + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) + this.last_active.onDrop(element, this.last_active.element, event); + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +} + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + if(draggable.options.delay) { + this._timeout = setTimeout(function() { + Draggables._timeout = null; + window.focus(); + Draggables.activeDraggable = draggable; + }.bind(this), draggable.options.delay); + } else { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + } + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + } + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + if(draggable.options[eventName]) draggable.options[eventName](draggable, event); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +} + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create(); +Draggable._dragging = {}; + +Draggable.prototype = { + initialize: function(element) { + var defaults = { + handle: false, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, + queue: {scope:'_draggable', position:'end'} + }); + }, + endeffect: function(element) { + var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0; + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, + queue: {scope:'_draggable', position:'end'}, + afterFinish: function(){ + Draggable._dragging[element] = false + } + }); + }, + zindex: 1000, + revert: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } + delay: 0 + }; + + if(!arguments[1] || typeof arguments[1].endeffect == 'undefined') + Object.extend(defaults, { + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + Draggable._dragging[element] = true; + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + } + }); + + var options = Object.extend(defaults, arguments[1] || {}); + + this.element = $(element); + + if(options.handle && (typeof options.handle == 'string')) + this.handle = this.element.down('.'+options.handle, 0); + + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { + options.scroll = $(options.scroll); + this._isScrollChild = Element.childOf(this.element, options.scroll); + } + + Element.makePositioned(this.element); // fix IE + + this.delta = this.currentDelta(); + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(typeof Draggable._dragging[this.element] != 'undefined' && + Draggable._dragging[this.element]) return; + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if((tag_name = src.tagName.toUpperCase()) && ( + tag_name=='INPUT' || + tag_name=='SELECT' || + tag_name=='OPTION' || + tag_name=='BUTTON' || + tag_name=='TEXTAREA')) return; + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = Position.cumulativeOffset(this.element); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + Position.prepare(); + Droppables.show(pointer, this.element); + Draggables.notify('onDrag', this, event); + + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft + Position.deltaX; + p[1] += this.options.scroll.scrollTop + Position.deltaY; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.ghosting) { + Position.relativize(this.element); + Element.remove(this._clone); + this._clone = null; + } + + if(success) Droppables.fire(event, this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && typeof revert == 'function') revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = Position.cumulativeOffset(this.element); + if(this.options.ghosting) { + var r = Position.realOffset(this.element); + pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; + } + + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(typeof this.options.snap == 'function') { + p = this.options.snap(p[0],p[1],this); + } else { + if(this.options.snap instanceof Array) { + p = p.map( function(v, i) { + return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) + } else { + p = p.map( function(v) { + return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + if(!(speed[0] || speed[1])) return; + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + if (this._isScrollChild) { + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + } + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight + } + } + return { top: T, left: L, width: W, height: H }; + } +} + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create(); +SortableObserver.prototype = { + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +} + +var Sortable = { + SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, + + sortables: {}, + + _findRootElement: function(element) { + while (element.tagName.toUpperCase() != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + var s = Sortable.options(element); + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + delay: 0, + hoverclass: null, + ghosting: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: this.SERIALIZE_RULE, + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || {}); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + delay: options.delay, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + } + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + } + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (this.findElements(element, options) || []).each( function(e) { + // handles are per-draggable + var handle = options.handle ? + $(e).down('.'+options.handle,0) : e; + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.id] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Sortable._marker.hide(); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = + ($('dropmarker') || Element.extend(document.createElement('DIV'))). + hide().addClassName('dropmarker').setStyle({position:'absolute'}); + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = Position.cumulativeOffset(dropon); + Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); + else + Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); + + Sortable._marker.show(); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: [], + position: parent.children.length, + container: $(children[i]).down(options.treeTag) + } + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child) + + parent.children.push (child); + } + + return parent; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || {}); + + var root = { + id: null, + parent: null, + children: [], + container: element, + position: 0 + } + + return Sortable._tree(element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || {}); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || {}); + + var nodeMap = {}; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || {}); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "[id]=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +} + +// Returns true if child is contained within element +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + if (child.parentNode == element) return true; + return Element.isParent(child.parentNode, element); +} + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +} + +Element.offsetSize = function (element, type) { + return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; +} diff --git a/web/sf/prototype/js/effects.js b/web/sf/prototype/js/effects.js new file mode 100644 index 0000000..06f59b4 --- /dev/null +++ b/web/sf/prototype/js/effects.js @@ -0,0 +1,1090 @@ +// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 + +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if(this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if(this.slice(0,1) == '#') { + if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if(this.length==7) color = this.toLowerCase(); + } + } + return(color.length==7 ? color : (arguments[0] || this)); +} + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +} + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +} + +Element.setContentZoom = function(element, percent) { + element = $(element); + element.setStyle({fontSize: (percent/100) + 'em'}); + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + return element; +} + +Element.getOpacity = function(element){ + return $(element).getStyle('opacity'); +} + +Element.setOpacity = function(element, value){ + return $(element).setStyle({opacity:value}); +} + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +} + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +Array.prototype.call = function() { + var args = arguments; + this.each(function(f){ f.apply(this, args) }); +} + +/*--------------------------------------------------------------------------*/ + +var Effect = { + _elementDoesNotExistError: { + name: 'ElementDoesNotExistError', + message: 'The specified DOM element does not exist, but is required for this effect to operate' + }, + tagifyText: function(element) { + if(typeof Builder == 'undefined') + throw("Effect.tagifyText requires including script.aculo.us' builder.js library"); + + var tagifyStyle = 'position:relative'; + if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1'; + + element = $(element); + $A(element.childNodes).each( function(child) { + if(child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + Builder.node('span',{style: tagifyStyle}, + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if(((typeof element == 'object') || + (typeof element == 'function')) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || {}); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, arguments[2] || {}); + Effect[element.visible() ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +var Effect2 = Effect; // deprecated + +/* ------------- transitions ------------- */ + +Effect.Transitions = { + linear: Prototype.K, + sinoidal: function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; + }, + reverse: function(pos) { + return 1-pos; + }, + flicker: function(pos) { + return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; + }, + wobble: function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; + }, + pulse: function(pos, pulses) { + pulses = pulses || 5; + return ( + Math.round((pos % (1/pulses)) * pulses) == 0 ? + ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : + 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) + ); + }, + none: function(pos) { + return 0; + }, + full: function(pos) { + return 1; + } +}; + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(); +Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = (typeof effect.options.queue == 'string') ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'with-last': + timestamp = this.effects.pluck('startOn').max() || timestamp; + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if(!this.interval) + this.interval = setInterval(this.loop.bind(this), 15); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if(this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + for(var i=0, len=this.effects.length;i= this.startOn) { + if(timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if(this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); + var frame = Math.round(pos * this.options.fps * this.options.duration); + if(frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + render: function(pos) { + if(this.state == 'idle') { + this.state = 'running'; + this.event('beforeSetup'); + if(this.setup) this.setup(); + this.event('afterSetup'); + } + if(this.state == 'running') { + if(this.options.transition) pos = this.options.transition(pos); + pos *= (this.options.to-this.options.from); + pos += this.options.from; + this.position = pos; + this.event('beforeUpdate'); + if(this.update) this.update(pos); + this.event('afterUpdate'); + } + }, + cancel: function() { + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if(this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + var data = $H(); + for(property in this) + if(typeof this[property] != 'function') data[property] = this[property]; + return '#'; + } +} + +Effect.Parallel = Class.create(); +Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if(effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Event = Class.create(); +Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), { + initialize: function() { + var options = Object.extend({ + duration: 0 + }, arguments[0] || {}); + this.start(options); + }, + update: Prototype.emptyFunction +}); + +Effect.Opacity = Class.create(); +Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + // make this work on IE on elements without 'layout' + if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || {}); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(); +Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Bug in Opera: Opera returns the "real" position of a static element or + // relative element that does not have top/left explicitly set. + // ==> Always set top and left for position relative elements in your stylesheets + // (to 0 if you do not need them) + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if(this.options.mode == 'absolute') { + // absolute movement, so we need to calc deltaX and deltaY + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: Math.round(this.options.x * position + this.originalLeft) + 'px', + top: Math.round(this.options.y * position + this.originalTop) + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); +}; + +Effect.Scale = Class.create(); +Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { + initialize: function(element, percent) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or {} with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || {}); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = {}; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if(fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if(this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if(/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if(!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if(this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = {}; + if(this.options.scaleX) d.width = Math.round(width) + 'px'; + if(this.options.scaleY) d.height = Math.round(height) + 'px'; + if(this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if(this.elementPositioning == 'absolute') { + if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if(this.options.scaleY) d.top = -topd + 'px'; + if(this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(); +Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if(this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = {}; + if (!this.options.keepBackgroundImage) { + this.oldStyle.backgroundImage = this.element.getStyle('background-image'); + this.element.setStyle({backgroundImage: 'none'}); + } + if(!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if(!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = Class.create(); +Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + this.start(arguments[1] || {}); + }, + setup: function() { + Position.prepare(); + var offsets = Position.cumulativeOffset(this.element); + if(this.options.offset) offsets[1] += this.options.offset; + var max = window.innerHeight ? + window.height - window.innerHeight : + document.body.scrollHeight - + (document.documentElement.clientHeight ? + document.documentElement.clientHeight : document.body.clientHeight); + this.scrollStart = Position.deltaY; + this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; + }, + update: function(position) { + Position.prepare(); + window.scrollTo(Position.deltaX, + this.scrollStart + (position*this.delta)); + } +}); + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if(effect.options.to!=0) return; + effect.element.hide().setStyle({opacity: oldOpacity}); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from).show(); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { + opacity: element.getInlineOpacity(), + position: element.getStyle('position'), + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height + }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + Position.absolutize(effect.effects[0].element) + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().setStyle(oldStyle); } + }, arguments[1] || {}) + ); +} + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }, arguments[1] || {}) + ); +} + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || {})); +} + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); + } + }) + } + }, arguments[1] || {})); +} + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); + } + }, arguments[1] || {})); +} + +Effect.Shake = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + effect.element.undoPositioned().setStyle(oldStyle); + }}) }}) }}) }}) }}) }}); +} + +Effect.SlideDown = function(element) { + element = $(element).cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || {}) + ); +} + +Effect.SlideUp = function(element) { + element = $(element).cleanWhitespace(); + var oldInnerBottom = element.down().getStyle('bottom'); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + restoreAfterFinish: true, + beforeStartInternal: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom}); + effect.element.down().undoPositioned(); + } + }, arguments[1] || {}) + ); +} + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, { + restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }); +} + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide().makeClipping().makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); + } + }, options) + ) + } + }); +} + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } + }, options) + ); +} + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || {}; + var oldOpacity = element.getInlineOpacity(); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 2.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +} + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + element.makeClipping(); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().setStyle(oldStyle); + } }); + }}, arguments[1] || {})); +}; + +Effect.Morph = Class.create(); +Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + if(!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + style: {} + }, arguments[1] || {}); + if (typeof options.style == 'string') { + if(options.style.indexOf(':') == -1) { + var cssText = '', selector = '.' + options.style; + $A(document.styleSheets).reverse().each(function(styleSheet) { + if (styleSheet.cssRules) cssRules = styleSheet.cssRules; + else if (styleSheet.rules) cssRules = styleSheet.rules; + $A(cssRules).reverse().each(function(rule) { + if (selector == rule.selectorText) { + cssText = rule.style.cssText; + throw $break; + } + }); + if (cssText) throw $break; + }); + this.style = cssText.parseStyle(); + options.afterFinishInternal = function(effect){ + effect.element.addClassName(effect.options.style); + effect.transforms.each(function(transform) { + if(transform.style != 'opacity') + effect.element.style[transform.style.camelize()] = ''; + }); + } + } else this.style = options.style.parseStyle(); + } else this.style = $H(options.style) + this.start(options); + }, + setup: function(){ + function parseColor(color){ + if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; + color = color.parseColor(); + return $R(0,2).map(function(i){ + return parseInt( color.slice(i*2+1,i*2+3), 16 ) + }); + } + this.transforms = this.style.map(function(pair){ + var property = pair[0].underscore().dasherize(), value = pair[1], unit = null; + + if(value.parseColor('#zzzzzz') != '#zzzzzz') { + value = value.parseColor(); + unit = 'color'; + } else if(property == 'opacity') { + value = parseFloat(value); + if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + } else if(Element.CSS_LENGTH.test(value)) + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/), + value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null; + + var originalValue = this.element.getStyle(property); + return $H({ + style: property, + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), + targetValue: unit=='color' ? parseColor(value) : value, + unit: unit + }); + }.bind(this)).reject(function(transform){ + return ( + (transform.originalValue == transform.targetValue) || + ( + transform.unit != 'color' && + (isNaN(transform.originalValue) || isNaN(transform.targetValue)) + ) + ) + }); + }, + update: function(position) { + var style = $H(), value = null; + this.transforms.each(function(transform){ + value = transform.unit=='color' ? + $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(transform.originalValue[i]+ + (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : + transform.originalValue + Math.round( + ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit; + style[transform.style] = value; + }); + this.element.setStyle(style); + } +}); + +Effect.Transform = Class.create(); +Object.extend(Effect.Transform.prototype, { + initialize: function(tracks){ + this.tracks = []; + this.options = arguments[1] || {}; + this.addTracks(tracks); + }, + addTracks: function(tracks){ + tracks.each(function(track){ + var data = $H(track).values().first(); + this.tracks.push($H({ + ids: $H(track).keys().first(), + effect: Effect.Morph, + options: { style: data } + })); + }.bind(this)); + return this; + }, + play: function(){ + return new Effect.Parallel( + this.tracks.map(function(track){ + var elements = [$(track.ids) || $$(track.ids)].flatten(); + return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) }); + }).flatten(), + this.options + ); + } +}); + +Element.CSS_PROPERTIES = $w( + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + + 'fontSize fontWeight height left letterSpacing lineHeight ' + + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + + 'right textIndent top width wordSpacing zIndex'); + +Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; + +String.prototype.parseStyle = function(){ + var element = Element.extend(document.createElement('div')); + element.innerHTML = '

    '; + var style = element.down().style, styleRules = $H(); + + Element.CSS_PROPERTIES.each(function(property){ + if(style[property]) styleRules[property] = style[property]; + }); + if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) { + styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]; + } + return styleRules; +}; + +Element.morph = function(element, style) { + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {})); + return element; +}; + +['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', + 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( + function(f) { Element.Methods[f] = Element[f]; } +); + +Element.Methods.visualEffect = function(element, effect, options) { + s = effect.gsub(/_/, '-').camelize(); + effect_class = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[effect_class](element, options); + return $(element); +}; + +Element.addMethods(); \ No newline at end of file diff --git a/web/sf/prototype/js/index.html b/web/sf/prototype/js/index.html new file mode 100644 index 0000000..7879e1c --- /dev/null +++ b/web/sf/prototype/js/index.html @@ -0,0 +1,4 @@ + + + + diff --git a/web/sf/prototype/js/prototype.js b/web/sf/prototype/js/prototype.js new file mode 100644 index 0000000..0476b8f --- /dev/null +++ b/web/sf/prototype/js/prototype.js @@ -0,0 +1,2515 @@ +/* Prototype JavaScript framework, version 1.5.0 + * (c) 2005-2007 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://prototype.conio.net/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.5.0', + BrowserFeatures: { + XPath: !!document.evaluate + }, + + ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', + emptyFunction: function() {}, + K: function(x) { return x } +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.extend(Object, { + inspect: function(object) { + try { + if (object === undefined) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({}, object); + } +}); + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments))); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(this); + } finally { + this.currentlyExecuting = false; + } + } + } +} +String.interpret = function(value){ + return value == null ? '' : String(value); +} + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return this; + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : this; + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var div = document.createElement('div'); + var text = document.createTextNode(this); + div.appendChild(text); + return div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return {}; + + return match[1].split(separator || '&').inject({}, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var name = decodeURIComponent(pair[0]); + var value = pair[1] ? decodeURIComponent(pair[1]) : undefined; + + if (hash[name] !== undefined) { + if (hash[name].constructor != Array) + hash[name] = [hash[name]]; + if (value) hash[name].push(value); + } + else hash[name] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function(){ + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.replace(/\\/g, '\\\\'); + if (useDoubleQuotes) + return '"' + escapedString.replace(/"/g, '\\"') + '"'; + else + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (typeof replacement == 'function') return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +} + +String.prototype.parseQuery = String.prototype.toQueryParams; + +var Template = Class.create(); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; +Template.prototype = { + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + return this.template.gsub(this.pattern, function(match) { + var before = match[1]; + if (before == '\\') return match[2]; + return before + String.interpret(object[match[3]]); + }); + } +} + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + }, + + eachSlice: function(number, iterator) { + var index = -number, slices = [], array = this.toArray(); + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.map(iterator); + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = false; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push((iterator || Prototype.K)(value, index)); + }); + return results; + }, + + detect: function(iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inGroupsOf: function(number, fillWith) { + fillWith = fillWith === undefined ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.map(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.map(); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + size: function() { + return this.toArray().length; + }, + + inspect: function() { + return '#'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray +}); +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0, length = iterable.length; i < length; i++) + results.push(iterable[i]); + return results; + } +} + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) + Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value && value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0, length = this.length; i < length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + reduce: function() { + return this.length > 1 ? this : this[0]; + }, + + uniq: function() { + return this.inject([], function(array, value) { + return array.include(value) ? array : array.concat([value]); + }); + }, + + clone: function() { + return [].concat(this); + }, + + size: function() { + return this.length; + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); + +Array.prototype.toArray = Array.prototype.clone; + +function $w(string){ + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +if(window.opera){ + Array.prototype.concat = function(){ + var array = []; + for(var i = 0, length = this.length; i < length; i++) array.push(this[i]); + for(var i = 0, length = arguments.length; i < length; i++) { + if(arguments[i].constructor == Array) { + for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) + array.push(arguments[i][j]); + } else { + array.push(arguments[i]); + } + } + return array; + } +} +var Hash = function(obj) { + Object.extend(this, obj || {}); +}; + +Object.extend(Hash, { + toQueryString: function(obj) { + var parts = []; + + this.prototype._each.call(obj, function(pair) { + if (!pair.key) return; + + if (pair.value && pair.value.constructor == Array) { + var values = pair.value.compact(); + if (values.length < 2) pair.value = values.reduce(); + else { + key = encodeURIComponent(pair.key); + values.each(function(value) { + value = value != undefined ? encodeURIComponent(value) : ''; + parts.push(key + '=' + encodeURIComponent(value)); + }); + return; + } + } + if (pair.value == undefined) pair[1] = ''; + parts.push(pair.map(encodeURIComponent).join('=')); + }); + + return parts.join('&'); + } +}); + +Object.extend(Hash.prototype, Enumerable); +Object.extend(Hash.prototype, { + _each: function(iterator) { + for (var key in this) { + var value = this[key]; + if (value && value == Hash.prototype[key]) continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject(this, function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + remove: function() { + var result; + for(var i = 0, length = arguments.length; i < length; i++) { + var value = this[arguments[i]]; + if (value !== undefined){ + if (result === undefined) result = value; + else { + if (result.constructor != Array) result = [result]; + result.push(value) + } + } + delete this[arguments[i]]; + } + return result; + }, + + toQueryString: function() { + return Hash.toQueryString(this); + }, + + inspect: function() { + return '#'; + } +}); + +function $H(object) { + if (object && object.constructor == Hash) return object; + return new Hash(object); +}; +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '' + } + Object.extend(this.options, options || {}); + + this.options.method = this.options.method.toLowerCase(); + if (typeof this.options.parameters == 'string') + this.options.parameters = this.options.parameters.toQueryParams(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + _complete: false, + + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = this.options.parameters; + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + params = Hash.toQueryString(params); + if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_=' + + // when GET, append parameters to URL + if (this.method == 'get' && params) + this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params; + + try { + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) + setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + var body = this.method == 'post' ? (this.options.postBody || params) : null; + + this.transport.send(body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (typeof extras.push == 'function') + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + return !this.transport.status + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + this.transport.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + if ((this.getHeader('Content-type') || 'text/javascript').strip(). + match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + state, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) { return null } + }, + + evalJSON: function() { + try { + var json = this.getHeader('X-JSON'); + return json ? eval('(' + json + ')') : null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, param) { + this.updateContent(); + onComplete(transport, param); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.container[this.success() ? 'success' : 'failure']; + var response = this.transport.responseText; + + if (!this.options.evalScripts) response = response.stripScripts(); + + if (receiver = $(receiver)) { + if (this.options.insertion) + new this.options.insertion(receiver, response); + else + receiver.update(response); + } + + if (this.success()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (typeof element == 'string') + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(query.snapshotItem(i)); + return results; + }; +} + +document.getElementsByClassName = function(className, parentElement) { + if (Prototype.BrowserFeatures.XPath) { + var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; + return document._getElementsByXPath(q, parentElement); + } else { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + var elements = [], child; + for (var i = 0, length = children.length; i < length; i++) { + child = children[i]; + if (Element.hasClassName(child, className)) + elements.push(Element.extend(child)); + } + return elements; + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) + var Element = new Object(); + +Element.extend = function(element) { + if (!element || _nativeExtensions || element.nodeType == 3) return element; + + if (!element._extended && element.tagName && element != window) { + var methods = Object.clone(Element.Methods), cache = Element.extend.cache; + + if (element.tagName == 'FORM') + Object.extend(methods, Form.Methods); + if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName)) + Object.extend(methods, Form.Element.Methods); + + Object.extend(methods, Element.Methods.Simulated); + + for (var property in methods) { + var value = methods[property]; + if (typeof value == 'function' && !(property in element)) + element[property] = cache.findOrStore(value); + } + } + + element._extended = true; + return element; +}; + +Element.extend.cache = { + findOrStore: function(value) { + return this[value] = this[value] || function() { + return value.apply(null, [this].concat($A(arguments))); + } + } +}; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + $(element).style.display = 'none'; + return element; + }, + + show: function(element) { + $(element).style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, html) { + html = typeof html == 'undefined' ? '' : html.toString(); + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + replace: function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + if (element.outerHTML) { + element.outerHTML = html.stripScripts(); + } else { + var range = element.ownerDocument.createRange(); + range.selectNodeContents(element); + element.parentNode.replaceChild( + range.createContextualFragment(html.stripScripts()), element); + } + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $A($(element).getElementsByTagName('*')); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (typeof selector == 'string') + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + return Selector.findElement($(element).ancestors(), expression, index); + }, + + down: function(element, expression, index) { + return Selector.findElement($(element).descendants(), expression, index); + }, + + previous: function(element, expression, index) { + return Selector.findElement($(element).previousSiblings(), expression, index); + }, + + next: function(element, expression, index) { + return Selector.findElement($(element).nextSiblings(), expression, index); + }, + + getElementsBySelector: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + getElementsByClassName: function(element, className) { + return document.getElementsByClassName(className, element); + }, + + readAttribute: function(element, name) { + element = $(element); + if (document.all && !window.opera) { + var t = Element._attributeTranslations; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + var attribute = element.attributes[name]; + if(attribute) return attribute.nodeValue; + } + return element.getAttribute(name); + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + if (elementClassName.length == 0) return false; + if (elementClassName == className || + elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + return true; + return false; + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).add(className); + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).remove(className); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); + return element; + }, + + observe: function() { + Event.observe.apply(Event, arguments); + return $A(arguments).first(); + }, + + stopObserving: function() { + Event.stopObserving.apply(Event, arguments); + return $A(arguments).first(); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Position.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + if (['float','cssFloat'].include(style)) + style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat'); + style = style.camelize(); + var value = element.style[style]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } else if (element.currentStyle) { + value = element.currentStyle[style]; + } + } + + if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none')) + value = element['offset'+style.capitalize()] + 'px'; + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + if(style == 'opacity') { + if(value) return parseFloat(value); + if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if(value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (var name in style) { + var value = style[name]; + if(name == 'opacity') { + if (value == 1) { + value = (/Gecko/.test(navigator.userAgent) && + !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0; + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); + } else if(value === '') { + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,''); + } else { + if(value < 0.00001) value = 0; + if(/MSIE/.test(navigator.userAgent) && !window.opera) + element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') + + 'alpha(opacity='+value*100+')'; + } + } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat'; + element.style[name.camelize()] = value; + } + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = $(element).getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = element.style.overflow || 'auto'; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + } +}; + +Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf}); + +Element._attributeTranslations = {}; + +Element._attributeTranslations.names = { + colspan: "colSpan", + rowspan: "rowSpan", + valign: "vAlign", + datetime: "dateTime", + accesskey: "accessKey", + tabindex: "tabIndex", + enctype: "encType", + maxlength: "maxLength", + readonly: "readOnly", + longdesc: "longDesc" +}; + +Element._attributeTranslations.values = { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + + title: function(element) { + var node = element.getAttributeNode('title'); + return node.specified ? node.nodeValue : null; + } +}; + +Object.extend(Element._attributeTranslations.values, { + href: Element._attributeTranslations.values._getAttr, + src: Element._attributeTranslations.values._getAttr, + disabled: Element._attributeTranslations.values._flag, + checked: Element._attributeTranslations.values._flag, + readonly: Element._attributeTranslations.values._flag, + multiple: Element._attributeTranslations.values._flag +}); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + var t = Element._attributeTranslations; + attribute = t.names[attribute] || attribute; + return $(element).getAttributeNode(attribute).specified; + } +}; + +// IE is missing .innerHTML support for TABLE-related elements +if (document.all && !window.opera){ + Element.Methods.update = function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + var tagName = element.tagName.toUpperCase(); + if (['THEAD','TBODY','TR','TD'].include(tagName)) { + var div = document.createElement('div'); + switch (tagName) { + case 'THEAD': + case 'TBODY': + div.innerHTML = '' + html.stripScripts() + '
    '; + depth = 2; + break; + case 'TR': + div.innerHTML = '' + html.stripScripts() + '
    '; + depth = 3; + break; + case 'TD': + div.innerHTML = '
    ' + html.stripScripts() + '
    '; + depth = 4; + } + $A(element.childNodes).each(function(node){ + element.removeChild(node) + }); + depth.times(function(){ div = div.firstChild }); + + $A(div.childNodes).each( + function(node){ element.appendChild(node) }); + } else { + element.innerHTML = html.stripScripts(); + } + setTimeout(function() {html.evalScripts()}, 10); + return element; + } +}; + +Object.extend(Element, Element.Methods); + +var _nativeExtensions = false; + +if(/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) { + var className = 'HTML' + tag + 'Element'; + if(window[className]) return; + var klass = window[className] = {}; + klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__; + }); + +Element.addMethods = function(methods) { + Object.extend(Element.Methods, methods || {}); + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + var cache = Element.extend.cache; + for (var property in methods) { + var value = methods[property]; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = cache.findOrStore(value); + } + } + + if (typeof HTMLElement != 'undefined') { + copy(Element.Methods, HTMLElement.prototype); + copy(Element.Methods.Simulated, HTMLElement.prototype, true); + copy(Form.Methods, HTMLFormElement.prototype); + [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) { + copy(Form.Element.Methods, klass.prototype); + }); + _nativeExtensions = true; + } +} + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content.stripScripts(); + + if (this.adjacency && this.element.insertAdjacentHTML) { + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + var tagName = this.element.tagName.toUpperCase(); + if (['TBODY', 'TR'].include(tagName)) { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.insertContent([this.range.createContextualFragment(this.content)]); + } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '' + this.content + '
    '; + return $A(div.childNodes[0].childNodes[0].childNodes); + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); + } +}); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); +var Selector = Class.create(); +Selector.prototype = { + initialize: function(expression) { + this.params = {classNames: []}; + this.expression = expression.toString().strip(); + this.parseExpression(); + this.compileMatcher(); + }, + + parseExpression: function() { + function abort(message) { throw 'Parse error in selector: ' + message; } + + if (this.expression == '') abort('empty expression'); + + var params = this.params, expr = this.expression, match, modifier, clause, rest; + while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { + params.attributes = params.attributes || []; + params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); + expr = match[1]; + } + + if (expr == '*') return this.params.wildcard = true; + + while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { + modifier = match[1], clause = match[2], rest = match[3]; + switch (modifier) { + case '#': params.id = clause; break; + case '.': params.classNames.push(clause); break; + case '': + case undefined: params.tagName = clause.toUpperCase(); break; + default: abort(expr.inspect()); + } + expr = rest; + } + + if (expr.length > 0) abort(expr.inspect()); + }, + + buildMatchExpression: function() { + var params = this.params, conditions = [], clause; + + if (params.wildcard) + conditions.push('true'); + if (clause = params.id) + conditions.push('element.readAttribute("id") == ' + clause.inspect()); + if (clause = params.tagName) + conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); + if ((clause = params.classNames).length > 0) + for (var i = 0, length = clause.length; i < length; i++) + conditions.push('element.hasClassName(' + clause[i].inspect() + ')'); + if (clause = params.attributes) { + clause.each(function(attribute) { + var value = 'element.readAttribute(' + attribute.name.inspect() + ')'; + var splitValueBy = function(delimiter) { + return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; + } + + switch (attribute.operator) { + case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; + case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; + case '|=': conditions.push( + splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() + ); break; + case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; + case '': + case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break; + default: throw 'Unknown operator ' + attribute.operator + ' in selector'; + } + }); + } + + return conditions.join(' && '); + }, + + compileMatcher: function() { + this.match = new Function('element', 'if (!element.tagName) return false; \ + element = $(element); \ + return ' + this.buildMatchExpression()); + }, + + findElements: function(scope) { + var element; + + if (element = $(this.params.id)) + if (this.match(element)) + if (!scope || Element.childOf(element, scope)) + return [element]; + + scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); + + var results = []; + for (var i = 0, length = scope.length; i < length; i++) + if (this.match(element = scope[i])) + results.push(Element.extend(element)); + + return results; + }, + + toString: function() { + return this.expression; + } +} + +Object.extend(Selector, { + matchElements: function(elements, expression) { + var selector = new Selector(expression); + return elements.select(selector.match.bind(selector)).map(Element.extend); + }, + + findElement: function(elements, expression, index) { + if (typeof expression == 'number') index = expression, expression = false; + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + return expressions.map(function(expression) { + return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) { + var selector = new Selector(expr); + return results.inject([], function(elements, result) { + return elements.concat(selector.findElements(result || element)); + }); + }); + }).flatten(); + } +}); + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, getHash) { + var data = elements.inject({}, function(result, element) { + if (!element.disabled && element.name) { + var key = element.name, value = $(element).getValue(); + if (value != undefined) { + if (result[key]) { + if (result[key].constructor != Array) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return getHash ? data : Hash.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, getHash) { + return Form.serializeElements(Form.getElements(form), getHash); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + form.getElements().each(function(element) { + element.blur(); + element.disabled = 'true'; + }); + return form; + }, + + enable: function(form) { + form = $(form); + form.getElements().each(function(element) { + element.disabled = ''; + }); + return form; + }, + + findFirstElement: function(form) { + return $(form).getElements().find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + } +} + +Object.extend(Form, Form.Methods); + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +} + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = {}; + pair[element.name] = value; + return Hash.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + element.focus(); + if (element.select && ( element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type) ) ) + element.select(); + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.blur(); + element.disabled = false; + return element; + } +} + +Object.extend(Form.Element, Form.Element.Methods); +var Field = Form.Element; +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + default: + return Form.Element.Serializers.textarea(element); + } + }, + + inputSelector: function(element) { + return element.checked ? element.value : null; + }, + + textarea: function(element) { + return element.value; + }, + + select: function(element) { + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +} + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + var changed = ('string' == typeof this.lastValue && 'string' == typeof value + ? this.lastValue != value : String(this.lastValue) != String(value)); + if (changed) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback.bind(this)); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + + element: function(event) { + return event.target || event.srcElement; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0, length = Event.observers.length; i < length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) + name = 'keydown'; + + Event._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.detachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + try { + element.detachEvent('on' + name, observer); + } catch (e) {} + } + } +}); + +/* prevent memory leaks in IE */ +if (navigator.appVersion.match(/\bMSIE\b/)) + Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if(element.tagName=='BODY') break; + var p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!window.opera || element.tagName=='BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} + +Element.addMethods(); \ No newline at end of file diff --git a/web/sf/prototype/js/scriptaculous.js b/web/sf/prototype/js/scriptaculous.js new file mode 100644 index 0000000..585313c --- /dev/null +++ b/web/sf/prototype/js/scriptaculous.js @@ -0,0 +1,51 @@ +// script.aculo.us scriptaculous.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 + +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +var Scriptaculous = { + Version: '1.7.0', + require: function(libraryName) { + // inserting via DOM fails in Safari 2.0, so brute force approach + document.write(''); + }, + load: function() { + if((typeof Prototype=='undefined') || + (typeof Element == 'undefined') || + (typeof Element.Methods=='undefined') || + parseFloat(Prototype.Version.split(".")[0] + "." + + Prototype.Version.split(".")[1]) < 1.5) + throw("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0"); + + $A(document.getElementsByTagName("script")).findAll( function(s) { + return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/)) + }).each( function(s) { + var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,''); + var includes = s.src.match(/\?.*load=([a-z,]*)/); + (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each( + function(include) { Scriptaculous.require(path+include+'.js') }); + }); + } +} + +Scriptaculous.load(); \ No newline at end of file diff --git a/web/sf/prototype/js/slider.js b/web/sf/prototype/js/slider.js new file mode 100644 index 0000000..f24f282 --- /dev/null +++ b/web/sf/prototype/js/slider.js @@ -0,0 +1,278 @@ +// script.aculo.us slider.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 + +// Copyright (c) 2005, 2006 Marty Haught, Thomas Fuchs +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +if(!Control) var Control = {}; +Control.Slider = Class.create(); + +// options: +// axis: 'vertical', or 'horizontal' (default) +// +// callbacks: +// onChange(value) +// onSlide(value) +Control.Slider.prototype = { + initialize: function(handle, track, options) { + var slider = this; + + if(handle instanceof Array) { + this.handles = handle.collect( function(e) { return $(e) }); + } else { + this.handles = [$(handle)]; + } + + this.track = $(track); + this.options = options || {}; + + this.axis = this.options.axis || 'horizontal'; + this.increment = this.options.increment || 1; + this.step = parseInt(this.options.step || '1'); + this.range = this.options.range || $R(0,1); + + this.value = 0; // assure backwards compat + this.values = this.handles.map( function() { return 0 }); + this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false; + this.options.startSpan = $(this.options.startSpan || null); + this.options.endSpan = $(this.options.endSpan || null); + + this.restricted = this.options.restricted || false; + + this.maximum = this.options.maximum || this.range.end; + this.minimum = this.options.minimum || this.range.start; + + // Will be used to align the handle onto the track, if necessary + this.alignX = parseInt(this.options.alignX || '0'); + this.alignY = parseInt(this.options.alignY || '0'); + + this.trackLength = this.maximumOffset() - this.minimumOffset(); + + this.handleLength = this.isVertical() ? + (this.handles[0].offsetHeight != 0 ? + this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : + (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : + this.handles[0].style.width.replace(/px$/,"")); + + this.active = false; + this.dragging = false; + this.disabled = false; + + if(this.options.disabled) this.setDisabled(); + + // Allowed values array + this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; + if(this.allowedValues) { + this.minimum = this.allowedValues.min(); + this.maximum = this.allowedValues.max(); + } + + this.eventMouseDown = this.startDrag.bindAsEventListener(this); + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.update.bindAsEventListener(this); + + // Initialize handles in reverse (make sure first handle is active) + this.handles.each( function(h,i) { + i = slider.handles.length-1-i; + slider.setValue(parseFloat( + (slider.options.sliderValue instanceof Array ? + slider.options.sliderValue[i] : slider.options.sliderValue) || + slider.range.start), i); + Element.makePositioned(h); // fix IE + Event.observe(h, "mousedown", slider.eventMouseDown); + }); + + Event.observe(this.track, "mousedown", this.eventMouseDown); + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + + this.initialized = true; + }, + dispose: function() { + var slider = this; + Event.stopObserving(this.track, "mousedown", this.eventMouseDown); + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + this.handles.each( function(h) { + Event.stopObserving(h, "mousedown", slider.eventMouseDown); + }); + }, + setDisabled: function(){ + this.disabled = true; + }, + setEnabled: function(){ + this.disabled = false; + }, + getNearestValue: function(value){ + if(this.allowedValues){ + if(value >= this.allowedValues.max()) return(this.allowedValues.max()); + if(value <= this.allowedValues.min()) return(this.allowedValues.min()); + + var offset = Math.abs(this.allowedValues[0] - value); + var newValue = this.allowedValues[0]; + this.allowedValues.each( function(v) { + var currentOffset = Math.abs(v - value); + if(currentOffset <= offset){ + newValue = v; + offset = currentOffset; + } + }); + return newValue; + } + if(value > this.range.end) return this.range.end; + if(value < this.range.start) return this.range.start; + return value; + }, + setValue: function(sliderValue, handleIdx){ + if(!this.active) { + this.activeHandleIdx = handleIdx || 0; + this.activeHandle = this.handles[this.activeHandleIdx]; + this.updateStyles(); + } + handleIdx = handleIdx || this.activeHandleIdx || 0; + if(this.initialized && this.restricted) { + if((handleIdx>0) && (sliderValuethis.values[handleIdx+1])) + sliderValue = this.values[handleIdx+1]; + } + sliderValue = this.getNearestValue(sliderValue); + this.values[handleIdx] = sliderValue; + this.value = this.values[0]; // assure backwards compat + + this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = + this.translateToPx(sliderValue); + + this.drawSpans(); + if(!this.dragging || !this.event) this.updateFinished(); + }, + setValueBy: function(delta, handleIdx) { + this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, + handleIdx || this.activeHandleIdx || 0); + }, + translateToPx: function(value) { + return Math.round( + ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * + (value - this.range.start)) + "px"; + }, + translateToValue: function(offset) { + return ((offset/(this.trackLength-this.handleLength) * + (this.range.end-this.range.start)) + this.range.start); + }, + getRange: function(range) { + var v = this.values.sortBy(Prototype.K); + range = range || 0; + return $R(v[range],v[range+1]); + }, + minimumOffset: function(){ + return(this.isVertical() ? this.alignY : this.alignX); + }, + maximumOffset: function(){ + return(this.isVertical() ? + (this.track.offsetHeight != 0 ? this.track.offsetHeight : + this.track.style.height.replace(/px$/,"")) - this.alignY : + (this.track.offsetWidth != 0 ? this.track.offsetWidth : + this.track.style.width.replace(/px$/,"")) - this.alignY); + }, + isVertical: function(){ + return (this.axis == 'vertical'); + }, + drawSpans: function() { + var slider = this; + if(this.spans) + $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); + if(this.options.startSpan) + this.setSpan(this.options.startSpan, + $R(0, this.values.length>1 ? this.getRange(0).min() : this.value )); + if(this.options.endSpan) + this.setSpan(this.options.endSpan, + $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum)); + }, + setSpan: function(span, range) { + if(this.isVertical()) { + span.style.top = this.translateToPx(range.start); + span.style.height = this.translateToPx(range.end - range.start + this.range.start); + } else { + span.style.left = this.translateToPx(range.start); + span.style.width = this.translateToPx(range.end - range.start + this.range.start); + } + }, + updateStyles: function() { + this.handles.each( function(h){ Element.removeClassName(h, 'selected') }); + Element.addClassName(this.activeHandle, 'selected'); + }, + startDrag: function(event) { + if(Event.isLeftClick(event)) { + if(!this.disabled){ + this.active = true; + + var handle = Event.element(event); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var track = handle; + if(track==this.track) { + var offsets = Position.cumulativeOffset(this.track); + this.event = event; + this.setValue(this.translateToValue( + (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2) + )); + var offsets = Position.cumulativeOffset(this.activeHandle); + this.offsetX = (pointer[0] - offsets[0]); + this.offsetY = (pointer[1] - offsets[1]); + } else { + // find the handle (prevents issues with Safari) + while((this.handles.indexOf(handle) == -1) && handle.parentNode) + handle = handle.parentNode; + + if(this.handles.indexOf(handle)!=-1) { + this.activeHandle = handle; + this.activeHandleIdx = this.handles.indexOf(this.activeHandle); + this.updateStyles(); + + var offsets = Position.cumulativeOffset(this.activeHandle); + this.offsetX = (pointer[0] - offsets[0]); + this.offsetY = (pointer[1] - offsets[1]); + } + } + } + Event.stop(event); + } + }, + update: function(event) { + if(this.active) { + if(!this.dragging) this.dragging = true; + this.draw(event); + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + Event.stop(event); + } + }, + draw: function(event) { + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var offsets = Position.cumulativeOffset(this.track); + pointer[0] -= this.offsetX + offsets[0]; + pointer[1] -= this.offsetY + offsets[1]; + this.event = event; + this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] )); + if(this.initialized && this.options.onSlide) + this.options.onSlide(this.values.length>1 ? this.values : this.value, this); + }, + endDrag: function(event) { + if(this.active && this.dragging) { + this.finishDrag(event, true); + Event.stop(event); + } + this.active = false; + this.dragging = false; + }, + finishDrag: function(event, success) { + this.active = false; + this.dragging = false; + this.updateFinished(); + }, + updateFinished: function() { + if(this.initialized && this.options.onChange) + this.options.onChange(this.values.length>1 ? this.values : this.value, this); + this.event = null; + } +} \ No newline at end of file diff --git a/web/sf/prototype/js/unittest.js b/web/sf/prototype/js/unittest.js new file mode 100644 index 0000000..a447885 --- /dev/null +++ b/web/sf/prototype/js/unittest.js @@ -0,0 +1,564 @@ +// script.aculo.us unittest.js v1.7.0, Fri Jan 19 19:16:36 CET 2007 + +// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005, 2006 Jon Tirsen (http://www.tirsen.com) +// (c) 2005, 2006 Michael Schuerig (http://www.schuerig.de/michael/) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// experimental, Firefox-only +Event.simulateMouse = function(element, eventName) { + var options = Object.extend({ + pointerX: 0, + pointerY: 0, + buttons: 0, + ctrlKey: false, + altKey: false, + shiftKey: false, + metaKey: false + }, arguments[2] || {}); + var oEvent = document.createEvent("MouseEvents"); + oEvent.initMouseEvent(eventName, true, true, document.defaultView, + options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, 0, $(element)); + + if(this.mark) Element.remove(this.mark); + this.mark = document.createElement('div'); + this.mark.appendChild(document.createTextNode(" ")); + document.body.appendChild(this.mark); + this.mark.style.position = 'absolute'; + this.mark.style.top = options.pointerY + "px"; + this.mark.style.left = options.pointerX + "px"; + this.mark.style.width = "5px"; + this.mark.style.height = "5px;"; + this.mark.style.borderTop = "1px solid red;" + this.mark.style.borderLeft = "1px solid red;" + + if(this.step) + alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options)); + + $(element).dispatchEvent(oEvent); +}; + +// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2. +// You need to downgrade to 1.0.4 for now to get this working +// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much +Event.simulateKey = function(element, eventName) { + var options = Object.extend({ + ctrlKey: false, + altKey: false, + shiftKey: false, + metaKey: false, + keyCode: 0, + charCode: 0 + }, arguments[2] || {}); + + var oEvent = document.createEvent("KeyEvents"); + oEvent.initKeyEvent(eventName, true, true, window, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, + options.keyCode, options.charCode ); + $(element).dispatchEvent(oEvent); +}; + +Event.simulateKeys = function(element, command) { + for(var i=0; i' + + '' + + '' + + '' + + '
    StatusTestMessage
    '; + this.logsummary = $('logsummary') + this.loglines = $('loglines'); + }, + _toHTML: function(txt) { + return txt.escapeHTML().replace(/\n/g,"
    "); + }, + addLinksToResults: function(){ + $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log + td.title = "Run only this test" + Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;}); + }); + $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log + td.title = "Run all tests" + Event.observe(td, 'click', function(){ window.location.search = "";}); + }); + } +} + +Test.Unit.Runner = Class.create(); +Test.Unit.Runner.prototype = { + initialize: function(testcases) { + this.options = Object.extend({ + testLog: 'testlog' + }, arguments[1] || {}); + this.options.resultsURL = this.parseResultsURLQueryParameter(); + this.options.tests = this.parseTestsQueryParameter(); + if (this.options.testLog) { + this.options.testLog = $(this.options.testLog) || null; + } + if(this.options.tests) { + this.tests = []; + for(var i = 0; i < this.options.tests.length; i++) { + if(/^test/.test(this.options.tests[i])) { + this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"])); + } + } + } else { + if (this.options.test) { + this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])]; + } else { + this.tests = []; + for(var testcase in testcases) { + if(/^test/.test(testcase)) { + this.tests.push( + new Test.Unit.Testcase( + this.options.context ? ' -> ' + this.options.titles[testcase] : testcase, + testcases[testcase], testcases["setup"], testcases["teardown"] + )); + } + } + } + } + this.currentTest = 0; + this.logger = new Test.Unit.Logger(this.options.testLog); + setTimeout(this.runTests.bind(this), 1000); + }, + parseResultsURLQueryParameter: function() { + return window.location.search.parseQuery()["resultsURL"]; + }, + parseTestsQueryParameter: function(){ + if (window.location.search.parseQuery()["tests"]){ + return window.location.search.parseQuery()["tests"].split(','); + }; + }, + // Returns: + // "ERROR" if there was an error, + // "FAILURE" if there was a failure, or + // "SUCCESS" if there was neither + getResult: function() { + var hasFailure = false; + for(var i=0;i 0) { + return "ERROR"; + } + if (this.tests[i].failures > 0) { + hasFailure = true; + } + } + if (hasFailure) { + return "FAILURE"; + } else { + return "SUCCESS"; + } + }, + postResults: function() { + if (this.options.resultsURL) { + new Ajax.Request(this.options.resultsURL, + { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false }); + } + }, + runTests: function() { + var test = this.tests[this.currentTest]; + if (!test) { + // finished! + this.postResults(); + this.logger.summary(this.summary()); + return; + } + if(!test.isWaiting) { + this.logger.start(test.name); + } + test.run(); + if(test.isWaiting) { + this.logger.message("Waiting for " + test.timeToWait + "ms"); + setTimeout(this.runTests.bind(this), test.timeToWait || 1000); + } else { + this.logger.finish(test.status(), test.summary()); + this.currentTest++; + // tail recursive, hopefully the browser will skip the stackframe + this.runTests(); + } + }, + summary: function() { + var assertions = 0; + var failures = 0; + var errors = 0; + var messages = []; + for(var i=0;i 0) return 'failed'; + if (this.errors > 0) return 'error'; + return 'passed'; + }, + assert: function(expression) { + var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"'; + try { expression ? this.pass() : + this.fail(message); } + catch(e) { this.error(e); } + }, + assertEqual: function(expected, actual) { + var message = arguments[2] || "assertEqual"; + try { (expected == actual) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertInspect: function(expected, actual) { + var message = arguments[2] || "assertInspect"; + try { (expected == actual.inspect()) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertEnumEqual: function(expected, actual) { + var message = arguments[2] || "assertEnumEqual"; + try { $A(expected).length == $A(actual).length && + expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ? + this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + + ', actual ' + Test.Unit.inspect(actual)); } + catch(e) { this.error(e); } + }, + assertNotEqual: function(expected, actual) { + var message = arguments[2] || "assertNotEqual"; + try { (expected != actual) ? this.pass() : + this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertIdentical: function(expected, actual) { + var message = arguments[2] || "assertIdentical"; + try { (expected === actual) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertNotIdentical: function(expected, actual) { + var message = arguments[2] || "assertNotIdentical"; + try { !(expected === actual) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertNull: function(obj) { + var message = arguments[1] || 'assertNull' + try { (obj==null) ? this.pass() : + this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); } + catch(e) { this.error(e); } + }, + assertMatch: function(expected, actual) { + var message = arguments[2] || 'assertMatch'; + var regex = new RegExp(expected); + try { (regex.exec(actual)) ? this.pass() : + this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertHidden: function(element) { + var message = arguments[1] || 'assertHidden'; + this.assertEqual("none", element.style.display, message); + }, + assertNotNull: function(object) { + var message = arguments[1] || 'assertNotNull'; + this.assert(object != null, message); + }, + assertType: function(expected, actual) { + var message = arguments[2] || 'assertType'; + try { + (actual.constructor == expected) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + (actual.constructor) + '"'); } + catch(e) { this.error(e); } + }, + assertNotOfType: function(expected, actual) { + var message = arguments[2] || 'assertNotOfType'; + try { + (actual.constructor != expected) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + (actual.constructor) + '"'); } + catch(e) { this.error(e); } + }, + assertInstanceOf: function(expected, actual) { + var message = arguments[2] || 'assertInstanceOf'; + try { + (actual instanceof expected) ? this.pass() : + this.fail(message + ": object was not an instance of the expected type"); } + catch(e) { this.error(e); } + }, + assertNotInstanceOf: function(expected, actual) { + var message = arguments[2] || 'assertNotInstanceOf'; + try { + !(actual instanceof expected) ? this.pass() : + this.fail(message + ": object was an instance of the not expected type"); } + catch(e) { this.error(e); } + }, + assertRespondsTo: function(method, obj) { + var message = arguments[2] || 'assertRespondsTo'; + try { + (obj[method] && typeof obj[method] == 'function') ? this.pass() : + this.fail(message + ": object doesn't respond to [" + method + "]"); } + catch(e) { this.error(e); } + }, + assertReturnsTrue: function(method, obj) { + var message = arguments[2] || 'assertReturnsTrue'; + try { + var m = obj[method]; + if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)]; + m() ? this.pass() : + this.fail(message + ": method returned false"); } + catch(e) { this.error(e); } + }, + assertReturnsFalse: function(method, obj) { + var message = arguments[2] || 'assertReturnsFalse'; + try { + var m = obj[method]; + if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)]; + !m() ? this.pass() : + this.fail(message + ": method returned true"); } + catch(e) { this.error(e); } + }, + assertRaise: function(exceptionName, method) { + var message = arguments[2] || 'assertRaise'; + try { + method(); + this.fail(message + ": exception expected but none was raised"); } + catch(e) { + ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e); + } + }, + assertElementsMatch: function() { + var expressions = $A(arguments), elements = $A(expressions.shift()); + if (elements.length != expressions.length) { + this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions'); + return false; + } + elements.zip(expressions).all(function(pair, index) { + var element = $(pair.first()), expression = pair.last(); + if (element.match(expression)) return true; + this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect()); + }.bind(this)) && this.pass(); + }, + assertElementMatches: function(element, expression) { + this.assertElementsMatch([element], expression); + }, + benchmark: function(operation, iterations) { + var startAt = new Date(); + (iterations || 1).times(operation); + var timeTaken = ((new Date())-startAt); + this.info((arguments[2] || 'Operation') + ' finished ' + + iterations + ' iterations in ' + (timeTaken/1000)+'s' ); + return timeTaken; + }, + _isVisible: function(element) { + element = $(element); + if(!element.parentNode) return true; + this.assertNotNull(element); + if(element.style && Element.getStyle(element, 'display') == 'none') + return false; + + return this._isVisible(element.parentNode); + }, + assertNotVisible: function(element) { + this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1])); + }, + assertVisible: function(element) { + this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1])); + }, + benchmark: function(operation, iterations) { + var startAt = new Date(); + (iterations || 1).times(operation); + var timeTaken = ((new Date())-startAt); + this.info((arguments[2] || 'Operation') + ' finished ' + + iterations + ' iterations in ' + (timeTaken/1000)+'s' ); + return timeTaken; + } +} + +Test.Unit.Testcase = Class.create(); +Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), { + initialize: function(name, test, setup, teardown) { + Test.Unit.Assertions.prototype.initialize.bind(this)(); + this.name = name; + + if(typeof test == 'string') { + test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,'); + test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)'); + this.test = function() { + eval('with(this){'+test+'}'); + } + } else { + this.test = test || function() {}; + } + + this.setup = setup || function() {}; + this.teardown = teardown || function() {}; + this.isWaiting = false; + this.timeToWait = 1000; + }, + wait: function(time, nextPart) { + this.isWaiting = true; + this.test = nextPart; + this.timeToWait = time; + }, + run: function() { + try { + try { + if (!this.isWaiting) this.setup.bind(this)(); + this.isWaiting = false; + this.test.bind(this)(); + } finally { + if(!this.isWaiting) { + this.teardown.bind(this)(); + } + } + } + catch(e) { this.error(e); } + } +}); + +// *EXPERIMENTAL* BDD-style testing to please non-technical folk +// This draws many ideas from RSpec http://rspec.rubyforge.org/ + +Test.setupBDDExtensionMethods = function(){ + var METHODMAP = { + shouldEqual: 'assertEqual', + shouldNotEqual: 'assertNotEqual', + shouldEqualEnum: 'assertEnumEqual', + shouldBeA: 'assertType', + shouldNotBeA: 'assertNotOfType', + shouldBeAn: 'assertType', + shouldNotBeAn: 'assertNotOfType', + shouldBeNull: 'assertNull', + shouldNotBeNull: 'assertNotNull', + + shouldBe: 'assertReturnsTrue', + shouldNotBe: 'assertReturnsFalse', + shouldRespondTo: 'assertRespondsTo' + }; + Test.BDDMethods = {}; + for(m in METHODMAP) { + Test.BDDMethods[m] = eval( + 'function(){'+ + 'var args = $A(arguments);'+ + 'var scope = args.shift();'+ + 'scope.'+METHODMAP[m]+'.apply(scope,(args || []).concat([this])); }'); + } + [Array.prototype, String.prototype, Number.prototype].each( + function(p){ Object.extend(p, Test.BDDMethods) } + ); +} + +Test.context = function(name, spec, log){ + Test.setupBDDExtensionMethods(); + + var compiledSpec = {}; + var titles = {}; + for(specName in spec) { + switch(specName){ + case "setup": + case "teardown": + compiledSpec[specName] = spec[specName]; + break; + default: + var testName = 'test'+specName.gsub(/\s+/,'-').camelize(); + var body = spec[specName].toString().split('\n').slice(1); + if(/^\{/.test(body[0])) body = body.slice(1); + body.pop(); + body = body.map(function(statement){ + return statement.strip() + }); + compiledSpec[testName] = body.join('\n'); + titles[testName] = specName; + } + } + new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name }); +}; \ No newline at end of file diff --git a/web/sf/sf_admin/css/main.css b/web/sf/sf_admin/css/main.css new file mode 100644 index 0000000..4f96ae1 --- /dev/null +++ b/web/sf/sf_admin/css/main.css @@ -0,0 +1,339 @@ +#sf_admin_container ul, #sf_admin_container ol, #sf_admin_container li, #sf_admin_container h1, #sf_admin_container h2, #sf_admin_container h3, #sf_admin_container h4, #sf_admin_container h5, #sf_admin_container h6, #sf_admin_container pre, #sf_admin_container form, #sf_admin_container body, #sf_admin_container html, #sf_admin_container p, #sf_admin_container blockquote, #sf_admin_container fieldset, #sf_admin_container input { margin: 0; padding: 0; } +#sf_admin_container a img,:link img,:visited img { border: none; } + +#sf_admin_container a:link, #sf_admin_container a:visited +{ + text-decoration: none; +} + +#sf_admin_container a:hover +{ + text-decoration: underline; +} + +#sf_admin_container td +{ + margin: 0; + padding: 20px; + font-family: Arial, sans-serif; + font-size: 11px; + background-color: #fff; +} + +#sf_admin_container p +{ + margin-bottom: 5px; +} + +#sf_admin_container #sf_admin_bar +{ + width: auto; +} + +#sf_admin_container #sf_admin_content +{ + +} + +#sf_admin_container h1 +{ + margin: 8px 0; + padding: 3px; + padding-left: 0px; + color: #555; + font-family: "Trebuchet MS", Arial, Verdana, sans-serif; + font-size: 25px; +} + +#sf_admin_container fieldset h2 +{ + padding: 3px; + color: #333; + background-color: #ccf; + font-size: 11px; +} + +#sf_admin_container input, #sf_admin_container textarea, #sf_admin_container select +{ + padding: 3px; + border: 1px solid #ddd; + font-family: Arial, sans-serif; + font-size: 11px; + vertical-align:middle; +} +#sf_admin_container input[type="text"], #sf_admin_container textarea +{ + border: 1px solid #A5ACB2; +} + +#sf_admin_container label +{ + display: block; + padding: 0 1em 3px 0; + float: left; + text-align: left; + width: 11em; + color: #666; + font-weight: normal !important; +} + +#sf_admin_container label.required +{ + color: #333 !important; + font-weight: bold !important; +} + +#sf_admin_container .sf_admin_filters input[type="checkbox"] + label +{ + display: inline; + float: none; +} + +#sf_admin_container .save-ok +{ + margin-bottom: 10px; + border: 1px solid #73B65A; +} + +#sf_admin_container .save-ok h2 +{ + margin: 0 !important; + padding: 5px 20px 5px 25px; + font-size: 11px; + color: #fff; + background: #73B65A url(../images/ok.png) no-repeat 5px 2px; +} + +#sf_admin_container .form-row +{ + clear: both; + padding: 10px; + border-bottom: 1px solid #ddd; +} + +#sf_admin_container .form-row .content +{ + padding-left: 12em; +} + +#sf_admin_container .form-errors +{ + margin-bottom: 10px; + border: 1px solid #f33; + background-color: #ffc; +} + +#sf_admin_container .form-errors h2 +{ + padding: 5px 20px 5px 25px; + font-size: 11px; + color: #fff; + background: #f33 url(../images/error.png) no-repeat 5px 2px; +} + +#sf_admin_container .form-errors dl +{ + padding: 5px; +} + +#sf_admin_container .form-errors dt +{ + font-weight: bold; + float: left; + padding-right: 5px; +} + +#sf_admin_container .form-errors dd +{ + margin: 0; +} + +#sf_admin_container .form-error +{ + color: #f33; +} + +#sf_admin_container .form-error input, #sf_admin_container .form-error select, #sf_admin_container .form-error textarea +{ + border: 1px solid #f33; +} + +#sf_admin_container fieldset +{ + margin-bottom: 3px; + border: 1px solid #ddd; + border-bottom: 0px; + background-color: #fff; +} + +#sf_admin_container fieldset.collapsed * { display:none; } +#sf_admin_container fieldset.collapsed h2, #sf_admin_container fieldset.collapsed { display:block !important; } +#sf_admin_container fieldset.collapsed .collapse-toggle { display: inline !important; } +#sf_admin_container fieldset.collapse h2 a.collapse-toggle { color:#ffc; } +#sf_admin_container fieldset.collapse h2 a.collapse-toggle:hover { text-decoration:underline; } + +#sf_admin_container .float-left +{ + float: left; +} + +#sf_admin_container .float-right +{ + float: right; +} + +#sf_admin_container ul.sf_admin_td_actions +{ + list-style-type: none; +} + +#sf_admin_container ul.sf_admin_td_actions li +{ + list-style-type: none; + display: inline; +} + +#sf_admin_container ul.sf_admin_actions +{ + margin: 10px 0; + list-style-type: none; + text-align: left; +} + +#sf_admin_container ul.sf_admin_actions a +{ + color: #333; +} + +#sf_admin_container ul.sf_admin_actions li +{ + list-style-type: none; + display: inline; +} + +#sf_admin_container ul.sf_admin_actions input +{ + padding: 3px 3px 3px 20px; + cursor: hand; + cursor: pointer; +} + +#sf_admin_container .sf_admin_action_create +{ + background: url(../images/add.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_action_save +{ + background: url(../images/save.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_action_save_and_add +{ + background: url(../images/save.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_action_save_and_list +{ + background: url(../images/save.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_action_delete +{ + background: url(../images/delete.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_action_cancel +{ + background: url(../images/cancel.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_action_filter +{ + background: url(../images/filter.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_action_reset_filter +{ + background: url(../images/reset.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_action_list +{ + background: url(../images/list.png) no-repeat 3px 2px; +} + +#sf_admin_container .sf_admin_default_action +{ + background-color: #fc6 !important; + font-weight: bold !important; +} + +#sf_admin_container .sf_admin_list +{ + width: 100%; + border: 1px solid #ddd; + border-bottom: 0px; + border-right: 0px; +} + +#sf_admin_container .sf_admin_list th +{ + padding: 2px; + background-color: #ccf; + text-align: left; +} + +#sf_admin_container .sf_admin_list th a +{ + color: #333; +} + +#sf_admin_container .sf_admin_list td +{ + padding: 3px; + border-bottom: 1px solid #ddd; + border-right: 1px solid #ddd; +} + +#sf_admin_container .sf_admin_filters li +{ + list-style-type: none; +} + +#sf_admin_container .sf_admin_row_0 td +{ + +} + +#sf_admin_container .sf_admin_row_1 td +{ + background-color: #eef; +} + +#sf_admin_container .sf_admin_edit_help +{ + color: #aaa; +} + +#sf_admin_container .mceEditor td +{ + padding: 0px; +} + +#sf_admin_container select.sf_admin_multiple, #sf_admin_container select.sf_admin_multiple-selected +{ + width: 12em; +} + +#sf_admin_container ul.sf_admin_checklist li +{ + list-style: none; + line-height: 1.5em; +} + +#sf_admin_container ul.sf_admin_checklist li label +{ + display: inline; + float: none; +} diff --git a/web/sf/sf_admin/images/add.png b/web/sf/sf_admin/images/add.png new file mode 100644 index 0000000..323edb0 Binary files /dev/null and b/web/sf/sf_admin/images/add.png differ diff --git a/web/sf/sf_admin/images/cancel.png b/web/sf/sf_admin/images/cancel.png new file mode 100644 index 0000000..744df79 Binary files /dev/null and b/web/sf/sf_admin/images/cancel.png differ diff --git a/web/sf/sf_admin/images/date.png b/web/sf/sf_admin/images/date.png new file mode 100644 index 0000000..c245f1b Binary files /dev/null and b/web/sf/sf_admin/images/date.png differ diff --git a/web/sf/sf_admin/images/default_icon.png b/web/sf/sf_admin/images/default_icon.png new file mode 100644 index 0000000..3103c92 Binary files /dev/null and b/web/sf/sf_admin/images/default_icon.png differ diff --git a/web/sf/sf_admin/images/delete.png b/web/sf/sf_admin/images/delete.png new file mode 100644 index 0000000..3ba9615 Binary files /dev/null and b/web/sf/sf_admin/images/delete.png differ diff --git a/web/sf/sf_admin/images/delete_icon.png b/web/sf/sf_admin/images/delete_icon.png new file mode 100644 index 0000000..73e8638 Binary files /dev/null and b/web/sf/sf_admin/images/delete_icon.png differ diff --git a/web/sf/sf_admin/images/edit.png b/web/sf/sf_admin/images/edit.png new file mode 100644 index 0000000..62ac3a5 Binary files /dev/null and b/web/sf/sf_admin/images/edit.png differ diff --git a/web/sf/sf_admin/images/edit_icon.png b/web/sf/sf_admin/images/edit_icon.png new file mode 100644 index 0000000..62ac3a5 Binary files /dev/null and b/web/sf/sf_admin/images/edit_icon.png differ diff --git a/web/sf/sf_admin/images/error.png b/web/sf/sf_admin/images/error.png new file mode 100644 index 0000000..84b465a Binary files /dev/null and b/web/sf/sf_admin/images/error.png differ diff --git a/web/sf/sf_admin/images/filter.png b/web/sf/sf_admin/images/filter.png new file mode 100644 index 0000000..3187e59 Binary files /dev/null and b/web/sf/sf_admin/images/filter.png differ diff --git a/web/sf/sf_admin/images/first.png b/web/sf/sf_admin/images/first.png new file mode 100644 index 0000000..aa27b55 Binary files /dev/null and b/web/sf/sf_admin/images/first.png differ diff --git a/web/sf/sf_admin/images/help.png b/web/sf/sf_admin/images/help.png new file mode 100644 index 0000000..64e7412 Binary files /dev/null and b/web/sf/sf_admin/images/help.png differ diff --git a/web/sf/sf_admin/images/last.png b/web/sf/sf_admin/images/last.png new file mode 100644 index 0000000..6f8ce77 Binary files /dev/null and b/web/sf/sf_admin/images/last.png differ diff --git a/web/sf/sf_admin/images/list.png b/web/sf/sf_admin/images/list.png new file mode 100644 index 0000000..8965e34 Binary files /dev/null and b/web/sf/sf_admin/images/list.png differ diff --git a/web/sf/sf_admin/images/next.png b/web/sf/sf_admin/images/next.png new file mode 100644 index 0000000..c02a9b5 Binary files /dev/null and b/web/sf/sf_admin/images/next.png differ diff --git a/web/sf/sf_admin/images/ok.png b/web/sf/sf_admin/images/ok.png new file mode 100644 index 0000000..a24d605 Binary files /dev/null and b/web/sf/sf_admin/images/ok.png differ diff --git a/web/sf/sf_admin/images/previous.png b/web/sf/sf_admin/images/previous.png new file mode 100644 index 0000000..6cf3ac1 Binary files /dev/null and b/web/sf/sf_admin/images/previous.png differ diff --git a/web/sf/sf_admin/images/reset.png b/web/sf/sf_admin/images/reset.png new file mode 100644 index 0000000..e6e51a1 Binary files /dev/null and b/web/sf/sf_admin/images/reset.png differ diff --git a/web/sf/sf_admin/images/save.png b/web/sf/sf_admin/images/save.png new file mode 100644 index 0000000..a24d605 Binary files /dev/null and b/web/sf/sf_admin/images/save.png differ diff --git a/web/sf/sf_admin/images/tick.png b/web/sf/sf_admin/images/tick.png new file mode 100644 index 0000000..a9925a0 Binary files /dev/null and b/web/sf/sf_admin/images/tick.png differ diff --git a/web/sf/sf_admin/js/collapse.js b/web/sf/sf_admin/js/collapse.js new file mode 100644 index 0000000..c3d466d --- /dev/null +++ b/web/sf/sf_admin/js/collapse.js @@ -0,0 +1,87 @@ +// django javascript file + +// Finds all fieldsets with class="collapse", collapses them, and gives each +// one a "show" link that uncollapses it. The "show" link becomes a "hide" +// link when the fieldset is visible. + +function findForm(node) { + // returns the node of the form containing the given node + if (node.tagName.toLowerCase() != 'form') { + return findForm(node.parentNode); + } + return node; +} + +var CollapsedFieldsets = { + collapse_re: /\bcollapse\b/, // Class of fieldsets that should be dealt with. + collapsed_re: /\bcollapsed\b/, // Class that fieldsets get when they're hidden. + collapsed_class: 'collapsed', + init: function() { + var fieldsets = document.getElementsByTagName('fieldset'); + var collapsed_seen = false; + for (var i = 0, fs; fs = fieldsets[i]; i++) { + // Collapse this fieldset if it has the correct class, and if it + // doesn't have any errors. (Collapsing shouldn't apply in the case + // of error messages.) + if (fs.className.match(CollapsedFieldsets.collapse_re) && !CollapsedFieldsets.fieldset_has_errors(fs)) { + collapsed_seen = true; + // Give it an additional class, used by CSS to hide it. + fs.className += ' ' + CollapsedFieldsets.collapsed_class; + // (show) + var collapse_link = document.createElement('a'); + collapse_link.className = 'collapse-toggle'; + collapse_link.id = 'fieldsetcollapser' + i; + collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;'); + collapse_link.href = '#'; + collapse_link.innerHTML = 'show'; + var h2 = fs.getElementsByTagName('h2')[0]; + h2.appendChild(document.createTextNode(' [')); + h2.appendChild(collapse_link); + h2.appendChild(document.createTextNode(']')); + } + } + if (collapsed_seen) { + // Expand all collapsed fieldsets when form is submitted. + Event.observe(findForm(document.getElementsByTagName('fieldset')[0]), 'submit', function() { CollapsedFieldsets.uncollapse_all(); }, false); + } + }, + fieldset_has_errors: function(fs) { + // Returns true if any fields in the fieldset have validation errors. + var divs = fs.getElementsByTagName('div'); + for (var i=0; i + + + + + diff --git a/web/sf/sf_default/css/screen.css b/web/sf/sf_default/css/screen.css new file mode 100644 index 0000000..be45f7d --- /dev/null +++ b/web/sf/sf_default/css/screen.css @@ -0,0 +1,182 @@ +body +{ + font-family: "Trebuchet MS", Geneva, Arial, Helvetica, sans-serif; + margin: 0; + padding: 0; + font-size: 80%; + background-image: url(../images/bg_body.jpg); + background-repeat: repeat-x; + background-color: #E4D7C5; + color: #81571F; + text-align: center; +} + +img +{ + border: none; +} + +a +{ + color: #81571F; + text-decoration: underline; +} + +a:hover +{ + color: #CC0000; + text-decoration: none; +} + +code +{ + font-size:120%; +} + +.sfTContainer +{ + position: relative; + text-align: left; + width: 515px; + margin: 0 auto; + padding: 0; + margin-top: 115px; +} + +.sfTMessageContainer +{ + padding: 5px; + margin-top: 25px; + float: left; + width: 515px; +} + +.sfTMessage +{ + background-image: url(../images/bg_sfTMessage.jpg); + background-repeat: repeat-x; + background-color: #E8DDCF; + border: 1px solid #FFFFFF; + border-bottom-color: #C2AB8C; + border-right-color: #C2AB8C; +} + +.sfTAlert +{ + background-image: url(../images/bg_sfTAlert.jpg); + background-repeat: repeat-x; + background-color: #F8E1D1; + border: 1px solid #FFFFFF; + border-bottom-color: #F0B17C; + border-right-color: #F0B17C; +} + +.sfTLock +{ + background-image: url(../images/bg_sfTLock.jpg); + background-repeat: repeat-x; + background-color: #DEE8F2; + border: 1px solid #FFFFFF; + border-bottom-color: #B1C4EC; + border-right-color: #B1C4EC; +} + +.sfTMessageContainer .sfTMessageWrap +{ + float: left; + width: 440px; +} + +.sfTMessageContainer .sfTMessageWrap h1 +{ + color: #503512; + font-weight: normal; + font-size: 165%; + padding: 0; + margin: 0; + line-height: 100%; + padding-top: 5px; +} + +.sfTMessageContainer .sfTMessageWrap h5 +{ + font-weight: normal; + font-size: 100%; + padding: 0; + margin: 0; +} + +.sfTMessageContainer img.sfTMessageIcon +{ + width: 48px; + height: 48px; + float: left; + margin-right: 12px; + margin-left: 5px; +} + +.sfTMessageInfo +{ + margin: 0; + padding: 0; + margin-top: 15px; + float: left; + width: 440px; +} + +.sfTMessageInfo dt +{ + font-weight: bolder; + font-size: 115%; + margin: 5px 0; +} + +.sfTMessageInfo dd +{ + margin: 0; + padding: 0; +} + +.sfTIconList +{ + margin: 0; + padding: 0; + list-style: none; +} + +.sfTIconList li +{ + clear: left; + line-height: 170%; + padding-left: 20px; +} + +.sfTIconList li.sfTDatabaseMessage +{ + background: url(../images/icons/db16.png) no-repeat top left; +} + +.sfTIconList li.sfTColorMessage +{ + background: url(../images/icons/colour16.png) no-repeat top left; +} + +.sfTIconList li.sfTLinkMessage +{ + background: url(../images/icons/linkOut16.png) no-repeat top left; +} + +.sfTIconList li.sfTDirectoryMessage +{ + background: url(../images/icons/folder16.png) no-repeat top left; +} + +.sfTIconList li.sfTEditMessage +{ + background: url(../images/icons/edit16.png) no-repeat top left; +} + +.sfTIconList li.sfTReloadMessage +{ + background: url(../images/icons/reload16.png) no-repeat top left; +} diff --git a/web/sf/sf_default/images/bg_body.jpg b/web/sf/sf_default/images/bg_body.jpg new file mode 100644 index 0000000..2fd07c5 Binary files /dev/null and b/web/sf/sf_default/images/bg_body.jpg differ diff --git a/web/sf/sf_default/images/bg_sfTAlert.jpg b/web/sf/sf_default/images/bg_sfTAlert.jpg new file mode 100644 index 0000000..0a57dc9 Binary files /dev/null and b/web/sf/sf_default/images/bg_sfTAlert.jpg differ diff --git a/web/sf/sf_default/images/bg_sfTLock.jpg b/web/sf/sf_default/images/bg_sfTLock.jpg new file mode 100644 index 0000000..2dc8849 Binary files /dev/null and b/web/sf/sf_default/images/bg_sfTLock.jpg differ diff --git a/web/sf/sf_default/images/bg_sfTMessage.jpg b/web/sf/sf_default/images/bg_sfTMessage.jpg new file mode 100644 index 0000000..ecc6868 Binary files /dev/null and b/web/sf/sf_default/images/bg_sfTMessage.jpg differ diff --git a/web/sf/sf_default/images/icons/cancel48.png b/web/sf/sf_default/images/icons/cancel48.png new file mode 100644 index 0000000..f299b2d Binary files /dev/null and b/web/sf/sf_default/images/icons/cancel48.png differ diff --git a/web/sf/sf_default/images/icons/colour16.png b/web/sf/sf_default/images/icons/colour16.png new file mode 100644 index 0000000..f8e2fe5 Binary files /dev/null and b/web/sf/sf_default/images/icons/colour16.png differ diff --git a/web/sf/sf_default/images/icons/db16.png b/web/sf/sf_default/images/icons/db16.png new file mode 100644 index 0000000..dfd9911 Binary files /dev/null and b/web/sf/sf_default/images/icons/db16.png differ diff --git a/web/sf/sf_default/images/icons/disabled48.png b/web/sf/sf_default/images/icons/disabled48.png new file mode 100644 index 0000000..2e0fff0 Binary files /dev/null and b/web/sf/sf_default/images/icons/disabled48.png differ diff --git a/web/sf/sf_default/images/icons/edit16.png b/web/sf/sf_default/images/icons/edit16.png new file mode 100644 index 0000000..cd77c30 Binary files /dev/null and b/web/sf/sf_default/images/icons/edit16.png differ diff --git a/web/sf/sf_default/images/icons/folder16.png b/web/sf/sf_default/images/icons/folder16.png new file mode 100644 index 0000000..edfd01e Binary files /dev/null and b/web/sf/sf_default/images/icons/folder16.png differ diff --git a/web/sf/sf_default/images/icons/linkOut16.png b/web/sf/sf_default/images/icons/linkOut16.png new file mode 100644 index 0000000..d3e9c67 Binary files /dev/null and b/web/sf/sf_default/images/icons/linkOut16.png differ diff --git a/web/sf/sf_default/images/icons/lock48.png b/web/sf/sf_default/images/icons/lock48.png new file mode 100644 index 0000000..ad5f308 Binary files /dev/null and b/web/sf/sf_default/images/icons/lock48.png differ diff --git a/web/sf/sf_default/images/icons/ok48.png b/web/sf/sf_default/images/icons/ok48.png new file mode 100644 index 0000000..cd736e8 Binary files /dev/null and b/web/sf/sf_default/images/icons/ok48.png differ diff --git a/web/sf/sf_default/images/icons/reload16.png b/web/sf/sf_default/images/icons/reload16.png new file mode 100644 index 0000000..dfb9feb Binary files /dev/null and b/web/sf/sf_default/images/icons/reload16.png differ diff --git a/web/sf/sf_default/images/icons/tools48.png b/web/sf/sf_default/images/icons/tools48.png new file mode 100644 index 0000000..30a40f6 Binary files /dev/null and b/web/sf/sf_default/images/icons/tools48.png differ diff --git a/web/sf/sf_default/images/sfTLogo.png b/web/sf/sf_default/images/sfTLogo.png new file mode 100644 index 0000000..287b4bf Binary files /dev/null and b/web/sf/sf_default/images/sfTLogo.png differ diff --git a/web/sf/sf_default/images/trans.gif b/web/sf/sf_default/images/trans.gif new file mode 100644 index 0000000..73130b9 Binary files /dev/null and b/web/sf/sf_default/images/trans.gif differ diff --git a/web/sf/sf_web_debug/css/main.css b/web/sf/sf_web_debug/css/main.css new file mode 100644 index 0000000..4056931 --- /dev/null +++ b/web/sf/sf_web_debug/css/main.css @@ -0,0 +1,284 @@ +#sfWebDebug +{ + padding: 0; + margin: 0; + font-family: Arial, sans-serif; + font-size: 12px; + color: #333; + text-align: left; + line-height: 12px; +} + +#sfWebDebug a, #sfWebDebug a:hover +{ + text-decoration: none; + border: none; + background-color: transparent; + color: #000; +} + +#sfWebDebug img +{ + border: 0; +} + +#sfWebDebugBar +{ + position: absolute; + margin: 0; + padding: 1px 0; + right: 0px; + top: 0px; + opacity: 0.80; + filter: alpha(opacity:80); + z-index: 10000; +} + +#sfWebDebugBar[id] +{ + position: fixed; +} + +#sfWebDebugBar img +{ + vertical-align: middle; + float: left; + margin-right: 7px; +} + +#sfWebDebugBar .menu +{ + padding: 5px; + display: inline; +} + +#sfWebDebugBar ul +{ + position: relative; + top: -10px; +} + +#sfWebDebugBar .menu li +{ + /*display: inline;*/ + list-style: none; + margin-left: 5px; + padding: 0px; + border-right: 1px solid #aaa; + padding: 5px; + border-bottom: 1px solid #C0C0C0; +} + +#sfWebDebugBar .menu li.last +{ +} + +#sfWebDebugDatabaseDetails li +{ + margin: 0; + margin-left: 30px; + padding: 5px 0; +} + +#sfWebDebugShortMessages li +{ + margin-bottom: 10px; + padding: 5px; + background-color: #ddd; +} + +#sfWebDebugShortMessages li +{ + list-style: none; +} + +#sfWebDebugDetails +{ + margin-right: 7px; +} + +#sfWebDebug pre +{ + line-height: 1.3; + margin-bottom: 10px; +} + +#sfWebDebug h1 +{ + font-size: 16px; + font-weight: bold; + margin-bottom: 20px; + padding: 0; + border: 0px; + background-color: #eee; +} + +#sfWebDebug h2 +{ + font-size: 14px; + font-weight: bold; + margin: 10px 0; + padding: 0; + border: 0px; + background: none; +} + +#sfWebDebug .sfWebDebugTop +{ + position: absolute; + left: 0px; + top: 0px; + width: 100%; + padding: 10px; + z-index: 9999; + background-color: #efefef; + border-bottom: 1px solid #aaa; +} + +#sfWebDebugLog +{ + margin: 0; + padding: 3px; + font-size: 11px; +} + +#sfWebDebugLogMenu li +{ + display: inline; + list-style: none; + margin: 0; + padding: 0 5px; + border-right: 1px solid #aaa; +} + +#sfWebDebugConfigSummary +{ + display: inline; + padding: 5px; + background-color: #ddd; + border: 1px solid #aaa; + margin: 20px 0; +} + +#sfWebDebugConfigSummary li +{ + list-style: none; + display: inline; + margin: 0; + padding: 0 5px; + border-right: 1px solid #aaa; +} + +#sfWebDebugConfigSummary li.last +{ + margin: 0; + padding: 0; + border: 0; +} + +.sfWebDebugInfo, .sfWebDebugInfo td +{ + background-color: #ddd; +} + +.sfWebDebugWarning, .sfWebDebugWarning td +{ + background-color: orange; +} + +.sfWebDebugError, .sfWebDebugError td +{ + background-color: #f99; +} + +.sfWebDebugLogNumber +{ + width: 1%; +} + +.sfWebDebugLogType +{ + width: 1%; + white-space: nowrap; + color: darkgreen; +} + +.sfWebDebugLogInfo +{ + color: blue; +} + +.ison +{ + color: #3f3; + margin-right: 5px; +} + +.isoff +{ + color: #f33; + margin-right: 5px; + text-decoration: line-through; +} + +.sfWebDebugLogs +{ + padding: 0; + margin: 0; + border: 1px solid #999; + font-family: Arial; + font-size: 11px; +} + +.sfWebDebugLogs tr +{ + padding: 0; + margin: 0; + border: 0; +} + +.sfWebDebugLogs td +{ + margin: 0; + border: 0; + padding: 1px 3px; + vertical-align: top; +} + +.sfWebDebugLogs th +{ + margin: 0; + border: 0; + padding: 3px 5px; + vertical-align: top; + background-color: #999; + color: #eee; + white-space: nowrap; +} + +.sfWebDebugDebugInfo +{ + margin-left: 10px; + padding-left: 5px; + border-left: 1px solid #aaa; +} + +.sfWebDebugCache +{ + padding: 0; + margin: 0; + font-family: Arial; + position: absolute; + overflow: hidden; + z-index: 995; + font-size: 9px; + padding: 2px; + filter:alpha(opacity=85); + -moz-opacity:0.85; + opacity: 0.85; +} + +#sfWebDebugDatabaseLogs +{ + padding-right: 135px; +} diff --git a/web/sf/sf_web_debug/images/close.png b/web/sf/sf_web_debug/images/close.png new file mode 100644 index 0000000..1514d51 Binary files /dev/null and b/web/sf/sf_web_debug/images/close.png differ diff --git a/web/sf/sf_web_debug/images/comment.png b/web/sf/sf_web_debug/images/comment.png new file mode 100644 index 0000000..7bc9233 Binary files /dev/null and b/web/sf/sf_web_debug/images/comment.png differ diff --git a/web/sf/sf_web_debug/images/config.png b/web/sf/sf_web_debug/images/config.png new file mode 100644 index 0000000..7851cf3 Binary files /dev/null and b/web/sf/sf_web_debug/images/config.png differ diff --git a/web/sf/sf_web_debug/images/database.png b/web/sf/sf_web_debug/images/database.png new file mode 100644 index 0000000..3d09261 Binary files /dev/null and b/web/sf/sf_web_debug/images/database.png differ diff --git a/web/sf/sf_web_debug/images/error.png b/web/sf/sf_web_debug/images/error.png new file mode 100644 index 0000000..e8a602d Binary files /dev/null and b/web/sf/sf_web_debug/images/error.png differ diff --git a/web/sf/sf_web_debug/images/info.png b/web/sf/sf_web_debug/images/info.png new file mode 100644 index 0000000..e4bc611 Binary files /dev/null and b/web/sf/sf_web_debug/images/info.png differ diff --git a/web/sf/sf_web_debug/images/memory.png b/web/sf/sf_web_debug/images/memory.png new file mode 100644 index 0000000..9051fbc Binary files /dev/null and b/web/sf/sf_web_debug/images/memory.png differ diff --git a/web/sf/sf_web_debug/images/reload.png b/web/sf/sf_web_debug/images/reload.png new file mode 100644 index 0000000..e6e51a1 Binary files /dev/null and b/web/sf/sf_web_debug/images/reload.png differ diff --git a/web/sf/sf_web_debug/images/sf.png b/web/sf/sf_web_debug/images/sf.png new file mode 100644 index 0000000..962bf2a Binary files /dev/null and b/web/sf/sf_web_debug/images/sf.png differ diff --git a/web/sf/sf_web_debug/images/time.png b/web/sf/sf_web_debug/images/time.png new file mode 100644 index 0000000..911da3f Binary files /dev/null and b/web/sf/sf_web_debug/images/time.png differ diff --git a/web/sf/sf_web_debug/images/toggle.gif b/web/sf/sf_web_debug/images/toggle.gif new file mode 100644 index 0000000..ad1bf0f Binary files /dev/null and b/web/sf/sf_web_debug/images/toggle.gif differ diff --git a/web/sf/sf_web_debug/images/warning.png b/web/sf/sf_web_debug/images/warning.png new file mode 100644 index 0000000..14c89a5 Binary files /dev/null and b/web/sf/sf_web_debug/images/warning.png differ diff --git a/web/sf/sf_web_debug/js/main.js b/web/sf/sf_web_debug/js/main.js new file mode 100644 index 0000000..f75419f --- /dev/null +++ b/web/sf/sf_web_debug/js/main.js @@ -0,0 +1,133 @@ +function sfWebDebugGetElementsByClassName(strClass, strTag, objContElm) +{ + // http://muffinresearch.co.uk/archives/2006/04/29/getelementsbyclassname-deluxe-edition/ + strTag = strTag || "*"; + objContElm = objContElm || document; + var objColl = (strTag == '*' && document.all) ? document.all : objContElm.getElementsByTagName(strTag); + var arr = new Array(); + var delim = strClass.indexOf('|') != -1 ? '|' : ' '; + var arrClass = strClass.split(delim); + var j = objColl.length; + for (var i = 0; i < j; i++) { + if(objColl[i].className == undefined) continue; + var arrObjClass = objColl[i].className.split(' '); + if (delim == ' ' && arrClass.length > arrObjClass.length) continue; + var c = 0; + comparisonLoop: + { + var l = arrObjClass.length; + for (var k = 0; k < l; k++) { + var n = arrClass.length; + for (var m = 0; m < n; m++) { + if (arrClass[m] == arrObjClass[k]) c++; + if (( delim == '|' && c == 1) || (delim == ' ' && c == arrClass.length)) { + arr.push(objColl[i]); + break comparisonLoop; + } + } + } + } + } + return arr; +} + +function sfWebDebugToggleMenu() +{ + var element = document.getElementById('sfWebDebugDetails'); + + var cacheElements = sfWebDebugGetElementsByClassName('sfWebDebugCache'); + var mainCacheElements = sfWebDebugGetElementsByClassName('sfWebDebugActionCache'); + + if (element.style.display != 'none') + { + document.getElementById('sfWebDebugLog').style.display = 'none'; + document.getElementById('sfWebDebugConfig').style.display = 'none'; + document.getElementById('sfWebDebugDatabaseDetails').style.display = 'none'; + document.getElementById('sfWebDebugTimeDetails').style.display = 'none'; + + // hide all cache information + for (var i = 0; i < cacheElements.length; ++i) + { + cacheElements[i].style.display = 'none'; + } + for (var i = 0; i < mainCacheElements.length; ++i) + { + mainCacheElements[i].style.border = 'none'; + } + } + else + { + for (var i = 0; i < cacheElements.length; ++i) + { + cacheElements[i].style.display = ''; + } + for (var i = 0; i < mainCacheElements.length; ++i) + { + mainCacheElements[i].style.border = '1px solid #f00'; + } + } + + sfWebDebugToggle('sfWebDebugDetails'); + sfWebDebugToggle('sfWebDebugShowMenu'); + sfWebDebugToggle('sfWebDebugHideMenu'); +} + +function sfWebDebugShowDetailsFor(element) +{ + if (element != 'sfWebDebugLog') document.getElementById('sfWebDebugLog').style.display='none'; + if (element != 'sfWebDebugConfig') document.getElementById('sfWebDebugConfig').style.display='none'; + if (element != 'sfWebDebugDatabaseDetails') document.getElementById('sfWebDebugDatabaseDetails').style.display='none'; + if (element != 'sfWebDebugTimeDetails') document.getElementById('sfWebDebugTimeDetails').style.display='none'; + + sfWebDebugToggle(element); +} + +function sfWebDebugToggle(element) +{ + if (typeof element == 'string') + element = document.getElementById(element); + + if (element) + element.style.display = element.style.display == 'none' ? '' : 'none'; +} + +function sfWebDebugToggleMessages(klass) +{ + var elements = sfWebDebugGetElementsByClassName(klass); + + var x = elements.length; + for (var i = 0; i < x; ++i) + { + sfWebDebugToggle(elements[i]); + } +} + +function sfWebDebugToggleAllLogLines(show, klass) +{ + var elements = sfWebDebugGetElementsByClassName(klass); + var x = elements.length; + for (var i = 0; i < x; ++i) + { + elements[i].style.display = show ? '' : 'none'; + } +} + +function sfWebDebugShowOnlyLogLines(type) +{ + var types = new Array(); + types[0] = 'info'; + types[1] = 'warning'; + types[2] = 'error'; + for (klass in types) + { + var elements = sfWebDebugGetElementsByClassName('sfWebDebug' + types[klass].substring(0, 1).toUpperCase() + types[klass].substring(1, types[klass].length)); + var x = elements.length; + for (var i = 0; i < x; ++i) + { + if ('tr' == elements[i].tagName.toLowerCase()) + { + elements[i].style.display = (type == types[klass]) ? '' : 'none'; + } + } + } +} diff --git a/web/tests.php b/web/tests.php new file mode 100644 index 0000000..f1d8df4 --- /dev/null +++ b/web/tests.php @@ -0,0 +1,55 @@ +\n"; + readfile($smResults); + echo "\n"; +} +if (!file_exists($db) || filesize($db) == 0) { + trigger_error("Can't find the databae file..", E_USER_ERROR); +} + +$pdo = new PDO("sqlite:$db"); +$stmt = $pdo->query("SELECT DISTINCT filename, date FROM tests ORDER BY date DESC, filename"); +if (!$stmt) { + trigger_error(var_export($pdo->errorInfo(), true), E_USER_ERROR); +} + +$stmt->setFetchMode(PDO::FETCH_ASSOC); +$sql = "SELECT description, line, status FROM tests WHERE filename=%s AND date=%d"; +$files = array(); +$sumFailed = $sumPassed = 0; +foreach($stmt as $row) { + $fn = basename($row["filename"]); + + // Awesome workaround for not-normalized database + if (in_array($fn, $files)) { + continue; + } + $files[] = $fn; + + echo ""; + printf("\n", $fn, date(DATE_RSS, $row["date"])); + $tests = $pdo->query(sprintf($sql, $pdo->quote($row["filename"]), (int)$row["date"])); + $failed = $passed = 0; + foreach($tests as $test) { + printf("\n", $test["description"], $test["status"] ? "00FF00" : "FF0000", $test["status"] ? "PASS" : "FAIL"); + if ($test["status"]) { + ++$passed; + } else { + ++$failed; + } + } + $sumFailed += $failed; + $sumPassed += $passed; + echo "\n"; + echo "
    %s%s
    %s%s
    SummaryFailed: $failed
    Passed: $passed


    "; +} +echo "
    \n"; +echo "Overall failures: $sumFailed
    \n"; +echo "Overall passsess: $sumPassed
    \n"; +?> + + diff --git a/web/uploads/profile_images/default.gif b/web/uploads/profile_images/default.gif new file mode 100644 index 0000000..8be2b5e Binary files /dev/null and b/web/uploads/profile_images/default.gif differ diff --git a/web/uploads/profile_images/default16x16.gif b/web/uploads/profile_images/default16x16.gif new file mode 100644 index 0000000..00fbcff Binary files /dev/null and b/web/uploads/profile_images/default16x16.gif differ diff --git a/web/uploads/profile_images/old_default.gif b/web/uploads/profile_images/old_default.gif new file mode 100644 index 0000000..9b0517e Binary files /dev/null and b/web/uploads/profile_images/old_default.gif differ diff --git a/web/xspf_player/license.txt b/web/xspf_player/license.txt new file mode 100644 index 0000000..12d609e --- /dev/null +++ b/web/xspf_player/license.txt @@ -0,0 +1,10 @@ +Copyright (c) 2005, Fabricio Zuardi +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/web/xspf_player/xspf_player.as b/web/xspf_player/xspf_player.as new file mode 100644 index 0000000..0cd58e1 --- /dev/null +++ b/web/xspf_player/xspf_player.as @@ -0,0 +1,448 @@ +/* +Copyright (c) 2005, Fabricio Zuardi +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +stop(); +//autoplay=true +//repeat_playlist = true; +//playlist_size = 3; +//player_title = "customizeable title test" +//song_url = "http://downloads.betterpropaganda.com/music/Imperial_Teen-Ivanka_128.mp3"; +//playlist_url = "http://cchits.ning.com/recent/xspf/?xn_auth=no"; +//playlist_url = "http://hideout.com.br/shows/radio-test.xspf"; +//radio_mode = true; +//song_title = "Imperial Teen - Ivanka"; +autoload=true; +//info_button_text = "Add to Cart" +//playlist_url = "http%3A%2F%2Fwebjay%2Eorg%2Fby%2Flucas%5Fgonze%2Flaconic%2Exspf" +//playlist_url= "http://hideout.com.br/tests/hideout2325.xspf" +//constants +DEFAULT_PLAYLIST_URL = "http://hideout.com.br/shows/allshows.xspf"; +DEFAULT_WELCOME_MSG = "Hideout XSPF Music Player - by Fabricio Zuardi"; +LOADING_PLAYLIST_MSG = "Loading Playlist..."; +DEFAULT_LOADED_PLAYLIST_MSG = "- click to start" +DEFAULT_INFOBUTTON_TXT = "Info" +//playlists has priority over songs, if a playlist_url parameter is found the song_url is ignored +//default playlist if none is passed through query string +if(!playlist_url){ + if(!song_url){ + playlist_url = DEFAULT_PLAYLIST_URL; + }else{ + single_music_playlist = ""; + single_music_playlist += ""+song_url+""+song_title+"" + single_music_playlist += "" + } +} +info_mc._visible=false; +if(!info_button_text){ + info_button_text = DEFAULT_INFOBUTTON_TXT; +} +info_mc.display_txt.text = info_button_text; + +//variables initialization +playlist_array = []; +track_index = 0; +playlist_mc.track_count = 0; +pause_position = 0; +volume_level = 100; +playlist_xml = new XML(); +playlist_xml.ignoreWhite = true; +playlist_xml.onLoad = playlistLoaded; +mysound = new Sound(this); +playlist_listener = new Object(); +playlist_list.addEventListener("change", playlist_listener) +//play_btn.onPress = playTrack; +//functions +//xml parser +function playlistLoaded (success){ + if(success){ + var root_node = this.firstChild; + for(var node = root_node.firstChild; node != null; node = node.nextSibling){ + if(node.nodeName == "title"){ + playlist_title = node.firstChild.nodeValue; + } + if(node.nodeName == "trackList"){ + //tracks + var tracks_array = []; + for(var track_node = node.firstChild; track_node != null; track_node = track_node.nextSibling){ + var track_obj = new Object() + //track attributes + for(var track_child = track_node.firstChild; track_child != null; track_child = track_child.nextSibling){ + if(track_child.nodeName=="location"){ + track_obj.location = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="image"){ + track_obj.image = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="title"){ + track_obj.title = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="creator"){ + track_obj.creator = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="annotation"){ + track_obj.annotation = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="info"){ + track_obj.info = track_child.firstChild.nodeValue + } + } + track_obj.label = (tracks_array.length+1) +". "; + if(track_obj.title) { + if(track_obj.creator) { + track_obj.label += track_obj.creator+' - '; + } + track_obj.label += track_obj.title; + } else { + track_obj.label += track_obj.annotation; + } + tracks_array.push(track_obj) + addTrack(track_obj.label); + } + } + } + playlist_array = tracks_array; + if(!playlist_size) playlist_size = playlist_array.length; + playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(2) + if(autoplay){ + loadTrack() + }else{ + start_btn_mc.start_btn.onPress = loadTrack; + track_display_mc.display_txt.text = playlist_title+" "+DEFAULT_LOADED_PLAYLIST_MSG; + if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; + }else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; + } + } + }else{ + annotation_txt.text = "Error opening "+playlist_url; + } +} + +playlist_listener.change = function(eventObject){ + annotation_txt.text = playlist_list.selectedItem.annotation; + location_txt.text = playlist_list.selectedItem.location; +} + +function loadTrack(){ + + //Radio Mode feature by nosferathoo, more info in: https://sourceforge.net/tracker/index.php?func=detail&aid=1341940&group_id=128363&atid=711474 + if (radio_mode && track_index==playlist_size-1) { + playlist_url=playlist_array[track_index].location; + for (i=0;itrack_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; + }else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; + } + cover_mc.content_mc["photo"+last_track_index].removeMovieClip(); + mysound.loadSound(playlist_array[track_index].location,true); + play_mc.gotoAndStop(2) + + //image from playlist + if(playlist_array[track_index].image!=undefined){ + cover_mc.content_mc.createEmptyMovieClip("photo"+track_index,track_index) + cover_mc.content_mc["photo"+track_index].loadMovie(playlist_array[track_index].image) + }else{ + } + //info button + if(playlist_array[track_index].info!=undefined){ + info_mc._visible = true; + info_mc.info_btn.onPress = function(){ + getURL(playlist_array[track_index].info,"_blank") + } + }else{ + info_mc._visible = false; + } + _root.onEnterFrame=function(){ + //HACK doesnt need to set the volume at every enterframe + mysound.setVolume(this.volume_level) + var sound_load_percent = (mysound.getBytesLoaded()/mysound.getBytesTotal())*100 + track_display_mc.loader_mc.load_bar_mc._xscale = sound_load_percent; + var image_load_percent = (cover_mc.content_mc["photo"+track_index].getBytesLoaded()/cover_mc.content_mc["photo"+track_index].getBytesTotal())*100 + cover_mc.load_bar_mc._xscale = image_load_percent; + if((cover_mc.content_mc["photo"+track_index].getBytesLoaded()>4)&&(image_load_percent==100)){ + //image loaded + //make image fit + cover_mc.content_mc["photo"+track_index]._width = cover_mc.load_bar_mc._width + cover_mc.content_mc["photo"+track_index]._height = cover_mc.load_bar_mc._height + } + } +} + +stop_btn.onRelease = stopTrack; +play_mc.play_btn.onRelease = playTrack +next_btn.onRelease = nextTrack +prev_btn.onRelease = prevTrack +mysound.onSoundComplete = nextTrack; +volume_mc.volume_btn.onPress = volumeChange; +volume_mc.volume_btn.onRelease = volume_mc.volume_btn.onReleaseOutside = function(){ + this._parent.onMouseMove = this._parent.onMouseDown = null; +} + +function volumeChange(){ + this._parent.onMouseMove = this._parent.onMouseDown = function(){ + var percent = (this._xmouse/this._width)*100 + if(percent>100)percent=100; + if(percent<0)percent=0; + this.volume_bar_mc._xscale = percent + this._parent.volume_level = percent; + mysound.setVolume(percent) + } +} + +function stopTrack() { + mysound.stop(); + play_mc.gotoAndStop(1) + mysound.stop(); + mysound.start(); + mysound.stop(); + _root.pause_position = 0; + +}; +function playTrack() { + if(play_mc._currentframe==1){ //play + seekTrack(_root.pause_position) + play_mc.gotoAndStop(2) + }else if(play_mc._currentframe==2){ + _root.pause_position = mysound.position; + mysound.stop(); + play_mc.gotoAndStop(1) + } + +}; +function seekTrack(p_offset:Number){ + mysound.stop() + mysound.start(int((p_offset)/1000),1) +} +function nextTrack(){ + if(track_index0){ + last_track_index = track_index; + track_index --; + loadTrack(); + } + playlist_mc.tracks_mc["track_"+last_track_index+"_mc"].bg_mc.gotoAndStop(1) + playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(2) +} + +function scrollTitle(){ + track_display_mc.display_txt._x -= 5; + if (track_display_mc.display_txt._x+track_display_mc.display_txt._width<0){ + track_display_mc.display_txt._x = track_display_mc.mask_mc._width; + } +} + +function resizeUI(){ + bg_mc._width = Stage.width; + track_display_mc.loader_mc._width = Stage.width - track_display_mc._x - 2; + track_display_mc.mask_mc._width = track_display_mc.loader_mc._width-3; + if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; + }else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; + } + volume_mc._x = Stage.width - 22; + start_btn_mc._xscale = Stage.width; + //playlist area tinnier that the album cover + if(Stage.width<2.5*cover_mc._width){ + // + if (Stage.height>2.5*cover_mc._height){ + //send album cover to bottom + cover_mc._y = Stage.height - cover_mc._height -2- info_mc._height -2; + info_mc._y = Stage.height - info_mc._height -2; + var covervisible =1; + }else{ + var covervisible =0; + //hide album cover + cover_mc._y = Stage.height; + } + //send playlist to left + playlist_mc._x = cover_mc._x; + scrollbar_mc.bg_mc._height = Stage.height - (19+(cover_mc._height+info_mc._height+4)*covervisible); + playlist_mc.bg_mc._height = Stage.height - (19+(cover_mc._height+info_mc._height+4)*covervisible); + playlist_mc.mask_mc._height = Stage.height - (23+(cover_mc._height+info_mc._height+4)*covervisible); + }else{ + cover_mc._y = 17; + info_mc._y = 153; + playlist_mc._x = 138; + scrollbar_mc.bg_mc._height = Stage.height -19; + playlist_mc.bg_mc._height = Stage.height - 19; + playlist_mc.mask_mc._height = Stage.height - 23; + } + scrollbar_mc._x = Stage.width - 12; + playlist_mc.mask_mc._width = Stage.width - (playlist_mc._x + 19); + playlist_mc.bg_mc._width = Stage.width - (playlist_mc._x + 14); +} +function addTrack(track_label){ + if(playlist_mc.track_count>0) { + playlist_mc.tracks_mc.track_0_mc.duplicateMovieClip("track_"+playlist_mc.track_count+"_mc",playlist_mc.track_count); + } + playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"]._y += playlist_mc.track_count*14; + playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"].display_txt.autoSize = "left"; + playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"].display_txt.text = track_label; + playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"].bg_mc.index = playlist_mc.track_count; + playlist_mc.tracks_mc["track_"+playlist_mc.track_count+"_mc"].bg_mc.select_btn.onPress = function(){ + last_track_index = track_index; + playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(1) + track_index = this._parent.index; + playlist_mc.tracks_mc["track_"+track_index+"_mc"].bg_mc.gotoAndStop(2) + loadTrack(); + } + playlist_mc.track_count ++; +} +//scroll + +scrollbar_mc.up_btn.onPress = function(){ + this._parent.v = -1; + this._parent.onEnterFrame = scrollTracks; +} +scrollbar_mc.down_btn.onPress = function(){ + this._parent.v = 1; + this._parent.onEnterFrame = scrollTracks; +} +scrollbar_mc.up_btn.onRelease = scrollbar_mc.down_btn.onRelease = function(){ + this._parent.onEnterFrame = null; +} +scrollbar_mc.handler_mc.drag_btn.onPress = function(){ + var scroll_top_limit = 19; + var scroll_bottom_limit = scrollbar_mc.bg_mc._height - scrollbar_mc.handler_mc._height - 2; + this._parent.startDrag(false,this._parent._x,scroll_top_limit,this._parent._x,scroll_bottom_limit) + this._parent.isdragging = true; + this._parent.onEnterFrame = scrollTracks; +} +scrollbar_mc.handler_mc.drag_btn.onRelease = scrollbar_mc.handler_mc.drag_btn.onReleaseOutside = function(){ + stopDrag() + this._parent.isdragging = false; + this._parent.onEnterFrame = null; +} +function scrollTracks(){ + var scroll_top_limit = 19; + var scroll_bottom_limit = scrollbar_mc.bg_mc._height - scrollbar_mc.handler_mc._height - 2; + var list_bottom_limit = 1; + var list_top_limit = (1-Math.round(playlist_mc.tracks_mc._height))+Math.floor(playlist_mc.mask_mc._height/14)*14 + if(playlist_mc.tracks_mc._height>playlist_mc.mask_mc._height){ + if(scrollbar_mc.handler_mc.isdragging){ + var percent = (scrollbar_mc.handler_mc._y-scroll_top_limit)/(scroll_bottom_limit-scroll_top_limit) + playlist_mc.tracks_mc._y = (list_top_limit-list_bottom_limit)*percent+list_bottom_limit; + }else{ + if(scrollbar_mc.v==-1){ + if(playlist_mc.tracks_mc._y+14list_top_limit){ + playlist_mc.tracks_mc._y -= 14; + }else{ + playlist_mc.tracks_mc._y = list_top_limit; + } + var percent = (playlist_mc.tracks_mc._y-1)/(list_top_limit-1) + scrollbar_mc.handler_mc._y = percent*(scroll_bottom_limit - scroll_top_limit)+scroll_top_limit; + } + } + } +} +function loadPlaylist(){ + track_display_mc.display_txt.text = LOADING_PLAYLIST_MSG; + if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; + }else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; + } + + //playlist + if(playlist_url){ + playlist_xml.load(unescape(playlist_url)) + }else{ + //single track + playlist_xml.parseXML(single_music_playlist) + playlist_xml.onLoad(true); + } +} + +//first click - load playlist +start_btn_mc.start_btn.onPress = function(){ + autoplay = true; + loadPlaylist(); +} + + +//main +Stage.scaleMode = "noScale" +Stage.align = "LT"; +this.onResize = resizeUI; +Stage.addListener(this); +if(!player_title) player_title = DEFAULT_WELCOME_MSG; +track_display_mc.display_txt.autoSize = "left"; +track_display_mc.display_txt.text = player_title; +if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; +}else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; +} +//start to play automatically if parameter autoplay is present +if(autoplay){ + start_btn_mc.start_btn.onPress(); +} else if (autoload){ + loadPlaylist() +} +//customized menu +var my_cm:ContextMenu = new ContextMenu(); +my_cm.customItems.push(new ContextMenuItem("Stop", stopTrack)); +my_cm.customItems.push(new ContextMenuItem("Play!", playTrack)); +my_cm.customItems.push(new ContextMenuItem("Next", nextTrack)); +my_cm.customItems.push(new ContextMenuItem("Previous", prevTrack)); +my_cm.customItems.push(new ContextMenuItem("Download this song", function(){getURL(playlist_array[track_index].location,"_blank")},true)); +my_cm.customItems.push(new ContextMenuItem("Add song to Webjay playlist", function(){getURL("http://webjay.org/poster?media="+escape(playlist_array[track_index].location),"_blank")})); +my_cm.customItems.push(new ContextMenuItem("About Hideout", function(){getURL("http://www.hideout.com.br","_blank")},true)); +//my_cm.customItems.push(new ContextMenuItem("Crossfade", function(){})); +//my_cm.customItems.push(new ContextMenuItem("Mando Diao - Paralyzed", function(){})); +my_cm.hideBuiltInItems(); +this.menu = my_cm; +resizeUI(); \ No newline at end of file diff --git a/web/xspf_player/xspf_player.fla b/web/xspf_player/xspf_player.fla new file mode 100644 index 0000000..aa7b413 Binary files /dev/null and b/web/xspf_player/xspf_player.fla differ diff --git a/web/xspf_player/xspf_player.swf b/web/xspf_player/xspf_player.swf new file mode 100644 index 0000000..f03790a Binary files /dev/null and b/web/xspf_player/xspf_player.swf differ diff --git a/web/xspf_player/xspf_player_slim.as b/web/xspf_player/xspf_player_slim.as new file mode 100644 index 0000000..019d48d --- /dev/null +++ b/web/xspf_player/xspf_player_slim.as @@ -0,0 +1,342 @@ +/* +Copyright (c) 2005, Fabricio Zuardi +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//repeat_playlist = true; +//playlist_size = 3; +//player_title = "customizeable title test" +//song_url = "http://downloads.betterpropaganda.com/music/Imperial_Teen-Ivanka_128.mp3"; +//song_title = "Imperial Teen - Ivanka"; +//autoload=true +//playlist_url = "testplaylist02.xspf" +//info_button_text = "Buy Album" +//playlist_url = "http://hideout.com.br/shows/radio-test.xspf"; +//playlist_url = "http://cchits.ning.com/recent/xspf/?xn_auth=no"; +//radio_mode = true; + + +stop(); +//constants +DEFAULT_PLAYLIST_URL = "http://webjay.org/by/hideout/allshows.xspf"; +DEFAULT_WELCOME_MSG = "Hideout XSPF Music Player - by Fabricio Zuardi"; +LOADING_PLAYLIST_MSG = "Loading Playlist..."; +DEFAULT_LOADED_PLAYLIST_MSG = "- click to start" +DEFAULT_INFOBUTTON_TXT = "Track Info" +//default playlist if none is passed through query string +if(!playlist_url){ + if(!song_url){ + playlist_url = DEFAULT_PLAYLIST_URL; + }else{ + single_music_playlist = ""; + single_music_playlist += ""+song_url+""+song_title+"" + single_music_playlist += "" + } +} +//info button +info_mc._visible=false; +if(!info_button_text){ + info_button_text = DEFAULT_INFOBUTTON_TXT; +} + +//variables initialization +playlist_array = []; +track_index = 0; +volume_level = 100; +pause_position = 0; + +playlist_xml = new XML(); +playlist_xml.ignoreWhite = true; +playlist_xml.onLoad = playlistLoaded; +mysound = new Sound(this); +playlist_listener = new Object(); +playlist_list.addEventListener("change", playlist_listener) +//play_btn.onPress = playTrack; +//functions +//xml parser +function playlistLoaded (success){ + if(success){ + var root_node = this.firstChild; + for(var node = root_node.firstChild; node != null; node = node.nextSibling){ + if(node.nodeName == "title"){ + playlist_title = node.firstChild.nodeValue; + } + if(node.nodeName == "trackList"){ + //tracks + var tracks_array = []; + for(var track_node = node.firstChild; track_node != null; track_node = track_node.nextSibling){ + var track_obj = new Object() + //track attributes + for(var track_child = track_node.firstChild; track_child != null; track_child = track_child.nextSibling){ + if(track_child.nodeName=="location"){ + track_obj.location = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="image"){ + track_obj.image = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="title"){ + track_obj.title = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="creator"){ + track_obj.creator = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="annotation"){ + track_obj.annotation = track_child.firstChild.nodeValue + } + if(track_child.nodeName=="info"){ + track_obj.info = track_child.firstChild.nodeValue + } + } + track_obj.label = (tracks_array.length+1) +". "; + if(track_obj.title) { + if(track_obj.creator) { + track_obj.label += track_obj.creator+' - '; + } + track_obj.label += track_obj.title; + } else { + track_obj.label += track_obj.annotation; + } + tracks_array.push(track_obj) + } + } + } + playlist_array = tracks_array; + if(!playlist_size) playlist_size = playlist_array.length; + if(autoplay){ + loadTrack() + }else{ + start_btn_mc.start_btn.onPress = loadTrack; + track_display_mc.display_txt.text = playlist_title+" "+DEFAULT_LOADED_PLAYLIST_MSG; + if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; + }else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; + } + } + }else{ + annotation_txt.text = "Error opening "+playlist_url; + } + +} + +playlist_listener.change = function(eventObject){ + annotation_txt.text = playlist_list.selectedItem.annotation; + location_txt.text = playlist_list.selectedItem.location; +} + +function loadTrack(){ + + //Radio Mode feature by nosferathoo, more info in: https://sourceforge.net/tracker/index.php?func=detail&aid=1341940&group_id=128363&atid=711474 + if (radio_mode && track_index==playlist_size-1) { + playlist_url=playlist_array[track_index].location; + for (i=0;itrack_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; + }else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; + } + mysound.loadSound(playlist_array[track_index].location,true); + play_mc.gotoAndStop(2) + + //info button + if(playlist_array[track_index].info!=undefined){ + info_mc._visible = true; + info_mc.info_btn.onPress = function(){ + getURL(playlist_array[track_index].info,"_blank") + } + info_mc.info_btn.onRollOver = function(){ + track_display_mc.display_txt.text = info_button_text; + } + info_mc.info_btn.onRollOut = function(){ + track_display_mc.display_txt.text = playlist_array[track_index].label; + } + }else{ + info_mc._visible = false; + } + resizeUI(); + _root.onEnterFrame=function(){ + //HACK doesnt need to set the volume at every enterframe + mysound.setVolume(this.volume_level) + var load_percent = (mysound.getBytesLoaded()/mysound.getBytesTotal())*100 + track_display_mc.loader_mc.load_bar_mc._xscale = load_percent; + if(mysound.getBytesLoaded()==mysound.getBytesTotal()){ + //_root.onEnterFrame = null; + } + } +} + +stop_btn.onRelease = stopTrack; +play_mc.play_btn.onRelease = playTrack +next_btn.onRelease = nextTrack +prev_btn.onRelease = prevTrack +mysound.onSoundComplete = nextTrack; +volume_mc.volume_btn.onPress = volumeChange; +volume_mc.volume_btn.onRelease = volume_mc.volume_btn.onReleaseOutside = function(){ + this._parent.onEnterFrame = null; +} + +function volumeChange(){ + this._parent.onEnterFrame = function(){ + var percent = (this._xmouse/this._width)*100 + if(percent>100)percent=100; + if(percent<0)percent=0; + this.volume_bar_mc._xscale = percent + this._parent.volume_level = percent; + mysound.setVolume(percent) + } +} + +function stopTrack() { + mysound.stop(); + play_mc.gotoAndStop(1) + mysound.stop(); + mysound.start(); + mysound.stop(); + _root.pause_position = 0; + +}; +function playTrack() { + if(play_mc._currentframe==1){ //play + seekTrack(_root.pause_position) + play_mc.gotoAndStop(2) + }else if(play_mc._currentframe==2){ + _root.pause_position = mysound.position; + mysound.stop(); + play_mc.gotoAndStop(1) + } + +}; + +function seekTrack(p_offset:Number){ + mysound.stop() + mysound.start(int((p_offset)/1000),1) +} +function nextTrack(){ + if(track_index0){ + track_index --; + loadTrack(); + } +} + +function scrollTitle(){ + track_display_mc.display_txt._x -= 5; + if (track_display_mc.display_txt._x+track_display_mc.display_txt._width<0){ + track_display_mc.display_txt._x = track_display_mc.mask_mc._width; + } +} + +function resizeUI(){ + bg_mc._width = Stage.width; + track_display_mc.loader_mc._width = Stage.width - track_display_mc._x - 3; + track_display_mc.mask_mc._width = track_display_mc.loader_mc._width - 26; + if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; + }else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; + } + if (info_mc._visible){ + info_mc._x = Stage.width - info_mc._width - 4; + }else{ + info_mc._x = Stage.width - 4; + } + volume_mc._x = info_mc._x - volume_mc._width - 2; + start_btn_mc._xscale = Stage.width; +} + +function loadPlaylist(){ + track_display_mc.display_txt.text = LOADING_PLAYLIST_MSG; + if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; + }else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; + } + + //playlist + if(playlist_url){ + playlist_xml.load(playlist_url) + }else{ + //single track + playlist_xml.parseXML(single_music_playlist) + playlist_xml.onLoad(true); + } +} + +//first click - load playlist +start_btn_mc.start_btn.onPress = function(){ + autoplay = true; + loadPlaylist(); +} + +//main +Stage.scaleMode = "noScale" +Stage.align = "LT"; +this.onResize = resizeUI; +Stage.addListener(this); +if(!player_title) player_title = DEFAULT_WELCOME_MSG; +track_display_mc.display_txt.autoSize = "left"; +track_display_mc.display_txt.text = player_title; +if(track_display_mc.display_txt._width>track_display_mc.mask_mc._width){ + track_display_mc.onEnterFrame = scrollTitle; +}else{ + track_display_mc.onEnterFrame = null; + track_display_mc.display_txt._x = 0; +} +//start to play automatically if parameter autoplay is present +if(autoplay){ + start_btn_mc.start_btn.onPress(); +} else if (autoload){ + loadPlaylist() +} + +//customized menu +var my_cm:ContextMenu = new ContextMenu(); +my_cm.customItems.push(new ContextMenuItem("Stop", stopTrack)); +my_cm.customItems.push(new ContextMenuItem("Play!", playTrack)); +my_cm.customItems.push(new ContextMenuItem("Next", nextTrack)); +my_cm.customItems.push(new ContextMenuItem("Previous", prevTrack)); +my_cm.customItems.push(new ContextMenuItem("Download this song", function(){getURL(playlist_array[track_index].location)},true)); +my_cm.customItems.push(new ContextMenuItem("Add song to Webjay playlist", function(){getURL("http://webjay.org/poster?media="+escape(playlist_array[track_index].location))})); +my_cm.customItems.push(new ContextMenuItem("About Hideout", function(){getURL("http://www.hideout.com.br")},true)); +//my_cm.customItems.push(new ContextMenuItem("Crossfade", function(){})); +//my_cm.customItems.push(new ContextMenuItem("Mando Diao - Paralyzed", function(){})); +my_cm.hideBuiltInItems(); +this.menu = my_cm; +resizeUI(); \ No newline at end of file diff --git a/web/xspf_player/xspf_player_slim.fla b/web/xspf_player/xspf_player_slim.fla new file mode 100644 index 0000000..7e6a01f Binary files /dev/null and b/web/xspf_player/xspf_player_slim.fla differ diff --git a/web/xspf_player/xspf_player_slim.swf b/web/xspf_player/xspf_player_slim.swf new file mode 100644 index 0000000..24b36c9 Binary files /dev/null and b/web/xspf_player/xspf_player_slim.swf differ